0
\$\begingroup\$

I have an existing PCB that is no longer supported by the manufacturer and has been plagued with software issues for years. So i don't have much control over how the board is laid out and what components are used.

The board has a PIC16F747 running on the internal oscillator at 8Mhz, and a 24AA01 EEPROM chip with 1k ohm pullups (to 5v).

I have had no problem with any other aspects of the PIC, ive got ADC and PWM working fine but i just cannot get I2C communication to work as expected.

All I2C commands are being accepted but I'm not getting the data i have written back as I expected.

I know the EEPROM is working as i can interface with the chip using a AVR MCU using a PCB header that has connections to the I2C bus.

The next port of call is for me to invest in a oscilloscope or I2C buss sniffer so i can actually see what is being sent.

Here is some stripped down code of what I'm trying to achieve.

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on OSC1/CLKI/RA7 and OSC2/CLKO/RA6)
#pragma config WDTE = OFF        // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR/VPP/RE3 Pin Function Select bit (MCLR/VPP/RE3 pin function is digital input only, MCLR gated to '1')
#pragma config BOREN = ON       // Brown-out Reset Enable bit (Enabled)
#pragma config BORV = 20        // Brown-out Reset Voltage bits (VBOR set to 2.0V)
#pragma config CCP2MX = RC1     // CCP2 Multiplex bit (CCP2 is on RC1)
#pragma config CP = OFF         // Flash Program Memory Code Protection bits (Code protection off)

// CONFIG2
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode enabled)
#pragma config BORSEN = ON      // Brown-out Reset Software Enable bit (Enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.



#define _XTAL_FREQ 8000000

#include <xc.h>

void i2c_wait(){
    while (!SSPIF);
    SSPIF = 0;

    while ((SSPCON2 & 0b00011111)    ||    (SSPSTAT & 0b00000100));
}


int address = 0x01; // Address to write to
int value = 0x11; // Value to write
int result = 0x00; // Result returned from SSPBUF

void main(void) {

    // Set Internal Oscillator to 8Mhz
    OSCCONbits.IRCF = 0x7;


    // Setup EEPROM Write Enable
    TRISA4 = 0;
    RA4 = 0;

    // Setup output for testing
    TRISD6 = 0;
    RD6 = 0;

    // Set SDA & SCL to  inputs
    TRISC3 = 1;
    TRISC4 = 1;


    SSPCONbits.SSPM = 0x8; // i2c Master mode
    SSPADD = 4; // Set Clock for 400k
    SSPEN = 1; // Enable SSP Module

    while(1)        
    {       
        // Init Interrupt
        SSPIF = 0;

        // Write Data
        // Start    
        SEN = 1;        
        i2c_wait();
        // Send Addres + W      
        SSPBUF = 0xA0;
        i2c_wait();
        // Send EEPROM Address      
        SSPBUF = address;
        i2c_wait();
        // Send Data to set in address      
        SSPBUF = value;
        i2c_wait();
        // Send Stop        
        PEN = 1;
        i2c_wait();     

        // Let EEPROM Settle
        __delay_ms(10);

        // Read Data
        // Start
        SEN = 1;
        i2c_wait();
        // Send Address + W 
        SSPBUF = 0xA0;
        i2c_wait();
        // Send EEPROM Address      
        SSPBUF = address;
        i2c_wait();
        // Repeat Start     
        RSEN = 1;
        i2c_wait();
        // Send Address + R     
        SSPBUF = 0xA1;
        i2c_wait();
        // Read Data        
        RCEN = 1;
        i2c_wait();
        result = (SSPBUF);
        // Set NACK     
        ACKDT = 1;
        ACKEN = 1;
        i2c_wait();
        // Stop     
        PEN = 1;
        i2c_wait();                             


        // Let see what we got then!
        if (result < 0x22){
            RD6 = 1;
        } 
        else
        {
            RD6 = 0;
        }

        // Settle 
        __delay_ms(10);

    }   
    return; 
}
```
\$\endgroup\$
  • \$\begingroup\$ increase the VDD from 4.0 volts, in 0.1 volt steps, to 5.5 volts. And touch a 100pF capacitor, from GND to each wire in the I2C data link, to detect timing and bandwidth and overshoot issues. \$\endgroup\$ – analogsystemsrf Oct 22 at 9:58
  • 1
    \$\begingroup\$ In complement to @analogsystemsrf - I agree that the problem might be hardware related - measure your signals, share a scope trace clearly showing rise times and voltage levels. I've had an experience where my code was blamed for a long time and after many hence and forths I finally got the détailed graphs. The ultimate issue was that the overall pull up in the customer's system was too small and one of the drivers could not pull it down enough for their uC - it involved an EEPROM that was not working! \$\endgroup\$ – le_top Oct 22 at 10:08
  • 1
    \$\begingroup\$ You really shouldn't be using the "naive" default data types like int. Particularly not on a 8 bit MCU. Use the types of stdint.h and use uint8_t whenever possible. \$\endgroup\$ – Lundin Oct 22 at 12:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.