Skip to main content
Visitor II
September 12, 2025
Solved

STM32H745I-DISCO – CAN TXFIFO Buffer Full Issue

  • September 12, 2025
  • 5 replies
  • 987 views

Post edited by ST moderator to be inline with the community rules especially with the code sharing. In next time please use </> button to paste your code. Please read this post: How to insert source code.

Hi everyone,

I am working on Classic CAN communication using the STM32H745I-Discovery board with FDCAN2.
My target CAN configuration is 500 Kbps nominal baud rate with a 16 MHz clock.

Below is my initialization code:

static void MX_FDCAN2_Init(void)
{
hfdcan2.Instance = FDCAN2;
hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan2.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan2.Init.AutoRetransmission = ENABLE;
hfdcan2.Init.TransmitPause = DISABLE;
hfdcan2.Init.ProtocolException = ENABLE;

// Timing config: 500 Kbps @ 16 MHz
hfdcan2.Init.NominalPrescaler = 1;
hfdcan2.Init.NominalSyncJumpWidth = 1;
hfdcan2.Init.NominalTimeSeg1 = 23;
hfdcan2.Init.NominalTimeSeg2 = 8;

hfdcan2.Init.DataPrescaler = 1;
hfdcan2.Init.DataSyncJumpWidth = 1;
hfdcan2.Init.DataTimeSeg1 = 1;
hfdcan2.Init.DataTimeSeg2 = 1;

hfdcan2.Init.MessageRAMOffset = 0;
hfdcan2.Init.StdFiltersNbr = 1;
hfdcan2.Init.ExtFiltersNbr = 0;
hfdcan2.Init.RxFifo0ElmtsNbr = 1;
hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.TxFifoQueueElmtsNbr = 1;
hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;

if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK) Error_Handler();

// Configure filter (accept all standard IDs)
FDCAN_FilterTypeDef filter;
filter.IdType = FDCAN_STANDARD_ID;
filter.FilterIndex = 0;
filter.FilterType = FDCAN_FILTER_MASK;
filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
filter.FilterID1 = 0x000;
filter.FilterID2 = 0x7FF;
HAL_FDCAN_ConfigFilter(&hfdcan2, &filter);

HAL_FDCAN_Start(&hfdcan2);

// Tx header
txHeader.Identifier = 0x123;
txHeader.IdType = FDCAN_STANDARD_ID;
txHeader.TxFrameType = FDCAN_DATA_FRAME;
txHeader.DataLength = FDCAN_DLC_BYTES_8;
txHeader.BitRateSwitch = FDCAN_BRS_OFF;
txHeader.FDFormat = FDCAN_CLASSIC_CAN;
txHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
txHeader.MessageMarker = 0;
}
And the send function:
HAL_StatusTypeDef CAN_Send(uint8_t* data)
{
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &txHeader, data) == HAL_OK)
{ 

 return HAL_OK;
}
else
{
 return HAL_ERROR;
}
}

Issue:

The first few CAN frames transmit successfully.

After that, the TXFIFO becomes full and no further frames are sent.

Sometimes it transmits several messages before stopping, sometimes only one or two.

 

What I tried so far:

  1. Increased TxFifoQueueElmtsNbr (tried more than 1).

  2. Verified hardware connections and ensured 120Ω termination resistor is present.

  3. Tested the receiver side (looped with another working board), and confirmed reception is fine there.

  4. Tried with both AutoRetransmission enabled/disabled.

  5. Verified the 500 Kbps baud rate configuration with 16 MHz clock.

Still, the issue persists.

Any guidance or working examples would be very helpful.

Thanks!

 

    This topic has been closed for replies.
    Best answer by mƎALLEm

    Hello,

    I tested your project with a little modification and there is no issue. I just connected another CAN node which is a NUCLEO-F767 board (CAN2.0) + a transceiver, and the latter is receiving the CAN frames from STM32H745I-DISCO without issues.

    These are the frames send each 100ms:

    mALLEm_0-1758641742972.png

    This screenshot spots one frame:

    mALLEm_1-1758641807647.png

    A screenshot for IAR of the receiving CAN frame (F767 side) showing the Rx content changing in live (only data 0 and data 7 are changing):

    mALLEm_2-1758641895245.png

    Attached the projects that I used for the test.

    Now, I'm pretty sure it's not a software issue and you have a hardware issue. Either with the transceiver or the wiring or something else. Maybe you swapped CAN_H and CAN_L? need to check.

    Hope that helps.

     

    5 replies

    Graduate II
    September 12, 2025

    Are you queuing your CAN messages? Because if you send a bunch of messages and the Tx buffer is full, then you lose those messages. By using a queue, you can send those messages once the Tx buffer is available.

     

    Also, use the </> to post code so that it's formatted and readable.

    SumithraAuthor
    Visitor II
    September 13, 2025

    Hi,
    Thanks for your reply.

    Right now I’m only using HAL_FDCAN_AddMessageToTxFifoQ() directly, so when the hardware Tx FIFO gets full I lose messages. I understand now that I should add a software queue on top and retry sending when space becomes available.

    However, in my case I’m transmitting only one CAN frame every 1 second. Since a CAN frame takes just a few hundred microseconds on the bus, the Tx FIFO should normally be free by the time the next frame is sent, correct?

    Graduate II
    September 13, 2025

    What I tried so far:

    Tested the receiver side (looped with another working board), and confirmed reception is fine there.


    It's unclear what is happening. So, is this other working board continuously working and your main board is transmitting without getting full? What is the other node that you're trying to transmit to that is causing your main board to get full?

     

     

    SumithraAuthor
    Visitor II
    September 14, 2025

    I’m using an Arduino Nano on the receiver side. I’ve tested the Nano as the receiver with different STM32 MCU board, and it is receiving the data without any errors

    Technical Moderator
    September 17, 2025

    What is the clock source of your FDCAN? Did you set HSE as main clock source for FDCAN?

    Graduate
    September 17, 2025

    After start fdcan, the interrupt should be start
    企业微信截图_17580915249987.png

    SumithraAuthor
    Visitor II
    September 18, 2025

    I haven’t enabled any interrupts there. Do I still need to mention it?

    Graduate
    September 25, 2025

    What are you use to receive the data? The can bus analyzer? if in this case you can check the voltage of it, because i find that it will not receive data in many case when the voltage is lower than 5V.

    Explorer
    September 22, 2025

    > Issue:
    > The first few CAN frames transmit successfully.

    No you don't.

    Read the CAN specification, you cannot force a transmission on the CAN bus.
    First, you can add a message to a queue (or Tx buffer), but the CAN peripheral only transmits it when the bus is free.
    And second, the CAN peripheral will retry until the transmission is successful (or it turns itself off).

    I am 100% sure your transmission attempts fail, because the bus is not set up correctly.
    Check with a scope, and check the transmit and receive error counters (TEC, REC) in the CAN peripheral after each transmission attempt.
    After a defined number of errors, the device goes first into passive mode, and then into "bus-off" mode.

    SumithraAuthor
    Visitor II
    September 23, 2025

    I see your point. In my case, transmissions sometimes succeed, but not always. Could you help me pinpoint what part of the setup I should correct first?

    Explorer
    September 23, 2025

    What is your second device on the bus ?
    CAN does not work with only one node. A successful transmission requires the acknowledge from another participant.
    This could be a CAN dongle for a PC, if you configure it correctly (proper baudrate, and not in listen-only mode).

    Check the physical signal, you could use a scope for that.
    But if you need to deal with CAN more than once, get a PC CAN dongle (with appropriate software). I suppose the cheapest variant is a Raspberry Pi with a CAN shield and open source tools : https://github.com/ajouatom/canbus-tools

    And you can monitor the success (or failure) of a transmission attempt in the debugger.
    The TEC and REC counters are visible in the CAN register interface. If they go up after each transmission attempt, something is wrong.

    If you have another STM32 board as second CAN device, you could connect the CAN signals (CAN_Tx, CAN_Rx and GND) directly, bypassing the transceivers. Rx/Tx would have to be crossed, then.
    The usualy precautions for such direct connections between different boards apply ...