Hello everyone,
For my project I want to use a frdm-K64F to read in quadrature encoder pulses. I have been using mbed to abstract most of the lower level code, however I have found that it has no implementation of hardware quadrature decoding, necessitating lower level code to facilitate this. Most of the implemented code is working, the only issue remaining is that the timer overflow interrupt seems to make the system hang.
For the K64F, flex timer 1 (FTM1) and FTM2 support quadrature decoding. For the code below FTM2 is used as its inputs are available directly on the headers of the frdm board, to which the A and B phase signals are connected (PTB18 and PTB19 respectively).
The code is confirmed to work properly for counting the encoder up and down, but locks up and goes into an infinite loop when a timer overflow occurs. If I don't enable interrupts (remove FTM2->SC |= FTM_SC_TOIE(1);) the code simply loops back from 64 to 0, and visa versa.
My steps for enabling the interrupts are:
- Enable interrupts for FTM2: FTM2->SC |= FTM_SC_TOIE(1);
- Tell the NVIC to handle FTM2 interrupts: NVIC_EnableIRQ(FTM2_IRQn);
- Handle the interrupt by overriding the weak callback function: void FTM2_IRQHandler(void){ .... }
I suspect that either I am missing an initialization step of the interrupt, or that somehow using the IRQHandler is not working well with mbed. Of course I am leaning more towards the former than the latter. Am I missing something? Or is there a mistake I am making?
For completion sake, I am using mbed studio with mbed OS 6.8.0 on the FRDM-K64F.
#include "mbed.h"
const unsigned int CONST_ENC_MOD_SIZE = 65;
static BufferedSerial pc(USBTX, USBRX);
void FTM2_IRQHandler(void);
// main() runs in its own thread in the OS
int main()
{
pc.set_baud(115200);
// Register reference: https://os.mbed.com/questions/77426/Why-cant-I-access-FTM2-MODE-on-the-FRDM-/
// https://www.nxp.com/docs/en/application-note/AN5142.pdf
// RF chapter 40 for FTM modules
//
// In the reference manual of k64F, page 1100 [40.4.25 QUadrature Decoder mode]
// page 142 [3.8.2.1 (FTM) Instantiation information] -> FTM1 and FTM2 are used for quadrature decoders
// page 249 [10.3.1 K64 Signal Multiplexing and Pin assignments] -> pin connections for the timers
//
// This gives the following possible pins for the two timers (A; B), tqfp 100
// FTM1
// (PTB0, PTB1) on ALT6 function (PCR MUX)
// (PTA12, PTA13) on ALT7 function (PCR MUX)
//
// FTM2
// (PTB18, PTB19) on ALT6 function (PCR mux)
printf("Initializing...\n");
// Enable the clock for FTM
SIM->SCGC6 |= SIM_SCGC6_FTM2_MASK;
// Enable the counter
FTM2->MODE |= FTM_MODE_FTMEN_MASK;
// Enable the counter to run in the BDM mode
FTM2->CONF |= FTM_CONF_BDMMODE(3);
// Load the modulo register (max is 2^16 -1, 65535)
FTM2->MOD = CONST_ENC_MOD_SIZE;
// Load initial value into the timer register
FTM2->CNTIN = 0; // Note that writing a value to the 'count' register doesn't updata it, but instead updates it with the initial value.
// Config quadrature mode
FTM2->QDCTRL |= FTM_QDCTRL_QUADEN_MASK;
// Start the timer clock with src as external (RF P 993)
FTM2->SC |= FTM_SC_CLKS(3); // Clock source as external
FTM2->SC |= FTM_SC_TOIE(1); // Enable interrupts on overflow
// Configuring the input pins
PORTB->PCR[18] = PORT_PCR_MUX(6); // Select pin alt. function, quadrature mode FTM2 CHA
PORTB->PCR[19] = PORT_PCR_MUX(6); // Select pin alt. function, quadrature mode FTM2 CHB
//NVIC->ISER[FTM2_IRQn / 32] |= (1 << (FTM2_IRQn% 32));
NVIC_EnableIRQ(FTM2_IRQn);
while (true) {
wait_us(200000); // 200ms wait
uint32_t cnt = FTM2->CNT;
printf("%d\n", cnt);
}
}
void FTM2_IRQHandler(void){
if(FTM2->CNT > (CONST_ENC_MOD_SIZE/2)){ // Negative overflow
printf("Negative overflow\n");
// TODO handle overflow
}else{ // Positive overflow
printf("Positive overflow\n");
// TODO handle overflow
}
FTM2->SC &= ~FTM_SC_TOF(1); // Clear timer overflow bit
}
Additionally I have tried to override the interrupt vector:
NVIC_SetVector(FTM2_IRQn, (uint32_t)&FTM2_IRQHandler);
This sadly just results in the MCU throwing an error (flashing red led)