Skip to main content
Visitor II
February 24, 2025
Question

STM32F429: CAN cannot receive messages

  • February 24, 2025
  • 6 replies
  • 3372 views

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.

    This topic has been closed for replies.

    6 replies

    Technical Moderator
    February 24, 2025

    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?

     

    most1maAuthor
    Visitor II
    February 25, 2025

    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.

    Graduate II
    February 24, 2025

    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)

     

    Technical Moderator
    February 24, 2025

    @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) ;)

    Graduate II
    February 24, 2025

    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.

    most1maAuthor
    Visitor II
    February 25, 2025

    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.


     

    Graduate II
    February 25, 2025

    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.

    most1maAuthor
    Visitor II
    February 25, 2025

    Sorry I didn't make it clear. The X and Y I mentioned are actually channels 1 and 2. When testing, since my CAN cable did not lead out GND, I simply connected CANH to channel 1 and CANL to channel 2. The oscilloscope probe was not connected to anything else.

    Speaking of this, I do think the signal returned by my oscilloscope is a bit strange. I think the CAN bus should be a differential signal, but the actual signal is very strange...
    IMG_0828.JPG

    Graduate II
    February 25, 2025

    @most1ma wrote:

    Sorry I didn't make it clear. The X and Y I mentioned are actually channels 1 and 2. When testing, since my CAN cable did not lead out GND, I simply connected CANH to channel 1 and CANL to channel 2. The oscilloscope probe was not connected to anything else.

    Speaking of this, I do think the signal returned by my oscilloscope is a bit strange. I think the CAN bus should be a differential signal, but the actual signal is very strange...
    IMG_0828.JPG


    You don't have a signal on channel 2. So it's a hardware/wiring issue. Without both differential signals present, you won't get any signal going to the CAN Rx of the STM32.

    Also, other than the PC and STM32, are there any other CAN nodes connected? 

    Technical Moderator
    February 25, 2025

    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:

    mALLEm_0-1740467629613.png

     

    most1maAuthor
    Visitor II
    February 25, 2025

    Sorry i forgot it. See the attach file please.

    Technical Moderator
    February 25, 2025

    Hello @most1ma ,

    The main doesn't contain the CAN code just only can_receive_msg() call and this doesn't help.

    In order to avoid unnecessary ping pongs:

    1- Probe the Rx pin from SIT1042.

    2- Check if you have the VIO pin version of the transceiver:

    mALLEm_1-1740468009560.png

    Not related directly to the reception but it will be a problem to send the acknowledgement bit after reception.

    3- Please clarify this statement:

    " I did consider it was an issue with the initialization or the filter, but after I tested it, I became even more confused."

    Did you succeed the loopback mode or not?

    Graduate II
    February 26, 2025

    Your time seg 1 and 2 are pretty close to each other. The sampling point should be in the high 80s

    Your values might be closer to ~30

     

    try these values

     

    KarlYamashita_0-1740545457963.png

     

    most1maAuthor
    Visitor II
    February 26, 2025

    Good news, I tried to recreate a new project, where only CAN1 and USART1 (for sending debug data) were enabled, and it seems that the STM32 can normally and stably receive the data returned from the host computer.

    In my original project with LVGL integrated, CAN could not be received normally even after trying the new sampling point. There must be something in my code that prevents CAN from running normally.

    I am troubleshooting the problem step by step, maybe you have any clues about this phenomenon?

    most1maAuthor
    Visitor II
    February 26, 2025

    After a night of debugging, I finally located the problem in the initialization function of my LTDC screen. When I disabled everything except CAN and UART (including LVGL), whenever lcd_init() was called, CAN would definitely fail after a while of receiving. If I commented out lcd_init() and did not initialize the LTDC screen, everything worked fine.

    The driver file for the LTDC screen was obtained from the screen manufacturer, which included some color filling functions and the DMA2D driver. I tried to change the priority of the DMA2D interrupt and reduce the main frequency of the LTDC screen, but nothing seemed to work. The original version of this driver was written, compiled and run under Keil. Since I was familiar with IAR EW, I converted it to an IAR EW version and added it to my project file. But obviously, something went wrong during the conversion process, and I didn't know what it was.Unfortunately, my development experience is not enough for me to answer this strange phenomenon. Maybe you have some ideas about this phenomenon?

    I spent a little time porting my project file back to the version adapted for Keil, and now it works fine, and LVGL and CAN can run perfectly well. Although the previous problem has not been fundamentally solved, at least I can continue working now. 

    In any case, I want to thank you for your help - you, Mr. Karl Yamashita, Mr. LCE and other partners. In order to save resources, I will not reply to them one by one. I hope they can all see this message. It is your wisdom that helps this community grow better and also helps STM32 become one of the best MCUs. Thank you again for your help!

    Technical Moderator
    February 27, 2025

    Hello @most1ma 

    Thank your for your valuable feedback :).


    @most1ma wrote:

    In any case, I want to thank you for your help - you, Mr. Karl Yamashita, Mr. LCE and other partners. In order to save resources, I will not reply to them one by one. 


    In next time you can tag the contributors using '@ ' so they can get the notification and read your message.

    And thank you for choosing STM32 MCU.