2025-08-19 7:57 PM - last edited on 2025-08-21 2:00 AM by mƎALLEm
Hello @D.Botelho @mƎALLEm
I had an issue of ThreadX and FDCAN transmit as below.
I use the stm32g474 and config a threadx and fdcan with stm32cubemx, so far it works well.
but when i add some fdcan transmit code, it comes strangely.
the code as below
void appThread2(ULONG thread_input)
{
while(1)
{
if(fdcan1_RXFlag == 1)
{
fdcan1_RXFlag = 0; // Clear the receive flag
for(int i = 0; i < 8; i++)
{
fdcan1TxData[i] = fdcan1RxData[i]+1; // Copy received data to transmit buffer
}
my_FDCAN1_Transmit(fdcan1TxData); // Echo back the received data
printf("FDCAN1 Received data: ");
for (int i = 0; i < 8; i++)
{
printf("%02X ", fdcan1RxData[i]);
}
printf("\r\n");
}
// // 发送 0x12
fdcan1TxHeader.Identifier=0x012;
fdcan1TxData[0] = (dis_sensor_data1.dis1 >> 0) & 0xff;
fdcan1TxData[1] = (dis_sensor_data1.dis1 >> 8) & 0xff;
fdcan1TxData[2] = (dis_sensor_data1.dis2 >> 0) & 0xff;
fdcan1TxData[3] = (dis_sensor_data1.dis2 >> 8) & 0xff;
fdcan1TxData[4] = (dis_sensor_data1.dis3 >> 0) & 0xff;
fdcan1TxData[5] = (dis_sensor_data1.dis3 >> 8) & 0xff;
fdcan1TxData[6] = (dis_sensor_data1.dis4 >> 0) & 0xff;
fdcan1TxData[7] = (dis_sensor_data1.dis4 >> 8) & 0xff;
my_FDCAN1_Transmit(fdcan1TxData);
// // 发送 0x13
fdcan1TxHeader.Identifier=0x013;
fdcan1TxData[0] = (dis_sensor_data2.dis1 >> 0) & 0xff;
fdcan1TxData[1] = (dis_sensor_data2.dis1 >> 8) & 0xff;
fdcan1TxData[2] = (dis_sensor_data2.dis2 >> 0) & 0xff;
fdcan1TxData[3] = (dis_sensor_data2.dis2 >> 8) & 0xff;
fdcan1TxData[4] = (dis_sensor_data2.dis3 >> 0) & 0xff;
fdcan1TxData[5] = (dis_sensor_data2.dis3 >> 8) & 0xff;
fdcan1TxData[6] = (dis_sensor_data2.dis4 >> 0) & 0xff;
fdcan1TxData[7] = (dis_sensor_data2.dis4 >> 8) & 0xff;
my_FDCAN1_Transmit(fdcan1TxData);
// // 发送 0x14
fdcan1TxHeader.Identifier=0x014;
fdcan1TxData[0] = sbusHandle.isExist; // 遥控器工作状态
fdcan1TxData[1] = sys_status; // 系统状态
fdcan1TxData[2] = (encoder_data1.counter >> 0) & 0xff;
fdcan1TxData[3] = (encoder_data1.counter >> 8) & 0xff;
fdcan1TxData[4] = (encoder_data2.counter >> 0) & 0xff;
fdcan1TxData[5] = (encoder_data2.counter >> 8) & 0xff;
fdcan1TxData[6] = encoder_data1.direction;
fdcan1TxData[7] = encoder_data1.direction;
my_FDCAN1_Transmit(fdcan1TxData);
// 发送 0x15
fdcan1TxHeader.Identifier=0x015;
fdcan1TxData[0] = RS485_RXData[0]+0x0A;
fdcan1TxData[1] = RS485_RXData[1];
fdcan1TxData[2] = RS485_RXData[2];
fdcan1TxData[3] = RS485_RXData[3];
fdcan1TxData[4] = RS485_RXData[4];
fdcan1TxData[5] = RS485_RXData[5];
fdcan1TxData[6] = RS485_RXData[6];
fdcan1TxData[7] = RS485_RXData[7];
my_FDCAN1_Transmit(fdcan1TxData);
tx_thread_sleep(20); // Sleep for 20 ticks
}
}
I use a thread to send can message with a peroid of 20ms.
the CAN message ID is 0x12, 0x13, 0x14, 0x15.
as the code above, when i compiled the code and programming to mcu, just after 1s, the system stack and Error_Handler() called. when I comment out 0x15 CAN transimt, only transmit 0x12, 0x13, 0x14, it works well.
why?
I have increased the thread_stack of appThread2, but it seems the issue still exists.
how should i do to fix this issue?
Thanks,
dqsh06
2025-08-20 12:55 PM
You forgot to show code for my_FDCAN1_Transmit
2025-08-20 5:50 PM
OK, the code of my_FDCAN1_Transmit is as below:
void my_FDCAN1_Transmit(uint8_t *TxData)
{
// 发送数据
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &fdcan1TxHeader, TxData) != HAL_OK)
{
// usb_printf("HAL_FDCAN_AddMessageToTxFifoQ failed\r\n");
printf("HAL_FDCAN_AddMessageToTxFifoQ failed\r\n");
Error_Handler();
}
}
and just as your minds, the function
why call HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &fdcan1TxHeader, TxData) failed for ID 0x15?
Thanks.
2025-08-20 6:15 PM - edited 2025-08-20 6:17 PM
Because you're trying to send 5 CAN messages (your reply message and 4 other CAN messages) back to back and your Tx only has 3 mailboxes. The mailboxes are getting full quickly, so you get HAL_ERROR.
Create a queue buffer to hold your CAN messages and when you call HAL_FDCAN_AddMessageToTxFifoQ and it returns HAL_OK, then you increment your queue pointer. When you get HAL_FDCAN_TxFifoEmptyCallback, you can send the next message in the queue. To get HAL_FDCAN_TxFifoEmptyCallback, you need to activate the notification
if (HAL_FDCAN_ActivateNotification(msg->hfdcan, FDCAN_FLAG_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_TX_FIFO_EMPTY, 0) != HAL_OK)
{
Error_Handler();
}
2025-08-21 12:58 AM
Hello @Karl Yamashita ,
Thanks for your reply, but it is too difficult for me, can i just add a delay after 3 transmit to wait the transmit mailbox has space? as below
// 发送 0x12
fdcan1TxHeader.Identifier=0x012;
fdcan1TxData[0] = (dis_sensor_data1.dis1 >> 0) & 0xff;
fdcan1TxData[1] = (dis_sensor_data1.dis1 >> 8) & 0xff;
fdcan1TxData[2] = (dis_sensor_data1.dis2 >> 0) & 0xff;
fdcan1TxData[3] = (dis_sensor_data1.dis2 >> 8) & 0xff;
fdcan1TxData[4] = (dis_sensor_data1.dis3 >> 0) & 0xff;
fdcan1TxData[5] = (dis_sensor_data1.dis3 >> 8) & 0xff;
fdcan1TxData[6] = (dis_sensor_data1.dis4 >> 0) & 0xff;
fdcan1TxData[7] = (dis_sensor_data1.dis4 >> 8) & 0xff;
my_FDCAN1_Transmit(fdcan1TxData);
// 发送 0x13
fdcan1TxHeader.Identifier=0x013;
fdcan1TxData[0] = (dis_sensor_data2.dis1 >> 0) & 0xff;
fdcan1TxData[1] = (dis_sensor_data2.dis1 >> 8) & 0xff;
fdcan1TxData[2] = (dis_sensor_data2.dis2 >> 0) & 0xff;
fdcan1TxData[3] = (dis_sensor_data2.dis2 >> 8) & 0xff;
fdcan1TxData[4] = (dis_sensor_data2.dis3 >> 0) & 0xff;
fdcan1TxData[5] = (dis_sensor_data2.dis3 >> 8) & 0xff;
fdcan1TxData[6] = (dis_sensor_data2.dis4 >> 0) & 0xff;
fdcan1TxData[7] = (dis_sensor_data2.dis4 >> 8) & 0xff;
my_FDCAN1_Transmit(fdcan1TxData);
tx_thread_sleep(1);
// 发送 0x14
fdcan1TxHeader.Identifier=0x014;
fdcan1TxData[0] = sbusHandle.isExist; // 遥控器工作状态
fdcan1TxData[1] = sys_status; // 系统状态
fdcan1TxData[2] = (encoder_data1.counter >> 0) & 0xff;
fdcan1TxData[3] = (encoder_data1.counter >> 8) & 0xff;
fdcan1TxData[4] = (encoder_data2.counter >> 0) & 0xff;
fdcan1TxData[5] = (encoder_data2.counter >> 8) & 0xff;
fdcan1TxData[6] = encoder_data1.direction;
fdcan1TxData[7] = encoder_data2.direction;
my_FDCAN1_Transmit(fdcan1TxData);
// 发送 0x15
fdcan1TxHeader.Identifier=0x015;
fdcan1TxData[0] = RS485_RXData[0]+0x0A;
fdcan1TxData[1] = RS485_RXData[1];
fdcan1TxData[2] = RS485_RXData[2];
fdcan1TxData[3] = RS485_RXData[3];
fdcan1TxData[4] = RS485_RXData[4];
fdcan1TxData[5] = RS485_RXData[5];
fdcan1TxData[6] = RS485_RXData[6];
fdcan1TxData[7] = RS485_RXData[7];
my_FDCAN1_Transmit(fdcan1TxData);
tx_thread_sleep(20);
How do you think just add a tx_thread_sleep(1) to wait?
Thanks.
2025-08-21 2:38 AM
Hello @dqsh06
Please refer to example below:
2025-08-21 6:04 PM
Hello @Saket_Om ,
I can send and receive FDCAN messages already, I said it is difficult for me is as below
Create a queue buffer to hold your CAN messages and when you call HAL_FDCAN_AddMessageToTxFifoQ and it returns HAL_OK, then you increment your queue pointer. When you get HAL_FDCAN_TxFifoEmptyCallback, you can send the next message in the queue.
i dont know how to get a queue buffer and let it works well. not for FDCAN config.
I have checked your link, but i found it no new information for me.
could you teach me how to get a queue buffer and let it works well for this situation?
Thanks.
2025-08-21 10:20 PM
>...but it is too difficult for me, can i just add a delay after 3 transmit to wait the transmit mailbox has space? as below
The CAN bus is not synchronous, you cannot send a message directly, but only add it to the queue.
It will only be sent once the CAN peripheral acquires the bus the next time (or the current transmission by the same node is finished).
Thus you have to wait for the AddMessage call until there is free space.
You could implement an additional, memory-based queue you operate based upon CAN interrupts. This is what we use in my company, either implemented by ourselves or within a commercial CAN stack.
2025-08-24 6:06 PM
Hello @Ozone ,
for my project situation, now i am thinking 2 methods.
1. extend the can2.0 to canfd, that means 1 transmit including 64bytes payload, then i dont need send 5-6 times of 8bytes with different canID.
2. use memory-based queue as you and @Karl Yamashita said. this method, maybe i need 2 thread and 1 message queue under threadx, i am a new player of threadx, but i can try.
thanks.
2025-08-24 10:10 PM
I can't comment on CAN FD (or CAN XL), because I have no real experience with those.
The machinery our devices are employed in can have bus lengths of several dozen meters, so the baud rates are limited. And second, most of our external nodes are CANopen devices, not supporting CAN FD.
On a related note - depending on machine and size, we employ several CAN busses. This helps to group nodes by function and required transfer rates, and distributes the bus throughput more evenly.
If it applies to your case, you can run CAN FD on a bus (or busses) allowing this.