2020-05-26 08:15 AM
Hello,
I have a STM32G431KB on a custom PCB and got the CAN bus to work. The only problem I have is that the TX FIFO is always filling up and the bus stops after 127 errors.
The workaround I have is to abort the TX request.
/* Add message to Tx FIFO */
if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) > 0)
{
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &FDCAN1_TxHeader, FDCAN1_TxData) != HAL_OK) {
Error_Handler();
}
}
else
{
uint32_t txFifoRequest = HAL_FDCAN_GetLatestTxFifoQRequestBuffer(&hfdcan1);
if (HAL_FDCAN_IsTxBufferMessagePending(&hfdcan1, txFifoRequest)) {
HAL_FDCAN_AbortTxRequest(&hfdcan1, txFifoRequest);
}
}
This however doesn't feel like a proper solution. How can I correctly implement the use of the TX FIFO without aborting messages?
Solved! Go to Solution.
2025-02-05 02:36 AM
It is almost 5 years had passed, but I'll leave a comment in case someone would bump into this topic.
@PKavv.1wrote:
> TX FIFO is always filling up and the bus stops after 127 errors
It is correct behavior called BusOff, when there is "nobody" on the bus to receive a message. I assume that CAN controller has AutoRetransmission enabled, so it will keep trying to send message until BusOff occurred. Although FDCAN controller can't leave BusOff state by itself, so MCU need to handle that. Register `HAL_FDCAN_ErrorStatusCallback` via `HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0)`
during fdcan initialization. There was other topic with example, but here is the copy of the callback itself:
static void check_can_bus(FDCAN_HandleTypeDef *hfdcan)
{
FDCAN_ProtocolStatusTypeDef protocolStatus = {};
HAL_FDCAN_GetProtocolStatus(hfdcan, &protocolStatus);
if (protocolStatus.BusOff) {
CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_INIT);
}
}
void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
if (hfdcan == &hfdcan1) {
if ((ErrorStatusITs & FDCAN_IT_BUS_OFF) != RESET) {
check_can_bus(hfdcan);
}
}
}
IIRC, doing that will drop frames already in the queues, but it is fine, because in other case they would become outdated. However consider disabling AutoRetransmission, because there is still a chance for a frame to become outdated. By doing that frame is dropped if CAN controller failed to send it due to any problem, but such approach require complex handling via `HAL_FDCAN_TxBufferCompleteCallback`.
> The workaround I have is to abort the TX request.
That is legal solution, one of actually. Don't know what is Your app is doing, but if it is, for example, data from some sensor, then it shouldn't be sent over CAN, if nobody would receive it. Also, as @Karl Yamashita suggested, it make sense to implement sort of a handshake between nodes. If Jetson is the main one, then it can manage registration and so on.
@seppeltronics_vwrote:
> how to set up the CAN-Controller properly
STM32CubeIDE should have done all set up properly by default. If TX is working for You then everything is set up correctly.
> I do not get any RX Callback
Try to use `HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, data)` from the main loop (pay attention to correct fdcan handler). To use RX callback one needed to be registered and enabled.
Cheers.
2020-05-26 10:00 AM
If the TX FIFO is full, you need to wait for it to empty before adding more data. Can't send more data than the bus allows.
2020-05-28 12:12 AM
This PCB is connected to another embedded system, the Nvidia Jetson TX2. How can I make sure that the TX FIFO won't be completely filled before the Jetson has booted up to acknowledge CAN messages?
I would like to know how to solve this without altering the interval of the sent messages (currently at 10Hz). If I add a second buffer, I will introduce a delay that can not go away if the interval stays the same.
2020-05-28 03:48 AM
> How can I make sure that the TX FIFO won't be completely filled before the Jetson has booted up to acknowledge CAN messages? I would like to know how to solve this without altering the interval of the sent messages (currently at 10Hz).
If there are no guarantees on how long it takes to boot up, you can't. The buffer is not infinite.
If you know how long it takes to boot up, you can calculate whether or not it will work based on your rate and the buffer size.
2020-05-28 04:03 AM
If you know how long it takes to boot up, you can calculate whether or not it will work based on your rate and the buffer size.
I did check out the memory management (FDCAN_MsgRamAddressTypeDef ) of the CAN bus, but I can not figure out how to properly set it up, as it requires to use addresses with an offset.
Currently the TX FIFO can hold 3 messages without modifying anything. FDCAN_MsgRamAddressTypeDef has the parameter TxFIFOQSA, which specifies the Tx FIFO/Queue starting address. I am not sure if this is directly linked to the amount of messages that can be stored in the TX FIFO.
2020-06-05 02:22 AM
You can use the following function to check for errors:
FDCAN_ProtocolStatusTypeDef psr;
/* get actual psr value */
HAL_FDCAN_GetProtocolStatus(fdcanHandle, &psr);
Inside psr (Protocol Status Register) you can find the register LEC (Last Error Code). With the value you can check for every error on the physical bus:
/** @defgroup FDCAN_protocol_error_code FDCAN protocol error code
* @{
*/
#define FDCAN_PROTOCOL_ERROR_NONE ((uint32_t)0x00000000U) /*!< No error occurred */
#define FDCAN_PROTOCOL_ERROR_STUFF ((uint32_t)0x00000001U) /*!< Stuff error */
#define FDCAN_PROTOCOL_ERROR_FORM ((uint32_t)0x00000002U) /*!< Form error */
#define FDCAN_PROTOCOL_ERROR_ACK ((uint32_t)0x00000003U) /*!< Acknowledge error */
#define FDCAN_PROTOCOL_ERROR_BIT1 ((uint32_t)0x00000004U) /*!< Bit 1 (recessive) error */
#define FDCAN_PROTOCOL_ERROR_BIT0 ((uint32_t)0x00000005U) /*!< Bit 0 (dominant) error */
#define FDCAN_PROTOCOL_ERROR_CRC ((uint32_t)0x00000006U) /*!< CRC check sum error */
#define FDCAN_PROTOCOL_ERROR_NO_CHANGE ((uint32_t)0x00000007U) /*!< No change since last read */
2023-04-04 08:22 AM
Hello @PKavv.1 ,
have you been able to solve the issue and get mor information on how to set up the CAN-Controller properly?
I use a STM32G474, TX works, but I do not get any RX Callback and I also tumbled over the RAM confic and there should be s asetting for the queue if it is full(overwrite the old or ignore the new frame)
There is a presenatation, but I could not find any information on how to use the described functionalities: STM32G4-Peripheral-Flexible_Datarate_Controller_Area_Network_FDCAN.pdf I could also not figure out ho wrote it.
Best Regards, Seppel
2023-04-04 04:36 PM
@PKavv.1 Why don't you have the Jetson send a SOH message when it is up and running? Then the STM32G431KB can start sending CAN messages.
2025-02-05 02:36 AM
It is almost 5 years had passed, but I'll leave a comment in case someone would bump into this topic.
@PKavv.1wrote:
> TX FIFO is always filling up and the bus stops after 127 errors
It is correct behavior called BusOff, when there is "nobody" on the bus to receive a message. I assume that CAN controller has AutoRetransmission enabled, so it will keep trying to send message until BusOff occurred. Although FDCAN controller can't leave BusOff state by itself, so MCU need to handle that. Register `HAL_FDCAN_ErrorStatusCallback` via `HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0)`
during fdcan initialization. There was other topic with example, but here is the copy of the callback itself:
static void check_can_bus(FDCAN_HandleTypeDef *hfdcan)
{
FDCAN_ProtocolStatusTypeDef protocolStatus = {};
HAL_FDCAN_GetProtocolStatus(hfdcan, &protocolStatus);
if (protocolStatus.BusOff) {
CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_INIT);
}
}
void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
if (hfdcan == &hfdcan1) {
if ((ErrorStatusITs & FDCAN_IT_BUS_OFF) != RESET) {
check_can_bus(hfdcan);
}
}
}
IIRC, doing that will drop frames already in the queues, but it is fine, because in other case they would become outdated. However consider disabling AutoRetransmission, because there is still a chance for a frame to become outdated. By doing that frame is dropped if CAN controller failed to send it due to any problem, but such approach require complex handling via `HAL_FDCAN_TxBufferCompleteCallback`.
> The workaround I have is to abort the TX request.
That is legal solution, one of actually. Don't know what is Your app is doing, but if it is, for example, data from some sensor, then it shouldn't be sent over CAN, if nobody would receive it. Also, as @Karl Yamashita suggested, it make sense to implement sort of a handshake between nodes. If Jetson is the main one, then it can manage registration and so on.
@seppeltronics_vwrote:
> how to set up the CAN-Controller properly
STM32CubeIDE should have done all set up properly by default. If TX is working for You then everything is set up correctly.
> I do not get any RX Callback
Try to use `HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, data)` from the main loop (pay attention to correct fdcan handler). To use RX callback one needed to be registered and enabled.
Cheers.
2025-02-05 10:44 AM
Unfortunately the journey for me ended back in 2020, so I couldn't complete the project, someone else took over.
Thanks for the suggestions back in 2023 and even now, hopefully helping someone in the future who stumbles on the same issue as I did (nearly) five years ago.