Professional Documents
Culture Documents
*
* File: I2C_EEPROM_LIB.c
* Author name: Seth Cram
* Rev. Date: 11/02/2021
*
* File Description:
* Source code for writing an arbitrary number of bytes to a specified EEPROM from
the PIC32.
* Essentially, an EEPROM device driver.
* Tested in test_proj8.c.
*
* Notes:
* OpenI2C2() = brg computed value for the baud rate generator. The value is
* calculated as follws: BRG = (Fpb / 2 / baudrate) - 2
* Always have to idle after a stop, start, restart, ack, or nack
*
* RestartI2C2() = generates I2C Bus Restart condition.
* StartI2C2() = Generates I2C Bus Start condition
* IdleI2C2() = This function generates Wait condition until I2C bus is Idle.
* - blocking function till I2C bus idle
* - This function will be in a wait state until Start Condition
Enable bit, Stop
* Condition Enable bit, Receive Enable bit, Acknowledge
Sequence
* Enable bit of I2C Control register and Transmit Status bit
I
* 2C Status register are clear.
* - I2C peripheral must be in Idle state before an I
* 2C operation can be initiated
* or write collision will be generated.
* StopI2C2() = Generates I2C Bus Stop condition
* NotAckI2C2() = Generates I2C bus Not Acknowledge condition
**********************************************************************/
//Initializes the I2C bus and the EEPROM such that after this function is called,
the user of the
// library can immediately begin using the read and write functions
// Initializes the I2C2 port for the requested speed (baud rate):
void init_I2C2( int Sck_Freq )
{
//open I2C port 2 by enabling it and giving it the baud rate
//if macro: OpenI2C2( I2C_EN, BRG_VAL);
OpenI2C2( I2C_EN, ( FPB / 2 / Sck_Freq ) - 2 );
}
//simply looping a single byte read or a single byte write will not suffice for the
// arbitrary length read and write functions
/*
Read len bytes from the EEPROM starting from EEPROM memory address mem addr into
the
buffer pointed to by i2c_byte.
Return zero on success or a non-zero value if there is an error. Examples of errors
might include
an invalid memory address passed into the function, a NULL pointer for
i2c_byte, an invalid len
argument, or an I2C bus error. Each error handled should return a different
non-zero value.
The function will not return until either len bytes were read into i2c_byte or
there was error.
*/
int eeprom_read( int slaveAddy, int mem_addr, char *i2c_byte, int len )
{
unsigned int index = 0;
unsigned char write_err = 0;
unsigned int upper_addr = mem_addr >> SHIFT_BYTE; //shift MSB to LSB
unsigned int lower_addr = mem_addr & 0x00FF; //mask off upper byte
unsigned int memAddyCntr = mem_addr;
I2C2_Start_Condition();
I2C2_Restart();
I2C2_Stop_Condition();
I2C2_Nack();
I2C2_Stop_Condition();
I2C2_Nack();
I2C2_Stop_Condition();
//if write_err != 0:
if( write_err ) //BREAKPOINT
{
return write_err; //problem during write
}
/*
Write len bytes into the EEPROM starting at memory address mem addr from the buffer
i2c_data.
The function should not return until either the write is complete or an error has
occurred.
So, poll the device until it isn't busy anymore before returning from the function.
*/
int eeprom_write( int slaveAddy, int mem_addr, char *i2c_data, int len)
{
unsigned int index = 0;
unsigned char write_err = 0;
unsigned char poll_err = 0;
unsigned int upper_addr = mem_addr >> SHIFT_BYTE; //move upper byte to lower
byte to write
unsigned int lower_addr = mem_addr & LOWER_BYTE; //mask off upper byte
//write data:
while( len-- )
{
//if curr loc in array is NULL:
if( i2c_data[ index ] == NULL )
{
I2C2_Stop_Condition();
//stop transfer
I2C2_Stop_Condition();
I2C2_Start_Condition();
I2C2_Stop_Condition();
/*
This is a blocking function until the slave device has completed
the operation.
Used by I2CWriteEEPROM to determine if the device has completed the
internal page write.
Also a helper funct.
*/
int wait_i2c_xfer( int slaveAddy )
{
const unsigned int maxWrites = 1000;
unsigned int currWrite = 0;
void I2C2_Start_Condition()
{
StartI2C2();
IdleI2C2();
}
void I2C2_Stop_Condition()
{
StopI2C2(); //ACK received, so write complete
IdleI2C2();
}
void I2C2_Nack()
{
NotAckI2C2();
IdleI2C2(); //idle after nacks too
}
void I2C2_Ack()
{
AckI2C2();
IdleI2C2(); //idle for next read
}
void I2C2_Restart()
{
RestartI2C2();
IdleI2C2();
}