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

查看: 5181|回复: 7

想问一个串口DMA的问题。

[复制链接]

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2012-11-13 02:40:13 | 显示全部楼层 |阅读模式
 问一个关于串口DMA的问题,感觉和串口接收缓冲区有关。
最近在做一个项目,要用串口接收固定40个字节的数据,每隔10ms40个字节的数据。
但是接收数据之前要用串口发命令给设备,请求这些数据,发送请求的时候,设备也会回复几个字节的应答。
 
当发送完请求的命令后,收到指定的回复(3个字节)后,每隔10ms就会有40个字节的需要的数据通过串口发回来。
但是前面发送的命令和回复的应答都是4、5个字节,所以我没用DMA,而是直接用串口接收中断。
当在串口接收终端中接收到正确的回复后,马上开启DMA模式,用DMA接收数据,DMA接收完成中断一次,就接收到40个字节。
比如发送命令 char command[ ] = { ‘s','e','n','d' }  4个字节, 接收到  char  respond[] = { ' s' , 'e', 'n', 'd', 'o','k'} 6个字节,
然后设备就一直发送40字节的数据。
问题来了,我把DMA的计数设置成40,然后开启的时候,第一次的DMA中断的第一个字节收到的是之前应答的最后一个字节’k',然后才是40字节的数据, 所以接收到39字节数据时就DMA中断了,最后一个字节又到下一次DMA中断才收到。
后面的所有DMA中断都会因为这个原因而错开1字节。但是我在串口中断中已经接收了最后一个字节了(确实接收到了,usart_receive 了最后一个字节了),为什么开启DMA时还会接收到最后一个字节 (我也尝试过开dma前执行一遍 usart_receive(USART),也不行) 。
可能是最后一个字节还留在缓冲区里(我猜想)?,所以有什么办法可以清空串口接收缓冲区吗?
后面我的解决办法是第一次开DMA时,把DMA计数加1 ,即41, 然后在中断中重新设置DMA计数为40,这样是把问题解决了,就是第一组数据丢弃了。
不过我还是想知道是什么原因,是缓冲区问题吗,还是别的?所以来这里求助一下,看看有没有遇到相同问题的,或者有对stm32了解深入一点的大神解答下,谢谢!!
回复

使用道具 举报

25

主题

446

回帖

0

蝴蝶豆

中级会员

最后登录
2019-12-10
发表于 2012-11-13 08:39:14 | 显示全部楼层

RE:想问一个串口DMA的问题。

经楼主这么一分析,我也认为可以是缓冲区的问题,要不这样,用串口收完"K"后再开DMA接收,应该数据就全了吧
回复 支持 反对

使用道具 举报

134

主题

4489

回帖

239

蝴蝶豆

版主

最后登录
2020-12-9
发表于 2012-11-13 09:39:10 | 显示全部楼层

RE:想问一个串口DMA的问题。

能不能看看你的串口配置?DMA的配置。
回复 支持 反对

使用道具 举报

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-11-13 12:00:03 | 显示全部楼层

回复:想问一个串口DMA的问题。

回复第 2 楼 于2012-11-13 08:39:14发表:
经楼主这么一分析,我也认为可以是缓冲区的问题,要不这样,用串口收完"K"后再开DMA接收,应该数据就全了吧
 
串口已经收完K了,我还用另一个串口发回来看过了。
 
回复 支持 反对

使用道具 举报

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-11-13 12:29:02 | 显示全部楼层

RE:想问一个串口DMA的问题。

//这个是DMA的配置
void DMA_Configuration()
{
        DMA_InitTypeDef DMA_InitStructure;
        /* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
       
        DMA_DeInit(USARTy_Tx_DMA_Channel);
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)tmp;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = 0x40;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(USARTy_Tx_DMA_Channel, &DMA_InitStructure);
        /* USARTy RX DMA1 Channel (triggered by USARTy Rx event) Config */
        DMA_DeInit(USARTy_Rx_DMA_Channel);  
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer_rx;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = RxBufferSize;
        DMA_Init(USARTy_Rx_DMA_Channel, &DMA_InitStructure);
}
回复 支持 反对

使用道具 举报

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-11-13 12:29:53 | 显示全部楼层

RE:想问一个串口DMA的问题。

这个是串口配置。
void My_Usart_Init()
{
      USART_InitTypeDef USART_InitStructure;
      
      RCC_Configuration();
      DMA_Configuration();
      GPIO_Configuration();
      NVIC_Configuration();
  
      USART_InitStructure.USART_BaudRate = 115200  ;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      USART_InitStructure.USART_StopBits = USART_StopBits_1;
      USART_InitStructure.USART_Parity = USART_Parity_No;
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      
      //³õʼ»¯´®¿Ú2
      USART_Init(USARTy,&USART_InitStructure);   
      //ʹÄÜ´®¿Ú½ÓÊÕÖжÏ
      USART_ITConfig(USARTy,USART_IT_RXNE ,ENABLE);
      //ʹÄÜ´®¿Ú2
      USART_Cmd(USARTy,ENABLE);
      //ʹÄÜ´®¿ÚYµÄDMA
      USART_DMACmd(USARTy,USART_DMAReq_Tx | USART_DMAReq_Rx,ENABLE);
//      DMA_ITConfig(USARTy_Tx_DMA_Channel, DMA_IT_TC, ENABLE);
//      Periph_NVIC_config(USARTy_Tx_DMA_IRQn,0,5,ENABLE);
           
        /////* Enable the USARTz Interrupt */     
      DMA_ITConfig(USARTy_Rx_DMA_Channel, DMA_IT_TC, ENABLE);
      Periph_NVIC_config(USARTy_Rx_DMA_IRQn,0,3,ENABLE);
回复 支持 反对

使用道具 举报

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-11-13 12:34:43 | 显示全部楼层

回复:想问一个串口DMA的问题。

刚刚一直用快速回复栏,格式没搞好。 重复上一贴。
这个是串口的配置。
因为有时要改串口,所以代码里面用了宏,但是这些定义应该是没问题的,因为都能正常使用了(只是多一位)。我想没有必要贴上来吧。
void My_Usart_Init()
{
      USART_InitTypeDef USART_InitStructure;
      
      RCC_Configuration();
      DMA_Configuration();
      GPIO_Configuration();
      NVIC_Configuration();
  
      USART_InitStructure.USART_BaudRate = 115200  ;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      USART_InitStructure.USART_StopBits = USART_StopBits_1;
      USART_InitStructure.USART_Parity = USART_Parity_No;
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      
      //初始化串口
      USART_Init(USARTy,&USART_InitStructure);    
      //开接收中断
      USART_ITConfig(USARTy,USART_IT_RXNE ,ENABLE);
      //使能串口
      USART_Cmd(USARTy,ENABLE);
      //使能串口DMA
      USART_DMACmd(USARTy,USART_DMAReq_Tx | USART_DMAReq_Rx,ENABLE);
//      DMA_ITConfig(USARTy_Tx_DMA_Channel, DMA_IT_TC, ENABLE);
//      Periph_NVIC_config(USARTy_Tx_DMA_IRQn,0,5,ENABLE);
           
 
        /////* Enable the USARTz Interrupt */     
      DMA_ITConfig(USARTy_Rx_DMA_Channel, DMA_IT_TC, ENABLE);     使能DMA接收中断
      Periph_NVIC_config(USARTy_Rx_DMA_IRQn,0,3,ENABLE);   //开NVIC中断,自己写的函数,这样代码好看点。
回复 支持 反对

使用道具 举报

6

主题

18

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-11-13 12:54:41 | 显示全部楼层

回复:想问一个串口DMA的问题。

 我的代码是这样的,先是开串口接收中断来接收回复,一旦接收到了第一个应带,马上开启一个定时器,当然串口接收的数据也会保存起来。当定时器到时间时(3ms),我就开始检查串口接收的数据(4、5字节)。
volatile char buffer_rx[60];
volatile u8 num = 0;
volatile u8 commandflag = 0;
void USART3_IRQHandler(void)
{   
        USART_ClearITPendingBit(USART3,USART_IT_RXNE); 
        if( !commandflag ) {       //第一次接收到串口回复后开定时器,后面的字节直接跳过。
            commandflag = 1;
            TIM_SetCounter( TIM3, 0 );
            TIM_Cmd(TIM3,ENABLE);
        }
 
        buffer_rx[num++] = USART_ReceiveData(USART3);   //保存数据。
        
     
                //memset(RxBuffer1,0,RxBufferSize1);
}
 
volatile char commandWaitingFlag = 0;
/**
 * @brief This function handles TIM2 global interrupt request by resuming the
 * iNemoData task.
 */
void TIM3_IRQHandler( void ) {
  if(TIM_GetITStatus(TIM3, TIM_IT_Update))
  {
        TIM_ClearITPendingBit( TIM3, TIM_IT_Update );
        TIM_Cmd(TIM3,DISABLE);          //关定时器。
        commandflag = 0;                        //下次接收回复后开定时器。
        commandWaitingFlag = 1;    //   这个标志位用于在发送命令后,检查回复的有效性。
        printf("%d: %x %x %x\r\n", num, buffer_rx[0], buffer_rx[1], buffer_rx[2]);  //用USART1发送出回复,串口中断是USART3。这行可省略,调试用的。
        num = 0;
        GPIOA->ODR ^= 1 CNDTR = RxBufferSize + 1;            //这里其实是41,理想值当然是40啦
                USARTy_Rx_DMA_Channel->CMAR  = (uint32_t)buffer_rx;          //接收数据的buffer
                DMA_Cmd(USARTy_Rx_DMA_Channel,ENABLE);                        //开启串口DMA
        }
        res = true;
      } else {
        res = false;
      }
      return res;
}
嗯上面就是所有的代码了。还有,很感谢你们看完这些东西。

</p>
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版