PIC32MX: I2C EEPROM
Original Assignment
Do not erase this section!
Your assignment is to interface to the I2C 24AA1025 EEPROM chip.
Overview
You can use the PIC32 to communicate with an EEPROM chip using I2C. The EEPROM chip can store data sent from the PIC and be retrieved at a later time (like an external hardrive).
To test that the code data was writing and reading correctly, the attached code sends data to the EEPROM through I2C, then from the EEPROM back to the PIC, and out to a LED display screen.
Circuit
Connection schematic for 24AA1025 Chip.
For visual feedback the PIC32 was connected to and LCD screen(1602A1 USB-A/Mini-B5-06):
Timing
Table of times for sending data
# of Characters | sendChar | sendString |
---|---|---|
5 | 3.88 ms | 3.79 ms |
250 | 32.4 ms | 30.8 ms |
Table of times for reading data
# of Characters | receiveString |
---|---|
5 | 0.93 ms |
250 | 26.8 ms |
Note, we are able to read a single character using the recieveChar function, but cannot read a string.
Code
Main.c
/************************************************************** * I2C EEPROM using LCD screen as output display * **************************************************************/ /*Includes****************************************************/ #include <string.h> // used for string compare to verify data transmission #include <plib.h> #include <HardwareProfile.h> #include <LCD.h> // used to display for debugging #include <I2C_EEPROM.h> /*Definitions*************************************************/ #define BAUD_RATE 100000 #define BRG_VAL ((SYS_FREQ/2/BAUD_RATE)-2) /*Global Variables *******************************************/ unsigned char SlaveAddress = 0x50; short int memoryAddress = 0x0540; /*Main Function***********************************************/ int main(void) { char LCDbuffer[33]; // this will store the string for the LCD //unsigned char test[28]="Hello world\nI2C is working!"; unsigned char test[13]="Hello world!"; int size = sizeof(test); unsigned char readtest[size]; //Initialize LCD lcd_init(); //Enable channel OpenI2C1( I2C_EN, BRG_VAL ); SlaveAddress = 0x50; //0b1010(B0)(A0)(A1) 24AA1025 EEPROM address sendString(SlaveAddress, memoryAddress, test, size); receiveString(SlaveAddress, memoryAddress, readtest, size); //Print to LCD screen if(strcmp(readtest, test)==0) sprintf(LCDbuffer, "\fTrue"); // make the string else sprintf(LCDbuffer, "\fFalse"); putsLCD(LCDbuffer); // write the contents of the variable StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete CloseI2C1(); while(1) {} }
I2C_EEPROM.h
#ifndef I2C_EEPROM_H #define I2C_EEPROM_H void sendString(unsigned char SlaveAddress, short address, unsigned char *data, int length); void sendChar(unsigned char SlaveAddress, short address, unsigned char *data, int length); void getWriteAck(unsigned char SlaveAddress); void sendRecieveRequest(unsigned char SlaveAddress, short address); void receiveString(unsigned char SlaveAddress, short address, unsigned char *data, int length); void receiveChar(unsigned char SlaveAddress, short address, unsigned char *data, int length); #endif
I2C_EEPROM.c
#include <I2C_EEPROM.h> #include <plib.h> /******************************************************************* * Name: sendString.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * short address - 16-bit memory address to write the data to * unsigned char *data - pointer to data string to be stored * int length - length of data string to be stored * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. A string of data (with length bytes) * is sent to the I2C device with SlaveAddress. Data is written to * the specified memory address on the EEPROM using the function * MasterputsI2C1, which writes a string of data. It then waits * for an acknowledgement from the EEPROM saying that it has finished * writing the data. * *******************************************************************/ void sendString(unsigned char SlaveAddress, short address, unsigned char *data, int length) { // Initialize data sending char i2cData[3]; int DataSz = 3; // Send Data to eeprom to program one location i2cData[0] = (SlaveAddress << 1) | 0; //EEPROM Device Address and WR Command i2cData[1] = (address>>8); //eeprom location to program (high address byte) i2cData[2] = (address); //eeprom location to program (low address byte) StartI2C1(); //Send the Start Bit IdleI2C1(); //Wait to complete int Index = 0; while( DataSz ) { MasterWriteI2C1( i2cData[Index++] ); IdleI2C1(); //Wait to complete DataSz--; //ACKSTAT is 0 when slave acknowledge. if 1 then slave has not acknowledge the data. if( I2C1STATbits.ACKSTAT ) break; } MasterputsI2C1(data); StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete // wait for eeprom to complete write process getWriteAck(SlaveAddress); } /******************************************************************* * Name: sendChar.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * short address - 16-bit memory address to write the data to * unsigned char *data - pointer to data string to be stored * int length - length of data string to be stored * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. A string of data (with length bytes) * is sent to the I2C device with SlaveAddress. Data is written to * the specified memory address on the EEPROM using the function * MasterWriteI2C1, which writes a string of data one character at a time. * It then waits for an acknowledgement from the EEPROM saying that it * has finished writing the data. * *******************************************************************/ void sendChar(unsigned char SlaveAddress, short address, unsigned char *data, int length) { // Initialize data sending char i2cData[3]; int DataSz = 3; // Send Data to eeprom to program one location i2cData[0] = (SlaveAddress << 1) | 0; //EEPROM Device Address and WR Command i2cData[1] = (address>>8); //eeprom location to program (high address byte) i2cData[2] = (address); //eeprom location to program (low address byte) StartI2C1(); //Send the Start Bit IdleI2C1(); //Wait to complete int Index = 0; while( DataSz ) { MasterWriteI2C1( i2cData[Index++] ); IdleI2C1(); //Wait to complete DataSz--; //ACKSTAT is 0 when slave acknowledge. if 1 then slave has not acknowledge the data. if( I2C1STATbits.ACKSTAT ) break; } while(length) { MasterWriteI2C1( *data ); IdleI2C1(); //Wait to complete data++; // go to next memory address length--; //ACKSTAT is 0 when slave acknowledge. if 1 then slave has not acknowledge the data. if( I2C1STATbits.ACKSTAT ) break; } StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete // wait for eeprom to complete write process getWriteAck(SlaveAddress); } /******************************************************************* * Name: getWriteAck.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. It polls the EEPROM until it recieves an * acknowlegement that it has completed the write process. * *******************************************************************/ void getWriteAck(unsigned char SlaveAddress) { // wait for eeprom to complete write process. poll the ack status while(1) { //i2c_wait(10); StartI2C1(); //Send the Start Bit IdleI2C1(); //Wait to complete MasterWriteI2C1( (SlaveAddress << 1) | 0 ); IdleI2C1(); //Wait to complete if( I2C1STATbits.ACKSTAT == 0 ) //eeprom has acknowledged { StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete break; } StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete } } /******************************************************************* * Name: sendRecieveRequest.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * short address - 16-bit memory address to write the data to * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. The read command is sent to the EEPROM * to initialize a reading sequence. * *******************************************************************/ void sendRecieveRequest(unsigned char SlaveAddress, short address) { char i2cData[3]; int DataSz = 3; // Now Readback the data from the serial eeprom i2cData[0] = (SlaveAddress << 1) | 0; //EEPROM Device Address and WR Command (to write the address) i2cData[1] = address>>8; //eeprom location to read (high address byte) i2cData[2] = address; //eeprom location to read (low address byte) StartI2C1(); //Send the Start Bit IdleI2C1(); //Wait to complete //send the address to read from the serial eeprom int Index = 0; while( DataSz ) { MasterWriteI2C1( i2cData[Index++] ); IdleI2C1(); //Wait to complete DataSz--; //ACKSTAT is 0 when slave acknowledge. if 1 then slave has not acknowledge the data. if( I2C1STATbits.ACKSTAT ) break; } //now send a start sequence again RestartI2C1(); //Send the Restart condition //wait for this bit to go back to zero IdleI2C1(); //Wait to complete MasterWriteI2C1( (SlaveAddress << 1) | 1 ); //transmit read command IdleI2C1(); //Wait to complete } /******************************************************************* * Name: receiveString.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * short address - 16-bit memory address to read the data from * unsigned char *data - pointer to data string to be read * int length - length of data string to be read * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. A string of data (with length bytes) * is read from the I2C device with SlaveAddress. Data is read from * the specified memory address on the EEPROM using the function * MastergetsI2C1, which reads a string of data all at once. * *******************************************************************/ void receiveString(unsigned char SlaveAddress, short address, unsigned char *data, int length) { sendRecieveRequest(SlaveAddress, address); // get data as a string MastergetsI2C1(length-1, data, 100*length); // Set the last character to null as it will otherwise be random data from the EEPROM data+=length-1; *data = 0; StopI2C1(); IdleI2C1(); } /******************************************************************* * Name: receiveChar.c * * Inputs: * unsigned char SlaveAddress - I2C address of the chip * short address - 16-bit memory address to read the data from * unsigned char *data - pointer to data string to be read * int length - length of data string to be read * * Description: * This function uses I2C communication to interface with the * 24AA1025 EEPROM. A string of data (with length bytes) * is read from the I2C device with SlaveAddress. Data is read from * the specified memory address on the EEPROM using the function * MasterReadI2C1, which reads a string of data one byte at a time. * *******************************************************************/ void receiveChar(unsigned char SlaveAddress, short address, unsigned char *data, int length) { sendRecieveRequest(SlaveAddress, address); // get data one byte at a time while(length-1) { *data = MasterReadI2C1(); IdleI2C1(); //Wait to complete data++; // go to next memory address length--; //ACKSTAT is 0 when slave acknowledge. if 1 then slave has not acknowledge the data. if( I2C1STATbits.ACKSTAT ) break; } // Set the last character to null as it will otherwise be random data from the EEPROM data--; *data = 0; StopI2C1(); IdleI2C1(); }