milkv-duo / duo-buildroot-sdk

Milk-V Duo Official buildroot SDK
384 stars 168 forks source link

Arduino I2C 成功发送后返回值不正确 #118

Open ArielHeleneto opened 2 months ago

ArielHeleneto commented 2 months ago

I2C 成功发送后返回值不正确

代码

#include <Wire.h>

void receive(int a) {
  Serial.printf("receive %d bytes\n\r", a);
  while(a--) {
    Serial.printf("%d \n\r", Wire1.read());
  }
}

void setup() {
  Serial.begin(38400);

  Wire1.begin(0x50);
  Wire1.onReceive(receive);

  Wire.begin();
  Serial.printf("test slave\n\r");
  Wire1.print();
}

byte val = 0;

void loop() {
  Wire.beginTransmission(0x50);         // Transmit to device number 0x50
  Serial.printf("send %d \n\r", ++val);
  Wire.write(val);                      // Sends value byte
  int ans=Wire.endTransmission();               // Stop transmitting
  Serial.printf("ans=%d\n\r",ans);
  Wire1.onService();
  delay(1000);
}

接线

将 GP0 和 GP9、GP1 和 GP8、GP4 和 RX、GP5 和 TX、GND 和 G 相连,打开 UART 并设置波特率为 38400 观察现象。

预期结果

ans 为 0。

实际结果

ans 为 4,即 endTransmission() 中的 other error。

203 
ans=4
send 204 
receive 1 bytes
204 
ans=4
send 205 
receive 1 bytes
205 
ans=4
send 206 
receive 1 bytes
206 
ans=4
shiptux commented 1 month ago

@ArielHeleneto Hi 感谢抓虫。

endTransmisson 会调用 csi_iic_master_send 函数。同时做以下判断:

   int ret = csi_iic_master_send(&_iic, txAddress, data, i, _timeout, stopBit);
    switch (ret) {
    case CSI_OK:
        return 0;
    case CSI_TIMEOUT:
        return 5;
    default:
        return 4;

可以看出只有在返回 CSI_OK 状态下 endTransmission 的返回值才是正确的。但由于 csi_iic_master_send 的约定,他的返回值只能是 size 或者是错误值。这就导致了在正常运行的流程下也只会打印 4(在 Arduino 约定中属于其他错误)

/**
  \brief       Start sending data as IIC Master.
               This function is blocking
  \param[in]   iic            handle of iic instance
  \param[in]   devaddr        addrress of slave device
  \param[in]   data           data to send to IIC Slave
  \param[in]   size           size of data items to send
  \param[in]   timout         unit of time delay
  \return      master send real size and error code
*/

由于 csi_iic_master_send 部分属于厂商的的 bsp 部分代码,不适合进行直接修改。而 endTransmission 属于适配 Arduino 部分的代码,可以加上判断。real size 应该是一个正数,而根据 cores/sg200x/bsp/include/csi/csi_common.h 错误值都是复数:

typedef enum {
    CVI_OK          =  0,
    CVI_ERROR       = -1,
    CVI_BUSY        = -2,
    CVI_TIMEOUT     = -3,
    CVI_UNSUPPORTED = -4
} cvi_error_t;

我认为可以在这里进行判断。