i2c slave clock stretching

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i2c slave clock stretching

2,942 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dpa on Mon Aug 06 01:48:25 MST 2012
Hi there,

I'm trying to reliably read data from an i2c master, using the i2c slave example code from nxp. I'm getting data back, now I need to work out how to process it reliably... The master (a gps) sends out text strings by default from initialisation (NMEA for those in the know). The master sends each string followed by a Stop condition. I deduced that the receipt of the stop meant I have a message-worth of data in the i2c read buffer. The spec for i2c says that if the slave requires time for data processing it should stretch the clock by holding SCL low until it is ready for more data (I2C-bus specification and user manual, UM-10204, 3.1.5). The LPC User Manual (UM-10398, p234) says in order to stretch the clock, the SI flag in the CON register should be set. So I presumed that meant I could copy a message in the interrupt handler for later process, by doing it before clearing the SI flag, which all the i2c states in the handler do, presumably to acknowledge the irq. I modified the code thus:
...
    case 0xA0:
        /* Stop condition or repeated start has */
        LPC_I2C->CONSET = I2CONSET_AA; /* been received, assert ACK.  */
        if (BufIndex < NBUFS) {
            memcpy(&bufs[BufIndex], (void*)I2CRdBuffer, RdIndex);
            bufs[BufIndex][RdIndex] = '\0';
            ++BufIndex;
        }
        LPC_I2C->CONCLR = I2CONCLR_SIC;
        I2CSlaveState = I2C_IDLE;
        break;
...
(in main)
    for (i = 0; i < NBUFS; ++i) {
        debug_printf("|%s| (%u)\n", bufs, strlen((void*)bufs));
    }
but when I examine the buffer afterwards, it is not consistent. Each message should start with a '$', and end with '*<x>', where x is a checksum byte. For example:

Quote:
...
|

| (2)
|$GPGSV,3,1,12,18,00,000,28,27,00,000,31,01,00,000,,02,00,000,*7F$GPGSV,3,2,12,03,00,000,,04,00,000,,05,00,000,,06,00,000,*7F

| (66)
...

I can believe the first print is a message we started reading half-way through, so is not complete, but the next message is oddly corrupt. strlen believes it to be 66 bytes long, but printf has printed more than that, as if the irq handler was still incrementing RdIndex when we where trying to copy the string? Or something...  Ideally I'd like to be able to reliably pause the i2c while I collect the data, and then have it reliably continue. Can anyone share any insight?

Thanks in advance.
0 Kudos
Reply
4 Replies

2,482 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dpa on Mon Aug 06 23:36:10 MST 2012
Thanks for that - why do you say reduce the buffer size? I get the data in bursts, I think too quickly to do anything useful on a per-character basis - after I get a full buffer I have time to process the message... and the strings are largely >64 bytes... so I'm not sure what value I would derive from reducing the size of the buffer (I've currently got BUFSIZE set to 128..)

All the best,
dpa
0 Kudos
Reply

2,482 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by researchinnovation on Mon Aug 06 21:21:50 MST 2012
Hi...!!!

Please keep size of buffer 32, it will work fine. Try with 8 also.


Thanks & Regards....:)
0 Kudos
Reply

2,482 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by atomicdog on Mon Aug 06 10:28:09 MST 2012
How slowly are you running the ARM?
Are you trying to consume the data in bufs inside main() without knowing if the message is complete?
0 Kudos
Reply

2,482 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dpa on Mon Aug 06 10:19:17 MST 2012
Answered it myself, sorry...

I believe there's nothing wrong with the logic of clock stretching, the corruption was due to the default i2c buffer size being too small. Oops.
0 Kudos
Reply