Hi :
I am working on a custom board equipped with K66 MCU, three quadrature decoders and other peripherals. Since three quadrature decoders, I am going to utilized FTM1, and 2 for two devices, and general gpio interrupt for the other. The software development is based on KDS3.0 and KSDK1.2. The first thing I would like to do is verifying the integrity of GPIO interrupt from encoder. I basically jump the FTM1_QD_PHA and FTM1_QD_PHB signals to PTE8, and PTE9, and a motor encoder signal connects to FTM1. Therefore, the same encoder signal should feed to both FTM1 and GPIO port E. When I test it with bare board and SDK platform only, the had pretty match count from both decoder. This gives me confirmation that FTM and GPIO interrupt and decoder algorithm are running OK. However, if I have similar code and utilize SDK with MQX, I am facing lose count on GPIO interrupt. For example I ran the motor about 3 seconds (the encoder signals tick in at 6.64kHz, 150us period), the FTM reads 61438 count, but GPIO interrupt counts 60967. I am wondering if I miss something, or this is drawback of utilizing MQX. Does MQX take lots of CPU resource that cause losing interrupt? If you have any idea or recommendation please let me know. Thank you very much.
main.c without MQX
// Standard C Included Files #include <stdio.h> // SDK Included Files #include "board.h" #include "gpio_pins.h" #include "fsl_debug_console.h" #include "fsl_device_registers.h" #include "fsl_ftm_driver.h" #include "fsl_ftm_hal.h" //----------------------------------------------------------------------- // Function Prototypes //----------------------------------------------------------------------- void gpio_Init(void); void encoderX_Init(void); void encoderZ_Init(void); void FlexTimer1_IRQHandler(void); uint8_t ScanEcn(uint8_t InputAB, uint8_t PreviousStateAB, int64_t *EncCnt); void BOARD_ENCZ_IRQ_HANDLER(void); int64_t GetEncXCnt(void); //----------------------------------------------------------------------- // Constants //----------------------------------------------------------------------- #define ENCX_OVERFLOW 4000 //1000 CPR(cycle/rev) #define ENCY_OVERFLOW 4000 //1000 CPR(cycle/rev) //----------------------------------------------------------------------- // Typedefs //----------------------------------------------------------------------- //----------------------------------------------------------------------- // Global Variables //----------------------------------------------------------------------- int64_t EncXOF = 0; int64_t PosX = 0; int64_t PosZ = 0; int64_t PosXPV = 0; int64_t PosZPV = 0; volatile uint8_t stateOld = 0; //----------------------------------------------------------------------- // Main Function //----------------------------------------------------------------------- int main(void) { /* Write your code here */ // Init hardware hardware_init(); dbg_uart_init(); PRINTF("\r\n\nRunning QEncIntTest example."); gpio_Init(); encoderX_Init(); encoderZ_Init(); PosXPV = GetEncXCnt(); PosXPV = PosZPV = PosZ; /* This for loop should be replaced. By default this loop allows a single stepping. */ for (;;) { PosX = GetEncXCnt(); if (PosX != PosXPV || PosZ != PosZPV) { PRINTF("\r\nPosX = %ld, PosZ = %ld", (int32_t)PosX, (int32_t)PosZ); PosXPV = PosX; PosZPV = PosZ; } } /* Never leave main */ return 0; } void gpio_Init(void) { gpio_output_pin_user_config_t outputPinConfig; outputPinConfig.pinName = kGpioE0; outputPinConfig.config.outputLogic = 0; outputPinConfig.config.slewRate = kPortSlowSlewRate; outputPinConfig.config.isOpenDrainEnabled = false; outputPinConfig.config.driveStrength = kPortLowDriveStrength; GPIO_DRV_OutputPinInit(&outputPinConfig); } void encoderX_Init(void) { FTM_Type *ftmBase; // Configure FTM1,2 encoder pins ftmBase = g_ftmBase[BOARD_ENCX_FTM_INSTANCE]; configure_ftm_pins(BOARD_ENCX_FTM_INSTANCE); ftm_user_config_t flexTimer1_InitConfig0 = { .tofFrequency = 0U, .isWriteProtection = false, // Disable write protection .BDMMode = kFtmBdmMode_11, .syncMethod = kFtmUseSoftwareTrig }; FTM_DRV_Init(BOARD_ENCX_FTM_INSTANCE,&flexTimer1_InitConfig0); FTM_HAL_SetMod(ftmBase, ENCX_OVERFLOW-1); FTM_HAL_SetCounterInitVal(ftmBase, 0); FTM_DRV_SetClock(BOARD_ENCX_FTM_INSTANCE, kClock_source_FTM_SystemClk, kFtmDividedBy1); //start the timer clock, source is the the phase A and B input signals ftm_phase_params_t flexTimer1_QdConfig0 = { .kFtmPhaseInputFilter = false, .kFtmPhaseFilterVal = 0U, .kFtmPhasePolarity = kFtmQuadPhaseNormal, }; FTM_DRV_QuadDecodeStart(BOARD_ENCX_FTM_INSTANCE, &flexTimer1_QdConfig0, &flexTimer1_QdConfig0, kFtmQuadPhaseEncode); FTM_DRV_SetTimeOverflowIntCmd(BOARD_ENCX_FTM_INSTANCE,true); FTM_DRV_SetFaultIntCmd(BOARD_ENCX_FTM_INSTANCE,false); } void encoderZ_Init(void) { GPIO_DRV_Init(encoderZPins, NULL); //configure QD_PHB and QD_PHB signal } /* FTM1 IRQ handler that would cover the same name's APIs in startup code. */ extern void FTM_DRV_IRQHandler(uint32_t instance); void FTM1_IRQHandler(void) { if((FTM1_QDCTRL & FTM_QDCTRL_TOFDIR_MASK) == 0) EncXOF--; else EncXOF++; FTM_DRV_IRQHandler(1); } uint8_t ScanEcn(uint8_t InputAB, uint8_t PreviousStateAB, int64_t *EncCnt) { switch (PreviousStateAB){ case 0x0: if(InputAB == 0x1){ (*EncCnt)++; }else if(InputAB == 0x2){ (*EncCnt)--; } break; case 0x1: if(InputAB == 0x0){ (*EncCnt)--; }else if(InputAB == 0x3){ (*EncCnt)++; } break; case 0x2: if(InputAB == 0x0){ (*EncCnt)++; }else if(InputAB == 0x3){ (*EncCnt)--; } break; case 0x3: if(InputAB == 0x1){ (*EncCnt)--; }else if(InputAB == 0x2){ (*EncCnt)++; } break; default: break; } return InputAB; } /* PORTE IRQ handler that would cover the same name's APIs in startup code. */ void PORTE_IRQHandler(void) { uint8_t state; if (PORTE_PCR8 & PORT_PCR_ISF_MASK) { //interrupt on A changing state PORTE_PCR8 |= PORT_PCR_ISF_MASK; // clear the flag state = (uint8_t)((GPIOE_PDIR & 0x00000300) >> 8); stateOld = ScanEcn(state, stateOld, &PosZ); } if (PORTE_PCR9 & PORT_PCR_ISF_MASK) { //interrupt on B changing state PORTE_PCR9 |= PORT_PCR_ISF_MASK; // clear the flag state = (uint8_t)((GPIOE_PDIR & 0x00000300) >> 8); stateOld = ScanEcn(state, stateOld, &PosZ); } } int64_t GetEncXCnt(void) { return ((ENCX_OVERFLOW * EncXOF) + FTM1_CNT); }
main.c without MQX
//----------------------------------------------------------------------- // Standard C/C++ Includes //----------------------------------------------------------------------- #include <stdio.h> #include "main.h" void main_task(uint32_t param); void task_example(task_param_t param); void gpio_Init(void); void encoderX_Init(void); void encoderZ_Init(void); void FlexTimer1_IRQHandler(void); uint8_t ScanEcn(uint8_t InputAB, uint8_t PreviousStateAB, int64_t *EncCnt); void BOARD_ENCZ_IRQ_HANDLER(void); int64_t GetEncXCnt(void); //----------------------------------------------------------------------- // Constants //----------------------------------------------------------------------- #define MAIN_TASK 8U const TASK_TEMPLATE_STRUCT MQX_template_list[] = { { MAIN_TASK, main_task, 0xC00, 20, "main_task", MQX_AUTO_START_TASK}, { 0L, 0L, 0L, 0L, 0L, 0L } }; #define TASK_EXAMPLE_PRIO 6U #define TASK_EXAMPLE_STACK_SIZE 1024U #define ENCX_OVERFLOW 4000 //1000 CPR(cycle/rev) #define ENCY_OVERFLOW 4000 //1000 CPR(cycle/rev) //----------------------------------------------------------------------- // Global Variables //----------------------------------------------------------------------- int64_t EncXOF = 0; int64_t PosX = 0; int64_t PosZ = 0; int64_t PosXPV = 0; int64_t PosZPV = 0; volatile uint8_t stateOld = 0; //----------------------------------------------------------------------- // Macros //----------------------------------------------------------------------- OSA_TASK_DEFINE(task_example, TASK_EXAMPLE_STACK_SIZE); //----------------------------------------------------------------------- // Main Function //----------------------------------------------------------------------- void main_task(uint32_t param) { osa_status_t result = kStatus_OSA_Error; printf("\n\nRunning the KSDK_1_2_0_PCB58852 project."); gpio_Init(); encoderX_Init(); encoderZ_Init(); PosXPV = GetEncXCnt(); PosZ = PosXPV; PosZPV = PosXPV; // OSA_Init(); // result = OSA_TaskCreate(task_example, // (uint8_t *)"example", // TASK_EXAMPLE_STACK_SIZE, // task_example_stack, // TASK_EXAMPLE_PRIO, // (task_param_t)0, // false, // &task_example_task_handler); // if (result != kStatus_OSA_Success) // { // printf("Failed to create example task\r\n"); // return; // } // OSA_Start(); for (;;) // Forever loop { PosX = GetEncXCnt(); if (PosX != PosXPV || PosZ != PosZPV) { printf("\nPosX = %ld, PosZ = %ld", (int32_t)PosX, (int32_t)PosZ); PosXPV = PosX; PosZPV = PosZ; } OSA_TimeDelay(100); //500ms delay } } //----------------------------------------------------------------------- // Task Functions //----------------------------------------------------------------------- // //void task_example(task_param_t param) //{ // printf("\r\nHellow World.\r\n"); // // while(1) // { // __asm("NOP"); // } //}