Hello everyone,
For my application I want to use a quadrature encoder on a motor, but I have found that the mbed library does not use the hardware support for quadrature decoding on the board I am using (NXP/Freescale K64F).
I have figured out most of what I needed with the help of the user manual of the K64F, however, I have become stuck at the handling of the interrupt.
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, 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.
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
}