[STM32F4] 关于FreeRTOS的任务消息替代事件组问题

[复制链接]
1543|19
 楼主| shipeng1989 发表于 2024-7-12 17:20 | 显示全部楼层 |阅读模式
本帖最后由 shipeng1989 于 2024-7-12 17:33 编辑

最近在使用FreeRTOS的任务消息功能替代事件组,遇到一个毫无头绪的问题:当在中断函数中置位任务消息osSignalSet(TaskHandle,1);时会导致osEvent ReadEvent = osSignalWait(2,100);退出等待状态。仿真调试此时的ReadEvent.value.v=1,但是osSignalWait(2,100);却并没有阻塞100毫秒,不知是何原因?请大神们指教!

以下我附上我的源码:
#define CPL_U3TX_SIG        0x00000001u
#define ACK_U3TX_SIG        0x00000002u





  1. void StartTaskAndroidTx(void const * argument)
  2. {
  3.         MyDataStruct_t *tx_buffer;
  4.         osSignalSet(AndroidTxHandle,CPL_U3TX_SIG);//osSemaphoreRelease(myBinarySemU3TxHandle);
  5.         /* Infinite loop */
  6.         for(;;)
  7.         {
  8.                 if (pdPASS==xQueueReceive(U3TxQueueHandle, (uint8_t*)&tx_buffer, osWaitForever))
  9.                 {
  10.                         if (NULL!=tx_buffer) {
  11.                                 uint8_t data_len=tx_buffer->length;
  12.                                 if (0!=data_len) {
  13.                                         osEvent ReadEvent;
  14.                                         osSignalWait(CPL_U3TX_SIG,100);
  15.                                         osSignalWait(ACK_U3TX_SIG,0);
  16.                                         memcpy(DMA_USART3_TxBuf,tx_buffer->DatArea,data_len);
  17.                                         vPortFree((uint8_t*)tx_buffer);
  18.                                         for (int i = 0; i < 10; ++i) {
  19.                                                 LCD_RS485_DE=LCD_RS485_RE=1;
  20.                                                 LL_DMA_DisableStream(DMA1,LL_DMA_STREAM_3);
  21.                                                 LL_DMA_SetDataLength(DMA1,LL_DMA_STREAM_3,data_len);
  22.                                                 LL_DMA_EnableStream(DMA1,LL_DMA_STREAM_3);
  23.                                                 ReadEvent = osSignalWait(ACK_U3TX_SIG,100);
  24.                                                 if (ReadEvent.value.v & ACK_U3TX_SIG)break;
  25.                                         }
  26.                                 }
  27.                                 else vPortFree((uint8_t*)tx_buffer);
  28.                         }
  29.                 }
  30.         }
  31. }
以下为中断中发送任务消息:
  1. void DMA1_Stream3_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
  4.         if (LL_DMA_IsEnabledIT_TC(DMA1,LL_DMA_STREAM_3)!=RESET && LL_DMA_IsActiveFlag_TC3(DMA1) != RESET)
  5.         {
  6.                 LL_DMA_ClearFlag_TC3(DMA1);
  7.                 LL_DMA_DisableStream(DMA1,LL_DMA_STREAM_3);
  8. osSignalSet(AndroidTxHandle,CPL_U3TX_SIG);
  9.         }
  10.   /* USER CODE END DMA1_Stream3_IRQn 0 */

  11.   /* USER CODE BEGIN DMA1_Stream3_IRQn 1 */

  12.   /* USER CODE END DMA1_Stream3_IRQn 1 */
  13. }

当DMA传输完成后置位“CPL_U3TX_SIG”任务消息,此时任务中ReadEvent = osSignalWait(ACK_U3TX_SIG,100);也退出等待了,我的本意是要收到ACK_U3TX_SIG消息才退出阻塞


yiy 发表于 2024-7-13 22:11 | 显示全部楼层
要确保osSignalWait(ACK_U3TX_SIG,100);等待ACK_U3TX_SIG信号,而不是由于其他原因退出,可以修改代码以确保信号的处理更加明确和准确。
yiy 发表于 2024-7-13 22:11 | 显示全部楼层
任务
  1. #define CPL_U3TX_SIG        0x00000001u
  2. #define ACK_U3TX_SIG        0x00000002u

  3. void StartTaskAndroidTx(void const * argument)
  4. {
  5.     MyDataStruct_t *tx_buffer;
  6.     osSignalSet(AndroidTxHandle, CPL_U3TX_SIG); // osSemaphoreRelease(myBinarySemU3TxHandle);

  7.     /* Infinite loop */
  8.     for (;;)
  9.     {
  10.         if (pdPASS == xQueueReceive(U3TxQueueHandle, (uint8_t*)&tx_buffer, osWaitForever))
  11.         {
  12.             if (NULL != tx_buffer)
  13.             {
  14.                 uint8_t data_len = tx_buffer->length;

  15.                 if (0 != data_len)
  16.                 {
  17.                     osEvent ReadEvent;

  18.                     osSignalWait(CPL_U3TX_SIG, 100);

  19.                     osSignalWait(ACK_U3TX_SIG, osWaitForever); // 这里确保等待ACK信号

  20.                     memcpy(DMA_USART3_TxBuf, tx_buffer->DatArea, data_len);
  21.                     vPortFree((uint8_t*)tx_buffer);

  22.                     for (int i = 0; i < 10; ++i)
  23.                     {
  24.                         LCD_RS485_DE = LCD_RS485_RE = 1;

  25.                         LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
  26.                         LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, data_len);
  27.                         LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3);

  28.                         ReadEvent = osSignalWait(ACK_U3TX_SIG, 100);

  29.                         if (ReadEvent.value.signals & ACK_U3TX_SIG)
  30.                         {
  31.                             osSignalClear(AndroidTxHandle, ACK_U3TX_SIG); // 清除信号以避免重复处理
  32.                             break;
  33.                         }
  34.                     }
  35.                 }
  36.                 else
  37.                 {
  38.                     vPortFree((uint8_t*)tx_buffer);
  39.                 }
  40.             }
  41.         }
  42.     }
  43. }
yiy 发表于 2024-7-13 22:12 | 显示全部楼层
中断
  1. void DMA1_Stream3_IRQHandler(void)
  2. {
  3.     /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
  4.     if (LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_STREAM_3) != RESET && LL_DMA_IsActiveFlag_TC3(DMA1) != RESET)
  5.     {
  6.         LL_DMA_ClearFlag_TC3(DMA1);
  7.         LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);

  8.         osSignalSet(AndroidTxHandle, CPL_U3TX_SIG);
  9.         // 在DMA传输完成后发送ACK信号
  10.         osSignalSet(AndroidTxHandle, ACK_U3TX_SIG);
  11.     }
  12.     /* USER CODE END DMA1_Stream3_IRQn 0 */

  13.     /* USER CODE BEGIN DMA1_Stream3_IRQn 1 */

  14.     /* USER CODE END DMA1_Stream3_IRQn 1 */
  15. }
yiy 发表于 2024-7-13 22:12 | 显示全部楼层
说明
任务函数(StartTaskAndroidTx):

使用osSignalWait(ACK_U3TX_SIG, osWaitForever);确保任务在接收到ACK信号之前一直处于阻塞状态。
清除ACK_U3TX_SIG信号以避免重复处理。
中断服务程序(DMA1_Stream3_IRQHandler):

在DMA传输完成后,除了发送CPL_U3TX_SIG信号,还要发送ACK_U3TX_SIG信号,以通知任务传输完成并继续执行后续操作。
通过这些调整,确保任务在接收到ACK_U3TX_SIG信号后才继续执行,从而达到预期的行为。
 楼主| shipeng1989 发表于 2024-7-14 13:45 | 显示全部楼层

我可能没有说清楚,ACK信号是在收到串口应答数据后才置位的,所以在发出数据之前不能一直等这个信号,另外为啥我的osSignalClear函数只有一个函数头,没有函数体 联想截图_20240714134438.png
 楼主| shipeng1989 发表于 2024-7-14 13:51 | 显示全部楼层
yiy 发表于 2024-7-13 22:12
说明
任务函数(StartTaskAndroidTx):

我的本意是CPL_U3TX_SIG信号用来指示DMA是否发送完成,ACK_U3TX_SIG信号用来指示发出数据后收到接收端的应答,否则如等待100毫秒依然未收到接收端的应答信号,则重发数据10次
 楼主| shipeng1989 发表于 2024-7-14 13:58 | 显示全部楼层
另外我再补充一点,虽然ReadEvent = osSignalWait(ACK_U3TX_SIG,100);阻塞等待被打断了,但是if (ReadEvent.value.signals & ACK_U3TX_SIG)条件却不成立,也就是ACK_U3TX_SIG信号并没有被置位
xiaoqi000 发表于 2024-7-26 13:29 | 显示全部楼层
确保您定义的信号位 CPL_U3TX_SIG 和 ACK_U3TX_SIG 是唯一且不会冲突的。
初级工程渣 发表于 2024-7-29 00:37 | 显示全部楼层
您使用了 0x00000001u 和 0x00000002u,这看起来是合适的,但需要确保这两个信号位没有被其他代码修改。
lxs0026 发表于 2024-7-30 20:34 | 显示全部楼层
在中断服务例程(ISR)中,您调用了 osSignalSet(AndroidTxHandle, CPL_U3TX_SIG)。需要确保:

osSignalSet 在 ISR 中的调用是安全的。在某些 FreeRTOS 配置中,可能需要在 ISR 中使用 BaseType_t xHigherPriorityTaskWoken = pdFALSE 参数来标记是否需要上下文切换。
lxs0026 发表于 2024-7-30 20:34 | 显示全部楼层
如果中断处理程序的时间过长,可能会影响到 FreeRTOS 的时间片和任务切换。确保中断处理程序尽可能短,避免长时间运行。
我爱台妹mmd 发表于 2024-7-31 23:10 | 显示全部楼层
osSignalWait 之后的 ReadEvent.value.v 的值应准确反映收到的信号位。如果 ReadEvent.value.v 是 1,则可能说明 CPL_U3TX_SIG 被意外设置了。
我爱台妹mmd 发表于 2024-7-31 23:10 | 显示全部楼层
osSignalWait 的第一个参数是等待的信号位,第二个参数是等待超时时间。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

140

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部