Problemas de interfaz PIC32 e I2C EEPROM

Estoy escribiendo código para un PIC32MX250F128B para interactuar con la EEPROM Microchip 24LC02B con interfaz I2C. Seguí muy de cerca la hoja de datos de la EEPROM, el PIC32 y la sección 24 del manual de referencia de la familia PIC32 e intenté escribir código para interactuar con la EEPROM. No tengo ningún "bloqueo" en ninguna de las pruebas para los bits que deben borrarse/establecerse después, por ejemplo. se recibe un ACK: el código se ejecuta por completo. Sin embargo, cuando compruebo el valor de la variable de datos justo al final de la función readEeprom, obtengo un carácter nulo (después de escribir una 'H' en la dirección de memoria EEPROM especificada, en modo de escritura de bytes (el código de escritura de página es comentado con #if)). Esto indica que la escritura no se realizó correctamente o que la lectura no se realizó correctamente.

No tengo acceso a un osciloscopio o analizador lógico para verificar qué sucede exactamente en las líneas SDA y SCL.

El oscilador PIC32 está configurado a 8 MHz y tenía la intención de usar una velocidad de transmisión de 100 kHz para la comunicación con la EEPROM. Entonces, usando la ecuación I2CBRG = (PBCLK/(2*FSCK))-2, como se encuentra en la sección 24 de los documentos de referencia de la familia PIC32, uso 0x26 para el valor I2CBRG.

¿Quizás alguien podría detectar si algo está mal en mi código? He intentado encontrar el problema durante un día, pero no he tenido éxito.

Aquí está mi código: /* Prueba de interfaz para EEPROM I2C con 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()*/

Agradecería mucho cualquier ayuda que alguien pueda ofrecer. Gracias de antemano.

EDITAR : Me doy cuenta de que leí mal en la hoja de datos que solo se requiere un byte de dirección de palabra (en lugar de 2 - MSByte y LSByte) para el 24LC02. Así que lo arreglé en mi código, pero sigo teniendo el mismo problema. También he usado un Arduino para escribir (con éxito) en la EEPROM y leer los datos y, por lo tanto, puedo confirmar que incluso la función writeEeprom en mi código no funciona.

Después de algunas búsquedas en Google también he leído que el periférico I2C podría dar problemas mientras el PIC está en modo de depuración, que es lo que estoy usando actualmente.


Lo último:

Resolví el problema de lectura, aunque mi método de lectura secuencial no lo está realizando de la forma prevista, pero funciona. Sin embargo, tengo problemas para escribir en la EEPROM. Mi código sigue exactamente las pautas de la hoja de datos (incluso con algunos retrasos adicionales por seguridad), pero aún no funciona. Mi función de escritura es la función llamada "writeEeprom" en el siguiente código:

/* 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

¿Puede alguien tomarse la molestia de echarle un vistazo y al menos proporcionarme algunos comentarios? Una vez más, el problema radica en la función "writeEeprom" que se llama en main().

Gracias.

¿Ha considerado usar el entorno de programación chipKIT en lugar del código PIC sin procesar? Tiene soporte I2C completo integrado al igual que Arduino. Se necesita una gran cantidad de trabajo pesado para hacer que este tipo de cosas funcionen y, en cambio, le permite continuar escribiendo su código.
No, no consideré eso (no estoy familiarizado con eso). Prefiero usar el código PIC sin formato y hacerlo funcionar de la manera correcta y comprender completamente todos los aspectos del mismo. Desde el punto de vista del desarrollo, no creo que siempre sea una buena práctica cambiar a un entorno de programación diferente solo porque el código en bruto tarda demasiado en funcionar. Por supuesto, depende de cuán compleja sea la implementación, e I2C realmente no es tan complejo como para justificar que use un entorno de programación diferente. Si esto fuera por ej. algún tipo de implementación de host USB, entonces consideraría mudarme.
Eso es bastante justo y una visión perfectamente razonable que puedo respetar. Sin embargo, tal vez podría echar un vistazo a la implementación chipKIT de Wire.h (en realidad, un envoltorio para DTWI) para ver cómo se implementa allí y ver si hay algo que se haya perdido en su implementación. A menudo es bueno comparar su programa con un código de trabajo conocido de otro lugar para ver si se ha perdido algo. Personalmente, no sé cómo implementar I2C directo en un PIC32, pero sé que hay algunas cosas que debe tener en cuenta.
Gracias Majenko. Estoy totalmente de acuerdo con usted en que se puede ver cómo se implementa en una biblioteca pública en funcionamiento. Voy a echar un vistazo a eso y ver si puedo solucionar este problema.

Respuestas (2)

Tu código se ve bien. Sin embargo, escribir un controlador por su cuenta puede llevar mucho tiempo y es propenso a errores. Microchip también proporciona bibliotecas básicas y EEPROM I2C.

¿Estás seguro de que ambas líneas tienen pull-ups (resistencias a 3V)? Sin esto, PIC no generará bits.

Aquí hay un ejemplo para trabajar con el controlador EEPROM I2C que puede usar tanto plib como hardware manual I2C en PIC32 o 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();
}
}

Sin embargo, no llegará muy lejos sin el DSO más básico. Hay demasiadas cosas que pueden salir mal.

Adjunto rutinas de trabajo que he usado en un PIC32, usando las llamadas a funciones de la biblioteca heredada en plib. Es para lecturas o escrituras aleatorias desde la EEPROM.

Si desea ver el código fuente de cómo plib implementa estas funciones, puede encontrarlas en el directorio de instalación de su microchip del compilador:

C:\Archivos de programa (x86)\Microchip\xc32\v1.34\pic32-libs\peripheral\i2c\legacy

(puede ser una versión diferente en su máquina)

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;
}