Very strange I2C behaviour when reading a byte with NACK

spuzesp32
Posts: 9
Joined: Sun Jul 23, 2017 2:24 pm

Very strange I2C behaviour when reading a byte with NACK

Postby spuzesp32 » Wed Jul 26, 2017 5:17 pm

I've been trying to convert a program from the ESP Arduino core to a C version which reads accelerometer data via I2C. The Ardunio version works fine but I am struggling to get the C version to behave correctly. The problem is when reading bytes from the bus. The relevant code is:

Code: Select all

/**
 * Read register
 */
uint8_t read_reg(uint8_t reg_addr)
{
  // Specify register to read
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte (cmd, (ACCEL<<1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
  i2c_master_write_byte (cmd, reg_addr, ACK_CHECK_EN);
  esp_err_t ret = i2c_master_cmd_begin (I2C_MASTER_NUM, cmd, 100/ portTICK_PERIOD_MS);
  i2c_cmd_link_delete(cmd);
  if (ret != ESP_OK) {
    printf("Error writing i2c address byte %d. Ret: %d\n", reg_addr, ret);
  } else {
    printf("Successfully wrote i2c address byte %d. Ret: %d\n", reg_addr, ret);
  }

  // Now read a byte from that register
  cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte (cmd, (ACCEL<<1) | I2C_MASTER_READ, ACK_CHECK_EN);
  uint8_t res = 0;
  i2c_master_read_byte (cmd, &res, NACK_VAL);
  ret = i2c_master_cmd_begin (I2C_MASTER_NUM, cmd, 100/ portTICK_PERIOD_MS);
  i2c_cmd_link_delete(cmd);
  if (ret != ESP_OK) {
    printf("Error reading register %d: %d. Ret: %d\n", reg_addr, res, ret);
  } else {
    printf("Successfully read register %d: %d. Ret: %d\n", reg_addr, res, ret);
  }

  return res;
}
Notice in particular this line:

Code: Select all

  i2c_master_read_byte (cmd, &res, NACK_VAL);
As far as I understand this is the correct way to read a single byte from the I2C bus. However it fails to return successfully. If I switch the NACK_VAL to an ACK_VAL however (which is incorrect because we only want to read a single byte), it does successfully read the value. Debugging with a logic analyser, we can see a little bit what is going on. It appears that when I ask the driver to read a byte with a NACK bit, the SCL clock simply stops.

Not working with NACK:
NACK3.png
NACK3.png (311.84 KiB) Viewed 5425 times
Kind of working but not really with ACK:
ACK3.png
ACK3.png (360.79 KiB) Viewed 5425 times
I have no idea why this is happening but it is very reliable. Also, the original Arduino version is able to send a NACK bit with no problems and the SCL clock continues to run smoothly. Any ideas what I am doing wrong or what I might try next to continue debugging?

Full code listing along with outputs, more screenshots and datatraces are here: https://github.com/alexspurling/lis3dh

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: Very strange I2C behaviour when reading a byte with NACK

Postby WiFive » Thu Jul 27, 2017 5:16 am

You aren't using any i2c_master_stop commands?

spuzesp32
Posts: 9
Joined: Sun Jul 23, 2017 2:24 pm

Re: Very strange I2C behaviour when reading a byte with NACK

Postby spuzesp32 » Thu Jul 27, 2017 8:30 am

Thank you WiFive, that is exactly what was wrong! I feel stupid that it was such a simple error but also glad it wasn't something more nasty. :D

Who is online

Users browsing this forum: markkuk and 312 guests