Engee documentation
Notebook

Code generation for STM32 (Button and flashing LED on finite automata)

This demo looks at the Engee model for controlling the digital input and output of an STM32 microcontroller.

Introduction

The objective of this example is to develop a Engee model of a fairly simple program to control the digital input and output of a STM32F446RE microcontroller using the nested states and supertransitions of the Engee finite automata library. This demo is a functional development of the Code generation for STM32 (Flashing LED on finite automata) example.

Model description

The example model - stm32_button_blink.engee includes three blocks C Function, configuring and connecting the controller peripherals:

  • GPIO_PC13_INPUT (USER_BUTTON) - during program initialisation configures and initialises the PC13 pin of the microcontroller as an output. During the step-by-step execution of the programme, it returns the state of the digital output PinState. On the NUCLEO-F446RE debug board, the user button B1 "USER " is connected to this pin.
  • GPIO_5_OUTPUT (LED) - configures and initialises the PA5 pin of the microcontroller as an input during program initialisation. During the step-by-step execution it assigns to it the state from PinState. On the debug board NUCLEO-F446RE LED LD2 "GREEN " is connected to this pin.
  • DELAY - during program initialisation configures and initialises the internal timer SysTick. During the step-by-step execution it generates with its help the delay Ts, equal to the modelling step.

image.png

The adjustable parameter Ts is defined by the function PreLoadFunc in callbacks and is used as the step size in the model solver, the input value for block DELAY and the calculation step of block Pulse Generator.

The Pulse Generator block simulates the periodic pressing of the B1 button of the debug board during the simulation. The duration of pressing is 10 seconds, periodicity - 20 seconds. During the simulation process the signal of this block passes through the digital input block without changes.

In the block Blink the logic of pulse generation for LED flashing is realised with the help of state diagram.

Status diagram

Following the state diagram from the example Code Generation for STM32 (Flashing LED on Finite State Machines), which contains one parent state, the block Chart of this example contains two parent states with super transitions between them.

chart.png

The internal variable FullTime sets the duration of LED blinking periods - $100\cdot T_s$ seconds in the parent state Period_and_Clock, if the B1 button is not pressed and the input variable ChangeFreq is equal to $0$, and $50\cdot T_s$ seconds in the parent state Period_and_Clock_2 otherwise. When in the parent states, the counter variable CurrentTime is incremented, and when leaving the parent states, the counter variable is reset.

Connecting peripherals

Unlike the example Code generation for STM32 (Flashing LED on finite automata), in which the STM32 Hardware Abstraction Layer (HAL) library is used to work with peripherals, here the peripheral blocks use register accesses according to the header file stm32f4xx.h. This file is connected in the Build options (Build options) of the blocks C Functions. The stm32f4xx.h file itself, located in the example folder, is used only for modelling and code generation, there is no need to add it further to the IDE project.

image.png

Further explanations of the peripheral block code are given in the code comments.

Modelling results

To simulate the algorithm for generating control pulses at the push of a button, let's load and run the model stm32_button_blink.engee:

In [ ]:
if "stm32_button_blink" in [m.name for m in engee.get_all_models()]
    m = engee.open( "stm32_button_blink" );
else
    m = engee.load( "$(@__DIR__)/stm32_button_blink.engee" );
end

data = engee.run(m);

From the obtained simulation data we plot the signals Blink.Out - the state of the built-in LED and Pulse Generator.1 - the state of the button:

In [ ]:
using Plots
plotlyjs()
plot(data["Pulse Generator.1"].time,
     data["Pulse Generator.1"].value,
     label="Переключение частоты", size=(900,300),
     lw=2, legend=:topright)
plot!(data["Blink.Out"].time,
     data["Blink.Out"].value,
     label="Состояние светодиода", lw=2, )
Out[0]:

As can be seen from the graphs, the model generates periodic signals for the LED with a frequency variable by pressing the button.

Code generation

Let's generate code from the model to load the control algorithm into the microcontroller:

In [ ]:
engee.generate_code( "$(@__DIR__)/stm32_button_blink.engee",
                     "$(@__DIR__)/stm32_button_blink_code")
[ Info: Generated code and artifacts: /user/start/examples/codegen/stm32_button_blink/stm32_button_blink_code

The files created in the folder stm32_button_blink_code - header stm32_button_blink.h and source stm32_button_blink.c will be used further in the project assembly.

Preparing the project in the development environment

The development environment through which the project is built and loaded into the target device is VS Code with the PlatformIO add-on. The configurations of the environment and connections correspond to those already described in the example Code generation for STM32 (Flashing LED on finite automata).

After creating a new project you need to add the files generated in Engee and the file with the code of the main programme main.c (added to the example folder):

stm32.png

After that you can proceed to build the project and load the programme.

Executing the model on STM32

Let's connect the debug board NUCLEO-F446RE to the USB port of the computer, and then in PlatformIO we can observe the connected device. To correctly identify the connection of this board requires a driver ST-Link V2.

After successful connection, let's proceed to the project building: "PLATFORMIO -> PROJECT TASKS -> nucleo_f446re -> General -> Build". If there are no build errors, load the compiled code into the microcontroller: "PLATFORMIO -> PROJECT TASKS -> nucleo_f446re -> nucleo_f446re -> General -> Upload".
As a result of loading the programme on the debug board, you can observe the LED blinking with a frequency of 1 Hz. When pressing the B1 button, the LED blinking frequency is 2 Hz.

btn_blnk.gif

To demonstrate in the example, a Hantec DSO digital oscilloscope was connected to the corresponding pin of the debug board (D13) and the waveform was read through the serial port of the computer using the DSO Analyzer shell. As can be seen in the animation above, the frequency of the output signal doubles when the built-in button is pressed.

Conclusion

In this example we have considered the development of the Engee model for the control programme of a blinking LED on the STM32F446RE microcontroller as part of the NUCLEO debug board. The algorithm is implemented using nested states and super transitions of block Chart from the Engee library of Engee automata and is suitable for code generation. The developed model is embedded with generated files in the PlatformIO environment project for VS Code with further assembly, loading and execution on the target device.

Blocks used in example