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

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

Open
3 tasks done
luckycheng2017 opened this issue Sep 7, 2023 · 6 comments
Open
3 tasks done

Comments

@luckycheng2017
Copy link

luckycheng2017 commented Sep 7, 2023

描述一下这个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.
  • 已经提供了完整的报错信息、日志、截图,没有经过删减。
@luckycheng2017
Copy link
Author

luckycheng2017 commented Sep 7, 2023

补充说明:差不多同一份代码,修改一下引脚,两个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

@luckycheng2017
Copy link
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

@luckycheng2017
Copy link
Author

luckycheng2017 commented Sep 7, 2023

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

@jyzhkj
Copy link

jyzhkj commented Sep 15, 2023

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

@jyzhkj
Copy link

jyzhkj commented Sep 15, 2023

在主机端,暂时用这个方式来解决: 速度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

@jyzhkj
Copy link

jyzhkj commented Sep 16, 2023

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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants