OpenEdv-开源电子网

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

翻出了本站内“DMA传输完成一次后再传输一个字符就不再传输“之一个封存已久的帖子,如今我也遇到了这个问题,望重视

[复制链接]

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
发表于 2016-1-18 08:43:03 | 显示全部楼层 |阅读模式
200金钱
帖子地址:http://www.openedv.com/posts/list/22466.htm
帖子题目:
求助,串口DMA接收只能进一次中断,再收到一个字节就收不到了,万分苦恼中!
问题核心:
开启接收DMA后,第一次中断正常进入中断服务程序,但是之后,无论如何初始化DMA接收的寄存器设置(即使设置为与初始化相同的代码),也无法再进入中断,而且观察DMA1_Channel5->CNDTR的值,发现再收到一个字符就停止了。

该贴的测试内容我在早期进行过,但当时比较顺利就飘过了。。。
我的测试贴(库函数版F103)地址:http://www.openedv.com/thread-64008-1-1.html

如今我在我之前的测试帖的内容下加了sd卡存储和gprs等功能,之前测试是没有问题的,后来我把波特率改为115200
就出现了和源求助帖一样的现象,在第一次传输完成中断顺利,中断处理完成后跟踪发现只传输了一个字符就不再传
输了。接着我把测试帖源程序中的波特率由9600改为115200发现传输没有问题,但在现在加额外功能的程序上却出现
了问题,我把这些功能都注释掉只留下DMA传输还是如此,核心代码如下
串口1的设置
[mw_shl_code=c,true]void uart_init(u32 bound){
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟
        USART_DeInit(USART1);  //复位串口1
         //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
   
    //USART1_RX          PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10

   //Usart1 NVIC 配置

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置
        USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        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); //初始化串口
    //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
        //USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
    USART_Cmd(USART1, ENABLE);                    //使能串口
}[/mw_shl_code]

DMA设置
[mw_shl_code=c,true]//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHxMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //打开DMA时钟线
        /////////////////////////////////串口接收数据DMA的配置//////////////////////////////////////
        USART_DMACmd(USART1,USART_DMAReq_Rx,DISABLE);
        DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
        DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从内存读取发送到外设
        DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
        //DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环模式下
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
        DMA_ClearFlag(DMA1_FLAG_TC5); //清除DMA接收完成标志
        DMA_ClearFlag(DMA1_FLAG_TE5); //清除DMA接收错误标志DMA1_FLAG_TE5
        DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);//DMA5传输完成中断
        DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);//DMA5传输错误中断DMA_IT_TE
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//使能USART1的接收DMA请求
        Free_Buf_No=BUF_NO2; //因为 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
    Buf_Ok=0; //此时没有数据准备完成 当然FALSE
        COM_DMA_NVIC_Config();
    //DMA_Cmd(DMA1_Channel5, ENABLE); //正式允许DMA
        MYDMA_Enable(DMA1_Channel5);         
}[/mw_shl_code]

传输完成中断
[mw_shl_code=c,true]void DMA1_Channel5_IRQHandler(void)
{
   
        OSIntEnter();
        if(DMA_GetITStatus(DMA1_IT_TC5)) //通道5传输完成中断TC 还有传输 过半中断HT 错误中断TE 全局中断GL
     {       
            MYDMA_Disable(DMA1_Channel5);       
        DMA_ClearITPendingBit(DMA1_IT_GL5);    //清除全部中断标志
                DMA_InitStructure.DMA_BufferSize = (u16)500;      
       //转换可操作BUF
        if(Free_Buf_No==BUF_NO1)
        {   
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
                        FIFO_WRITE_BUF(RX_BUF_FIFO,USART1_DMA_Buf2,USART1_RX_BUF2_SIZE);                       
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);                       
            Free_Buf_No=BUF_NO2;
                        LED0=!LED0;
        }
        else
        {
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;
                        FIFO_WRITE_BUF(RX_BUF_FIFO,USART1_DMA_Buf1,USART1_RX_BUF1_SIZE);               
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);
            Free_Buf_No=BUF_NO1;
                        LED1=!LED1;
        }
        Buf_Ok=1; //有准备好的数据了
                MYDMA_Enable(DMA1_Channel5);                   
     }
         if(DMA_GetITStatus(DMA1_IT_TE5))
         {
                 DMA_ClearITPendingBit(DMA1_IT_GL5);    //清除全部中断标志
                BEEP=1;
                MYDMA_Enable(DMA1_Channel5);       
         }
         OSIntExit();
}[/mw_shl_code]

完整源代码下载调试请附件下载



impinj.rar

19.7 MB, 下载次数: 93

如想调试解决问题下载此文件

最佳答案

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

解决了,是DMA缓冲区切换前在中断里面缓冲区数据存储占用时间过长
我是一只菜鸟,但我会大鹏展翅
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2016-1-18 08:43:04 | 显示全部楼层
解决了,是DMA缓冲区切换前在中断里面缓冲区数据存储占用时间过长
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2016-1-18 09:19:21 | 显示全部楼层
[mw_shl_code=c,true]
void DMA1_Channel4_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC4))
    {
        DMA_Cmd(DMA1_Channel4,DISABLE);
        DMA_ClearITPendingBit(DMA1_IT_GL4);
        DMA_ClearFlag(DMA1_FLAG_TC4);  
    }
}

//从新启动DMA:

    USART1_TX_DMA->CNDTR = len;
    USART1_TX_DMA->CMAR = AddrBase;
    DMA_Cmd(USART1_TX_DMA,ENABLE);[/mw_shl_code]
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2016-1-18 09:59:39 | 显示全部楼层
ricefat 发表于 2016-1-18 09:19
[mw_shl_code=c,true]
void DMA1_Channel4_IRQHandler(void)
{

请问友人何意
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

18

主题

422

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1139
金钱
1139
注册时间
2014-5-24
在线时间
116 小时
发表于 2016-1-18 10:09:20 | 显示全部楼层
按楼主描述,新增功能变得不正常,我猜测是事务处理逻辑有问题。
I See Fire.·.·.·.·.·.·.·.·.·.·.·.·.·.·.·.·.·.·.·.  只给方向,不妨碍思考
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2016-1-18 10:10:18 | 显示全部楼层
ricefat 发表于 2016-1-18 09:19
[mw_shl_code=c,true]
void DMA1_Channel4_IRQHandler(void)
{

DMA_ClearFlag(DMA1_FLAG_TC4);
如果是清传输完成的标志的话,DMA1_IT_GL4清零是可以达到效果的吧,我之前的测试程序就是这么做的,没有再去清TC4
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2016-1-18 10:17:13 | 显示全部楼层
ricefat 发表于 2016-1-18 09:19
[mw_shl_code=c,true]
void DMA1_Channel4_IRQHandler(void)
{

比较郁闷的是波特率改为9600就可以    原先测试版什么波特率都可以
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2016-1-18 10:23:04 | 显示全部楼层
emWin 发表于 2016-1-18 10:09
按楼主描述,新增功能变得不正常,我猜测是事务处理逻辑有问题。

我现在已经把其余功能屏蔽了,主函数里面只有一个无限循环跑,波特率9600正常,115200就出现描述的问题
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2016-1-18 10:43:53 | 显示全部楼层
本帖最后由 ricefat 于 2016-1-18 10:50 编辑
战舰水手 发表于 2016-1-18 10:23
我现在已经把其余功能屏蔽了,主函数里面只有一个无限循环跑,波特率9600正常,115200就出现描述的问题

还有个问题,F103的 usart好像有硬件BUG,初始化时候必须先传一个字节,不然后面可能出现无法传输的问题,试试看
另外还有些问题你看看
http://blog.csdn.net/love_maomao/article/details/8234039
http://bbs.21ic.com/icview-160999-1-1.html
回复

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1684
金钱
1684
注册时间
2014-2-25
在线时间
230 小时
发表于 2016-1-18 12:16:24 | 显示全部楼层
你在DMA中断加上这句试试看  
USART_ReceiveData(USART1); //
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-21 13:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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