OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5613|回复: 9

基于STM32的FreeRtos下开启DMA接收空闲中断系统卡死的问题

[复制链接]

1

主题

3

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2018-9-20
在线时间
9 小时
发表于 2020-5-26 14:01:02 | 显示全部楼层 |阅读模式
9金钱
向大佬们求助!!在FreeRTOS系统上添加了三个任务,解析报文任务、打印函数任务、指示灯检测任务,每当串口来了个IDLE中断,其他任务都会先执行一次,但然后就卡住了。这是为啥呀?
//串口中断函数
void USART1_IRQHandler(void)                       
{
       
        uint32_t temp=0;
         if(__HAL_USART_GET_FLAG(&UART1_Handler, USART_FLAG_IDLE)!=RESET)
    {
        __HAL_UART_CLEAR_IDLEFLAG(&UART1_Handler);  
        HAL_UART_DMAStop(&UART1_Handler);  
        temp = UART1_Handler.hdmarx->Instance->NDTR;
        rx_len= USART_REC_LEN-temp;                       
        HAL_UART_Receive_DMA(&UART1_Handler,USART_RX_BUF,USART_REC_LEN);
        Comp_Flag=1;
         vTaskResume(Fetch_Da_task);
                          
    }


//解析报文任务
void Fetch_Da_task(void *pvParameters)
{
        const u8* qt = USART_RX_BUF;
        while(1)
        {
            if(Comp_Flag)
                  {
                          Buffer=My_ctoi(qt, Buffer);   //解析报文
                          Tak_Data();                         //提取报文
                                Comp_Flag=0;
                        }
                        else vTaskSuspend(Fetch_Da_task);
                       
                         vTaskDelay(500);
        }
}




最佳答案

查看完整内容[请看2#楼]

提个小小的建议,在FREERTOS下编程你应该忘记前后台的编程方法。 1、在串口中断服务程序中 你设置 Comp_Flag=1; 然后在解析任务中用 if (Comp_Flag ) 方法检测 是否有报文,是前后台编程的方法 2、 FreeRTOS编程方法如下 (1)、定义一个信号量 (2)、在串口中断中检测到数据后,释放信号量 (3)、定义一个高优先级的任务void Fetch_Da_task(void *pvPar ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-26 14:01:03 | 显示全部楼层
  提个小小的建议,在FREERTOS下编程你应该忘记前后台的编程方法。

   1、在串口中断服务程序中
          你设置  Comp_Flag=1;
          然后在解析任务中用   if (Comp_Flag ) 方法检测 是否有报文,是前后台编程的方法

  2、 FreeRTOS编程方法如下
        (1)、定义一个信号量
         (2)、在串口中断中检测到数据后,释放信号量
          (3)、定义一个高优先级的任务void Fetch_Da_task(void *pvParameters),目的是只要中断服务程序释放信号量就可以立即获得CPU的控制权
          (4)、在任务void Fetch_Da_task(void *pvParameters) 中读取信号量
                      如果读取到信号量,就解析该报文
      
      3、还发现一个问题
           你在中断服务程序中调用  vTaskResume(Fetch_Da_task);  问题很严重。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-26 21:14:47 | 显示全部楼层
本帖最后由 霸王猫 于 2020-5-27 13:12 编辑

  • //DMA中断方式
  • void USART1_IRQHandler(void)
  • {
  •         uint16_t ch;
  •         BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  •         if (USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
  •         {
  •                 USART_ClearITPendingBit(USART1 , USART_IT_IDLE);        //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。
  •                 ch =  USART_ReceiveData(USART1);
  •                 DMA_Cmd(DMA1_Channel5 , DISABLE);                                         //关闭DMA,防止处理其间有数据
  •                 DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_HT5 | DMA1_FLAG_TE5);
  •                 ch = USART1_DMA_RX_BUFFER_MAX_LENGTH - DMA_GetCurrDataCounter(DMA1_Channel5);
  •                 if (ch > 0)      //表示收到数据
  •                 {
  •                         MB_USART1.receCount        = ch;
  •                         memcpy(MB_USART1.mscomm_buffer , USART1_DMA_RX_Buffer , MB_USART1.receCount);
  •                 }
  •                 DMA_SetCurrDataCounter(DMA1_Channel5 , USART1_DMA_RX_BUFFER_MAX_LENGTH);
  •                 DMA_Cmd(DMA1_Channel5, ENABLE);
  •                 xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);//释放信号量
  •                 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  •         }
  • }
  • void MODBUS_Task(void *pvParameters)
  • {
  •         BaseType_t xResult;
  •         BaseType_t xStatus;
  •         const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
  •         uint8_t Buffer[10];
  •         uint8_t Over = 0x00;
  •         USART1_Configuration();
  •         USART1_DMA_Tx_Configuration();
  •         USART1_DMA_Rx_Configuration();
  •     while(1)
  •     {
  •                 xResult = xSemaphoreTake(xSemaphore, portMAX_DELAY); //读取信号量
  •                 if(xResult == pdTRUE)   //读取信号时成功
  •                 {
  •                          解析报文
  •                 }//if(xResult == pdTRUE)
  •     }//while(1)
  • }



回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165353
金钱
165353
注册时间
2010-12-1
在线时间
2108 小时
发表于 2020-5-27 01:29:17 | 显示全部楼层
帮顶
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2017-8-21
在线时间
4 小时
发表于 2020-5-27 09:45:15 | 显示全部楼层
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
        USART1->SR;
        USART1->DR; //清USART_IT_IDLE标志

        DMA_Cmd(DMA1_Channel5, DISABLE);

        USART1_RX_LEN = USART1_REC_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);

        DMA_SetCurrDataCounter(DMA1_Channel5, USART1_REC_LEN);//设置传输数据长度

        xEventGroupSetBitsFromISR(usart1_t.eventhandle, UART_EVENT_RECIVE_STATUS, &xHigherPriorityTaskWoken);

        DMA_Cmd(DMA1_Channel5, ENABLE);//打开DMA
    }
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);


if(xEventGroupWaitBits(usart1_t.eventhandle, UART_EVENT_RECIVE_STATUS, pdTRUE, pdFALSE, timeout))
    {
        *(u32 *)buf = (u32)&USART1_RX_BUF;
        cnt = USART1_RX_LEN;
        USART1_RX_LEN = 0;

        return  cnt;
    }

你这个中断里不能让任务恢复,可以让任务一直跑着,长时间等待一个状态,可以用事件标志,或者信号量都可以实现。
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2017-8-21
在线时间
4 小时
发表于 2020-5-27 09:46:37 | 显示全部楼层
我这个在stm32f105底下实现的代码,用了很长时间,没有问题的。
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
        USART1->SR;
        USART1->DR; //清USART_IT_IDLE标志

        DMA_Cmd(DMA1_Channel5, DISABLE);

        USART1_RX_LEN = USART1_REC_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);

        DMA_SetCurrDataCounter(DMA1_Channel5, USART1_REC_LEN);//设置传输数据长度

        xEventGroupSetBitsFromISR(usart1_t.eventhandle, UART_EVENT_RECIVE_STATUS, &xHigherPriorityTaskWoken);

        DMA_Cmd(DMA1_Channel5, ENABLE);//打开DMA
    }
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);


if(xEventGroupWaitBits(usart1_t.eventhandle, UART_EVENT_RECIVE_STATUS, pdTRUE, pdFALSE, timeout))
    {
        *(u32 *)buf = (u32)&USART1_RX_BUF;
        cnt = USART1_RX_LEN;
        USART1_RX_LEN = 0;

        return  cnt;
    }

你这个中断里不能让任务恢复,可以让任务一直跑着,长时间等待一个状态,可以用事件标志,或者信号量都可以实现
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-27 13:06:26 | 显示全部楼层
本帖最后由 霸王猫 于 2020-5-27 13:15 编辑

楼主主要的问题如下:

   1、在中断服务程序中使用唤醒任务API---》vTaskResume(Fetch_Da_task);

   2、标准的做法如下:
        定义1个信号量,用于唤醒Fetch_Da_task任务。
       (1)、中断服务程序中调用释放信号量API函数,注意:一定要使用ISR的释放信号量API函数,例如:xSemaphoreGiveFromISR
        (2)、Fetch_Da_task任务中调用读取信号量API函数,例如:xSemaphoreTake
  3、你根本就没有必要让该任务挂起呀!
         当使用了信号量后,如果收到信号量该任务    Fetch_Da_task 会自动被唤醒,执行完后,自动会被操作系统挂起的呀!
   直到下次再次收到信号量。所以你根本没有必要调用
vTaskSuspend(Fetch_Da_task);挂起Fetch_Da_task呀!

4、感觉楼主还停留在前后台编程模式中,没有真正进入到FREERTOS编程模式。
        在FREERTOS编程模式下是不会使用(1)、在中断服务程序中置标识Comp_Flag=1
       (2)、在Fetch_Da_task任务中通过if(Comp_Flag) 来判断是否收到数据这种方法的。
      在FREERTOS编程模式下使用信号量即可,即:
              中断服务程序中调用释放信号量API函数,注意:一定要使用ISR的释放信号量API函数。
             Fetch_Da_task任务中调用读取信号量API函数
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-5-28 16:30:30 | 显示全部楼层
在FREERTOS编程模式下,虽然使用:
     (1)、在中断服务程序中置标识Comp_Flag=1
      (2)、在Fetch_Da_task任务中通过if(Comp_Flag) 来判断是否收到数据这种方法
   也可以解析报文,但是【实时性不高】,你需要将Fetch_Da_task任务设计成周期性任务

     用信号量的方式实现,实时响应快(前提是你把Fetch_Da_task任务的优先级定义的高一些)。

回复

使用道具 举报

4

主题

82

帖子

0

精华

高级会员

Rank: 4

积分
743
金钱
743
注册时间
2018-9-1
在线时间
177 小时
发表于 2020-5-28 17:31:56 | 显示全部楼层
- 在中断中恢复任务使用支持中断的API: vTaskResumeFromISR()函数,而不是vTaskResume()
- vTaskSuspend() 和 vTaskResumeFromISR() 的参数为TaskHandle_t类型,即任务句柄,而不是函数名(函数指针)。
uevip#126.com
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2018-9-20
在线时间
9 小时
 楼主| 发表于 2020-6-2 11:17:34 | 显示全部楼层
霸王猫 发表于 2020-5-26 14:01
提个小小的建议,在FREERTOS下编程你应该忘记前后台的编程方法。

   1、在串口中断服务程序中

你说的这些都是问题,还有个小问题是堆栈大小不够,一直被忽略了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-26 04:57

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表