I2C: add bus error checks

This commit is contained in:
King Kévin 2018-04-03 15:41:31 +02:00
parent 9ddb85bdcb
commit ebcaf5723e
2 changed files with 40 additions and 12 deletions

View File

@ -293,9 +293,14 @@ enum i2c_master_rc i2c_master_start(uint32_t i2c)
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
}
i2c_send_start(i2c); // send start condition to start transaction
while (I2C_CR1(i2c) & I2C_CR1_START); // wait until start condition has been accepted and cleared
while ((I2C_CR1(i2c) & I2C_CR1_START)); // wait until start condition is accepted and cleared
while (!(I2C_SR1(i2c) & I2C_SR1_SB)); // wait until start condition is transmitted
while ((I2C_CR1(i2c) & I2C_CR1_START) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until start condition has been accepted and cleared
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
while (!(I2C_SR1(i2c) & I2C_SR1_SB) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until start condition is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // verify if in master mode
return I2C_MASTER_RC_NOT_MASTER;
}
@ -325,7 +330,10 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
if (!address_10bit) { // 7-bit address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
i2c_send_7bit_address(i2c, slave, write ? I2C_WRITE : I2C_READ); // select slave, with read/write flag
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF))); // wait until address is transmitted
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
}
@ -333,14 +341,17 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
// send first part of address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = 11110000 | (((slave>>8)&0x3)<<1); // send first header (11110xx0, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADD10|I2C_SR1_AF))); // wait until first part of address is transmitted
while (!(I2C_SR1(i2c) & (I2C_SR1_ADD10|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until first part of address is transmitted
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
}
// send second part of address
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = (slave&0xff); // send remaining of address
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF))); // wait until remaining part of address is transmitted
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
}
@ -353,7 +364,10 @@ enum i2c_master_rc i2c_master_select_slave(uint32_t i2c, uint16_t slave, bool ad
// send first part of address with receive flag
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
I2C_DR(i2c) = 11110001 | (((slave>>8)&0x3)<<1); // send header (11110xx1, where xx are 2 MSb of slave address)
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF))); // wait until remaining part of address is transmitted
while (!(I2C_SR1(i2c) & (I2C_SR1_ADDR|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until remaining part of address is transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
return I2C_MASTER_RC_NAK;
}
@ -400,7 +414,10 @@ enum i2c_master_rc i2c_master_read(uint32_t i2c, uint8_t* data, size_t data_size
} else {
i2c_enable_ack(i2c); // ACK received byte to continue slave transmission
}
while (!(I2C_SR1(i2c) & I2C_SR1_RxNE)); // wait until byte has been received
while (!(I2C_SR1(i2c) & I2C_SR1_RxNE) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until byte has been received
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
data[i] = i2c_get_data(i2c); // read received byte
}
@ -432,7 +449,10 @@ enum i2c_master_rc i2c_master_write(uint32_t i2c, const uint8_t* data, size_t da
for (size_t i=0; i<data_size; i++) { // write bytes
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
i2c_send_data(i2c, data[i]); // send byte to be written in memory
while (!(I2C_SR1(i2c) & (I2C_SR1_TxE|I2C_SR1_AF))); // wait until byte has been transmitted
while (!(I2C_SR1(i2c) & (I2C_SR1_TxE|I2C_SR1_AF)) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until byte has been transmitted
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
if (I2C_SR1(i2c) & I2C_SR1_AF) { // data has not been acknowledged
return I2C_MASTER_RC_NAK;
}
@ -458,8 +478,14 @@ enum i2c_master_rc i2c_master_stop(uint32_t i2c)
}
i2c_send_stop(i2c); // send stop to release bus
while ((I2C_CR1(i2c) & I2C_CR1_STOP)); // wait until stop condition is accepted and cleared
while ((I2C_SR2(i2c) & I2C_SR2_MSL)); // wait until bus released (non master mode)
while ((I2C_CR1(i2c) & I2C_CR1_STOP) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until stop condition is accepted and cleared
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
while ((I2C_SR2(i2c) & I2C_SR2_MSL) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until bus released (non master mode)
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
return I2C_MASTER_RC_BUS_ERROR;
}
return I2C_MASTER_RC_NONE;
}

View File

@ -29,6 +29,7 @@ enum i2c_master_rc {
I2C_MASTER_RC_NOT_RECEIVE, /**< not in receive mode */
I2C_MASTER_RC_NOT_READY, /**< slave is not read (previous operations has been nacked) */
I2C_MASTER_RC_NAK, /**< not acknowledge received */
I2C_MASTER_RC_BUS_ERROR, /**< an error on the I2C bus occurred */
};
/** setup I2C peripheral
@ -42,7 +43,8 @@ void i2c_master_setup(uint32_t i2c, uint16_t frequency);
*/
void i2c_master_release(uint32_t i2c);
/** reset I2C peripheral, fixing any locked state
* @note to be used after failed start and stop
* @warning the I2C peripheral needs to be re-setup
* @note to be used after failed start or stop, and bus error
* @param[in] i2c I2C base address
*/
void i2c_master_reset(uint32_t i2c);