i2c issues

lg.lindstrom
Posts: 47
Joined: Fri Sep 17, 2021 4:02 pm

i2c issues

Postby lg.lindstrom » Sun Dec 04, 2022 9:45 am

Hi

I am writing a I2C component to handle communication with a DSP. There are some problems i need to discuss because I am not sure if I handling the I2C protocol correctly.

First, ESP is master and DSP is slave.

I have defined a protocol where ESP is sending a command and DSP is returning a response. The response is data values.
The ESP knows what command it have sent and knows how much data it is expecting back from the DSP.
The first byte of data is a "status" byte that can be interpreted by the ESP.
The ESP is requesting correct number of data bytes from the DSP based on command.

This part of the "protocol" is working fine.

The problematic part is.
To avoid the requirement that the firmware in ESP and DSP must be completely in sync in respect versioning there is a special case.
- If the DSP don't recognize the received command it returns "unknown command" in the status byte. Also it returns M bytes.

Because of the ESP is expecting N bytes of data and the DSP responding witch M bytes of data the ESP throws a WDT interrupt.

I have set all ESP watchdogs to seconds to make sure that none of them are the cause of the interrupt so the conclusion is that somewhere in the ESP-IDF i2c component there is a timer watchdog that are triggered.
Normally when ESP and DSP agrees on the number of bytes that should be returned from the DSP, this is not happening.


So my questions is.
- is it even possible to use i2c in the way I intend?
- is it possible to add my own code to catch this error ?

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: i2c issues

Postby ESP_Sprite » Mon Dec 05, 2022 5:37 am

Can you post your code? (Or at least the relevant bits?)

lg.lindstrom
Posts: 47
Joined: Fri Sep 17, 2021 4:02 pm

Re: i2c issues

Postby lg.lindstrom » Tue Dec 13, 2022 6:12 pm

Hi

I beginning to be quite sure that if requestet data from slave not is correct number of bytes,, something goes serious wrong.
I was planning to use this line:

Code: Select all

   
esp_err_t ret = i2c_master_cmd_begin(i2c_num, link,pdMS_TO_TICKS(100)) ;

to see if something goes wrong and act accordingly. But I never reach this line,, a exception is thrown.

I have a slave that always responds with 10 bytes.
=> writeAndReadSlave(sd,10,rd,10); //Works
=> writeAndReadSlave(sd,10,rd,15); // Throws exception

The slave in my case, is a DSP. Normally it should respond with correct number of bytes. But something can go wrong,, either some disturbance on the PCB board or DPS SW bug,, and in that case I would like to be able to handle IT. Not a complete restart.

Code: Select all

 
#pragma once
#include "esp_log.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
#include "hw_configuration.h"
#include "wrapper.h"
#include "i2c_exception.h"
#include <string>

typedef enum {
    BOOL_FALSE = 0,
    BOOL_TRUE = 1
} ack_check_t;


#define WRITE_BIT                       I2C_MASTER_WRITE        /*!< I2C master write */
#define READ_BIT                        I2C_MASTER_READ         /*!< I2C master read */
#define ACK_CHECK                       BOOL_TRUE                   /*!< I2C master will check ack from slave*/                     /*!< I2C master will not check ack from slave */
#define ACK_VAL                         I2C_MASTER_ACK          /*!< I2C ack value */
#define NACK_VAL                        I2C_MASTER_NACK  
#define I2C_MASTER_TX_BUF_DISABLE       20                       /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE       20  
#define I2C_MASTER_FREQ_HZ              100000 
 
class I2cWrapper : public Wrapper {
    
constexpr static const char *TAG = "I2C_WRAPPER";

public:
    I2cWrapper (const uint8_t slaveAddress, const uint8_t sda, const uint8_t scl , const int port) : Wrapper(std::string(TAG)),
    _slaveAddress {slaveAddress},
    _sdaPin{sda},
    _sclPin{scl},
    _i2c_master_port {port} {
     
    I2cWrapper::_init();
    
} 
    void writeAndReadSlave(uint8_t * sendBuf, size_t send_buf_len, uint8_t * receiveBuf ,size_t receive_buf_len);
    
    i2c_config_t configuration;

private:
    const uint8_t   _slaveAddress{0};  //Slave address
    const uint8_t   _sdaPin{0}; //TODO fix this, global init
    const uint8_t   _sclPin{0};
    const int       _i2c_master_port = 0;

    bool            _configurationReady = false;
    SemaphoreHandle_t print_mux = NULL;

    void _init();
    esp_err_t  _read_from_slave(i2c_cmd_handle_t cmd, i2c_port_t i2c_num, uint8_t *data_rd, size_t size);
    esp_err_t  _write_to_slave( i2c_cmd_handle_t cmd ,  i2c_port_t i2c_num, uint8_t *data_wr, size_t size);
};

Code: Select all


#include "i2c_wrapper.h"
#include <iostream>
using std::runtime_error;
#include "i2c_wrapper.h"
#include <iostream>
using std::runtime_error;
#include "i2c_wrapper.h"
#include <iostream>
using std::runtime_error

void I2cWrapper::_init() {

    I2cWrapper::configuration.mode              = I2C_MODE_MASTER;
    I2cWrapper::configuration.clk_flags         = 0;
    I2cWrapper::configuration.sda_io_num        = _sdaPin;
    I2cWrapper::configuration.sda_pullup_en     = false;
    I2cWrapper::configuration.scl_io_num        = _sclPin;
    I2cWrapper::configuration.scl_pullup_en     = false;
    I2cWrapper::configuration.master.clk_speed  = I2C_MASTER_FREQ_HZ; //1 MHz
     
   
    /// @brief 
    FAILURE_HANDLER(i2c_param_config(_i2c_master_port, &configuration));
 
    FAILURE_HANDLER(i2c_driver_install(_i2c_master_port, configuration.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0));
}
/// @brief Writes to I2C slave and waits for response. Number of bytes to write to I2C slave are 
/// defined by sendBuf length. Number of bytes to read from I2C slave are defined by receiveBuf length.
/// @param command 
/// @param sendBuf 
/// @param send_buf_len 
/// @param receiveBuf 
/// @param len 
void I2cWrapper::writeAndReadSlave( uint8_t * sendBuf, size_t send_buf_len,uint8_t * receiveBuf , size_t  receiveBuf_len){

    esp_err_t result        = ESP_OK; 
    i2c_cmd_handle_t link    = i2c_cmd_link_create();

    // Send command to I2C slave
    ESP_LOGD(TAG, "%s:%d Command data is:  %i", __func__, __LINE__, sendBuf[1]);
    result = I2cWrapper::_write_to_slave( link, _i2c_master_port, sendBuf, send_buf_len);
    
    if (ESP_OK != result) {
        ESP_LOGE(TAG, "%s:%d I2C slave returned a ERROR: %s ",__func__, __LINE__,esp_err_to_name(result));
        i2c_cmd_link_delete(link);
        throw I2cException("Write Slave Error");
        return ;
    }
    i2c_cmd_link_delete(link);

    vTaskDelay(50 / portTICK_PERIOD_MS);  //Give device time to prepare; //TODO: HOW LONG
    
    ESP_LOGD(TAG,"%s:%d Read response from MDP",__func__, __LINE__);
    link = i2c_cmd_link_create();

    result = I2cWrapper::_read_from_slave(link, _i2c_master_port, receiveBuf, receiveBuf_len);
    if (ESP_OK != result) {
        ESP_LOGE(TAG, "%s:%d Read from slave returned a ERROR : %s ", __func__, __LINE__,esp_err_to_name(result)); 
        //TODO: Add error handling; 
        i2c_cmd_link_delete(link);
         throw I2cException("Read Slave Error");
        return ;
    }
    i2c_cmd_link_delete(link);
    return;
}

/// @brief Read bytes from I2C slave. 
/// @param link 
/// @param i2c_num 
/// @param data_rd Receive buffer
/// @param size Size of Receive buffer
/// @return ESP error codes
esp_err_t I2cWrapper::_read_from_slave(i2c_cmd_handle_t link, i2c_port_t i2c_num, uint8_t *data_rd, size_t size)
{
     
    ERROR_HANDLER(i2c_master_start(link));
    ERROR_HANDLER(i2c_master_write_byte(link, (_slaveAddress << 1) | READ_BIT, ACK_CHECK));
    if (size > 1) {
        ERROR_HANDLER(i2c_master_read(link, data_rd, size - 1 , ACK_VAL));  
    }
    ERROR_HANDLER(i2c_master_read_byte(link, data_rd + size - 1  , NACK_VAL));
    ERROR_HANDLER(i2c_master_stop(link));

    esp_err_t ret = i2c_master_cmd_begin(i2c_num, link, 500 / portTICK_PERIOD_MS);

    return ret;
}

/// @brief Write bytes to I2C slave. 
/// @param link 
/// @param i2c_num 
/// @param buffer Bytes to be written 
/// @param len Length of buffer
/// @return ESP error codes
esp_err_t I2cWrapper::_write_to_slave( i2c_cmd_handle_t link ,  i2c_port_t i2c_num, uint8_t *buffer, size_t len)
{
    ERROR_HANDLER(i2c_master_start(link));
    ERROR_HANDLER(i2c_master_write_byte(link, (_slaveAddress << 1) | WRITE_BIT, ACK_CHECK));
    ERROR_HANDLER(i2c_master_write(link, buffer, len, ACK_CHECK));
    ERROR_HANDLER(i2c_master_stop(link));
    esp_err_t ret = i2c_master_cmd_begin(i2c_num, link,pdMS_TO_TICKS(100)) ;
   
    return ret;
}
 

chegewara
Posts: 2207
Joined: Wed Jun 14, 2017 9:00 pm

Re: i2c issues

Postby chegewara » Tue Dec 13, 2022 9:13 pm

writeAndReadSlave(sd,10,rd,15); // Throws exception
What is the size of rd?

lg.lindstrom
Posts: 47
Joined: Fri Sep 17, 2021 4:02 pm

Re: i2c issues

Postby lg.lindstrom » Wed Dec 14, 2022 7:41 am

sd and rd is set to the same size as the "buffer length" integers, 10 respective 15.

Who is online

Users browsing this forum: ESP_Roland, ESP_rrtandler and 112 guests