2025-05-15 4:22 AM - last edited on 2025-05-15 7:24 AM by mƎALLEm
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.
2025-05-27 9:20 AM
Hi @John_RENRUS
This post has been escalated to the ST Online Support Team for additional assistance. We'll contact you directly.
Regards,
Billy
2025-05-27 1:10 PM
I've looked at your code and I see you're missing some function calls
/*
function: Set CAN filter to pass all ID's
input: hcan instance
output: none
*/
void CAN_SetFilter(CAN_HandleTypeDef *hcan)
{
static CAN_FilterTypeDef sFilterConfig;
if(hcan == &hcan1)
{
sFilterConfig.FilterBank = 0;
}
#ifdef HCAN2
else if(hcan == &hcan2)
{
sFilterConfig.FilterBank = 14;
}
#endif
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_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
if(HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(hcan) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY ) != HAL_OK) // enables CAN notification.
{
Error_Handler();
}
}