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

查看: 5125|回复: 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管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版