cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L010C6 TIM2 IRQ Priority, Over capture Vs edge detection, classic timer issue

SandMan
Associate II

So I want to use a capture compare to measure an input frequency 0.1Hz to 100kHz. Peripheral clock is set to 32MHz to cover full range and maximise speed of calculations. At lower frequency I have to count the number of times the over capture call-back is called, to put into the calculation. However there are a few frequencies where the over capture and edge detection IRQs have a beating effect, I have delt with this on other processors by ensuring the order IRQs are delt with but it doesn't seem to be working here.
Sometimes the last over capture is called first, other times in is not, leading to a large jump in my calculated result. As anyone any experience with this issue on the STM32 TIM peripherals?

/******************************************************************************
        Function : Calculate_Frequency
        Return : Frequency post calculation as a float
*****************************************************************************/
#define TIMCLOCK 32000000.00 //System clock value post PLL
#define PRESCALAR 1

unsigned int Pending_Result;
unsigned int Frequency_Counter_Overflow;
unsigned int IC_Val1_OFC;
unsigned int IC_Val2_OFC;
unsigned int Overflow_Difference;
unsigned int Last_Overflow_Count;

unsigned int IC_Val1;
unsigned int IC_Val2;

unsigned int Difference;

unsigned int IC_Val1_Array[8];
unsigned int IC_Val2_Array[8];
unsigned int Difference_Array[8];
unsigned int frequency_Array[8];
unsigned int Sum_Array[8];
unsigned int Overflow_Difference_Array[8];
unsigned int IC_Val1_OFC_Array[8];
unsigned int IC_Val2_OFC_Array[8];
unsigned int x;
unsigned int Sum_Used;

float frequency;

//This table removes the need for a multiplication, speeding up the capture to output time.
unsigned long Overflow_Lookup[256] = {
0, 65535, 131070, 196605, 262140, 327675, 393210, 458745, 524280, 589815, 655350,
720885, 786420, 851955, 917490, 983025, 1048560, 1114095, 1179630, 1245165, 1310700,
1376235, 1441770, 1507305, 1572840, 1638375, 1703910, 1769445, 1834980, 1900515, 1966050,
2031585, 2097120, 2162655, 2228190, 2293725, 2359260, 2424795, 2490330, 2555865, 2621400,
2686935, 2752470, 2818005, 2883540, 2949075, 3014610, 3080145, 3145680, 3211215, 3276750,
3342285, 3407820, 3473355, 3538890, 3604425, 3669960, 3735495, 3801030, 3866565, 3932100,
3997635, 4063170, 4128705, 4194240, 4259775, 4325310, 4390845, 4456380, 4521915, 4587450,
4652985, 4718520, 4784055, 4849590, 4915125, 4980660, 5046195, 5111730, 5177265, 5242800,
5308335, 5373870, 5439405, 5504940, 5570475, 5636010, 5701545, 5767080, 5832615, 5898150,
5963685, 6029220, 6094755, 6160290, 6225825, 6291360, 6356895, 6422430, 6487965, 6553500,
6619035, 6684570, 6750105, 6815640, 6881175, 6946710, 7012245, 7077780, 7143315, 7208850,
7274385, 7339920, 7405455, 7470990, 7536525, 7602060, 7667595, 7733130, 7798665, 7864200,
7929735, 7995270, 8060805, 8126340, 8191875, 8257410, 8322945, 8388480, 8454015, 8519550,
8585085, 8650620, 8716155, 8781690, 8847225, 8912760, 8978295, 9043830, 9109365, 9174900,
9240435, 9305970, 9371505, 9437040, 9502575, 9568110, 9633645, 9699180, 9764715, 9830250,
9895785, 9961320, 10026855, 10092390, 10157925, 10223460, 10288995, 10354530, 10420065,
10485600, 10551135, 10616670, 10682205, 10747740, 10813275, 10878810, 10944345, 11009880,
11075415, 11140950, 11206485, 11272020, 11337555, 11403090, 11468625, 11534160, 11599695,
11665230, 11730765, 11796300, 11861835, 11927370, 11992905, 12058440, 12123975, 12189510,
12255045, 12320580, 12386115, 12451650, 12517185, 12582720, 12648255, 12713790, 12779325,
12844860, 12910395, 12975930, 13041465, 13107000, 13172535, 13238070, 13303605, 13369140,
13434675, 13500210, 13565745, 13631280, 13696815, 13762350, 13827885, 13893420, 13958955,
14024490, 14090025, 14155560, 14221095, 14286630, 14352165, 14417700, 14483235, 14548770,
14614305, 14679840, 14745375, 14810910, 14876445, 14941980, 15007515, 15073050, 15138585,
15204120, 15269655, 15335190, 15400725, 15466260, 15531795, 15597330, 15662865, 15728400,
15793935, 15859470, 15925005, 15990540, 16056075, 16121610, 16187145, 16252680, 16318215,
16383750, 16449285, 16514820, 16580355, 16645890, 16711425};

float Calculate_Frequency (void)
{
    if (Pending_Result == 1)
    {
        Overflow_Difference = (IC_Val2_OFC - IC_Val1_OFC); //work out how many periods have passed between edges

        if (Overflow_Difference > 255) //it's a very slow frequency so we can work it out
        {
            if (IC_Val2 > IC_Val1) //no interim period to deal with
            {
                Difference = (Overflow_Difference * 0xFFFF) + (IC_Val2 - IC_Val1); //(total passed periods * full period count) + (second edge time - first edge time)
            }
            else if (IC_Val1 > IC_Val2) //interim period to deal with
            {
                Difference = (((Overflow_Difference) * 0xFFFF) - IC_Val1) + IC_Val2; //((total passed periods * full period count) - first edge time[interim]) + second edge time
            }
        }
        else
        {

            if (IC_Val2 > IC_Val1) //no interim period to deal with
            {
                Difference = Overflow_Lookup[Overflow_Difference] + (IC_Val2 - IC_Val1); //(total passed periods * full period count) + (second edge time - first edge time)
                Sum_Used = 1;
            }
            else if (IC_Val1 > IC_Val2) //interim period to deal with
            {
                Difference = (Overflow_Lookup[Overflow_Difference] - IC_Val1) + IC_Val2; //((total passed periods * full period count) - first edge time[interim]) + second edge time
                Sum_Used = 2;
            }
        }

        Frequency_Counter_Overflow = 0; //reset the period counter
        __HAL_TIM_SET_COUNTER(&htim2, 0);  // reset the counter
        TIM2->SR &= ~TIM_SR_UIF; //clear the global IRQ flag, before re-enabling the IRQs
         TIM2->SR = ~(TIM_SR_CC1OF | TIM_SR_TIF); // Clear the bitwise flags
        __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1); //restart IRQ now calculations are complete
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
        frequency = TIMCLOCK/Difference;

        Last_Overflow_Count = Overflow_Difference;
        Pending_Result = 0;  //clear the flag that a result is awaiting processing

        //Bug trap code ----------------------------------------------------------------
        IC_Val1_Array[x] = IC_Val1;
        IC_Val2_Array[x] = IC_Val2;
        Difference_Array[x] = Difference;
        frequency_Array[x] = frequency;
        Sum_Array[x] = Sum_Used;
        Overflow_Difference_Array[x] = Overflow_Difference;
        IC_Val1_OFC_Array[x] = IC_Val1_OFC;
        IC_Val2_OFC_Array[x] = IC_Val2_OFC;
        x++;
        if (x>7)
        {
            x=0;
        }
        //Bug trap code end -------------------------------------------------------------

        return (frequency);
    }
    else
    {
        if (Frequency_Counter_Overflow >= (Last_Overflow_Count + 250))
        {
            return(200000); //dummy value to show no calculation as been done, but enough time as passed that there is no valid signal
        }
        else
        {
            return(300000); //dummy value to show no calculation as been done
        }
    }
}

 

/******************************************************************************
        ISR : Input Capture Callback
 *****************************************************************************/
unsigned int Is_First_Captured;
unsigned int Miss_Intrim_Edge;

extern unsigned int Both_Edges;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (Pending_Result == 0)  //there is not already a result awaiting processing
    {
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
        {
            if (Is_First_Captured==0) // if the first edge is not captured
            {
                IC_Val1_OFC = Frequency_Counter_Overflow; //record the period in which this edge occurred
                IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // read the first value
                Is_First_Captured = 1;  // set the first captured as true
            }
            else if ((Both_Edges == 1) && (Miss_Intrim_Edge == 0)) //miss the alternate edge, in all edges mode
            {
                Miss_Intrim_Edge = 1;
            }

            else if ((Both_Edges == 0) || (Miss_Intrim_Edge == 1)) // If the first edge is captured, now we will capture the second edge
            {
                IC_Val2_OFC = Frequency_Counter_Overflow; //record the period in which this edge occurred
                IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  // read second value
                Is_First_Captured = 0; // set it back to false
                Miss_Intrim_Edge = 0; // set it back to false
                Pending_Result = 1;  //set flag that a result calculation is required
                __HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1); //stop IRQ to maximise calculation time
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
            }
        }
    }
}

/******************************************************************************
        ISR : Input Capture overflow
 *****************************************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    Frequency_Counter_Overflow ++;  //a full timer period as passed, increment the period counter
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
}
4 REPLIES 4
SandMan
Associate II
TDK
Super User

If your timer frequency is 32 MHz, using a 32-bit timer is sufficient to capture 0.1 Hz without overflow.

You can do it with a 16-bit timer but you'll run into race conditions if not done right.

If you feel a post has answered your question, please click "Accept as Solution".

Thank you TDK, unfortunately the L0 series part only has 16 bit timers. 

It is the race condition that is causing my issue, I have had this on other uC in the past but making sure the over capture flag in tested first normally fixes the issue, but not this time. 

Francois VILMAIN
ST Employee

Hello,

If there is no timer instance supporting a 32 bit counter on your STM32L0 MCU, you can still chain 2 timers to increase the frequency range of your frequency measure and avoid to have to deal with capture overflows. To do so you can refer to the section 16.3.3 of the reference manual (RM0377). For instance, if TIM2 is configured in external clock mode 1, TIM3 TRGO can be used to feed the TIM2 counter through ITR2 interconnect.