Teensy 3.0 background interrupts / interrupt priority

Status
Not open for further replies.

badsector

Well-known member
I have started a project to control a 3.5inch FDD using a Teensy3.0. The idea is to be able to read Atari ST floppy disks. There is code for similar projects on the web, which I downloaded and used as a starting point, but I have observed the waveforms and created my own code (Teensy specific). The hardware interface is quite simple, just a pair of 74LS05 hex open collector inverter ICs. Signals at the Teensy end look nice and clean.

I can step in and out and detect track 0. I am now working on the code to decode the MFM stream. The read data stream consists of a set of pulses of about 0.5us width, the distance between can be 2,4 or 6us. I am attaching an interrupt to the rising edge of the read data which calls an ISR to read a FTM timer, use or store the value, then reset the timer ready for the next pulse.

Here is the code so far...

Code:
//
// modified by badsector
// 31-Dec-2019 : Port to Teensy 3.0
//             : Using 74LS05 which is inverting.
// 01-Jan-2020 : Add timer code to measure time between pulses from floppy read pin.
//

#include <stdio.h> // for function sprintf

const byte STEP_TIME  = 10;
const byte STEP_PULSE =  2;

const byte ON  = 1;
const byte OFF = 0;
const byte IN  = 1;
const byte OUT = 0; // towards outer track (track 0)

const byte toFDDdirSelect = 11;
const byte toFDDmotorOn   = 12;
const byte toFDDselect    = 14;
const byte toFDDstep      = 15;
const byte toFDDside      = 16;

const byte fromFDDtrack00  = 23;
const byte fromFDDindexPin = 22;
const byte fromFDDreadPin  = 21;
const byte debugpin        = 20;

const byte userButton = 0;

const word len = 1400;
byte data[len];

int  track = 1;
byte stepdir=OUT;
int  motoron=ON;
int  drivesel=ON;

char sbuf[99];

void setup() {
  Serial.begin(9600);

  pinMode(fromFDDindexPin, INPUT_PULLUP);
  pinMode(fromFDDreadPin,  INPUT_PULLUP);
  pinMode(fromFDDtrack00,  INPUT_PULLUP);

  pinMode(toFDDstep,      OUTPUT);
  pinMode(toFDDdirSelect, OUTPUT);
  pinMode(toFDDmotorOn,   OUTPUT);
  pinMode(toFDDselect,    OUTPUT);
  pinMode(toFDDside,      OUTPUT);

  pinMode(userButton, INPUT);
  pinMode(debugpin,   OUTPUT);
  digitalWrite(debugpin,LOW);

  digitalWrite(toFDDstep,      LOW);   // sets it high
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
  digitalWrite(toFDDside,      HIGH);
  digitalWrite(toFDDmotorOn,   (motoron==ON)?HIGH:LOW);
  digitalWrite(toFDDselect,    (drivesel==ON)?HIGH:LOW);
}

bool isTrack00(void) {
  return (digitalRead(fromFDDtrack00)==HIGH);
}

void stepOut() {
  stepdir=OUT;
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
}
void stepIn() {
  stepdir=IN;
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
}

void stepPulse() {
  digitalWrite(toFDDstep, HIGH);
  delay(STEP_PULSE); // 800us minimum
  digitalWrite(toFDDstep, LOW);
  delay(STEP_TIME); 
  if (isTrack00()) { 
    track=0; 
  } else {
    if (stepdir==IN) { track++; } else { track--; }
  }
}

//--------------------------------------------------------------------------------------------

volatile int events;
volatile uint16_t eventdata[1024];

//--------------------------------------------------------------------------------------------

void FDdecode(void) {
  uint16_t timer;
  digitalWrite(debugpin,HIGH);
  FTM0_SC   = FTM_SC_CLKS(0) | FTM_SC_PS(2); // STOP CLOCK
  timer = FTM0_CNT;
  if (events<1024) { 
    eventdata[events++] = timer;          // read count
  }
  FTM0_CNT = 0;                              // reset count
  FTM0_SC   = FTM_SC_CLKS(1) | FTM_SC_PS(2); // RESTART CLOCK
  digitalWrite(debugpin,LOW);
}

//--------------------------------------------------------------------------------------------

void readTrack() {

  // wait for index pulse to go (low from floppy) (high seen by Teensy)
  while (digitalRead(fromFDDindexPin)==HIGH); // in case the index pulse is already active
  while (digitalRead(fromFDDindexPin)==LOW);

  FTM0_MODE = FTM_MODE_FTMEN | FTM_MODE_WPDIS;
  FTM0_SC   = FTM_SC_CLKS(0) | FTM_SC_PS(2); // disable clock + no prescale
  FTM0_CNT  = 0;
  FTM0_MOD  = 0xFFFF;

  events=0;
  FTM0_SC   = FTM_SC_CLKS(1) | FTM_SC_PS(2); // system (48MHz) clock + no prescale
  attachInterrupt(fromFDDreadPin,FDdecode,RISING);
  delay(10); // 10ms - enough to capture some sample data
  detachInterrupt(fromFDDreadPin);
  FTM0_SC   = FTM_SC_CLKS(0) | FTM_SC_PS(2); // disable clock + no prescale
  sprintf(sbuf,"No of events = %d\n",events);
  Serial.println(sbuf);

}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

bool active = true;
byte k = 25;
unsigned char cmd;

void loop() {
  
  if (Serial.available()) {
    cmd = Serial.read();
    if (cmd=='s') {
      stepPulse();
      //Serial.println("step...");
      sprintf(sbuf, "Track0 = %s track = %d Step dir = %s",isTrack00()?"TRUE":"false",track,stepdir==OUT?"OUT":"IN");
      Serial.println(sbuf);
    }
    if (cmd==' ') {
      sprintf(sbuf, "Track0 = %s track = %d Step dir = %s",isTrack00()?"TRUE":"false",track,stepdir==OUT?"OUT":"IN");
      Serial.println(sbuf);
    }
    if (cmd=='i') {
      stepIn();
      Serial.println("step dir in...");
    }
    if (cmd=='o') {
      stepOut();
      Serial.println("step dir out...");
    }
    if (cmd=='m') {
      if (motoron==ON) { motoron=OFF; } else { motoron=ON; }
      digitalWrite(toFDDmotorOn,   (motoron==ON)?HIGH:LOW);
      Serial.println("motor ...");
    }
    if (cmd=='d') {
      if (drivesel==ON) { drivesel=OFF; } else { drivesel=ON; }
      digitalWrite(toFDDselect,    (drivesel==ON)?HIGH:LOW);
      Serial.println("drive ...");
    }
    if (cmd=='r') {
      drivesel=ON; digitalWrite(toFDDselect,    (drivesel==ON)?HIGH:LOW);
      motoron =ON; digitalWrite(toFDDmotorOn,   (motoron ==ON)?HIGH:LOW);
      delay(100); // wait for drive to spin up
      Serial.println("reading track ...");
      readTrack();
      int i;
      for (i=0;i<1024;i++) { 
        uint16_t t;
        t=eventdata[i];
        byte d; 
             if (t < 30) { d=22; }
        else if (t < 50) { d=0; }
        else if (t < 75) { d=1; }
        else             { d=99; }
        sprintf(sbuf, "%2d ", d);
        Serial.print(sbuf);
      }
      Serial.println("");
    }
  }
}

While I was looking at the datastream on the scope I noted an anomoly. The yellow trace is the read data from the floppy (actually inverted by the 74LS05), and the blue trace is a Teensy debug output pin which goes high on entry to the ISR and low on exit. I wanted to check that the ISR completed fast enough, under 2us. It does!.

Teensy30_floppy_read_data and interrupt_routine_flag - annotated.png

So there is a short interrupt latency(is that the word?) of about 1us. The ISR takes about 1us. BUT every now and again (the pulse underlined in blue) the ISR response is delayed. This messes up the time recorded between pulses and causes the decoded data stream to be corrupted.

My question is .. what is causing this?

My guess is that there is another interrupt which occurs at that time, but if so, what? The only other thing I can think of is "Serial", but the link is inactive during data read time (or could this be something to do with USB ???).

So I did some searching on this forum. I wanted to make the edge detect interrupt the highest priority. I have the following, which appeared to work, but I am not 100% certain it is correct.

Code:
const byte fromFDDreadPin  = 21; // PORT-D IRQ #43

const byte fromFDDreadPinIRQ  = 43; 

NVIC_SET_PRIORITY(fromFDDreadPinIRQ, 0); // HIGHEST priority

I have developed the code to decode the actual data in the ISR and I am able to read the raw data and I can see sector headers and data, BUT it is corrupted. I see a stream of zeroes become a stream of ones. This could be explained by having a single pulse read longer than 2us. NOTE: a stream of 2us pulses means a stream of all ones of all zeroes (you need the sync byte to determine which), but if there is a rogue 3us pulse then the stream will be inverted when decoded.

Could my ISR be interrupted by something else causing a delay and bad timer reading?

During user ISR are lower priority interrupts disabled?

Any help or pointers would be appreciated.

--badsector
 
Your interrupt may got delayed by higher or same priority Interrupts. Or interrupts may be disabled for some time, which, unfortunately, happens for example during loop() - So, try a higher priority for your interrupt and use your own while(1) {..... in loop().
 
Yes that's what I thought, so that's exactly what I tried to do (see above code).

Questions remain...

Did I set the edge detect interrupt priority correctly (set the right number)?

Exactly what other background interrupts are active? Obvious one is Serial (shouldn't be active). I use "delay()". Does this use some timer/interrupt resources?

BTW I am searching through Teensy3 library code (C:\Arduino\hardware\teensy\avr\cores\teensy3) to see if I can figure out answers to the above. The processors are very sophisticated, but also very complicated, and I am still on a learning curve :)

regards...

--badsector
 
Last edited:
You can speed up the interrupt timing by using digitalWriteFast(debugpin,HIGH);.

Also take a look at the freqMeasure library that uses flextime hardware capture mode, captures the timer value at the rising edge of a pulse in hardware, and then in the irq places the data in an accesible data structure. Perhaps you can use the library instead of your time handling, or get some ideas from the code.
 
Thank you @mlu. Your suggestion shaved several hundred nanoseconds off the length of my interrupt routine execution time.

DS2_QuickPrint3.png

In another posting I also found some useful information about improving the latency of edge detect interrupts (sorry can't find the message right now).

Code:
Instead of...

  attachInterrupt(fromFDDreadPin,FDD_stream_decode_ISR,RISING);

use...

  attachInterrupt(fromFDDreadPin, nullptr, RISING);        // just using this to setup the CHANGE interrupt trigger
  attachInterruptVector(IRQ_PORTD, FDD_stream_decode_ISR); // this is the ISR that will be run

and in the ISR routine add this extra code...

  uint32_t isfr = PORTD_ISFR;     // NEW
  PORTD_ISFR = isfr;              // NEW

I believe that the original ISR routine needs to check which port has caused the interrupt, which would take some time, but the modified code forces the choice of port, for my pin this was PORTD. This improves the interrupt latency as follows...

DS2_QuickPrint4.png

NOTE/WARNING: Originally in my readTrack() function I was doing the interrupt attach, track read, then detaching the interrupt. With the modified code the teensy locked up. So I moved the two "attach" lines of code to setup() and I used the following commands to enable and disable interrupts...

Code:
  enable_FDD_stream_decode_ISR();
  clearpending_FDD_stream_decode_ISR();

  ...readTrack()...

  disable_FDD_stream_decode_ISR();
  clearpending_FDD_stream_decode_ISR();

these use the following macros which enable and disable specific interrupt sources...

  NVIC_ENABLE_IRQ(fromFDDreadPinIRQ);
  NVIC_DISABLE_IRQ(fromFDDreadPinIRQ);
  NVIC_CLEAR_PENDING(fromFDDreadPinIRQ);

I wrote some code to draw a histogram of pulse delta timings. Initially these were all over the place, presumably because of other interrupts. The results were significantly improved by adding the following command to maximise the interrupt priority of my read data stream ISR.

Code:
  NVIC_SET_PRIORITY(fromFDDreadPinIRQ, 0);   // HIGHEST priority

Code:
000 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
001 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
002 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
003 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
004 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
005 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
006 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
007 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
008 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- 00001
009 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
010 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
011 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
012 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
013 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 ----- ----- ----- -----
014 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
015 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 00001 00001 00001
016 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- 00001 ----- -----
017 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
018 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
019 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
020 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
021 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
022 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
023 00002 00001 ----- 00002 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
024 00001 ----- 00001 ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
025 00001 00002 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
026 00001 ----- ----- ----- = ----- 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
027 ----- 00001 ----- ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- -----
028 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
029 00001 00001 00001 00003 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
030 00001 ----- 00001 00001 = 00001 ----- 00001 ----- = 00001 00001 00001 00001 = 00001 00001 00001 00001 00001
031 ----- 00001 ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
032 00001 ----- 00001 ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- 00001 -----
033 00002 00002 00001 00003 = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 00001 ----- -----
034 00002 00002 00001 ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- 00001 00001
035 ----- ----- 00001 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
036 ----- 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
037 ----- 00002 00001 ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- -----
038 00003 ----- 00002 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
039 ----- ----- 00001 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 00001 00001 00001
040 ----- ----- ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
041 00001 ----- 00001 00002 = ----- 00001 ----- ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- -----
042 00039 00047 00026 00030 = 00026 00029 00028 00035 = 00009 00008 00006 00006 = 00001 ----- 00001 00001 00001
043 00110 00089 00131 00118 = 00108 00111 00131 00122 = 00062 00055 00062 00068 = 00010 00013 00010 00010 00015
044 00105 00107 00091 00117 = 00118 00140 00115 00103 = 00167 00177 00171 00163 = 00188 00184 00190 00198 00183
045 00060 00107 00097 00039 = 00076 00040 00053 00045 = 00231 00036 00253 00015 = 00019 00017 00013 00011 00031
046 00125 00110 00115 00124 = 00189 00141 00138 00159 = 00061 00247 00050 00010 = 00253 00004 00002 00007 00240
047 00184 00155 00165 00187 = 00127 00183 00180 00179 = 00162 00167 00139 00170 = 00131 00134 00132 00116 00133
048 00087 00097 00093 00095 = 00094 00093 00094 00097 = 00051 00052 00061 00053 = 00052 00047 00051 00056 00052
049 00005 00003 00005 00004 = 00004 00004 00002 ----- = ----- ----- ----- ----- = 00001 00001 ----- ----- -----
050 00003 00005 ----- 00001 = ----- ----- 00001 00002 = ----- ----- ----- ----- = ----- ----- ----- ----- -----
051 ----- ----- 00002 00002 = ----- ----- ----- ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- -----
052 ----- ----- 00002 ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
053 00001 ----- 00001 ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
054 00002 00001 00001 00002 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
055 ----- 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
056 00001 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
057 00001 ----- 00001 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 ----- ----- -----
058 00001 00002 00001 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- 00001 00001 00001
059 00001 ----- ----- ----- = ----- ----- ----- ----- = ----- 00001 ----- ----- = ----- ----- ----- ----- -----
060 00002 00001 00001 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
061 ----- 00001 ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
062 00001 ----- ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
063 00001 00002 00001 ----- = ----- ----- ----- 00001 = 00001 ----- ----- ----- = 00001 00001 00001 00001 00001
064 00002 00003 00001 ----- = ----- ----- 00001 00002 = 00001 ----- 00003 00001 = ----- ----- ----- ----- -----
065 00007 00002 00002 00003 = 00004 00002 00004 00005 = 00005 00005 00005 00009 = 00003 00003 00003 00002 00001
066 00016 00018 00017 00020 = 00022 00020 00018 00015 = 00028 00027 00026 00029 = 00019 00020 00024 00021 00024
067 00055 00053 00059 00057 = 00055 00055 00056 00057 = 00051 00059 00061 00054 = 00149 00143 00144 00163 00145
068 00064 00067 00058 00066 = 00060 00074 00071 00071 = 00069 00063 00056 00071 = 00095 00090 00095 00071 00095
069 00079 00102 00106 00091 = 00098 00079 00084 00088 = 00148 00138 00144 00124 = 00082 00084 00058 00080 00069
070 00243 00206 00219 00224 = 00218 00229 00228 00216 = 00176 00193 00197 00200 = 00144 00169 00182 00153 00171
071 00080 00095 00078 00089 = 00077 00078 00086 00092 = 00088 00089 00078 00078 = 00214 00198 00200 00216 00204
072 00083 00087 00093 00082 = 00102 00094 00083 00082 = 00067 00066 00064 00072 = 00047 00046 00047 00048 00044
073 00012 00005 00008 00015 = 00008 00011 00008 00008 = 00011 00005 00010 00006 = 00003 00003 00003 00002 00003
074 00001 00006 00002 00003 = 00002 00003 00008 00008 = ----- 00001 00002 00002 = ----- ----- ----- ----- -----
075 ----- 00002 00001 ----- = 00001 00001 ----- 00001 = ----- ----- 00001 ----- = ----- ----- ----- ----- -----
076 00001 ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
077 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
078 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
079 ----- ----- ----- ----- = ----- 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
080 ----- 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
081 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
082 00001 ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
083 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
084 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
085 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
086 00001 ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
087 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
088 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- 00001 ----- = ----- ----- ----- ----- -----
089 ----- ----- ----- 00003 = ----- 00001 ----- ----- = 00001 ----- ----- ----- = 00001 00003 00001 00001 00002
090 00004 00003 00003 ----- = 00002 00002 00002 00002 = 00004 00005 00004 00006 = 00015 00015 00016 00017 00018
091 00002 00007 00005 00004 = 00005 00004 00005 00006 = 00004 00005 00005 00004 = 00057 00059 00059 00061 00053
092 00003 00002 00003 00005 = 00005 00003 00003 00005 = 00003 00003 00006 00005 = 00100 00092 00094 00089 00096
093 00008 00005 00006 00005 = 00004 00006 00005 00006 = 00005 00004 00002 00003 = 00113 00123 00123 00130 00120
094 ----- 00004 00003 00002 = 00002 00003 00003 00001 = 00002 00003 00002 00002 = 00127 00116 00116 00113 00123
095 00005 00002 00004 00004 = 00004 00004 00004 00003 = 00004 00003 00002 00003 = 00069 00072 00072 00073 00069
096 00001 00001 ----- ----- = 00001 ----- 00001 ----- = 00001 00001 00001 ----- = 00022 00022 00023 00022 00024
097 ----- ----- 00001 00001 = 00001 00001 00001 ----- = ----- ----- ----- 00001 = 00004 00006 00004 00002 00003
098 ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 ----- 00001 ----- = ----- ----- ----- ----- -----
099 00001 ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
100 ----- 00001 ----- ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- -----
101 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 00001 00001 00001
102 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- 00001 = ----- ----- ----- ----- -----
103 ----- 00001 00001 ----- = ----- ----- ----- ----- = 00001 ----- ----- ----- = ----- ----- ----- ----- -----
104 00001 ----- ----- 00001 = 00001 ----- 00001 ----- = ----- 00001 00001 ----- = ----- ----- ----- ----- -----
105 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
106 ----- ----- ----- ----- = ----- 00001 ----- 00001 = ----- ----- ----- ----- = ----- ----- ----- ----- -----
107 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
108 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
109 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
110 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
111 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
112 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
113 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = 00001 00001 ----- 00001 00001
114 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- 00001 ----- -----
115 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
116 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
117 ----- 00001 00001 00001 = ----- ----- 00001 00001 = 00001 00001 00001 00001 = ----- ----- ----- ----- -----
118 00001 ----- ----- ----- = 00001 00001 ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
119 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
120 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
121 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
122 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
123 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
124 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
125 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
126 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----
127 ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- = ----- ----- ----- ----- -----

Ideally the 3 groupings of pulse deltas (2, 4 and 8us) should be quite separated. I did find that this showed up best on a newly formatted track. On track 0 I assume that some sectors had been over-written which introduces some pulse anomolies at the begining and end of the splice.

The first set of four columns are without the increased interrupt priority (default is 128) and the others are with it set to priority 0, plus some other experiments with SysTick.

I was also worried about the SysTick interrupt getting in the way. By default is has priority 16. To avoid any issues I disabled it with the following command...

Code:
  SYST_CSR = SYST_CSR_CLKSOURCE; // disable SYSTICK interrupts

and re-enabled it with the following command...

Code:
  SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE; // re-enable SYSTICK

WARNING: when disabled the delay() fuinction will almost certainly not work (I haven't confirmed but the SysTick ISR ised used to increment a milliseconds timer).

With no delay() function I used the index pulse to generate a different interrupt, which I could use to find the start and end of a track.

If anyone is interested in the code, here it is.

Code:
//
// modified by badsector
// 31-Dec-2019 : Port to Teensy 3.0
//             : Using hex open collector inverter 74LS05. 
// 01-Jan-2020 : Add timer code to measure time between pulses from floppy read pin.
//

#include <stdio.h> // for function sprintf

#define PRESCALE (FTM_SC_PS(2))
#define MAXEVENTCOUNT   6000

const byte STEP_TIME  = 10;
const byte STEP_PULSE =  2;

const byte ON  = 1;
const byte OFF = 0;
const byte IN  = 1;
const byte OUT = 0; // towards outer track (track 0)

// TEENSY3.0 pins and usage //
const byte toFDDdirSelect = 11;       // to floppy input pin 18
const byte toFDDmotorOn   = 12;       // to floppy input pin 16
const byte toFDDselect    = 14;       // to floppy input pin 12
const byte toFDDstep      = 15;       // to floppy input pin 20
const byte toFDDside      = 16;       // to floppy input pin 32

const byte fromFDDtrack00  = 23;       // from floppy output pin 26
const byte fromFDDindexPin = 22;       // from floppy output pin  8
const byte fromFDDreadPin  = 21;       // from floppy output pin  30

const byte fromFDDreadPinIRQ  = 43; // IRQ_PORTD = 43,   // kinetis.h (Teensy 3.0)

const byte debugpin = 20;      // connect to scope to see length of interrupt routine
//~~~~~~~~~~~~~~~~~~~~~~~~~~~//

//------------------------------------GLOBAL VARIABLES----------------------------------------
int  track = 1;
byte stepdir=OUT;
int  motoron=ON;
int  drivesel=ON;

char sbuf[99];       // sprintf buffer
uint16_t histo[256]; // collect histogram of measured pulse deltas

// capture delta timings between floppy read data stream pulses
volatile int events;
volatile uint8_t eventdata[MAXEVENTCOUNT];
volatile int index_detected;

//-----------------------------------------SETUP---------------------------------------------
void setup() {
  Serial.begin(9600);

  // pins to connect to/from the 3.5inch floppy drive
  pinMode(fromFDDindexPin, INPUT_PULLUP);
  pinMode(fromFDDreadPin,  INPUT_PULLUP);
  pinMode(fromFDDtrack00,  INPUT_PULLUP);

  pinMode(toFDDstep,      OUTPUT);
  pinMode(toFDDdirSelect, OUTPUT);
  pinMode(toFDDmotorOn,   OUTPUT);
  pinMode(toFDDselect,    OUTPUT);
  pinMode(toFDDside,      OUTPUT);

  pinMode(debugpin,   OUTPUT);
  digitalWrite(debugpin,LOW);

  // initial values
  digitalWrite(toFDDstep,      LOW);   // sets it high
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
  digitalWrite(toFDDside,      HIGH);
  digitalWrite(toFDDmotorOn,   (motoron==ON)?HIGH:LOW);
  digitalWrite(toFDDselect,    (drivesel==ON)?HIGH:LOW);

  // interrupt from index pulse
  attachInterrupt(fromFDDindexPin,FDD_index_ISR,RISING);

  // interrupt from read data stream pulses
  attachInterrupt(fromFDDreadPin, nullptr, RISING);        // just using this to setup the CHANGE interrupt trigger
  attachInterruptVector(IRQ_PORTD, FDD_stream_decode_ISR); // this is the ISR that will be run
  disable_FDD_stream_decode_ISR();
  clearpending_FDD_stream_decode_ISR();

  ////////////////////////////////////////////////////////////////
  // this really helps with repeatability of pulse measurements //
  ////////////////////////////////////////////////////////////////
  NVIC_SET_PRIORITY(fromFDDreadPinIRQ, 0);   // HIGHEST priority

  // setup timer config which doesnt change
  FTM0_MODE = FTM_MODE_FTMEN | FTM_MODE_WPDIS;
  FTM0_MOD  = 0xFFFF;
  // disable to begin with - done by setting clock to disabled!
  FTM0_SC   = FTM_SC_CLKS(0) | (PRESCALE); // disable clock + no prescale
}

//--------------------------------HARDWARE SPECIFIC-----------------------------------------------

void domotor(void) {
  digitalWrite(toFDDmotorOn,   (motoron==ON)?HIGH:LOW);   // motoron is a global variable
}

void dodrivesel(void) {
  drivesel=ON; digitalWrite(toFDDselect,    (drivesel==ON)?HIGH:LOW);   // drivesel is a global variable
}

bool isTrack00(void) {
  return (digitalRead(fromFDDtrack00)==HIGH);
}

void stepOut() {
  stepdir=OUT;
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
}
void stepIn() {
  stepdir=IN;
  digitalWrite(toFDDdirSelect, (stepdir==OUT)?LOW:HIGH);
}

void stepPulse() {
  digitalWrite(toFDDstep, HIGH);
  delay(STEP_PULSE); // 800us minimum
  digitalWrite(toFDDstep, LOW);
  delay(STEP_TIME); 
  if (isTrack00()) { 
    track=0; 
  } else {
    if (stepdir==IN) { track++; } else { track--; }
  }
}

//--------------------------------------------------------------------------------------------
// use macros to make interrupt enable/disable more readable

void enable_FDD_stream_decode_ISR(void) {
  NVIC_ENABLE_IRQ(fromFDDreadPinIRQ);
}
void disable_FDD_stream_decode_ISR(void) {
  NVIC_DISABLE_IRQ(fromFDDreadPinIRQ);
}
void clearpending_FDD_stream_decode_ISR(void) {
  NVIC_CLEAR_PENDING(fromFDDreadPinIRQ);
}

//--------------------------------------------------------------------------------------------
FASTRUN void FDD_index_ISR(void) {
  index_detected=1;
}

//--------------------------------------------------------------------------------------------

FASTRUN void FDD_stream_decode_ISR(void) {
  uint16_t timer;
  uint32_t isfr = PORTD_ISFR;     // NEW
  PORTD_ISFR = isfr;              // NEW

  if (events>0) {
  ;;;;;;;;;;;;;digitalWriteFast(debugpin,HIGH); // debug for scope to see length of interrupt execution
  }

  FTM0_SC   = FTM_SC_CLKS(0) | (PRESCALE); // STOP CLOCK
  timer = (uint8_t)(FTM0_CNT&0xff);
  // after reading immediately re-start
  FTM0_CNT = 0;                              // reset count
  FTM0_SC  = FTM_SC_CLKS(1) | (PRESCALE); // RESTART CLOCK
  if (events<MAXEVENTCOUNT) { 
    eventdata[events++] = timer;          // read count
  }

  ;;;;;;;;;;;;;digitalWriteFast(debugpin,LOW);
}

//--------------------------------------------------------------------------------------------

void readTrack() {

  // wait for index pulse to go (low from floppy) (high seen by Teensy)
  while (digitalRead(fromFDDindexPin)==HIGH); // in case the index pulse is already active
  while (digitalRead(fromFDDindexPin)==LOW);

  events=0;


  FTM0_SC   = FTM_SC_CLKS(1) | (PRESCALE); // system (48MHz) clock + no prescale
  FTM0_CNT  = 0;

  SYST_CSR = SYST_CSR_CLKSOURCE; // disable SYSTICK interrupts

  enable_FDD_stream_decode_ISR();
  clearpending_FDD_stream_decode_ISR();

  index_detected=0;          // reset variable - can only be set in interrupt routine
  while (index_detected==0); // wait for index pulse

  disable_FDD_stream_decode_ISR();
  clearpending_FDD_stream_decode_ISR();
  FTM0_SC   = FTM_SC_CLKS(0) | (PRESCALE); // disable clock + no prescale

  SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE; // re-enable SYSTICK

  sprintf(sbuf,"No of events = %d\n",events);
  Serial.println(sbuf);

}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

bool active = true;
byte k = 25;
unsigned char cmd;

void loop() {
  
  if (Serial.available()) {
    cmd = Serial.read();
    if (cmd=='s') {
      stepPulse();
      sprintf(sbuf, "Track0 = %s track = %d Step dir = %s",isTrack00()?"TRUE":"false",track,stepdir==OUT?"OUT":"IN");
      Serial.println(sbuf);
    }
    if (cmd==' ') {
      sprintf(sbuf, "Track0 = %s track = %d Step dir = %s",isTrack00()?"TRUE":"false",track,stepdir==OUT?"OUT":"IN");
      Serial.println(sbuf);
    }
    if (cmd=='i') {
      stepIn();
      Serial.println("step dir in...");
    }
    if (cmd=='o') {
      stepOut();
      Serial.println("step dir out...");
    }
    if (cmd=='m') {
      if (motoron==ON) { motoron=OFF; } else { motoron=ON; }
      domotor();
      Serial.println("motor ...");
    }
    if (cmd=='d') {
      if (drivesel==ON) { drivesel=OFF; } else { drivesel=ON; }
      dodrivesel();
      Serial.println("drive select...");
    }
    if (cmd=='r') {
      drivesel=ON; dodrivesel();
      motoron =ON; domotor();
      delay(100); // wait for drive to spin up
      Serial.println("reading track ...");
      readTrack();
      for (int i=0;i<256;i++) { histo[i]=0; } // zero histogram

      for (int i=0;i<events;i++) { uint8_t t=eventdata[i]; histo[t]++; } // create histogram

      int p2=0;
      int p4=0;
      int p6=0;
      for (int i=0;i<128;i++) { 
        uint8_t h=histo[i];
        if ((i>=32)&&(i<60)) { p2+=h; }
        if ((i>=60)&&(i<84)) { p4+=h; }
        if ((i>=84)&&(i<99)) { p6+=h; }
        if (h==0) {
          sprintf(sbuf, "%03d -----", i); Serial.println(sbuf); 
        } else {
          sprintf(sbuf, "%03d %05d", i,h); Serial.println(sbuf); 
        } 
      }
      sprintf(sbuf,"2us=%03d 4us=%03d 6us=%03d",p2,p4,p6); Serial.println(sbuf); 
      Serial.println("");
    }
  }
}

regards...

--badsector
 
Status
Not open for further replies.
Back
Top