AnsweredAssumed Answered

GPIO interrupt lose count from quadrature decoder

Question asked by PETER SHIH on Oct 20, 2015
Latest reply on Nov 16, 2015 by Alice_Yang

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"); //    } //}

Outcomes