Skip to content

Commit

Permalink
fix(twi): fails on repeated start condition
Browse files Browse the repository at this point in the history
reproduction: https://wokwi.com/arduino/projects/306115576172905024

minimal reproduction code:

```cpp
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin();

  Wire.beginTransmission(0x68);
  Wire.write( 0x3B);
  Wire.endTransmission( false);  // <---- Fails after this

  auto n = Wire.requestFrom(0x68, 6);
  if (n == 6) {
    int16_t AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
    int16_t AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
    int16_t AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
    Serial.print( "AcX = ");    Serial.print( AcX);
    Serial.print( " | AcY = "); Serial.print( AcY);
    Serial.print( " | AcZ = "); Serial.print( AcZ);
    Serial.println();
  } else {
    Serial.println( "--------- ERROR ---------");
  }
}

void loop() {}
```
  • Loading branch information
urish committed Dec 13, 2021
1 parent ad40366 commit 1d70883
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/peripherals/twi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class NoopTWIEventHandler implements TWIEventHandler {

export class AVRTWI {
public eventHandler: TWIEventHandler = new NoopTWIEventHandler(this);
private busy = false;

// Interrupts
private TWI: AVRInterruptConfig = {
Expand All @@ -112,18 +113,23 @@ export class AVRTWI {
this.cpu.clearInterruptByFlag(this.TWI, value);
this.cpu.updateInterruptEnable(this.TWI, value);
const { status } = this;
if (clearInt && value & TWCR_TWEN) {
if (clearInt && value & TWCR_TWEN && !this.busy) {
const twdrValue = this.cpu.data[this.config.TWDR];
this.cpu.addClockEvent(() => {
if (value & TWCR_TWSTA) {
this.busy = true;
this.eventHandler.start(status !== STATUS_TWI_IDLE);
} else if (value & TWCR_TWSTO) {
this.busy = true;
this.eventHandler.stop();
} else if (status === STATUS_START || status === STATUS_REPEATED_START) {
this.busy = true;
this.eventHandler.connectToSlave(twdrValue >> 1, twdrValue & 0x1 ? false : true);
} else if (status === STATUS_SLAW_ACK || status === STATUS_DATA_SENT_ACK) {
this.busy = true;
this.eventHandler.writeByte(twdrValue);
} else if (status === STATUS_SLAR_ACK || status === STATUS_DATA_RECEIVED_ACK) {
this.busy = true;
const ack = !!(value & TWCR_TWEA);
this.eventHandler.readByte(ack);
}
Expand Down Expand Up @@ -153,15 +159,18 @@ export class AVRTWI {
}

completeStart() {
this.busy = false;
this.updateStatus(this.status === STATUS_TWI_IDLE ? STATUS_START : STATUS_REPEATED_START);
}

completeStop() {
this.busy = false;
this.cpu.data[this.config.TWCR] &= ~TWCR_TWSTO;
this.updateStatus(STATUS_TWI_IDLE);
}

completeConnect(ack: boolean) {
this.busy = false;
if (this.cpu.data[this.config.TWDR] & 0x1) {
this.updateStatus(ack ? STATUS_SLAR_ACK : STATUS_SLAR_NACK);
} else {
Expand All @@ -170,10 +179,12 @@ export class AVRTWI {
}

completeWrite(ack: boolean) {
this.busy = false;
this.updateStatus(ack ? STATUS_DATA_SENT_ACK : STATUS_DATA_SENT_NACK);
}

completeRead(value: u8) {
this.busy = false;
const ack = !!(this.cpu.data[this.config.TWCR] & TWCR_TWEA);
this.cpu.data[this.config.TWDR] = value;
this.updateStatus(ack ? STATUS_DATA_RECEIVED_ACK : STATUS_DATA_RECEIVED_NACK);
Expand Down

0 comments on commit 1d70883

Please sign in to comment.