I2C: add bus error checks
This commit is contained in:
parent
9ddb85bdcb
commit
ebcaf5723e
|
@ -293,9 +293,14 @@ enum i2c_master_rc i2c_master_start(uint32_t i2c)
|
||||||
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
|
return I2C_MASTER_RC_START_STOP_IN_PROGESS;
|
||||||
}
|
}
|
||||||
i2c_send_start(i2c); // send start condition to start transaction
|
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) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until start condition has been accepted and cleared
|
||||||
while ((I2C_CR1(i2c) & I2C_CR1_START)); // wait until start condition is accepted and cleared
|
if (I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO)) {
|
||||||
while (!(I2C_SR1(i2c) & I2C_SR1_SB)); // wait until start condition is transmitted
|
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
|
if (!(I2C_SR2(i2c) & I2C_SR2_MSL)) { // verify if in master mode
|
||||||
return I2C_MASTER_RC_NOT_MASTER;
|
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
|
if (!address_10bit) { // 7-bit address
|
||||||
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
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
|
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
|
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
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
|
// send first part of address
|
||||||
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
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)
|
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
|
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
return I2C_MASTER_RC_NAK;
|
||||||
}
|
}
|
||||||
// send second part of address
|
// send second part of address
|
||||||
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
||||||
I2C_DR(i2c) = (slave&0xff); // send remaining of address
|
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
|
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
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
|
// send first part of address with receive flag
|
||||||
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
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)
|
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
|
if (I2C_SR1(i2c) & I2C_SR1_AF) { // address has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
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 {
|
} else {
|
||||||
i2c_enable_ack(i2c); // ACK received byte to continue slave transmission
|
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
|
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
|
for (size_t i=0; i<data_size; i++) { // write bytes
|
||||||
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
I2C_SR1(i2c) &= ~(I2C_SR1_AF); // clear acknowledgement failure
|
||||||
i2c_send_data(i2c, data[i]); // send byte to be written in memory
|
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
|
if (I2C_SR1(i2c) & I2C_SR1_AF) { // data has not been acknowledged
|
||||||
return I2C_MASTER_RC_NAK;
|
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
|
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_CR1(i2c) & I2C_CR1_STOP) && !(I2C_SR1(i2c) & (I2C_SR1_BERR|I2C_SR1_ARLO))); // wait until stop condition is accepted and cleared
|
||||||
while ((I2C_SR2(i2c) & I2C_SR2_MSL)); // wait until bus released (non master mode)
|
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;
|
return I2C_MASTER_RC_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ enum i2c_master_rc {
|
||||||
I2C_MASTER_RC_NOT_RECEIVE, /**< not in receive mode */
|
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_NOT_READY, /**< slave is not read (previous operations has been nacked) */
|
||||||
I2C_MASTER_RC_NAK, /**< not acknowledge received */
|
I2C_MASTER_RC_NAK, /**< not acknowledge received */
|
||||||
|
I2C_MASTER_RC_BUS_ERROR, /**< an error on the I2C bus occurred */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** setup I2C peripheral
|
/** setup I2C peripheral
|
||||||
|
@ -42,7 +43,8 @@ void i2c_master_setup(uint32_t i2c, uint16_t frequency);
|
||||||
*/
|
*/
|
||||||
void i2c_master_release(uint32_t i2c);
|
void i2c_master_release(uint32_t i2c);
|
||||||
/** reset I2C peripheral, fixing any locked state
|
/** 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
|
* @param[in] i2c I2C base address
|
||||||
*/
|
*/
|
||||||
void i2c_master_reset(uint32_t i2c);
|
void i2c_master_reset(uint32_t i2c);
|
||||||
|
|
Loading…
Reference in New Issue