Skip to main content
Visitor II
December 21, 2022
Question

Two STM32F4-discovery boards unable to communicate over CAN

  • December 21, 2022
  • 6 replies
  • 7892 views

Hi,

I am new to HAL libraries and currently working on a small CAN bus consisting of two STM32F4-discovery boards connected to a CAN transceiver connected to the bus. Both transceivers are externally powered with 5V.

So far, I tried the existing CAN examples from the STM32CubeF4 github. The loopback example works fine, the normal mode example does not.

After a few transmissions the mailboxes are filled and the transmit function returns an error. And I can't figure out why it does not transmit the requests. Below you can find the code I on both discovery boards. It is basically the Networking example but with some light adjustments for LED output pins.

Any ideas on why this might not be working as expected?

#include "main.h"
 
#define KEY_PRESSED 0x00
#define KEY_NOT_PRESSED 0x01
 
uint8_t ubKeyNumber = 0x0;
CAN_HandleTypeDef CanHandle;
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint8_t TxData[8];
uint8_t RxData[8];
uint32_t TxMailbox;
 
 
void SystemClock_Config(void);
void Error_Handler(void);
void CAN_Config(void);
void LED_Display(uint8_t LedStatus);
void Init_OnBoard_LEDs(void);
 
int main(void)
{
 HAL_Init();
 
 /* Configure the system clock to 168 MHz */
 SystemClock_Config();
 
 /* Configure LED1, LED2, LED3 and LED4 */
 Init_OnBoard_LEDs();
 
 LED_Display(ubKeyNumber);
 
 /* Configure the CAN peripheral */
 CAN_Config();
 
 /* Infinite loop */
 while (1)
 {
	 uint8_t state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
 if (state)
 {
 if (ubKeyNumber == 0x4)
 {
 ubKeyNumber = 0x00;
 }
 else
 {
 LED_Display(++ubKeyNumber);
 
 /* Set the data to be transmitted */
 TxData[0] = ubKeyNumber;
 TxData[1] = 0xAD;
 
 /* Start the Transmission process */
 if (HAL_CAN_AddTxMessage(&CanHandle, &TxHeader, TxData, &TxMailbox) != HAL_OK)
 {
 /* Transmission request Error */
 Error_Handler();
 }
 HAL_Delay(1000);
 }
 }
 }
}
 
void Init_OnBoard_LEDs(void){
	__HAL_RCC_GPIOD_CLK_ENABLE();
	GPIO_InitTypeDef BoardLEDs;
	BoardLEDs.Mode = GPIO_MODE_OUTPUT_PP;
	BoardLEDs.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
	HAL_GPIO_Init(GPIOD, &BoardLEDs);
 
 
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitTypeDef BlueButton;
	BlueButton.Mode = GPIO_MODE_INPUT;
	BlueButton.Pin = GPIO_PIN_0;
	BlueButton.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &BlueButton);
}
 
void SystemClock_Config(void)
{
 RCC_ClkInitTypeDef RCC_ClkInitStruct;
 RCC_OscInitTypeDef RCC_OscInitStruct;
 
 /* Enable Power Control clock */
 __HAL_RCC_PWR_CLK_ENABLE();
 
 /* The voltage scaling allows optimizing the power consumption when the device is
 clocked below the maximum system frequency, to update the voltage scaling value
 regarding system frequency refer to product datasheet. */
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
 /* Enable HSE Oscillator and activate PLL with HSE as source */
 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 = 25;
 RCC_OscInitStruct.PLL.PLLN = 336;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
 RCC_OscInitStruct.PLL.PLLQ = 7;
 HAL_RCC_OscConfig(&RCC_OscInitStruct);
 
 /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
 clocks dividers */
 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
 
 /* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported */
 if (HAL_GetREVID() == 0x1001)
 {
 /* Enable the Flash prefetch */
 __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
 }
}
 
 
 
/**
 * @brief This function is executed in case of error occurrence.
 * @param None
 * @retval None
 */
void Error_Handler(void)
{
 while (1)
 {
 }
}
 
/**
 * @brief Configures the CAN.
 * @param None
 * @retval None
 */
void CAN_Config(void)
{
	//Tx: PB12
	//Rx: PB13
 CAN_FilterTypeDef sFilterConfig;
 
 /*##-1- Configure the CAN peripheral #######################################*/
 CanHandle.Instance = CAN2;
 
 CanHandle.Init.TimeTriggeredMode = DISABLE;
 CanHandle.Init.AutoBusOff = DISABLE;
 CanHandle.Init.AutoWakeUp = DISABLE;
 CanHandle.Init.AutoRetransmission = ENABLE;
 CanHandle.Init.ReceiveFifoLocked = DISABLE;
 CanHandle.Init.TransmitFifoPriority = DISABLE;
 CanHandle.Init.Mode = CAN_MODE_NORMAL;
 CanHandle.Init.SyncJumpWidth = CAN_SJW_1TQ;
 CanHandle.Init.TimeSeg1 = CAN_BS1_4TQ;
 CanHandle.Init.TimeSeg2 = CAN_BS2_2TQ;
 CanHandle.Init.Prescaler = 6;
 
 if (HAL_CAN_Init(&CanHandle) != HAL_OK)
 {
 /* Initialization Error */
 Error_Handler();
 }
 
 /*##-2- Configure the CAN Filter ###########################################*/
 sFilterConfig.FilterBank = 0;
 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();
 }
 
 /*##-3- Start the CAN peripheral ###########################################*/
 if (HAL_CAN_Start(&CanHandle) != HAL_OK)
 {
 /* Start Error */
 Error_Handler();
 }
 
 /*##-4- Activate CAN RX notification #######################################*/
 if (HAL_CAN_ActivateNotification(&CanHandle, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
 {
 /* Notification Error */
 Error_Handler();
 }
 
 /*##-5- Configure Transmission process #####################################*/
 TxHeader.StdId = 0x321;
 TxHeader.ExtId = 0x01;
 TxHeader.RTR = CAN_RTR_DATA;
 TxHeader.IDE = CAN_ID_STD;
 TxHeader.DLC = 2;
 TxHeader.TransmitGlobalTime = DISABLE;
}
 
/**
 * @brief Rx Fifo 0 message pending callback
 * @param hcan: pointer to a CAN_HandleTypeDef structure that contains
 * the configuration information for the specified CAN.
 * @retval None
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
 /* Get RX message */
 if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
 {
 /* Reception Error */
 Error_Handler();
 }
 
 /* Display LEDx */
 if ((RxHeader.StdId == 0x321) && (RxHeader.IDE == CAN_ID_STD) && (RxHeader.DLC == 2))
 {
 LED_Display(RxData[0]);
 ubKeyNumber = RxData[0];
 }
}
 
/**
 * @brief Turns ON/OFF the dedicated LED.
 * @param LedStatus: LED number from 0 to 3
 * @retval None
 */
void LED_Display(uint8_t LedStatus)
{
 /* Turn OFF all LEDs */
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
 
	switch(LedStatus){
	case(0x0):
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
		break;
	case(0x1):
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
		break;
	case(0x2):
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
		break;
	case(0x3):
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
		break;
	default:
		break;
	}
}

    This topic has been closed for replies.

    6 replies

    Super User
    December 21, 2022

    > two STM32F4-discovery boards connected to a CAN transceiver

    How exactly? Aren't the pins used for this connected to some on-board circuitry, too?

    Observe CAN registers content and waveforms on the pins and on bus.

    JW

    PS. Looking at Init_OnBoard_LEDs(): always initialize or set all fields of structs used in Cube/HAL functions.

    Rde K.1Author
    Visitor II
    December 21, 2022

    That's only the case for CAN1, so I am using CAN2 on pins PB12 & PB13.

    I also have an oscilloscope on the CAN-bus, which shows approx. 2.5V on both lines.

    Graduate II
    December 21, 2022

    Are you using hardware transceivers?

    Graduate II
    December 21, 2022

    >>After a few transmissions the mailboxes are filled

    After how many, always the same number? is that number 3?

    Rde K.1Author
    Visitor II
    December 21, 2022

    Yes, this is always the same number. After 32 messages, this errorcode occurs in the can handler.

    0693W00000WLYYlQAP.png

    Graduate II
    December 22, 2022

    How are the CAN transceivers connected to the dev board and to the CAN bus? Are the terminating resistors enabled?

    Rde K.1Author
    Visitor II
    December 22, 2022

    0693W00000WLcd1QAD.jpg

    Graduate II
    December 22, 2022

    You need a ground reference connected from the PS/CAN transceivers to the Discovery board.

    Technical Moderator
    December 22, 2022

    Hello,

    It will not work as there is an issue with your filter config:

    - For CAN1: .FilterBank should be always < .SlaveStartFilterBank. 

    - For CAN2: .FilterBank should be always >= .SlaveStartFilterBank.

    I 've explained with more details in the attached .txt file how the filters are shared between CAN1 and CAN2.

    Also don't forget to enable CAN1 APB clock (explanation in the txt file) even it's not used in your application.

    Graduate II
    December 22, 2022

    If this is true, then the CAN_Networking example @Rde K.1​ used from ST's repository has been wrong, for many years. That includes the examples in F0, F1, F4, F7, L4 series

    Technical Moderator
    December 22, 2022

    No. The examples are correct. They are using CAN1.

    @Rde K.1​  is using CAN2. and here is the difference!

    Technical Moderator
    December 22, 2022

    Other points to check :

    • What is the voltage level of VIO pin of your transceiver TJA1051T/3? From the datasheet page 8: VIH min = 0.7xVIO. So if VIO = 5V. VIHmin = 5Vx0.7 = 3.5V! But your STM32 VDD= 3.3V < 3.6V!
    • Try to minimize the CAN prescaler value (.Prescaler) and maximize as much as possible the values of TimeSeg1 and TimeSeg2 and keeping your exact bitrate.
    ST Employee
    December 29, 2022

    Firstly, please confirm the connection of the two boards, it seems ok regarding your diagram.

    Secondly, it's necessary to combine these two boards' GND(seems ok).

    Then the direct way is to capture the signal through a oscilloscope: TX(1st tranciever) = > CAN H/L = > RX(2nd tranciever).

    Best Regards,

    Sco