Question
CAN messsages not transmitting even after successful return
- September 18, 2026
- 8 replies
- 36 views
Hello, hope you all are doing well.
I am unable to transmit messages over CAN using DMA on my STM32G431RB Nucleo board. My JLink didn’t show any errors in my code flow, but my logic analyzer did not register any CAN messages on the TX pin (PA12), and the output stays high. I also tried using a CAN adapter to read the messages which wasn’t fruitful. How can I debug this? I used this tutorial for reference:
Thank you in advance!
CanManager.cpp
#include "CanManager.h"
CanManager::CanManager(FDCAN_HandleTypeDef* hfdcan)
: mHandle(hfdcan)
{
mFilterConfig.IdType = FDCAN_STANDARD_ID;
mFilterConfig.FilterIndex = 0;
mFilterConfig.FilterType = FDCAN_FILTER_RANGE;
mFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
mFilterConfig.FilterID1 = TX_ID;
mFilterConfig.FilterID2 = 0x7FFU;
}
HAL_StatusTypeDef CanManager::Init()
{
HAL_StatusTypeDef ret = HAL_FDCAN_ConfigFilter(mHandle, &mFilterConfig);
if (ret != HAL_OK) {
return ret;
}
ret = HAL_FDCAN_Start(mHandle);
if (ret != HAL_OK) {
return ret;
}
ret = HAL_FDCAN_ActivateNotification(mHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
if (ret != HAL_OK) {
return ret;
}
mTxHeader.Identifier = TX_ID;
mTxHeader.IdType = FDCAN_STANDARD_ID;
mTxHeader.TxFrameType = FDCAN_DATA_FRAME;
mTxHeader.DataLength = FDCAN_DLC_BYTES_0;
mTxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
mTxHeader.BitRateSwitch = FDCAN_BRS_OFF;
mTxHeader.FDFormat = FDCAN_CLASSIC_CAN;
mTxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
mTxHeader.MessageMarker = 0;
return ret;
}
uint32_t CanManager::LengthToDlc(uint8_t length)
{
switch (length) {
case 0: return FDCAN_DLC_BYTES_0;
case 1: return FDCAN_DLC_BYTES_1;
case 2: return FDCAN_DLC_BYTES_2;
case 3: return FDCAN_DLC_BYTES_3;
case 4: return FDCAN_DLC_BYTES_4;
case 5: return FDCAN_DLC_BYTES_5;
case 6: return FDCAN_DLC_BYTES_6;
case 7: return FDCAN_DLC_BYTES_7;
default: return FDCAN_DLC_BYTES_8;
}
}
HAL_StatusTypeDef CanManager::TransmitMessage(const uint8_t* data, uint8_t length)
{
if (length > PAYLOAD_MAX_SIZE) {
return HAL_ERROR;
}
mTxHeader.DataLength = LengthToDlc(length);
return HAL_FDCAN_AddMessageToTxFifoQ(mHandle, &mTxHeader, data);
}
DoorECU.cpp
#include "DoorECU.h"
DoorECU::DoorECU()
: mCanManager(&hfdcan1),
mButton(BUTTON_GPIO_Port, BUTTON_Pin, &htim7, &mCanManager),
mLedDriver(&htim2, TIM_CHANNEL_1),
mTerminate(false)
{
}
HAL_StatusTypeDef DoorECU::Init()
{
HAL_StatusTypeDef ret = mCanManager.Init();
return ret;
}
void DoorECU::Run()
{
while (!mTerminate) {
uint8_t data[2] = {1,1};
mCanManager.TransmitMessage(data, FDCAN_DLC_BYTES_2);
HAL_Delay(1000);
}
}
appDoorECU.cpp
#include "appDoorECU.h"
#include "DoorECU.h"
static DoorECU gDoorECU;
HAL_StatusTypeDef appDoorECU_Init()
{
return gDoorECU.Init();
}
void appDoorECU_Run()
{
gDoorECU.Run();
}
void appDoorECU_Terminate()
{
gDoorECU.Terminate();
}
void appDoorECU_StartDebounceTimer()
{
gDoorECU.StartDebounceTimer();
}
void appDoorECU_OnDebounceTimerElapsed()
{
gDoorECU.OnDebounceTimerElapsed();
}
void appDoorECU_OnPwmPulseFinished()
{
gDoorECU.OnPwmPulseFinished();
}
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_FDCAN1_Init();
MX_TIM7_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_StatusTypeDef ret = appDoorECU_Init();
if (ret != HAL_OK) {
Error_Handler();
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
appDoorECU_Run();
/* USER CODE END 3 */
}
fdcan.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file fdcan.c
* @brief This file provides code for the configuration
* of the FDCAN instances.
******************************************************************************
* @attention
*
* Copyright (c) 2026 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.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "fdcan.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
FDCAN_HandleTypeDef hfdcan1;
/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{
/* USER CODE BEGIN FDCAN1_Init 0 */
/* USER CODE END FDCAN1_Init 0 */
/* USER CODE BEGIN FDCAN1_Init 1 */
/* USER CODE END FDCAN1_Init 1 */
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = ENABLE;
hfdcan1.Init.TransmitPause = DISABLE;
hfdcan1.Init.ProtocolException = DISABLE;
hfdcan1.Init.NominalPrescaler = 3;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 13;
hfdcan1.Init.NominalTimeSeg2 = 2;
hfdcan1.Init.DataPrescaler = 1;
hfdcan1.Init.DataSyncJumpWidth = 1;
hfdcan1.Init.DataTimeSeg1 = 1;
hfdcan1.Init.DataTimeSeg2 = 1;
hfdcan1.Init.StdFiltersNbr = 0;
hfdcan1.Init.ExtFiltersNbr = 0;
hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN FDCAN1_Init 2 */
/* USER CODE END FDCAN1_Init 2 */
}
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(fdcanHandle->Instance==FDCAN1)
{
/* USER CODE BEGIN FDCAN1_MspInit 0 */
/* USER CODE END FDCAN1_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/* FDCAN1 clock enable */
__HAL_RCC_FDCAN_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**FDCAN1 GPIO Configuration
PA11 ------> FDCAN1_RX
PA12 ------> FDCAN1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* FDCAN1 interrupt Init */
HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
/* USER CODE BEGIN FDCAN1_MspInit 1 */
/* USER CODE END FDCAN1_MspInit 1 */
}
}
void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{
if(fdcanHandle->Instance==FDCAN1)
{
/* USER CODE BEGIN FDCAN1_MspDeInit 0 */
/* USER CODE END FDCAN1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_FDCAN_CLK_DISABLE();
/**FDCAN1 GPIO Configuration
PA11 ------> FDCAN1_RX
PA12 ------> FDCAN1_TX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
/* FDCAN1 interrupt Deinit */
HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
/* USER CODE BEGIN FDCAN1_MspDeInit 1 */
/* USER CODE END FDCAN1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
