-1

I created a program on STM8S103F3 to generate a delay in rage of micro seconds using TIM2 module, but the timer is not ticking as expected and when I tried to call 5 sec delay using it, it is giving around 3 sec delay. I'm using 16MHz HSI oscillator and timer pre-scalar is set to 16. please see my code below. Please help me to figure out what is wrong with my code.

void clock_setup(void)
{
       CLK_DeInit();
       CLK_HSECmd(DISABLE);
       CLK_LSICmd(DISABLE);
       CLK_HSICmd(ENABLE);
       while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
       CLK_ClockSwitchCmd(ENABLE);
       CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
       CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
       CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
                            DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
}

void delay_us(uint16_t us)
{
    volatile uint16_t temp;
    TIM2_DeInit(); 
    TIM2_TimeBaseInit(TIM2_PRESCALER_16, 2000); //Prescalar value 8,Timer clock 2MHz
    TIM2_Cmd(ENABLE);  
    do{
        temp = TIM2_GetCounter();
    }while(temp < us);
    TIM2_ClearFlag(TIM2_FLAG_UPDATE);
    TIM2_Cmd(DISABLE); 
} 

void delay_ms(uint16_t ms)
{
    while(ms--)
    {
        //delay_us(1000);
        delay_us(1000);
    }
}
rahul_T_T
  • 133
  • 9
  • 1
    TIM2 is a 16 bit wide timer. Your count time seems to be 1us according to your config. With this configuration you cannot generate a delay larger than (2^16 x 1us) which is 65536 milliseconds. Instead of reading timer in do-while loop, just check whether it overflowed or not and then use its time base in order to achive good delay results. In this case your timebase is 65536 ms which is very large. You better to setup the timer so that it overflows every 1 ms to produce a 1ms time base. Then you construct your delays on top of this time base. This will make more sense. – Kozmotronik Dec 25 '20 at 14:47
  • Not that you cannot use my suggestion for the delays that lesser than 1 ms. – Kozmotronik Dec 25 '20 at 14:48
  • Hi @Kozmotronik, that is the problem. I want to create minimum 16uS delay. – rahul_T_T Dec 25 '20 at 17:52

1 Answers1

1

It is better to use a 10us time base to round the delays. Well in order to achive a 10us timebase, if you use 16MHz master clock and you prescale TIM2 by 16, then you get a 1 us increment time, right? But we want TIM2 to overflow to generate an event named 16us event. Since we know that the timer will increment every 1us, if we use a reload value 65536 - 10 = 65526, this will give us a 10us overflow hence, 10us time base. If we are ok until here in delay code we'll just check the TIM2 update flag to know whther it has overflowed or not. See the example code snippet below.

// Set up it once since our time base is a fixed 10us
void setupTIM2(){
    TIM2_DeInit(); 
    TIM2_TimeBaseInit(TIM2_PRESCALER_16, 65526); //Prescalar value 16,Timer clock 1MHz
}

void delay_us(uint16_t us)
{
    volatile uint16_t temp;
    
    TIM2_Cmd(ENABLE);
    const uint16_t count = us / 10; //Get the required counts for 10us time base
    // Loop until the temp reaches the required count value
    do{
        while(TIM2_GetFlagStatus(TIM2_FLAG_UPDATE) == RESET); //Wait for the TIM2 to overflow
        TIM2_ClearFlag(TIM2_FLAG_UPDATE); // Clear the overflow flag
        temp++;
    } while(temp < count);
    
    TIM2_Cmd(DISABLE); 
} 

void delay_ms(uint16_t ms)
{
    while(ms--)
    {
        //delay_us(1000);
        delay_us(1000);
    }
}

void main(void){
    ...
    setupTIM2();
    ...
    delay_ms(5000);
}
Kozmotronik
  • 2,080
  • 3
  • 10
  • 25