Hi all,

I'm currently developing severals samples codes (I2C, EEPROM...) for SDCC, but I have a strange problem:

First, I initialize my software I2C implementation.
SDA is on RC4, SCL is on RC3 with both 2 pull-up 2k2 resistors:

#define TRIS_SDA           TRISCbits.TRISC4
#define TRIS_SCL           TRISCbits.TRISC3

Then I set  SDA and SCL as inputs (hi Z)

TRIS_SDA = 1; 
TRIS_SCL = 1; 

finally I put SDA and SCL as low:

SDA = 0;
SCL = 0;

The problem is that SOMETIMES, SDA or SCL stay high or low event if I pull them down or up with externals resistors or 24cxxx EEPROM

I noticed the circuit works sometimes better if I put my oscilloscope probe on SDA or SCL !!

Here is a part of my code If you have any ideas, please tell me !!

----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
MAIN.C
----------------------------------------------------------------------------------------------------------------------
// Includes
#define __18F252
#include <pic18f252.h>
#include <stdio.h>

#include "..\..\Lib_pic_matt\delay.h"
#include "..\..\Lib_pic_matt\i2c_soft_sdcc.c"
#include "..\..\Lib_pic_matt\24cxxx_sdcc.c"
//-----------------------------------------------------------------------------

void main(void)
  {
  unsigned int i;

  // Wait a few ms for PIC initialisation
  for(i = 32760; i > 0; i--);

  // Port configuration (as input or outputs)
  TRISA  = 0x00;  // All PORTA pins are set as outputs
  TRISB  = 0xFF;  // All PORTA pins are set as inputs
  TRISC  = 0x81;  // All port C are outputs but RC7 (incoming RX RS232 or radio data) &

test_eeproms();
}

----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
24cxxx_sdcc.c
----------------------------------------------------------------------------------------------------------------------
#include "..\..\Lib_pic_matt\24cxxx_sdcc.c"

unsigned char test_eeproms()
{
unsigned int indx, tmp = 0;
unsigned int mydata2;
char ee_stat = 0;

print_str("\n\rVérification EEPROM I2C. Veillez patienter...\n\r");
for (indx = 0; indx <= 2047; indx+=2)
  {
  ee_stat = write16_24cxxx(indx, indx/2);
  if (ee_stat == ERR_WRITE_FAIL) {print_str("Secteur EEPROM défectueux à l'adresse : "); print_str(itoa(indx/2)); print_str("\n\r");}
  if (ee_stat == ERR_WRONG_ADDR) {print_str("Pas de réponse EEPROM (à l'adresse) : ");   print_str(itoa(indx/2)); print_str("\n\r");}
  if (ee_stat == ERR_WRITE_PROT) {print_str("EEPROM protégé en écriture secteur : ");    print_str(itoa(indx/2)); print_str("\n\r");}
  }

for (indx = 0; indx <= 2047; indx+=2)
  {
  ee_stat = read16_24cxxx(indx, &mydata2);
  if (ee_stat == ERR_WRONG_ADDR) {print_str("\n\rPas de réponse EEPROM (à l'adresse) : "); print_str(itoa(indx/2));}
  putc(' ');
  print_str(itoa(indx/2));   putc(':');
  print_str(itoa(mydata2)); putc(' ');
  }

print_str("\n\rFin du test\n\r");

return 0;
}

/////////////////////////////////////////////////////////////////////

// Read an 8 bits unsigned char from memory, address can be up to 0x7FFF (11 bits), (depending on memory used)
char read8_24cxxx(unsigned int _address, unsigned char* _data)
{
*_data = 0xFF; // default value
i2c_init();
i2c_start();
if (i2c_tx(0xA0 | ((_address>>7) & 0xE)) == 1)  return ERR_WRONG_ADDR;  // 1st @ 3 MSB; If No answers : Wrong adress ?
if (i2c_tx(_address&0xFF) == 1)  return ERR_WRONG_ADDR;                 // 2nd @ 8 LSB; If No answers : Wrong adress ?
i2c_start();
if (i2c_tx(0xA1 | ((_address>>7) & 0xE)) == 1)  return ERR_WRONG_ADDR;  // Read mode enabled; If No answers : Wrong adress ?
*_data = i2c_rx(0);                                                      // Get the data...
i2c_stop();
return OK;
}

/////////////////////////////////////////////////////////////////////

// Write an 8 bits unsigned char to memory, address can be up to 0x7FFF (11 bits), (depending on memory used)
// Verify the operation
char write8_24cxxx(unsigned int _address, unsigned char _data)
{
unsigned char data_verify = _data;

i2c_init();
i2c_start();
if (i2c_tx(0xA0 | ((_address>>7) & 0xE)) == 1)  return ERR_WRONG_ADDR;  // 1st @ 3 MSB; If No answers : Wrong adress ?
if (i2c_tx(_address&0xFF) == 1)                 return ERR_WRONG_ADDR;  // 2nd @ 8 LSB; If No answers : Wrong adress ?
if (i2c_tx(_data) == 1)                         return ERR_WRITE_PROT;  // Sends data; If no answers : write protect ?
DELAY_US(100);
i2c_stop();

DELAY_MS(10);
read8_24cxxx(_address, &_data);        // Check if _data was well written
if (data_verify == _data)  return OK;  // Check if _data was well written
else  return ERR_WRITE_FAIL;           // Check if _data was well written
}

/////////////////////////////////////////////////////////////////////

// Read an 16 bits unsigned int from memory, address can be up to 0x7FFF (11 bits), (depending on memory used)
char read16_24cxxx(unsigned int _address, unsigned int* _data)
{
unsigned char MSB = 0;
unsigned char LSB = 0;

if (read8_24cxxx(_address,   &MSB) != OK) return ERR_WRONG_ADDR; // Read MSB
if (read8_24cxxx(_address+1, &LSB) != OK) return ERR_WRONG_ADDR;   // Then read LSB
*_data = LSB|((unsigned int)MSB<<8);
return OK;
}

/////////////////////////////////////////////////////////////////////

// Write an 16 bits unsigned int from memory, address can be up to 0x7FFF (11 bits), (depending on memory used)
// Verify the operation
char write16_24cxxx(unsigned int _address, unsigned int _data)
{
char ee_stat;
ee_stat = write8_24cxxx(_address, _data>>8);          // Write MSB
if (ee_stat != OK)  return ee_stat;
ee_stat = write8_24cxxx(_address+1, _data&0x00FF);    // Then write LSB
if (ee_stat != OK)  return ee_stat;
return OK;
}

----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
i2c_soft_sdcc.c
----------------------------------------------------------------------------------------------------------------------

#include <pic18F252.h>

#include "delay.h"
#define    SDA             PORTCbits.RC4
#define    SCL             PORTCbits.RC3

#define TRIS_SDA           TRISCbits.TRISC4
#define TRIS_SCL           TRISCbits.TRISC3

/////////////////////////////////////////////////////////////////////
// Initialzation of software I2C bus
void i2c_init(void)
{
TRIS_SDA = 1;    SDA     set the output resistors to 0 and the tristate registers to 1 which disables the outputs and allows them to be pulled high by the resistors.
TRIS_SCL = 1;
DELAY_US(100);    
SDA = 0;
   DELAY_US(100);   

    DELAY_US(100);
    DELAY_US(100);
  SCL = 0;
}

/////////////////////////////////////////////////////////////////////
// Send a start sequence from software I2C bus
void i2c_start(void)
{
TRIS_SDA = 1;
TRIS_SCL = 1;
DELAY_US(100);
TRIS_SDA = 0;  // 1
DELAY_US(100);
TRIS_SCL = 0;
DELAY_US(100);             /* Start Condition */
}

/////////////////////////////////////////////////////////////////////
// Send a stop sequence from software I2C bus
void i2c_stop(void)
{
DELAY_US(100);
TRIS_SDA = 0;
DELAY_US(100);
TRIS_SCL = 1;
DELAY_US(100);
TRIS_SDA = 1;
DELAY_US(100);
}

/////////////////////////////////////////////////////////////////////
// Receive data from software I2C bus
char i2c_rx(char ack)
{
char x, d=0;

TRIS_SDA = 1;
DELAY_US(100);
for(x=0; x<8; x++)
  {
  DELAY_US(100);
  d <<= 1;
  do {TRIS_SCL = 1;}
  while(SCL==0);    // wait for any SCL clock stretching
  DELAY_US(100);
  if(SDA) d |= 1;
  TRIS_SCL = 0;
  }
DELAY_US(100);

if(ack) TRIS_SDA = 0;
else   TRIS_SDA = 1;
DELAY_US(100);
TRIS_SCL = 1;
DELAY_US(100);             // send (N)ACK bit
TRIS_SCL = 0;
DELAY_US(100);
TRIS_SDA = 1;
DELAY_US(100);
return d;
}

/////////////////////////////////////////////////////////////////////
// Send data from software I2C bus
char i2c_tx(unsigned char d)
{
char x;
static unsigned char b;
for(x=8; x; x--)
  {
  if(d&0x80) TRIS_SDA = 1;
  else TRIS_SDA = 0;
  DELAY_US(100);
  TRIS_SCL = 1;
  DELAY_US(100);
  d <<= 1;
  TRIS_SCL = 0;
  DELAY_US(100);
  }
TRIS_SDA = 1;
DELAY_US(100);
TRIS_SCL = 1;
DELAY_US(100);

b = SDA;          // possible ACK bit
TRIS_SCL = 0;
return b;
}

Thanks for your help!

Matthieu