CANopenSTM32 is a CANopen stack running on STM32 microcontroller based on CANOpenNode stack.
Examples are developed in STM32CubeIDE tool, official ST development studio for any STM32 microcontroller. You can directly open projects in the STM32CubeIDE and run examples on the relevant boards.
.\CANopenNode
: Includes the stack implemenation, for most of usecases 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 detect the controller type and activate the relevant calls to STM32 HAL libraries.\examples
: It include many examples on various boards including STM32F4-Discovery, STM32G0C1 Evaluation board, STM32F076 Nucleo Board, STM32H735G-Development Kit..\Legacy
: It include an older version of CANOpenSTM32 implementation, specifically made for FDCAN controllers, however it was stable and include the FreeRTOS implementation. It has many features of STM32H7xx series and includes 3 CAN transceivers on the board. You do not need any additional hardware to connect to existing CAN network. It also includes built-in programmer and virtual COM port for communication, hence evaluation is quick and easy.
CanOpen demo works at
FDCAN1
port. Use connector CN18.FDCAN IP block is same for any STM32H7xx MCU family, hence migration to your custom board should be straight-forward.
FDCAN1
(CN18) hardware is used for communication at 125kHz115200
baudsThe STM32G0C1E-EV Evaluation board is a high-end development platform for the STM32G0C1VET6 microcontroller. It has many features including two CAN FD controller and physical layer on board. You don't need any additional hardware to connect to existing CAN network. It also includes built-in programmer and virtual COM port for communication, hence evaluation is quick and easy.
CanOpen demo works at
FDCAN1
port. Use connector CN12. FDCAN IP block is same for any STM32G0xx MCU family, hence migration to your custom board should be straight-forward.
Nucleo includes an arduino compatible headers which can be used to add MAX33040ESHLD to it and this bundle provide the minimum required components to establish a CAN communication and CanOpenNode on top of that.
This project is tied to the CubeMX configuration, so it is up to the user to provide compatible configuration using CubeMX (bitrate, interrupt activiation and etc).
Have a look at STM32CubeMX configuration file for pin mapping.
To get a good grasp of CANOpenNode Stack and CANOpenNodeSTM32 stack, you can refer to this video, which explains from basics to implementation and porting of the CANOpenNode stack.
00:00 Introduction and Overview 1:13 Why CAN ? 4:51 CAN Bus 8:55 Why CANOpen ? 13:27 CANOpen architecture 20:00 Object dictionary 21:38 Important CANOpen concepts 23:29 PDO 27:25 SDO 32:23 NMT 33:25 CANOpenNode Open-Source Stack 39:26 STM32 Practical implementation 40:29 CANOpen Tutorial code preparation 43:09 Importing examples to STM32CubeIDE and programming them 47:04 Examples explanation 57:00 Porting to custom STM32 board 1:18:20 EDS Editor (Object dictionary editor) 1:25:54 Creating a TPDO 1:39:55 Accessing OD Variables 1:54:08 Creating an RPDO 2:05:50 Using the SDOs 2:52:52 Node guarding 3:04:38 Transmitting PDOs manually
CANopenNode
and CANopenNodeSTM32
into your project directory CANopenNode
and CANopenNodeSTM32
to Source locations in Project Properties -> C/C++ General -> Paths and Symbols -> Source Locations
example/
folder for CANopenNode
folderCANOpenNode
and CANopenNodeSTM32
to Project Properties -> C/C++ General -> Paths and Symbols -> Includes
under GNU C
items#include "CO_app_STM32.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "CO_app_STM32.h"
/* USER CODE END Includes */
HAL_TIM_PeriodElapsedCallback
function implmented with a call to canopen_app_interrupt
.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 your main.c, add following codes to your USER CODE BEGIN 2
/* 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 codes to your USER CODE BEGIN WHILE
/* USER CODE BEGIN WHILE */
while (1)
{
canopen_app_process();
/* USER CODE END WHILE */
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 :
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
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
andCO_LOCK_EMCY
.
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
This file is part of CANopenNode, an opensource 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