cancel
Showing results for 
Search instead for 
Did you mean: 

CAN1 loopback does not work on STM32F427

Louis00
Associate

Hello everyone,

I have recently been trying to get the CAN1 bus working on the STM32F427. So far, however, it has not worked in either loopback or normal mode. For the normal mode I had a CANCaseXL Analyzer available. The problem, however, is that not even the loopback works. I have attached the main.c file and the ioc project file.

When I call HAL_CAN_AddTxMessage(), I get HAL_OK back, so that seems to work. However, I have set a breakpoint in the CAN interrupt handler (HAL_CAN_IRQHandler() in file stm32f4xx_hal_can.c) and there I see that the TERR0 bit gets set. Accordingly, the transmission process has failed. I have already tried many other possibilities, which unfortunately did not work either.

Maybe someone has an idea. Many thanks in advance!

Louis

1 ACCEPTED SOLUTION

Accepted Solutions
SofLit
ST Employee

Hello,

At first check at your ioc file, I don't recommend these values for CAN bit timing:

 

hcan1.Init.Prescaler = 16;
hcan1.Init.TimeSeg1 = CAN_BS1_1TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;

 

BS1_1TQ and BS2_2TQ are very low. You need to increase them as much as possible by decreasing the prescaler as much as possible.

I recommend these values for 500kb/s:

SofLit_0-1720537708434.png

Also, we don't recommend HSI as clock source when using CAN in Normal mode. You need to use HSE with an external crystal otherwise you may face communication issues.

SofLit_0-1720537957478.png

 

 

 

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.

View solution in original post

3 REPLIES 3
SofLit
ST Employee

Hello,

At first check at your ioc file, I don't recommend these values for CAN bit timing:

 

hcan1.Init.Prescaler = 16;
hcan1.Init.TimeSeg1 = CAN_BS1_1TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;

 

BS1_1TQ and BS2_2TQ are very low. You need to increase them as much as possible by decreasing the prescaler as much as possible.

I recommend these values for 500kb/s:

SofLit_0-1720537708434.png

Also, we don't recommend HSI as clock source when using CAN in Normal mode. You need to use HSE with an external crystal otherwise you may face communication issues.

SofLit_0-1720537957478.png

 

 

 

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.
Karl Yamashita
Lead III

Segment 1 should be larger than Segment 2. Use this online calculator http://www.bittiming.can-wiki.info/

 

I did some test with your code and found an issue. If you're using polling method then don't use HAL_CAN_ActivateNotification else you'll get stuck in while(HAL_CAN_IsTxMessagePending(&hcan1, TxMailbox));

 

Here is what I did to get either Interrupt or Polling method to work. Interrupt mode blinks the LED fast while polling blinks the LED slowly. I moved your code out of main.c and created separate functions.

 

main.c

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

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

 

PollingRoutine.c

/*
 * PollingRoutine.c
 *
 *  Created on: Oct 24, 2023
 *      Author: karl.yamashita
 *
 *
 *      Template for projects.
 *
 */


#include "main.h"


//#define USE_CAN_INTERRUPT


extern CAN_HandleTypeDef hcan1;


CAN_TxHeaderTypeDef   TxHeader;
CAN_RxHeaderTypeDef   RxHeader;
uint8_t               TxData[8];
uint8_t               RxData[8];
uint32_t              TxMailbox;
bool CAN_MsgRdy = false;


void PollingInit(void)
{
	CAN_FilterInit();
}

void PollingRoutine(void)
{
	CAN_SendTxMessage();
#ifdef USE_CAN_INTERRUPT
	CAN_CheckMsg();
#else
	CAN_ReceiveMessage();
#endif
	HAL_Delay(100);
}

void led1_on(void)
{
	HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}

void led1_off(void)
{
	HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}


void CAN_FilterInit(void)
{
	CAN_FilterTypeDef CAN1_Filter;

	CAN1_Filter.FilterBank = 0;
	CAN1_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	CAN1_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1_Filter.FilterIdHigh = 0x0000;
	CAN1_Filter.FilterIdLow = 0x0000;
	CAN1_Filter.FilterMaskIdHigh = 0x0000;
	CAN1_Filter.FilterMaskIdLow = 0x0000;
	CAN1_Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1_Filter.FilterActivation = ENABLE;
	CAN1_Filter.SlaveStartFilterBank = 14;

	if (HAL_CAN_ConfigFilter(&hcan1, &CAN1_Filter) != HAL_OK)
	{
	  Error_Handler();
	}

	if (HAL_CAN_Start(&hcan1) != HAL_OK)
	{
	  Error_Handler();
	}
#ifdef USE_CAN_INTERRUPT
	if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY | CAN_IT_ERROR) != HAL_OK)
	{
	  Error_Handler();
	}
#endif
}

void CAN_SendTxMessage(void)
{
	TxHeader.StdId = 0x11;
	TxHeader.RTR = CAN_RTR_DATA;
	TxHeader.IDE = CAN_ID_STD;
	TxHeader.DLC = 2;
	TxHeader.TransmitGlobalTime = DISABLE;
	TxData[0] = 0xCA;
	TxData[1] = 0xFE;

	if (HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox) != HAL_OK)
	{
	  Error_Handler();
	}
}

#ifdef USE_CAN_INTERRUPT
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	// currently not used as we use polling for test purposes
	if(hcan == &hcan1)
	{
		if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
		{
		  Error_Handler();
		}
		CAN_MsgRdy = true;
	}
}

void CAN_CheckMsg(void)
{
	if(CAN_MsgRdy)
	{
		CAN_MsgRdy = false;
		if(RxHeader.StdId == 0x11)
		{
			if((RxData[0]<<8 | RxData[1]) == 0xCAFE)
			{
				led1_on();
				HAL_Delay(100);
				led1_off();
				HAL_Delay(100);
			}
		}
	}
}

#else // Polling
void CAN_ReceiveMessage(void)
{
	while(HAL_CAN_IsTxMessagePending(&hcan1, TxMailbox));
	while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) != 3);

	HAL_Delay(20);

	if (HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) != 1)
	{
	  Error_Handler();
	}

	if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
	{
	  Error_Handler();
	}

	if(RxHeader.StdId == 0x11)
	{
		if((RxData[0]<<8 | RxData[1]) == 0xCAFE)
		{
			led1_on();
			HAL_Delay(500);
			led1_off();
			HAL_Delay(500);
		}
	}
}
#endif

 

 

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
Louis00
Associate

Thanks to both of you, both answers were very helpful!

With the bit timing provided by @SofLit, the TX no longer failed. With the code from @Karl Yamashita , the reception also worked.