LPC1768 slave issues a STOP condition without waiting for master
This forum topic has been closed.
Topic last updated
01 Mar 2016, by
Austin Blackstone.
4
replies
ravibamidi_csr
#
07 Nov 2014
It seems LPC1768 I2C slave is issuing STOP too early when the size of data to be read in i2c_slave_read API is same as the size of data transmitted by a master.
Details of the issue in comments inline.
Usage
LPC1768 device is used as a SLAVE and Master transmits 256 byte chunks.
ret = i2c_slave_read(&i2c_slave, rx_buffer, 256); // Master is sending exactly 256 bytes.
Existing i2c_slave_read code
int i2c_slave_read(i2c_t *obj, char *data, int length) {
int count = 0;
int status;
do {
i2c_clear_SI(obj);
i2c_wait_SI(obj);
status = i2c_status(obj);
if((status == 0x80) || (status == 0x90)) {
data[count] = I2C_DAT(obj) & 0xFF;
}
count++;
} while (((status == 0x80) || (status == 0x90) ||
(status == 0x060) || (status == 0x70)) && (count < length));
// When length is same as data transmitted by master, above loop breaks after last byte read.
// In the code below, we are checking old status which is read in the loop.
// This might be reflecting old status which won't reflect matser's STOP.
// Slave forcibly issued a STOP condition which will overwrite the ACK sent
// if processor runs with higher speed than I2C bus.
// See Image - 1
if(status != 0xA0) {
i2c_stop(obj);
}
i2c_clear_SI(obj);
return count;
}

Suggested Modification to i2c_slave_read
int i2c_slave_read(i2c_t *obj, char *data, int length) {
int count = 0;
int status;
do {
i2c_clear_SI(obj);
i2c_wait_SI(obj);
status = i2c_status(obj);
if((status == 0x80) || (status == 0x90)) {
data[count] = I2C_DAT(obj) & 0xFF;
}
count++;
} while (((status == 0x80) || (status == 0x90) ||
(status == 0x060) || (status == 0x70)) && (count < length));
// Clear old status and wait for Serial Interrupt.
i2c_clear_SI(obj);
i2c_wait_SI(obj);
// Obtain new status. (See Image-2)
status = i2c_status(obj);
if(status != 0xA0) {
i2c_stop(obj);
}
i2c_clear_SI(obj);
return count;
}

Hello,
to be able to track this, we should create a new issue on github mbed SDK repository. Can you do that, and point to this bug report? Link https://github.com/mbedmicro/mbed/issues
Looks like you have provided even a fix for the issue, thanks !
Regards,
0xc0170
ravibamidi_csr
#
07 Nov 2014
My savior, now my project works!
I get mad with my code and config beliving that it was my fault, thank you!
Marking this topic closed as the pull request has been merged into mainline library.
It seems LPC1768 I2C slave is issuing STOP too early when the size of data to be read in i2c_slave_read API is same as the size of data transmitted by a master.
Details of the issue in comments inline.
Usage
LPC1768 device is used as a SLAVE and Master transmits 256 byte chunks.
Existing i2c_slave_read code
int i2c_slave_read(i2c_t *obj, char *data, int length) { int count = 0; int status; do { i2c_clear_SI(obj); i2c_wait_SI(obj); status = i2c_status(obj); if((status == 0x80) || (status == 0x90)) { data[count] = I2C_DAT(obj) & 0xFF; } count++; } while (((status == 0x80) || (status == 0x90) || (status == 0x060) || (status == 0x70)) && (count < length)); // When length is same as data transmitted by master, above loop breaks after last byte read. // In the code below, we are checking old status which is read in the loop. // This might be reflecting old status which won't reflect matser's STOP. // Slave forcibly issued a STOP condition which will overwrite the ACK sent // if processor runs with higher speed than I2C bus. // See Image - 1 if(status != 0xA0) { i2c_stop(obj); } i2c_clear_SI(obj); return count; }Suggested Modification to i2c_slave_read
int i2c_slave_read(i2c_t *obj, char *data, int length) { int count = 0; int status; do { i2c_clear_SI(obj); i2c_wait_SI(obj); status = i2c_status(obj); if((status == 0x80) || (status == 0x90)) { data[count] = I2C_DAT(obj) & 0xFF; } count++; } while (((status == 0x80) || (status == 0x90) || (status == 0x060) || (status == 0x70)) && (count < length)); // Clear old status and wait for Serial Interrupt. i2c_clear_SI(obj); i2c_wait_SI(obj); // Obtain new status. (See Image-2) status = i2c_status(obj); if(status != 0xA0) { i2c_stop(obj); } i2c_clear_SI(obj); return count; }