Archive

Posts Tagged ‘i2c’

I2C EEPROM & PIC32

December 9, 2010 1 comment

Few useful examples, how to force HW I2C module of PIC32MX to collaborate with I2C EEPROM chip, like Microchip’s 24LC1025.

I2C Module Initialization

void eepromInit(void)
{
 I2CConfigure(EE_I2C, I2C_ENABLE_SLAVE_CLOCK_STRETCHING | I2C_ENABLE_HIGH_SPEED);
 I2CSetFrequency(EE_I2C, GetPeripheralClock(),400000);
 I2CEnable(EE_I2C, TRUE);
}

For single master-slave enviroment, you can omit I2C_ENABLE_SLAVE_CLOCK_STRETCHING config word.

Reading from EEPROM.

void eepromRead(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 // Start
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);        // Write control byte
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 MasterWriteI2C2(ee_addr >> 8);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 RestartI2C2();
 IdleI2C2();
 MasterWriteI2C2(EE_ADDR | 1);        // Read command
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 while (len)
 { 
 I2C2CONbits.RCEN = 1;
 while(!DataRdyI2C2());
 *buf = I2C2RCV;
 buf++;
 len--;
 if (len)
 {
 // ACK the slave
 I2C2CONbits.ACKDT = 0;
 I2C2CONbits.ACKEN = 1;
 } 
 else
 {
 // NACK the slave
 I2C2CONbits.ACKDT = 1;
 I2C2CONbits.ACKEN = 1;
 } 
 while(I2C2CONbits.ACKEN == 1);    /* Wait till ACK/NACK sequence is over */
 } 
 StopI2C2();
 IdleI2C2();
}

where EE_ADDR is #defined as 0xA0 , corresponding to EEPROM’s control word.
This function has limited functionality – it can only read first 0xFFFF bytes of data from EEPROM – no code provided to set B0 bit in config word (see datasheet).

Writing to EEPROM.

void eepromWritePage(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 // Start
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);        // Write control byte
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr >> 8);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 MasterWriteI2C2(ee_addr);            // Address of operation
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?

 while (len)
 {    
 MasterWriteI2C2(*buf++);
 IdleI2C2();
 if (I2C2STATbits.ACKSTAT)    return;            // NACK'ed by slave ?
 len--;
 }    
 StopI2C2();
 IdleI2C2();

 // Do acknowledge poll (indicating, that eeprom has completed flashing our bytes
 while(1) {
 StartI2C2();
 IdleI2C2();

 MasterWriteI2C2(EE_ADDR | 0);    // Call the eeprom
 IdleI2C2();

 if (I2C2STATbits.ACKSTAT==0) break;
 StopI2C2();
 IdleI2C2();
 }

 StopI2C2();
 IdleI2C2();
}    

void eepromWrite(unsigned int ee_addr, unsigned char *buf, unsigned int len)
{
 int bytes_to_write;
 while (len)
 {
 bytes_to_write = 0x80;    // default xx1025 pagesize
 if (len<bytes_to_write) bytes_to_write = len;
 eepromWritePage(ee_addr, buf, bytes_to_write);
 len-=bytes_to_write;
 buf+=bytes_to_write;
 ee_addr+=bytes_to_write;
 }    
}

because of limited amount of data for single write command (page size of this eeprom is 128 bytes), you should call eepromWrite(…) function, which can handle writes in 0x0000-0xffff addresses in eeprom space. (the same limitation with B0 bit as for eepromRead() func).

Have fun.