Control LED Brightness with PWM

Hi tecsploiters!

This post is all about using Pulse Width Modulation on the STM32F4 Discovery board to control the brightness of some LED’s- It sounds complicated, but its actually very simple!

PWM Dimmer

PWM Dimmer using STM32F4 Discovery


Now if you dont know what pulse width modulation is (PWM) I’d suggest you look it up, Wikipedia gives a good introduction – but to put it simply PWM is used to control the power transmitted to a source, such as an LED or motor by simply turning the power on and off very quickly! The more the switch is on in a set time period, the higher the power and visa versa.

If you want to really get in to it there is some maths involved, and you would need to start considering other factors such as the speed (frequency) at which you do the switching – but we will leave that until another post! The rest of this post will show you how to program the STM32F4 Discovery board to ‘dim’ both the on board LED’s and an external LED.

As always the full code listing is available at the bottom of the article, and I have commented it throughout to try to explain whats going on.

Now if you are new to electronics you would definitely be forgiven for finding the documentation with the STM32F4 Discovery board a little intimidating – so I will do my best to explain a few points, as you will need to have a basic understanding of the documentation in order to link the configuration code below to the actual external pin used in the example.

Start by taking a look at the official documentation. The information of interest to us starts at page 21 and is a table that describes what each GPIO pin can be used for and goes on down to page 33. For now we are only interested in the first two columns ‘Main Function’ – which is essentially the Pin number on the board and ‘alternate functions’ that describes what else the pin can do other than stanard GPIO.

We are interested mostly in Pins that can be used as a timer, as you will see in the code later a timer is used when setting up PWM. I started by looking for TIMX_CHX in the ‘alternate functions’ column – where the ‘X’ is replaced by a number. If you scroll to page 26 you will find pin PB6 with the alternate function TIM4_CH1. This means the pin is can be used with timer number 4 on channel 1. (each timer has 4 channels)


Don’t worry if the concept of a timer or channel doesn’t make sense at the moment – all you really need to know is that it is used as part of the PWM setup, and that you can only output the PWM signal on certain timer compatible pins. The only way to know what pin to use is to find it in the documentation – and then ensure that your initialization code initializes the correct pin for the timer / channel you are using. In this example we are using timer 4, and we are using all 4 of the channels. 1 of the channels (channel 1) is being used to output a PWM signal on Pin PB6, the other 3 are being linked to the on board LEDs.

The full code listing is below, this can be pasted into the main.c file (of the hello world project) – If anyone would like me to upload the project in full please leave a comment.

Once you’ve got it running you should see 3 of the 4 on board LEDs cycle from bright to dim (at slightly different levels). If you get a volt meter an measure the voltage on pin PB6 (by putting the red lead on PB6 and the black lead on the GND pin) you should see the voltage cycling from low to high in a continuous loop!!!

All that remains then is to connect the pin to an external LED circuit as done in my previous post and you will see the LED going from bright to dim!!!

As always any questions please leave a comment or use the new contact us form, I’de be glad to help you out if I can!

See the video of the finished project on youtube

Have Fun!!

/**
  ******************************************************************************
  * @file    Pulse Width Modulation Demo
  * @author  Lee Dyche - Tecsploit.com
  * @version V1.0.0
  * @date    18/03/2014
  * @brief   3 LEDS go light to dim, and the GPIO pin PB6 has its voltage ramped up and down
  * and could be used to control the brightness of a LED / power of a motor
  ******************************************************************************
  * @attention
  * This is program is provided as is with no warranty!!
  ******************************************************************************
  */

#include "stm32f4_discovery.h"

void Delay(__IO uint32_t nCount);

int main(void)
{
	/*Structures used in the configuration*/
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable TIM4 Clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

  /* Enable GPIOD Pins that are used for on board LED's */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  //Enabled GPIOB we are going to use PB6 which is linked to TIM4_CH1 according to the
  //documentation
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  /* Initialise  pins 13, 14 and 15 D - relating to on board LED's*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  //initalise pin 6 B - relating to timer 4 channel 1
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4);

  /* Setup PWM */
  uint16_t PrescalerValue = 0;
  PrescalerValue = (uint16_t) ((SystemCoreClock /2) / 21000000) - 1;

  /* Setup timer defaults */
  TIM_TimeBaseStructure.TIM_Period = 665;
  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

  /* Configure timer for PWM - channel 1*/
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  //notice the number 1 in TIM_OC1Init
  TIM_OC1Init(TIM4, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* Configure timer for PWM - channel 2 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OC2Init(TIM4, &TIM_OCInitStructure);
  TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* Configure timer for PWM - channel 3*/
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OC3Init(TIM4, &TIM_OCInitStructure);
  TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);

  /* Configure timer for PWM - channel 4 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OC4Init(TIM4, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM4, ENABLE);

  /* Start timer*/
  TIM_Cmd(TIM4, ENABLE);

  int power = 0;
  //for this timer configuration a CCR (power) value of 700 yields approximately 3V on the pin (and is the max)
  while(1)  //Loop forever
  {
	  //The power calculations here are only for demonstration and are very rough!!!
	  //I've devided teh power of the on board LED so you can see the differnt brightnesses
	  TIM4->CCR1 = power; //CCR1 controls channel 1
	  TIM4->CCR2 = power /2;//CCR2 controls channel 1
	  TIM4->CCR3 = power /8;//CCR3 controls channel 1
	  TIM4->CCR4 = power /16;//CCR4 controls channel 1

	  Delay(80000);
	  power++;
	  if(power > 699){
		  power = 0;
		  Delay(900000);
	  }
    }
}

/**
  * @brief  Delay Function.
  * @param  nCount:specifies the Delay time length.
  * @retval None
  */
void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
  }
}

2 thoughts on “Control LED Brightness with PWM

    1. Hi thanks! Hope it was usefull, if u go to the downloads section you can get the complete project including the header file, you just need to register your email, have fun!

Leave a Reply

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