This repo will cover my journey in working on STM32MP135 microprocessor as Embedded Linux intern @STMicrocoelectronics.
Through this comprehensive README we will be going through the main aspects of my work during this project, but first we need to introduce some key tools and useful concepts.
The STM32MP135 is a microprocessor (MPU) developed by STMicroelectronics, based on a single
- Architecture: A single-core Cortex-A7 processor operating at speeds up to 1GHz.
- Display and Camera Interfaces: Equipped with a dedicated LCD-TFT parallel display interface and a 16-bit parallel camera interface.
- Connectivity: Includes dual Ethernet ports, providing enhanced capabilities for networked applications.
- Security: Cryptographic accelerator, Memory protection, Code isolation for runtime protection. Supports OP-TEE (Open Portable Trusted Execution Environment) and TF-A (Trusted Firmware-A),
This is the
To check the full functionnalities and features provided by this board check the user-manual.
To be able to manipulate and develop applications on this MPU a Linux Distribution is provided;
The OpenSTLinux package is a Linux distribution specifically designed for STM32MPU microprocessors, based on the Yocto Project utilizing OpenEmbedded framework. To ease-up the learning process this distribution comes in different software Packages:
-
$\color{Aqua}{Starter Package}$ Provides essential tools and basic environment for initial development. Starter Pckg -
$\color{Aqua}{Developer Package}$ Offers additional tools and libraries for more advanced development. Developer Pckg -
$\color{Aqua}{Distribution Package}$ A comprehensive package that includes all necessary components for building and deploying applications. Distribution Pckg
-
Board Support Package (BSP): It includes a BSP that integrates essential components such as:
- OP-TEE: A secure operating system that running in a trusted execution environment.
- TF-A (Trusted Firmware-A): Manages the boot process and transitions between secure and non-secure environments.
- Linux Kernel: Runs in non-secure mode, providing the primary operating system functionalities.
-
Application Frameworks: various application frameworks, including:
- Wayland-Weston: For graphical user interfaces.
- GStreamer: For multimedia processing.
- ALSA (Advanced Linux Sound Architecture): For audio functionalities.
We will take our first image, or build our first image i should say. First of we will follow the steps provided in this Distribution Pckg to setup our environment.
If you're not familiar with OpenSTLinux distribution i recommend starting with the Starter Pckg. Note that to deal efficiently with the distribution package, basic knowledge of Yocto is required, check this repo where ressources are provided.
After setting-up your workspace let's setup our build environment. A provided script in the package will do the work for us, we just need to source it with some parameters.
ak47@ak47:$ DISTRO=openstlinux-weston MACHINE=stm32mp13-disco IMAGE=st-image-core source layers/meta-st/scripts/envsetup.sh build-dir-name
Parameters are of my choice according to the hardware available to test everything is OK. Full list of provided parameters is here.
Mentionning the build-dir-name when sourcing the setup file is recommended to avoid any errors caused by path strings length.
Sourcing the file will take us automatically to the build directory where we launch our build process with bitbake.
ak47@ak47:$ bitbake <image>
In case we didn't mention the IMAGE parameter when sourcing our file we will have to mention it when launching the build.
Once the build is complete, we will flash our SD-Card. Two ways will be covered; Our device in DFU Mode through USB OTG port or Flash the image directly to SD-Card from host machine but first let's check some key files under DIR=build-dir/tmp-glibc/deploy/images/machine/
DIR --- arm-trusted-firmware/
--- kernel/
--- optee/
--- fip/
--- flashlayout_<IMAGE>/
--- scripts/
These directories contain the binaries of every element of our image, essential for a correct booting. You can check the boot sequence for the MP13 series.
scripts/ will be covered later. flashlayout_/ is used to locate binaries and set the partionning provided by tsv file used by STM32CubeProgrammer.
To flash our image with our device set in DFU Mode we will need the right combination of switches. An explanatory table is provided. Forced USB/UART boot for programming
Now let's flash the image using STM32CubeProgrammer. First let's check if our device is detected:
ak47@ak47:$ STM32_Programmer_CLI -l usb
Total number of available STM32 device in DFU mode: 1
Device Index : USB1
USB Bus Number :
USB Address Number :
...
We will pass the STM32CubeProgrammer the device index and TSV file as parameters to flash the image onto the SD card.
ak47@ak47:$ STM32_Programmer_CLI -c port=usb1 -w flashlayout_<IMAGE>/extensible/FlashLayout_sdcard_<>.tsv
USB speed : High Speed (480MBit/s)
Manuf. ID : STMicroelectronics
Product ID : DFU in HS Mode @Device ID /0x501, @Revision ID /0x1001
...
Common error may occur due to wrong directories in tsv file. You may need to move up two levels example: fip/ -> ../../fip/
If everything went ok you should see a message on your terminal.
Start operation done successfully at partition 0x13
Flashing service completed successfully
Now let's get back to the scripts/ folder we mentionned earlier. This folder provides a script that can be used to generate a raw image to be flashed directly to the micro SD-Car using the disk/data duplicator command (dd). Let's change dirctory to the scripts/ folder then:
ak47@ak47:$ ./create_sdcard_from_flashlayout.sh ../flashlayout_<IMAGE>/FlashLayout_sdcard_<>.tsv
This script will create a complete raw image using the partitions and binaries' paths mentionned in the tsv file.
ak47@ak47:$ sudo umount /dev/mmcblkX
Removing the card without unmounting it can result in data loss.
ak47@ak47:$ sudo dd if=../flashlayout_<>_FlashLayout_sdcard_<>.raw of=/dev/mmcblkX bs=8M conv=fdatasync status=progress
And there it is your image is flashed, enjoy the fruit of your work. But to really make it enjoyable will need another powerful tool; Minicom.
Minicom is a popular text-based terminal emulator program primarily used in Unix-like operating systems like Linux. It allows users to communicate with external devices connected via serial ports.
So connect the board to PC via STLINK, locate the corresponding tty interface under /dev. Set the switches so your board boots from SD-Card then launch minicom on your PC.
ak47@ak47:$ sudo apt install minicom
ak47@ak47:$ minicom -D /dev/ttyACMx
Now that we got familiar with our tools and environment let's get to the real deal.
Imagine this scenario; You're working on a custom product based on the
Note that DT = Device Tree
-
1. Modify the DT: Enable the UART instance connected to the module
2. Modify the DT: Make the module an in-tree device
3. Develop the Kernel Module
4. Develop the Command Line Interface
Let's understand the data structure we will be modifying which is the
The UART instance i am working on is the UART8 instance initially disabled. That's why we will be applying a patch.
1. Copy the DT device_tree.dts we will be modifying to a tmp/ directory
2. Copy in the same tmp/ device_tree.dts for example device_tree.dts.ref for reference
3. Modify the device_tree.dts to enable UART8
4. Generate the patch and copy to the folder in your custom layer
ak47@ak47:$ cp build-mp135/tmp-glibc/work-shared/<machine>/kernel-source/arch/arm/boot/dts/stm32mp135f-dk.dts ~/tmp/stm32mp135f-dk.dts
ak47@ak47:~/tmp/$ cp stm32mp135f-dk.dts stm32mp135f-dk.dts.ref
ak47@ak47:~/tmp/$ nano stm32mp135f-dk.dts
&uart8 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&uart8_pins_a>;
pinctrl-1 = <&uart8_sleep_pins_a>;
pinctrl-2 = <&uart8_idle_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
//status = "disabled";
status = "okay";
}
After modifying our file we will use git to compare and generate a file marking all differences in a patch file that will be applied in order to avoid modifying the original file
ak47@ak47:~/tmp/$ git diff --no-index stm32mp135f-dk.dts stm32mp135f-dk.dts.ref > 0001-Patch-File.patch
And there it is our patch file is ready.
The mentionned files in the patch file will be directing to tmp/ folder change that to:
a/arch/arm/boot/dts/stm32mp135f-dk.dts
b/arch/arm/boot/dts/stm32mp135f-dk.dts
Now move your patch to your custom layer. Check this repo for more informations about layers manipulation.
Same process as done to enable the UART8 instance will be repeated but the content is different. To tell the kernel that our Grove Wifi v2 is wired to UART8 we need to introduce the device as a child-node of the UART8 node.
&uart8 {
pinctrl-names = "default", "sleep", "idle";
pinctrl-0 = <&uart8_pins_a>;
pinctrl-1 = <&uart8_sleep_pins_a>;
pinctrl-2 = <&uart8_idle_pins_a>;
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
current-speed = <115200>;
grovewifi: grovewifiv2 {
compatible = "seeedstudio,grovewifiv2";
status = "okay";
};
};
So our final device-tree will look something like this one.
The compatible binding is used to make correspondance between the device and its kernel module which we will see later
A simple bbappend recipe will ensure applying those changes before compiling the device-tree into a device-tree blob by extending the original kernel recipe.
A detailed comprehensive documentation is provided about kernel development and the structure of the module i have developed..
Note that the correspondance between the hardware declared in the device-tree and the kernel module is ensured through of_device_id struct.
Now that our source code is ready we will need two things:
-
Makefile: This make will process our kernel module to turn it into a kernel object
-
Recipe: The recipe ensures that make process is done over cross-compilattion then installed under the right directory.
If you're not familiar with Makefile and the make build tool check this repo.
Let's go through the main components of this particular Recipe.
inherit modules
This line tells Yocto to inherit the module class, which contains common functions and behaviors used for building Linux kernel modules.
EXTRA_OEMAKE:append:task-install = " -C ${STAGING_KERNEL_DIR} M=${S}"
EXTRA_OEMAKE += "KDIR=${STAGING_KERNEL_DIR}"
Now to interact with our module an under-improvement CLI is provided.
A CLI written in C is provided as a built-in feature in our generated image is provided. This CLI exploits the Sysfs entries to communicate with the kernel module.
This CLI handles any unknown commands or commands with extra or missing arguments and provides the functionnalities below
grovewifi_CLI --chk-state /*Returns if the state is OK or Not*/
grovewifi_CLI --connect <ssid> <pwd> /*Returns connection is established*/
grovewifi_CLI --disconnect /*Returns if operation is successful or not*/
grovewifi_CLI --get-ip /*Returns your IP addr*/
grovewifi_CLI --ping <IP or Host> /*Returns ok or not*/
Note that this CLI is under improvement and "successful operation" and "unsuccessful operation" are the provided responses.
Let's go through the main components of this Recipe.
do_compile() {
${CC} grovewifi_cli.c -o grovewifi_CLI
}
This function is used to cross-compile the source code into binary that will be installed in our target image through:
do_install() {
install -d ${D}${bindir}
install -m 0755 grovewifi_CLI ${D}${bindir}
}
The first line command installs the bindir which references /usr/bin
The second line installs the executable with specific permissions under this directory
Let's go for a demo showcasing the outcome of our hardwork, after building and flashing.
Stm32mp135f-dk WiKi ST WiKi
DigiKey Shawn Hymel
Yocto Lab Christopher Blaess
12 Glossary Variables Yocto Project Documentation
Yocto Project Manual Yocto Documentation
The Linux Kernel Module Programming Guide Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang
LINUX DEVICE DRIVERS 3rd Edition Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
Serial Device Bus Johan Hovold