2024-07-09 06:51 AM
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
Solved! Go to Solution.
2024-07-09 08:10 AM - edited 2024-07-09 08:13 AM
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:
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.
2024-07-09 08:10 AM - edited 2024-07-09 08:13 AM
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:
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.
2024-07-09 02:59 PM
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
2024-07-10 12:04 AM
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.