Creating delay using Timer and configuring RCC clock | STM32F103C8T6 | Arm Cortex M3

STM32F103C8T6 - To get started with this ARM board, refer this post
In STM32F103C8T6 only 4 Timers are available, refer datasheet for more details

For creating delay, let use a general purpose - Timer 2. But before configuring the timer lets set the system clock source to get a desired peripheral clock frequency by configuring RCC registers.
Below diagram shows the whole clock picture:


After reset, HSI will be selected as the system clock by default. To change it configure RCC registers.
Note: If Keil startup code is used, it will change the system clock to HSE and frequency to 72 MHz
in SystemInit(). To set your own clock, disable the following:


RCC settings to set SysClk = HSE (8 MHz) :
1. PLLXTPRE = 0 -- HSE clock not divided  (default value)
2. PLLSRC = 1 -- HSE oscillator clock selected as PLL input clock
3. PLLMUL -- 0x0111 (PLL * 9)
4. PPRE1 -- 0x100 (APB1 Prescaler / 2), because APB1 max should be 36 MHz
4. SW = 0x2 -- PLL selected as system clock after multiplication
SysClk = 8 * 9 = 72 MHz
Then, AHB Prescaler is 0 by default and if APB1 clock is divided, the clock for timer will be multiplied by 2, making Timer 2 clock frequency = 72 MHz

Below is the final RCC register values observed in STM32Cube programmer:

Timer settings:

1. Enable timer clock
2. Disable timer before setting prescaler and auto-reload value

SysClk = 72 MHz 
Prescaler = 10000
Timer frequency = SysClk / Prescaler = 72000000 / 10000 = 7200 Hz 
Can make delay from 0.14 ms to 9.1 sec (0 to 65535) with auto-reload value
Auto_reloader = 7200
so, Timer counts till: 1 / f(timer) * Auto_reload = 1 / 7200 * 7200 = 1 sec delay

Auto_reload = required time * (SysClk / Prescaler) 

Note: Look into Keil website for correct header file (stm32f10x.h) to include for your board (STM32F103C8T6)

For a basic LED blinking program, refer this post

Program in Keil: reference manual

#include "stm32f10x.h"
void delay(float);
void RCC_config(void);

#define sys_clk 72000000
#define pre_scale (10000 - 1)

void RCC_config() // RCC clock configuration
{
  RCC -> CR |= RCC_CR_HSEON;                               // HSE ON
  RCC -> CFGR |= (RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);
 // Setting PLL - HSE * 9
  RCC -> CFGR |= RCC_CFGR_SW_1;                            // SysClk = PLLCLK
  RCC -> CR |= RCC_CR_PLLON;                                              
  // Turn ON PLL after above PLL configurations, making SysClk = HSE * 9 = 8 * 9 = 72 MHz
RCC -> CFGR |= RCC_CFGR_PPRE1_DIV2;
// APB1 = AHB / 2 = 72 / 2 = 36 MHz (max)
}

void delay(float i)
{
  uint16_t reload = (uint16_t)((float)(sys_clk / pre_scale) * i);
  TIM2 -> ARR = reload;           // Auto reload value
  TIM2 -> CNT = 0;                // Counter initialized to 0    
  TIM2 -> CR1 |= TIM_CR1_CEN;     // CEN = 1 - Counter enable
  while(TIM2 -> CNT < reload);
  TIM2 -> CR1 &= ~TIM_CR1_CEN;    // CEN = 0 - Counter disable
}

int main()
{
  RCC_config();
 
  /* Timer 2 settings
TIM2 -> CR1 &= ~TIM_CR1_DIR - by default - UP counter */
 
  RCC -> APB1ENR |= RCC_APB1ENR_TIM2EN;  // Enable clock for Timer 2
  TIM2 -> CR1 &= ~TIM_CR1_CEN;           // CEN = 0 - Counter disable
  TIM2 -> PSC = (10000 - 1);             // Prescaler

  /* Port C - pin 13 settings for LED*/
 
  RCC -> APB2ENR |= RCC_APB2ENR_IOPCEN;   // Enable PortC Clock
 
  /* Select PortC_Pin 13 as output @2MHZ
   * Configure Pin 13 with open-drain */
 
  GPIOC -> CRH |= GPIO_CRH_MODE13_1 | GPIO_CRH_CNF13_0;
  GPIOC -> BSRR = GPIO_BSRR_BS13;         // Initialize PC13 LED - OFF
 
  while(1)
  {
    GPIOC -> BSRR = GPIO_BSRR_BR13;       // PC13 LED - ON
    delay(1);                              // in sec (can give values from 0.14 ms to 9.1 sec)              
    GPIOC -> BSRR = GPIO_BSRR_BS13;
    delay(1);
  }
  return 0;
}



For Timer interrupt, see next post

Blinking LED program with own header file in KEIL IDE can be found in this post

For UART in STM32, see this post

Comments