/**************************************************************
        Schemat podłączeń programowanego układu
                       +----v----+
                 MCLR [| 1     28|] VDD
            D1 <- RA0 [| 2     27|] VSS
            D2 <- RA1 [| 3     26|] RP15 -> SCK1OUT	(SCK)
            D3 <- RB0 [| 4     25|] RP14 -> SDO1	(SI)
            D4 <- RB1 [| 5     24|] RP13 -> SDI1	(SO)
            D5 <- RB2 [| 6     23|] 
            D6 <- RB3 [| 7     22|] RB11 -> CS		(CS)
                  VSS [| 8     21|] 
       (8 MHz) / OSCI [| 9     20|] VCAP/VDDCORE
               \ OSCO [|10     19|] DISVREG
                      [|11     18|] 
                      [|12     17|] 
                  VDD [|13     16|] RB7 -> D8 
            D7 <- RB5 [|14     15|] 
                       +---------+
                     PIC24FJ64GB002
***************************************************************/
#include <p24Fxxxx.h>
//definiujemy szybkość oscylatora dla funkcji __delay_
#define FCY 16000000UL 
//biblioteka z funkcjami __delay_us i __delay_ms
#include <libpic30.h>

//ustawienia bitów konfiguracyjnych
//1. 
//FWDTEN_OFF - Watchdog wyłączony
//JTAGEN_OFF - JTAG wyłączony
_CONFIG1(FWDTEN_OFF & JTAGEN_OFF)
//2.
//FNOSC_PRIPLL - układ taktowany zewnętrznym oscylatorem z pętlą PLL
//POSCMOD_XT - częstotliwość taktowania oscylatora 8 MHz
//PLLDIV_DIV2 - konieczność podzielenia przez 2 dla modułu USB PLL
_CONFIG2(FNOSC_PRIPLL & POSCMOD_XT & PLLDIV_DIV2)

#define linia_CS		LATBbits.LATB11

/////////////////////////////////////////////////////
//funkcje obsługi interfejsu SPI
void StartSPI()
{
	//1. konfiguracja SPI2CON1 i SPI2CON2
	SPI2CON1bits.MSTEN = 1;		//tryb Master
	SPI2CON1bits.MODE16 = 0;	//dane 8-bitowe
	//2. ustawienie bitu SPIEN (włączenie modułu SPI2)
	SPI2STATbits.SPIEN = 1;	
}

unsigned char TransferSPI2(unsigned char dane)
{
    SPI2BUF = dane;				//załaduj dane do bufora
    while(!SPI2STATbits.SPIRBF);//zaczekaj na zakończenie operacji
    return SPI2BUF;    			//odczytaj dane
}

/////////////////////////////////////////////////////
//funkcja zaświecająca sekwencję diod LED
void Diody(unsigned char x)
{
	//zgaś diody				
	LATAbits.LATA0 = 0;		//(D1)
	LATAbits.LATA1 = 0;		//(D2)
	LATBbits.LATB0 = 0;		//(D3)
	LATBbits.LATB1 = 0;		//(D4)
	LATBbits.LATB2 = 0;		//(D5)
	LATBbits.LATB3 = 0;		//(D6)
	LATBbits.LATB5 = 0;		//(D7)
	LATBbits.LATB7 = 0;		//(D8)

	//zaświeć diody
	if(x&0x01)	LATAbits.LATA0 = 1;
	if(x&0x02)	LATAbits.LATA1 = 1;
	if(x&0x04)	LATBbits.LATB0 = 1;
	if(x&0x08)	LATBbits.LATB1 = 1;
	if(x&0x10)	LATBbits.LATB2 = 1;
	if(x&0x20)	LATBbits.LATB3 = 1;
	if(x&0x40)	LATBbits.LATB5 = 1;
	if(x&0x80)	LATBbits.LATB7 = 1;
}

/////////////////////////////////////////////////////
//funkcje obsługi pamięci EEPROM
void Uruchom_EEPROM()
{
	linia_CS = 0;				//CS w stanie niskim
	TransferSPI2(6);			//ustaw możliwość zapisu
	linia_CS = 1;				//CS w stanie wysokim
	__delay_us(1);				//czekaj 1 us
	linia_CS = 0;				//CS w stanie niskim
	TransferSPI2(1);			//rozkaz zapisu rejestru STATUS
	TransferSPI2(0);			//dane = 0
	linia_CS = 1;				//CS w stanie wysokim
	__delay_ms(5);				//czekaj 5 ms
}

void Uruchom_zapis_EEPROM()
{
	linia_CS = 0;				//CS w stanie niskim
	TransferSPI2(6);			//ustaw możliwość zapisu
	linia_CS = 1;				//CS w stanie wysokim
}

void Zakoncz_zapis_EEPROM()
{
	linia_CS = 0;				//CS w stanie niskim
	TransferSPI2(4);			//zakończ możliwość zapisu
	linia_CS = 1;				//CS w stanie wysokim
}

unsigned char Czytaj_status_EEPROM()
{
	unsigned char bajt;
	linia_CS = 0;				//CS w stanie niskim
	TransferSPI2(5);			//rozkaz odczytu rejestru STATUS
	bajt = TransferSPI2(0);		//odczytaj bajt
	linia_CS = 1;				//CS w stanie wysokim
	return bajt;
}	

void Zapisz_bajt_do_EEPROM(unsigned int adres, unsigned char bajt)
{
	Uruchom_zapis_EEPROM();			//
	__delay_us(1);					//zaczekaj 1 us
	linia_CS = 0;					//CS w stanie niskim
	TransferSPI2(2);				//rozkaz zapisu
	TransferSPI2((adres>>8)&0xFF);	//pierwsza część 16-bitowego adresu
	TransferSPI2(adres&0xFF);		//druga część 16-bitowego adresu
	TransferSPI2(bajt);				//bajt do zapisania
	linia_CS = 1;					//CS w stanie wysokim
	//zaczekaj na zakończenie zapisu
	while(Czytaj_status_EEPROM()&0x01);
	Zakoncz_zapis_EEPROM();
	__delay_ms(5);
}

unsigned char Czytaj_bajt_z_EEPROM(unsigned int adres)
{
	unsigned char bajt;
	linia_CS = 0;					//CS w stanie niskim
	TransferSPI2(3);				//rozkaz odczytu
	TransferSPI2((adres>>8)&0xFF);	//pierwsza część 16-bitowego adresu
	TransferSPI2(adres&0xFF);		//druga część 16-bitowego adresu
	bajt = TransferSPI2(0);			//odczytaj bajt
	linia_CS = 1;					//CS w stanie wysokim
	return bajt;					//powrót z wartością
}		

/////////////////////////////////////////////////////
//funkcja główna
int main()
{
	unsigned char bajt;
	int i;

	AD1PCFG = 0xFFFF;			//wszystkie linie cyfrowe
	/////////////////////////////////////////////////////
	// konfiguracja linii portów A i B
	TRISAbits.TRISA0 = 0;		//linia RA0 wyjściowa (D1)
	TRISAbits.TRISA1 = 0;		//linia RA1 wyjściowa (D2)
	TRISBbits.TRISB0 = 0;		//linia RB0 wyjściowa (D3)
	TRISBbits.TRISB1 = 0;		//linia RB1 wyjściowa (D4)
	TRISBbits.TRISB2 = 0;		//linia RB2 wyjściowa (D5)
	TRISBbits.TRISB3 = 0;		//linia RB3 wyjściowa (D6)
	TRISBbits.TRISB5 = 0;		//linia RB5 wyjściowa (D7)
	TRISBbits.TRISB7 = 0;		//linia RB7 wyjściowa (D8)

	/////////////////////////////////////////////////////
	// obsługa SPI2
	//remapowanie linii portów dla interfejsu SPI
	//linie wyjściowe
	//1. RP14 -> SDO2 (funkcja nr 10)
	RPOR7bits.RP14R = 10;
	//2. RP15 -> SCK2OUT (funkcja nr 11)
	RPOR7bits.RP15R = 11;
	//linia wejściowa
	//3. RP13 <- SDI2 (linia nr 13)
	RPINR22bits.SDI2R = 13;
	//linię CS będziemy zerować samodzielnie
	TRISBbits.TRISB11 = 0;		//linia RB11 wyjściowa (CS)
	LATBbits.LATB11 = 1;		//stan wysoki na linii
	
	StartSPI();					//uruchomienie modułu SPI

	/////////////////////////////////////////////////////
	//przykład obsługi pamięci EEPROM
	Uruchom_EEPROM();

	Zapisz_bajt_do_EEPROM(0x0100, 0x80);
	Zapisz_bajt_do_EEPROM(0x0101, 0x40);
	Zapisz_bajt_do_EEPROM(0x0102, 0x20);
	Zapisz_bajt_do_EEPROM(0x0103, 0x10);
	Zapisz_bajt_do_EEPROM(0x0104, 0x08);
	Zapisz_bajt_do_EEPROM(0x0105, 0x04);
	Zapisz_bajt_do_EEPROM(0x0106, 0x02);
	Zapisz_bajt_do_EEPROM(0x0107, 0x01);

	for(;;)
	{
		for(i=0x0100; i<0x0108; i++)
		{
			bajt = Czytaj_bajt_z_EEPROM(i);
			Diody(bajt);
			__delay_ms(500);
		}
	}

}
