When I try to read the OPT3001 ambient light sensor,
sometimes there is an I2C read error, but the returned ret value still appears correct, causing my illuminance value to suddenly jump and the screen brightness to change abruptly.
Why is this happening? I suspect that after an I2C read error, the bus might be immediately reset and then performs a successful re-read, which would explain why ret is non-zero (appearing successful) and recv_buf contains seemingly valid data. Is it possible that the I2C driver automatically retries after an error and recovers the communication, making the higher-level code unaware of the initial failure?
The returned value seems correct. The previous abrupt change was due to the driver’s brightness adjustment range being 0–100, but I wrote values using the range 0–255, which caused the error.
i2c_errcode=4 corresponds to HAL_I2C_ERROR_AF, which indicates an I2C no-acknowledge error.
The return value of 2 means that the amount of data read is 2 bytes. The function returns the number of bytes read, not an rt_err_t type value.
As for why an I2C error occurred but it still returned 2, do you have any multi-threaded read operations? Judging from your logs, the first two entries suggest a timeout occurred during TP read operations, while the last entry shows that the “brightne” thread successfully read data.
[2706111] E/drv.i2c tpread: bus err:0, xfer:0/2, i2c_stat:20, i2c_errcode=4
No, I should only have one thread obtaining the time. However, I can’t guarantee there are no bugs. This code was originally just a quick test setup for testing the light sensor, and according to the design, only one dedicated task handles this job.
void bringhtness_task(void *parameter)
{
opt3001_t opt3001;
uint8_t brightness;
uint16_t delay_ms;
if (!opt3001_init(&opt3001, NULL))
{
rt_kprintf("opt3001 init failed\n");
}
while (1)
{
if(alc_get_cur_brightness(&opt3001, &brightness, &delay_ms))
{
// rt_kprintf("Set brightness to %d\n", brightness);
set_brightness(brightness);
}
rt_thread_mdelay(delay_ms);
}
}
/**
* @brief Main program
* @param None
* @retval 0 if success, otherwise failure number
*/
int main(void)
{
rt_err_t ret = RT_EOK;
rt_uint32_t ms;
// hwp_pmuc->PERI_LDO |= PMUC_PERI_LDO_EN_VDD33_LDO3;
// int pin = GET_PIN(1,9);
// rt_pin_mode(pin, PIN_MODE_OUTPUT);
// rt_pin_write(pin, PIN_HIGH);
// rt_kprintf("Pin %d set to high\n", pin);
// rt_thread_mdelay(2000);
/* init littlevGL */
rt_kprintf("Initializing littlevGL...\n");
ret = littlevgl2rtt_init("lcd");
if (ret != RT_EOK)
{
return ret;
}
lv_ex_data_pool_init();
// init_pin();
lv_demo_main();
rt_thread_t tid = rt_thread_create("brightness_task", bringhtness_task, NULL, 2048, 10, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
while (1)
{
if (rt_mutex_take(lcd_mutex, RT_WAITING_FOREVER) == RT_EOK)
{
ms = lv_task_handler();
rt_thread_mdelay(ms);
rt_mutex_release(lcd_mutex);
}
}
return RT_EOK;
}
The TP reading itself runs on a separate thread in drv_touch.c.
Therefore, this error is not an I2C reading error from the ambient light sensor, but rather an error occurring during TP reading. Since the logs are printed consecutively, it appears as if it’s an error from the light sensor.