你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

stm32f743VIT6 + DMA空闲方式接收不定长度的字节

[复制链接]
稻草人+ 提问时间:2019-5-21 16:39 /
悬赏5ST金币已解决

           最近使用stm32f743VIT6 DMA通过空闲中断接收不定长度的字节。有个现象很奇怪,我接收GPS下发的数据的时候,使用的串口2的DMA的空闲中断来接收,(一般情况下GPS发出来的数据都是每秒钟一帧,美帧数据大约几百个字节),要么接收到1个字节就空闲中断了,要么就根本接收不到。
然后我换成用PC机模拟GPS通过USB转TTL 的线下发数据到串口2,这个时候能完整无误的接收到数据,无论下发的数据字节有多少都能 完整无误的接收到。  我把我的串口的配置和中断处理贴出来,希望有知道原因的大牛指点指点。谢谢

       说明一下, 以上我做实验都是通过串口2接收的数据,然后用串口3转发接收的数据到PC机上来观察的。

  以下是   串口1 和串口2和串口3 的初始化配置:


   void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  static DMA_HandleTypeDef U1hdma_tx;
  static DMA_HandleTypeDef U1hdma_rx;
   
    static DMA_HandleTypeDef U2hdma_tx;
  static DMA_HandleTypeDef U2hdma_rx;
   
   
    static DMA_HandleTypeDef U3hdma_tx;
  static DMA_HandleTypeDef U3hdma_rx;

  GPIO_InitTypeDef  GPIO_InitStruct;

  RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;

       if(huart->Instance==USART1)
                {        
                USARTx_TX_GPIO_CLK_ENABLE();
            
                RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16;
                RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
                HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);

                USARTx_CLK_ENABLE();

                DMAx_CLK_ENABLE();

                GPIO_InitStruct.Pin       = USARTx_TX_PIN;
                GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                GPIO_InitStruct.Pull      = GPIO_PULLUP;
                GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
                GPIO_InitStruct.Alternate = USARTx_TX_AF;

                HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

                GPIO_InitStruct.Pin = USARTx_RX_PIN;
                GPIO_InitStruct.Alternate = USARTx_RX_AF;

                HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
            
                U1hdma_tx.Instance                 = USARTx_TX_DMA_STREAM;
                U1hdma_tx.Init.Request             = USARTx_TX_DMA_CHANNEL;
                U1hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
                U1hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
                U1hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
                U1hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
                U1hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                U1hdma_tx.Init.Mode                = DMA_NORMAL;
                U1hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
                U1hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
                U1hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
                U1hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
                U1hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;

                HAL_DMA_Init(&U1hdma_tx);
            
                __HAL_LINKDMA(huart, hdmatx, U1hdma_tx);

                HAL_NVIC_SetPriority(USARTx_DMA_TX_IRQn, 3, 1);
                HAL_NVIC_EnableIRQ(USARTx_DMA_TX_IRQn);

                HAL_NVIC_SetPriority(USARTx_IRQn, 3, 1);
                HAL_NVIC_EnableIRQ(USARTx_IRQn);   
            }
       if(huart->Instance==USART2)
             {   
               UsartG_RX_GPIO_CLK_ENABLE();

                RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
                RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART2CLKSOURCE_D2PCLK1;
                HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);

                 __HAL_RCC_USART2_CLK_ENABLE();

                 __HAL_RCC_DMA1_CLK_ENABLE();

                GPIO_InitStruct.Pin       = UsartG_TX_PIN;
                GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                GPIO_InitStruct.Pull      = GPIO_PULLUP;
                GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
                GPIO_InitStruct.Alternate = UsartG_TX_AF;
                HAL_GPIO_Init(UsartG_TX_GPIO_PORT, &GPIO_InitStruct);
               
                GPIO_InitStruct.Pin = UsartG_RX_PIN;
                GPIO_InitStruct.Alternate = UsartG_RX_AF;
                HAL_GPIO_Init(UsartG_RX_GPIO_PORT, &GPIO_InitStruct);

              U2hdma_rx.Instance                 = UsartG_RX_DMA_STREAM;
              U2hdma_rx.Init.Request             = UsartG_RX_DMA_CHANNEL;
              U2hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
              U2hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
              U2hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
              U2hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
              U2hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
              U2hdma_rx.Init.Mode                = DMA_NORMAL;
              U2hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
              U2hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
              U2hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
              U2hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;
              U2hdma_rx.Init.PeriphBurst         = DMA_PBURST_INC4;

              HAL_DMA_Init(&U2hdma_rx);
               
              __HAL_LINKDMA(huart, hdmarx, U2hdma_rx);

                HAL_NVIC_SetPriority(UsartG_DMA_RX_IRQn, 0, 0);
                HAL_NVIC_EnableIRQ(UsartG_DMA_RX_IRQn);

                HAL_NVIC_SetPriority(UsartG_IRQn, 0, 0);
                HAL_NVIC_EnableIRQ(UsartG_IRQn);
             }
            
        if(huart->Instance==USART3)
            {   
                UsartX_TX_GPIO_CLK_ENABLE();

                RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3;
                RCC_PeriphClkInit.Usart234578ClockSelection = RCC_USART3CLKSOURCE_D2PCLK1;
                HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);

                UsartX_CLK_ENABLE();
   
                DMAX_CLK_ENABLE();
   
                GPIO_InitStruct.Pin       = UsartX_TX_PIN;
                GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                GPIO_InitStruct.Pull      = GPIO_PULLUP;
                GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
                GPIO_InitStruct.Alternate = UsartX_TX_AF;

                HAL_GPIO_Init(UsartX_TX_GPIO_PORT, &GPIO_InitStruct);

   
     
                U3hdma_tx.Instance                 = UsartX_TX_DMA_STREAM;
                U3hdma_tx.Init.Request             = UsartX_TX_DMA_CHANNEL;
                U3hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
                U3hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
                U3hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
                U3hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
                U3hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                U3hdma_tx.Init.Mode                = DMA_NORMAL;
                U3hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
                U3hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
                U3hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
                U3hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
                U3hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;

                HAL_DMA_Init(&U3hdma_tx);
            
                __HAL_LINKDMA(huart, hdmatx, U3hdma_tx);
               
              HAL_NVIC_SetPriority(UsartX_DMA_TX_IRQn, 1, 1);
              HAL_NVIC_EnableIRQ(UsartX_DMA_TX_IRQn);

                HAL_NVIC_SetPriority(UsartX_IRQn, 1, 1);
                HAL_NVIC_EnableIRQ(UsartX_IRQn);   
        }        
}


       以下是串口2的中断处理:
注:  GPS_UartHandle  是处理处理GPS 接收数据的一个Handle ,也就是串口2


void Usart2_IRQHandler(void)
{
  uint32_t tmp_flag = 0;
  uint32_t temp;
  //HAL_UART_IRQHandler(&GPS_UartHandle);
  tmp_flag = __HAL_UART_GET_FLAG(&GPS_UartHandle,UART_FLAG_IDLE);                  // 这里是获取空闲标志
    if((tmp_flag ==SET))                                                            
  {               
         __HAL_UART_CLEAR_IDLEFLAG(&GPS_UartHandle);                                            // 清除空闲标志      
          temp=__HAL_DMA_GET_COUNTER(GPS_UartHandle.hdmarx);                          // 获取接收缓存的剩余字节数
          HAL_UART_DMAStop(&GPS_UartHandle);                                                            /// 停止 串口2的DMA接收
          rx_len = (RXBUFFERSIZE - temp);                                                                       // 计算 接收到的数据长度   
         recv_end_flag = 1;                                                                                              // 置位接收完成标志,在main中提示处理接收到的数据
          temp =0;                  
  }
    __HAL_UART_CLEAR_IT(&GPS_UartHandle,UART_CLEAR_PEF                                //  清除 其他的中断标志 等
                                     |UART_CLEAR_FEF
                                     |UART_CLEAR_NEF
                                     |UART_CLEAR_OREF
                                   //|UART_CLEAR_IDLEF
                                      |UART_CLEAR_TCF
                                      |UART_CLEAR_LBDF
                                      |UART_CLEAR_CTSF
                                      |UART_CLEAR_RTOF
                                      |UART_CLEAR_WUF
                                      |UART_CLEAR_CMF
                                      |UART_CLEAR_TXFECF);
   
}


恳请 知道原因的大牛指点一二,谢谢


最佳答案

查看完整内容

空闲中断,只要连续的两个字节的等待时间超过一个bit的间隔就会产生中断,用电脑模拟的串口信号应该是很好的,两个字节之间间隔很短,但是实际从GPS模块出来的串口波形是不是两个字节很连贯就要你自己量一下波形看看了。 还有一个,你在串口中断处理函数里只有停止DMA的操作,怎么没有再次打开DMA的操作呢?不再次打开怎么能够接收新数据呢? ...
收藏 评论15 发布时间:2019-5-21 16:39

举报

15个回答
DavidTan 回答时间:2019-5-21 16:39:51
空闲中断,只要连续的两个字节的等待时间超过一个bit的间隔就会产生中断,用电脑模拟的串口信号应该是很好的,两个字节之间间隔很短,但是实际从GPS模块出来的串口波形是不是两个字节很连贯就要你自己量一下波形看看了。
还有一个,你在串口中断处理函数里只有停止DMA的操作,怎么没有再次打开DMA的操作呢?不再次打开怎么能够接收新数据呢?

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

tanic 回答时间:2019-5-21 17:15:55
本帖最后由 tanic 于 2019-5-21 17:21 编辑

说了多少次不要用空闲中断+DMA方式
能这么用的必须保证发送方也是DMA方式发送,且DMA优先级最高。否则一旦发送被打断,你接收端就认为空闲中断了,于是错了。
能用空闲+DMA的应用场景在于大数据传输之前,先通过简单串口协议交互,把数据信息准备好,然后启用DMA定长传输数据,传输完成后切换到普通模式,亦或者两个串口,一个走命令一个走大数据

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

tanic 回答时间:2019-5-21 17:25:58
另外你的GPS能有多大精度,设备运动速度有多快,需要这么搞。别说节约CPU,大多数限制程序性能的是代码逻辑,很多时候CPU都在空跑。
串口中断接收数据放入fifo,再找合适的时机处理即可。
edmundlee 回答时间:2019-5-21 19:47:28
DMA+IDLE中断不是问题
DMA的两个中断 TC及HT都要用上
这三个中断只应用作, 告诉你buf里有新来的数据, 而不能以IDLE中断来代替数据包的解析

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

稻草人+ 回答时间:2019-5-22 09:13:03
tgw860910 发表于 2019-5-21 17:13
空闲中断,只要连续的两个字节的等待时间超过一个bit的间隔就会产生中断,用电脑模拟的串口信号应该是很好 ...

GPS是标准的串口输出,我看了两个字节是连贯的,另外我开DMA的操作是在 main里面对数据处理了以后再开的
稻草人+ 回答时间:2019-5-22 09:15:40
tanic 发表于 2019-5-21 17:15
说了多少次不要用空闲中断+DMA方式
能这么用的必须保证发送方也是DMA方式发送,且DMA优先级最高。否则一旦 ...

接收不定长度的是字节不用DMA+空闲还有其他方式吗,主要是我通过USB转TTL 的线在PC上模拟下发数据的时候也是正常的,如果是DMA被中断了的话那么说这种方式应该是不正常或者不能够接收到完整的数据。
稻草人+ 回答时间:2019-5-22 09:37:29
edmundlee 发表于 2019-5-21 19:47
DMA+IDLE中断不是问题
DMA的两个中断 TC及HT都要用上
这三个中断只应用作, 告诉你buf里有新来的数据, 而 ...

你的意思是说我再空闲中断的处理函数中判断  DMA 通道的TC 中断标志是不是置位,如果置位才表示一帧数据接收完毕了对了?还要判断HT 这个中断标志,这个标志是半传输完成标志,?这个怎么操作,您有合适的例子吗,能给我发一个吗?   4094359@qq.com
稻草人+ 回答时间:2019-5-22 09:38:21
tanic 发表于 2019-5-21 17:25
另外你的GPS能有多大精度,设备运动速度有多快,需要这么搞。别说节约CPU,大多数限制程序性能的是代码逻辑 ...

谢谢,  中断接收放入FIFO 这个不错我可以试试。
Nikola 回答时间:2019-5-22 10:04:05
tanic 发表于 2019-5-21 17:15
说了多少次不要用空闲中断+DMA方式
能这么用的必须保证发送方也是DMA方式发送,且DMA优先级最高。否则一旦 ...

空闲+DMA被打断也没有什么问题吧
Nikola 回答时间:2019-5-22 10:05:07
用一个fifo把数据完整接收完再处理

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

稻草人+ 回答时间:2019-5-22 11:39:20
秦秦秦 发表于 2019-5-22 10:05
用一个fifo把数据完整接收完再处理

可以到是可以,这样子就要把接收字节数设置到最大,远远大于GPS下发一帧数据的最大字节数,也使用DMA来接收,这样子就是处理的效率不高,可能FIFO中存储的是不完整的两帧数据。
现在主要的问题是用一块单片机模拟GPS发送数据,另外一块板子都可以接收到,换成电脑模拟GPS发送数据也能接收到,但是就是换成GPS就是接收不到, (GPS通过USB转串口线发送到电脑上的数据也是正常的,说明GPS也木有问题),可能这个是硬件哪里的问题,。一时不明白
天臆弄人 回答时间:2019-5-22 11:42:44
干嘛用DMA,不麻烦吗,直接用 空闲中断就行了

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

爱电子辉辉 回答时间:2019-5-22 19:58:10
稻草人+ 发表于 2019-5-22 11:39
可以到是可以,这样子就要把接收字节数设置到最大,远远大于GPS下发一帧数据的最大字节数,也使用DMA来接 ...

看你的描述,有点像硬件哪里出了问题,你看看有没有共地啊,给GPS供电后的电压,能不能支持GPS的最小功耗啊之类的,接上去之后,在用逻辑分析仪抓GPS发送到板子里的数据,是不是正确的。。然后在慢慢排除吧。
稻草人+ 回答时间:2019-5-24 09:53:01
爱电子辉辉 发表于 2019-5-22 19:58
看你的描述,有点像硬件哪里出了问题,你看看有没有共地啊,给GPS供电后的电压,能不能支持GPS的最小功耗 ...

谢谢,确实是硬件问题。
12下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版