This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Timer accuracy

Hello,
I configured a timer to generate a signal every 1 ms.

See below my code about the timer:

TIM_DeInit(TIMx);  // TIM1 Deinitialization *
TIM_InitStructure.TIM_Mode                       = TIM_OCM_CHANNEL_1;
TIM_InitStructure.TIM_OC1_Modes          = TIM_TIMING;
TIM_InitStructure.TIM_Clock_Source       = TIM_CLK_APB;
TIM_InitStructure.TIM_Clock_Edge         = TIM_CLK_EDGE_FALLING;
TIM_InitStructure.TIM_Prescaler          = 0xEF; // period = 5us
TIM_InitStructure.TIM_Pulse_Length_1 = 0xC8; // cycle of 200 period => cycle = 1ms
TIM_Init (TIMx, &TIM_InitStructure);

And the statements inside timer's interrupt:

void TIM1_IRQHandler(void)
{
        // port 3 pin 7 activated
        P37_1;
        // ACK interrupt
        TIM_ClearFlag(TIM1, TIM_FLAG_OC1);      // clear Output Compare 1 flag
        TIM_CounterCmd(TIM1, TIM_CLEAR);        // Reset TIM1 Counter
    VIC0->VAR = 0xFF;                                        // write any value to VIC0 VAR
}

BUT my oscilloscope measured a period of 1.03 ms instead of the 1ms expected.
Normally to generate a pulse every 1.03 ms the TIM_Pulse_Length_1 should be set to 0xCE.
As you can see, the difference between 0xCE and 0xC8 is big.

What can be the cause of this timer's inaccuracy ?
> Problem in PLL configuration ?
> Problem of crystal ?
> Problem in timer configuration ?

Has someone the same problem ?
In advance, thank you

Parents
  • Hi everybody,
    We found a solution. We wanted to have an interruption every 1ms and now we measure 1.001 ms (because of the resolution of our oscillo) !
    What we did:
    - We use FIQ (fast interrupt) instead of classical interrupt (IRQ)
    - We acces directly registers (we stop to use ST library)
    - We reset the timer first !, after we clear the interrupt flag and we activate the flag to toggle a LED in the main loop

    BAD:

     void TIM1_IRQHandler(void)
    {
            P37_1;                                                                  // activate LED on Port 3 pin 1
            // ACK interrupt
            TIM_ClearFlag(TIM1, TIM_FLAG_OC1);      // clear Output Compare 1 flag
            TIM_CounterCmd(TIM1, TIM_CLEAR);        // Reset TIM1 Counter
        VIC0->VAR = 0xFF;                       // write any value to VIC0 VAR
    }
    


    GOOD:

    void FIQ_Handler(void)
    {
            // ACK interrupt
            TIM1->CNTR = 0x1234;                         // Reset TIM1 Counter
            TIM1->SR &= ~TIM_FLAG_OC1;                       // clear Interrupt Output Compare 1
            counter_ms++;                                           // use to toggle a LED in the main loop
    }
    

Reply
  • Hi everybody,
    We found a solution. We wanted to have an interruption every 1ms and now we measure 1.001 ms (because of the resolution of our oscillo) !
    What we did:
    - We use FIQ (fast interrupt) instead of classical interrupt (IRQ)
    - We acces directly registers (we stop to use ST library)
    - We reset the timer first !, after we clear the interrupt flag and we activate the flag to toggle a LED in the main loop

    BAD:

     void TIM1_IRQHandler(void)
    {
            P37_1;                                                                  // activate LED on Port 3 pin 1
            // ACK interrupt
            TIM_ClearFlag(TIM1, TIM_FLAG_OC1);      // clear Output Compare 1 flag
            TIM_CounterCmd(TIM1, TIM_CLEAR);        // Reset TIM1 Counter
        VIC0->VAR = 0xFF;                       // write any value to VIC0 VAR
    }
    


    GOOD:

    void FIQ_Handler(void)
    {
            // ACK interrupt
            TIM1->CNTR = 0x1234;                         // Reset TIM1 Counter
            TIM1->SR &= ~TIM_FLAG_OC1;                       // clear Interrupt Output Compare 1
            counter_ms++;                                           // use to toggle a LED in the main loop
    }
    

Children