2025-02-24 5:26 AM
I am trying to use my STM32F429IGT6 CAN to receive some data from the host computer. The data is basically 4 16-bit unsigned integers (8 bytes in total), the message ID is 0x16 and uses the 11-bit standard ID format. The host computer sends messages to the bus in a 2ms cycle.
On the STM32 part, I enabled CAN1 and used the interrupt function to receive and process the data. However, most of the time, the STM32 does not show any CAN messages coming, and the HAL_CAN_GetRxFifoFillLevel() function always returns 0. This makes me really confused.
Below is the initialization code in my can.c file. My CAN1 is mounted on the APB1 bus with a frequency of 45Mhz, and the CAN transmission rate of the host computer and STM32 is 500kbps.
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_8TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_6TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = ENABLE;
hcan1.Init.AutoRetransmission = ENABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
CAN_FilterTypeDef sFilterConfig;
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_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END CAN1_Init 2 */
}
void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(canHandle->Instance==CAN1)
{
/* USER CODE BEGIN CAN1_MspInit 0 */
/* USER CODE END CAN1_MspInit 0 */
/* CAN1 clock enable */
__HAL_RCC_CAN1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**CAN1 GPIO Configuration
PA11 ------> CAN1_RX
PA12 ------> CAN1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* CAN1 interrupt Init */
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
/* USER CODE BEGIN CAN1_MspInit 1 */
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
/* USER CODE END CAN1_MspInit 1 */
}
}
and this is my interrupt funciton:
CAN_RxHeaderTypeDef RxHeader;
uint16_t RxData[4];
uint16_t canbuf[4]; /* CAN rx dest */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, (uint8_t *)RxData) == HAL_OK)
{
for (int i = 0; i < RxHeader.DLC / 2; i++)
{
canbuf[i] = RxData[i];
}
}
}
So far, I have tried the following steps:
1. Confirm that the 120 ohm terminal resistors on both sides of the CAN have been added. The CAN cable is a standard twisted pair with a DB9 interface and is well connected.
2. The CAN configuration of the host computer is in send mode, using the standard 11-bit ID mode, the ID value is 18 (0x12), the data segment is 8 bytes, the baud rate is 500kbps (consistent with STM32), and the message transmission rate is 2ms once.
3. I tried to monitor the ESR register (error register) of CAN1 in real time through debug mode, but no abnormalities were found. All flag bits look normal (all 0).
4. I confirmed that I have called the HAL_CAN_Start() and HAL_CAN_ActivateNotification() functions normally.
The one thing I have left to do is to test the CAN message levels sent by the host computer through a logic analyzer (the analyzer is on the way), but I think the possibility of an error in the host computer is low.
Looking forward to responses from people who have had similar problems or professionals.
Solved! Go to Solution.
2025-02-26 11:01 AM - edited 2025-02-27 12:48 AM
Hello,
If you are able to receive CAN frames with a very simple project with the same hardware, this is a good sign and it confirms that it's not a hardware issue.
What I suggest is to comment out all the code not related to the CAN in your "LVGL project" and test. If it doesn't work replace the CAN configuration with the code you've written with the simple project. If it does work, it will be a bit tricky to debug. As I don't have your board and your project I cannot run the test. But think about a conflict of GPIOs. It may due to some code in your LVGL project that modified the CAN pins configuration. Check also if the CAN RXFIFO NVIC is enabled. Check also the interrupt priorities. For example increase the preemption of the CAN RXFIFO NVIC.
2025-02-24 6:40 AM
Hello,
1- Could you please share your ioc file and your main.c?
2- Could you please share the schematics part showing the STM32 and the CAN transceiver?
2025-02-24 6:43 AM - edited 2025-02-24 6:43 AM
What now, can or cannot ?
;) Couldn't resist, sorry...
So here's some serious and hopefully helpful advice:
Once upon a time the HAL examples were missing some global filter enable, maybe that's it?
Here's what I found in my notes - but that's for H7 FDCAN:
/* LISTENING:
* if global reject is NOT turned on with HAL_FDCAN_ConfigGlobalFilter(),
* then all messages are received in
* RX FIFO 0
*/
// after all the inits, before CAN start:
/* Configure global filter to reject all non-matching frames */
HAL_FDCAN_ConfigGlobalFilter(phCan, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE);
I recommend the following:
- use a STM32 UART and printf some debug info to a terminal
- reduce the host transmit rate for easier debugging
- connect an oscilloscope, check the incoming messages, look for the ACKNOWLEDGE bit by the STM32
- transmit some messages from STM32, just to check bit timings (trigger that by UART input)
2025-02-24 6:50 AM
@LCE wrote:
Here's what I found in my notes - but that's for H7 FDCAN:
/* LISTENING: * if global reject is NOT turned on with HAL_FDCAN_ConfigGlobalFilter(), * then all messages are received in * RX FIFO 0 */ // after all the inits, before CAN start: /* Configure global filter to reject all non-matching frames */ HAL_FDCAN_ConfigGlobalFilter(phCan, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE);
@LCE unfortunately, bxCAN and FDCAN have no similar implementation and there is no similar rejection mechanism on STM32F4 (bxCAN) ;)
2025-02-24 2:36 PM
Try testing in loop back mode. Have the STM32 transmit the same CAN message as the PC.
If you receive correctly, then it's probably a hardware/connection issue. Show a drawing/schematic of how everything is connected.
If you don't receive a message, then something in your CAN initialize stage/filter may not be correct. You have showed zero code, so no telling what could be wrong.
2025-02-24 10:41 PM
Ah sure.
Please allow me to provide you with more information: my project is simply to get some data from the host computer and then display it on the screen through the LVGL library. The peripherals used include SDRAM, an LTDC screen and some less important ICs (such as IO expansion). These peripherals are provided with ready-made driver files, so I did not initialize them manually in CubeMX, but directly used the functions provided by the driver files.
For the schematic diagram,: The CAN of the STM32F4 is connected to the SIT1042T/TPT1051V transceiver chip through the setting of P9 (a jumper cap), and then connected to the external CAN bus through the terminal block. CAN and USB share PA11 and PA12, so they cannot be used at the same time, and I have confirmed that the USB function is disabled and the jumper cap has been correctly connected externally.
Based on other people's advice, I did some more testing on my project this morning:
1. I disabled the interrupt function and used polling to get CAN messages in the while(1) loop in main.c. The corresponding function is:
uint8_t can_receive_msg(uint32_t id, uint8_t *buf)
{
if (HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) == 0)
{
return 0;
}
if (HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, buf) != HAL_OK)
{
return 0;
}
if (RxHeader.StdId != id || RxHeader.IDE != CAN_ID_STD || RxHeader.RTR != CAN_RTR_DATA)
{
return 0;
}
return RxHeader.DLC;
}
Then, I enabled the Loopback mode to confirm that CAN can send and receive data normally, stably and for a long time in Loopback mode
2. I used an oscilloscope to monitor the signal on the bus, connecting the X end of the oscilloscope to CANH and the Y end to CANL. The situation is very interesting:
2a: Without connecting the cable, start the host computer and start CAN transmission, the waveform on the bus is normal; then, connect the CAN cable to the STM32 board that has been powered on, the signal waveform on the CAN cable disappears, and even after unplugging the cable from the STM32 board, the signal cannot be reset
2b: Start the host computer and start CAN transmission, then connect the cable to the STM32 board that has not been powered on, the CAN bus signal displays normally; keep the cable connected, and then power on the STM32 board, the STM32 can read the data on the CAN normally and display it on the screen, but about 10s-45s later (this time is very random), the signal on the CAN bus suddenly disappears and cannot be restored
2c: If you connect the cable first, then power on the STM32 board, and then start the host computer and start CAN transmission, then the STM32 will only be able to read the first data frame, and then the bus signal disappears immediately and cannot be restored.
2025-02-24 10:42 PM
Thanks for the reply. I will try to add some more debug info and use UART to read them.
2025-02-24 10:48 PM
Yeah I've used the loopback mode to confirm that CAN can send and receive data normally, stably and for a long time. I did consider it was an issue with the initialization or the filter, but after I tested it, I became even more confused. Allow me to copy to you the answer I just gave to another helper:
I used an oscilloscope to monitor the signal on the bus, connecting the X end of the oscilloscope to CANH and the Y end to CANL. The situation is very interesting:
2a: Without connecting the cable, start the host computer and start CAN transmission, the waveform on the bus is normal; then, connect the CAN cable to the STM32 board that has been powered on, the signal waveform on the CAN cable disappears, and even after unplugging the cable from the STM32 board, the signal cannot be reset
2b: Start the host computer and start CAN transmission, then connect the cable to the STM32 board that has not been powered on, the CAN bus signal displays normally; keep the cable connected, and then power on the STM32 board, the STM32 can read the data on the CAN normally and display it on the screen, but about 10s-45s later (this time is very random), the signal on the CAN bus suddenly disappears and cannot be restored
2c: If you connect the cable first, then power on the STM32 board, and then start the host computer and start CAN transmission, then the STM32 will only be able to read the first data frame, and then the bus signal disappears immediately and cannot be restored.
2025-02-24 11:06 PM
These tests sound like it's a wiring / hardware problem, supported by the working loopback mode.
Maybe some CANH / CANL / GND wires reversed? Ground loops?
Oscilloscope:
What is X and Y? There's a special XY-mode, but that wouldn't make sense here.
Make sure you don't connect the scope probe GND to CANH or CANL - unless you are using a scope which is battery powered (and has no other ground connections) or a scope with differential inputs. Both are not really the regular kind, so maybe you killed the CAN bus by making it single-ended with the scope GND...
So, for monitoring the differential CAN bus with a regular scope, use 2 channels - but maybe that's what you meant with X & Y... :D
Anyway, as your CAN transceiver is not isolated, maybe you have a ground loop problem? Which might get worse with another grounded device (the scope). But if all the devices are on your desk, same power source, no long cables, this is probably not the problem.
2025-02-24 11:10 PM - edited 2025-02-24 11:15 PM
Hello,
Probe on Rx pin of the transceiver instead of CAN_H and CAN_L. And see if you see any CAN activity on it.
And please share your main.c file.
Another remark. I'm not sure which versions of the transceiver you have on the board? the VIO pin version? if not, the transceiver seems to be not suitable as VIHmin = 3.5V > VDD: