# CANopenSTM32 **Repository Path**: daizia/CANopenSTM32 ## Basic Information - **Project Name**: CANopenSTM32 - **Description**: STM32f407ZGT6 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-05 - **Last Updated**: 2025-12-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # CANopenNode STM32 CANopenSTM32 is a CANopen stack running on STM32 microcontroller based on [CANOpenNode](https://github.com/CANopenNode/CANopenNode) stack. ## How to run demos Examples are developed in [STM32CubeIDE](https://www.st.com/en/development-tools/stm32cubeide.html) tool, official ST development studio for any STM32 microcontroller. You can directly open projects in the STM32CubeIDE and run examples on the relevant boards. ## Repository directories - `.\CANopenNode` : Includes the stack implementation, for most of use cases you don't need to touch these files as they are constant between all the variations and ports (i.e. Linux, PIC, STM32 and etc.) - `.\CANopenNodeSTM32` : Includes the implementation of low-level driver for STM32 microcontrollers, support both CAN based controllers and FDCAN without any changes. It automatically detects the controller type and activate the relevant calls to STM32 HAL libraries - `.\examples` : It include many examples on various boards including STM32F407ZGTx野火霸天虎开发板 ## Supported boards and MCUs [STM32F407ZGTx 野火霸天虎开发板] + Any CAN Bus Physical Layer Module ## Porting to other STM32 microcontrollers checklist : - Create a new project in STM32CubeMXIDE - Configure CAN/FDCAN to your desired bitrate and map it to relevant tx/rx pins - Make sure you activate Auto Bus recovery (bxCAN) / protocol exception handling (FDCAN) - Activate the RX and TX interrupt on the CAN peripheral - Enable a timer for a 1ms overflow interrupt and activate interrupt for that timer - Copy or clone `CANopenNode` and `CANopenNodeSTM32` into your project directory - Add `CANopenNode` and `CANopenNodeSTM32` to Source locations in `Project Properties -> C/C++ General -> Paths and Symbols -> Source Locations` - add an exclusion filter for `example/` folder for `CANopenNode` folder - Add `CANOpenNode` and `CANopenNodeSTM32` to `Project Properties -> C/C++ General -> Paths and Symbols -> Includes` under `GNU C` items - In your main.c, add `#include "CO_app_STM32.h"` ```c /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "CO_app_STM32.h" /* USER CODE END Includes */ ``` - Make sure that you have the `HAL_TIM_PeriodElapsedCallback` function implemented with a call to `canopen_app_interrupt`. ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ if (htim->Instance == TIM1) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ // Handle CANOpen app interrupts if (htim == canopenNodeSTM32->timerHandle) { canopen_app_interrupt(); } /* USER CODE END Callback 1 */ } ``` - Now based on your application, you'll take one of the following approaches : ### In Bare-metal application - In your main.c, add following code to your USER CODE BEGIN 2 ```c /* USER CODE BEGIN 2 */ CANopenNodeSTM32 canOpenNodeSTM32; canOpenNodeSTM32.CANHandle = &hcan; canOpenNodeSTM32.HWInitFunction = MX_CAN_Init; canOpenNodeSTM32.timerHandle = &htim17; canOpenNodeSTM32.desiredNodeID = 29; canOpenNodeSTM32.baudrate = 125; canopen_app_init(&canOpenNodeSTM32); /* USER CODE END 2 */ ``` - In your main.c, add following code to your USER CODE BEGIN WHILE ```c /* USER CODE BEGIN WHILE */ while (1) { canopen_app_process(); /* USER CODE END WHILE */ ``` ### In FreeRTOS Applications - You need to create a task for CANOpen, we call it `canopen_task` with a high priority and in that task use the following code : ```c void canopen_task(void *argument) { /* USER CODE BEGIN canopen_task */ CANopenNodeSTM32 canOpenNodeSTM32; canOpenNodeSTM32.CANHandle = &hfdcan1; canOpenNodeSTM32.HWInitFunction = MX_FDCAN1_Init; canOpenNodeSTM32.timerHandle = &htim17; canOpenNodeSTM32.desiredNodeID = 21; canOpenNodeSTM32.baudrate = 125; canopen_app_init(&canOpenNodeSTM32); /* Infinite loop */ for(;;) { //Reflect CANopenStatus on LEDs //Review the hardware configuration to control the LEDs. Test is for STM32H735G-DK board //that turns on the LED when pin is set to low (ergo negation) HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, !canOpenNodeSTM32.outStatusLEDGreen); HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, !canOpenNodeSTM32.outStatusLEDRed); canopen_app_process(); // Sleep for 1ms, you can decrease it if required, in the canopen_app_process we will double check to make sure 1ms passed vTaskDelay(pdMS_TO_TICKS(1)); } /* USER CODE END canopen_task */ } ``` > In RTOS applications, be very careful when accessing OD variables, CAN Send and EMCY variable. You should lock the these critical sections to make sure prevent race conditions. Have a look at `CO_LOCK_CAN_SEND`, `CO_LOCK_OD` and `CO_LOCK_EMCY`. - Run your project on the target board, you should be able to see bootup message on startup ### Known limitations : - We have never tested the multiple CANOpen on a single STM32 device, but the original CANOpenNode has the capability to use multi modules, which you can develop yourself. ### Clone or update Clone the project from git repository and get submodules: ``` git clone https://github.com/CANopenNode/CANopenSTM32 cd CANopenSTM32 git submodule update --init --recursive ``` Update an existing project including submodules: ``` cd CANopenSTM32 git pull git submodule update --init --recursive ``` ## License This file is part of CANopenNode, an open-source CANopen Stack. Project home page is https://github.com/CANopenNode/CANopenNode. For more information on CANopen see http://www.can-cia.org/. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0