i2c randombly fails
Posted: Fri Jun 16, 2017 6:33 pm
I've had issues with i2c intermittently ever since I started using the i2c driver provided. I follow the i2c example very closely. It seems that the issues happen during transmit.
In the code, I get 1 of 3 types of errors. After the error the i2c will not recover until reset.
Here's my code:
With logic analyzer output, i2c commands run fine but then 1 of 2 problems occur:
In the code, I get 1 of 3 types of errors. After the error the i2c will not recover until reset.
- timeout error (263) returned from i2c_master_cmd_begin,
- a general error (-1) is returned from i2c_master_cmd_begin
- I get an assert on line 600 of xRingbufferReceiveUpToFromISR, only called by i2c driver in my code
Here's my code:
Code: Select all
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <i2c_master.h>
#include <driver/gpio.h>
#include <driver/periph_ctrl.h>
#include <driver/i2c.h>
#include <freertos/FreeRTOS.h>
enum
{
i2c_master_sclIo = 16, // gpio number for I2C master clock
i2c_master_sdaIo = 17, // gpio number for I2C master data
i2c_master_txBufDisable = 0, // I2C master do not need buffer
i2c_master_rxBufDisable = 0, // I2C master do not need buffer
i2c_master_freqHz = 400000, // I2C master clock frequency
};
enum
{
writeMask = 0xFE,
readMask = 0x01,
};
static const i2c_port_t I2C_MASTER_NUM = I2C_NUM_0; // I2C port number for master dev
static const bool ACK_CHECK_EN = 0x1; // I2C master will check ack from slave
static const bool ACK_CHECK_DIS = 0x0; // I2C master will not check ack from slave
static const bool ACK_VAL = 0x0; // I2C ack value
static const bool NACK_VAL = 0x1; // I2C nack value
static bool init = 0x0;
size_t myI2c_master_transmit(uint8_t slaveAddress, const uint8_t* txBuf, size_t size, bool sendStopBit)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
esp_err_t ret = i2c_master_start(cmd); //queue send start command
ret |= i2c_master_write_byte(cmd, ( slaveAddress ) & writeMask, true); //queue write address command
ret |= i2c_master_write(cmd, (uint8_t*)txBuf, size, ACK_CHECK_EN); //queue write data command
ret |= i2c_master_stop(cmd); //queue send stop command
if( ret != ESP_OK )
{
i2c_cmd_link_delete(cmd);
printf("i2c queue transmit commands error: %d\n", ret);
return 0;
}
ret = i2c_master_cmd_begin((i2c_port_t) I2C_MASTER_NUM, cmd, 500 / portTICK_RATE_MS);
//start execution of all commands that have been queued
i2c_cmd_link_delete(cmd);
if( ret != ESP_OK )
{
printf("slave Address: %02X\n", slaveAddress);
printf("i2c transmit error: %d\n", ret);
return 0;
}
return size;
}
size_t myI2c_master_receive(uint8_t slaveAddress, uint8_t* rxBuf, size_t size)
{
if ( size == 0 )
{
return 0;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); //create new handler for set of commands
esp_err_t ret = i2c_master_start(cmd); //queue send start command
ret |= i2c_master_write_byte(cmd, (slaveAddress | readMask), ACK_CHECK_EN); //queue write address command
if (size > 1) {
ret |= i2c_master_read(cmd, rxBuf, size - 1, ACK_VAL); //queue read data
}
ret |= i2c_master_read_byte(cmd, (rxBuf + size - 1), NACK_VAL); //queue read last byte of data
//i2c protocol requires nack on last byte of data read from slave
ret |= i2c_master_stop(cmd); //queue send stop command
if( ret != ESP_OK )
{
i2c_cmd_link_delete(cmd);
printf("i2c queue receive commands error: %d\n", ret);
return 0;
}
ret = i2c_master_cmd_begin((i2c_port_t) I2C_MASTER_NUM, cmd, 500 / portTICK_RATE_MS);
//start execution of all commands that have been queued
i2c_cmd_link_delete(cmd);
if( ret != ESP_OK )
{
printf("i2c receive error: %d\n", ret);
return 0;
}
return size;
}
void myI2c_master_init(void)
{
if( !init )
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = i2c_master_sdaIo;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = i2c_master_sclIo;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = i2c_master_freqHz;
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode, i2c_master_rxBufDisable, i2c_master_txBufDisable, 0);
init = true;
}
}
- a write continues indefinitely, writing 0xFF or a random byte. (the images below are of the same i2c write)
- esp32 starts a write with a bogus address and gets NAK. This continues indefinitely until reset. Also, the address passed into myI2c write is always correct.