Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32 S3 I2C issues when working as slave #10145

Open
1 task done
JorgeMALopes opened this issue Aug 12, 2024 · 17 comments
Open
1 task done

ESP32 S3 I2C issues when working as slave #10145

JorgeMALopes opened this issue Aug 12, 2024 · 17 comments
Assignees
Labels
Status: Awaiting triage Issue is waiting for triage

Comments

@JorgeMALopes
Copy link

JorgeMALopes commented Aug 12, 2024

Board

ESP32 S3 wroom 1

Device Description

Just an USB port, and a TI battery monitor.

Hardware Configuration

Currently only working with just the CPU, but has a TI battery monitor connected to the other I2C port.

Version

v3.0.3

IDE Name

Arduino IDE

Operating System

windows 10

Flash frequency

80MHz

PSRAM enabled

no

Upload speed

921600

Description

When i connect an ESP32S3 as an I2C slave to an ESP32 or a drone flight controller, as a master, the data comes out wrong.
When i reverse the code and the S3 is the master and the ESP32 is the slave then the data comes out correct.

I made a simple sketch where the slave returns 4 bytes when there is a request, 0x01FF0306 or 0x01FF03FF. The master requests a variable amount of bytes, sometimes more, sometimes less. When the S3 is the slave the first byte received from it is the slave address followed by part of the slave data. When the ESP32 is the slave then only data is returned.

I have asked a friend to lend me his oscilloscope so i can check the data lines for each case.

These are the lines for the S3 as a slave, notice the long time after the request and the repetition of the slave address.
scope_2
scope_1
scope_0

This is the lines for ESP32 as slave, the delay is minimal and there is no repetition of the slave address.
scope_3

The most stable case was then the returned bytes where of the same quantity as the requested ones, but sometimes the device address appears in the beginning and the only way to fix it is to reset the S3 which is not a viable solution.

I have tested with wire and wire1 and tested with other connections on the S3.

Sketch

-----------------------------------Slave code:-----------------------------

#include "Wire.h"             // i2c library

#define I2C_DEV_ADDR 0x30     // i2c adress, needs to be the same as in the lua script

typedef union {         // union for sending int via i2c
  int i;
  byte b[4];
} Dados_I;

Dados_I batata;

void setup() {
  Serial.begin(115200);        // start the serial port, used for debuging
  Serial.setDebugOutput(true);

  Wire.begin(I2C_DEV_ADDR,13,14,0);// start the i2c channel with the I2C_DEV_ADDR adress
  Wire.onRequest(onRequest);    // if there is a i2c request call then onRequest function is called
  Serial.println("setup");

  batata.i=0x01FF0306;
}

void loop() {
  // put your main code here, to run repeatedly:
}

void onRequest() {          // on request function, sends data via i2c depeding on the request
 Wire.write(batata.b, 4);
}

-----------------------------------master code:-----------------------------

#include "Wire.h"

#define I2C_DEV_ADDR 0x30

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Wire.begin();
}

void loop() {
  delay(100);

  uint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 2);
  Serial.printf("requestFrom: %u\n", bytesReceived);
  if ((bool)bytesReceived) {  //If received more than zero bytes
    uint8_t temp[bytesReceived];
    Wire.readBytes(temp, bytesReceived);
    log_print_buf(temp, bytesReceived);
  }
}

Debug Message

--------------ESP32 master:-------------

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1288
load:0x40078000,len:13872
load:0x40080400,len:4
ho 8 tail 4 room 4
load:0x40080404,len:3048
entry 0x40080590
[    16][D][esp32-hal-cpu.c:264] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
=========== Before Setup Start ===========
Chip Info:
------------------------------------------
  Model             : ESP32
  Package           : D0WD-Q5
  Revision          : 1.44
  Cores             : 2
  CPU Frequency     : 240 MHz
  XTAL Frequency    : 40 MHz
  Embedded Flash    : No
  Embedded PSRAM    : No
  2.4GHz WiFi       : Yes
  Classic BT        : Yes
  BT Low Energy     : Yes
  IEEE 802.15.4     : No
-----------------------------------------INTERNAL Memory Info:
------------------------------------------
  Total Size        :   382260 B ( 373.3 KB)
  Free Bytes        :   352228 B ( 344.0 KB)
  Allocated Bytes   :    22980 B (  22.4 KB)
  Minimum Free Bytes:   346716 B ( 338.6 KB)
  Largest Free Block:   118772 B ( 116.0 KB)
------------------------------------------
Flash Info:
------------------------------------------
  Chip Size         :  4194304 B (4 MB)
  Block Size        :    65536 B (  64.0 KB)
  Sector Size       :     4096 B (   4.0 KB)
  Page Size         :      256 B (   0.2 KB)
  Bus Speed         : 80 MHz
  Bus Mode          : DIO
------------------------------------------
Partitions Info:
------------------------------------------
                nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS
            otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA
               app0 : addr: 0x00010000, size:  1280.0 KB, type:  APP, subtype: OTA_0
               app1 : addr: 0x00150000, size:  1280.0 KB, type:  APP, subtype: OTA_1
             spiffs : addr: 0x00290000, size:  1408.0 KB, type: DATA, subtype: SPIFFS
           coredump : addr: 0x003F0000, size:    64.0 KB, type: DATA, subtype: COREDUMP
------------------------------------------
Software Info:
------------------------------------------
  Compile Date/Time : Aug 12 2024 10:15:22
  Compile Host OS   : windows
  ESP-IDF Version   : v5.1.4-497-gdc859c1e67-dirty
  Arduino Version   : 3.0.3
------------------------------------------
Board Info:
------------------------------------------
  Arduino Board     : ESP32_DEV
  Arduino Variant   : doitESP32devkitV1
  Arduino FQBN      : esp32:esp32:esp32doit-devkit-v1:UploadSpeed=921600,FlashFreq=80,DebugLevel=debug,EraseFlash=none
============ Before Setup End ============
[   515][I][esp32-hal-i2c.c:109] i2cInit(): Initializing I2C Master: sda=21 scl=22 freq=100000
=========== After Setup Start ============
INTERNAL Memory Info:
------------------------------------------
  Total Size        :   382260 B ( 373.3 KB)
  Free Bytes        :   349208 B ( 341.0 KB)
  Allocated Bytes   :    25552 B (  25.0 KB)
  Minimum Free Bytes:   343696 B ( 335.6 KB)
  Largest Free Block:   118772 B ( 116.0 KB)
------------------------------------------
GPIO Info:
------------------------------------------
  GPIO : BUS_TYPE[bus/unit][chan]
  --------------------------------------  
     1 : UART_TX[0]
     3 : UART_RX[0]
    21 : I2C_MASTER_SDA[0]
    22 : I2C_MASTER_SCL[0]
============ After Setup End =============


-----------------esp32 S3 slave------------

CPU Frequency     : 240 MHz
setup
=========== Before Setup Start ===========
Chip Info:
------------------------------------------
  Model             : ESP32-S3
  Package           : 0
  Revision          : 2
  Cores             : 2
  CPU Frequency     : 240 MHz
  XTAL Frequency    : 40 MHz
  Embedded Flash    : No
  Embedded PSRAM    : No
  2.4GHz WiFi       : Yes
  Classic BT        : No
  BT Low Energy     : Yes
  IEEE 802.15.4     : No
------------------------------------------
INTERNAL Memory Info:
------------------------------------------
  Total Size        :   396660 B ( 387.4 KB)
  Free Bytes        :   364480 B ( 355.9 KB)
  Allocated Bytes   :    27292 B (  26.7 KB)
  Minimum Free Bytes:   359432 B ( 351.0 KB)
  Largest Free Block:   327668 B ( 320.0 KB)
------------------------------------------
Flash Info:
------------------------------------------
  Chip Size         : 16777216 B (16 MB)
  Block Size        :    65536 B (  64.0 KB)
  Sector Size       :     4096 B (   4.0 KB)
  Page Size         :      256 B (   0.2 KB)
  Bus Speed         : 80 MHz
  Bus Mode          : QIO
------------------------------------------
Partitions Info:
------------------------------------------
                nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS
            otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA
               app0 : addr: 0x00010000, size:  3072.0 KB, type:  APP, subtype: OTA_0
               app1 : addr: 0x00310000, size:  3072.0 KB, type:  APP, subtype: OTA_1
               ffat : addr: 0x00610000, size: 10112.0 KB, type: DATA, subtype: FAT
           coredump : addr: 0x00FF0000, size:    64.0 KB, type: DATA, subtype: COREDUMP
------------------------------------------
Software Info:
------------------------------------------
  Compile Date/Time : Aug 12 2024 10:26:11
  Compile Host OS   : windows
  ESP-IDF Version   : v5.1.4-497-gdc859c1e67-dirty
  Arduino Version   : 3.0.3
------------------------------------------
Board Info:
------------------------------------------
  Arduino Board     : ESP32S3_DEV
  Arduino Variant   : esp32s3
  Arduino FQBN      : esp32:esp32:esp32s3:UploadSpeed=921600,USBMode=hwcdc,CDCOnBoot=cdc,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,CPUFreq=240,FlashMode=qio,FlashSize=16M,PartitionScheme=app3M_fat9M_16MB,DebugLevel=debug,PSRAM=disabled,LoopCore=1,EventsCore=1,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default
============ Before Setup End ============
[  1291][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 19 already has type USB_DM (45) with bus 0x3fc965c4
[  1291][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 20 already has type USB_DP (46) with bus 0x3fc965c4
[  1300][I][esp32-hal-i2c-slave.c:250] i2cSlaveInit(): Initializing I2C Slave: sda=14 scl=21 freq=100000, addr=0x30
[  1310][D][esp32-hal-i2c-slave.c:514] i2c_slave_set_frequency(): Fifo thresholds: rx_fifo_full = 28, tx_fifo_empty = 4
setup
=========== After Setup Start ============
INTERNAL Memory Info:
------------------------------------------
  Total Size        :   396660 B ( 387.4 KB)
  Free Bytes        :   358416 B ( 350.0 KB)
  Allocated Bytes   :    33052 B (  32.3 KB)
  Minimum Free Bytes:   353320 B ( 345.0 KB)
  Largest Free Block:   327668 B ( 320.0 KB)
------------------------------------------
GPIO Info:
------------------------------------------
  GPIO : BUS_TYPE[bus/unit][chan]
  --------------------------------------  
    14 : I2C_SLAVE_SDA[0]
    19 : USB_DM
    20 : USB_DP
    21 : I2C_SLAVE_SCL[0]
    43 : UART_TX[0]
    44 : UART_RX[0]
============ After Setup End =============

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@JorgeMALopes JorgeMALopes added the Status: Awaiting triage Issue is waiting for triage label Aug 12, 2024
@JorgeMALopes
Copy link
Author

esp32
S3

I got a pc based logic analyzer and an ESP32 S3 devkitc devboard and using the same code the same issue happens.

@me-no-dev
Copy link
Member

The ESP32's Slave works differently than all other chips we have. ESP32 needs data to be PRELOADED before the request is received. Fore reference are these lines in the slave example. That is why there is no delay between the address and the data. All other chips wait for the request to be handled and data written to the fifo, which is then returned.
In the code above, ESP32 returns the previous Wire.write.

@JorgeMALopes
Copy link
Author

The issue i am having is with the ESP32-S3 as a slave.
The first byte that the S3 slave sends is the slave address and not the data that was requested and it is trying to write with
Wire.write(batata.b, 4); in the onRequest().
This happens even when the master is an STM arm based flight controller.

This is also happening if i program the S3 with IDF.

@me-no-dev
Copy link
Member

I tried the code. the only change I made was to write two bytes, because that is how many you read in your master sketch and the result is as expected

requestFrom: 2
0x06, 0x03, // ..

@JorgeMALopes
Copy link
Author

JorgeMALopes commented Sep 10, 2024

Thank you.
I have noticed that works in this case. The code i put here is a very simplified version of what i am making and in that sometimes the data comes clean and sometimes it comes contaminated with a random byte. What confuses me is that the random byte that appears is the slave address byte. Is this a normal thing?

As a further experiment into this, if you request 5 bytes and the slave writes 4 bytes the response fluctuates:

requestFrom: 5
0x61, 0x61, 0x06, 0x03, 0x03, // aa...
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x06, 0x03, 0x03, 0x03, 0x03, // .....
requestFrom: 5
0x61, 0x61, 0x61, 0x61, 0x61, // aaaaa
requestFrom: 5

Why is the slave address appearing in the data?

@me-no-dev
Copy link
Member

where is it appearing? the slave address is 0x30 not 0x03

@me-no-dev
Copy link
Member

Please make sure that you write as many bytes as will be read. That is important, else you are reading random bytes in the fifo

@JorgeMALopes
Copy link
Author

The slave address is 0x30, if you bit shift it left once and put in the read bit it becomes 0x61. This follows when i change the slave address, 0x10 becomes 0x21. This is the data that is poluting the response.
Here is a capture of the data, notice that the first byte that is received as data is the same as the address byte plus the read bit.
adrees in data

Also I got it to get that random byte to appear even when i request the same size of data that the slave is writing.

bad data 4

I did one request for 1 byte, uploaded to the esp32 master and then changed the code and requested 4 bytes and uploaded to esp32 master, now it is locked in this situation. It comes out of this situation when i reset the S3.

Also it is kind of weird that if i place 4 known bytes in the fifo and read 3 bytes the first byte is the device address bit shifted left once plus the read bit.

@JorgeMALopes
Copy link
Author

After some playing around i noticed that if the ESP32 S3 slave does not write to the fifo then what is read by the ESP32 master is the left bit shifted address of the slave + 1.

Capturarar

Does this mean that on the previous examples the ESP32 S3 slave is to slow to populate the fifo?

I hope i am not being annoying, am truly trying to figure this out.
I am trying to avoid having to replace the ESP32 S3 with something else that is more stable.

Thanks for all the help.

@me-no-dev
Copy link
Member

You must read as many bytes as you wrote. That is all. No other tricks are necessary

@JorgeMALopes
Copy link
Author

I will try that. Thank you.

@JorgeMALopes
Copy link
Author

JorgeMALopes commented Sep 10, 2024

Same issue happens irregularly.

Master code:

#include "Wire.h"

#define I2C_DEV_ADDR 0x30

typedef union {          // union for sending int via i2c
  int i;
  byte b[4];
} Dados_I;


typedef union {         // union for sending float via i2c
  float f;
  byte b[4];
} Dados_F;


typedef union {        // union for sending a boolean via i2c
  bool bo;
  byte b[1];
} Dados_Bool;


// values that are requested from the smart battery
const int req_health = 1;       // battery health
const int req_voltage = 2;        // total battery voltage
const int req_cell_count = 3;     // cell count
const int req_rem_capacity_pct = 4;   // remaining capacity in percentage
const int req_cycle_count = 5;      // cycle count
const int req_current = 6;        // battery current
const int req_consumed_mah = 7;     // consumed capacity in mah
const int req_consumed_wh = 8;      // consumed capacity in wh
const int req_temperature = 9;      // battery temperature
const int req_cell_voltage_1 = 11;    // cell voltages for each of the cells
const int req_cell_voltage_2 = 12;
const int req_cell_voltage_3 = 13;
const int req_cell_voltage_4 = 14;
const int req_cell_voltage_5 = 15;
const int req_cell_voltage_6 = 16;
const int req_cell_voltage_7 = 17;
const int req_cell_voltage_8 = 18;
const int req_cell_voltage_9 = 19;
const int req_cell_voltage_10 = 20;
const int req_cell_voltage_11 = 21;
const int req_cell_voltage_12 = 22;
const int req_cell_voltage_13 = 23;
const int req_cell_voltage_14 = 24;
const int req_cell_voltage_15 = 25;
const int req_cell_voltage_16 = 26;
const int req_cell_voltage_17 = 27;
const int req_cell_voltage_18 = 28;
const int req_cell_voltage_19 = 29;
const int req_cell_voltage_20 = 30;
const int req_cell_voltage_21 = 31;
const int req_cell_voltage_22 = 32;
const int req_cell_voltage_23 = 33;
const int req_cell_voltage_24 = 34;

Dados_Bool health;          // local variable where the batttery health is stored
Dados_F voltage;          // local variable where the batttery voltage is stored (V)
Dados_I cell_count;         // local variable where the batttery cell count is stored
Dados_I rem_capacity_pct;     // local variable where the batttery capacity is stored (%)
Dados_I cycle_count;        // local variable where the batttery cycle count is stored
Dados_F current;          // local variable where the batttery current count is stored (A)
Dados_F consumed_mah;       // local variable where the batttery consumed mah is stored (mah)
Dados_F consumed_wh;        // local variable where the batttery consumed wh is stored (wh)
Dados_F temperature;        // local variable where the batttery temperature is stored (c)
Dados_I cell_voltage_1;       // local variables where the batttery cell voltages are stored (mv)
Dados_I cell_voltage_2;
Dados_I cell_voltage_3;
Dados_I cell_voltage_4;
Dados_I cell_voltage_5;
Dados_I cell_voltage_6;
Dados_I cell_voltage_7;
Dados_I cell_voltage_8;
Dados_I cell_voltage_9;
Dados_I cell_voltage_10;
Dados_I cell_voltage_11;
Dados_I cell_voltage_12;
Dados_I cell_voltage_13;
Dados_I cell_voltage_14;
Dados_I cell_voltage_15;
Dados_I cell_voltage_16;
Dados_I cell_voltage_17;
Dados_I cell_voltage_18;
Dados_I cell_voltage_19;
Dados_I cell_voltage_20;
Dados_I cell_voltage_21;
Dados_I cell_voltage_22;
Dados_I cell_voltage_23;
Dados_I cell_voltage_24;

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Wire.begin();
}

void loop() {
  delay(500);
  health.b[0] = i2cBoolGet(req_health);
  voltage.f = i2cFloatGet(req_voltage);
  cell_count.i = i2cIntGet(req_cell_count);
  rem_capacity_pct.i = i2cIntGet(req_rem_capacity_pct);
  cycle_count.i = i2cIntGet(req_cycle_count);
  current.f = i2cFloatGet(req_current);
  consumed_mah.f = i2cFloatGet(req_consumed_mah);
  consumed_wh.f = i2cFloatGet(req_consumed_wh);
  temperature.f = i2cFloatGet(req_temperature);
  cell_voltage_1.i = i2cIntGet(req_cell_voltage_1);
  cell_voltage_2.i = i2cIntGet(req_cell_voltage_2);
  cell_voltage_3.i = i2cIntGet(req_cell_voltage_3);
  cell_voltage_4.i = i2cIntGet(req_cell_voltage_4);
  cell_voltage_5.i = i2cIntGet(req_cell_voltage_5);
  cell_voltage_6.i = i2cIntGet(req_cell_voltage_6);
  cell_voltage_7.i = i2cIntGet(req_cell_voltage_7);
  cell_voltage_8.i = i2cIntGet(req_cell_voltage_8);
  cell_voltage_9.i = i2cIntGet(req_cell_voltage_9);
  cell_voltage_10.i = i2cIntGet(req_cell_voltage_10);
  cell_voltage_11.i = i2cIntGet(req_cell_voltage_11);
  cell_voltage_12.i = i2cIntGet(req_cell_voltage_12);
  cell_voltage_13.i = i2cIntGet(req_cell_voltage_13);
  cell_voltage_14.i = i2cIntGet(req_cell_voltage_14);
  cell_voltage_15.i = i2cIntGet(req_cell_voltage_15);
  cell_voltage_16.i = i2cIntGet(req_cell_voltage_16);
  cell_voltage_17.i = i2cIntGet(req_cell_voltage_17);
  cell_voltage_18.i = i2cIntGet(req_cell_voltage_18);
  cell_voltage_19.i = i2cIntGet(req_cell_voltage_19);
  cell_voltage_20.i = i2cIntGet(req_cell_voltage_20);
  cell_voltage_21.i = i2cIntGet(req_cell_voltage_21);
  cell_voltage_22.i = i2cIntGet(req_cell_voltage_22);
  cell_voltage_23.i = i2cIntGet(req_cell_voltage_23);
  cell_voltage_24.i = i2cIntGet(req_cell_voltage_24);

  Serial.println("=====================");
  Serial.print("health.bo = "); Serial.println(health.b[0]);
  Serial.print("voltage.f = "); Serial.println(voltage.f);
  Serial.print("cell_count.i = "); Serial.println(cell_count.i);
  Serial.print("rem_capacity_pct.i = "); Serial.println(rem_capacity_pct.i);
  Serial.print("cycle_count.i = "); Serial.println(cycle_count.i);
  Serial.print("current.f = "); Serial.println(current.f);
  Serial.print("consumed_mah.f = "); Serial.println(consumed_mah.f);
  Serial.print("consumed_wh.f = "); Serial.println(consumed_wh.f);
  Serial.print("temperature.f = "); Serial.println(temperature.f); 
  Serial.print("cell_voltage_1.i = "); Serial.println(cell_voltage_1.i);
  Serial.print("cell_voltage_2.i = "); Serial.println(cell_voltage_2.i);
  Serial.print("cell_voltage_3.i = "); Serial.println(cell_voltage_3.i);
  Serial.print("cell_voltage_4.i = "); Serial.println(cell_voltage_4.i);
  Serial.print("cell_voltage_5.i = "); Serial.println(cell_voltage_5.i);
  Serial.print("cell_voltage_6.i = "); Serial.println(cell_voltage_6.i);
  Serial.print("cell_voltage_7.i = "); Serial.println(cell_voltage_7.i);
  Serial.print("cell_voltage_8.i = "); Serial.println(cell_voltage_8.i);
  Serial.print("cell_voltage_9.i = "); Serial.println(cell_voltage_9.i);
  Serial.print("cell_voltage_10.i = "); Serial.println(cell_voltage_10.i);
  Serial.print("cell_voltage_11.i = "); Serial.println(cell_voltage_11.i);
  Serial.print("cell_voltage_12.i = "); Serial.println(cell_voltage_12.i);
  Serial.print("cell_voltage_13.i = "); Serial.println(cell_voltage_13.i);
  Serial.print("cell_voltage_14.i = "); Serial.println(cell_voltage_14.i);
  Serial.print("cell_voltage_15.i = "); Serial.println(cell_voltage_15.i);
  Serial.print("cell_voltage_16.i = "); Serial.println(cell_voltage_16.i);
  Serial.print("cell_voltage_17.i = "); Serial.println(cell_voltage_17.i);
  Serial.print("cell_voltage_18.i = "); Serial.println(cell_voltage_18.i);
  Serial.print("cell_voltage_19.i = "); Serial.println(cell_voltage_19.i);
  Serial.print("cell_voltage_20.i = "); Serial.println(cell_voltage_20.i);
  Serial.print("cell_voltage_21.i = "); Serial.println(cell_voltage_21.i);
  Serial.print("cell_voltage_22.i = "); Serial.println(cell_voltage_22.i);
  Serial.print("cell_voltage_23.i = "); Serial.println(cell_voltage_23.i);
  Serial.print("cell_voltage_24.i = "); Serial.println(cell_voltage_24.i);
  Serial.println();
}

byte i2cBoolGet(int command) {
  Wire.beginTransmission(I2C_DEV_ADDR);  // transmit to device #4
  Wire.write(command);                   // sends one byte
  Wire.endTransmission();                // stop transmitting

  byte value[1];
  Wire.requestFrom(I2C_DEV_ADDR, 1);
  Wire.readBytes(value, 1);
  return value[0];
}

int i2cIntGet(int command) {
  Wire.beginTransmission(I2C_DEV_ADDR);  // transmit to device #4
  Wire.write(command);                   // sends one byte
  Wire.endTransmission();                // stop transmitting

  Dados_I value;
  Wire.requestFrom(I2C_DEV_ADDR, 4);
  Wire.readBytes(value.b, 4);
  return value.i;
}

float i2cFloatGet(int command) {
  Wire.beginTransmission(I2C_DEV_ADDR);  // transmit to device #4
  Wire.write(command);                   // sends one byte
  Wire.endTransmission();                // stop transmitting

  Dados_F value;
  Wire.requestFrom(I2C_DEV_ADDR, 4);
  Wire.readBytes(value.b, 4);
  return value.f;
}

Slave code:

#include "Wire.h"             // i2c library

#define I2C_DEV_ADDR 0x30     // i2c adress, needs to be the same as in the lua script

int opcode = 0;             // received operation code
int i2cCommand = 0;           // received i2c command

typedef union {         // union for sending int via i2c
  int i;
  byte b[4];
} Dados_I;


typedef union {         // union for sending float via i2c
  float f;
  byte b[4];
} Dados_F;


typedef union {        // union for sending a boolean via i2c
  bool bo;
  byte b[1];
} Dados_Bool;

// values that are requested from the smart battery
const int req_health = 1;       // battery health
const int req_voltage = 2;        // total battery voltage
const int req_cell_count = 3;     // cell count
const int req_rem_capacity_pct = 4;   // remaining capacity in percentage
const int req_cycle_count = 5;      // cycle count
const int req_current = 6;        // battery current
const int req_consumed_mah = 7;     // consumed capacity in mah
const int req_consumed_wh = 8;      // consumed capacity in wh
const int req_temperature = 9;      // battery temperature
const int req_cell_voltage_1 = 11;    // cell voltages for each of the cells
const int req_cell_voltage_2 = 12;
const int req_cell_voltage_3 = 13;
const int req_cell_voltage_4 = 14;
const int req_cell_voltage_5 = 15;
const int req_cell_voltage_6 = 16;
const int req_cell_voltage_7 = 17;
const int req_cell_voltage_8 = 18;
const int req_cell_voltage_9 = 19;
const int req_cell_voltage_10 = 20;
const int req_cell_voltage_11 = 21;
const int req_cell_voltage_12 = 22;
const int req_cell_voltage_13 = 23;
const int req_cell_voltage_14 = 24;
const int req_cell_voltage_15 = 25;
const int req_cell_voltage_16 = 26;
const int req_cell_voltage_17 = 27;
const int req_cell_voltage_18 = 28;
const int req_cell_voltage_19 = 29;
const int req_cell_voltage_20 = 30;
const int req_cell_voltage_21 = 31;
const int req_cell_voltage_22 = 32;
const int req_cell_voltage_23 = 33;
const int req_cell_voltage_24 = 34;

Dados_Bool health;          // local variable where the batttery health is stored
Dados_F voltage;          // local variable where the batttery voltage is stored (V)
Dados_I cell_count;         // local variable where the batttery cell count is stored
Dados_I rem_capacity_pct;     // local variable where the batttery capacity is stored (%)
Dados_I cycle_count;        // local variable where the batttery cycle count is stored
Dados_F current;          // local variable where the batttery current count is stored (A)
Dados_F consumed_mah;       // local variable where the batttery consumed mah is stored (mah)
Dados_F consumed_wh;        // local variable where the batttery consumed wh is stored (wh)
Dados_F temperature;        // local variable where the batttery temperature is stored (c)
Dados_I cell_voltage_1;       // local variables where the batttery cell voltages are stored (mv)
Dados_I cell_voltage_2;
Dados_I cell_voltage_3;
Dados_I cell_voltage_4;
Dados_I cell_voltage_5;
Dados_I cell_voltage_6;
Dados_I cell_voltage_7;
Dados_I cell_voltage_8;
Dados_I cell_voltage_9;
Dados_I cell_voltage_10;
Dados_I cell_voltage_11;
Dados_I cell_voltage_12;
Dados_I cell_voltage_13;
Dados_I cell_voltage_14;
Dados_I cell_voltage_15;
Dados_I cell_voltage_16;
Dados_I cell_voltage_17;
Dados_I cell_voltage_18;
Dados_I cell_voltage_19;
Dados_I cell_voltage_20;
Dados_I cell_voltage_21;
Dados_I cell_voltage_22;
Dados_I cell_voltage_23;
Dados_I cell_voltage_24;

void setup() {
  Serial.begin(115200);        // start the serial port, used for debuging
  Serial.setDebugOutput(true);

  Wire.begin(I2C_DEV_ADDR, 42, 41, 0 ); // start the i2c channel with the I2C_DEV_ADDR adress
  Wire.onReceive(onReceive);    // if there is a i2c receive call then onReceive function is called
  Wire.onRequest(onRequest);    // if there is a i2c request call then onRequest function is called
  Serial.println("setup");
}

void loop() {
  setValues();
}

void onReceive(int len) {     // on receive function, used to update local variables or activate local functions
  Serial.print("receive[");
  Serial.print(len);
  Serial.print("]: ");
  i2cCommand = 0;       // resets the command
  opcode = Wire.read();     // reads the operation code
  Serial.print(opcode);
  if (len == 2) {       // if there are 2 bytes
    i2cCommand = Wire.read(); // the second byte is the command
    Serial.print(", ");
    Serial.print(i2cCommand);
  }
  Serial.println();
}

void onRequest() {          // on request function, sends data via i2c depeding on the request
  Serial.print("request: ");
  Serial.println(opcode);
  loadValues();
}

void setValues(){
  health.bo = true;
  voltage.f = 35.5;
  cell_count.i = 10;
  rem_capacity_pct.i = 55;
  cycle_count.i = 10;
  current.f = 40.35;
  consumed_mah.f = 20.2;
  consumed_wh.f = 11.3;
  temperature.f = 30.2;
  cell_voltage_1.i = 3000;
  cell_voltage_2.i = 3000;
  cell_voltage_3.i = 3000;
  cell_voltage_4.i = 3000;
  cell_voltage_5.i = 3000;
  cell_voltage_6.i = 3000;
  cell_voltage_7.i = 3000;
  cell_voltage_8.i = 3000;
  cell_voltage_9.i = 3000;
  cell_voltage_10.i = 3000;
  cell_voltage_11.i = 4;
  cell_voltage_12.i = 4;
  cell_voltage_13.i = 4;
  cell_voltage_14.i = 4;
  cell_voltage_15.i = 4;
  cell_voltage_16.i = 4;
  cell_voltage_17.i = 4;
  cell_voltage_18.i = 4;
  cell_voltage_19.i = 4;
  cell_voltage_20.i = 4;
  cell_voltage_21.i = 4;
  cell_voltage_22.i = 4;
  cell_voltage_23.i = 4;
  cell_voltage_24.i = 4;  
}

void loadValues(){
  switch (opcode) {
    case req_health:
      Wire.write(health.b, 1);
      break;

    case req_voltage:
      Wire.write(voltage.b, 4);
      break;

    case req_cell_count:
      Wire.write(cell_count.b, 4);
      break;

    case req_rem_capacity_pct:
      Wire.write(rem_capacity_pct.b, 4);
      break;

    case req_cycle_count:
      Wire.write(cycle_count.b, 4);
      break;

    case req_current:
      Wire.write(current.b, 4);
      break;

    case req_consumed_mah:
      Wire.write(consumed_mah.b, 4);
      break;

    case req_consumed_wh:
      Wire.write(consumed_wh.b, 4);
      break;

    case req_temperature:
      Wire.write(temperature.b, 4);
      break;

    case req_cell_voltage_1:
      Wire.write(cell_voltage_1.b, 4);
      break;

    case req_cell_voltage_2:
      Wire.write(cell_voltage_2.b, 4);
      break;

    case req_cell_voltage_3:
      Wire.write(cell_voltage_3.b, 4);
      break;

    case req_cell_voltage_4:
      Wire.write(cell_voltage_4.b, 4);
      break;

    case req_cell_voltage_5:
      Wire.write(cell_voltage_5.b, 4);
      break;

    case req_cell_voltage_6:
      Wire.write(cell_voltage_6.b, 4);
      break;

    case req_cell_voltage_7:
      Wire.write(cell_voltage_7.b, 4);
      break;

    case req_cell_voltage_8:
      Wire.write(cell_voltage_8.b, 4);
      break;

    case req_cell_voltage_9:
      Wire.write(cell_voltage_9.b, 4);
      break;

    case req_cell_voltage_10:
      Wire.write(cell_voltage_10.b, 4);
      break;

    case req_cell_voltage_11:
      Wire.write(cell_voltage_11.b, 4);
      break;

    case req_cell_voltage_12:
      Wire.write(cell_voltage_12.b, 4);
      break;

    case req_cell_voltage_13:
      Wire.write(cell_voltage_13.b, 4);
      break;

    case req_cell_voltage_14:
      Wire.write(cell_voltage_14.b, 4);
      break;

    case req_cell_voltage_15:
      Wire.write(cell_voltage_15.b, 4);
      break;

    case req_cell_voltage_16:
      Wire.write(cell_voltage_16.b, 4);
      break;

    case req_cell_voltage_17:
      Wire.write(cell_voltage_17.b, 4);
      break;

    case req_cell_voltage_18:
      Wire.write(cell_voltage_18.b, 4);
      break;

    case req_cell_voltage_19:
      Wire.write(cell_voltage_19.b, 4);
      break;

    case req_cell_voltage_20:
      Wire.write(cell_voltage_20.b, 4);
      break;

    case req_cell_voltage_21:
      Wire.write(cell_voltage_21.b, 4);
      break;

    case req_cell_voltage_22:
      Wire.write(cell_voltage_22.b, 4);
      break;

    case req_cell_voltage_23:
      Wire.write(cell_voltage_23.b, 4);
      break;

    case req_cell_voltage_24:
      Wire.write(cell_voltage_24.b, 4);
      break;

    default:
      break;
  }
}

What i should be getting is:
original

I am getting this:
outputdata

Notice the decimal 97 =0x61 when i request the health byte and the 768097 value, if you convert it into hex you get 0x0B, 0xB8 and 0x61, the value that is the slave adress bit shifted left + 1.

There are no tricks, I send the same amount of bytes that are requested.

It fixes itself if i reset the slave. This is not optimal.

@JorgeMALopes
Copy link
Author

I don't know why the code breaks when i paste it into the code tags. I'm sorry for that.

@me-no-dev
Copy link
Member

I have slightly revised your example above. Mostly prints and it's functionally the same. I use the same pins and all.
Screenshot 2024-09-11 at 12 27 34

@me-no-dev
Copy link
Member

One suggestion for your use case. Use Wire.slaveWrite(data, len) instead of Wire.write(data, len). Then you can load the values directly in the onReceive callback. That will make communication faster too. Also do not print inside the callbacks. It takes time and slows things down.

void onReceive(int len) {     // on receive function, used to update local variables or activate local functions
  i2cCommand = 0;             // resets the command
  opcode = Wire.read();       // reads the operation code
  if (len == 2) {             // if there are 2 bytes
    i2cCommand = Wire.read(); // the second byte is the command
  }
  loadValues();               // load the values here
}

void onRequest() {
}

void loadValues(){
  switch (opcode) {
    case req_health:
      Wire.slaveWrite(health.b, 1);
      break;

    case req_voltage:
      Wire.slaveWrite(voltage.b, 4);
      break;
 ............

@JorgeMALopes
Copy link
Author

Wonderful. Thank you.
I will try it now.

@me-no-dev
Copy link
Member

@JorgeMALopes any news?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Awaiting triage Issue is waiting for triage
Projects
None yet
Development

No branches or pull requests

2 participants