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.
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);
}
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;
}
and zoomed in
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;
}
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 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
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