mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Fix FIR I2C bus arbitration lost error.
* If the FIR I2C bus is interrupted during a read/write the I2C device misbehaves and gets stuck pulling SDA low and the next time the device is re-initialized the I2C controller detects an arbitration lost condition. * The most affected sensor seems to be the AMG8833 on the F4, F7 and H7 micros and the MLX90640 on the F4 mirco. * Add a function to switch SCL to GPIO and pulse SCL at ~100KHz to attempt to unstuck the I2C device, it will attempt this one time before giving up. * This seems to work very well on all the tested micro-controllers.
This commit is contained in:
parent
882dcabd94
commit
fce5c9016d
@ -98,7 +98,7 @@ static uint8_t height = 0;
|
|||||||
static uint8_t IR_refresh_rate = 0;
|
static uint8_t IR_refresh_rate = 0;
|
||||||
static uint8_t ADC_resolution = 0;
|
static uint8_t ADC_resolution = 0;
|
||||||
|
|
||||||
static I2C_HandleTypeDef fir_i2c = {0}; // SCCB/I2C bus.
|
static I2C_HandleTypeDef fir_i2c = {0}; // FIR/I2C bus.
|
||||||
|
|
||||||
static enum {
|
static enum {
|
||||||
FIR_NONE,
|
FIR_NONE,
|
||||||
@ -115,6 +115,29 @@ static void test_ack(int ret)
|
|||||||
PY_ASSERT_TRUE_MSG(ret == 0, "I2C Bus communication error - missing ACK!");
|
PY_ASSERT_TRUE_MSG(ret == 0, "I2C Bus communication error - missing ACK!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void generate_scl_train()
|
||||||
|
{
|
||||||
|
// Configure SCL as GPIO
|
||||||
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||||
|
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
|
||||||
|
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||||
|
GPIO_InitStructure.Pin = FIR_I2C_SCL_PIN;
|
||||||
|
HAL_GPIO_Init(FIR_I2C_PORT, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
// Pulse SCL to recover stuck device.
|
||||||
|
for (int i=0; i<10000; i++) {
|
||||||
|
HAL_GPIO_WritePin(FIR_I2C_PORT, FIR_I2C_SCL_PIN, GPIO_PIN_SET);
|
||||||
|
mp_hal_delay_us(10);
|
||||||
|
HAL_GPIO_WritePin(FIR_I2C_PORT, FIR_I2C_SCL_PIN, GPIO_PIN_RESET);
|
||||||
|
mp_hal_delay_us(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear ARLO flag if it's set.
|
||||||
|
__HAL_I2C_CLEAR_FLAG(&fir_i2c, I2C_FLAG_ARLO);
|
||||||
|
debug_printf("reset stuck i2c device\n");
|
||||||
|
}
|
||||||
|
|
||||||
static float calculate_Ta() // ambient temp
|
static float calculate_Ta() // ambient temp
|
||||||
{
|
{
|
||||||
// Code to handle dealing with brown-out conditions.
|
// Code to handle dealing with brown-out conditions.
|
||||||
@ -251,6 +274,7 @@ calling:
|
|||||||
mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
{
|
{
|
||||||
py_fir_deinit();
|
py_fir_deinit();
|
||||||
|
bool first_init = true;
|
||||||
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) {
|
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) {
|
||||||
case FIR_NONE: {
|
case FIR_NONE: {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
@ -353,6 +377,7 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case FIR_MLX90640: {
|
case FIR_MLX90640: {
|
||||||
|
FIR_MLX90640:
|
||||||
width = 32;
|
width = 32;
|
||||||
height = 24;
|
height = 24;
|
||||||
fir_sensor = FIR_MLX90640;
|
fir_sensor = FIR_MLX90640;
|
||||||
@ -378,18 +403,26 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
|||||||
uint16_t *eeprom = fb_alloc(832 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
uint16_t *eeprom = fb_alloc(832 * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||||
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
|
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
|
||||||
error |= MLX90640_ExtractParameters(eeprom, (paramsMLX90640 *) alpha_ij);
|
error |= MLX90640_ExtractParameters(eeprom, (paramsMLX90640 *) alpha_ij);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
|
||||||
|
if (error != 0 && first_init == true) {
|
||||||
|
first_init = false;
|
||||||
|
generate_scl_train();
|
||||||
|
xfree(alpha_ij);
|
||||||
|
alpha_ij = NULL;
|
||||||
|
goto FIR_MLX90640;
|
||||||
|
}
|
||||||
|
|
||||||
// Switch to FAST speed
|
// Switch to FAST speed
|
||||||
cambus_deinit(&fir_i2c);
|
cambus_deinit(&fir_i2c);
|
||||||
cambus_init(&fir_i2c, FIR_I2C, I2C_TIMING_FAST);
|
cambus_init(&fir_i2c, FIR_I2C, I2C_TIMING_FAST);
|
||||||
|
|
||||||
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90640!");
|
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90640!");
|
||||||
|
|
||||||
fb_alloc_free_till_mark();
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FIR_AMG8833: {
|
case FIR_AMG8833: {
|
||||||
|
FIR_AMG8833:
|
||||||
width = 8;
|
width = 8;
|
||||||
height = 8;
|
height = 8;
|
||||||
fir_sensor = FIR_AMG8833;
|
fir_sensor = FIR_AMG8833;
|
||||||
@ -398,16 +431,14 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
|||||||
IR_refresh_rate = 10;
|
IR_refresh_rate = 10;
|
||||||
ADC_resolution = 12;
|
ADC_resolution = 12;
|
||||||
|
|
||||||
for (int i=0; i<=10; i++) {
|
int error = cambus_write_bytes(&fir_i2c, AMG8833_ADDR, 0x01, (uint8_t [1]){0x3F}, 1);
|
||||||
if ((cambus_write_bytes(&fir_i2c, AMG8833_ADDR, 0x01, (uint8_t [1]){0x3F}, 1)) == 0) {
|
if (error != 0 && first_init == true) {
|
||||||
break;
|
first_init = false;
|
||||||
}
|
generate_scl_train();
|
||||||
if (i == 10) {
|
goto FIR_AMG8833;
|
||||||
test_ack(-1);
|
|
||||||
}
|
|
||||||
HAL_Delay(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the AMG8833!");
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user