en.radzio.dxp.pl

Lesson 3. Blinking with Timer.

As I wrote in lesson 1, this is not the best way to make a delay :

for(dly = 0; dly < 500000; dly++);

CPU wasting time to counting this loop, and aslo time of delay is hard to define. This kind of delay is maybe good for first program, but not for professional applications. So let's try blink LED with use one of STM32's timers. Look into section 13 of RM0041 document. This section describes general purpose timers TIM2 to TIM5. This timers are a 16-bit timer with 16-bit prescaler. Now, look into STM32F100RBT6 datasheet to section 3 "Pinouts an pin description". Look for PC8 and PC9 in table 4. As you see, this pin can be connected to channels 3 and 4 of timer TIM3. So let's use in this lesson timer TIM3 to blinking LEDs.

Make timer alive
First thing which we do is make timer counting. First of all, we need enable clock for timer TIM3 :

RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

Now, we can configure timer. Let's assume that we want change state of LED each one second. How to do it? You must know input frequency which clocking the timer. Now, look into file system_stm32f10x.c at fragment :

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif

As we use Medium Density Value Line microcontroller (MD_VL) we have two options of System Core Clock : equal to HSE (High Speed External source) and 24 MHz. Default value in file is SYSCLK_FREQ_24MHz. Based on this macrodefinition, functions from file system_stm32f10x.c will configure clock system of microcontroller to achieve 24MHz system core clock. So our system frequency is 24MHz. Same frequency clock all peripherals, including timer TIM3. But, how our timer works? In simplest mode timer is counting from 0 to value stored in ARR register, then count again form 0 to ARR. When couter value is equal to ARR the UIF flag in SR register is set.

How count one second with this timer? 24MHz of clock give us about 41 nanoseconds of one timer tick. So our timer should count 24 milion times to measure one second. But timer is only 16-bits with 16-bits prescaler. Almost like 32-bit timer, but with some limitations. If we don't need high timer resolution we can prescale timer clock, by 24 000 and counting elapsing miliseconds. One second is 1000 miliseconds, so look at code :

TIM3->PSC = 23999;      // Set prescaler to 24 000 (PSC + 1)
TIM3->ARR = 1000;       // Auto reload value 1000
TIM3->CR1 = TIM_CR1_CEN;// Enable timer

This is the simplest timer configuration. We set prescaler to 24k (remember - prescaler is PSC + 1) and auto reload register to 1000. Next, we enable the timer. From now, timer should be counting. When timer achieve ARR value, the UIF flag will be set. So now we need chceck this flag value, and toggle LED state, when flag is set (counter count to 1000). Code for check flag and toggle LED :

if(TIM3->SR & TIM_SR_UIF)
  {
  TIM3->SR &= ~TIM_SR_UIF;
  LED_BLUE_GPIO->ODR ^= (1 << LED_BLUE_PIN);
  }

But when chceck this flag? Now, we check this flag in endless loop :

while (1) {
if(TIM3->SR & TIM_SR_UIF)
  {
  TIM3->SR &= ~TIM_SR_UIF;
  LED_BLUE_GPIO->ODR ^= (1 << LED_BLUE_PIN);
  }
}

Of course, this is not the best way to do this, but at this moment try this. Complete source code :

//=============================================================================
// STM32VLDISCOVERY tutorial
// Lesson 3. Blinking with timer.
// Copyright : Radoslaw Kwiecien
// http://en.radzio.dxp.pl
// e-mail : radek(at)dxp.pl
//=============================================================================
#include "stm32f10x.h"
#include "antilib_gpio.h"
//=============================================================================
// Defines
//=============================================================================
#define LED_BLUE_GPIO GPIOC
#define LED_BLUE_PIN  8
//=============================================================================
// main function
//=============================================================================
int main(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

#if (LED_BLUE_PIN > 7)
  LED_BLUE_GPIO->CRH = (LED_BLUE_GPIO->CRH & CONFMASKH(LED_BLUE_PIN)) | GPIOPINCONFH(LED_BLUE_PIN,     GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_OUTPUT_PUSHPULL));
#else
  LED_BLUE_GPIO->CRL = (LED_BLUE_GPIO->CRL & CONFMASKL(LED_BLUE_PIN)) | GPIOPINCONFL(LED_BLUE_PIN,     GPIOCONF(GPIO_MODE_OUTPUT2MHz, GPIO_CNF_OUTPUT_PUSHPULL));
#endif

TIM3->PSC = 23999;      // Set prescaler to 24 000 (PSC + 1)
TIM3->ARR = 1000;       // Auto reload value 1000
TIM3->CR1 = TIM_CR1_CEN;// Enable timer

while (1) {
if(TIM3->SR & TIM_SR_UIF) // if UIF flag is set
  {
  TIM3->SR &= ~TIM_SR_UIF; // clear UIF flag
  LED_BLUE_GPIO->ODR ^= (1 << LED_BLUE_PIN); // toggle LED state
  }
}
}
//=============================================================================
// End of file
//=============================================================================

After flashing STM32VLDISCOVERY board blue LED should be change thier state each every second. As I wrote - this is not the best way to use timer. The better way are interrupts, described in next lesson.

 

 
(c) Radosław Kwiecień