Home - MichaelMcGetrick/meta-stm32mp1-custom GitHub Wiki
The STM32MP157F-DK2 discovery board (as part of the STMicroelectronics STM32MP157 series) offers Arm Dual Cortex-A7 800 MHz, Arm Cortex-M4 real-time coprocessor, 3D GPU, TFT/MIPI DSI display, Secure boot and Cryptography. In addition, this board offers a Murata 1DX chipset providing Wifi and Bluetooth functionality. Complete details may be found at [1]. As such, the board offers the ability to run Linux embedded applications on the A7, or bare metal and RTOS on the M4. A hybrid configuration allows for strict real time application on the M4 core combined with powerful signal process analysis and rich graphing ability on the A7 core, with interprocess communication possible between the A7 and M4 applications.
The ideal modern embedded system will be able to provide both strict real-time constraints and a plethora of functionality such as internet connectivity, high value signal processing and artificial intelligence, rich graphing features and touch screen capability.
This article describes the features of the meta-stm32mp1-custom layer for the STM32157F-DK2: Yocto recipes, device tree and Wifi configurations for successful deployment of Wifi and simple I2C and SPI applications. In Section 5, the article will describe how well the board can handle a SPI-based signal processing application running on the Linux-based A7 using graphics to trace simulated EEG biological signals. Further articles in this Wiki series will analyse sampling integrity (latency issues) of running the application on Linux and possible alternatives (such as reconfiguring for Linux RT, or utilising the M4 MCU for data collection), analysing waveforms with Fourier transforms, touch screen control and the uploading of processed data to the cloud.
The development environment, recommended by ST Microelectronics, employs Ubuntu 22.04 LTS running on a VMWare virtual machine.
After the Linux image for the STM32157F-DK2 has been successfully built, it must be flashed to the SD card. ST offers a comprehensive set of development tools for MCUs and MPUs one of which is the STM32CubeProgrammer [2]. Although flashing to the SD card can be performed using the Linux facility dd, it is recommended that the Programmer be used for this purpose. Figure 2.1 illustrates the use of STM32CubeProgrammer. A USB-C OTG cable between the host development machine and the target board is used for this purpose.
Figure 2.1: Flashing the STM32MP157F-DK2 Board with STM32CubeProgrammer
The correct FlashLayout file must be selected - in this case "FlashLayout_sdcard_stm32mp157f-dk2-optee.tsv". It must also be ensured that the on-board boot switches are set to the OFF position. The Programmer flashes sequentially each of the partitions required such as first stage and second stage bootloader, root file system and user file system. More details of the flash mapping may be found at [9].
An important consideration for modern Internet of Things (IOT) embedded systems is to provide support for WiFi connectivity. The STM32MP157f-dk2 board has an on board Wifi chip. The associated device tree node is indicated below:
&sdmmc2 {
...
status = "okay";
...
brcmf: bcrmf@1 {
reg = <1>;
compatible = "brcm,bcm4329-fmac";
interrupt-parent = <&gpiod>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; /* WL_HOST_WAKE */
interrupt-names = "host-wake";
};
};
It is seen that the bcrmf device interfaces with the host via SDIO and the SDMMC2 controller. The Murata Wifi chip runs in FullMAC mode, so the Broadcom device driver must also offload firmware to the WiFI chip. We can configure the Wifi device driver in the Linux Menuconfig utility by running
bitbake -c menuconfig virtual/kernel

Figure 3.1: Setting up the Broadcom FullMAC WLAN driver in Linux Menuconfig
Figure 3.1 shows the Menuconfig utility. One must navigate to Device Drivers -> Network device support -> Wireless LAN -> Broadcom devices and configure the Broadcom FullMAC WLAN driver with [M] to ensure that it will be initialised as a loadable kernel module.
A complete description of WLAN kernel configuration for STM32MP13x and STM32MP15x lines may be found at [3].
To ensure that a Wifi interface is enabled on the target, the correct Wifi firmware needs to be installed. The OpenSTLinux Layer takes care of this. The Murata module also incorporates Bluetooth in the chipset, so the appropriate firmware must also be installed for this. In the target, the firmware files are placed in /lib/firmware/brcm.
wpa_passphrase SSID PASSWORD >> recipes-connectivity/wpa-supplicant/files/wpa_supplicant-wlan0.conf
providing the relevant values for SSID and PASSWORD. The placeholder network code in wpa_supplicant-wlan0.conf may now be removed.
A recipe to install the required Wifi configuration files and allow Wifi to start automatically on bootup may be found at wpa-supplicant_%.bbappend. The recipe sets up a symbolic link to systemd/system/multi-user.target.wants/ directory to ensure that the service will be started.
The DS3231 Real Time Clock (RTC) module is an I2C peripheral that provides Date/Time and temperature data [7]. Additionally, there is an onboard EEPROM that can also be accessed via an I2C bus. The sections below describe how an I2C application may be set up to communicate with this peripheral.
The general features of the STM32MP157F-DK2 discovery board may be inspected in the STM32MP157 user manual for this line of devices [5]. Section 6 of this manual provides an overview of the hardware layout. There are some expansion connection options - a 40 PIN GPIO Raspberry Pi compatible connector (CN2) and Arduino-compatible expansion connectors (CN13, CN14, CN16, CN17). As can be gleaned from the STM32MP157 datasheet, there are six available I2C buses [6]. Both the GPIO expansion connector and the Arduino connectors provide connection to I2C5. Since the Arduino connectors are more easily accessible than the GPIO connector on this board, the Arduino connectors have been chosen for connection purposes.
Using the configuration information found in Table 24 (Section 6.16.3) of the user manual, the following pin connections have been implemented:
Connector | Arduino Pin | STM32 Pin | DS3231 Pin |
---|---|---|---|
CN16 | 4 | - | VCC |
CN16 | 6 | - | GND |
CN13 | 9 | PA12 | SDA |
CN13 | 10 | PA11 | SCL |
Figure 4.1 shows the connections from the STM32MP157F-DK2 board to the breadboard-based DS3231 module.

Figure 4.1: STM32MP157F-DK2 connected to DS3231 Module via I2C bus
The I2C5 bus is not enabled by default and it needs to be ensured that the required pins are configured as I2C5 pins. The device tree is modified by adding the following to the board-specific stm32mp157f-dk2.dts file :
&i2c5 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c5_pins_a>;
pinctrl-1 = <&i2c5_sleep_pins_a>;
i2c-scl-rising-time-ns = <185>;
i2c-scl-falling-time-ns = <20>;
clock-frequency = <100000>;
status = "okay";
};
The bus is enabled by setting the status attribute to "okay". Applying the correct pin muxing is performed by applying the correct pinctrl properties for default and sleep modes. For example, we see from stm32mp15-pinctrl.dtsi that <&i2c5_pins_a> is defined by:
i2c5_pins_a: i2c5-0 {
pins {
pinmux = <STM32_PINMUX('A', 11, AF4)>, /* I2C5_SCL */
<STM32_PINMUX('A', 12, AF4)>; /* I2C5_SDA */
bias-disable;
drive-open-drain;
slew-rate = <0>;
};
};
We see that pin PA11 is muxed for alternate function 4 (I2C5 SCL line) and PA12 is muxed for alternate function 4 (I2C5 SDA line). The memory address location for I2C5 is 0x40015000 which can found in the board datasheet, Section 2.5.2, Table 9 [6].
To apply the modifcation to the device tree code, a suitable patch is applied in accordance with the Yocto project guidelines [8]. In order to do this, a copy of the current build device tree is made and the original saved under a different name. From the build directory:
cp tmp/work-shared/stm32mp1/kernel-source/arch/arm/boot/dts/stm32mp157f-dk2.dts ~/Documents
cd ~/Documents
cp stm32mp157f-dk2.dts ctm32mp157f-dk2.dts.orig
The &i2c5 device tree node shown above is then added to the copy, and a comparison made using the git diff facility:
git diff --no-index stm32mp157f-dk2.dts.orig stm32mp157f-dk2.dts > 0001-add-i2c5-userspace-dts.patch
Since the patch file has been generated out of the normal git version control the following additions need to be made:
--- a/arch/arm/boot/dts/stm32mp157f-dk2.dts
+++ b/arch/arm/boot/dts/stm32mp157f-dk2.dts
A custom kernel recipe append file to apply the patch is created under the custom layer and can be seen at
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-kernel/linux/linux-stm32mp_%25.bbappend .
The contents of the patch file may be seen here:
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-kernel/linux/stm32mp1/0001-add-i2c5-userspace-dts.patch
During development activity it is useful to check that the I2C bus is functioning properly. The Linux I2C tools are useful for this. Figure 4.2 shows the output of running the i2cdetect facility on the target using the Linux Minicom facility.
Figure 4.2: Minicom Session with i2cdetect Tool showing i2c addresses for DS3231 Module
The relevant I2C bus can be found by running i2cdetect -l, which will list all of the I2c buses available. It is seen that i2c-1 is related to the host I2C controller at memory location 0x40015000 which is our required I2C5 bus.
Running i2cdetect -y 1 for this bus shows the i2c addresses of peripherals on this bus. Since this RTC module has an onboard 24C32 EEPROM module, the addresses given are 0x57 and 0x68 which are the addresses for the EEPROM (default) and RTC.
Figure 4.3. shows the output of running the simple application gettime. The program reads registers at the RTC I2C address (0x68) every five seconds. The RTC facility also has a temperature sensor. The register associated with this sensor is read in addition to the date/time information. The recipe to install this application may be found in gettime_0.1.bb. The program is run with the test type configuration set to RTC_CLOCK in gettime.c.

Figure 4.3: Minicom Session showing output for the i2c app
To ensure that the application is baked into the image, we add:
IMAGE_INSTALL:append = " gettime"
to the conf/local.conf file in the build directory.
This section describes how a EEG signal routed through the MCP3008 ADC can be processed and traced on the onboard TFT/DSI display. The aim will be to port existing graphics software (https://github.com/MichaelMcGetrick/Simple-Graphics) to the STM32MP1 environment for provision of real time display (GTK or Qt). Signal data processing, such as Fourier transform analysis and relevant pattern recognition techniques, will be used to ascertain certain properties of the signal for diagnostic purposes. Relevant data will be streamed to a cloud facility.
SPI functionality is provided to the Arduino-compatible connectors C13 of the STM32MP157F-DK2 board. The table below defines the required pin mappings:
Connector | Arduino Pin | STM32 Pin | Function |
---|---|---|---|
CN13 | 3 | PE11 | SPI4_NSS |
CN13 | 4 | PE14 | SPI4_MOSI |
CN13 | 5 | PE13 | SPI4_MISO |
CN13 | 6 | PE11 | SPI4_SCK |
Like the I2C5 bus, the SPI4 bus is not enabled by default. The device tree is modified by adding the following to the board-specific stm32mp157f-dk2.dts file :
&spi4 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi4_pins_b>;
pinctrl-1 = <&spi4_sleep_pins_b>;
status = "okay";
cs-gpios= <&gpioe 11 0>;
spidev@0{
compatible = "mjmtek,mcp3008";
reg = <0>; /* CS #0 */
spi-max-frequency = <1000000>;
};
};
The mcp3008 peripheral device is driven by a custom kernel module identified by the compatible string. To apply the modification to the device tree code, another suitable patch is applied to the board device tree. Care must be taken to ensure that a chip select pin is configured correctly with the cs-gpios attribute; otherwise the spi device will not be activated. The custom kernel recipe append file to apply the patch is modified to add the SPI4 bus patch. The contents of the patch file may be seen here:
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-kernel/linux/stm32mp1/0003-add-spi4-custom_userspace-dts.patch
In order to collect data, a custom loadable kernel module has been written (as an alternative to using spidev) and may be found at:
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/tree/master/recipes-mcp/mcp3008-mod/files. An accompanying Makefile is also provided that will be required by the Yocto recipe to build the kernel module.
To ensure that the kernel module is baked into the image, we add:
IMAGE_INSTALL:append = " mcp3008-mod"
to the conf/local.conf file in the build directory.
The recipe file is located at:
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-mcp/mcp3008-mod/mcp3008-mod_0.1.bb.
To ensure that the application is baked into the image, we add:
IMAGE_INSTALL:append = " spiapp"
to the conf/local.conf file in the build directory.
On the target, the kernel module mcp3008.ko is located in /lib/modules/6.1.28/extra. The spi bus and mcp3008 data collection can be tested using the program located at https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/tree/master/recipes-apps/spi_app/files/src. Since the kernel module is built as a loadable kernel module, it must be loaded into the kernel using either modprode or insmod. Then, on the target, the test program may be run:
cd /usr/bin
insmod /lib/modules/6.1.28/extra/mcp3008.ko
./spi_app
Figure 5.1 shows the use of a Digilent Analog Discovery 2 signal generator to provide an analog system to the input of the MCP3008. For this simple test, the MCP3008 is sampling at 100Hz. Figure 5.2 shows the ouput of the MCP3008 in a Minicom terminal. The layout and connections between the STM32MP157F, MCP3008 and Digilent signal generator are illustrated in Figure 5.3.

Figure 5.1: Using the Digilent Analog Discovery 2 to generate a steady 2V output

Figure 5.2: Minicom terminal showing output from the MCP3008 ADC

Figure 5.3: Circuit connections for MCP3008 ADC
It is useful to work with a loadable kernel module when regular changes are made to the module during the development stage. As a standalone module it can be built quickly and separately from the kernel image and easily transferred to the target. However, when the module has been developed, and is stable, it is far more useful to compile the module as a built-in module. Then, the module can be configured as a part of the kernel configuration and added to the menuconfig facility.
A patch has been implemented to add the driver to the kernel configuration and is located at
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-kernel/linux/stm32mp1/0001-mcp-char-driver.patch .
In order to create this patch, a git repo of the current kernel-source, found in the Yocto build directory, is first created.
A suitable sub-folder within the drivers directory of the kernel source is then created (in this case mcpdriver under the char folder).
The kernel souce code for the loadable kernel module is copied to this directory and then a Makefile and Kconfig file created. The Kconfig
file configures the entries for the Menuconfig:
config MCP3008_DRIVER
tristate "Device Driver for Microchip MCP3008"
help
MJMTek MCP3008 Driver
The parent Kconfig file (in char directory is modified by adding:
source "drivers/char/mcpdriver/Kconfig"
The Makefile in the parent directory is modified by adding:
obj-$(CONFIG_MCP3008_DRIVER) += mcpdriver/
The patch file may be created by:
git format-patch HEAD~1
The bbappend file https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-kernel/linux/linux-stm32mp_%25.bbappend is modified with:
SRC_URI += "file://0001-mcp-char-driver.patch"
Figure 5.4 shows an entry for the MCP3008 driver within menuconfig allowing it to be enabled as a built-in module.
Figure 5.4: Menuconfig listing driver for Microchip MCP3008 device
Figure 5.5 shows the STM32MP157F-DK2 display receiving data from the MCP3008 ADC. The simulated data is fed into the MCP3008 from the Digilent signal generator at a requested sampling rate of 2000Hz.
Figure 5.5: STM32MP157F-DK2 Display with Sampled Data
The frequency components in the signal are at 50Hz, 100Hz and 200Hz as seen by the Rigol FFT trace in Figure 5.6.
Figure 5.6: FFT Analysis of Sampled Signal
The graphical display has been developed using the GTK Cairo graphics framework. A graphics test program has been developed and the appplication recipe may be seen at
https://github.com/MichaelMcGetrick/meta-stm32mp1-custom/blob/master/recipes-apps/gtk-cairo/gtk-cairo_0.1.bb
and
IMAGE_INSTALL:append = " gtk-cairo"
added to the conf/local.conf file in the build directory.
A PNG image of the display was programically produced whilst running the application and transferred from the embedded target to the development machine. The graphics display may be seen more clearly in Figure 5.7.
Figure 5.7: Image taken by gtk_cairo application executing on target
The signal looks reasonable. However, it can be seen that the signal is rather sharp in places where it should be smoother and more rounded. A requested sampling rate of 2000Hz should be fine for a signal whose maximum frequency content is 200Hz - it certainly should meet the requirements of the Nyquist theorem for accurate analysis. However, as we shall see in the next article (ref), the sampling integrity begins to deteriorate significantly as we attempt to sample at higher and higher sample rates.
-
https://www.st.com/en/microcontrollers-microprocessors/stm32mp157f.html
-
https://www.st.com/en/development-tools/stm32cubeprog.html
-
https://wiki.st.com/stm32mpu/wiki/WLAN_overview
- https://wiki.st.com/stm32mpu/wiki/How_to_setup_a_WLAN_connection
-
Stm3mp157f-dk2 User Manual
-
https://www.st.com/resource/en/reference_manual/dm00327659.pdf
-
https://www.alldatasheet.com/datasheet-pdf/pdf/112132/DALLAS/DS3231.html
-
https://docs.yoctoproject.org/kernel-dev/common.html#applying-patches
-
https://wiki.st.com/stm32mpu/index.php?title=STM32CubeProgrammer_flashlayout&stableid=53554