-
Notifications
You must be signed in to change notification settings - Fork 7.6k
I2C slave cannot send data containing own address #6677
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
Comments
@JeffTheStig - Since you are using ESP32, please be aware that this chip has a specific way for the I2S Slave to work, which is not Arduino standard. It's necessary to pre-load the Slave answer prior to the Master Please check this lines inWire Arduino ESP example: https://github.com/espressif/arduino-esp32/blob/master/libraries/Wire/examples/WireSlave/WireSlave.ino#L28-L32
Thus, it may force the ESP32 application to use some sort of protocol, where the Master sends what sort of information it needs, and then the Slave preload the answer, then the Master just request it, and the Slave can then send it back. In other hand, Slave works exactly as Arduino API defines for the ESP32-C3, ESP32-S2 and ESP32-S3. |
@SuGlider I am so sorry, I messed up the example I wrote. I have the code setup in a different way, so I tried to make a small example that can reproduce the issue, only to swap the Request and Receive function (it was late). I understand what you mean on the preloading of the data, but that does not seem to fix the issue. I added the lines of code you suggested and tested using the following sample codes: Edit: I tried both Wire.write and Wire.print on the slave side. Master: #include "Arduino.h"
#include "Wire.h"
#define SLAVE_ADDR 0x55
#define I2C_Freq 100000
#define SDA_0 21
#define SCL_0 22
uint8_t i = 0;
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.begin(SDA_0 , SCL_0 , (uint32_t) I2C_Freq);
}
void loop() {
delay(1000);
char reading[64];
memset(reading, 0, sizeof(reading));
uint8_t error = 0;
error = Wire.requestFrom(SLAVE_ADDR, 1);
Serial.printf("requestFrom: %u\n", error);
if(error){
delay(10);
Wire.readBytes(reading, error);
Serial.printf("data: %u\n", reading[0]);
} else {
Serial.printf("Request failed.");
}
Serial.flush();
} Slave: #include "Arduino.h"
#include "Wire.h"
#define SLAVE_ADDR 0x55
#define I2C_Freq 100000
#define SDA_1 21
#define SCL_2 22
uint8_t it = 0;
void onRequest(){
uint8_t out[1];
out[0] = it;
Wire.print((char*) out);
Serial.printf("PL: %d\n", out[0]);
it++;
}
void onReceive(int len){
Serial.printf("onReceive[%d]: ", len);
while(Wire.available()){
Serial.write(Wire.read());
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.onReceive(onReceive);
Wire.onRequest(onRequest);
Wire.begin((uint8_t) SLAVE_ADDR, SDA_1, SCL_2, (uint32_t) I2C_Freq);
#if CONFIG_IDF_TARGET_ESP32
char message[64];
snprintf(message, 64, "%u Packets.", it++);
Wire.slaveWrite((uint8_t *)message, strlen(message));
#endif
}
void loop() {
} I let them run for a while, and when the slave arrived at 171, these where the outputs: Master:
Slave:
Does this mean that I have to use slaveWrite instead of write or print on the slave side? And if so, can this be added to the documentation to make it a bit more clear? |
I can confirm the issue. Just so that we are on the same page, here are the test sketches: Master#include "Arduino.h"
#include "Wire.h"
#define SLAVE_ADDR 0x55
#define I2C_Freq 100000
#define SDA_0 21
#define SCL_0 22
uint8_t i = 0;
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.begin(SDA_0 , SCL_0 , (uint32_t) I2C_Freq);
}
void loop() {
delay(1000);
uint8_t error = 0;
error = Wire.requestFrom(SLAVE_ADDR, 1);
Serial.printf("requestFrom: len:%u", error);
if(error){
Serial.printf(", data: %u\n", Wire.read());
} else {
Serial.printf(". Request failed.\n");
}
Serial.flush();
}
Slave#include "Arduino.h"
#include "Wire.h"
#define SLAVE_ADDR 0x55
#define I2C_Freq 100000
#define SDA_1 21
#define SCL_2 22
uint8_t it = 170;
void onRequest(){
Wire.write(it); // can use write/print, but recommended is slaveWrite
Serial.printf("PL: %d\n", it);
it++;
if(it > 180){ it = 170; }
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.onRequest(onRequest);
Wire.begin((uint8_t) SLAVE_ADDR, SDA_1, SCL_2, (uint32_t) I2C_Freq);
#if CONFIG_IDF_TARGET_ESP32
Wire.slaveWrite(&it, 1); // MUST use slaveWrite
Serial.printf("PL: %d\n", it);
it++;
if(it > 180){ it = 170; }
#endif
}
void loop() {
}
|
Board
nodemcu-32s
Device Description
Two nodemcu-32s boards with 2 wires connecting them.
Hardware Configuration
SDA: 21
SCL: 22
Version
v2.0.1
IDE Name
PlatformIO
Operating System
Windows
Flash frequency
40Mhz
PSRAM enabled
no
Upload speed
115200
Description
Two esp's are connected using i2c and communicate with each other. One is set to be slave, the other as master.
I slightly modified the example codes provided at https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/i2c.html. The difference is that the master will only make requests and that the slave will reply with an incrementing number.
What I found is that when the slave gets to number 171, it returns error "[951709][E][esp32-hal-i2c-slave.c:406] i2cSlaveWrite(): TX IDLE WAIT TIMEOUT!".
I was able to track it down to the following piece of code in file [email protected]\cores\esp32\esp32-hal-i2c-slave.c. On line 406, this error is called when a time-out occurs when i2c_ll_slave_addressed(i2c->dev) && i2c_ll_slave_rw(i2c->dev) stay true. The second expression should be false in this case, since the master released the bus (just like when I send 170 or 172), but it stays true.
It turned out that when I changed the address of the slave to 0x56, number 171 could be send, but now the error occured while sending number 173. What probably happens is the following:
The binary representation of address 0x55 is 01010101 and of address 0x56 is 01010110.
The binary representation of number 171 is 10101011 and of number 173 is 10101101.
What I found is that the numbers can be converted to the corresponding address by doing a left bit-shift on the address and next adding 1 (01010101 -bit-shift->10101010-add 1->10101011 = 171 dec).
This actually corresponds with the way I2C represents their addresses: it takes the 7 LSBs and the last bit is a r/w bit, so in case of address 0x55 and r/w-bit being one this would become: 1010101 for the address and then 1 for the r/w-bit = 10101011 = 171.
Could it be that the slave reads its own message and handles it as if the master is saying it is in read mode?
Sketch
On master ESP:
On slave ESP:
Debug Message
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
The text was updated successfully, but these errors were encountered: