Aidge Export for ARM CortexM systems
This plugin allow Aidge to create exports for ARM CortexM systems.
It generates standalone C/C++ code intended to run on STM32 targets.
pip install aidge_export_arm_cortexm
Examples
If you want to generate exports and/or better understand how it works in Aidge, you may take a look at the following resources :
- Example Scripts : Python scripts examples to export common models;
- Export Tutorials : Notebooks to better understand the export process (you may find these tutorials on the Aidge documentation page as well);
- User Guide : Theoretical guides detailing the export structure.
Supported targets
- STM32F746
- STM32H743
- STM32L4R5
- STM32F413
Additional targets can be added upon request.
Normally, any recent STM32 board should be compatible with the generated code. You must only ensure that the corresponding pack is installed in pyOCD (e.g., stm32h743zitx for NUCLEO-H743ZI), the board_config.json file is properly configured for your board, along with the respective hardware configuration (RAM/Flash size, UART settings, etc.) along with a template project for your board in aidge/aidge_core/aidge_core/hw_model/targets.
Backends
This export provides two backends:
-
arm_cortexm: Provides specific optimizations for Convolution and Fully Connected (FC) layers, and is largely based on theaidge_export_cppbackend. -
CMSIS-NN: Relies on the optimized kernels provided by CMSIS-NN.
Supported layers
arm_cortexm backend
| Layer | Supported |
|---|---|
| Convolution | ✔️ |
| Depthwise Convolution | ✔️ |
| Convolution Transpose | ✔️ |
| Fully Connected | ✔️ |
CMSIS-NN backend
| Layer | Supported |
|---|---|
| Add | ✔️ |
| Mul | ❌ |
| Convolution | ✔️ |
| Depthwise Convolution | ✔️ |
| Fully Connected | ✔️ |
| Average Pooling | ✔️ |
| Max Pooling | ✔️ |
| Global Average Pooling | ✔️ |
| Concat | ❌ |
| Reshape | ❌ |
| Softmax | ❌ |
[!NOTE]:
- If your model contains unsupported operators, the export will still work. In that case, the implementation from the
aidge_export_cppmodule will be used.- The CMSIS-NN backend only supports quantized models (int8).
Examples
Several example scripts are available in aidge/examples.
| Model | arm_cortexm | CMSIS-NN | Notes |
|---|---|---|---|
| LeNet | ✔️ | ✔️ | |
| Deep Autoencoder | ✔️ | 🔶 | Generation works, but slight output differences are observed on the last FC layer |
| DS-CNN | ✔️ | ✔️ | |
| MobileNetV1 VWW | ✔️ | ✔️ | |
| ResNet8 | ✔️ | 🔶 | Generation works, but slight output differences are observed on the third convolution |
Running an example
First of all, please make sure to execute the setup.sh script inside your target folder (eg. aidge/aidge_core/aidge_core/hw_model/targets/stm32/stm32h7/stm32h743/board_files/setup.sh) before trying to build for the first time. This will download the Drivers/HAL files directly from ST repository.
Then, navigate to the root of the repository and run the following command to execute the LeNet example:
cd aidge/examples/benchmark
Run the Python script:
python benchmark_model.py --profiling --board stm32h7 --model_path lenet_mnist
Run python <model>.py --help to see all available options.
The script will generate the export, compile it, flash it on the board, and capture the UART output to measure inference time and perform some benchmarking. Some chats will be generated with the results of the benchmark, and the raw output will be stored in export_folder/uart_output.txt.
By default, the compilation will be done using a docker container, but you can also choose to compile it locally by installing the required toolchain (e.g., arm-none-eabi-gcc for STM32 targets) and running the command with the --no_docker flag.
Running an tinyML benchmark
This module also provides a template for running the tinyMLPerf benchmark. The benchmark can be executed for the following models:
| Model | Dataset | Notes |
|---|---|---|
| Deep AutoEncoder | ToyADMOS | |
| DS-CNN | Speech Commands | |
| MobileNetV1 VWW | Visual Wake Words | |
| ResNet8 | Cifar10 |
Each dataset can be evaluated in terms of accuracy and inference time. For the moment, the evaluation of power consumption is not supported, since it relies on external hardware to do the measurement. In order to run the benchmark, you can use the following command :
python benchmark_model.py --board stm32h7 --model_path resnet8_cifar10 --tinymlbenchmark
This will create a different main file that communicates with the tinyML framework to perform the evaluation. Once you have flashed the board, you need to cancel the execution of the script (CTRL+C), and follow the instructions provided by tinyML to run the benchmark.
git clone https://github.com/mlcommons/tiny.git
cd tiny
# Install dependencies into virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows, use `.venv\Scripts\activate`
pip install -r benchmark/training/streaming_wakeword/requirements.txt pyusb libusb
To execute the benchmark itself, you'll first need to generate the dataset samples. Each folder inside tiny/benchmark/training/ contains the instructions to download and generate the samples for each model. For example, for the MobileNetV1 VWW model, you can run:
cd benchmark/training/visual_wake_words
./download_and_train_vww.sh
python generate_y_labels.py
Note: This procedure may change in the future, so please refer to the official tinyML repository for the most up-to-date instructions on dataset generation and benchmark execution.
Once you have generated the dataset samples (and placed them in the correct directory, which is tiny/evaluation/datasets/), you can run the benchmark using the command provided above.
cd benchmark/runner
python main.py --dataset_path=../evaluation/datasets/ --test_script=tests_accuracy.yaml --device_list=devices_kws_ic_vww.yaml --mode=a # for accuracy evaluation
python main.py --dataset_path=../evaluation/datasets/ --test_script=tests_performance.yaml --device_list=devices_kws_ic_vww.yaml --mode=p # for performance evaluation
This will generate a report with the results of the benchmark in tiny/runner/sessions/.
Flashing through an API
It is also possible to use the flashing and UART capture functionalities of this module through an API. Basically, instead flashing the board locally, the export will generate a .elf file that will then be flashed by the API using pyOCD. The API is available in the (repository)[https://gitlab.eclipse.org/antoniopereira/api_board_farms], along will all the necessary instructions. Once everything is set up, you can run the same example script as before, but with the --backend api flag:
cd aidge/examples/benchmark
python benchmark_model.py \
--board stm32h7 \
--backend api \
--api-url http://127.0.0.1:8000 \
--api-username admin \
--api-password changeme \
--api-board-name stm32h7_lab_01
--model_path lenet_mnist
Benchmarks with ST Edge AI Developer Cloud (STZooAPI)
You can also compare your model's performance against the ST Edge AI Developer Cloud using the stzooapi backend. This backend uploads your model to ST's cloud services and benchmarks it on their remote board farms.
Installation
To use this feature, you must install the stm32ai-dc Python package:
pip install pycurl seaborn numpy matplotlib ipywidgets gitdir shutils marshmallow tqdm
gitdir https://github.com/STMicroelectronics/stm32ai-modelzoo-services/tree/main/common/stm32ai_dc
Usage
You can use the benchmark_interface.py script (found in examples/) to compare onnxruntime, aidge_backend_cpu, and aidge_export_arm_cortexm with the ST Cloud results:
python examples/benchmark_interface.py \
--stmai-username your_email@st.com \
--stmai-password your_password \
--stmai-board B-U585I-IOT02A
Note: You need an active account on ST Edge AI Developer Cloud. You can also check the boards available on their website.
Installation
Prerequisite:
pyocd >= 0.35.0pyserial >= 3.5
pip install aidge_export_arm_cortexm
🛠 Build from Source
Prerequisite (in addition to previous one):
- Please review the global installation instructions before proceeding.
- If using a virtual environment, use the same one for all Aidge modules.
1. Python installation using setup scripts
| Environment | Python Development |
|---|---|
| Windows | .\setup.ps1 -Modules backend_cpu -Tests |
| Unix | ./setup.sh -m backend_cpu --tests |
[!TIP] Use
Get-Help setup.ps1(Win) or./setup.sh -h(Unix) for full documentation.
2. Python Installation using pip
Run these commands from the aidge_export_arm_cortexm/ directory:
#fStandard install
pip install . -v
# Install with testing dependencies
pip install .[test] -v && pytest
Manual download of HAL/Drivers files
Recently, we have changed the way we handle the HAL/Drivers files for STM32 boards. Now, these files are not included in the repository and must be downloaded manually. For each board in th hardware model, there is a setup.sh script that will download the necessary files from the ST repository. You must run this script before the first compilation. For example, for the STM32H7 board, you can run:
cd aidge/aidge_core/aidge_core/hw_model/targets/stm32/stm32h7/stm32h743/board_files
./setup.sh
Since every board has its own setup script, please make sure to run the script corresponding to your board before trying to compile the code.
Manual update of the STM32 pack is required
By default, pyOCD does not include all STM32 packs. The pack corresponding to NUCLEO-H743ZI (stm32h743zitx) must be installed manually:
pyocd pack install stm32h743zitx
This operation can take several minutes.
Verify that the board is correctly detected
If you are on Windows, make sure you installed the ST-LINK USB Driver that you can find on ST website.
Then connect your board via USB and run:
pyocd list
Expected output example:
# Probe/Board Unique ID Target
------------------------------------------------------------------
0 STM32 STLink 066DFF343339415043185830 ✔︎ stm32h743zitx
NUCLEO-H743ZI
If you see a green check ✔︎, the board is properly detected.
If you see a red cross x, manually install the pack as described above.
A permissions issue with PyOCD: "No available debug probes are connected"
If running the following command results in an error:
pyocd list
No available debug probes are connected
but your STM32 device is visible via lsusb, this may be due to missing USB permissions.
Follow these steps to fix the issue :
-
Create a new udev rule:
sudo nano /etc/udev/rules.d/50-st-link.rules -
Paste this content:
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374b", MODE="0666" -
Reload udev and trigger:
sudo udevadm control --reload-rulessudo udevadm trigger -
Unplug and replug your STM32 device.
-
Try again:
pyocd listYou should now see your board listed.
Important notes
Serial Port: "Permission denied: '/dev/ttyACM0'"
If you see an error like this when trying to flash :
Error connecting to serial port: [Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0'
This usually means your user doesn't have the right permissions for serial access.
For fix that you have to add your user to the dialout group :
sudo usermod -a -G dialout $USER
Then Restart your terminal for the change to take effect
Capture timeout and longer UART output
- When measuring inference time using multiple forward calls, capture times may increase. To avoid premature interruption of the capture process, it is important to increase
uart_capture_durationin theboard_config.jsonaccordingly (e.g., from 30s to 60 or more),
Retrying flash in case of UART failure
-
The flashing process now includes a retry mechanism:
if the UART output file is missing or empty, the firmware is reflashed up to 5 times by default (this can be changed via theMAX_RETRIESconstant in the code). -
This improves robustness against rare flashing issues caused by the
pyOCDlibrary, where firmware may not start correctly despite successful flashing. -
A special end keyword (default:
"DEMO END") is now expected in the UART output to determine when inference is complete and to stop UART capture. -
The file
uart_output.txtis automatically generated during execution and placed in theexport_folder. -
An
export_log.logfile is generated at compilation to store the build logs. -
The
board_config.jsonfile is essential for configuring board flashing. When testing dimensions like[16], you must increaseuart_capture_durationto at least60or more.
Limitations
1. Memory limitations (RAM / Flash)
- From dimensions like
[32, 32, 32, 32](e.g., for ReLU), compilation errors or RAM/Flash overflows may occur. - It is recommended to stay within maximum dimensions of
16, such as[1,1,1,1],[4,4,4,4], or[16,16,16,16].
Recommendations
- Separate different tensor dimensions into different JSON config files.
- Running benchmarks individually helps reduce flashing failures.
- Increase
uart_capture_durationwhen working with large output tensors.
License
Aidge has a Eclipse Public License 2.0, as found in the LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aidge_export_arm_cortexm-0.10.0.post3-py3-none-any.whl.
File metadata
- Download URL: aidge_export_arm_cortexm-0.10.0.post3-py3-none-any.whl
- Upload date:
- Size: 102.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f649310f2ae8f3020697c0bc84fe10f21f2062a7f8fd0f220c54a177bc6fae55
|
|
| MD5 |
36c0b3be8f1568c281b98aa37d4a673a
|
|
| BLAKE2b-256 |
1899efcfc3d255081f5ba8970612ac776758420d92382c0f52da59df61359dc3
|