Teensy 3.6 - Apparent Interrupt Delay

Status
Not open for further replies.

td0g

Member
Hello all, this is my first time posting but I am completely perplexed. I have a project involving a Teensy 3.6 and an encoder. It's a wheel which mounts on a car bumper and records the vehicle's position to the microSD card. The encoder never outputs more than about 400 hz. I'm noticing an apparent delay of up to 96 microseconds per sample in the data.

Here's a link to the data file:https://drive.google.com/open?id=1T_qQJ6P6mnl2qhEdIbuD69vT4ytKL-w3 Below is the code I've used to sample for 10 seconds on controller startup. It interrupts when the A channel changes, and buffers a time stamp if A is high. After 10 seconds it writes the buffer to the microSD card.

The issue is in the time difference from one time stamp to the next (t1 - t0), there appears to be certain values occurring much more often than the rest. Specifically, every 96th value has a much greater frequency than the rest (eg. 2798 microseconds, 2894 microseconds, 2990 microseconds, etc. appear very often). You can see this on the graph below. The only explanation I have is that the controller will often ignore the interrupts for up to 96 microseconds, but I don't understand why. Can anyone explain what causes this anomaly? Thanks!!!

Capture.JPG

Code:
#define ENCODER_PPR 128
#define ENCODER_PPM 103.8 
#define FILE_BASE_NAME "Data"

#include "SdFat.h"

//uSD Card
	SdFatSdioEX sdEx;
	File file;
	boolean sdAvailable = false;
	boolean recording = false;

//Encoder
	#define ENCODER_INDEX_BUFFER_SIZE ENCODER_BUFFER_SIZE/ENCODER_PPR
	volatile uint32_t encoderBuffer[ENCODER_BUFFER_SIZE];
	volatile uint32_t encoderIndexBuffer[ENCODER_INDEX_BUFFER_SIZE];  //Not used in this test code
	volatile long encoderPosition;

//Pins
  const byte aPin = 11;
  const byte bPin = 10;

//Battery Voltage
	#define VOLTAGE_DIVISOR 20.43
	float voltIn;

void setup() {
	
//Set pin modes
  pinMode(aPin, INPUT);
  pinMode(bPin, INPUT); 

//Set interrupt
  attachInterrupt(aPin, aISR, CHANGE); // Calls ISR when encoder pin A changes state

//Sample for 10 seconds then stop
  recording = true;
    while (millis() < 10000){};
      if (sdEx.begin()) sdAvailable = true;  //Check if SD card is inserted
  sdEx.chvol();
  recordData();       //Copy data to MicroSD Card
  recording = false;
  recordData();
}

void loop() {
}

void aISR(){
  static uint32_t _bufPos;
  uint8_t dir;
  if (digitalRead(bPin)){
    encoderBuffer[_bufPos] = micros() & 0b01111111111111111111111111111111;
    if (!digitalRead(aPin)){
      dir = 0b10000000000000000000000000000000;
      encoderPosition++;
    }
    else {
      dir = 0;
      encoderPosition--;
    }
    if (recording){ //Copy data to buffer, will be moved onto card by recordData function
       encoderBuffer[_bufPos] += dir; //Round to nearest 2 microseconds, save directionality bit in LSB
      _bufPos++;
      _bufPos %= ENCODER_BUFFER_SIZE;
    }
    else encoderBuffer[_bufPos] = 0;
  }
}

void recordData(){
  static uint32_t _bufPos;
  static uint32_t _bufIndexPos;
  static uint8_t _fileOpen = false;
  static uint32_t _fStartTime;

  if (recording && !_fileOpen){
      char fileName[13] = FILE_BASE_NAME "00.csv";
      const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
      while (sdEx.exists(fileName)) {
        if (fileName[BASE_NAME_SIZE + 1] != '9') {
          fileName[BASE_NAME_SIZE + 1]++;
        } 
        else if (fileName[BASE_NAME_SIZE] != '9') {
          fileName[BASE_NAME_SIZE + 1] = '0';
          fileName[BASE_NAME_SIZE]++;
        } 
        else break;
      }
      if (!sdEx.exists(fileName)){
        if(file.open(fileName, O_RDWR | O_CREAT)){
          _fStartTime = micros();
          file.print(F("Calibration Factor (pulses per metre): "));
          file.println(ENCODER_PPM);
          file.print(F("Encoder Precision (pulses per revolution: "));
          file.println(ENCODER_PPR);
          file.println(F("Time (us), Dir (+1/-1),Special Flags"));   
          file.println(F("0,0"));
          _fileOpen = true;
        }
      }
      if (!_fileOpen) {     
        recording = 0;
      }
  }

  
  while (encoderBuffer[_bufPos]){
    file.print((encoderBuffer[_bufPos] & 0b01111111111111111111111111111111) - _fStartTime, DEC);
    file.print(F(","));
    if (encoderBuffer[_bufPos] & 0b10000000000000000000000000000000) file.print(F("1"));
    else file.print(F("-1"));
    if (encoderIndexBuffer[_bufIndexPos]){           //Not used in this test code
      file.print(F(",INDEX:"));
      file.print(encoderIndexBuffer[_bufIndexPos]);
      encoderIndexBuffer[_bufIndexPos] = 0;
      _bufIndexPos++;
      _bufIndexPos %= ENCODER_INDEX_BUFFER_SIZE;
    }
    else file.print(",");
    if(!file.println())
      {
        recording = 0;
      }
    encoderBuffer[_bufPos] = 0;
    _bufPos++;
    _bufPos %=ENCODER_BUFFER_SIZE;
  }

  if (!recording) {
    file.print(micros() - _fStartTime);
    file.print(F(",0,end"));
    file.close();
    _fileOpen = false;
  }
}
 

Attachments

  • Capture.JPG
    Capture.JPG
    12.7 KB · Views: 101
since these { A & B ) are const:: const byte bPin = 10;
using "digitalReadFast()' might make the _isr run faster.

It may be related to the time the aISR() is running
 
Thanks for the advice defragster - I'll change to digitalReadFast().

Still doesn't explain the issue. The time between ISR executes is never less than 2000 microseconds. It's almost like other, higher-priority ISR's occur every 96 microseconds.

I might need to get rid of the interrupt and modify the code such that the pins can be polled at regular intervals.
 
If the problem is another interrupt with higher priority, change your priority. But I find it hard to believe that there is an ISR that requires 96us to execute.
 
Thank you both for your input. I discovered the problem and am embarrassed to say it wasn't the controller. The quadrature-output encoder apparently only reports data every 96 microseconds, not in real-time. This was not in the encoder's datasheet, I had to do much digging to find this.

Very best, Tyler
 
Status
Not open for further replies.
Back
Top