1
\$\begingroup\$

I am writing code for a PIC32MX250F128B to interface with the Microchip 24LC02B EEPROM with I2C interface. I have followed the datasheet of the EEPROM, the PIC32 and section 24 of the PIC32 family reference manual very closely and attempted to write code to interface with the EEPROM. I do not get any "hang" on any of the tests for the bits that need to be cleared/set after eg. an ACK is received - the code executes completely. However, when I check the value of the data variable right at the end of the readEeprom function, I just get a Null-character (after writing an 'H' in the EEPROM memory address specified, in byte write mode (page write code is commented out with #if)). This indicates that either the write did not occur properly, or the read did not occur properly.

I do not have access to an oscilloscope or logic analyzer to check what exactly happens on the SDA and SCL lines.

The PIC32 oscillator is set to 8 MHz and I intended to use a 100 kHz baud rate for communication with the EEPROM. So therefore, using the equation I2CBRG = (PBCLK/(2*FSCK))-2, as found in section 24 of the PIC32 family reference documents, I use 0x26 for theI2CBRG value.

Perhaps someone could spot if something is wrong in my code? I have tried to find the problem over a day now, but have not succeeded.

Here is my code: /* Interface test for I2C EEPROM with PIC32 */

#include <plib.h>
#include <p32xxxx.h>


/* Pin outline:
 * SCL1 - pin 17 - (EEPROM pin 6)
 * SDA1 - pin 18 - (EEPROM pin 5)
 * WP - pin 16 (RB7) (EEPROM pin 7) - Currently connected to GND
 */


//configuration bits
// DEVCFG3
//#pragma config PMDL1WAY = OFF           // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
//#pragma config IOL1WAY = OFF            // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
//#pragma config FUSBIDIO = OFF            // USB USID Selection (Controlled by the USB Module)
//#pragma config FVBUSONIO = OFF           // USB VBUS ON Selection (Controlled by USB Module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_1        // PLL Input Divider (12x Divider)
#pragma config FPLLMUL = MUL_24        // PLL Multiplier (24x Multiplier)
//#pragma config UPLLIDIV = DIV_1        // USB PLL Input Divider (12x Divider)
//#pragma config UPLLEN = OFF             // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_1       // System PLL Output Clock Divider (PLL Divide by 256)
// DEVCFG1
#pragma config FNOSC = FRC              // Oscillator Selection Bits (Fast RC Osc (FRC))
#pragma config FSOSCEN = OFF             // Secondary Oscillator Disnable (Disabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSECMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
//#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
//#pragma config FWDTWINSZ = WISZ_25      // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
//#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)
//////////////////////////////////////////

#define EEPROM_WP PORTBbits.RB7
#define CLOCK   8000000 /*8 MHz clock*/
#define HIGH 1 //logic values declaration
#define LOW 0 //logic values declaration

char data[10];
void init(void);
void readEeprom(void);
void writeEeprom(void);

int main (void)
{
    init();
    writeEeprom();
    readEeprom();
} /*main*/

void init(void)
{
    SYSTEMConfigPerformance(CLOCK);
    TRISBbits.TRISB7 = 0x01;
    /*I2C peripheral overrides states of respective interface pins - no need
     to set state of SCLx and SDAx pins here*/   

    /*Initialize I2C Peripheral*/    
    I2C1CONbits.DISSLW = HIGH; /*disable slew rate for 100 kHz*/
    I2C1BRG = 0x26; /*Set Baud Rate Generator*/
    I2C1CONbits.ON = HIGH;

    int i = 0;
    for (i = 0; i < 10; i++)
    {
        data[i] = '0';
    } /*for*/
} /*init*/

void writeEeprom(void)
{
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = 0b10100000;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send word address for read*/
    I2C1TRN = 0x00;
    while (I2C1STATbits.ACKSTAT == HIGH); /*wait for ACK from device*/

#if 0 /*Page write*/
    int i;
    /*24LC02 can only write up to 8 bytes at a time*/
    for (i = 0; i < 7; i++)
    {
        I2C1TRN = i;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 
        /*Generate ACK event*/        
        I2C1CONbits.ACKEN;
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Byte write*/    
    I2C1TRN = 'H';
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 
    /*Generate ACK event*/        
    I2C1CONbits.ACKEN; 
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif
} /*writeEeprom*/

void readEeprom(void)
{
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = 0b10100000;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send address for read*/
    I2C1TRN = 0x00; /*Upper 8 bits of address*/
    while (I2C1STATbits.ACKSTAT == HIGH); /*wait for ACK from device*/

    /*Send Repeated start event again*/
    I2C1CONbits.RSEN = HIGH;

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and read indication*/
    I2C1TRN = 0b10100001;

    while (I2C1STATbits.ACKSTAT == HIGH);
    int i = 0;
#if 0 /*Sequential read*/    
    for (i = 0; i < 10; i++)
    {
        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        data[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        /*Generate ACK event - do not send ACK for last sequential read*/
        if (i < 9)
        {
            I2C1CONbits.ACKEN;
        } /*if*/
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Single read*/
    /*Enable receive mode - RCEN cleared after 8th bit is received*/
    I2C1CONbits.RCEN = HIGH; 
    //while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
    data[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
    while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
    /*Send stop event - no ACK event must be sent*/
    I2C1CONbits.PEN;
#endif
} /*readEeprom()*/

I would greatly appreciate any help that anyone can offer. Thanks in advance.

EDIT: I realize that I misread in the datasheet that only one word address byte (instead of 2 - MSByte and LSByte) is required for the 24LC02. So I fixed that in my code, but I still have the same problem. I have also used an Arduino to (successfully) write to the EEPROM and read the data, and therefore I can confirm that even the writeEeprom function in my code is not working.

After some Google searches I have also read that the I2C peripheral could give problems while the PIC is in debug mode, which is what I am currently using.


The latest:

I sorted out the read problem, although my sequential read method is not performing it the intended way of doing it, but it works. However, I am having trouble writing to the EEPROM. My code follows the datasheet's guidlines exactly (even with some additional delays for safety), but it still doesn't work. My write function is the function called "writeEeprom" in the following code:

/* Interface test for I2C EEPROM 24LC02B with PIC32
 */

#include <plib.h>
#include <p32xxxx.h>


/* Pin outline:
 * SCL1 - pin 17 - (EEPROM pin 6)
 * SDA1 - pin 18 - (EEPROM pin 5)
 * WP - pin 16 (RB7) (EEPROM pin 7) - Currently connected to GND
 */


//configuration bits
// DEVCFG3
//#pragma config PMDL1WAY = OFF           // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
//#pragma config IOL1WAY = OFF            // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
//#pragma config FUSBIDIO = OFF            // USB USID Selection (Controlled by the USB Module)
//#pragma config FVBUSONIO = OFF           // USB VBUS ON Selection (Controlled by USB Module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_1        // PLL Input Divider (12x Divider)
#pragma config FPLLMUL = MUL_24        // PLL Multiplier (24x Multiplier)
//#pragma config UPLLIDIV = DIV_1        // USB PLL Input Divider (12x Divider)
//#pragma config UPLLEN = OFF             // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_1       // System PLL Output Clock Divider (PLL Divide by 256)
// DEVCFG1
#pragma config FNOSC = FRC              // Oscillator Selection Bits (Fast RC Osc (FRC))
#pragma config FSOSCEN = OFF             // Secondary Oscillator Disnable (Disabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSECMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
//#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
//#pragma config FWDTWINSZ = WISZ_25      // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx1        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)
//////////////////////////////////////////

#define EEPROM_WP PORTBbits.RB7
#define CLOCK   8000000
#define HIGH 1 //logic values declaration
#define LOW 0 //logic values declaration

char dataArr[8];
int controlWrite = 0b10100000; /*Control byte for writing to EEPROM*/
int controlRead = 0b10100001; /*Control byte for reading from EEPROM*/
int wordAddress = 0x00; /*Address of word in EEPROM*/

void init(void);
void readEeprom(void);
void readEepromSeq(void);
void writeEeprom(void);
void delayus(unsigned t); //1us delay
void delayms(unsigned k); //1ms delay

int main (void)
{
    init();
    delayms(10);
    writeEeprom();
    delayms(10);
    readEepromSeq();
} /*main*/

void init(void)
{
    SYSTEMConfigPerformance(CLOCK);
    /*I2C peripheral overrides states of respective interface pins - no need
     * to set state of SCLx and SDAx pins here.
     * I2C pins must be set to digital pins by clearing the respective ANSEL-SFR
     */
    ANSELB = 0x00; /*Configure port B as digital port, not analog*/

    /*Initialize I2C Peripheral*/    
    I2C1CONbits.DISSLW = HIGH; /*disable slew rate for 100 kHz*/
    I2C1BRG = 0x26; /*Set Baud Rate Generator - for PBCLK = 8 MHz, Fck = 100 kHz*/
    I2C1CONbits.ON = HIGH;

    int i = 0;
    for (i = 0; i < 10; i++)
    {
        dataArr[i] = '0';
    } /*for*/
} /*init*/

void writeEeprom(void)
{    
    wordAddress = 0x00;
    int data = 0x48; /*Character "H"*/
    int i = 0;

    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/     

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = controlWrite;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    //while (I2C1STATbits.TBF == HIGH); 
    /*Wait for transmit process to end - bit clears once transmit not in progress*/
    while (I2C1STATbits.TRSTAT == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send address for read*/
    I2C1TRN = wordAddress;
    /*Wait for transmit process to end*/
    while (I2C1STATbits.TRSTAT == HIGH); 
    /*Wait for ACK signal from device*/
    while (I2C1STATbits.ACKSTAT == HIGH);

#if 0 /*Page write*/
    int i;
    /*24LC02 can only write up to 8 bytes at a time*/
    for (i = 0; i < 7; i++)
    {
        I2C1TRN = i;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 
        /*Generate ACK event*/        
        delayms(10);
        I2C1CONbits.ACKEN;
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Byte write*/  
    I2C1TRN = data;
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while(I2C1STATbits.TRSTAT == HIGH); /*Wait until transmit is completed*/
    delayms(10);
    /*wait for ACK from device*/       
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);
    /*Send stop event*/
    I2C1CONbits.PEN;
    delayms(10);
#endif
} /*writeEeprom*/

void readEepromSeq()
{
    int i = 0;      
    wordAddress = 0x00;

    /*loop 8-times - the amount of bits in a byte*/
    for (i = 0; i < 8; i++)
    {
        /*Assert start condition*/
        I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

        /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
        while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

        /*Send device address and write indication - address = "1010xxx0"*/
        I2C1TRN = controlWrite;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 

        /*Wait for ACK signal from device - bit will clear when ACK is received*/
        while (I2C1STATbits.ACKSTAT == HIGH);
        delayms(10);

        /*Send address for read*/
        I2C1TRN = wordAddress; /*Lower 8 bits of address*/        
        while (I2C1STATbits.ACKSTAT == HIGH);
        delayms(10);

        /*Send Repeated start event again*/
        I2C1CONbits.RSEN = HIGH;

        /*Test if Repeated START condition is completed - test interrupt I2C1MIF in IFS1*/
        while (I2C1CONbits.RSEN == HIGH); /*wait until repeated start condition finishes*/ 

        /*Send device address and read indication*/
        I2C1TRN = controlRead;
        delayms(10);

        while (I2C1STATbits.ACKSTAT == HIGH);

        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        /*Send stop event - no ACK event must be sent*/
        I2C1CONbits.PEN;
        wordAddress++;
    } /*for*/
} /*readEepromSeq*/

void readEeprom(void)
{
    int i = 0;      
    wordAddress = 0x00;
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = controlWrite;
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);

    /*Send address for read*/
    I2C1TRN = wordAddress; /*Lower 8 bits of address*/        
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);

    /*Send Repeated start event again*/
    I2C1CONbits.RSEN = HIGH;

    /*Test if Repeated START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.RSEN == HIGH); /*wait until repeated start condition finishes*/ 

    /*Send device address and read indication*/
    I2C1TRN = controlRead;
    delayms(10);

    while (I2C1STATbits.ACKSTAT == HIGH);   

#if 1 /*Sequential read*/    
    for (i = 0; i < 8; i++)
    {
        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        delayms(10);
        /*Generate ACK event - do not send ACK for last sequential read*/
        if (i < 8)
        {
            I2C1CONbits.ACKEN;
        } /*if*/        
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 0 /*Single read*/
    /*Enable receive mode - RCEN cleared after 8th bit is received*/
    I2C1CONbits.RCEN = HIGH; 
    while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
    dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
    while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
    /*Send stop event - no ACK event must be sent*/
    I2C1CONbits.PEN;
#endif
} /*readEeprom()*/

void delayus(unsigned t)
{
    T1CONbits.ON = 1;                   //enable timer1
    while(t--)
    {
        TMR1 = 0;                       //reset timer1
        while(TMR1 < 8);                //delay of 1us: (1us)/(125ns) = 8
    } //while(t--)
    T1CONbits.ON = 0;                   //disable timer1 (power saving)
} //delayus

void delayms(unsigned k)
{
    T1CONbits.ON = 1;                   //enable timer1
    while(k--)
    {
        TMR1 = 0;                       //reset timer1
        while(TMR1 < 8000);                //delay of 1us: (1ms)/(125ns) = 8000
    } //while(t--)
    T1CONbits.ON = 0;                   //disable timer1 (power saving)
} //delayms

Can someone please take the trouble and have a look at it and at least provide me with some comments? Once again, the problem lies within the "writeEeprom" function that is called in main().

Thank you.

\$\endgroup\$
4
  • \$\begingroup\$ Have you considered using the chipKIT programming environment instead of raw PIC code? It has full I2C support built in just the same as Arduino. It takes a massive amount of the drudgery of getting these kind of things working and lets you get on with writing your code instead. \$\endgroup\$
    – Majenko
    Commented Aug 6, 2015 at 9:23
  • 1
    \$\begingroup\$ No I did not consider that (I am not familiar with it). I prefer using raw PIC code and to get it working the right way and completely understand all aspects of it. From a development point of view, I do not think that it is always good practice to switch to a different programming environment just because the raw code takes too long to get it working. It is of course dependent on how complex the implementation is, and I2C is really not that complex to justify me using a different programming environment. If this was eg. some sort of USB host implementation, then I would consider moving. \$\endgroup\$
    – wave.jaco
    Commented Aug 6, 2015 at 11:21
  • \$\begingroup\$ That's fair enough and a perfectly reasonable view which I can respect. However, maybe you could take a look at the chipKIT implementation of Wire.h (actually a wrapper for DTWI) to see how it's implemented in there and see if there's anything you've missed in your implementation. It's often good to compare your program with known working code from elsewhere to see if you have missed something. I personally don't know how to implement I2C direct on a PIC32 but I do know there are some things you have to watch out for. \$\endgroup\$
    – Majenko
    Commented Aug 6, 2015 at 11:23
  • \$\begingroup\$ Thanks Majenko. I totally agree with you that one can have a look at how it is implemented in a working, public library. I will have a look at that and see if I can sort out this problem. \$\endgroup\$
    – wave.jaco
    Commented Aug 6, 2015 at 11:32

2 Answers 2

1
\$\begingroup\$

Your code looks fine. However writing driver on your own can be time consuming and is prone to errors. Microchip supplies basic libraries and I2C EEPROM as well.

Are you sure both lines have pull-ups ( resistors to 3V ) ? Without this no bits will be generated by PIC.

Here is an example for working I2C EEPROM driver which can use both plib or manual hardware I2C on PIC32 or PIC16/18(HW_CFG_SENSOR).

void i2cSetupMaster(unsigned int BaudRate)
{
#ifdef I2C_USE_PLIB
    #ifndef HW_CFG_SENSOR
            I2CEnable(I2C_MOD,0);
            I2CConfigure(I2C_MOD,0);
            I2CSetFrequency(I2C_MOD,GetPeripheralClock(), BaudRate);
            I2CEnable(I2C_MOD,1);
    #else
            ANSELC = 0;
            TRISC3 = 1;
            TRISC4 = 1;
            SSP1ADD =   39; // 39 @ 16Mhz  = 100khz        SCL pin clock     period = ((ADD<7:0> + 1) *4)/FOSC
            OpenI2C1(MASTER,SLEW_OFF);
    #endif
#else

    I2C_CONbits.ON = 0;
    idleI2C();

     //BRG
     //   I2C_BRG = BaudRate; // 0x0C2; //( (sourceClock/i2cClock)/2 ) - 2; // 100Khz at 40Mhz PBCLK
     //  I2C3ADD =   0x09;//( (_XTAL_FREQ/100000) /4 )-1;

    I2CConfigure(I2C_MOD,   I2C_ENABLE_SMB_SUPPORT);  //I2C_ENABLE_SMB_SUPPORT
    I2CSetFrequency(I2C_MOD, GetPeripheralClock(), BaudRate);

    idleI2C();
    //I2C_CONbits.ACKDT = 0; //send ACK on recieved byte
    I2C_CONbits.STRICT = 0;
    I2C_CONbits.SMEN = 1;  //SMB bus compliant

    //enable, master, no collision
    I2C_CONbits.DISSLW = 1;  //Slew rate control disabled for Standard Speed mode (100 kHz)
    I2C_STATbits.I2COV = 0;

    I2C_CONbits.ON = 1;

     DelayMs(2);
#endif

}


bool i2cSendByte(unsigned char byte)
{
#ifdef I2C_USE_PLIB
    #ifndef HW_CFG_SENSOR
            if (I2CTransmitterIsReady(I2C_MOD))
            {
               return I2CSendByte( I2C_MOD, byte );
            }
    #else
            putcI2C(byte); 
            while(SSPSTATbits.R_NOT_W){}
            return 1;
    #endif

#else
   I2C_TRN = byte;
   int timeout = 0;
   msspWait(); //wait until byte is latched
   while (     I2C_STATbits.TRSTAT == 1) {
        timeout++;
        if ( timeout > MAX_WAIT_CYCLES) {
            return 0x00;
        }
   };
   if (  msspOVF() ||   msspBWcol() )  {  return 0; } //send failed
   else { return 1; } //success
#endif


}



 /**********  Write fixed length in page portions   *****************/
void seqWriteEE (byte deviceAddr, word Addr,  word  bytes, byte* buff)
{
#ifdef MEM_I2C_HARDWARE

    i2cSetupMaster( I2C_BRG_100kHz  ); //concurrency enable

    /*If the  master should transmit more than 64 bytes prior to
    generating the Stop condition, the address counter will
    roll over and the previously received data will be overwritten.*/

    CurrentDeviceAddr = deviceAddr;
    int pages = (int)(bytes / i2cMemPageSize);
    int singleBytes = (int) (bytes % i2cMemPageSize);

    word writeAddr = Addr;
    int pageInc = 0;

    if ( bytes >= i2cMemPageSize)
    {
        word BufferPos;
        for (pageInc = 0; pageInc < pages; pageInc++)
        {
            writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
            BufferPos = pageInc*i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
        }
        if (singleBytes > 0){
            BufferPos = pages*i2cMemPageSize;
            writeAddr += i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
        }
    }
    else
    {
        WriteSectorBytesAtAddr(Addr,buff,bytes);
    } 
#else
    i2cSetupMaster( I2C_BRG_100kHz  ); //concurrency enable

    /*If the  master should transmit more than 64 bytes prior to
    generating the Stop condition, the address counter will
    roll over and the previously received data will be overwritten.*/

    CurrentDeviceAddr = deviceAddr;
    int pages = (int)(bytes / i2cMemPageSize);
    int singleBytes = (int) (bytes % i2cMemPageSize);

    word writeAddr = Addr;
    int pageInc = 0;

    if ( bytes >= i2cMemPageSize)
    {
        word BufferPos;
        for (pageInc = 0; pageInc < pages; pageInc++)
        {
            writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
            BufferPos = pageInc*i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
        }
        if (singleBytes > 0){
            BufferPos = pages*i2cMemPageSize;
            writeAddr += i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
        }
    }
    else
    {
        WriteSectorBytesAtAddr(Addr,buff,bytes);
    }
#endif

}

void WriteSectorBytesAtAddr(word Addr, byte* buff, word bytes){
if ( IsWriteOnSectorBoundries(Addr,bytes) ){
    word buffPos;
    word SecEndAddr = GetSectorEndForWriteAddr(Addr);
    word SecBytesToEnd = SecEndAddr-Addr;
    int binc = 0;
    StartWriteAtAddr(Addr);
    for(binc=0; binc< SecBytesToEnd; binc++)
    {
        i2cSendByte(buff[binc]);
    }
    FinishSectorWrite();

    StartWriteAtAddr(Addr+SecBytesToEnd);
    word BytesToEnd = bytes - SecBytesToEnd;
    buffPos = SecBytesToEnd;
    for(binc=0; binc< BytesToEnd; binc++)
    {
        i2cSendByte(buff[buffPos+binc]);
    }
    FinishSectorWrite();
}else{
    StartWriteAtAddr(Addr);
    int binc = 0;
    for(binc=0; binc<bytes; binc++)
    {
        i2cSendByte(buff[binc]);
    }
    FinishSectorWrite();
}
}

However you will not get far without even most basic DSO. There's just too many things that can go wrong.

\$\endgroup\$
0
\$\begingroup\$

I have attached working routines that I have used in a PIC32, using the legacy library function calls in plib. It is for random read or writes from the EEPROM.

If you want to look at the source code for how plib implements these functions, you can find them in your microchip install directory of the compiler:

C:\Program Files (x86)\Microchip\xc32\v1.34\pic32-libs\peripheral\i2c\legacy

(may be a different version on your machine)

void i2c1Write(unsigned char dev_addr, unsigned char addr,unsigned char data){
    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr); // Write control byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(addr); // address byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(data); // Read Command
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    StopI2C1();
    IdleI2C1();
}

unsigned char i2c1Read(unsigned char dev_addr, unsigned char addr){
    unsigned char data;

    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr | 0); // Write control byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(addr); // write address byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?


    //initiate repeated start and read data
    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr | 1); // Issue Read Command
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    data = MasterReadI2C1(); // Read the data
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    StopI2C1();
    IdleI2C1();

    return data;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.