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