cancel
Showing results for 
Search instead for 
Did you mean: 

issue of ThreadX and FDCAN function

dqsh06
Senior

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

11 REPLIES 11
Karl Yamashita
Principal

You forgot to show code for my_FDCAN1_Transmit

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.
CAN Jammer an open source CAN bus hacking tool

@Karl Yamashita ,

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 

HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &fdcan1TxHeader, TxData)
returns HAL_ERROR when call my_FDCAN1_Transmit() for ID 0x15.
because i got a printf of 
"HAL_FDCAN_AddMessageToTxFifoQ failed"
and Error_Handler() called.

 why call HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &fdcan1TxHeader, TxData) failed for ID 0x15?

 

Thanks.

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();
	}

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.
CAN Jammer an open source CAN bus hacking tool

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.

Saket_Om
ST Employee

Hello @dqsh06 

Please refer to example below:

STM32CubeG4/Projects/STM32G474E-EVAL/Examples/FDCAN/FDCAN_Com_IT at master · STMicroelectronics/STM32CubeG4 · GitHub

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

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.

>...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.

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.

 

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.