Continuing the STM8 Expedition

STM8S105 Discovery

Creating Delays using Basic Timer

Rather than using loops of no operation instructions, it is wiser to use an unused or free timer to create software delays. It will be both accurate and precise. It can be done with any timer but using a basic timer will be a smart move because basic timers are usually for timebase generation purposes.

Hardware Connection

CubeMX

Code Example

 #include "STM8S.h"


void clock_setup(void);
void GPIO_setup(void);
void delay_us(signed int us);
void delay_ms(signed int ms);


void main(void)
{
       clock_setup();
       GPIO_setup();

       while(TRUE)
       {
              GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
              delay_ms(400);
       };
}


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);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);
}


void GPIO_setup(void)
{
       GPIO_DeInit(GPIOD);
       GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_OD_HIZ_SLOW);
}


void delay_us(signed int us)
{
       TIM4_DeInit();     

       if((us <= 200) && (us >= 0))
       {
              TIM4_TimeBaseInit(TIM4_PRESCALER_16, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 400) && (us > 200))
       {
              us >>= 1;
              TIM4_TimeBaseInit(TIM4_PRESCALER_32, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 800) && (us > 400))
       {
              us >>= 2;
              TIM4_TimeBaseInit(TIM4_PRESCALER_64, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 1600) && (us > 800))
       {
              us >>= 3;
              TIM4_TimeBaseInit(TIM4_PRESCALER_128, 200);
              TIM4_Cmd(ENABLE);  
       }
       while(TIM4_GetCounter() < us);
       TIM4_ClearFlag(TIM4_FLAG_UPDATE);
       TIM4_Cmd(DISABLE);    
}


void delay_ms(signed int ms)
{
       while(ms--)
       {
              delay_us(1000);
       };
}

 

Explanation

The very first important things to decide and note are the clock speeds of peripherals and CPU. Here both are set to 16MHz. Secondly, TIM4 is use to create software delays and so it should be clocked.

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_TIMER4, ENABLE);

The smallest unit of time that we usually use in microcontroller coding is microseconds and so it should be coded first:

void delay_us(signed int us)
{
       TIM4_DeInit();     

       if((us <= 200) && (us >= 0))
       {
              TIM4_TimeBaseInit(TIM4_PRESCALER_16, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 400) && (us > 200))
       {
              us >>= 1;
              TIM4_TimeBaseInit(TIM4_PRESCALER_32, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 800) && (us > 400))
       {
              us >>= 2;
              TIM4_TimeBaseInit(TIM4_PRESCALER_64, 200);
              TIM4_Cmd(ENABLE);  
       }
       else if((us <= 1600) && (us > 800))
       {
              us >>= 3;
              TIM4_TimeBaseInit(TIM4_PRESCALER_128, 200);
              TIM4_Cmd(ENABLE);  
       }
       while(TIM4_GetCounter() < us);
       TIM4_ClearFlag(TIM4_FLAG_UPDATE);
       TIM4_Cmd(DISABLE);    

}

TIM4 is deinitialized first. The input or argument to the delay_us function is the amount of time in microseconds we wish to delay. TIM4 is an 8-bit timer and so it can count up to 255. For simplicity, the count has been limited to 200. The first if-else conditional statement will configure the timer for periods from 0 to 200 microseconds. Input clock to the timer is prescaled by 16 and so it has a input clock frequency of 1MHz or 1 microsecond tick interval. In the while loop at the bottom of the function, TIM4’s counter count is checked against the variable us. The loop breaks when the counter exceeds the variable’s value, creating a software delay. For bigger delays, the other conditional statements are used.

For more bigger delays, delay milliseconds (delay_ms) function is used. This function loops calls of a thousand microseconds.

void delay_ms(signed int ms)
{
       while(ms--)
       {
              delay_us(1000);
       };
}

The demo here is just a simple LED blinker.

Demo

Software Delay

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *