softi2c_master: add timeout to prevent infinite loop
This commit is contained in:
parent
04901a6ce1
commit
52d130a832
|
@ -19,10 +19,16 @@
|
|||
// half period to wait for I²C clock
|
||||
static uint16_t period = 0;
|
||||
|
||||
// port for data line
|
||||
#define SDA_PORT GPIO_PB
|
||||
// pin for data line
|
||||
#define SDA_PIN PB5
|
||||
// port for clock line
|
||||
#define SCL_PORT GPIO_PB
|
||||
// pin for clock line
|
||||
#define SCL_PIN PB4
|
||||
// operation timeout (in half period)
|
||||
#define TIMEOUT 10U
|
||||
|
||||
// delay for half a period
|
||||
static void I2C_delay(void)
|
||||
|
@ -84,7 +90,7 @@ bool softi2c_master_setup(uint16_t freq_khz)
|
|||
SDA_PORT->CR1.reg &= ~SDA_PIN; // use in open-drain mode
|
||||
|
||||
I2C_delay(); // give time to get high
|
||||
return (read_SCL() && read_SDA());
|
||||
return (read_SCL() && read_SDA()); // line is ready when the two lines are high
|
||||
}
|
||||
|
||||
void softi2c_master_release(void)
|
||||
|
@ -104,7 +110,14 @@ bool softi2c_master_start(void)
|
|||
set_SDA();
|
||||
I2C_delay();
|
||||
set_SCL();
|
||||
while (read_SCL() == 0); // Clock stretching
|
||||
uint8_t timeout = TIMEOUT;
|
||||
while (read_SCL() == 0 && timeout) { // Clock stretching
|
||||
I2C_delay();
|
||||
timeout--;
|
||||
}
|
||||
if (0 == timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Repeated start setup time, minimum 4.7us
|
||||
I2C_delay();
|
||||
|
@ -130,7 +143,14 @@ bool softi2c_master_stop(void)
|
|||
I2C_delay();
|
||||
|
||||
set_SCL();
|
||||
while (read_SCL() == 0); // Clock stretching
|
||||
uint8_t timeout = TIMEOUT;
|
||||
while (read_SCL() == 0 && timeout) { // Clock stretching
|
||||
I2C_delay();
|
||||
timeout--;
|
||||
}
|
||||
if (0 == timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_delay(); // Stop bit setup time, minimum 4us
|
||||
|
||||
|
@ -158,7 +178,15 @@ static bool softi2c_master_write_bit(bool bit) {
|
|||
I2C_delay(); // SDA change propagation delay
|
||||
set_SCL(); // Set SCL high to indicate a new valid SDA value is available
|
||||
I2C_delay(); // Wait for SDA value to be read by slave, minimum of 4us for standard mode
|
||||
while (read_SCL() == 0); // Clock stretching
|
||||
uint8_t timeout = TIMEOUT;
|
||||
while (read_SCL() == 0 && timeout) { // Clock stretching
|
||||
I2C_delay();
|
||||
timeout--;
|
||||
}
|
||||
if (0 == timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SCL is high, now data is valid
|
||||
if (bit && (read_SDA() == 0)) { // If SDA is high, check that nobody else is driving SDA
|
||||
return false;
|
||||
|
@ -173,7 +201,14 @@ static bool softi2c_master_read_bit(void) {
|
|||
set_SDA(); // Let the slave drive data
|
||||
I2C_delay(); // Wait for SDA value to be written by slave, minimum of 4us for standard mode
|
||||
set_SCL(); // Set SCL high to indicate a new valid SDA value is available
|
||||
while (read_SCL() == 0); // Clock stretching
|
||||
uint8_t timeout = TIMEOUT;
|
||||
while (read_SCL() == 0 && timeout) { // Clock stretching
|
||||
I2C_delay();
|
||||
timeout--;
|
||||
}
|
||||
if (0 == timeout) {
|
||||
return false;
|
||||
}
|
||||
I2C_delay(); // Wait for SDA value to be written by slave, minimum of 4us for standard mode
|
||||
const bool bit = read_SDA(); // SCL is high, read out bit
|
||||
clear_SCL(); // Set SCL low in preparation for next operation
|
||||
|
|
Loading…
Reference in New Issue