打印
[STM32F4]

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

[复制链接]
399|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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





void StartTaskAndroidTx(void const * argument)
{
        MyDataStruct_t *tx_buffer;
        osSignalSet(AndroidTxHandle,CPL_U3TX_SIG);//osSemaphoreRelease(myBinarySemU3TxHandle);
        /* Infinite loop */
        for(;;)
        {
                if (pdPASS==xQueueReceive(U3TxQueueHandle, (uint8_t*)&tx_buffer, osWaitForever))
                {
                        if (NULL!=tx_buffer) {
                                uint8_t data_len=tx_buffer->length;
                                if (0!=data_len) {
                                        osEvent ReadEvent;
                                        osSignalWait(CPL_U3TX_SIG,100);
                                        osSignalWait(ACK_U3TX_SIG,0);
                                        memcpy(DMA_USART3_TxBuf,tx_buffer->DatArea,data_len);
                                        vPortFree((uint8_t*)tx_buffer);
                                        for (int i = 0; i < 10; ++i) {
                                                LCD_RS485_DE=LCD_RS485_RE=1;
                                                LL_DMA_DisableStream(DMA1,LL_DMA_STREAM_3);
                                                LL_DMA_SetDataLength(DMA1,LL_DMA_STREAM_3,data_len);
                                                LL_DMA_EnableStream(DMA1,LL_DMA_STREAM_3);
                                                ReadEvent = osSignalWait(ACK_U3TX_SIG,100);
                                                if (ReadEvent.value.v & ACK_U3TX_SIG)break;
                                        }
                                }
                                else vPortFree((uint8_t*)tx_buffer);
                        }
                }
        }
}
以下为中断中发送任务消息:
void DMA1_Stream3_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
        if (LL_DMA_IsEnabledIT_TC(DMA1,LL_DMA_STREAM_3)!=RESET && LL_DMA_IsActiveFlag_TC3(DMA1) != RESET)
        {
                LL_DMA_ClearFlag_TC3(DMA1);
                LL_DMA_DisableStream(DMA1,LL_DMA_STREAM_3);
osSignalSet(AndroidTxHandle,CPL_U3TX_SIG);
        }
  /* USER CODE END DMA1_Stream3_IRQn 0 */

  /* USER CODE BEGIN DMA1_Stream3_IRQn 1 */

  /* USER CODE END DMA1_Stream3_IRQn 1 */
}

当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 | 只看该作者
任务
#define CPL_U3TX_SIG        0x00000001u
#define ACK_U3TX_SIG        0x00000002u

void StartTaskAndroidTx(void const * argument)
{
    MyDataStruct_t *tx_buffer;
    osSignalSet(AndroidTxHandle, CPL_U3TX_SIG); // osSemaphoreRelease(myBinarySemU3TxHandle);

    /* Infinite loop */
    for (;;)
    {
        if (pdPASS == xQueueReceive(U3TxQueueHandle, (uint8_t*)&tx_buffer, osWaitForever))
        {
            if (NULL != tx_buffer)
            {
                uint8_t data_len = tx_buffer->length;

                if (0 != data_len)
                {
                    osEvent ReadEvent;

                    osSignalWait(CPL_U3TX_SIG, 100);

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

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

                    for (int i = 0; i < 10; ++i)
                    {
                        LCD_RS485_DE = LCD_RS485_RE = 1;

                        LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
                        LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, data_len);
                        LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3);

                        ReadEvent = osSignalWait(ACK_U3TX_SIG, 100);

                        if (ReadEvent.value.signals & ACK_U3TX_SIG)
                        {
                            osSignalClear(AndroidTxHandle, ACK_U3TX_SIG); // 清除信号以避免重复处理
                            break;
                        }
                    }
                }
                else
                {
                    vPortFree((uint8_t*)tx_buffer);
                }
            }
        }
    }
}

使用特权

评论回复
地板
yiy| | 2024-7-13 22:12 | 只看该作者
中断
void DMA1_Stream3_IRQHandler(void)
{
    /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
    if (LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_STREAM_3) != RESET && LL_DMA_IsActiveFlag_TC3(DMA1) != RESET)
    {
        LL_DMA_ClearFlag_TC3(DMA1);
        LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);

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

    /* USER CODE BEGIN DMA1_Stream3_IRQn 1 */

    /* USER CODE END DMA1_Stream3_IRQn 1 */
}

使用特权

评论回复
5
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信号后才继续执行,从而达到预期的行为。

使用特权

评论回复
6
shipeng1989|  楼主 | 2024-7-14 13:45 | 只看该作者

我可能没有说清楚,ACK信号是在收到串口应答数据后才置位的,所以在发出数据之前不能一直等这个信号,另外为啥我的osSignalClear函数只有一个函数头,没有函数体

使用特权

评论回复
7
shipeng1989|  楼主 | 2024-7-14 13:51 | 只看该作者
yiy 发表于 2024-7-13 22:12
说明
任务函数(StartTaskAndroidTx):

我的本意是CPL_U3TX_SIG信号用来指示DMA是否发送完成,ACK_U3TX_SIG信号用来指示发出数据后收到接收端的应答,否则如等待100毫秒依然未收到接收端的应答信号,则重发数据10次

使用特权

评论回复
8
shipeng1989|  楼主 | 2024-7-14 13:58 | 只看该作者
另外我再补充一点,虽然ReadEvent = osSignalWait(ACK_U3TX_SIG,100);阻塞等待被打断了,但是if (ReadEvent.value.signals & ACK_U3TX_SIG)条件却不成立,也就是ACK_U3TX_SIG信号并没有被置位

使用特权

评论回复
9
xiaoqi000| | 2024-7-26 13:29 | 只看该作者
确保您定义的信号位 CPL_U3TX_SIG 和 ACK_U3TX_SIG 是唯一且不会冲突的。

使用特权

评论回复
10
初级工程渣| | 2024-7-29 00:37 | 只看该作者
您使用了 0x00000001u 和 0x00000002u,这看起来是合适的,但需要确保这两个信号位没有被其他代码修改。

使用特权

评论回复
11
lxs0026| | 2024-7-30 20:34 | 只看该作者
在中断服务例程(ISR)中,您调用了 osSignalSet(AndroidTxHandle, CPL_U3TX_SIG)。需要确保:

osSignalSet 在 ISR 中的调用是安全的。在某些 FreeRTOS 配置中,可能需要在 ISR 中使用 BaseType_t xHigherPriorityTaskWoken = pdFALSE 参数来标记是否需要上下文切换。

使用特权

评论回复
12
lxs0026| | 2024-7-30 20:34 | 只看该作者
如果中断处理程序的时间过长,可能会影响到 FreeRTOS 的时间片和任务切换。确保中断处理程序尽可能短,避免长时间运行。

使用特权

评论回复
13
我爱台妹mmd| | 2024-7-31 23:10 | 只看该作者
osSignalWait 之后的 ReadEvent.value.v 的值应准确反映收到的信号位。如果 ReadEvent.value.v 是 1,则可能说明 CPL_U3TX_SIG 被意外设置了。

使用特权

评论回复
14
我爱台妹mmd| | 2024-7-31 23:10 | 只看该作者
osSignalWait 的第一个参数是等待的信号位,第二个参数是等待超时时间。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

134

帖子

1

粉丝