STM32F0 Tutorial 3 – Timers Pt1

On any microcontroller, timers are arguably one of the most useful peripherals, probably along with GPIO. What is a microcontroller without the ability to measure time reasonably accurately?!

Timers on the STM32 series of chips are quite complex and will be spread across multiple tutorials, each hopefully demonstrating one useful section of timers.

The tutorial today will simply be on setting up the timer and using its count value for something. I will be flashing the two on board LED’s with the pulse cycle time dependent on the timer and the pulse width dependent on a variable.

Most people generally use timers to create a constant timebase as a division of the clock frequency. The timers in the STM32 chips have much more functionality and can be used from triggering internal peripherals (such as the DAC) to creating PWM signals in hardware. In a future tutorial, I will explain how to set up a timer with a timer update interrupt, manually creating pulse a pulse width modulation source.

So onwards with the tutorial! If any of you have been reading any of my other tutorials, you will see that in my GPIO example, I explain how to set up a new project within CooCox (my IDE of choice and strongly recommended!). As I’ve explained it in the past, to save myself from explaining in every tutorial, that tutorial can be found at: GPIO Tutorial

Assuming you have now set up a blank project, the libraries required in this tutorial will be:

  • M0 Cmsis Core (Included when the RCC library is included)
  • CMSIS BOOT
  • RCC
  • GPIO
  • TIM

Libs
The standard repository of STM32 libraries

Once these libraries have been included, you can start with the coding!

As per usual, include the libraries you will be using in the main file.

#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_tim.h>

All three of these libraries are required to use the timer functionality on an STM32F0 chip.

Next, state all the definitions of the program, along with initializing the standard peripheral library structs.

//Define onboard LED’s
#define GreenLED GPIO_Pin_8
#define BlueLED GPIO_Pin_9
#define LEDGPIO GPIOC
#define LEDToggleValue ((uint16_t) 3000)

//Initialization structs
GPIO_InitTypeDef LEDs;
TIM_TimeBaseInitTypeDef TTB;

As per usual, I have defined the GPIO pins used for the onboard LED’s, along with the value that specifies the pulse width of the timer. Later on, you will see that LEDToggleValue is used to set the time that the green LED is on vs the blue LED out of a total value of 65535. With this value set to 3000, the green LED will be on (3000*100/65535 = 4.6)% of the time. The first struct GPIO_InitTypeDef LEDs is required to store all the information about the GPIO. TIM_TimeBaseInitTypeDef TTB is a structure which stores all the information about the timebase parameters of the timer. These timebase parameters set the speed that the timer runs at, along with the direction it counts to/from. In this example, the timer will be counting upwards from 0.

The code!

Now to the main code! In the main code, the system core clock is initialized, the clock to GPIOC is enabled, along with the clock for TIM1.

int main(void)
{
//Initialize system and ensure core clock is up to date
SystemInit();
          SystemCoreClockUpdate();

//Enable GPIO Clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

Next, the LED gpio is initialized, like in the first tutorial!

//Initialize LEDs
LEDs.GPIO_Pin = GreenLED | BlueLED;
LEDs.GPIO_Mode = GPIO_Mode_OUT;
LEDs.GPIO_OType = GPIO_OType_PP;
LEDs.GPIO_PuPd = GPIO_PuPd_NOPULL;
LEDs.GPIO_Speed = GPIO_Speed_Level_3;
GPIO_Init(LEDGPIO, &LEDs);

Both the blue and green LED’s are set as outputs. The above code uses the definitions found at the start of the file.

Now that the GPIO and clocks have been sorted, we can get on with setting up the fun stuff – The timer timebase!

A slight bit of maths is involved in calculating the speed at which the timer runs though its never too hard. The equation is:

TimerClock
——————                         = Timer frequency
((Prescalar – 1)*Period)

Using this, I can calculate how fast the LED’s are toggling.

The code to setting up the timebase of timer 1 is as follows:

//Initialize and enable timer to have a maximum period for 16bits
//running at a frequency of 48MHz/(65535*(1000 – 1)) = 0.732Hz
TTB.TIM_ClockDivision = TIM_CKD_DIV1;
TTB.TIM_CounterMode = TIM_CounterMode_Up;
TTB.TIM_Period = 0xFFFF;
TTB.TIM_Prescaler = 1000;
TTB.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TTB);
TIM_Cmd(TIM1, ENABLE);

So, as well as having a dedicated prescaler, the clock to the timer can be divided even more by setting the value for TTB.TIM_ClockDivision. In this example however, I’m setting this divider to 1. As stated earlier, the timer will be counting upwards, as set by: TTB.TIM_CounterMode = TIM_CounterMode_Up. The maximum period of all the timers is 65535 due to the 16bit limitation. The prescaler also is limited to 65535 as this is 16bits too. This therefore means that the slowest speed that the timer can update is 0.0026Hz (achieved by also setting the clock division to divide by 4). The timer parameters are initialized into the timer register using TIM_TimeBaseInit(TIM1, &TTB);. The timer is also started using TIM_Cmd(TIM1, ENABLE);. Subsequently, the timer can also be stopped by disabling it.

Along with the initialization of all hardware parameters, a variable is initialized to store the current count value of the timer:

uint16_t CurrentTimerVal = 0;

Now comes the main loop! Inside of this loop, the current timer count value is stored in the above variable. This variable is used as a comparison to the definition LEDToggleValue. If the timer count is less than this, the green LED will be active. If the timer count is more than this, the blue LED will be active. The code is:

while(1)
{
            //Store current timer value in variable
          CurrentTimerVal = TIM_GetCounter(TIM1);

//See if current timer value is more than LED toggle value
          if(CurrentTimerVal>LEDToggleValue){
                    GPIO_SetBits(LEDGPIO, GreenLED);
                    GPIO_ResetBits(LEDGPIO, BlueLED);
          }
          else{
                    GPIO_ResetBits(LEDGPIO, GreenLED);
                    GPIO_SetBits(LEDGPIO, BlueLED);
          }
}

If you’ve managed to compile this correctly, you should see the LED’s flashing with the blue LED being on significantly longer than the green LED. I’ll include a picture but as with most things, its quite hard to tell if its working because a photograph is static!

P1020413
STM32F0 discovery connected to my trusty breadboard! Ignore the wires below, they’re not related.

As you can see, setting up the timer as a constant timebase and using the count value is really easy to do and if you’ve managed to get this far, you’ll easily be able to use the timers to more functionality!

FCode
The final code! If you want to maximise your current window in CooCox, double click on the tab at the top. In this case, I double clicked main.c. To exit the fully windowed mode, just double click again!

And now for all the code:

#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_tim.h>

//Define onboard LED’s
#define GreenLED GPIO_Pin_8
#define BlueLED GPIO_Pin_9
#define LEDGPIO GPIOC
#define LEDToggleValue ((uint16_t) 3000)

//Initialization structs
GPIO_InitTypeDef LEDs;
TIM_TimeBaseInitTypeDef TTB;

int main(void)
{
//Initialize system and ensure core clock is up to date
          SystemInit();
          SystemCoreClockUpdate();

          //Enable GPIO Clock
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

          //Initialize LEDs
          LEDs.GPIO_Pin = GreenLED | BlueLED;
          LEDs.GPIO_Mode = GPIO_Mode_OUT;
          LEDs.GPIO_OType = GPIO_OType_PP;
          LEDs.GPIO_PuPd = GPIO_PuPd_NOPULL;
          LEDs.GPIO_Speed = GPIO_Speed_Level_3;
          GPIO_Init(LEDGPIO, &LEDs);

          //Initialize and enable timer to have a maximum period for 16bits
//running at a frequency of 48MHz/(65535*(1000 – 1)) = 0.732Hz
          TTB.TIM_ClockDivision = TIM_CKD_DIV1;
          TTB.TIM_CounterMode = TIM_CounterMode_Up;
          TTB.TIM_Period = 0xFFFF;
          TTB.TIM_Prescaler = 1000;
          TTB.TIM_RepetitionCounter = 0;
          TIM_TimeBaseInit(TIM1, &TTB);
          TIM_Cmd(TIM1, ENABLE);

          uint16_t CurrentTimerVal = 0;

          while(1)
          {
//Store current timer value in variable
                    CurrentTimerVal = TIM_GetCounter(TIM1);

                    //See if current timer value is more than LED toggle value
                    if(CurrentTimerVal>LEDToggleValue){
                              GPIO_SetBits(LEDGPIO, GreenLED);
                              GPIO_ResetBits(LEDGPIO, BlueLED);
                    }
                    else{
                              GPIO_ResetBits(LEDGPIO, GreenLED);
                              GPIO_SetBits(LEDGPIO, BlueLED);
                    }
          }
}

As with all my tutorials, this can be found on my github!

https://github.com/pyrohaz/STM32F0-Discovery-Timer-Tutorial1.git

Hope its been atleast a bit helpful. Enjoy STM32’s, they’re an exceptional micro 🙂

Advertisements

5 responses to “STM32F0 Tutorial 3 – Timers Pt1

    • Hi, I’m glad you like it! Some of my other blog posts include advanced timer functionality. I’d be more than happy to make another timer tutorial however! What kind of functionality are you looking for? 🙂

  1. I have just move from ATMEGA8 to STM32F0, so the timer of STM32 is complex when compare with ATMEGA.Can you make a full tutorial to use Advanced TIMER 1 of STM32F0, how to interrupt using TIM1 (upcounter, downcounter and center), how to make a PWM with it?

    • Yes and no! Depending on which timer you’re using, along with what speed your processor is running at, 1MHz can be generated by the timers easily, the problem comes with what you will be doing in your interrupt. 1Mhz leaves 48 cycles if your processor is running at 48MHz, where that includes entering the interrupt, executing your code, leaving the interrupt and restoring the stack! I can’t imagine you’d have much time to do much else. What would you be doing inside of the interrupt? Depending on your application, you might be able to use DMA to slacken your requirements (for example, collecting ADC samples).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s