Skip to content

AIR001的I2C作从机,接收主机用Wire.write发送过来的数据异常 #67

Open

Description

@luckycheng2017

描述一下这个bug / Describe the bug

两块板子,一块是ESP32C3,另一块是AIR001,用I2C连接,有接上拉电阻。ESP32C3作主机,AIR001作从机。ESP32C3主机用Wire.write方法发送操作多个字节的数据时,反馈结果是2,AIR001从机那边没有收到数据。之前 #34 这个bug有提过,但是没彻底解决。

复现步骤 / To Reproduce

从机先复位,然后主机复位,主机能找到从机的地址,从机没有收到主机发送过来的数据。

如果正常,应该是什么样 / Expected behavior

正常AIR001从机能够读取到ESP32主机发过来的数据。

截图 / Screenshots

ESP32C3主机代码:
`
#include <Wire.h>

#define I2C_slave_ADDR 0x08

uint8_t hello[] = {1, 2, 3, 4, 5, 6};
uint8_t aTxBuffer[] = "你好";
uint8_t myBuffer[10];

void setup() {
Wire.setClock(100000);
Wire.begin(4, 5);

Serial.begin(9600);

byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
}

void loop() {
Wire.beginTransmission(I2C_slave_ADDR);
Wire.write((uint8_t *) hello, sizeof(hello));
Serial.print("发送:");
Serial.println(Wire.endTransmission());
delay(2000);
}

`

AIR001从机代码
`
#include <Wire.h>

#define I2C_ADDR 0x08

uint8_t hello[] = {1, 2, 3};
uint8_t aTxBuffer[] = "你好";

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
while(1 < Wire.available()) // loop through all but the last
{
int c = Wire.read(); // receive byte as a character
Serial.println(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
int res = Wire.write((uint8_t *) hello, sizeof(hello));
Serial.print("发送数据, res = ");
Serial.println(res);
}

void setup()
{
Serial.begin(9600); // start serial for output

Wire.setSDA(PF_0);
Wire.setSCL(PF_1);
Wire.setClock(100000);
Wire.begin((int) I2C_ADDR, false, true); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
}

void loop()
{
//empty loop
}
`

日志 / Logs

主机日志:
990ff76fdbc68116e70e62105a953fa

从机日志:
e955f0e6a6af9b15ba693432f75f7dc

系统 / System

Win10

PACK包版本 / Version

0.4.5

验证

  • 检查过该问题,之前没有人提过 / Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • 提供了最小可复现工程或详细的复现步骤,确保开发者可以复现 / The provided reproduction is a minimal reproducible example of the bug.
  • 已经提供了完整的报错信息、日志、截图,没有经过删减。

Activity

  1. luckycheng2017 commented on Sep 7, 2023

    @luckycheng2017
    Author

    补充说明:差不多同一份代码,修改一下引脚,两个ESP32C3的板子之间I2C通信是正常的。
    ESP32C3主机代码:
    `
    #include <Wire.h>

    #define I2C_slave_ADDR 0x08

    uint8_t hello[] = {1, 2, 3, 4, 5, 6};
    uint8_t aTxBuffer[] = "你好";
    uint8_t myBuffer[10];

    void setup() {
    Wire.setClock(100000);
    Wire.begin(4, 5);

    Serial.begin(9600);

    byte error, address;
    int nDevices;
    Serial.println("Scanning...");
    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
    Serial.print("I2C device found at address 0x");
    if (address<16) {
    Serial.print("0");
    }
    Serial.println(address,HEX);
    nDevices++;
    }
    else if (error==4) {
    Serial.print("Unknow error at address 0x");
    if (address<16) {
    Serial.print("0");
    }
    Serial.println(address,HEX);
    }
    }
    if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
    }
    else {
    Serial.println("done\n");
    }
    }

    void loop() {
    Wire.beginTransmission(I2C_slave_ADDR);
    Wire.write((uint8_t *) hello, sizeof(hello));
    Serial.print("发送:");
    Serial.println(Wire.endTransmission());
    delay(2000);
    }

    `

    ESP32C3从机代码:
    `
    #include <Wire.h>

    #define I2C_slave_ADDR 0x08

    uint8_t hello[] = {1, 2, 3, 4, 5, 6};
    uint8_t aTxBuffer[] = "你好";

    void receiveEvent(int len) {
    while (Wire.available() > 1) {
    int c = Wire.read();
    Serial.print(c);
    }
    int x = Wire.read();
    Serial.println(x);
    }

    void requestEvent() {
    Wire.write(hello, sizeof(hello));
    Wire.write(0);
    }

    void setup() {
    Wire.begin(I2C_slave_ADDR, 4, 5, 100000);
    Wire.onRequest(requestEvent);
    Wire.onReceive(receiveEvent);

    Serial.begin(9600);

    }

    void loop() {
    }

    `

    ESP32C3主机日志:
    c0d130be40f0ebe2617ab3f8c73e4b0

    ESP32C3从机日志:
    c782883c4b45e16b1e24272588633f7

  2. luckycheng2017 commented on Sep 7, 2023

    @luckycheng2017
    Author

    补充说明,ESP32C3主机用Wire.write发送单个字节的数据,AIR001才能收到,但是发送下个字节前,要操作Wire.beginTransmission(I2C_slave_ADDR); Wire.endTransmission()才不会漏发数据。

    ESP32C3主机代码:
    `
    #include <Wire.h>

    #define I2C_slave_ADDR 0x08

    uint8_t hello[] = {1, 2, 3, 4, 5, 6};
    uint8_t aTxBuffer[] = "你好";
    uint8_t myBuffer[10];

    void setup() {
    Wire.setClock(100000);
    Wire.begin(4, 5);

    Serial.begin(9600);

    byte error, address;
    int nDevices;
    Serial.println("Scanning...");
    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
    Serial.print("I2C device found at address 0x");
    if (address<16) {
    Serial.print("0");
    }
    Serial.println(address,HEX);
    nDevices++;
    }
    else if (error==4) {
    Serial.print("Unknow error at address 0x");
    if (address<16) {
    Serial.print("0");
    }
    Serial.println(address,HEX);
    }
    }
    if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
    }
    else {
    Serial.println("done\n");
    }
    }

    int i = 0;

    void loop() {
    i++;
    if (i > 100) {
    i = 0;
    }
    Wire.beginTransmission(I2C_slave_ADDR);
    Wire.write(i);
    Serial.print("发送1:");
    Serial.println(Wire.endTransmission());
    Wire.beginTransmission(I2C_slave_ADDR);
    Serial.print("发送2:");
    Serial.println(Wire.endTransmission());
    delay(2000);
    }
    `

    AIR001从机代码:
    `
    #include <Wire.h>

    #define I2C_ADDR 0x08

    uint8_t hello[] = {1, 2, 3};
    uint8_t aTxBuffer[] = "你好";

    // function that executes whenever data is received from master
    // this function is registered as an event, see setup()
    void receiveEvent(int howMany)
    {
    while(1 < Wire.available()) // loop through all but the last
    {
    int c = Wire.read(); // receive byte as a character
    Serial.println(c); // print the character
    }
    int x = Wire.read(); // receive byte as an integer
    Serial.println(x); // print the integer
    }

    // function that executes whenever data is requested by master
    // this function is registered as an event, see setup()
    void requestEvent()
    {
    int res = Wire.write((uint8_t *) hello, sizeof(hello));
    Serial.print("发送数据, res = ");
    Serial.println(res);
    }

    void setup()
    {
    Serial.begin(9600); // start serial for output

    Wire.setSDA(PF_0);
    Wire.setSCL(PF_1);
    Wire.setClock(100000);
    Wire.begin((int) I2C_ADDR, false, true); // join i2c bus with address #4
    Wire.onReceive(receiveEvent); // register event
    Wire.onRequest(requestEvent); // register event
    }

    void loop()
    {
    //empty loop
    }
    `

    ESP32C3主机日志:
    9718d8757580ee45118550416d51bcd

    AIR001从机日志:
    45de914ae47eb751ed47442601f4d68

  3. luckycheng2017 commented on Sep 7, 2023

    @luckycheng2017
    Author

    AIR001作I2C从机时,比较不稳定,容易返回2,望解决这个问题。

  4. jyzhkj commented on Sep 15, 2023

    @jyzhkj

    用逻辑分析仪看数据,
    可以发现,应该是ev中断的处理判断 问题。
    主机发数据后,下个周期再发,air从机才会触 发中断。 hal库的HAL_I2C_Slave_Receive_IT 函数,是有字节长度判断 的。

  5. jyzhkj commented on Sep 15, 2023

    @jyzhkj

    在主机端,暂时用这个方式来解决: 速度400k(从机不需要指定速度)
    ` u8_t rtv;

    Wire.beginTransmission(I2c_base);       // transmit to device #8
    Wire.write((uint8_t *)&au16data[1], 2); // sends 2 byte
    Wire.write((uint8_t *)&au16data[2], 2); // sends 2 byte
    rtv = Wire.endTransmission();       // stop transmitting
    bitWrite(au16data[24], 0, rtv); // i2c 状态  出错置0
    //delayMicroseconds(10);
    Wire.beginTransmission(I2c_base);
    Wire.endTransmission();
    return true;`
    

    /
    未处理前的 时序图, 分别是scl,sda,接收中断中的串口输出

    1
    2
    3

    处理后:

    4
    5

  6. jyzhkj commented on Sep 16, 2023

    @jyzhkj

    TWI.C中的 HAL_I2C_ListenCpltCallback 回调函数不能有效触发,
    上面增加了
    Wire.beginTransmission(I2c_base);
    Wire.endTransmission();
    也就是激活触发这个回调函数。

    也可在HAL_I2C_SlaveRxCpltCallback 函数中
    增加判断接收的字节来实现回调(前提是你I2C固定通讯长度)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions