OpenEdv-开源电子网

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

STM32F2 DMA串口接收中断DISABLE DMA命令卡死

[复制链接]

2

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2016-12-21
在线时间
6 小时
发表于 2016-12-21 13:23:57 | 显示全部楼层 |阅读模式
1金钱
STM32F207VCT6 串口DMA收发
DMA每次可以接收到数据,且能正常中断。
如今程序现出以下问题:加入DMA_Cmd(DMA2_Stream5, DISABLE); 这句会导致CPU卡死;无法重新对DMA长度配置。不加这句,但由于无法关闭DMA导致DMA计数器一直在增加,即上一中断接收到的数据无法清除,如图片所以。
请问大家有没有遇到这种问题?


USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef  DMA_InitStructure;
////////////
   //GPIO¶Ë¿ÚÉèÖÃ
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOD,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
     
    //USART1¶Ë¿ÚÅäÖÃ
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
   
    //USART1¶Ë¿ÚÅäÖÃ
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ; //GPIOA9
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
   
    //´®¿Ú1¶ÔÓ¦Òý½Å¸´ÓÃÓ³Éä
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9¸
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10¸  

   //USART1 ³õʼ»¯ÉèÖÃ
    USART_InitStructure.USART_BaudRate = brt;
    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(USART1, &USART_InitStructure);

    //Usart1 NVIC ÅäÖÃ
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=INT_Prio_HIGH;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =INT_Prio_HIGHEST;      
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            
    NVIC_Init(&NVIC_InitStructure);   
            
    /* ÅäÖÃ DMA2_Stream7 */        
   
    DMA_DeInit(DMA2_Stream7);
    while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);
   
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (u32)RunData.SenBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize = SBuf_SIZE;
    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_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream7, &DMA_InitStructure);
    //DMA NVIC  
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = INT_Prio_HIGHEST;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = INT_Prio_HIGHEST;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);  

    DMA_Cmd(DMA2_Stream5, DISABLE);  

  /* ÅäÖÃ DMA2_Stream5 */
   
  DMA_DeInit(DMA2_Stream5);
    while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE);
   
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (u32)RunData.RecBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = RBuf_SIZE;
    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_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream5, &DMA_InitStructure);//³õʼ»¯DMA Stream
    //DMA NVIC  
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = INT_Prio_HIGHEST;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = INT_Prio_HIGH;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);  
    DMA_Cmd(DMA2_Stream5, ENABLE);  
   
    DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_FEIF7 | DMA_FLAG_DMEIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TCIF7);
    DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5 | DMA_FLAG_TCIF5);
   
    DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);
    DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);
   
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
   
    USART_Cmd(USART1, ENABLE);           
    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);

//接收中断
void USART1_IRQHandler(void)
{
    u16 temp = 0;  
      
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  
    {  
        //USART_ClearFlag(USART1,USART_IT_IDLE);  
        temp = USART1->SR;  
        temp = USART1->DR; //清USART_IT_IDLE标志
               
               
                DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5);//清除标志
                DMA_Cmd(DMA2_Stream5, DISABLE); //关闭DMA(执行此句将卡死)
                temp = RBuf_SIZE - DMA_GetCurrDataCounter(DMA2_Stream5);     //长度
                COM_PC_ACK_Pro(temp-2);//数据处理
                DMA_SetCurrDataCounter(DMA2_Stream5,RBuf_SIZE);                                       
                DMA_Cmd(DMA2_Stream5,ENABLE); //
    }
}

屏蔽关DMA命令后,中断3次

屏蔽关DMA命令后,中断3次

最佳答案

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

差点就放弃DMA接收了,还好查出来了,主要是因为这句话DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);,当关闭DMA时会产生void DMA2_Stream5_IRQHandler(void)中断,而之前没有写中断函数,所以程序指针就飞了。 现在屏蔽DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);这句就行了。 然后我发现一个不太理解的现象: 接收数据中断后,在中断函数中仅使用这命令DMA_Cmd(DMA2_Stream5, DISABLE);,然后不设长度,不使能DMA,下次 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2016-12-21
在线时间
6 小时
 楼主| 发表于 2016-12-21 13:23:58 | 显示全部楼层
差点就放弃DMA接收了,还好查出来了,主要是因为这句话DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);,当关闭DMA时会产生void DMA2_Stream5_IRQHandler(void)中断,而之前没有写中断函数,所以程序指针就飞了。
现在屏蔽DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);这句就行了。

然后我发现一个不太理解的现象:
接收数据中断后,在中断函数中仅使用这命令DMA_Cmd(DMA2_Stream5, DISABLE);,然后不设长度,不使能DMA,下次报文来了DMA仍然可以正常中断,数据处理均正常!
有大神可以解释下么!
回复

使用道具 举报

18

主题

238

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1823
金钱
1823
注册时间
2014-8-5
在线时间
211 小时
发表于 2016-12-21 18:29:04 | 显示全部楼层
楼主想法还是不错的,提几个建议吧1、不要在中断中执行处理函数,而是采用标记,让处理的函数在主程序中执行
2、关键字 __weak 可以很好的帮助你
3、串口空闲中断中不要控制DMA(死掉的原因不清楚)
4、为了考虑方便移植及实用性,建议把需要用的硬件参数用结构体的方式留出(设计接口)

这是我自己设计的一个串口DMA收发方案,只要写好一个串口需要用到资源(比如时钟、端口、引脚、DMA通道等),调用初始化就可以直接使用了
支持双缓存配置(单缓存或者双缓存),接收数据完成的处理函数用 用关键字__weak关联回调函数,这个需要用户自己重写。
这个工程已经写好了例子 ,请参考下   
里面也有对STM32的FLASH操作的函数,支持字节操作
代码风格固定,几乎每行注释。如有瑕疵欢迎指正

串口DMA收发方案.zip

11.99 MB, 下载次数: 3099

串口DMA收发方案

回复

使用道具 举报

2

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2016-12-21
在线时间
6 小时
 楼主| 发表于 2016-12-22 13:47:19 | 显示全部楼层
513393302@qq.co 发表于 2016-12-21 18:29
楼主想法还是不错的,提几个建议吧1、不要在中断中执行处理函数,而是采用标记,让处理的函数在主程序中执 ...

谢谢你的建议,我把中断数据处理函数放到主函数去了,但在主函数里添加这句话还是会死掉--〉DMA_Cmd(DMA2_Stream5, DISABLE); //关闭DMA
看了你的函数,同样也是要关闭DMA再重新定义接收长度,从而确保下次DMA接收数据时,从指定BUFF的起始地址开始接收数据。
我现在就是无法关闭,所以后续报文处理很麻烦~
请问是我的DMA配置有问题么!
回复

使用道具 举报

18

主题

238

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1823
金钱
1823
注册时间
2014-8-5
在线时间
211 小时
发表于 2016-12-22 20:07:24 | 显示全部楼层
mzcw15 发表于 2016-12-22 16:02
差点就放弃DMA接收了,还好查出来了,主要是因为这句话DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);,当 ...

我记得DMA的寄存器好像有个保护,就是写寄存器的时候需要满足一定的条件才能保证写入的操作是正常。有可能你在执行关闭DMA这个操作的时候,寄存器的值没有写入。建议可以用程序跟踪下,看下DMA的寄存器或者看数据手册里面的描述。

回复

使用道具 举报

2

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2016-12-21
在线时间
6 小时
 楼主| 发表于 2017-1-1 00:05:25 | 显示全部楼层
下次中断的数据其实是原来的,正确的做法就是:关闭DMA后,需要再次清标志位,然后重新设置发送长度,开DMA就行了。
回复

使用道具 举报

1

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2017-10-1
在线时间
23 小时
发表于 2018-1-6 23:13:40 | 显示全部楼层
513393302@qq.co 发表于 2016-12-21 18:29
楼主想法还是不错的,提几个建议吧1、不要在中断中执行处理函数,而是采用标记,让处理的函数在主程序中执 ...

真棒!!!!
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-17 02:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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