CanOpenSTM32 ports the CANopen stack to STM32 with FDCAN and FreeRTOS examples
CANopenNode on STM32 microcontrollers.
At a glance
- What is it?
- CanOpenSTM32 is the STM32 port of the CANopenNode stack, where the generic CANopen implementation is kept untouched, the low level driver picks between classic CAN and FDCAN automatically, and the examples cover bare metal and FreeRTOS builds for five board families.
- Who is it for?
- CanOpenSTM32 fits a team building a CANopen node on an STM32 who wants the maintained CANopenNode stack rather than a fresh implementation, and who can work in either STM32CubeIDE or a CMake and VSCode setup. It is the wrong choice if your controller is not an STM32, since the driver layer is where the portability stops, and the wrong choice for a controller family the FDCAN block does not match, because the auto-detection assumes the same peripheral design.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A port, not a fork of the stack itself
CanOpenSTM32 is a CANopen stack running on STM32 microcontrollers, and it is built on top of the CANopenNode stack rather than reimplementing CANopen. The relationship is the first thing to understand, because it decides what you have to read and what you have to maintain.
The repository directories make the split explicit. The CANopenNode directory holds the stack implementation, and the README says that for most use cases you do not need to touch these files, since they are constant between all the variations and ports, naming Linux, PIC and STM32 as examples of the others. The CANopenNodeSTM32 directory holds the low-level driver for STM32 microcontrollers, and that is where the board-specific work lives.
The driver is where the interesting design decision sits. It supports both CAN based controllers and FDCAN without any changes, and it automatically detects the controller type and activates the relevant calls to the STM32 HAL libraries. So the same example source runs on a board with a classic CAN peripheral and on one with the FDCAN peripheral, and the porting work for a new board is largely about the peripheral and the pins rather than about rewriting a driver.
A legacy directory is also present, holding an older version of the implementation made specifically for FDCAN controllers, which was stable and includes a FreeRTOS implementation.
Two ways to build: STM32CubeIDE and CMake with VSCode
The examples are developed in STM32CubeIDE, the official ST development studio for any STM32 microcontroller, and the README says you can open the projects directly in it and run the examples on the relevant boards. That is the path of least resistance if you already work in the ST toolchain.
Most of the examples also come with a CMake build system and a dedicated preset, and those can be opened with VSCode or any other tool that can process CMake. The .vscode folder in each project carries the practical setup: recommended extensions to install, C and C++ IntelliSense configuration with CMake as the provider, a launch file to load and debug the application with STLink using the cortex-debug extension, and a tasks file with generic tasks to compile, run and list STLinks.
The toolchain you need in the path is listed too: CMake as the build configurator, Ninja as the build system, ARM GCC none eabi as the compiler, and STLink Server for programming and debugging along with the STM32CubeProgrammer CLI. The README shows the versions it was developed against:
# CMake
cmake --version
cmake version 4.3.1
# Ninja
ninja --version
1.13.2
# ARM GCC
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for STM32 14.3.rel1.20251027-0700) 14.3.1 20250623The practical shortcut the README offers is the STM32CubeCLT package from ST, which comes with the minimum required set of tools for STM32 development with an external IDE and CMake.
The board list, and what each board needs from you
Five example areas are listed in the repository, one per MCU family: general, stm32f0xx_can, stm32f3xx_can, stm32f4xx_can, stm32g0xx_fdcan, stm32g0xx_fdcan_rtos and stm32h7xx_fdcan.
The board descriptions are where the practical detail is. The STM32H735G-DK has many features of the STM32H7xx series and includes three CAN transceivers on the board, so you need no additional hardware to connect to an existing CAN network, and it includes a built-in programmer and a virtual COM port for communication, which the README says makes evaluation quick and easy. The demo works at the FDCAN1 port with connector CN18, and the FDCAN IP block is the same for any STM32H7xx family, so migration to a custom board should be straightforward. It runs out of the box on that board, offers bare metal and FreeRTOS operating system examples, uses FDCAN1 at 125kHz for communication, integrates CANopen LED control, and provides debug messages through the VCP COM port at 115200 bauds.
The STM32G0C1VE-EV is described in the same terms, a high-end development platform for the STM32G0C1VET6 with two CAN FD controllers and a physical layer on board, again with no additional hardware needed, and the demo works at FDCAN1 with connector CN12.
The Nucleo boards, the F303ZE and the F072RB, need a MAX33040ESHLD transceiver board, because the Nucleo headers are arduino-compatible and the bundle provides the minimum components to establish CAN communication with CANopen on top of it. That project is tied to the CubeMX configuration, so you supply a compatible configuration with the bitrate and interrupt activation, and the STM32F4DISCOVERY needs any CAN bus physical layer module, with pin mapping taken from the CubeMX configuration file.
The example set covers bare metal and FreeRTOS
The examples directory carries the same targets in two forms for at least one family, and the naming makes the distinction visible: stm32g0xx_fdcan alongside stm32g0xx_fdcan_rtos, with the same pattern implied for the h7xx family by the listing.
That pairing matters for embedded work, because the two configurations are not just a different scheduler. A bare metal build polls and the CAN interrupt handling is yours to arrange, while a FreeRTOS build has a task model, and the timing of the CAN callbacks relative to the stack has to be right for the stack to behave. Having both configurations for the same board lets you move between them without redesigning the application.
The general example directory is the board-agnostic one, and the per-family directories are where the peripheral and pin differences are absorbed.
The value of the examples as a starting point is stated for the H735G board, which can be used as reference code for an end product. That is the strongest claim in the README about the examples, and it is a reasonable one for a driver layer whose job is to hide the difference between classic CAN and FDCAN.
The FDCAN auto-detection is what makes the porting story work, and it is also the constraint. The detection assumes a peripheral layout that matches the families the driver was written against, which is why the README notes that the FDCAN IP block is the same for any STM32H7xx and for any STM32G0xx family, and why the claim of straightforward migration is qualified by family.
Where the tutorial and the protocol overview live
For anyone who has not worked with CANopen before, the README points at a video tutorial that goes from the basics to implementation and porting of the CANopenNode stack, and it includes a chapter list with timestamps.
The chapter list is a compact map of the protocol as this project uses it. It covers why CAN, the CAN bus, why CANopen, the CANopen architecture, the object dictionary, important CANopen concepts, and then the two mechanisms that carry data, PDO and SDO, followed by NMT. After the theory it moves to the CANopenNode open source stack and then to the STM32 practical implementation.
The object dictionary and the split between PDO and SDO are the parts worth understanding before touching the code, because they are what the stack's API is organised around. The object dictionary is the shared data model that every device on the bus exposes, PDO is the mechanism for moving values in a way that is mapped in advance, SDO is the request and response path for reading and writing individual entries, and NMT is the network management state machine that starts and stops nodes.
The video is a better starting point than the repository for that reason, and the repository is a better starting point once the concepts are familiar.
Repository layout, licences and maintenance
The top-level entries show the structure. There is a CANopenNode directory for the shared stack, a CANopenNode_STM32 directory for the port, an examples directory, a legacy directory, a cmake directory, a docs directory and a scripts directory. There is a .clang-format file, which tells you the code is formatted with clang-format, a .gitmodules file, and a CONTRIBUTING.md.
The licence is recorded as a custom one that GitHub cannot classify, with the LICENSE file in the repository as the reference. Since this is a port of the upstream CANopenNode stack, the terms of both matter, and the LICENSE file is where to read them.
On maintenance, the repository is not archived and the last push was on 2026-10-12, but there are no GitHub releases, so the version you pick has to come from the source tree rather than from a tag. For a project that sits in the firmware of a device, that is worth weighing: the upstream CANopenNode stack is where the protocol implementation changes over time, and this port has to be updated to match.
The repository also carries documentation and a docs directory, and the README itself includes screenshots of the VSCode setup with the syntax highlighting and IntelliSense provider, and the CMake project detection with the correct preset, which is a good picture of what a working environment looks like.
Where this is the wrong choice
The first limit is the platform. The driver is written against the STM32 HAL libraries and the STM32 peripheral layout, so a project on a different microcontroller family needs the other CANopenNode ports, of which the README names a Linux port and a PIC port. The upstream stack is the portable part and this repository is the part that is not.
The second is the CubeMX coupling. For the Nucleo and discovery examples the project is tied to the CubeMX configuration and you have to supply a compatible one, with the bitrate and the interrupt activation set correctly. That is a real dependency for a team that would rather configure pins and clocks by hand, and it is the piece of the setup most likely to cause a first failure.
The third is the FDCAN assumption. The auto-detection of controller type means you do not have to choose, but it also means the peripheral has to be one the driver recognises. A board with a classic CAN peripheral in a family the examples do not cover, or with a peripheral that behaves differently, will not simply work.
The fourth is the absence of releases, mentioned above, which for firmware is a bigger deal than for a library, because a device in the field needs a known version of what is burned into it, and this repository gives you a branch rather than a set of tags. A team that needs reproducible firmware builds has to manage that itself, for example by vendoring a known commit.
Editorial conclusion
CanOpenSTM32 fits a team building a CANopen node on an STM32 who wants the maintained CANopenNode stack rather than a fresh implementation, and who can work in either STM32CubeIDE or a CMake and VSCode setup. It is the wrong choice if your controller is not an STM32, since the driver layer is where the portability stops, and the wrong choice for a controller family the FDCAN block does not match, because the auto-detection assumes the same peripheral design. Before you start, check three things: that your board has a CAN transceiver and that you know which connector to use, since the demos are documented per board, that you can supply the CubeMX configuration the driver expects, because the project is tied to that configuration for bitrate and interrupt setup, and that you can accept a custom licence, since the licence field is recorded as one that GitHub cannot classify and the LICENSE file in the repository is the reference. The last push was on 2026-10-12 and there are no GitHub releases.
Frequently asked questions
What is the difference between CANopenNode and CanOpenSTM32?
CANopenNode is the shared CANopen stack implementation, kept constant between ports, and CanOpenSTM32 is the STM32 port of it, with the low level driver that supports both CAN based controllers and FDCAN and auto-detects which one is present.
What tools do I need to build the CanOpenSTM32 examples?
CMake as the build configurator, Ninja as the build system, ARM GCC none eabi as the compiler, and STLink Server with the STM32CubeProgrammer CLI for programming and debugging. The README also points at the STM32CubeCLT package as the quickest way to get that toolset.
Which boards are supported?
The examples cover the STM32H735G-DK, the STM32G0C1VE-EV, the NUCLEO-F303ZE and NUCLEO-F072RB with a MAX33040ESHLD transceiver board, and the STM32F4DISCOVERY with any CAN bus physical layer module. The H735G and G0C1E run out of the box.
Do the CanOpenSTM32 examples include FreeRTOS versions?
Yes. The examples directory includes both bare metal and RTOS variants for the G0xx FDCAN family, and the H735G board notes list bare metal and FreeRTOS operating system examples. A legacy directory also holds an older FDCAN-specific implementation that includes a FreeRTOS implementation.
What licence applies to CanOpenSTM32?
The licence field is recorded as a custom licence that GitHub cannot classify, with the LICENSE file in the repository as the reference. The last push to the repository was on 2026-10-12 and the repository publishes no GitHub releases.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/canopennode-canopenstm32)Was this useful?