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 ?
i2c issues
-
- Posts: 9749
- Joined: Thu Nov 26, 2015 4:08 am
Re: i2c issues
Can you post your code? (Or at least the relevant bits?)
-
- Posts: 48
- Joined: Fri Sep 17, 2021 4:02 pm
Re: i2c issues
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:
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.
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;
}
Re: i2c issues
What is the size of rd?writeAndReadSlave(sd,10,rd,15); // Throws exception
-
- Posts: 48
- Joined: Fri Sep 17, 2021 4:02 pm
Re: i2c issues
sd and rd is set to the same size as the "buffer length" integers, 10 respective 15.
Who is online
Users browsing this forum: No registered users and 111 guests