Dealing with LEDs using a STM32

Requirement

This first collection of examples and exercises is focused on LEDs. This article is strictly related to some other articles which explains the fundamentals of STM32 programming with ChibiOS. There articles are:

  1. From 0 to STM32, which is a light introduction to the STM32 microcontrollers and to its driver setup;
  2. Developing on STM32: introducing ChibiStudio, which explains how to setup a working environment for firmware development in Windows;
  3. A close look to ChibiOS demos for STM32, which explains how to deal with default demos of ChibiOS;
  4. Using STM32’s GPIO with ChibiOS’ PAL Driver, which explains in details how GPIO works.

Before to read this article you should match this simple requirement (this could be easily achieved reading the just listed articles) :

  • You must be capable to create, build and run a custom project with ChibiOS on a STM32 development board.

Preliminary notes

I what follows I will not add downloadable projects for three main reasons:

  1. These demos could be easily applied to every STM32 development board and microcontroller so I should create tens of demos for each example/exercise
  2. A downloadable project requires maintenance over time and a lot of effort which are unjustified for these examples/exercises which are extremely simple.
  3. Putting examples to work is actually part of the exercise.

In any case each example will be explained in a way that you will be able to the use it on your side.

If you have any question ask support commenting this article or subscribing to our forum.

Examples

A simple LED blinker

Create a single thread project which blinks a LED using an STM32 development board.

From task to solution

If you are thinking that the default demo already does what we are asking for the answer is yes. Anyway, you should consider that here we are not talking about a generic LED blinker but we want to create the simpler LED blinker. So, the simplest solution would be a single threaded application and we can do this using only the main() thread.

To achieve the goal, the best approach would be to duplicate a default demo and edit it. We have already explained how to create a new project duplicating a default one in the Chapter 5 of the article “A close look to ChibiOS demos for STM32”. In this chapter you can also find a nice video I am going to re-share here as a quick reference.

So let’s create a new project giving it a proper name. For instance, if the project would be for the STM32 Nucleo F401RE I would could call it RT-STM32F401RE-NUCLEO64-Simple_blinker. After we have properly edited makefile and debug configuration we can start to edit the main.c. A solution could be:

  1. remove the inclusion of ch_test.h;
  2. remove the sdStart (we are not going to use the test suite nor the serial driver);
  3. remove the chThdCreateStatic (we are not going to create another thread);
  4. replace the loop of main with the loop of Thread1;
  5. delete the declaration of waThread1 and Thread1;
  6. edit the comment before the main loop (not necessary but is a good habit).
Implementation

For a STM32 Nucleo-64 the main.c would be this

A screen of projects and its board files.

This code is valid for each STM32 Nucleo-64 because all these board have a Green LED which line is named (LINE_LED_GREEN). This code could be also used on other development board by editing this line properly.

If you are not aware about what a “Line” is you should read again Using STM32’s GPIO with ChibiOS’ PAL Driver. As quick reference remember that all the lines related to your board are declared in board.h file which is easily reachable through the linked folder inside your project (see Fig.1).

The code we have written here blinks the LED with a period of 1 second and duty cycle of 50%. This because the palToggleLine() inverts the logic state of the line where the LED is connected and the chThdSleepMilliseconds() adds a pause between each toggle. The next figure is the timing diagram of the main thread as is.

Led blinker 1s 50%
The timing diagram of a thread which blinks a LED with period 1 second and duty cycle 50%
Final remarks

With our modification we have deleted all the code related to Serial Driver and Test suite. This means we can completely disable all the code related to these parts.

It is possible to disable the Serial Driver acting on act on halconf.h:

To exclude the Test Suite  we have to act on the makefile commenting the entry related to it. Considering that in makefile a comment begins with hashkey that a look to the last line of the following code:

A blinking LED in our project is a cheap probe inside our firmware: if it stops to blink the firmware has crashed!

Speeding up!

How to double the LED’s blinking speed?

From task to solution

In this case the task is enough clear. Looking back to previous example we can figure out that a easy solution could be to copy the previous code and act on thread sleep Looking at timing diagram it is clear that the timing is achieved using the sleep. So to double the frequency we just have to half the sleep time.

Implementation

For a generic STM32 Nucleo-64 the implementation would be

As before to use this code on another development board the only difference in main.c will be the line to use. This code blinks the LED with a period of half second and duty cycle of 50% and the next figure is the timing diagram of the main thread as is now.

Led blinker 500ms 50%
The timing diagram of a thread which blinks a LED with period 500 millisecond and duty cycle 50%
Final remarks

To conclude this exercise lets point out something about timing. In all the timing diagrams we have stated that the turn-on/turn-off of the the Green LED is instantaneous. In reality the change of the status of a digital output PIN involves some logic circuitry and this means that palTogglePad() requires a non-zero time to be put in practice. Anyway the execution time is in the order of hundreds of nanoseconds which is much smaller than hundreds of milliseconds. Thus, we can confidently say that the turn-on/turn-off of the LED is almost instantaneous.

About timing what beats the time are the thread sleeps. Except in case of extreme CPU load or tight scheduling (which means that intervals between context switches in the order of hundreds of microseconds) the timing provided by a sleep is extremely reliable.

If the blinker thread is the thread with highest priority and sleeps are in the order of few milliseconds, even in case of extreme CPU load its schedule is reliable.

If you are interested in this argument you should absolutely walk through this further reading about scheduling and multi-threading.

Changing the duty cycle!

How is it possible to change the duty cycle to the 25%?

From task to solution

The duty cycle is a concept which is specific of square waves. In the common sense, the duty cycle is a percentage representing the fraction one period in which the signal is active. In our case since the LED is active (turned on) on the high side the duty cycle is

Duty=\frac{T_{High}}{T_{High} + T_{Low}}

This means that if we want to keep the period to one second then the LED should be turned on for 200 ms and turned off for 800 ms. In this way the duty would be

Duty=\frac{250ms}{250ms + 750ms}=25\%

Implementation

To match the requirement we have to slightly change the code in the main loop. For a generic STM32 Nucleo-64 it would be

LED on a STM32 Nucleo-64
The schematic of the Green Led on the STM32 Nucleo-64 board

This code works as expected only if LED is connected as active high or, in other words, if the LED is turned on when the signal which drives it is set to High.

Looking at figure 4 we can see that the LD2 which is the green LED has its cathode connected to the ground and its anode connected in series with a 510Ω resistor to the PA5 (alias Arduino D13).

That means if PA5 is set as high (which is 3.3V) the current flow through the LED and it turns and this is the definition of active high.

What follows is the timing diagram of the main loop for this example.

Led blinker 1s 25%
The timing diagram of a thread which blinks a LED with period 1 second and duty cycle 25%
Final remarks

The following circuit could better explain the difference between an active high (left) and active low (right) circuit. Note that the round symbol which switches between 1 and 0 represent the GPIO of an STM32.

Note also that this circuit works with 0-5V logic (differently from STM32 which works with 0-3.3V logic).

Exercises

External LED

Connect an external LED to your board as active high and make it blinks

Hint: a GPIO must be properly configured to drive a LED as explained here.

Counter phase

Blink the on board LED and the external LED alternatively (e.g. when one is on the other is off)

Dimming

Reduce the LED bright using only the PAL Driver

Hint: duty cycle, persistence of view, chThdSleepMicroseconds().

Solutions for proposed exercises

Well, right now it’s all folks. Solution to these articles will be the argument of the next E&E appointment.

 

Be the first to reply at Dealing with LEDs using a STM32

Leave a Reply