您的位置 首页 电子

完成STM32中USART的DMA

对于没玩过DMA的朋友,这里简单说一下DMA,用自己的语言说吧,那就是,从某个位置传输数据到某个位置,如果不用DMA,那要CPU参与操作,一个字节…

关于没玩过DMA 的朋友,这儿简单说一下DMA,用自己的言语说吧,那便是,从某个方位

传输数据到某个方位,假如不必DMA,那要CPU参加操作,一个字节一个字节地搬,效率高
点的,就一个字一个字地搬.但当你用了DMA 后,那便是只需求设置:A.从哪里开端搬; B,
搬到哪里去;C以字节办法搬仍是半字仍是字;D:总共搬多少个.之后,发动DMA.CPU内部
就会开端搬数据了,整个搬数据的进程都不需求指令的参加,仅有要做的,便是检测什么时
候搬完.你可以扫描存放器,也可以用中止.这儿,我运用了中止.
详细设置功能看注释就可以理解了.留意一点便是,有一个设置:
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
这个是外设的地址不递加.也便是说,每次搬动,都是从源头,也便是USART1的DR存放器
搬,但内存地址却是递加的:
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

这个进程完结了 承受 串口的数据 写到FLASH 之中作业,而DMA的效果在于将 串口收存放器 USART1->DR 的 数据写到内存之中 比方某个数组之中 u8 USART1_DMA_Buf1[512]; 写满512个字节之后将进入DMA中止(通道5)在这儿修正DMA 的内存写入进口
u8 USART1_DMA_Buf2[512]; ,一起符号 下次的进口Free_Buf_No=BUF_NO1; 与 Buf_Ok=TRUE; 证明已有数据预备完结。这时CUP将USART1_DMA_Buf1中的数据写入FLASH .

又抄了一点

这次运用的是双缓冲,也有人
叫乒乓缓冲.由于一般情况下,串口的数据DMA 传输进BUF1 的进程中,是不主张对
BUF1 进行操作的.但由于串口数据是不会等候的直传,所以你总不能等BUF1 满了,
才往FLASH 上写,由于这时分串口数据依旧是照本宣科.所以,运用双缓冲就变的理
所当然了.当BUF1 满了的时分,就立刻设置DMA的方针为BUF2,并且BUF1的数据
往25F080上灌.当串口DMA写满了BUF2的时分,再设置DMA的方针为BUF1,此刻
再操作BUF2写进25F080.如此一向循环,就好像打乒乓球那样吧,所以就叫乒乓缓冲.
用这个办法的速度极限便是,你有必要确保两点a.DMA 灌满了BUF1 的时分,会产生中
断,此刻切换DMA 的方针缓冲为BUF2,并且切换的进程有必要在新的串口数据溢出之
前完结.b.在DMA的BUF1满之前,其他一个有数据的BUF2有必要能悉数写进25F080,
其间包含了遇到新的扇区鸿沟而要刷除扇区的操作时刻!!
可以看出,BUF的增大,并不行以很大程度的提高速度极限.

假定 USART 与 FLASH 的底层驱动现已写好了。 点击检查。

#define SRC_USART1_DR (&(USART1->DR)) //串口接纳存放器作为源头

//DMA方针缓冲,这儿运用双缓冲
u8 USART1_DMA_Buf1[512];
u8 USART1_DMA_Buf2[512];
bool Buf_Ok; //BUF是否现已可用
BUF_NO Free_Buf_No; //闲暇的BUF号 typedef enum {BUF_NO1=0,BUF_NO2=1}BUF_NO;

DMA_InitTypeDef DMA_InitStructure;

void USART_DMAToBuf1(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开DMA时钟
DMA_DeInit(DMA1_Channel5); //将DMA的通道1存放器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR; //源头BUF 既是 (&(USART1->DR))
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1; //方针BUF 既是要写在哪个个数组之中
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作源头//外设是作为数据传输的目的地仍是来历
DMA_InitStructure.DMA_BufferSize = 512; //DMA缓存的巨细 单位在下边设定
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_PeripheralDataSize_Byte; //内存字节为单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //作业在循环缓存形式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //4优先级之一的(高优先) VeryHigh/High/Medium/Low
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //依据DMA_InitStruct中指定的参数初始化DMA的通道1存放器

DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); //DMA5传输完结中止

USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能USART1的接纳DMA恳求

//初始化BUF标志
Free_Buf_No=BUF_NO2; //由于 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
Buf_Ok=FALSE; //此刻没有数据预备完结 当然FALSE
DMA_Cmd(DMA1_Channel5, ENABLE); //正式答应DMA

}

再来看看DMA中止:

//u16 DataCounter;
extern DMA_InitTypeDef DMA_InitStructure;
void DMA1_Channel5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC5)) //通道5传输完结中止TC 还有传输 过半中止HT 过错中止TE 大局中止GL
{
//DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);//获取剩下长度,一般都为0,调试用
DMA_ClearITPendingBit(DMA1_IT_GL5); //铲除悉数中止标志

//转化可操作BUF
if(Free_Buf_No==BUF_NO1)
{
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
Free_Buf_No=BUF_NO2;
}
else
{
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
Free_Buf_No=BUF_NO1;
}
Buf_Ok=TRUE; //有预备好的数据了

}
}

写FLASH的操作
while(1)
{
if(Buf_Ok==TRUE)
{
LED1_ON; //一个符号
Buf_Ok=FALSE; //操作了预备好的数据
if((addr@96)==0) //跨过一个扇区,则需求先刷除
{
SST25SectorErase(addr);
sector_count++;
}
if(Free_Buf_No==BUF_NO1)
SST25Write(addr,USART1_DMA_Buf1,512);
else
SST25Write(addr,USART1_DMA_Buf2,512);
addr+=512;
Timer1=5000; //时刻重置
LED1_OFF;
}

//检测超时 开了 定时器
if(Timer1==0) //五秒内没预备好的数据
{
//获取长度
len=512-DMA_GetCurrDataCounter(DMA1_Channel5);
//写入最终数据
if(Free_Buf_No==BUF_NO1)
SST25Write(addr,USART1_DMA_Buf2,len);
else
SST25Write(addr,USART1_DMA_Buf1,len);
addr+=len;

break;
}
}

仍是很简单的。
有一点比较困扰 便是 FlagStatus标志位 与 ITStatus中止标志位 的差异。 其实就 DMA 来说 DMA_IT值 与 DMA_FLAG值 是相同的
乃至2者值的获取 都是读 DMA ISR register 的值 铲除也是设置 DMA_IFCR 存放器来铲除的所以圆满没有差异………同理这个问题在其他中止也存在但我还不行确保 IT 与FLAG 的值总是相同的这个存在惹祸是为了兼容但一定有其意义必须不行混用即便有时用错也正确…..

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/dianzi/264435.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部