Working with STM32 and Timers part 2: PWM mode, fading 2 LEDs

In the previous guide (here), we discussed how to use the timer to generate accurate delay. In this guide, we shall look at another application for timer which is to generate PWM signal on two channels and fading two leds.

In this guide, we will cover the following:

  • What is PWM
  • Configure the timer and GPIO to generate PWM signal
  • Connection
  • Code
  • Demo

1. What is PWM:

PWM is a technique used to emulate “analog signal” by rapidly turning on-off the pin. This allow the mcu to vary the power delivered to the load such as motor (will be covered later). The PWM has three main characteristics;

  • Frequency:

which describe the duration time of the entire signal

  • Duty cycle

The term duty cycle describes the proportion of ‘on’ time to the regular interval or ‘period’ of time; a low duty cycle corresponds to low power, because the power is off for most of the time. Duty cycle is expressed in percent, 100% being fully on.

  • Amplitude

Which is the voltage level of the PWM (3.3v for STM32f4).

For more details, please check this wikipedia article (here)

2. Configure the timer and GPIO to generate PWM Signal:

First we need to locate which pins connected to TIMER2_CH1 and TIMER2_CH2.

According to the datasheet of STM32F411, PA0 and PA1 are connected to TIM2_CH1 and TIM2_CH2. Hence, we need to enable clock access to GPIOA as following: (for details refer to this topic)

RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;

The we need to configure PA0 and PA1 as alternate function as following:

GPIOA->MODER|=(1<<1)|(1<<3);

After that, wee need to select AF1 for PA0 and PA1 since it is responsible to TIM2 as following

GPIOA->AFR[0]|=(1<<0)|(1<<4);

After that, we enable clock access to TIMER2 as following

RCC->APB1ENR|=RCC_APB1ENR_TIM2EN; //enable clock access to tim2

Hence we determine the prescaller and the ARR

TIM2->PSC=0; //set prescaller to 0 (no divider)
TIM2->ARR=255; //set the maximum count value
TIM2->CNT=0; //seset the current count

with prescaler of 0 and ARR of 255 we will get 62.5KHz (16000000/255)

Then we need to configure capture/compare mode register (CCMR)

The capture/compare mode register has two register (CCMR1 and CCMR2)

  • CCMR1 is for channel 1 and channel 2 of the timer
  • CCMR2 is for channel 3 and channel 4 of the timer

Hence we need CCMR1

For OC1M and OC2M we need to set them as PWM

TIM2->CCMR1=(1<<5)|(1<<6)|(1<<13)|(1<<14); //configure the pins as PWM

From capture/compare enable register we need to enable channel1 and channel2

TIM2->CCER|=0x11; //enbale channel1 and channel2

Finally, we enable the timer from control register 1 (CR1)

TIM2->CR1=1; //enable timer

3. Connection

Connection
actual connection

4. Code:

#include "stm32f4xx.h"                  // Device header
void GPIO_Init(void);
void Timer2_init(void);
void delay(int ms );
#define rate 255
int main(void)
{

GPIO_Init();
Timer2_init();
while(1)
{
for (int i=0;i<rate;i++){
TIM2->CCR1=i;
TIM2->CCR2=rate-i;
delay(5);
}
for (int i=255;i>0;i--){
TIM2->CCR1=i;
TIM2->CCR2=rate-i;
delay(5);
}

}
}

void GPIO_Init(void)
{
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
GPIOA->AFR[0]|=(1<<0)|(1<<4);
GPIOA->MODER|=(1<<1)|(1<<3);

}
void  Timer2_init(void){
RCC->APB1ENR|=RCC_APB1ENR_TIM2EN; //enable clock access tto tim2
TIM2->PSC=0; //set prescaller to 0 (no divider)
TIM2->ARR=255; //set the maximum count value
TIM2->CNT=0; //seset the current count
TIM2->CCMR1=(1<<5)|(1<<6)|(1<<13)|(1<<14); //configure the pins as PWM
TIM2->CCER|=0x11; //enbale channel1 and channel2
TIM2->CR1=1; //enable timer
}


void delay(int ms)

{

int i;

for(; ms>0 ;ms--)

{

for(i =0; i<3195;i++);

}

}


5. Demo:

Add Comment

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