EEPROM:
Pamięć 24AA02E48 jest to 2 Kbit pamięć PROM. Pamięć zorganizowana jest w dwóch blokach 128 x 8 bit. Komunikacja odbywa się przez interfejs I2C. Zaletą tej pamięci jest przechowywanie danych z adresem MAC w osobnym miejscu w pamięci. Przez co uzyskuje się możliwość posiadania unikalnego adresu MAC urządzenia.
Wyprowadzenia układu są następujące:
A0, A1, A2 - piny nieużywane, można je zostawić wiszące lub podłączyć do masy bądź zasilania. Ja wspomniane piny podłączyłem do masy,
VSS - do masy,
SDA - linia danych I2C, podłączana pod mikrokontroler,
SCL - linia zegara I2C, podłączana pod mikrokontroler,
NC - jeden pin w obudowie 8 nóżkowej zostaje nie podłączony do niczego.
VCC - do zasilania, układ akceptuje napięcie od 1.7V do 5.5V
Program:
Inicjalizacja interfejsu I2C w celu rozpoczęcia komunikacji z pamięcią. Podłączenie kości pod mikrokontroler LPC1769 jest następujące:
- /*
- * P0[0] - EEPROM SDA
- * P0[1] - EEPROM SCL
- * */
- #define EEPROM_I2C_PORT_SDA 0
- #define EEPROM_I2C_PIN_SDA 0
- #define EEPROM_PORT_I2C_SCL 0
- #define EEPROM_PIN_I2C_SCL 1
- #define EEPROM_I2C LPC_I2C1
- #define EEPROM_FUNC PINSEL_FUNC_3
Pozostałe stałe definicje:
- #define I2CDEV LPC_I2C1
- #define EEPROM_I2C_ADDR1 (0x57)
- #define EEPROM_TOTAL_SIZE 256
- #define EEPROM_BLOCK_SIZE 256
- #define EEPROM_PAGE_SIZE 8
- #define READ_MAC_ADDR_OFFSET 0xfa
Inicjalizacja interfejsu I2C wygląda następująco:
- void EEPROM_Initial(void) {
- PINSEL_CFG_Type PinCfg;
- PinCfg.Funcnum = EEPROM_FUNC;
- PinCfg.Pinnum = EEPROM_I2C_PIN_SDA;
- PinCfg.Portnum = EEPROM_I2C_PORT_SDA;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = EEPROM_PIN_I2C_SCL;
- PINSEL_ConfigPin(&PinCfg);
- I2C_Init(EEPROM_I2C, 100000);
- I2C_Cmd(EEPROM_I2C, ENABLE);
- }
Funkcję opisaną powyżej należy wywołać na samym początku, przed rozpoczęciem wykonywania jakichkolwiek operacji na pamięci.
Odczyt danych po I2C:
- static int I2CRead(uint8_t addr, uint8_t* buf, uint32_t len) {
- I2C_M_SETUP_Type i2cReadSetup;
- i2cReadSetup.sl_addr7bit = addr;
- i2cReadSetup.tx_data = NULL;
- i2cReadSetup.tx_length = 0;
- i2cReadSetup.rx_data = buf;
- i2cReadSetup.rx_length = len;
- i2cReadSetup.retransmissions_max = 3;
- if(I2C_MasterTransferData(I2CDEV, &i2cReadSetup, I2C_TRANSFER_POLLING)== SUCCESS) {
- return (0x00);
- }
- else {
- return (-1);
- }
- }
Zapis danych po I2C:
- static int I2CWrite(uint8_t addr, uint8_t* buf, uint32_t len) {
- I2C_M_SETUP_Type i2cWriteSetup;
- i2cWriteSetup.sl_addr7bit = addr;
- i2cWriteSetup.tx_data = buf;
- i2cWriteSetup.tx_length = len;
- i2cWriteSetup.rx_data = NULL;
- i2cWriteSetup.rx_length = 0;
- i2cWriteSetup.retransmissions_max = 3;
- if(I2C_MasterTransferData(I2CDEV, &txsetup, I2C_TRANSFER_POLLING)== SUCCESS){
- return (0x00);
- }
- else{
- return (-1);
- }
- }
Odczytanie danych z pamięci EEPROM i ich zapisanie do zdefiniowanego bufora przekazywanego jako wskaźnik:
- int16_t EEPROM_READFROM_MEM(unsigned char* readBufPtr, unsigned short readStartPosition, unsigned short readDataLength) {
- uint8_t addr = 0;
- uint16_t readDataOffset = readStartPosition;
- if (readDataLength > EEPROM_TOTAL_SIZE || offset + readDataLength > EEPROM_TOTAL_SIZE) {
- return -1;
- }
- addr = EEPROM_I2C_ADDR1 + (readStartPosition/ EEPROM_BLOCK_SIZE);
- readDataOffset = readStartPosition % EEPROM_BLOCK_SIZE;
- I2CWrite((addr), (uint8_t*)&readDataOffset , 1);
- EEPROM_DELAY();
- I2CRead((addr), readBufPtr, readDataLength);
- return readDataLength; /* Ret number of readed bytes */
- }
Zapisanie danych do pamięci EEPROM:
- int16_t EEPROM_WRITE_TO_MEM(unsigned char* readBufPtr, unsigned short writeStartPosition, unsigned short writeDataLength) {
- uint8_t addr = 0;
- int16_t writtenDataCounter = 0;
- uint16_t wLen = 0;
- uint16_t off = writeStartPosition;
- uint8_t tmp[9];
- if (writeDataLength> EEPROM_TOTAL_SIZE || writeStartPosition + writeDataLength> EEPROM_TOTAL_SIZE) {
- return -1;
- }
- addr = EEPROM_I2C_ADDR1 + (writeStartPosition / EEPROM_BLOCK_SIZE);
- off = writeStartPosition % EEPROM_BLOCK_SIZE;
- wLen = ((((off >> 3) + 1) << 3) - off);=
- wLen = MIN(wLen, writeDataLength);
- while (writeDataLength) {
- tmp[0] = off;
- memcpy(&tmp[1], (void*) &readBufPtr[writtenDataCounter ], wLen);
- I2CWrite((addr), tmp, wLen + 1);
- /* delay to wait for a write cycle */
- EEPROM_DELAY();
- writeDataLength-= wLen;
- writtenDataCounter += wLen;
- off += wLen;
- wLen = MIN(EEPROM_PAGE_SIZE, writeDataLength);
- addr += off / EEPROM_BLOCK_SIZE;
- off = off % EEPROM_BLOCK_SIZE;
- }
- return writtenDataCounter ;
- }
Odczyt zapisanego adresu MAC:
- void Read_MacAddress(uint8_t *MACbuf) {
- eeprom_read(MACbuf, READ_MAC_ADDR_OFFSET, 6);
- }
Reset pamięci EEPROM:
- uint8_t EEPROM_Reset() {
- uint8_t i = 0
- uint8_t len = 255;
- uint8_t dataBuffer[len];
- for (i = 0; i < len; i++) {
- if(i < 0x80) { dataBuffer[i] = 0x00; }
- else if(i < 0xfa) { dataBuffer[i] = 0xff; }
- }
- for(uint8_t j = 0; j<6; j++)
- {
- dataBuffer[249 + i] = (i + 1);
- }
- if(EEPROM_WRITE_TO_MEM((uint8_t *)&dataBuffer, 0, len) != (-1))
- {
- return 0xFF;
- }
- return (0x00);
- }
Odczyt pojedynczego bajtu z wybranego adresu:
- uint8_t readByte(uint8_t readAddress) {
- uint8_t readedData = 0;
- EEPROM_READFROM_MEM(&odczyt, readAddress, 1);
- return readedData;
- }
Teraz krótka funkcje pozwalające na ustawienie bądź czyszczenie wybranego bitu:
- void ClearBit(uint8_t dataAddress, uint8_t bitToClear) {
- uint8_t dataBuffer = 0;
- eeprom_read(&dataBuffer, dataAddress, 1);
- dataBuffer&= ~bitToClear;
- eeprom_write(&dataBuffer, dataAddress, 1);
- }
- void SetBit(uint8_t dataAddress, uint8_t bitToSet) {
- uint8_t dataBuffer = 0;
- eeprom_read(&dataBuffer, dataAddress, 1);
- dataBuffer |= bitToSet;
- eeprom_write(&dataBuffer, dataAddress, 1);
- }
Do funkcji podajemy bit, który ma być wyczyszczony lub ustawiony. Dane następnie są odczytywane z pamięci, dokonywana jest ich zmiana po czym ponownie wpisujemy je do pamięci.
Proste opóźnienie pomiędzy poszczególnymi operacjami:
- static void EEPROM_DELAY(void) {
- volatile int i = 0;
- for (i = 0; i < 0x04000; i++) { ; }
- }