Hello Everyone,
I would like to used FTM2_QD(PTD10, PTD11) to measure every rising or falling edge of A and B by using counter overflow interrupt and then calculate the motor position based on encoder. But I am troubled by the FTM2_QD configuration for a long time.
Below is my configuration for FTM2_QD. Please provide some help.
void FTM2_Quadrature_Decoder_Mode()
{
/* Enable clock for PORTD */
PCC->PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK;
/* Select and enable clock for FTM2 */
PCC->PCCn[PCC_FLEXTMR2_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK;
PORTD->PCR[10] = PORT_PCR_MUX(3); // Set PTD10 for FTM2 - Phase B input
PORTD->PCR[11] = PORT_PCR_MUX(3); // Set PTD11 for FTM2 - Phase A input
FSL_NVIC->ISER[FTM2_IRQn / 32] |= (1 << (FTM2_IRQn % 32)); // Enable FTM2 counter overflow interrupt
// FSL_NVIC->ICPR[116/32] = 1 << (116% 32);
FSL_NVIC->ISER[116/32] = 1 << (116% 32); // overflow interrupt number
// FSL_NVIC->IP[116] = 0;
FTM2->MODE = FTM_MODE_WPDIS_MASK | FTM_MODE_FTMEN_MASK;
//Enable FTM2 module (0x00000005): D2(WPDIS) and D0(FTMEN) are set.
FTM2->MOD = FTM_MOD_MOD(10); // overflow after totally 4096 rising/falling edges
FTM2->CNT = 0;
FTM2->CNTIN = FTM_CNTIN_INIT(0);
FTM2->QDCTRL &= ~FTM_QDCTRL_QUADMODE_MASK; // Phase A and phase B encoding mode
FTM2->QDCTRL = FTM_QDCTRL_PHAFLTREN_MASK | FTM_QDCTRL_PHBFLTREN_MASK | FTM_QDCTRL_QUADEN_MASK; // Enable QD mode and input filter
FTM2->SC |= FTM_SC_CLKS(1) | FTM_SC_PS(2) | FTM_SC_CPWMS_MASK | FTM_SC_TOIE_MASK;
// FTM_SC_CLKS(1): select FTM as input timer.
// FTM_SC_PS(2): clock source FTM, prescaler 2^2, clock frequency = 112MHz/4 = 28MHz
// FTM_SC_TOIE_MASK: enable timer overflow interruption
// FTM_SC_CPWMS_MASK; D5(CPWMS) is set to enable up-down counting mode
}
Below is the overflow interrupt function.
void FTM2_Ovf_Reload_IRQHandler()
{
if( FTM2->SC & FTM_SC_TOF_MASK ){ // there is overflow interrupt
PTC->PTOR |= 1<<9; // Toggle PTC9 for scope display
FTM2_ISR_Counter++;
Temp_EncoderB = FTM2->CONTROLS[0].CnV; //store the captured C0V value (Counter's vaule)
Temp_EncoderA = FTM2->CONTROLS[1].CnV; //store the captured C1V value (Counter's vaule)
FTM2->CONTROLS[0].CnSC &= ~FTM_CnSC_CHF_MASK; //clear Ch0 flag D7(CHF) is required to be reset after reading
FTM2->CONTROLS[1].CnSC &= ~FTM_CnSC_CHF_MASK; //clear Ch1 flag D7(CHF) is required to be reset after reading
Count_Encoder = FTM2->CNT;
FTM2->SC &= ~FTM_SC_TOF_MASK; // Clear timer overflow flag D9(TOF) after reading the captured C0V and C0V1 values.
}
}
I do not know why there is no output for Temp_EncoderB and Temp_EncoderA. It sounds like the overflow interrupt does not happen. Please provide some help if you know.
Thanks.
Best,
Jianfei Chen
Hello Rong,
The interrupt does not work because you are using old code/header file where is used FSL_NVIC write.
The S32_NVIC should be used instead of FSL_NVIC in the new projects.
I recommend you to create a new project. After that, the header file will be correct and you can use, for example, code below for initialization of the interrupt:
S32_NVIC->ICPR[3] = 1 << (116 % 32);
S32_NVIC->ISER[3] = 1 << (116 % 32);
S32_NVIC->IP[116] = 0x00;
I hope it helps.
Best Regards,
Diana
Hello Diana,
Thanks so much.
According to your suggest, I creat a new project in S32 Design Studio but it showed there is no "S32_NVIC". What is the problem ? Is it a must to replace FSL_NVIC by S32_NVIC ?
Best,
Jianfei
Hello Rong,
Which version of S32 Design Studio do you use?
Please, use the newest version S32 Design Studio for Arm 2018.R1:
https://www.nxp.com/webapp/swlicensing/sso/downloadSoftware.sp?catid=S32-DS-ARM_v2018
Best Regards,
Diana
Maybe the problem is caused by the interruption type. I used overflow interruption, which maybe not suitable for quadrature encoder mode. What do you think ?
Best,
Jianfei
Hello Jianfei,
I really recommend you to install the newest version of the S32DS - S32 Design Studio for Arm 2018.R1 – Windows/Linux(REV 2018-R1), after that, it should work:
S32 Design Studio IDE for Arm® based MCUs | NXP
Have you seen the maskset when you select the device in v1.3? I'm asking because the v1.3 generates the old header file where the FSL_NVIC is implemented.
Best Regards,
Diana
Hello Diana,
According to your suggestion, I have installed the newest version of S32DS. Below is the code built in S32-Arm2018.R1.
#include "S32K144.h" /* include peripheral declarations S32K144 */
void FTM2_Quadrature_Decoder_Mode();
uint16_t Temp_EncoderA; //Port D11
uint16_t Temp_EncoderB; //Port D10
uint16_t FTM2_ISR_Counter=0;
uint16_t Count_Encoder = 0;
uint16_t Pre_Count_Encoder = 0;
uint16_t Count_Overflow,k;
uint8_t Motor_TOFDIR_Encoder, Motor_TOF_Encoder; // Timer overflow direction
int main(void)
{
int counter = 0;
FTM2_Quadrature_Decoder_Mode();
// for(;;) {
// }
/* to avoid the warning message for GHS and IAR: statement is unreachable*/
#if defined (__ghs__)
#pragma ghs nowarning 111
#endif
#if defined (__ICCARM__)
#pragma diag_suppress=Pe111
#endif
return 0;
}
void FTM2_Quadrature_Decoder_Mode()
{
/* Enable clock for PORTD */
PCC->PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK; // clock enabled
/* Select and enable clock for FTM2 */
PCC->PCCn[58] |= PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK;
// PORTD->PCR[4] |= PORT_PCR_MUX(1) | PORT_PCR_IRQC(9);
PORTD->PCR[10] |= PORT_PCR_MUX(3); // Set PTD10 for FTM2 - Phase B input
PORTD->PCR[11] |= PORT_PCR_MUX(3); // Set PTD11 for FTM2 - Phase A input
// S32_NVIC->ISER[3] |= (1 << (FTM2_IRQn % 32)); // Enable FTM2 interrupt FTM2_IRQn
S32_NVIC->ICPR[3] = (1<<(116%32)); //116/32=3 /* clr any pending IRQ*/
S32_NVIC->ISER[3] = (1<<(116%32)); //116/32=3 /* enable IRQ */
S32_NVIC->IP[116] = 0x00;
/* Input capture mode sensitive on both rising and falling edges to measure duty cycle of tested signal */
FTM2->MODE |= FTM_MODE_WPDIS_MASK | FTM_MODE_FTMEN_MASK; // Enable write the FTM CnV register (0x00000004): D2(WPDIS)
// Enable FTM2 module (0x00000001): D0(FTMEN) are set.FTM_MODE_INIT_MASK
//enable the counter to run in the BDM mode
//FTM2->CONF = FTM_CONF_BDMMODE(3);
/* Encoder simulation with totally 144 rising/falling edges */
FTM2->MOD = FTM_MOD_MOD(10);
/* Reset counter */
FTM2->CNTIN = FTM_CNTIN_INIT(0); // initial value of FTM2 counter
FTM2->QDCTRL &= ~FTM_QDCTRL_QUADMODE_MASK; // Phase A and phase B encoding mode
FTM2->QDCTRL |= FTM_QDCTRL_QUADEN_MASK; // Enable QD mode.
FTM2->QDCTRL &= ~FTM_QDCTRL_TOFDIR_MASK;
FTM2->CNT = 0;
/* Select clock */
FTM2->SC |= FTM_SC_CLKS(1) | FTM_SC_PS(4) | FTM_SC_TOIE_MASK;
// FTM_SC_CLKS(1) selects FTM as input timer.
// FTM_SC_PS(2); clock source FTM, prescaler 2^2, clock frequency = 112MHz/4 = 28MHz
// FTM_SC_TOIE_MASK enables timer overflow interruption
// FTM_SC_CPWMS_MASK; D5(CPWMS) is set to enable up-down counting mode FTM_SC_CPWMS_MASK
}
void FTM2_Ovf_Reload_IRQHandler()//this interrupt is FTM2
//void FTM2_Ch0_Ch1_IRQHandler()//this interrupt is FTM2
{
PTA->PTOR |= 0x0800; //PTA11 is set
if(FTM2->SC & FTM_SC_TOF_MASK ){
Motor_TOFDIR_Encoder = ((FTM2->QDCTRL)>>1)&0x1; // the QUADIR bit in the FTM_QDCTRL register indicates Timer overflow direction in QD mode
Motor_TOF_Encoder = ((FTM2->SC)>>9)&0x1; // Timer overflow flag
if(Motor_TOFDIR_Encoder){
Count_Overflow++;
}else{
Count_Overflow--;
}
Pre_Count_Encoder = Count_Encoder;
Count_Encoder = Count_Encoder*10 + FTM2->CNT;
FTM2->SC &= ~FTM_SC_TOF_MASK; // Clear timer overflow flag D9(TOF) is reset
}
PTA->PTOR &= 0x7FFF; //PTA11 is reset
}
I debuged it in Debug_RAM mode and found it cannot enter the overflow interrupt. So FTM2->CNT has no change. I also tried another interrupt FTM2_Ch0_Ch1_IRQHandler() but still cannot enter the interrupt. I was troubled by this issue for so long time.
Best,
Jianfei
Hi Diana,
Thanks for your patience and kind help. Finally I figured it out and found the FTM2 should be configured to work under debug mode as I would like to debug it under the debug_RAM mode. So the following code must be added.
FTM2->CONF = FTM_CONF_BDMMODE(3);
Under this way, the overflow interrrupt is set as follows:
Then, quadrature decoder works well and there is the same result as you attached. FTM2->CNT successfully changes.
But here I have one more question. I used overflowed interrupt (TOF) but you suggested reload interrupt (RF) with the code as follows:
Interestingly, the output results are the same. Can you explain why this happen ?
Hi Rong,
I'm very sorry for the delay. I'm glad that it works.
Actually I'm using TOIE - overflowed interrupt in this code. I'm using this code as a test code (it is not an official example) so, the clearing reload flag RF it's unnecessary. It should not be there. I'm sorry I confused you. There should be clearing TOF.
If you have the interest to know more about reload interrupt I recommend you to read sections in the RM rev 11:
45.5.29 Reload Points and 45.5.29.1 Reload Opportunities
Best Regards,
Diana
Hello Diana,
Thanks so much. The version I used is Arm V1.3. As you said, quadrature encoder is not availablel in Arm V1.3 ?
Best,
Jianfei