cancel
Showing results for 
Search instead for 
Did you mean: 

CAN communication not working

John_RENRUS
Visitor

Hello everyone,

I’m currently experiencing difficulties with setting up CAN communication on my STM32F4 microcontroller. Despite having configured the CAN interface and connecting it to a CAN transceiver, I observe no activity on my designated can_tx and can_rx pins. I have a second node connected for communication testing.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 "main.h"
#include "usb_device.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32f4xx_hal_dac.h"
#include "stm32f4xx_hal_adc.h"
#include "usbd_cdc_if.h"
#include "stm32f4xx_hal_can.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

#define TRUE_THRESHOLD 0.4588235294117647  //(6,5V/42,5V)*3.0V ADC Schwellenwert nach Skalierung
#define ADC_VOLTAGE_FULL_SCALE 3.0 // Maximal erreichbare Spannung fuer ADC

// Am Anfang Ihres Programms im User Define Bereich
#define DAC_OUTPUT_VOLTAGE 0.4588235294117647 //(6,5V/42,5V)*3.0V oder welcher Wert gebraucht wird
#define DAC_VOLTAGE_FULL_SCALE 3.0 // oder welcher Wert gebraucht wird

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;

CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;

DAC_HandleTypeDef hdac;

/* USER CODE BEGIN PV */
CAN_TxHeaderTypeDef myTxHeader;
uint8_t TxData[8];
uint32_t TxMailbox;
uint32_t adcValue1, adcValue2; 
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN1_Init(void);
static void MX_CAN2_Init(void);
static void MX_DAC_Init(void);
static void MX_ADC1_Init(void);
static void MX_ADC2_Init(void);
/* USER CODE BEGIN PFP */

void DAC_SetComparisonVoltage(void);
void ADC_Scan_RegularChannels(void);
void Send_CAN_Message(void);
void Send_USB_Data(void);
void ToggleErrorLED(uint8_t number_of_blinks);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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_CAN1_Init();
  MX_CAN2_Init();
  MX_DAC_Init();
  MX_USB_DEVICE_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  /* USER CODE BEGIN 2 */
  DAC_SetComparisonVoltage(); // Setze die Vergleichsspannung per DAC

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
ADC_Scan_RegularChannels(); // Lese ADC-Werte

    // ueberpruefe, ob die Spannung unter/ueber dem Schwellenwert ist
    if (adcValue1 > TRUE_THRESHOLD / ADC_VOLTAGE_FULL_SCALE * 4095)
    {
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET); // Orange LED anschalten
    }
    else
    {
      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET); // Orange LED ausschalten
    }

    Send_CAN_Message(); // Sende Nachricht über CAN

Send_USB_Data(); //test massage über usb

    HAL_Delay(50); // 1/50 Sekunde warten

  }
  /* USER CODE END 3 */
}
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    ToggleErrorLED(2); // Toggle LED zweimal für Fehler in SystemClock_Config
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    ToggleErrorLED(3); // Toggle LED dreimal für Fehler in der ClockConfig
  }
}
/**
  * @brief ADC1 Initialization Function
  *  None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    ToggleErrorLED(4); // Toggle LED viermal für Fehler in ADC1_Init
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    ToggleErrorLED(5); // Toggle LED fünfmal für Fehler bei der Kanal-Konfiguration
  }
}
/**
  * @brief ADC2 Initialization Function
  *  None
  * @retval None
  */
static void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    ToggleErrorLED(6); // Toggle LED sechsmal für Fehler in ADC2_Init
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    ToggleErrorLED(7); // Toggle LED siebenmal für Fehler bei der Kanal-Konfiguration
  }
}
/**
  * @brief CAN1 Initialization Function
  *  None
  * @retval None
  */
static void MX_CAN1_Init(void)
{

  /* USER CODE BEGIN CAN1_Init 0 */

  /* USER CODE END CAN1_Init 0 */

  /* USER CODE BEGIN CAN1_Init 1 */

  /* USER CODE END CAN1_Init 1 */
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 6;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = ENABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    ToggleErrorLED(8); // Toggle LED achtmal für Fehler in CAN1_Init
  }
}
/**
  * @brief CAN2 Initialization Function
  *  None
  * @retval None
  */
static void MX_CAN2_Init(void)
{

  /* USER CODE BEGIN CAN2_Init 0 */

  /* USER CODE END CAN2_Init 0 */

  /* USER CODE BEGIN CAN2_Init 1 */

  /* USER CODE END CAN2_Init 1 */
  hcan2.Instance = CAN2;
  hcan2.Init.Prescaler = 6;
  hcan2.Init.Mode = CAN_MODE_NORMAL;
  hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan2.Init.TimeSeg1 = CAN_BS1_11TQ;
  hcan2.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan2.Init.TimeTriggeredMode = DISABLE;
  hcan2.Init.AutoBusOff = DISABLE;
  hcan2.Init.AutoWakeUp = DISABLE;
  hcan2.Init.AutoRetransmission = ENABLE;
  hcan2.Init.ReceiveFifoLocked = DISABLE;
  hcan2.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan2) != HAL_OK)
  {
    ToggleErrorLED(9); // Toggle LED neunmal für Fehler in CAN2_Init
  }
}
/**
  * @brief DAC Initialization Function
  *  None
  * @retval None
  */
static void MX_DAC_Init(void)
{

  /* USER CODE BEGIN DAC_Init 0 */

  /* USER CODE END DAC_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC_Init 1 */

  /* USER CODE END DAC_Init 1 */

  /** DAC Initialization
  */
  hdac.Instance = DAC;
  if (HAL_DAC_Init(&hdac) != HAL_OK)
  {
    ToggleErrorLED(10); // Toggle LED zehnmal für Fehler in DAC_Init
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    ToggleErrorLED(11); // Toggle LED elfmal für Fehler bei der Kanal-Konfiguration
  }
}
/**
  * @brief GPIO Initialization Function
  *  None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN MX_GPIO_Init_1 */

  /* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* USER CODE BEGIN MX_GPIO_Init_2 */

  /* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
void DAC_SetComparisonVoltage(void)
{
  HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
  HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (uint32_t)(DAC_OUTPUT_VOLTAGE / DAC_VOLTAGE_FULL_SCALE * 4095));
}
void ADC_Scan_RegularChannels(void)
{
  HAL_ADC_Start(&hadc1); 
  if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
  {
    adcValue1 = HAL_ADC_GetValue(&hadc1); 
  }
  
  HAL_ADC_Start(&hadc2); 
  if (HAL_ADC_PollForConversion(&hadc2, 100) == HAL_OK)
  {
    adcValue2 = HAL_ADC_GetValue(&hadc2);
  }
}
unsigned int value = 0; 
void Send_CAN_Message(void)
{

  myTxHeader.StdId = 0x321;
  myTxHeader.ExtId = 0x00;
  myTxHeader.RTR = CAN_RTR_DATA;
  myTxHeader.IDE = CAN_ID_STD;
  myTxHeader.DLC = 8;
  myTxHeader.TransmitGlobalTime = DISABLE;

value = HAL_CAN_AddTxMessage(&hcan1, &myTxHeader, TxData, &TxMailbox);

if (value != HAL_OK)
{
ToggleErrorLED(2); // Toggle LED zwölfmal für Fehler bei Send_CAN_Message
}
}
/* Beispiel: Senden einer Testnachricht ueber USB CDC */
void Send_USB_Data(void) {
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15); // Toggle der blauen LED
    
    // Berechnung des Spannungswertes
    uint32_t adcValue = adcValue1; 
    float voltageMeasured = (adcValue / 4095.0) * 3.0; // Skalierung für 3.0V statt 3.3V, auf die Hardware anpassen
    
    // Offset-Korrektur basierend auf Beobachtungen
    float offsetCorrection = 0.0;

    // Anpassen des Offsets basierend auf gemessener Spannung
    if (voltageMeasured < 1.0) {
        offsetCorrection = 0.030 * voltageMeasured; // zu niedrige Werte offset-Korrektur
    } else if (voltageMeasured < 2.0) {
        offsetCorrection = 0.025 * voltageMeasured; // mittlere Werte offset-Korrektur
    } else {
        offsetCorrection = 0.022 * voltageMeasured; // höhere Werte offset-Korrektur
    }

    // Endgültige Korrektur der Messspannung
    float correctedVoltage = voltageMeasured - offsetCorrection; 

    // Berechnung der tatsächlichen Spannung, basierend auf Spannungsteiler
    float actualVoltage = (correctedVoltage / 3.0) * 42.5;

    // Holen Sie sich den aktuellen Zeitstempel
    uint32_t timestamp = HAL_GetTick();

    // Formatieren Sie die Nachricht im CSV-Format
    char message[50];
    snprintf(message, sizeof(message), "%u, %.4f\n", timestamp, actualVoltage);

    // Senden Sie die formatierte Nachricht über USB
    CDC_Transmit_FS((uint8_t*)message, strlen(message));

    
}
void ToggleErrorLED(uint8_t number_of_blinks)
{
    for(uint8_t i = 0; i < number_of_blinks * 2; i++) // Immer gerade Anzahl, um LED zurückzusetzen
    {
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
        HAL_Delay(400);
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  // HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); // Fehleranzeige auch hier
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  *   file: pointer to the source file name
  *   line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Edited to apply code formatting - please see How to insert source code for future reference.

5 REPLIES 5
Ozone
Principal

First, there is a source code formatting tool which makes code snippets much more readable:

Ozone_0-1747308504854.png

And second, there is a lot of irrelevant code which clutters the post.
Just sticking to CAN functionality would make it more readable.

I don't use Cube / HAL, to put that upfront.
But I can't see the respective pin initialisation code. For the CAN peripheral to work, the CAN functionality needs to be assigned to the proper pins.

I suggest to take a proper CAN example for your MCU (might come in handy to specify what F4 exactly), and try that first. Perhaps starting with a loopback example, and move a proper example afterwards.

> I observe no activity on my designated can_tx and can_rx pins. I have a second node connected for communication testing.

Which points to an initialisation issue.
If you use another STM32 board (or a similiar one operating with +3.3V supply), you can connect the Tx/Rx pins of both nodes directly (including a GND connection, of course), as a more incremental approach.

Hi,

Sorry, I'm a bit of a forum newbie. Thanks for pointing out the clutter; I'll focus on the CAN functionality now.

I use STM32CubeMX to initialize the pins and most registers.

Screenshot 2025-05-15 135137.png

My board is the STM32F407G-DISC1, and though it might not be relevant, the transceiver I’m using is the LTC2875. To my knowledge, the pin configuration isn’t directly visible in main.c

I've already looked for examples but haven't found any specific to my board configuration yet. If you have any suggestions or know where I might find a suitable example, I’d appreciate it.

I'll take your suggestion to try a proper CAN example, perhaps starting with a loopback test to troubleshoot the initialization issue further.

Thanks again for your help!

> My board is the STM32F407G-DISC1, and though it might not be relevant, the transceiver I’m using is the LTC2875. To my knowledge, the pin configuration isn’t directly visible in main.c

I am no Cube user, I'm not sure where the GPIO initialisations are "hidden".
The CAN transceiver is basically only logic, so the type does not really matter.

But the board matters- the F4 Discovery is "old-school", being released quite a while before ST switched from the SPL ("Standard Peripheral Library") to Cube. Which means there are very few - if any - Cube examples available.

The "legacy" firmware package for F407 contains two CAN examples. In the version I have (V1.8.0), these are  :
..\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Examples\CAN\CAN_Loopback and 
..\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Examples\CAN\CAN_Networking.
Check with F4 Discovery schematics which pins are free.
It seems this are only CAN_2 and PB12 / PB13 are available, the other pins are connected to onboard peripheral.

> I'll take your suggestion to try a proper CAN example, perhaps starting with a loopback test to troubleshoot the initialization issue further.

To continue ...

The switch from SPL to Cube examples happened aound the release of F42x/43x/44x MCUs, which supposedly use the same CAN peripheral. Perhaps you can use CAN examples for those MCU variant, and adapt them.

Hello @John_RENRUS and welcome to the ST community,

1 - You didn't tell if you already established a complete CAN bus as you are using Normal mode:

hcan2.Init.Mode = CAN_MODE_NORMAL;

Two CAN nodes should be used in this mode.

2 -  What about the voltage level on the LTC2875 RS pin?

mALLEm_0-1747319421297.png

Did you set that pin to the ground?

3 - Better to share your schematics especially the CAN part and also your project. 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.