{"id":131,"date":"2014-04-22T17:33:36","date_gmt":"2014-04-22T17:33:36","guid":{"rendered":"http:\/\/visualgdb.com\/w\/?p=131"},"modified":"2015-09-24T10:24:36","modified_gmt":"2015-09-24T17:24:36","slug":"arm-stm32-pwm","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/pwm\/","title":{"rendered":"Using STM32 timers in PWM mode"},"content":{"rendered":"<p>This tutorial shows how to configure the STM32 hardware timers to generate output signals. The mode in which the timers generate the output signals is called PWM (pulse-width modulation) referring to the pulses of adjustable width that can be generated as a result.<\/p>\n<p>Before you begin with this tutorial please create a basic project for your STM32 device (e.g. by following <a href=\"http:\/\/visualgdb.com\/tutorials\/arm\/stm32\/pwm\/..\/\"> this tutorial for STM32F1 series devices<\/a> or this <a href=\"http:\/\/visualgdb.com\/tutorials\/arm\/stm32\/pwm\/..\/f4_discovery\">tutorial for the STM32F4-Discovery board<\/a>).<\/p>\n<ol>\n<li>The STM32 hardware timers are separate hardware blocks that can count from 0 to a given value triggering some events in between. In the PWM mode the timer controls the output of 1 or more output channels. When the counter value reaches 0, maximum or a <strong>compare value <\/strong> defined for each channel, the output value of the channel can be changed. Various configuration options define which events change the value and how it is changed. <a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/01-pwm.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/01-pwm.png\" alt=\"01-pwm\" width=\"700\" height=\"377\" \/><\/a><\/li>\n<li>Before we can use the PWM mode, we need to setup the timer so that it starts counting. We will configure it to count upwards with a period of 1000 and set the divider to 1 and the prescaler to 40000. This is done by calling the <strong>TIM_TimeBaseInit()<\/strong> function followed by a call to <strong>TIM_Cmd() <\/strong>to enable the timer:\n<pre>void InitializeTimer(int period = 500)\r\n{\r\n    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);\r\n\r\n    TIM_TimeBaseInitTypeDef timerInitStructure;\r\n    timerInitStructure.TIM_Prescaler = 40000;\r\n    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;\r\n    timerInitStructure.TIM_Period = period;\r\n    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;\r\n    timerInitStructure.TIM_RepetitionCounter = 0;\r\n    TIM_TimeBaseInit(TIM4, &amp;timerInitStructure);\r\n    TIM_Cmd(TIM4, ENABLE);\r\n}<\/pre>\n<\/li>\n<li>On the STM32F4Discovery board the main LEDs are connected to pins PD12-PD15 having channels 1-4 of timer 4 as the alternate function #2. <a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/leds.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/leds.png\" alt=\"leds\" width=\"700\" height=\"368\" \/><\/a><\/li>\n<li>\u00a0We will now configure the timer to generate 80% impulses on LED4 (i.e. active for 4\/5 of the period and inactive for the next 1\/5). This is done by configuring the channel 1 in the PWM\u00a0 mode with a compare value of 400 (out of period 500) and selecting alternate function 2 (AF2) for the pin PD12:\n<pre>void InitializePWMChannel()\r\n{\r\n    TIM_OCInitTypeDef outputChannelInit = {0,};\r\n    outputChannelInit.TIM_OCMode = TIM_OCMode_PWM1;\r\n    outputChannelInit.TIM_Pulse = 400;\r\n    outputChannelInit.TIM_OutputState = TIM_OutputState_Enable;\r\n    outputChannelInit.TIM_OCPolarity = TIM_OCPolarity_High;\r\n\r\n    TIM_OC1Init(TIM4, &amp;outputChannelInit);\r\n    TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);\r\n\r\n    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);\r\n}<\/pre>\n<\/li>\n<li>Note that in the very beginning of our program we want to enable the GPIOD peripheral and configure the pin PD12 to be an output:\n<pre>void InitializeLEDs()\r\n{\r\n    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);\r\n\r\n    GPIO_InitTypeDef gpioStructure;\r\n    gpioStructure.GPIO_Pin = GPIO_Pin_12;\r\n    gpioStructure.GPIO_Mode = GPIO_Mode_AF;\r\n    gpioStructure.GPIO_Speed = GPIO_Speed_50MHz;\r\n    GPIO_Init(GPIOD, &amp;gpioStructure);\r\n}<\/pre>\n<\/li>\n<li>Finally let&#8217;s put things together in a main() function:\n<pre class=\"\">int main()\r\n{\r\n    InitializeLEDs();\r\n    InitializeTimer();\r\n    InitializePWMChannel();\r\n    for (;;)\r\n    {\r\n    }\r\n}<\/pre>\n<\/li>\n<li>Run the program.\u00a0The green LED will start blinking in short<br \/>\ncycles being on most of the time. Note that the blinking<br \/>\nhappens without any extra work from the CPU that is looping<br \/>\ninside the infinite loop in main() :<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/02-loop.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/tutorials\/arm\/stm32\/pwm\/02-loop.png\" alt=\"02-loop\" width=\"700\" height=\"626\" \/><\/a>In real-world scenarios this would allow allocating the CPU to do some computation while the pulse generation happens completely in the background.<\/li>\n<li>We can easily configure the timer to generate pulse signal on another channel. The period will have to be the same, however the compare value can be different:\n<pre>void InitializePWMChannel2()\r\n{\r\n    TIM_OCInitTypeDef outputChannelInit = {0,};\r\n    outputChannelInit.TIM_OCMode = TIM_OCMode_PWM1;\r\n    outputChannelInit.TIM_Pulse = 100;\r\n    outputChannelInit.TIM_OutputState = TIM_OutputState_Enable;\r\n    outputChannelInit.TIM_OCPolarity = TIM_OCPolarity_High;\r\n\r\n    TIM_OC2Init(TIM4, &amp;outputChannelInit);\r\n    TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);\r\n\r\n    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);\r\n}<\/pre>\n<\/li>\n<li>In order to test this function we also need to enable PD13 in the <strong>InitializeLEDs()<\/strong> function:\n<pre>    gpioStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;<\/pre>\n<\/li>\n<li>If you run the modified program now, you will see how both LEDs are blinking with the same period, however the orange LED blinks with much shorter impulse lengths than the green LED.<\/li>\n<\/ol>\n<p>You can download the full source code of this sample here: <a href=\"http:\/\/sysprogs.com\/files\/visualgdb\/tutorials\/PWMDemo.cpp\">PWMDemo.cpp<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to configure the STM32 hardware timers to generate output signals. The mode in which the timers<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[53,69,61,68],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/131"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=131"}],"version-history":[{"count":1,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/131\/revisions"}],"predecessor-version":[{"id":1062,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/131\/revisions\/1062"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=131"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=131"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=131"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}