attachInterrupt() corrupting Serial buffer requiring Serial restart

Status
Not open for further replies.

mcooi77

Member
I am working on a proof-of-concept ADC to "explode" what's inside of an ADC chip for teaching purposes.

Currently, I have a sketch that uses a push-button to act as a clock-pulse that counts up (1, 2, 3, 4, ...) for every positive edge using the attachInterrupt() function.

The sketch works great to view the data in the serial monitor.

I am pairing the Arduino (Teensy 3.2) with a Raspberry Pi configured to read data off the Serial line to a text box.

After a good bit of troubleshooting it appears that the attachInterrupt() function corrupts the Serial buffer with garbage for every interrupt. For instance, if I use

Code:
Serial1.flush();
Serial1.begin(115200);

immediately after the interrupt and then send out my data using Serial.println() I get my expected decimal value at my output. However, without these lines I just get unicode garbage at my Serial output. See full "fixed" sketch code below:

My question is: why is this happening? I should not need to restart Serial every iteration of the clock.

Code:
#define HWSERIAL Serial1

const int numBits = 12;             //Number of bits in ADC (resolution)
const int comparatorPin = 14;       //Pin number of comparator out
const int clockPin = 15;            //Pin number of external clock (square wave) input; expecting clock with 50% duty-cycle
volatile int comparatorState = 0;   //Is comparator high or low?
volatile bool clockState = 0;       //Is clock high or low?
volatile int masterCount = 0;       //Our master count
volatile bool isSameVal = false;    //Is the value of the master count the same value as last cycle?

int outVal = 0;

int masterBinCount[12];     //Array to store binary value of the master count
byte outputPins[12];        //Array to store the numbers associated with the output pin numbers
int maxValue = 0;           //Initialize max counter value to zero

void setup() {
  Serial.begin(115200);       //Begin Serial transmission
  HWSERIAL.begin(115200, SERIAL_8N1);
  HWSERIAL.flush();
  delay(2000);

  defineOutPins(outputPins);  //Assign pin numbers for output pins

  pinMode(14, INPUT);   //Comparator Pin
  pinMode(15, INPUT);   //Clock-in pin

  maxValue = pow(2, numBits);   //Set max counter value to max bit resolution. Ex. for 12 bits --> 4096
}

void loop() {
  attachInterrupt(clockPin, doOnClock, RISING);   //When clock is on a positive-edge execute doOnClock function

  HWSERIAL.flush();
  HWSERIAL.begin(115200);

  if(isSameVal == false) {    //If the master count is NOT the same as the last cycle
    convertDecToBin();        //Convert the master count (dec) to binary
    binaryToPins();           //Send the binary value (via digitalWrite) to output pins
  }
  else {
    //Do nothing
  }
  delay(1000);
}

void defineOutPins(byte pinNos[]) {   //Assign pin numbers to parallel binary out: Teensy 3.2 pin #0 --> #11
  for(byte i = 0; i < numBits; i++) {
    pinNos[i] = {i};      //Assign current pin this value
    pinMode(i, OUTPUT);   //Define pins as outputs
  } 
}

void doOnClock() {
  comparatorState = digitalRead(comparatorPin);   //Check comparator state

  if(comparatorState >= 0.5) {            //Check if positive clock pulse
    if(masterCount == (maxValue - 1)) {   //Check if current count value is at "ceiling"
      //Do nothing
    }
    else {            //Else increment count up
      masterCount++;
    }
  }
  else if(comparatorState < 0.5) {    //Check if negative clock pulse
    if(masterCount == 0) {            //Check if current count value is at "floor"
      //Do nothing
    }
    else {
      masterCount--;    //Else decrment count down
    }
  }

  isSameVal = false;    //Set "finished" counting for this clock-pulse
}

void convertDecToBin() {
  for(int j = 0; j < numBits; j++) {
    int tempCnt = bitRead(masterCount, j);
    masterBinCount[numBits - (j+1)] = tempCnt;    //Populate the master binary count array in "reverse" order starting with the LSB at the highest array index
  }
}

void binaryToPins() {
  for(int e = 0; e < numBits; e++) {
    //digitalWrite(outputPins[e], masterBinCount[e]);   //Write our master binary value to output pins
    //Serial.print(masterBinCount[e]);                    //THIS LINE IS FOR TROUBLESHOOTING!!
  }
  isSameVal = true;       //Tell program we wrote the master count to the pins for this clock cycle

  outVal = masterCount;

  Serial.println(outVal);
  HWSERIAL.println(outVal);

  //Serial.print(" decimal: ");   //THIS LINE IS FOR TROUBLESHOOTING!!
  //Serial.print(masterCount);    //THIS LINE IS FOR TROUBLESHOOTING!!
  //Serial.println("");           //THIS LINE IS FOR TROUBLESHOOTING!!
}
 
First step would be to do these only once in setup() - remove this code from loop():
Code:
  attachInterrupt(clockPin, doOnClock, RISING);   //When clock is on a positive-edge execute doOnClock function

  HWSERIAL.flush();
  HWSERIAL.begin(115200);

The attach is persistent

The .begin is also persistent after it sets up the hardware. Doing it again will cause a reset in some fashion and may be the trouble.

You can test this to work by wiring Serial1 to Serial2 ( crossing RX<>Tx, or a second Teensy ) and verify the transfer works.

Teensy only sends what it is given - not sure what happens on the RasPi
 
Why are you calling attachInterrupt() on every pass through loop?

‘comparatorState’ variable does not need to be ‘volatile’ or global, it can be local to ‘doOnClock()’. It also doesn’t need to be an ‘int’, ‘uint8_t’ would be fine. Why compare it to 0.5? it can ONLY be 1 or 0.
 
First step would be to do these only once in setup() - remove this code from loop():
Code:
  attachInterrupt(clockPin, doOnClock, RISING);   //When clock is on a positive-edge execute doOnClock function

  HWSERIAL.flush();
  HWSERIAL.begin(115200);

The attach is persistent

The .begin is also persistent after it sets up the hardware. Doing it again will cause a reset in some fashion and may be the trouble.

You can test this to work by wiring Serial1 to Serial2 ( crossing RX<>Tx, or a second Teensy ) and verify the transfer works.

Teensy only sends what it is given - not sure what happens on the RasPi

Yes! You are correct, thank you for pointing that out. I think you are helping me down the right path because I think the only reason why I could "force" it to work by force-restarting the Serial in the loop is because of the innate "reset" resulted in a random transient that matched my expected results.

Why are you calling attachInterrupt() on every pass through loop?

‘comparatorState’ variable does not need to be ‘volatile’ or global, it can be local to ‘doOnClock()’. It also doesn’t need to be an ‘int’, ‘uint8_t’ would be fine. Why compare it to 0.5? it can ONLY be 1 or 0.

Thank you for pointing that out as well! I wouldn't have have caught that error. I chose fix-points on either side of 0.5 to mitigate any potential misreadings or voltage sag that could somehow result in my "check" value a bit above or below the expected logic levels in 3.3v. Like you suggest, it's basically impossible if I designed everything properly but I'm developed a habitual wariness of EQUALS statements over the years for anything that takes place outside of a software app.
 
Status
Not open for further replies.
Back
Top