sp32s3 - I2C transaction unexpected nack detected

ravikumar
Posts: 9
Joined: Thu Feb 27, 2025 8:17 am

sp32s3 - I2C transaction unexpected nack detected

Postby ravikumar » Thu Apr 17, 2025 5:48 am

[#include <stdio.h>
#include <math.h>
#include "bmi323.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "string.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"


#define TAG "BMI323_APP"
#define GRAVITY_EARTH (9.80665f)
#define I2C_MASTER_SCL_IO 5
#define I2C_MASTER_SDA_IO 6
#define I2C_PORT_NUM_0 I2C_NUM_0
#define BMI323_I2C_ADDR 0x69
#define READ_WRITE_LEN 8

static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t dev_handle;

static int8_t bmi3_i2c_read(uint8_t reg_addr, uint8_t *data, uint32_t len, void *intf_ptr)
{
i2c_master_dev_handle_t handle = (i2c_master_dev_handle_t)intf_ptr;
esp_err_t ret = i2c_master_transmit_receive(handle, &reg_addr, 1, data, len, -1);
return (ret == ESP_OK) ? BMI3_OK : BMI3_E_COM_FAIL;
}

static int8_t bmi3_i2c_write(uint8_t reg_addr, const uint8_t *data, uint32_t len, void *intf_ptr)
{
i2c_master_dev_handle_t handle = (i2c_master_dev_handle_t)intf_ptr;
uint8_t buffer[len + 1];
buffer[0] = reg_addr;
memcpy(&buffer[1], data, len);
esp_err_t ret = i2c_master_transmit(handle, buffer, len + 1, -1);
return (ret == ESP_OK) ? BMI3_OK : BMI3_E_COM_FAIL;
}

static void bmi3_delay_us(uint32_t period, void *intf_ptr)
{
(void)intf_ptr;
esp_rom_delay_us(period);
}

static int8_t set_accel_config(struct bmi3_dev *dev);
static int8_t set_gyro_config(struct bmi3_dev *dev);
static float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width);
static float lsb_to_dps(int16_t val, float dps, uint8_t bit_width);

int app_main(void)
{
struct bmi3_dev dev = {0};
int8_t rslt;
struct bmi3_sensor_data accel_data = {0};
struct bmi3_sensor_data gyro_data = {0};
float ax = 0, ay = 0, az = 0;
float gx = 0, gy = 0, gz = 0;

int16_t raw_ax = 0, raw_ay = 0, raw_az = 0;
int16_t raw_gx = 0, raw_gy = 0, raw_gz = 0;

// I2C Configuration
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_PORT_NUM_0,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_io_num = I2C_MASTER_SDA_IO,
.glitch_ignore_cnt = 7,
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BMI323_I2C_ADDR,
.scl_speed_hz = 100000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));

// Assign interface functions
dev.read = bmi3_i2c_read;
dev.write = bmi3_i2c_write;
dev.intf = BMI3_I2C_INTF;
dev.intf_ptr = dev_handle;
dev.delay_us = bmi3_delay_us;
dev.read_write_len = READ_WRITE_LEN;

rslt = bmi323_init(&dev);
if (rslt != BMI323_OK) {
printf("bmi323_init failed\n");
return rslt;
}

rslt = set_accel_config(&dev);
if (rslt != BMI323_OK) {
printf("set_accel_config failed\n");
return rslt;
}

rslt = set_gyro_config(&dev);
if (rslt != BMI323_OK) {
printf("set_gyro_config failed\n");
return rslt;
}

accel_data.type = BMI323_ACCEL;
gyro_data.type = BMI323_GYRO;

while (1) {
rslt = bmi323_get_sensor_data(&accel_data, 1, &dev);
if (rslt == BMI323_OK) {
raw_ax = accel_data.sens_data.acc.x;
raw_ay = accel_data.sens_data.acc.y;
raw_az = accel_data.sens_data.acc.z;
ax = lsb_to_mps2(raw_ax, 2, dev.resolution);
ay = lsb_to_mps2(raw_ay, 2, dev.resolution);
az = lsb_to_mps2(raw_az, 2, dev.resolution);
}

rslt = bmi323_get_sensor_data(&gyro_data, 1, &dev);
if (rslt == BMI323_OK) {
raw_gx = gyro_data.sens_data.gyr.x;
raw_gy = gyro_data.sens_data.gyr.y;
raw_gz = gyro_data.sens_data.gyr.z;
gx = lsb_to_dps(raw_gx, 2000.0f, dev.resolution);
gy = lsb_to_dps(raw_gy, 2000.0f, dev.resolution);
gz = lsb_to_dps(raw_gz, 2000.0f, dev.resolution);
}

printf("Accel => raw-> x=%d, y=%d, z=%d | mps2-> x=%4.2f, y=%4.2f, z=%4.2f || Gyro => raw-> x=%d, y=%d, z=%d | dps-> x=%4.2f, y=%4.2f, z=%4.2f\n",
raw_ax, raw_ay, raw_az, ax, ay, az, raw_gx, raw_gy, raw_gz, gx, gy, gz);

vTaskDelay(pdMS_TO_TICKS(1000));
}

return rslt;
}

static int8_t set_accel_config(struct bmi3_dev *dev)
{
int8_t rslt;
struct bmi3_sens_config config;
struct bmi3_map_int map_int = {0};

config.type = BMI323_ACCEL;
rslt = bmi323_get_sensor_config(&config, 1, dev);
if (rslt != BMI323_OK) return rslt;

map_int.acc_drdy_int = BMI3_INT1;
rslt = bmi323_map_interrupt(map_int, dev);
if (rslt != BMI323_OK) return rslt;

config.cfg.acc.odr = BMI3_ACC_ODR_100HZ;
config.cfg.acc.range = BMI3_ACC_RANGE_2G;
config.cfg.acc.bwp = BMI3_ACC_BW_ODR_QUARTER;
config.cfg.acc.avg_num = BMI3_ACC_AVG64;
config.cfg.acc.acc_mode = BMI3_ACC_MODE_NORMAL;

rslt = bmi323_set_sensor_config(&config, 1, dev);
return rslt;
}

static int8_t set_gyro_config(struct bmi3_dev *dev)
{
int8_t rslt;
struct bmi3_sens_config config;
struct bmi3_map_int map_int = {0};

config.type = BMI323_GYRO;
rslt = bmi323_get_sensor_config(&config, 1, dev);
if (rslt != BMI323_OK) return rslt;

map_int.gyr_drdy_int = BMI3_INT1;
rslt = bmi323_map_interrupt(map_int, dev);
if (rslt != BMI323_OK) return rslt;

config.cfg.gyr.odr = BMI3_GYR_ODR_100HZ;
config.cfg.gyr.range = BMI3_GYR_RANGE_2000DPS;
config.cfg.gyr.bwp = BMI3_GYR_BW_ODR_HALF;
config.cfg.gyr.avg_num = BMI3_GYR_AVG1;
config.cfg.gyr.gyr_mode = BMI3_GYR_MODE_NORMAL;

rslt = bmi323_set_sensor_config(&config, 1, dev);
return rslt;
}

static float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width)
{
float half_scale = (float)((1UL << bit_width) / 2.0f);
return (GRAVITY_EARTH * val * g_range) / half_scale;
}

static float lsb_to_dps(int16_t val, float dps, uint8_t bit_width)
{
float half_scale = (float)((1UL << bit_width) / 2.0f);
return (dps / half_scale) * val;
}
]

this is my code to interface of bmi323 with esp32s3 this code work fine but after some time getting error long below

E (250477) i2c.master: I2C transaction unexpected nack detected
E (250477) i2c.master: s_i2c_synchronous_transaction(872): I2C transaction failed
E (250477) i2c.master: i2c_master_transmit_receive(1097): I2C transaction failed
E (250487) i2c.master: I2C transaction unexpected nack detected
E (250487) i2c.master: s_i2c_synchronous_transaction(872): I2C transaction failed
E (250497) i2c.master: i2c_master_transmit_receive(1097): I2C transaction failed
Accel => raw-> x=-2538, y=-2604, z=15898 | mps2-> x=-1.52, y=-1.56, z=9.52 || Gyro => raw-> x=-2, y=-7, z=-1 | dps-> x=-0.12, y=-0.43, z=-0.06
E (251517) i2c.master: I2C transaction unexpected nack detected
E (251517) i2c.master: s_i2c_synchronous_transaction(872): I2C transaction failed
E (251517) i2c.master: i2c_master_transmit_receive(1097): I2C transaction failed
E (251527) i2c.master: I2C transaction unexpected nack detected
E (251527) i2c.master: s_i2c_synchronous_transaction(872): I2C transaction failed
E (251537) i2c.master: i2c_master_transmit_receive(1097): I2C transaction failed
Accel => raw-> x=-2538, y=-2604, z=15898 | mps2-> x=-1.52, y=-1.56, z=9.52 || Gyro => raw-> x=-2, y=-7, z=-1 | dps-> x=-0.12, y=-0.43, z=-0.06

eriksl
Posts: 232
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: sp32s3 - I2C transaction unexpected nack detected

Postby eriksl » Fri Apr 18, 2025 9:05 am

I have some experience with this, no solution though.

There are, as far as I've seen, two reasons why this happens.

1) when the slave sends a NAK after the point where the address has been ACKed, i.e.
- master sends <start>
- master sends <address> + <write bit> (7 bits + 1 bit)
- slave sends <ack>
- master send <data> (first 8 bytes, usually means register pointer, but does not need to be)
- slave sends <nak>
In some devices this can happen when a register index (as <data>) has been sent that's not supported/recognised. It's not invalid as seen from the I2C protocol and I wonder why the IDF makes such a fuss about it.
OR
- master sends <start>
- master sends <address> + <read bit>
- slave sends NAK
In some devices this can happen when the device is not ready to supply data (e.g. a measurement that's not finished yet). It's not invalid as seen from the I2C protocol and I wonder why the IDF makes such a fuss about it.

I've made a bug report about this here: https://github.com/espressif/esp-idf/issues/14715. It seems a workaround has been planned for a future version of IDF, but feel free to add your statements there (maybe they'll speed it up a bit...)

2) it looks like there is a bug in de IDF concerning I2C handling. Whenever I add "sleep" statement (suspending the current thread using vTaskDelay by a few milliseconds, this is required for some, not 100% i2c compliant, devices) the I2C module sooner or later goes into a weird state where transactions to most (all?) slaves on the bus end up with the above errors, report about NAK's being send by the slaves, even though my logic analyser doesn't show any of it, all transactions are ACKed. Rebooting the esp32s3 solves the issue for a short time. It looks like (fingers crossed), when I remove all of the sleep statements, the issue goes away (but I need to workaround the non-compliant slaves in another way, not sure how, yet).

My very uninformed guess is that due to the task being in suspended state, some I2C hardware module handling is also suspended which causes a timeout somewhere. I'll be monitoring this and when I have a little more information, I'll create a bug report as well.

Acuario
Posts: 17
Joined: Mon Apr 04, 2016 11:21 am

Re: sp32s3 - I2C transaction unexpected nack detected

Postby Acuario » Sun Apr 20, 2025 4:58 pm

I have the same problem with a single GT911 touch sensor when using the 3.2.0 Arduino build on an S3
Downgrading to 3.1.3 resolves the problem.
I run the touch code in an RTOS task.

eriksl
Posts: 232
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: sp32s3 - I2C transaction unexpected nack detected

Postby eriksl » Wed Apr 23, 2025 6:50 am

Hmmm yeah that suggests a bug then. Did you file a bug report on github? That's important!

Energiya
Posts: 9
Joined: Sat Jan 27, 2024 2:22 pm

Re: sp32s3 - I2C transaction unexpected nack detected

Postby Energiya » Sun Jun 15, 2025 10:38 am

Hi,
To resolve the bug.You have to update i2c_master.c and change from

Code: Select all

    I2C_CLOCK_SRC_ATOMIC() {
        i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz);
    }

    // Set the timeout value
    i2c_hal_master_set_scl_timeout_val(hal, i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz);
to

Code: Select all

    // Set the timeout value
    i2c_hal_master_set_scl_timeout_val(hal, i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz);

    I2C_CLOCK_SRC_ATOMIC() {
        i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz);
    }
in other words move line i2c_hal_master_set_scl_timeout_val above I2C_CLOCK_SRC_ATOMIC
2025-06-15_12-33.png
2025-06-15_12-33.png (205.61 KiB) Viewed 5816 times
it works for me

eriksl
Posts: 232
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: sp32s3 - I2C transaction unexpected nack detected

Postby eriksl » Sun Jun 15, 2025 10:50 am

Please add your suggestion to the issue you made on github (I guess you did...)

edo76mal
Posts: 16
Joined: Wed May 11, 2022 10:17 am

Re: sp32s3 - I2C transaction unexpected nack detected

Postby edo76mal » Wed Jun 18, 2025 10:08 am

Hi.

I have similar problem with BH1750 sensor (and AK09915 magnetometer):

Found BH1750 device at 0x23
[0;31mE (649) i2c.master: I2C transaction unexpected nack detected[0m
[0;31mE (649) i2c.master: s_i2c_synchronous_transaction(918): I2C transaction failed[0m
[0;31mE (652) i2c.master: i2c_master_multi_buffer_transmit(1180): I2C transaction failed[0m

Using old i2c.c dev everythoing works, with i2c_master.c there is the problem.

I tried to invert lines as suggested, no result.

eriksl
Posts: 232
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: sp32s3 - I2C transaction unexpected nack detected

Postby eriksl » Wed Jun 18, 2025 10:14 am

I have bh1750 working like a charm, so I wonder what you're doing differently!

The only thing is that you can't use the bh1750 with the "RTC" I2C bus. I am not sure if that's what you're trying to do. The RTC I2C bus can only do transactions of the type <start><write 1 byte><restart><read x bytes><stop> and <start><write x bytes><stop>. For the bh1750 you need to do a <start><read x bytes><stop> transaction.

Besides that the bh1750 is really quite a simple device to communicate with, no weird stuff there (like e.g. pulling on the SCL).

Be aware though that it can have two addresses, make sure you configure the right one.

edo76mal
Posts: 16
Joined: Wed May 11, 2022 10:17 am

Re: sp32s3 - I2C transaction unexpected nack detected

Postby edo76mal » Wed Jun 18, 2025 3:37 pm

@ eriksl

I attached my sample project.
Attachments
BH1750_Prj.zip
Sample project with NACK problem
(43.4 KiB) Downloaded 25 times

eriksl
Posts: 232
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: sp32s3 - I2C transaction unexpected nack detected

Postby eriksl » Wed Jun 18, 2025 4:17 pm

You're doing bh1750_read() somewhere which calls i2c_dev_read_reg(), a function that's not included, so I can't tell.

I suggest you double check the address used. Be aware that I2C addresses can be expressed in two ways, with and without the R/W bit included (at bit position 0). bh1750's default address is 0x23, but if you include the R/W bit, it actually becomes two address: 0x46 for writing and 0x47 for reading. Double check which convention is used in your program, your libraries and the IDF API. Cause I think there is actually no error, just the slave not responding because it's not addressed at all.

For an example of a working bh1750 (and others) implementation: https://github.com/eriksl/esp32/blob/ma ... n/sensor.c

Who is online

Users browsing this forum: Baidu [Spider], PerplexityBot and 1 guest