I2C problems

User avatar
Jakobsen
Posts: 89
Joined: Mon Jan 16, 2017 8:12 am

I2C problems

Postby Jakobsen » Sun Feb 26, 2017 1:32 am

Hi
I have done some low level debug to get the hardware i2c block to operate correct. I see random brake down in the i2c communication.

Image

My setup is the webradio example from buddyCasino.

The esp32 connects to my MA12040P Merus-Audio power amplifier - I2S for audio and I2C for control.

1: Simple i2c write procedure. I have this function that use the i2c.c driver from the idf-sdk

Code: Select all

#include <stdio.h>
#include <stdint.h>
#include "driver/i2c.h"

#define I2C_MASTER_SCL_IO    27   /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO    14
    /*!< gpio number for I2C master data  */
#define I2C_MASTER_NUM I2C_NUM_0   /*!< I2C port number for master dev */
#define I2C_MASTER_TX_BUF_DISABLE   0   /*!< I2C master do not need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0   /*!< I2C master do not need buffer */
#define I2C_MASTER_FREQ_HZ    100000     /*!< I2C master clock frequency */

#define MA12040_ADDR  0x20   /*!< slave address for MA12040 amplifier */

#define WRITE_BIT  I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT   I2C_MASTER_READ  /*!< I2C master read */
#define ACK_CHECK_EN   0x1     /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS  0x0     /*!< I2C master will not check ack from slave */
#define ACK_VAL    0x0         /*!< I2C ack value */
#define NACK_VAL   0x1         /*!< I2C nack value */


void i2c_master_init()
{   int i2c_master_port = I2C_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = I2C_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
    esp_err_t res = i2c_param_config(i2c_master_port, &conf);
    printf("Driver param setup : %d\n",res);
	res = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
    printf("Driver installed   : %d\n",res);
}
All setup is more or less from the example in the sdk

Code: Select all

esp_err_t ma_write_byte(uint8_t address, uint8_t value)
{
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (MA12040_ADDR<<1) | WRITE_BIT , ACK_CHECK_EN);
  i2c_master_write_byte(cmd, address, ACK_VAL);
  i2c_master_write_byte(cmd, value, ACK_VAL);
  i2c_master_stop(cmd); 
  esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 20 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  if (ret == ESP_FAIL) {
     printf("ESP_I2C_WRITE ERROR : %d\n",ret);
	 return ret;
  }
  return ESP_OK;
}
All works perfect and i can do <i2c hardware addr + write> <address><date> . But from time to time i get this pattern on the SCL/SDA bus and cannot recover.
Image
and zoomed in
Image

It is only one out of 100-200 writes that fails but it is non recoverable.

2: I2C read: According to the hardware ref. there is a procedure to setup n byte read operations

Code: Select all

esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, int ack)
{
    I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
    I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);

    int len_tmp;
    int data_offset = 0;
    esp_err_t ret;
    while (data_len > 0) {
        len_tmp = data_len > 0xff ? 0xff : data_len;
        data_len -= len_tmp;
        i2c_cmd_t cmd;
        cmd.ack_en = 0;
        cmd.ack_exp = 0;
        cmd.ack_val = ack & 0x1;
        cmd.byte_num = len_tmp;
        cmd.op_code = I2C_CMD_READ;
        cmd.data = data + data_offset;
        ret = i2c_cmd_link_append(cmd_handle, &cmd);
        data_offset += len_tmp;
        if (ret != ESP_OK) {
            return ret;
        }
    }
    return ESP_OK;
}
I cannot get this code to work and have to loop multiple call to i2c_master_read_byte like this

Code: Select all

esp_err_t ma_read(uint8_t address, uint8_t *rbuf, uint8_t n)
{ esp_err_t ret;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (MA12040_ADDR<<1) | WRITE_BIT, ACK_CHECK_EN);
  i2c_master_write_byte(cmd, address, ACK_VAL);
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, (MA12040_ADDR<<1) | READ_BIT, ACK_CHECK_EN);
  for (uint8_t i = 0;i<n;i++) 
  { i2c_master_read_byte(cmd, rbuf++, ACK_VAL);
  }
  i2c_master_read_byte(cmd, rbuf++, NACK_VAL);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 20 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  if (ret == ESP_FAIL) {
      printf("i2c Error read - readback\n");
	  return ESP_FAIL;
  }
  return ret; 
}
When using the i2c_master_read_byte I get this correct result

Image

When using i2c_master_read call: No stop condition is clocked out and the bus get stucked.

And also for read from time to time the bus end up like this
Image

If needed I can make an isolated example to demo what I think i have found. (Please note the SCL/SDA lables is not correct in some plots. SCL above SDA)

Regards Jørgen Jakobsen
Analog Digital IC designer / DevOps @ Merus Audio, Copenhagen, Denmark.
We do novel and best in class Audio amplifiers for consumer products.
Programmed assembler for C-64 back in 1980's, learned some electronics - hacking since then

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: I2C problems

Postby kolban » Sun Feb 26, 2017 4:59 pm

It may be that you are running across the issue reported here ...

https://github.com/espressif/esp-idf/issues/377

Do you have a link to the datasheet for the device which shows the expected I2C flows? (I wasn't able to find it through a google search).

In my experiences, I have found that the i2c_master_read() wants to use the same ACK value for ALL reads of all bytes ... where when I look at a variety of datasheets, what we actually want is a positive ACK for all reads of all bytes EXCEPT the last byte that we expected and we (ESP32 master) should send a NACK for that last byte. The workaround I use is as follows:

assume I want to read 6 bytes:

i2c_master_read(buffer, 5, ACK);
i2c_master_read_byte(buffer+5, NACK);

So I end up with two commands in my I2C command buffer. A request to read 5 bytes with ACK and a request to read 1 byte with NACK.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

User avatar
Jakobsen
Posts: 89
Joined: Mon Jan 16, 2017 8:12 am

Re: I2C problems

Postby Jakobsen » Sun Feb 26, 2017 9:18 pm

Hi Kolban

Yes - I have seen some of your code using i2c_master_read - I will try a second time. What I saw as a missing stop message.

I am sorry to hear that you could not find the datasheet of MA12040P - Spend the last 5 year on the team that created it - I will make sure we pay the google juice to get it up the search list.

So for our chip when it comes to i2c ACK: i2c master needs to ACK the data on SDA line by pulling SDA low on the 9'th clk after 8 bits has been read. In the MA120x0 we check that the master has ACK the data and prepare the next byte to be read - If not ACK'ed we just backup and restart state machine to look for a new start condition on the bus.

Direct like to the datasheet :-)
http://www.merus-audio.com/images/pdf/e ... asheet.pdf

/Jørgen
Analog Digital IC designer / DevOps @ Merus Audio, Copenhagen, Denmark.
We do novel and best in class Audio amplifiers for consumer products.
Programmed assembler for C-64 back in 1980's, learned some electronics - hacking since then

User avatar
Jakobsen
Posts: 89
Joined: Mon Jan 16, 2017 8:12 am

Re: I2C problems

Postby Jakobsen » Mon Feb 27, 2017 8:14 am

Can random printf from different threads with out mutex access show up like this?
printf (but not ets_printf) to the UART already takes a mutex before writing. Even if it wasn't properly protected, I don't see how that would cause I2C to fail.

If you can give us some test case which we can run, and any necessary instructions, we can take a look. I think Jeroen happens to have a dev board with your amp chip on it :)
Analog Digital IC designer / DevOps @ Merus Audio, Copenhagen, Denmark.
We do novel and best in class Audio amplifiers for consumer products.
Programmed assembler for C-64 back in 1980's, learned some electronics - hacking since then

A1k1shay
Posts: 2
Joined: Thu Jan 14, 2021 7:26 am

Re: I2C problems

Postby A1k1shay » Thu Jan 14, 2021 9:47 am

Can someone please tell me, where am I wrong? I am continuously getting ESP_FAIL error from i2c_master_cmd_begin
  1. #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
  2. #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
  3. #define ACK_CHECK_EN 0x1            /*!< I2C master will check ack from slave*/
  4. #define ACK_CHECK_DIS 0x0           /*!< I2C master will not check ack from slave */
  5. #define ACK_VAL 0x0                 /*!< I2C ack value */
  6. #define NACK_VAL 0x1               /*!< I2C nack value */
  7.  
  8. //static const char *TAG = "cmd_i2ctools";
  9.  
  10. static gpio_num_t i2c_gpio_sda = 21;
  11. static gpio_num_t i2c_gpio_scl = 22;
  12. static uint32_t i2c_frequency = 1000;
  13. static i2c_port_t i2c_port = I2C_NUM_0;
  14. uint8_t datah;
  15. uint8_t datal;
  16. esp_err_t i2c_ret;
  17. uint8_t config_reg_val1 = 0b00001110;
  18. uint8_t config_reg_val2 = 0b00000011;
  19.  
  20. void app_main ()
  21. {
  22.  
  23.   i2c_config_t conf = {
  24.       .mode = I2C_MODE_MASTER,
  25.       .sda_io_num = i2c_gpio_sda,
  26.       .sda_pullup_en = GPIO_PULLUP_ENABLE,
  27.       .scl_io_num = i2c_gpio_scl,
  28.       .scl_pullup_en = GPIO_PULLUP_ENABLE,
  29.       .master.clk_speed = i2c_frequency
  30.   };
  31.   i2c_param_config(i2c_port, &conf);
  32.   i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
  33.   i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
  34.   i2c_master_start(cmd);
  35.   i2c_master_write_byte(cmd, 0b1001000|I2C_MASTER_WRITE, 1); //address pin connected to ground
  36.   i2c_master_write_byte(cmd, 0b00000001, 1); // config register
  37.   i2c_master_write(cmd, config_reg_val1, 8, 1);
  38.   i2c_master_write(cmd, config_reg_val2 , 8, 1);
  39.   i2c_master_stop(cmd);
  40.   i2c_ret = i2c_master_cmd_begin(i2c_port, cmd, 10000/portTICK_RATE_MS);
  41.   i2c_cmd_link_delete(cmd);
  42.  
  43.   if (i2c_ret == ESP_OK)
  44.   {
  45.     printf("I2C Write OK\n");
  46.   }
  47.   if (i2c_ret == ESP_FAIL)
  48.   {
  49.     printf("I2C_fail\n");
  50.   }
  51.   if (i2c_ret == ESP_ERR_INVALID_ARG)
  52.   {
  53.     printf("wrong parameter\n");
  54.   }
  55.   if (i2c_ret == ESP_ERR_INVALID_STATE)
  56.   {
  57.     printf("driver_error\n");
  58.   }
  59.   if (i2c_ret == ESP_ERR_TIMEOUT)
  60.   {
  61.     printf("timeout\n");
  62.   }
  63.  
  64.   i2c_driver_delete(i2c_port);
  65. }
  66. ]

Who is online

Users browsing this forum: No registered users and 41 guests