CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

i2c_start(); i2c_write(ADDRESS) no ack!

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
valemike
Guest







i2c_start(); i2c_write(ADDRESS) no ack!
PostPosted: Thu May 12, 2005 2:53 pm     Reply with quote

99.99% of the time, when I do an i2c_start(); followed by an i2c_write();, then there is an 'ack' returned by the slave.

Once in a great while, I don't get the ACK. The ACK is generated in hardware automatically, right? Thus there is no software intervention by the i2c slave PIC to send an 'ack' on the 9th bit following an address match.

I only have two devices on the i2c bus - one master PIC and one slave PIC.

What would cause this ACK from the slave to master to fail once in a rare while? A delayed slave isr perhaps??

i2c_start();
ack = i2c_write(address);
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Fri May 13, 2005 12:26 pm     Reply with quote

Quote:

The ACK is generated in hardware automatically, right? Thus there is no software intervention by the i2c slave PIC to send an 'ack' on the 9th bit following an address match.


Assuming this you are right but, your i2c_write() handler (Master side)
normally doesn´t check this condition.

Quote:

I only have two devices on the i2c bus - one master PIC and one slave PIC.


In this case the Slave may be servicing an interrupt (just before sending
the ACK) that insert an unexpected delay which hold off the master in the
middle of a transaction using what's called a clock stretching (the slave
keeps SCL pulled low until it's ready to continue). Most I2C slave devices
don't use this feature but in this case the Slave is another PIC.

What I know is that every Master should support this condition.
To workaround: add a 10-15ms delay after the i2c_stop() in the
i2c_write() routine and tell us your result.

Best wishes,

Humberto
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon May 16, 2005 2:09 pm     Reply with quote

I, personally, hate using delay statements in my code especially in I2C routines. It's like having the processor twiddle it's thumbs while it could be doing something productive. I like using something like this:

Code:

if(!i2c_write(address))
{
  do i2c stuff here
}


If the i2c_write() returns an ACK then the rest of the sequence can be done. If it returns a NOACK then you could have it loop on it until it does or until a counter times out, just so you don't get stuck there forever. I've seen devices not ACK back for whatever reason and hitting it again had it ACK the second time.

Ronald
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon May 16, 2005 8:02 pm     Reply with quote

Quote:
Assuming this you are right but, your i2c_write() handler (Master side)
normally doesn´t check this condition.



Well it should if you are a good coder! And Mike is checking:
Code:
ack = i2c_write(address);


BTW, this is the way you should check to see if devices are ready. People usually just stick delays in there to try and make it work. That is just plain bad programming if you ask me and you are just asking for trouble in the long run. Just wait until your buyers change vendors on an eeprom and your code no longer works.

Quote:
In this case the Slave may be servicing an interrupt (just before sending
the ACK) that insert an unexpected delay which hold off the master in the
middle of a transaction using what's called a clock stretching (the slave
keeps SCL pulled low until it's ready to continue). Most I2C slave devices
don't use this feature but in this case the Slave is another PIC.
Clock stretching doesn't have anything to do with not receiving ACKS. Don't know why you think slave devices don't use clock stretching. Well they do, they are just really fast so you probably wouldn't notice it.

Quote:
What I know is that every Master should support this condition.
To workaround: add a 10-15ms delay after the i2c_stop() in the
i2c_write() routine and tell us your result.
Not necessary and just plain wastes time. rnielsen has the right idea.



Code:

/* *************************************************************************
  Useful defines for writing to the I2C bus
 *************************************************************************** */
#define I2C_IDLE()  while ((SSPCON2 & 0x1F) || (SSPSTATbits.R_W))
#define I2C_START() \
  SSPCON2bits.SEN = 1; \
while (SSPCON2bits.SEN) \
{ \
  _asm nop _endasm \
}

#define I2C_RESTART() \
  SSPCON2bits.RSEN = 1; \
  while (SSPCON2bits.RSEN) \
  { \
    _asm nop _endasm \
  }

#define I2C_STOP() \
  SSPCON2bits.PEN = 1; \
  while (SSPCON2bits.PEN) \
  { \
    _asm nop _endasm \
  }

#define I2C_WRITE(x) \
  SSPBUF = (x); \
  while (SSPSTATbits.BF) \
  { \
    _asm nop _endasm \
  } \
  I2C_IDLE()
#define I2C_READ(x) \
  SSPCON2bits.RCEN = 1; \
  while (SSPCON2bits.RCEN) \
  { \
    _asm nop _endasm \
  } \
  SSPCON2bits.ACKDT = (x); \
  SSPCON2bits.ACKEN = 1; \
  while (SSPCON2bits.ACKEN) \
  { \
    _asm nop _endasm \
  }
/* *************************************************************************
  DESCRIPTION:  This function checks to see if an i2c device will ACK

  RETURN: TRUE if device ACKed otherwise FALSE

  ALGORITHM:  none

  NOTES:  none
 *************************************************************************** */
static bool I2C_Device_Ready(
  uint8_t id) /* FIX ME: add comment */
{
  do
  {
    /* Important to clear these bits before we attempt to write */
    PIR2bits.BCLIF = 0;
    SSPCON1bits.WCOL = 0;
    I2C_IDLE();             /* ensure module is idle */
    I2C_START();
  } while (PIR2bits.BCLIF);

  I2C_WRITE(id);

  if (!SSPCON2bits.ACKSTAT) /* test for ACK condition, if received */
    return (TRUE);
  return (FALSE);
}

/* *************************************************************************
  DESCRIPTION:  This function writes the passed data to the specified
                address of the serial eeprom.

  RETURN: none

  ALGORITHM:  none

  NOTES:  none
 *************************************************************************** */
void I2C_Write_Byte(
  uint8_t   device,   /* I2C address of the device that we are writing to */
  uint8_t   data,     /* byte written to seeprom */
  uint16_t  address)  /* SEEPROM address to write data */
{
  uint8_t control;

  /* MSB if address > 0xFF. Should be in bit1 */
  control = device | ((uint8_t) (address >> 8) << 1);

  while (!I2C_Device_Ready(control));
  I2C_WRITE((uint8_t) address);
  I2C_WRITE(data);
  I2C_STOP();
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group