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
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++); } }
2 Comments
Add Comment