Problem: As soon as I write to the USB serial port after accessing my I2C device asynchronously (polling it in main loop rather than a blocking loop), I get a CPU exception
Background: I have an Arduino project running under Microchip studio (for debugging via the J-Link interface). I am communicating with a VCNL4010 proximity sensor via I2C. I have a working synchronous function that reads proximity as such:
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");
}
This code works fine, but blocks my main loop until the sensor reading is complete. I need to avoid blocking because I'm also controlling a motor. I wrote an async version that's broken into these functions:
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;
}
In response to a serial command I invoke readProximityBegin
and call update in my main loop until readProximityReady
becomes true, at which time I read the value using readProximityResult
. As mentioned, as soon as I write to the USB serial port after all this, I get a CPU exception (the error originates from the serial write
in the RTL). I'm not sure which exception exactly because in cortex_handlers.c it looks like the arduino code for the SAMD21 routes all sorts of exceptions to this same function:
void Dummy_Handler(void)
{
#if defined DEBUG
__BKPT(3); // this is where my debugger stops
#endif
for (;;) { }
}
Here's an example of one of my I2C functions referenced by the above:
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());
}