OpenEdv-开源电子网

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

***********STM32F407 DMA求助 Demo是参考原子哥的!***********

[复制链接]

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
发表于 2014-5-6 19:15:24 | 显示全部楼层 |阅读模式
5金钱
思路:我写的是利用DMA将内存的数据送到串口3上,在中断里写清除的标志位!
现象:在所有的数据都搬运完毕后,才打印剩余量!
代码:
***********************************************************************************************************
int main(void)
{
int pro=0;
int i=0;
BSP_Init();
delay_init();
for(i=0;i<8000;i++)
Buffer=i;
USART_OUT(USART3,"****  F407_USART_DMA  ****\r\n");      //向串口1发送开机字符 
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);/*使能 USART3的发送数据DMA请求 至此USART3与DMA开始工作*/
GPIO_SetBits(GPIOB,GPIO_Pin_11);
while(1)
{
/*因为 DMA 工作是独立于 CPU 之外的,所以在 DMA 工作的同时 CPU 可以做其他事
 我们等到 DMA 传输完毕后产生一个状态指示,即点亮一个 LED */
delay_ms(1000);
pro=DMA_GetCurrDataCounter(DMA1_Stream3);
USART_OUT(USART3, "剩余传送量=%d\r\n",pro);

 /*DMA 传输完毕后会自动关闭通道,数据就打印不出来了!   
而且还得开启DMA的接收完成中断服务函数*/
}
}
***********************************************************************************************************
void DMA1_Stream3_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3) != RESET)  //判断传输完成后,标志位置1
{
DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);//清除通道3传输完成标志
DMA_Cmd(DMA1_Stream3, DISABLE);  
GPIO_ResetBits(GPIOB,GPIO_Pin_11);
USART_OUT(USART3,"\r\n ****DMA传输完毕_中断******* \r\n"); 
}
}
***********************************************************************************************************


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-6 19:16:08 | 显示全部楼层
额,上传完以后才发现图片有点让人无语!抱歉!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-5-6 23:21:16 | 显示全部楼层
 今天刚写了串口1的DMA.
[mw_shl_code=c,true]#include "dma.h" #include "delay.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32F407开发板 //DMA 驱动代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2014/5/6 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// //DMAx的各通道配置 //这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 //chxMA通道选择,范围:0~7 //par:外设地址 //mar:存储器地址 //ndtr:数据传输量 void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar,u16 ndtr) { DMA_TypeDef *DMAx; u8 streamx; if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1 { DMAx=DMA2; RCC->AHB1ENR|=1<<22;//DMA2时钟使能 }else { DMAx=DMA1; RCC->AHB1ENR|=1<<21;//DMA1时钟使能 } while(DMA_Streamx->CR&0X01);//等待DMA可配置 streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18; //得到stream通道号 if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16); //清空之前该stream上的所有中断标志 else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4); //清空之前该stream上的所有中断标志 else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志 else DMAx->LIFCR|=0X3D<<6*streamx; //清空之前该stream上的所有中断标志 DMA_Streamx->AR=par; //DMA外设地址 DMA_Streamx->M0AR=mar; //DMA 存储器0地址 DMA_Streamx->NDTR=ndtr; //DMA 存储器0地址 DMA_Streamx->CR=0; //先全部复位CR寄存器值 DMA_Streamx->CR|=1<<6; //存储器到外设模式 DMA_Streamx->CR|=0<<8; //非循环模式(即使用普通模式) DMA_Streamx->CR|=0<<9; //外设非增量模式 DMA_Streamx->CR|=1<<10; //存储器增量模式 DMA_Streamx->CR|=0<<11; //外设数据长度:8位 DMA_Streamx->CR|=0<<13; //存储器数据长度:8位 DMA_Streamx->CR|=1<<16; //中等优先级 DMA_Streamx->CR|=0<<21; //外设突发单次传输 DMA_Streamx->CR|=0<<23; //存储器突发单次传输 DMA_Streamx->CR|=(u32)chx<<25;//通道选择 //DMA_Streamx->FCR=0X21; //FIFO控制寄存器 } //开启一次DMA传输 //DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7 //ndtr:数据传输量 void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) { DMA_Streamx->CR&=~(1<<0); //关闭DMA传输 while(DMA_Streamx->CR&0X1); //确保DMA可以被设置 DMA_Streamx->NDTR=ndtr; //DMA 存储器0地址 DMA_Streamx->CR|=1<<0; //开启DMA传输 } [/mw_shl_code]



分享部分代码:
[mw_shl_code=c,true]#define SEND_BUF_SIZE 8200 //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍. u8 SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区 const u8 TEXT_TO_SEND[]={"ALIENTEK Explorer STM32F4 DMA 串口实验"}; int main(void) { u16 i; u8 t=0; u8 j,mask=0; float pro=0;//进度 Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz delay_init(168); //延时初始化 uart_init(84,115200); //初始化串口波特率为115200 LED_Init(); //初始化LED LCD_Init(); //LCD初始化 KEY_Init(); //按键初始化 MYDMA_Config(DMA2_Stream7,4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA2,STEAM7,CH4,外设为串口1,存储器为SendBuff,长度为:SEND_BUF_SIZE. POINT_COLOR=RED; LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); LCD_ShowString(30,70,200,16,16,"DMA TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,"2014/5/6"); LCD_ShowString(30,130,200,16,16,"KEY0:Start"); POINT_COLOR=BLUE;//设置字体为蓝色 //显示提示信息 j=sizeof(TEXT_TO_SEND); for(i=0;i<SEND_BUF_SIZE;i++)//填充ASCII字符集数据 { if(t>=j)//加入换行符 { if(mask) { SendBuff=0x0a; t=0; }else { SendBuff=0x0d; mask++; } }else//复制TEXT_TO_SEND语句 { mask=0; SendBuff=TEXT_TO_SEND[t]; t++; } } POINT_COLOR=BLUE;//设置字体为蓝色 i=0; while(1) { t=KEY_Scan(0); if(t==1)//KEY0按下 { printf("\r\nDMA DATA:\r\n"); LCD_ShowString(30,150,200,16,16,"Start Transimit...."); LCD_ShowString(30,170,200,16,16," %");//显示百分号 USART1->CR3=1<<7; //使能串口1的DMA发送 MYDMA_Enable(DMA2_Stream7,SEND_BUF_SIZE);//开始一次DMA传输! //等待DMA传输完成,此时我们来做另外一些事,点灯 //实际应用中,传输数据期间,可以执行另外的任务 while(1) { if(DMA2->HISR&(1<<27)) //等待DMA2_Steam7传输完成 { DMA2->HIFCR|=1<<27; //清除DMA2_Steam7传输完成标志 break; } pro=DMA2_Stream7->NDTR; //得到当前还剩余多少个数据 pro=1-pro/SEND_BUF_SIZE;//得到百分比 pro*=100; //扩大100倍 LCD_ShowNum(30,170,pro,3,16); } LCD_ShowNum(30,170,100,3,16);//显示100% LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示传送完成 } i++; delay_ms(10); if(i==20) { LED0=!LED0;//提示系统正在运行 i=0; } } } [/mw_shl_code]

我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 00:08:46 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
期待原子哥的F4的板子!

问题找到了,DMA的功能我早就实现了,一直想要模仿原子哥,做出那个进度的显示(PS:设备简陋,用打印了),然后我就用顺手用那个DMA传输的串口打印,结果一直实现不了!后来我分析了好久,最后换了一个串口打印,就出效果了!

不过那个F4的double buffer还是不是很清楚,不知道你搞清楚了么?这个的配置貌似要比起几个系列的简单吧?
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 00:11:09 | 显示全部楼层
uint8_t Buffer1[] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
uint8_t Buffer2[] = {0x99,0xaa};

DMA_DeInit(DMA1_Stream3);
DMA_StructInit( &DMA_InitStructure);  
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //选择 Channel_5
DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Addr; //数据传输的外设首地址,详解见上
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer2; //自己定义待发送数组的首地址,要强制转换为32位
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //数据传输方向选择为内存->外设
DMA_InitStructure.DMA_BufferSize = 10; //传输数据大小为8,大小要配合定义的数组类型和外设数据类型,否则会丢失或补充数据
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器自动增加禁止,因为这里只用到了 DR 数据寄存器
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增允许,因为要读取一个数组
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设的数据大小,因为 USART3_DR 数据寄存器为8位,故选Byte
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //这里也选 Byte
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA 传输模式为 DMA_Mode_Normal,如果为 DMA_Mode_Circular,将会循环传输
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级为 High
/*双缓冲模式,在 DMA_Init 之前调用在 Circular 模式有效,会强制 Circular,
  *不支持 Memory to Memory,(uint32_t)Buffer2为 DMA_Memory_1,DMA 先将 Buffer
*中的数据发送完毕后在发送 Buffer2的数据,当然顺序可以改变*/
DMA_DoubleBufferModeConfig(DMA1_Stream3, (uint32_t)Buffer1, DMA_Memory_1);
DMA_DoubleBufferModeCmd(DMA1_Stream3, ENABLE);

蓝色的部分我觉得是没法修改的,定义为不变量,而红色部分我调换了位置为啥打印的数据没有调换?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-5-7 00:16:09 | 显示全部楼层
double buffer很简单的,就是2个buf自动切换,可以通过查询寄存器得到当前空闲buf,DMA操作BUF1的时候,CPU操作BUF2,从而实现乒乓操作,在IIS音频的时候,非常有用,可以做到真正不断流....
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 00:25:55 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
是的,原子哥,我第一次接触DMA,看了下,网上人的例子,都是F1系列的,我不是很了解,看了他们的code,发现都是在中断里进行buf的切换,
是不是F4可以不用这么麻烦了!
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 00:28:21 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
顺便补充下,将u8 buffer1改为u16 buffer1后,会出现乱码?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-5-7 00:42:18 | 显示全部楼层
回复【7楼】小Y:
---------------------------------
也是要在中断里面处理,不过不需要切换了,硬件自动切换好了。
串口是8位的,你怎么用16位?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 10:00:14 | 显示全部楼层
回复【9楼】正点原子:
---------------------------------
嗯!好的!
但是我配置了F4的DMA双缓冲模式(库函数版本的)!
在DMA的配置里加了这么两句话(含自己理解)
DMA_DoubleBufferModeConfig(DMA1_Stream3, 
(uint32_t)Buffer1/*Memory1BaseAddr*/,
 DMA_Memory_1/*Memory x is the current buffer,当前第一个开始传输的memory
  不使用DoubleBuffer模式的时候,默认当前的memory是第一个*/);
DMA_DoubleBufferModeCmd(DMA1_Stream3, ENABLE);

补充:前面memory0的时候设置了Buffer0,且
uint8_t Buffer0[4] = {0x11,0x22,0x33,0x44};
uint8_t Buffer1[4] = {0x55,0x66,0x77,0x88};
DMA_BufferSize设置为8
同时中断里只是清除标志位
但是如果memory0设置为buffer1,而memory1设置为buffer0的话,打印出来就是11 ...88
但是如果memory0设置为buffer0,而memory1设置为buffer1的话,打印出来就是55 66 77 88 15 00 08 52 
我分析了下,后面的四个和我不使用双缓存模式,将DMA_BufferSize设置的长度大于数组长度时候的一样!
感觉就和找不到buffer1一样~
请原子哥看看~(又写的多了、、、)
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-5-7 14:36:47 | 显示全部楼层
回复【10楼】小Y:
---------------------------------
库函数没研究了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

46

主题

333

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
357
金钱
357
注册时间
2013-12-12
在线时间
63 小时
 楼主| 发表于 2014-5-7 14:59:51 | 显示全部楼层
回复【11楼】正点原子:
---------------------------------
是的了,这个也的确很苦逼!参考手册就是这样!
回复

使用道具 举报

63

主题

238

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1136
金钱
1136
注册时间
2015-11-29
在线时间
146 小时
发表于 2017-9-14 11:09:41 | 显示全部楼层
突发传输时什么意思?设置这个的作用是什么?
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-18 20:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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