I2C: fix read NACK

NACKing in receive mode is different when 1, 2, or more bytes are
read.
see the reference manual for the cases and how to handle them.
This commit is contained in:
King Kévin 2019-03-26 18:12:21 +01:00
parent bf2eca0401
commit a50a181b86
2 changed files with 18 additions and 2 deletions

View File

@ -417,7 +417,18 @@ enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size
// sanity check
if (data==NULL || data_size==0) { // no data to read
return I2C_MASTER_RC_NONE;
}
}
if (1 == data_size) {
i2c_nack_current(i2c); // [N]ACK current byte
i2c_disable_ack(i2c); // NACK after first byte
} else if (2 == data_size) {
i2c_nack_next(i2c); // [N]ACK next byte
i2c_enable_ack(i2c); // NACK first byte
} else {
i2c_nack_current(i2c); // ACK current byte
i2c_enable_ack(i2c); // NAK after next byte
}
// reading SR2 will also also clear ADDR and start the transaction
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // I2C device is not master
return I2C_MASTER_RC_NOT_MASTER;
}
@ -430,7 +441,11 @@ enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size
// read data
for (size_t i=0; i<data_size; i++) { // read bytes
if (i==data_size-1) { // prepare to sent NACK for last byte
if (2 == data_size - i) { // prepare to sent NACK for second last byte
i2c_nack_next(i2c); // NACK next byte
i2c_disable_ack(i2c); // NACK received to stop slave transmission
} else if (1 == data_size - i) { // prepare to sent NACK for last byte
i2c_nack_current(i2c); // ACK current byte
i2c_disable_ack(i2c); // NACK received to stop slave transmission
} else {
i2c_enable_ack(i2c); // ACK received byte to continue slave transmission

View File

@ -73,6 +73,7 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
* @param[in] i2c I2C base address
* @param[out] data array to store bytes read
* @param[in] data_size number of bytes to read
* @note the last read byte is NACKed, but the I2C peripheral will clock the read for at least 2 more bytes after the NACK
* @return I2C return code
*/
enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size);