问题:在异步访问我的 I2C 设备(在主循环而不是阻塞循环中轮询它)后,一旦我写入 USB 串行端口,就会出现 CPU 异常
背景:我有一个在 Microchip Studio 下运行的 Arduino 项目(用于通过 J-Link 接口进行调试)。我正在通过 I2C 与 VCNL4010 接近传感器通信。我有一个有效的同步函数,可以读取接近度:
Zult<uint16_t> ProximitySensor::readProximity(void) {
auto res = setIntMask(0x80);
if (res.isError())
return Zult<uint16_t>(res);
res = write8(VCNL4010_COMMAND, VCNL4010_MEASUREPROXIMITY);
if (res.isError())
return Zult<uint16_t>(res);
auto start = millis();
do {
auto cmd = read8(VCNL4010_COMMAND);
if (cmd.isError())
return Zult<uint16_t>(cmd);
if (cmd.getResult() & VCNL4010_PROXIMITYREADY) {
return read16(VCNL4010_PROXIMITYDATA);
}
delay(1);
} while (millis() - start < 1000);
return Zult<uint16_t>(0, "timeout in readProximity");
}
此代码工作正常,但会阻塞我的主循环,直到传感器读取完成。我需要避免阻塞,因为我也在控制电机。我写了一个异步版本,分为以下功能:
Zult<bool> ProximitySensor::readProximityBegin() {
auto res = setIntMask(0x80);
if (res.isError())
return Zult<uint16_t>(res);
res = write8(VCNL4010_COMMAND, VCNL4010_MEASUREPROXIMITY);
if (res.isError())
return Zult<uint16_t>(res);
asyncStart = millis();
asyncReady = false;
asyncResult = NotReadyZult;
}
bool ProximitySensor::readProximityReady() {
return asyncReady;
}
void ProximitySensor::stopAsync() {
asyncReady = true;
asyncStart = 0;
}
void ProximitySensor::update() {
if (asyncStart != 0) {
auto cmd = read8(VCNL4010_COMMAND);
if (cmd.isError()) {
asyncResult = Zult<uint16_t>(cmd);
stopAsync();
return;
}
if (cmd.getResult() & VCNL4010_PROXIMITYREADY) {
asyncResult = read16(VCNL4010_PROXIMITYDATA);
stopAsync();
return;
}
if (millis() - asyncStart > 1000) {
asyncResult = Zult<uint16_t>(0, "timeout in readProximity");
stopAsync();
}
}
}
Zult<uint16_t> ProximitySensor::readProximityResult() {
return asyncResult;
}
作为对串行命令的响应,我readProximityBegin
在主循环中调用并调用 update 直到readProximityReady
变为真,此时我使用readProximityResult
. 如前所述,一旦我在这一切之后写入 USB 串行端口,就会出现 CPU 异常(错误源于write
RTL 中的串行)。我不确定究竟是哪个异常,因为在 cortex_handlers.c 中,SAMD21 的 arduino 代码将各种异常路由到同一函数:
void Dummy_Handler(void)
{
#if defined DEBUG
__BKPT(3); // this is where my debugger stops
#endif
for (;;) { }
}
这是上面引用的我的 I2C 函数之一的示例:
Zult<uint8_t> ProximitySensor::read8(uint8_t command) {
Wire.beginTransmission(_i2caddr);
Wire.write(command);
auto result = Wire.endTransmission();
if (result != 0) {
return Zult<uint8_t>((int)result, "Writing request to read8");
}
delayMicroseconds(170); // delay required
Wire.requestFrom(_i2caddr, (uint8_t)1);
auto start = millis();
while (!Wire.available()) {
if (millis() - start > 1000)
return Zult<uint16_t>(0, "Timeout waiting for read");
}
return Zult<uint8_t>(Wire.read());
}