on 2025-05-23 9:00 AM
This article is a tutorial on how to get the STM32F769I-EVAL board’s CAN_Loopback example project working on the STM32F769I-DISCO board using CAN2. This example project was created for the STM32F769I-EVAL board. However, since the STM32F769I-EVAL and STM32F769I-DISCO boards both use the STM32F769NI MCU, this same example project can be run on the STM32F769I-DISCO board.
The CAN_Loopback example project works as-is on the STM32F769I-DISCO board when using CAN1. When using CAN2, there are a couple of changes that need to be made for the example project to work.
Refer to the example project’s readme file for a detailed description of how the example works.
This article can also be followed with other STM32 development boards that share the same STM32 MCU and have a CAN_Loopback example project.
Make sure that all the jumpers on your STM32F769I-DISCO board are in their default position as shown in the below picture. The CN3 jumper should be set to power the board via ST-LINK.
Plug the STM32F769I-DISCO board into your computer using the micro-USB cable. Make sure you plug the micro-USB cable into CN16 on the STM32F769I-DISCO board, which is connected to the on-board ST-LINK debugger/programmer.
Create a new project in STM32CubeIDE, then use the "Example Selector" tab to search for and select the CAN_Loopback example project for the STM32F769I-EVAL board.
Once the project is imported, click the build icon to compile the project. It is important to verify that the project builds successfully before proceeding.
You need to check the STM32 MCU’s datasheet to see which GPIO pins can be configured as CAN2 functionality. For the STM32F769I-DISCO board, we have the following pinout options.
Function |
Pinout options |
CAN2_TX |
PB6 or PB13 |
CAN2 _RX |
PB5 or PB12 |
Next, check the board’s schematics to make sure the CAN2 pins are not already reserved for something else. It could be connected to another IC that is being used in the application. For example, in the STM32F769I-DISCO board schematic, PB13 is connected to the ULPI_D6 pin of the USB ULPI transceiver. In this case, you may not want to use pin PB13 for CAN2 purposes if you plan on using the USB ULPI transceiver in your application.
However, for the purposes of this example, it would be ok to use pin PB13 for CAN2 purposes because this CAN_Loopback example project does not use the USB ULPI transceiver.
In this article, we use the following pinout for the STM32F769I-DISCO board.
Function |
Pin |
CAN2_TX |
PB6 |
CAN2 _RX |
PB5 |
We need to change all the CANx parameters in main.h to values that are compatible with CAN2.
#define |
New value |
Note |
CANx |
CAN2 |
|
CANx_CLK_ENABLE() |
__HAL_RCC_CAN2_CLK_ENABLE() |
|
CANx_GPIO_CLK_ENABLE() |
__HAL_RCC_GPIOB_CLK_ENABLE() |
This is for GPIO port B pins. If you are using CAN2 pins on another port, then use the correct GPIO clock enable function for that specific GPIO port. |
CANx_FORCE_RESET() |
__HAL_RCC_CAN2_FORCE_RESET() |
|
CANx_RELEASE_RESET() |
__HAL_RCC_CAN2_RELEASE_RESET() |
|
CANx_TX_PIN |
GPIO_PIN_6 |
Using pin PB6 as CAN2_TX. If you are using a different pin, then edit this value accordingly. |
CANx_TX_GPIO_PORT |
GPIOB |
Using pin PB6 as CAN2_TX. If you are using a different pin, then edit this value accordingly. |
CANx_TX_AF |
GPIO_AF9_CAN2 |
|
CANx_RX_PIN |
GPIO_PIN_5 |
Using pin PB5 as CAN2_RX. If you are using a different pin, then edit this value accordingly. |
CANx_RX_GPIO_PORT |
GPIOB |
Using pin PB5 as CAN2_RX. If you are using a different pin, then edit this value accordingly. |
CANx_RX_AF |
GPIO_AF9_CAN2 |
|
Here is the fully modified main.h file for reference. The original configurations are kept commented out and the new configurations are between the “MODIFICATION BEGIN” and “MODIFICATION END” labels.
/**
******************************************************************************
* @file CAN/CAN_LoopBack/Inc/main.h
* @author MCD Application Team
* @brief Header for main.c module
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
#include "stm32f769i_eval.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* User can use this section to tailor CANx instance used and associated
resources */
/* Definition for CANx clock resources */
//#define CANx CAN1
//#define CANx_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE()
//#define CANx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
//
//#define CANx_FORCE_RESET() __HAL_RCC_CAN1_FORCE_RESET()
//#define CANx_RELEASE_RESET() __HAL_RCC_CAN1_RELEASE_RESET()
//
///* Definition for CANx Pins */
//#define CANx_TX_PIN GPIO_PIN_12
//#define CANx_TX_GPIO_PORT GPIOA
//#define CANx_TX_AF GPIO_AF9_CAN1
//#define CANx_RX_PIN GPIO_PIN_11
//#define CANx_RX_GPIO_PORT GPIOA
//#define CANx_RX_AF GPIO_AF9_CAN1
//MODIFICATION BEGIN
//MAIN.H file changes for using CAN2:
#define CANx CAN2
#define CANx_CLK_ENABLE() __HAL_RCC_CAN2_CLK_ENABLE()
#define CANx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define CANx_FORCE_RESET() __HAL_RCC_CAN2_FORCE_RESET()
#define CANx_RELEASE_RESET() __HAL_RCC_CAN2_RELEASE_RESET()
// Definition for CANx Pins
#define CANx_TX_PIN GPIO_PIN_6
#define CANx_TX_GPIO_PORT GPIOB
#define CANx_TX_AF GPIO_AF9_CAN2
#define CANx_RX_PIN GPIO_PIN_5
#define CANx_RX_GPIO_PORT GPIOB
#define CANx_RX_AF GPIO_AF9_CAN2
//MODIFICATION END
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void LED_Display(uint8_t Ledstatus);
#endif /* __MAIN_H */
We need to modify the sFilterConfig.FilterBank value appropriately depending on whether we are using CAN1 or CAN2. Refer to the STM32 in dual CAN configuration: bxCAN Filter bank explanation and relation with CAN2 Start Bank parameter article for a detailed explanation on how to choose an appropriate CAN FilterBank value.
The modification we need to make in main.c is in section “2- Configure the CAN Filter” inside the CAN_Polling() function. The new configurations are between the “MODIFICATION BEGIN” and “MODIFICATION END” labels in the code snippet below.
HAL_StatusTypeDef CAN_Polling(void)
{
…
/*##-2- Configure the CAN Filter ###########################################*/
//MODIFICATION BEGIN
if (CANx == CAN1) {
sFilterConfig.FilterBank = 0;
} else if (CANx == CAN2) {
sFilterConfig.FilterBank = 14;
}
//MODIFICATION END
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if(HAL_CAN_ConfigFilter(&CanHandle, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}
…
return HAL_OK; /* Test Passed */
}
The final modification that we need to make is to keep the CAN1 RCC clock enabled even though we are using CAN2. As explained in the STM32 in dual CAN configuration: bxCAN Filter bank explanation and relation with CAN2 Start Bank parameter article, the two CAN instances share resources. CAN1 is the controller and CAN2 is the target, so we must keep the CAN1 RCC clock enabled to use CAN2. To do this, we add a call to __HAL_RCC_CAN1_CLK_ENABLE() inside the HAL_CAN_MspInit() function.
The modification we need to make in stm32f7xx_hal_msp.c is in section “1- Enable peripherals and GPIO Clocks” inside the HAL_CAN_MspInit() function. The new configurations are between the “MODIFICATION BEGIN” and “MODIFICATION END” labels in the code snippet below.
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
…
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* CAN1 Periph clock enable */
//MODIFICATION BEGIN
__HAL_RCC_CAN1_CLK_ENABLE();
//MODIFICATION END
CANx_CLK_ENABLE();
/* Enable GPIO clock ****************************************/
CANx_GPIO_CLK_ENABLE();
…
}
To run the example project, first launch a debug session by clicking the [Debug] icon.
Now, add the CAN2 TxData and RxData variables to the STM32CubeIDE "Expressions" tab so we can see the CAN2 data after it is transmitted.
Run the application by clicking the Run/Resume icon. After a few seconds, click the Pause icon to pause execution of the application so we can view the values of the CAN2 TxData and RxData variables.
Now when we inspect the CAN2 TxData and RxData, we can see that the values ‘0xCA 0xFE‘ were transmitted, and the same ‘0xCA 0xFE‘ values were received. This indicates that the example is working properly on the STM32F769I-DISCO board when using CAN2.
Knowledge article: Guide to CAN (bxCAN/CAN2.0) configuration in Loop back mode on STM32 MCUs