TelephoneBill
Well-known member
My thanks to colleague “FAlameda” for pointing me in the right direction on this little experiment.
In addition to their use as “timers”, the Flextimer(s) in Teensy 3.1 may also be used as “pulse counters” to count external pulses edges.
If you have a steady train of pulses, this mode of operation is a bit like using an external clock signal. But rather than injecting the external clock through the ARM chip pins 32 or 33 (which the schematic diagram shows are already used for the Teensy 16 MHz crystal), you can inject this “external clock” through one of the standard PORT pins. You may then also “trap and read the value” of the Flextimer at any instant using another standard PORT pin.
In this experiment, I wanted to count every single cycle of a 10 MHz oscillator, just to prove that the frequency was precisely 10,000,000 Hz and not 9,999,999 Hz or 10,000,001 Hz. I trap and read the value using another precise signal source of 1 pulse per second (1PPS) – from a Rubidium Standard Freq Module (some cheap GPS modules will also provide a 1 PPS).
Table 36-1 of the Freescale reference manual, or paragraph 36.4.25, illustrates that the Flextimer can be set into “Quadrature Decoder Mode”. If your program code sets QUADMODE = 1, then the pin associated with PHA is available as an input pin for inserting external pulses which the Flextimer will count in its 16 bit counter. The up/down direction of counting is set by the pin associated with PHB (PHB high = count upwards, low = count downwards).
To read the value of the 16 bit counter, you can then use one of the “channels” associated with the Flextimer. I use CH0.
The following code shows how this mode of operation was configured for my experiment using Flextimer 1:
//(1) Setup statements
void setup() {
//configure Flextimer 1
FTM1_MODE = 0x05; //set write-protect disable (WPDIS) bit to modify other registers
//FAULTIE=0, FAULTM=00, CAPTEST=0, PWMSYNC=0, WPDIS=1, INIT=0, FTMEN=1(no restriction FTM)
FTM1_SC = 0x00; //set status/control to zero = disable all internal clock sources
FTM1_CNT = 0x0000; //reset count to zero
FTM1_MOD = 9999; //max modulus = 9999 (gives count = 10000 on roll-over)
FTM1_C0SC = 0x04; // CHF=0, CHIE=0 (disable interrupt, use software polling), MSB=0 MSA=0, ELSB=0 ELSA=1 (input capture - rising edge), 0, DMA=0
//enable FTM1 interrupt within NVIC table
NVIC_ENABLE_IRQ(IRQ_FTM1);
//configure Teensy port pins
PORTA_PCR12 |= 0x700; //MUX = alternative function 7 on Chip Pin 28 (FTM1_QD_PHA) = Teensy Pin 3
PORTA_PCR13 |= 0x700; //MUX = alternative function 7 on Chip Pin 29 (FTM1_QD_PHB) = Teensy Pin 4
PORTB_PCR0 |= 0x300; //MUX = alternative function 3 on Chip Pin 35 (FTM1_CH0) = Teensy Pin 16
//set flextimer quad decode mode and enable overflow interrupt
FTM1_QDCTRL = 0x0F; //see section 36.3.21 of ref manual for details
FTM1_SC = 0x40; // (Note – FTM1_SC [TOF=0 TOIE=1 CPWMS=0 CLKS=00 (internal clocks disabled) PS=000 [no prescale divide])
}
//(2) ISR routine for FlexTimer1 Module
extern "C" void ftm1_isr(void) {
if ((FTM1_SC & FTM_SC_TOF) != 0) { //read the timer overflow flag (TOF in FTM1_SC)
FTM1_SC &= ~FTM_SC_TOF; //if set, clear overflow flag
}
FTM1CountOVFlow++; //increment overflow counter
}
//(3) main loop statements
void loop() {
//read FTM1 Ch0 value if valid
if ((FTM1_C0SC&0x80) != 0) { //look for CH0 event flag
FTM1Ch0CountValue = FTM1_C0V; //read CH0 value
FTM1_C0SC &= ~0x80; //clear CH0 event flag
}
}
Explanation…
The code above is divided into three sections – (1) Setup, (2) Interrupt Service Routine, and (3) Main Loop.
In “Setup”, notice that the internal clock source (the normal 48 MHz peripheral clock) is switched off and never switched back on - the last statement in this section “FTM1_SC = 0x40;” is only enabling the overflow interrupt flag. I set the count modulus to 9999 so that the 16 bit counter will overflow on a count of 10,000, which will be every millisecond for 10 MHz external pulse rate. I’m also using a polling technique via CH0 of FTM1 in the main loop to read the value at a fixed instant in time. That value is trapped when Teensy pin 16 goes high from the 1 PPS source.
The ISR routine simply resets the TOF flag in the “FTM1_SC” register, and then increments the overflow count program variable “FTM1CountOVFlow”.
The main loop code is polling the CH0 event flag and resetting it appropriately. I also transfer the “instant value” of the 16 bit counter into a program variable “FTM1Ch0CountValue”, so that I can display this on my PC screen using other statements (not shown above) during a later time in the main loop.
To summarise, the three port pins employed are Teensy pin 3 (inject my 10 MHz signal), Teensy pin 4 (connected to logic high +5v), and Teensy pin 16 (inject my 1 PPS signal).
The experiment was run for over one hour. The displayed value of “FTM1Ch0CountValue” was “3986” and never varied from that figure over the hour (save for a momentary flicker occasionally down to “3985” and then back to “3986”) This is an arbitrary absolute value and depends only on the instant that the 10 MHz was connected to the Teensy board. The flicker is illustrating that just occasionally, the edge of the 1 PPS is not quite catching the last cycle – but it corrects this on the next count and hence restores “3986”.
This experiment illustrated that the each cycle of the 10 million cycles was being counted successfully by the Flextimer counter, and that precisely 10 million cycles were being executed every second for the whole of the hour period. If the frequency had been 1 Hz above (or below), then “3986” would eventually creep upwards in value (or downwards) at a rate of change of one unit per second. I did deliberately upset the 10 MHz afterwards to demonstrate this was the case.
Considering that more than 36 billion cycles had been accurately counted by the Teensy board, then I consider this experiment a resounding success !!
In addition to their use as “timers”, the Flextimer(s) in Teensy 3.1 may also be used as “pulse counters” to count external pulses edges.
If you have a steady train of pulses, this mode of operation is a bit like using an external clock signal. But rather than injecting the external clock through the ARM chip pins 32 or 33 (which the schematic diagram shows are already used for the Teensy 16 MHz crystal), you can inject this “external clock” through one of the standard PORT pins. You may then also “trap and read the value” of the Flextimer at any instant using another standard PORT pin.
In this experiment, I wanted to count every single cycle of a 10 MHz oscillator, just to prove that the frequency was precisely 10,000,000 Hz and not 9,999,999 Hz or 10,000,001 Hz. I trap and read the value using another precise signal source of 1 pulse per second (1PPS) – from a Rubidium Standard Freq Module (some cheap GPS modules will also provide a 1 PPS).
Table 36-1 of the Freescale reference manual, or paragraph 36.4.25, illustrates that the Flextimer can be set into “Quadrature Decoder Mode”. If your program code sets QUADMODE = 1, then the pin associated with PHA is available as an input pin for inserting external pulses which the Flextimer will count in its 16 bit counter. The up/down direction of counting is set by the pin associated with PHB (PHB high = count upwards, low = count downwards).
To read the value of the 16 bit counter, you can then use one of the “channels” associated with the Flextimer. I use CH0.
The following code shows how this mode of operation was configured for my experiment using Flextimer 1:
//(1) Setup statements
void setup() {
//configure Flextimer 1
FTM1_MODE = 0x05; //set write-protect disable (WPDIS) bit to modify other registers
//FAULTIE=0, FAULTM=00, CAPTEST=0, PWMSYNC=0, WPDIS=1, INIT=0, FTMEN=1(no restriction FTM)
FTM1_SC = 0x00; //set status/control to zero = disable all internal clock sources
FTM1_CNT = 0x0000; //reset count to zero
FTM1_MOD = 9999; //max modulus = 9999 (gives count = 10000 on roll-over)
FTM1_C0SC = 0x04; // CHF=0, CHIE=0 (disable interrupt, use software polling), MSB=0 MSA=0, ELSB=0 ELSA=1 (input capture - rising edge), 0, DMA=0
//enable FTM1 interrupt within NVIC table
NVIC_ENABLE_IRQ(IRQ_FTM1);
//configure Teensy port pins
PORTA_PCR12 |= 0x700; //MUX = alternative function 7 on Chip Pin 28 (FTM1_QD_PHA) = Teensy Pin 3
PORTA_PCR13 |= 0x700; //MUX = alternative function 7 on Chip Pin 29 (FTM1_QD_PHB) = Teensy Pin 4
PORTB_PCR0 |= 0x300; //MUX = alternative function 3 on Chip Pin 35 (FTM1_CH0) = Teensy Pin 16
//set flextimer quad decode mode and enable overflow interrupt
FTM1_QDCTRL = 0x0F; //see section 36.3.21 of ref manual for details
FTM1_SC = 0x40; // (Note – FTM1_SC [TOF=0 TOIE=1 CPWMS=0 CLKS=00 (internal clocks disabled) PS=000 [no prescale divide])
}
//(2) ISR routine for FlexTimer1 Module
extern "C" void ftm1_isr(void) {
if ((FTM1_SC & FTM_SC_TOF) != 0) { //read the timer overflow flag (TOF in FTM1_SC)
FTM1_SC &= ~FTM_SC_TOF; //if set, clear overflow flag
}
FTM1CountOVFlow++; //increment overflow counter
}
//(3) main loop statements
void loop() {
//read FTM1 Ch0 value if valid
if ((FTM1_C0SC&0x80) != 0) { //look for CH0 event flag
FTM1Ch0CountValue = FTM1_C0V; //read CH0 value
FTM1_C0SC &= ~0x80; //clear CH0 event flag
}
}
Explanation…
The code above is divided into three sections – (1) Setup, (2) Interrupt Service Routine, and (3) Main Loop.
In “Setup”, notice that the internal clock source (the normal 48 MHz peripheral clock) is switched off and never switched back on - the last statement in this section “FTM1_SC = 0x40;” is only enabling the overflow interrupt flag. I set the count modulus to 9999 so that the 16 bit counter will overflow on a count of 10,000, which will be every millisecond for 10 MHz external pulse rate. I’m also using a polling technique via CH0 of FTM1 in the main loop to read the value at a fixed instant in time. That value is trapped when Teensy pin 16 goes high from the 1 PPS source.
The ISR routine simply resets the TOF flag in the “FTM1_SC” register, and then increments the overflow count program variable “FTM1CountOVFlow”.
The main loop code is polling the CH0 event flag and resetting it appropriately. I also transfer the “instant value” of the 16 bit counter into a program variable “FTM1Ch0CountValue”, so that I can display this on my PC screen using other statements (not shown above) during a later time in the main loop.
To summarise, the three port pins employed are Teensy pin 3 (inject my 10 MHz signal), Teensy pin 4 (connected to logic high +5v), and Teensy pin 16 (inject my 1 PPS signal).
The experiment was run for over one hour. The displayed value of “FTM1Ch0CountValue” was “3986” and never varied from that figure over the hour (save for a momentary flicker occasionally down to “3985” and then back to “3986”) This is an arbitrary absolute value and depends only on the instant that the 10 MHz was connected to the Teensy board. The flicker is illustrating that just occasionally, the edge of the 1 PPS is not quite catching the last cycle – but it corrects this on the next count and hence restores “3986”.
This experiment illustrated that the each cycle of the 10 million cycles was being counted successfully by the Flextimer counter, and that precisely 10 million cycles were being executed every second for the whole of the hour period. If the frequency had been 1 Hz above (or below), then “3986” would eventually creep upwards in value (or downwards) at a rate of change of one unit per second. I did deliberately upset the 10 MHz afterwards to demonstrate this was the case.
Considering that more than 36 billion cycles had been accurately counted by the Teensy board, then I consider this experiment a resounding success !!