No ACL setup yet! Denying access to everyone.
en:edu:zmitac:macro:embedeed:lab:stm32-pwm

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:edu:zmitac:macro:embedeed:lab:stm32-pwm [2024/03/04 21:16] – [Prerequisites] ktokarzen:edu:zmitac:macro:embedeed:lab:stm32-pwm [2025/04/02 08:50] (current) – ktokarz
Line 1: Line 1:
-====== STM32 Control of build-in LEDs with PWM ===== +====== STM32 Control of built-in LEDs with PWM ===== 
-This exercise presents how to handle the brightness control of three LEDs mounted on the Nucleo STM32WB55 board. LEDs are electrically connected to microcontroller's pins. Those LEDs have 3 different colours (Red, Green, and Blue) and are accessible in the software as digital pins named LED_RED, LED_GREEN, and LED_BLUE respectively. Each LED can be controlled with the Arduino standard DigitalWrite() function to switch it on or off or control brightness using a PWM signal.+This exercise presents how to handle the brightness control of three LEDs mounted on the Nucleo STM32WB55 board. LEDs are electrically connected to the microcontroller's pins. Those LEDs are in 3 different colours (Red, Green, and Blue). The red LED is connected to pin PB1, the green LED to pin PB0, and the blue LED to pin PB5. LED is lit when the pin state is "1", and dark when the pin state is "0". LEDs are easily accessible in the software as digital pins named LED_RED, LED_GREEN, and LED_BLUE, respectively. Each LED can be controlled with the Arduino standard DigitalWrite() function to switch it on or off or control brightness using a PWM signal.
  
 ===== Prerequisites ===== ===== Prerequisites =====
 A good understanding of the digital GPIO pins operation, PWM signal and duty cycle is necessary. We also use built-in timers to control the PWM hardware channels of the STM32WB55 chip. In this case, we do not use an external library; instead, we use the hardware timer library built in the Arduino Core STM32 framework (stm32duino)(("stm32duino", https://github.com/stm32duino)) for STM32WB55 so that no additional external libraries will be included in the project. A good understanding of the digital GPIO pins operation, PWM signal and duty cycle is necessary. We also use built-in timers to control the PWM hardware channels of the STM32WB55 chip. In this case, we do not use an external library; instead, we use the hardware timer library built in the Arduino Core STM32 framework (stm32duino)(("stm32duino", https://github.com/stm32duino)) for STM32WB55 so that no additional external libraries will be included in the project.
  
-==== Task to be implemented ==== +==== Tasks to be implemented ==== 
-Implement a program that will light LEDs consecutively with R, G, and B. Use 50% of the maximum brightness. Use a PWM signal to control each GPIO for R, G and B, each colour separately to let you easily observe it. You can also experiment with various duty cycle settings for all channels to obtain different LED colours.+1. Write the program that will switch the red LED for one second, then the green LED for one second, and the blue LED for one second repeatedly. This part is to recall the knowledge from the first STM laboratory, be familiar with the equipment, and confirm the proper operation of laboratory elements. 
 +\\ 
 +2. Implement a program that will light LEDs consecutively with red, green, and blue with a PWM signal. Every LED should start from dark, go up to the maximum brightness and then go down to dark. This must be implemented with the use of a timer.
  
-==== Start ==== +==== Task 1 ==== 
-The hardware timer library implements functions which allow us to control the duty cycle of the PWM signal and express it in different formats, including percentages. In the laboratory equipment, all three LEDs are connected to one hardware timer instance. Thanks to this LEDs operate as three separate channels of a single timer. +In the Arduino framework for STM32 handling the GPIO pins is done the same way as for the classic Arduino board. First, the pin should be configured as the output. 
-In the case of setting the PWM duty cycle expressed in percentages, the minimum value is 0, and the max (full brightness) is 100. Note that full brightness may be too bright for the observation camera, so consider using a range between 0 and 50%.+<code c> 
 +pinMode(LED_RED, OUTPUT); 
 +</code>
  
-==== Steps ==== +To turn the LED on we have to set the output pin to "1". 
-To use PWM in STM32WB55, it is best to use a built-in hardware timer library.  +<code c> 
-<code> +DigitalWrite(LED_RED, 1);
-#include <HardwareTimer.h>+
 </code> </code>
-The hardware timer uses internal timer modules and allows us to define channels attached to the timer. We will use 1 channel per colour (R, G and B, so 3 in total). A PWM frequency is controlled with the timer to be shared for all 3 R, G and B channels. Channels control the PWM duty cycle.+ 
 +To turn the LED off we have to clear the output pin. 
 +<code c> 
 +DigitalWrite(LED_RED, 0); 
 +</code> 
 +Use the delay function to be able to observe the behaviour of LEDs. 
 + 
 +==== Task 2 ==== 
 +To do the second task it is necessary to understand the timer operation. It is a more complex task than the previous so some detailed explanation is provided below. 
 +=== Hardware we use === 
 +In the STM32WB55, there are two timers capable of generating the PWM signal for up to four channels per timer. Unfortunately, all three LEDs mounted on the Nucleo board are connected to pins which are not controlled directly by a timer. This situation requires using the interrupts to turn the LEDs on and off in the callback functions connected to interrupts signalled by the chosen timer instance. If we use one timer for all three LEDs they will operate with the same frequency. The duty cycle can be different for every LED if we use a separate channel for each of them. 
 + 
 +=== Software library === 
 +The Arduino framework for STM implements the Hardware Timer library. The library implements a set of functions which allow us to choose the working mode of the timer, enable or disable its operation, and control the duty cycle of the PWM signal expressing it in different formats, including percentages. 
 === Step 1 === === Step 1 ===
-Include the library, and define PIN assignments to channels and PWM frequency (100Hz):+In the first step, we include the library, define PIN assignments to channels, and specify the PWM frequency (100Hz). It is not possible to define a PWM channel without pin assignment, so here we assign channels to pins capable of operating as PWM outputs (although we are not able to control on-board LEDs with these pins).  
 +<note> 
 +We use pins which are not connected to on-board LEDs, so the pins here are dummies. In the case of our own PCB design, it is possible to connect proper outputs to LEDs directly and control them without the need to use interrupts. 
 +</note>
 <code c> <code c>
 #include <HardwareTimer.h> #include <HardwareTimer.h>
Line 30: Line 50:
 #define PWM_freq 100 #define PWM_freq 100
 </code> </code>
-GPIO pins controlling  LEDS are D9 (Red), D3 (Green) and D6 (Blue), respectively.+GPIO dummy pins for PWM channels are D9 (Red), D3 (Green) and D6 (Blue). They are internally connected at the outputs of timer 1.
  
 === Step 2 === === Step 2 ===
Line 50: Line 70:
 channelB = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(LED_PWM_BLUE), PinMap_PWM)); channelB = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(LED_PWM_BLUE), PinMap_PWM));
  
-// Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.+// Instantiate HardwareTimer object. Thanks to the 'new' instantiation, HardwareTimer is not destroyed when the setup() function is finished.
 MyTimLED = new HardwareTimer(Instance); MyTimLED = new HardwareTimer(Instance);
  
 // Configure and start PWM // Configure and start PWM
-MyTimLED->setPWM(channelR,LED_PWM_RED,PWM_freq,1);   /* 100 Hertz, 1% dutycycle. */ +MyTimLED->setPWM(channelR, LED_PWM_RED, PWM_freq, 1);   /* 100 Hertz, 1% dutycycle. */ 
-MyTimLED->setPWM(channelG,LED_PWM_GREEN,PWM_freq,1); /* 100 Hertz, 1% dutycycle. */ +MyTimLED->setPWM(channelG, LED_PWM_GREEN, PWM_freq, 1); /* 100 Hertz, 1% dutycycle. */ 
-MyTimLED->setPWM(channelB,LED_PWM_BLUE,PWM_freq,1);  /* 100 Hertz, 1% dutycycle. */+MyTimLED->setPWM(channelB, LED_PWM_BLUE, PWM_freq, 1);  /* 100 Hertz, 1% dutycycle. */
 </code> </code>
  
-To modify the intensity of the chosen LED after initialisation use the setCaptureCompare function. In the following example, the duty_cycle_value can vary between 0 and 100.+ 
 + 
 +=== Step 3 === 
 +Define callback functions to control real on-board LEDs. There will be one common callback to turn on all LEDs at the beginning of every cycle, and three separate callbacks for three channels to turn LEDs off. This enables different brightness of specific LEDs. 
 +<code> 
 +MyTimLED->attachInterrupt(Update_on_callback); 
 +MyTimLED->attachInterrupt(channelR, Update_off_callback); 
 +</code> 
 + 
 +=== Step 4 === 
 +To modify the intensity of the chosen LED in the loop() function, use the setCaptureCompare function. It changes the content of the capture compare register responsible for the duration of the duty cycle. In the following example, the duty_cycle_value can vary between 0 and 100.
 <code c> <code c>
 MyTimLED->setCaptureCompare(channelR, duty_cycle_value, PERCENT_COMPARE_FORMAT);   //modify duty cycle MyTimLED->setCaptureCompare(channelR, duty_cycle_value, PERCENT_COMPARE_FORMAT);   //modify duty cycle
 </code> </code>
  
-=== Step 3 ===+=== Step 5 ===
 Write a loop for each colour (R, G, then B) to light the colour from dark to max value. Write a loop for each colour (R, G, then B) to light the colour from dark to max value.
-<note important> Full duty cycle (100%) will be too bright for the remote access video camera to handle it. Use some reasonable range such as 0..50% is strongly advised.</note> 
 Mind to compose code to increase and decrease each colour. A hint is below (for channelR): Mind to compose code to increase and decrease each colour. A hint is below (for channelR):
 <code c> <code c>
Line 87: Line 116:
 </code> </code>
 ==== Result validation ==== ==== Result validation ====
-You should be able to observe the pulsing colours of the RGB LED, increasing and decreasing brightness linearly.+You should be able to observe the pulsing colours of the LEDs, increasing and decreasing brightness linearly.
  
 ===== FAQ ===== ===== FAQ =====
-**What is the maximum number of channels?**: the MCU we use here is STM32WB55 on the Nucleo board. The pins available are connected to timer 1 with three PWM channels (connected to our RGB LED) and timer 2 with 4 PWM channels (with two of them connected to the servo and fan described in other scenarios). A single timer can generate PWM signals with independent duty cycles and identical frequency.+**What is the maximum number of channels?**: The MCU we use here is STM32WB55 on the Nucleo board. The pins available are connected to timer 1 with three PWM channels and timer 2 with 4 PWM channels. A single timer can generate PWM signals with independent duty cycles and identical frequency.
 \\ \\
-**What is the maximum bit resolution for PWM?**: Maximum resolution is 16 bits. Note that we can express the duty cycle in a variety of formats. In the presented example we expressed it in percentage so it varies between 1 and 100. It can be also expressed in ticks, Hertz, microseconds, and 1-16 bits numbers.+**What is the maximum bit resolution for PWM?**: Maximum resolution is 16 bits. Note that we can express the duty cycle in a variety of formats. In the presented example, we expressed it in percentage so it varies between 1 and 100. It can also be expressed in ticks, Hertz, microseconds, and 1-16 bit numbers.
 \\ \\
-**What PWM frequency should I use?**: there is no straightforward answer to this question: assuming you observe LED remotely with a camera, even 50Hz would be enough. But it would give a severe flickering experience to the live user, on the other hand. In the example above, we propose 100Hz, but this MCU can easily handle higher frequencies.+**What PWM frequency should I use?**: There is no straightforward answer to this question: assuming you observe the LED remotely with a camera, even 50Hz would be enough. But it would give a severe flickering experience to the live user, on the other hand. In the example above, we propose 100Hz, but this MCU can easily handle higher frequencies.
  
  
en/edu/zmitac/macro/embedeed/lab/stm32-pwm.1709583412.txt.gz · Last modified: by ktokarz