单片机的DMA的要点难点概括
DMA控制器
1 stm32的dma控制器有两组 DMA1,DMA2;
2 dma的运行也就是传输数据不通过内核,直接进行传输也就是cpu不干涉
3 DMA的数据传输方向 外设到储存器 储存器到外设 储存器到储存器
4 dma1有7 个通道,dma2有5 个通道 一个通道连接多个外设
5 DMA的优先级通过dma仲裁器来协调
DMA主要特性
1 dma的优先级通过软件编程设置,具有四种优先级别 很高 高 中 低 当优先级相同时由硬件决定。
2 源和目标数据必须对齐 两边同时为 半字 字 字节
3 每个通道具有三个中断标志 DMA半传输、 DMA传输完成和DMA传输出错
4 传输数据最大长度 65535
DMA框图
请注意图片下面的三句话
1 DMA2仅存在与大容量产品和互联网型产品
2 SPI/I2S3、 UART4、 TIM5、 TIM6、 TIM7和DAC的DMA请求仅存在于大容量产品和互联型产品
3 ADC3、 SDIO和TIM8的DMA请求仅存在于大容量产品
当cpu与DMA同时获取存储器或外设的数据时dma会暂时暂停,等待cpu若干个时钟周期。
DMA处理
在发生一个事件后,外设向DMA控制器发送一个请求信号。 DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时, DMA控制器立即发送给它一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求, DMA控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。总之,每次DMA传送由3个操作组成。
从外设数据寄存器或者从当前外设/存储器地址寄存器指示的存储器地址取数据,第一次传
输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。
存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输
时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。
执行一次DMA_CNDTRx寄存器的递减操作,该寄存器包含未完成的操作数目。、
DMA中断
每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考
虑,通过设置寄存器的不同位来打开这些中断。
DMA1设备
dma1连接的外设
各个通道的表
DMA2
dma2连接的外设
dma连接的外设
通道配置过程(软件初始化通道)
下面是配置DMA通道x的过程(x代表通道号):
1. 在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将
是数据传输的源或目标。
2. 在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数
据将从这个地址读出或写入这个地址。
3. 在DMA_CNDTRx寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。
4. 在DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级。
5. 在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外
设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。
6. 设置DMA_CCRx寄存器的ENABLE位,启动该通道。
一旦启动了DMA通道,它既可响应连到该通道上的外设的DMA请求。
瑞萨单片机基于DMA的串口通讯实例
单片机程序开发中,经常用到串口通讯,一般大家都是采用中断的方式实现,但是如果要求通讯波特率很高,那么就会导致程序频繁地进行中断处理,更甚者导致主循环得不到运行,这时候一般都会选择DMA+UART的方式进行设计,接收和发送交给DMA,释放MCU去做别的事情。
这里以瑞萨单片机为例,接收和发送均通过DMA实现,上实例代码,包括DMA和UART的配置以及详细的注释,用到同款单片机的朋友可以参考。
//DMA+USART的配置 250字节的定长发送和250字节的定长接收
INT8U sciTxBuf[256];//定长发送缓冲数组,DMA接收的目标地址
INT8U sciRxBuf[256];//定长接收缓冲数组,DMA发送的源地址
void dmac0_init(void)//接收DMA通道0
{
IEN(DMAC,DMAC0I) = 0; /* 禁用DMAC0I中断请求 */
DMAC0.DMCNT.BIT.DTE = 0; /* 禁用DMA0传送数据*/
ICU.DMRSR0 = 219; /* DMAC0的请求源: RXI1 ,(RXI中断向量号为219) */
DMAC0.DMAMD.BIT.DM = 2; /* 目标地址更新方式:递增,值为10b */
DMAC0.DMAMD.BIT.SM = 0; /* 源地址更新方式:固定,值为00b */
DMAC0.DMAMD.BIT.DARA = 0; /* 目标地址扩展重复区域:不指定 */
DMAC0.DMAMD.BIT.SARA = 0; /* 源地址扩展重复区域 :不指定*/
DMAC0.DMTMD.BIT.DCTG = 1; /* DMA 请求源: 外设中断 */
DMAC0.DMTMD.BIT.SZ = 0; /* 数据传送长度: 8 bits */
DMAC0.DMTMD.BIT.MD = 0; /* 传送模式: 正常传送 */
DMAC0.DMCSL.BIT.DISEL = 0; /* 传送结束后,将启动源的中断标志清0 */
DMAC0.DMSAR = (void *)&SCI1.RDR; /* 源地址: SCI1.RDR register */
DMAC0.DMDAR = (void *)sciRxBuf; /* 目标地址: 接收缓存 */
DMAC0.DMCRA = 250; /* DMCRA.DMCRAL = 0, 指定传送个数 1024*/
/* DMCRA.DMCRAH = 0, 指定备份传送个数1024 */
IPR(DMAC,DMAC0I) = 10; /* DMAC0I中断优先级: Level 12 */
DMAC0.DMINT.BIT.DTIE = 1; /* 允许传送结束中断请求 */
IEN(DMAC,DMAC0I) = 1; /* 允许DMAC0I的中断请求 */
DMAC0.DMCNT.BIT.DTE = 1; /* 允许DMA传送数据 */
}
void dmac1_init(void)//发送DMA通道1
{
IEN(DMAC,DMAC1I) = 0; /* 禁用DMAC1I的中断请求 */
DMAC1.DMCNT.BIT.DTE = 0; /* 禁用DMA传送 */
ICU.DMRSR1 = 220; /* DMAC1的请求源:TXI ,(TXI中断向量号为220)*/
DMAC1.DMAMD.BIT.DM = 0; /* 目标地址更新方式:固定 ,值为00b */
DMAC1.DMAMD.BIT.SM = 2; /* 源地址更新方式:递增 , 值为10b */
DMAC1.DMAMD.BIT.DARA = 0; /* 目标地址扩展重复区域:不指定 */
DMAC1.DMAMD.BIT.SARA = 0; /* 源地址扩展重复区域 :不指定*/
DMAC1.DMTMD.BIT.DCTG = 1; /* DMA 请求源: 外设中断 */
DMAC1.DMTMD.BIT.SZ = 0; /* 数据传送长度: 8 bits */
DMAC1.DMTMD.BIT.MD = 0; /* 传送模式: 正常传送 */
DMAC1.DMCSL.BIT.DISEL = 0; /* 传送结束后,将启动源的中断标志清0 */
DMAC1.DMSAR = (void *)sciTxBuf; /* 源地址: 传送缓存 */
DMAC1.DMDAR = (void *)&SCI1.TDR; /* 目标地址: SCI1.TDR 发送寄存器 */
DMAC1.DMCRA = 250; /* 指定传送个数 */
IPR(DMAC,DMAC1I) = 10; /* DMAC1I 中断优先级: Level 12 */
DMAC1.DMINT.BIT.DTIE = 1; /* 允许传送结束中断请求 */
IEN(DMAC,DMAC1I) = 1; /* 允许DMAC1I的中断请求 */
DMAC1.DMCNT.BIT.DTE = 0; /* 允许DMA数据传送 */
}
void init_uart(void)
{
dmac0_init(); /* 初始化DMAC0,用于串口SCI1接收 */
dmac1_init(); /* 初始化DMAC1,用于串口SCI1发送 */
SYSTEM.PRCR.WORD = 0xA502;
MSTP(SCI1) = 0;
SYSTEM.PRCR.WORD = 0xA500;
IEN(SCI1,ERI1) = 0; /* 禁用SCI1.ERI1中断 */
IEN(SCI1,RXI1) = 0; /* 禁用SCI1.RXI1中断 */
IEN(SCI1,TXI1) = 0; /* 禁用SCI1.TXI1中断 */
IEN(SCI1,TEI1) = 0; /* 禁用SCI1.TEI1中断 */
/*SCI1 module stop state cancel*/
SCI1.SCR.BYTE = 0x00; /* 禁用发送和接收 */
while (0x00 != (SCI1.SCR.BYTE & 0xF0)){}/* Confirm that bit is actually 0 */
/*only RE/TE/RIE/TIE==0 can write register*/
MPC.PWPR.BIT.B0WI = 0;
MPC.PWPR.BIT.PFSWE = 1;
MPC.P30PFS.BYTE = 0x0A;//RXD1
MPC.P26PFS.BYTE = 0x0A;//TXD1
MPC.PWPR.BIT.PFSWE = 0;
MPC.PWPR.BIT.B0WI = 1;
/*MPC=RXD and TXD*/
PORT3.PMR.BYTE |= 0x01U;//PORT3.PMR.BIT.B0 = 1;//串口管脚配置
/*PMR=peripheral*/
SCI1.SCR.BIT.CKE = 0; /* 使用内部波特率发生器*/
SCI1.SMR.BYTE = 0x20; /* 时钟源:PCLK */
/* 1个停止位,偶校验,数据位:8,异步通信 */
SCI1.SCMR.BYTE = 0xF2; /* SCI1通信模式:串行通信 */
SCI1.SEMR.BIT.ABCS = 1; /* ABCS值为0: 16个基本时钟为1bit的传送时间 */
/* ABCS值为1: 8个基本时钟为1bit的传送时间 */
SCI1.BRR = 0; /* 波特率: 0->781250bps ,所以最后波特率是1.5M*/
/*interrupt priority*/
IPR(SCI1, ) = 10;
IR(SCI1,RXI1) = 0;
IR(SCI1,TXI1) = 0;
IR(SCI1,ERI1) = 0;//
SCI1.SCR.BIT.RIE = 1;
SCI1.SCR.BIT.RE = 1;
IEN(SCI1,RXI1)=1;
IEN(SCI1,ERI1)=1;
DMAC.DMAST.BYTE = 0x01; /* DMAC启动 */
}
void uart_send(INT8U*pdata,INT8U len)//DMA定长模式发送250字节
{
int i = 0;
if(len>=250)
{
return;//发送长度不对
}
for(i = 0; i < 250; i++)
{
if(i < len)
{
sciTxBuf[i] = pdata[i];
}
else
{
sciTxBuf[i] = 0x00;
}
}
DMAC1.DMCNT.BYTE = 0x00;
DMAC1.DMSAR = (void *)sciTxBuf; /* 源地址: 传送缓存 */
DMAC1.DMCRA = 250; /* 指定传送个数,250字节 */
DMAC1.DMCNT.BYTE = 0x01;
PORT2.PMR.BIT.B6 = 1;
SCI1.SCR.BIT.TIE = 1;
SCI1.SCR.BIT.TE = 1;
IEN(SCI1,TXI1)=1;
}
void Excep_SCI1_ERI1(void)//串口接收错误中断
{
INT8U dummy;
dummy = SCI1.RDR;
dummy+=0;
init_uart_terminal();//重新配置串口
}
void Excep_DMAC_DMAC0I(void)// DMAC DMAC0I RCV
{
INT16U i;
for(i=0;i<250;i++)
{
message_buff[i]=sciRxBuf[i];// 接收内容缓存到message_buff
}
dmac0_init();
}
void Excep_DMAC_DMAC1I(void)// DMAC1 SEND
{
IEN(SCI1,TXI1) = 0;
SCI1.SCR.BIT.TIE = 0;
while(0 != SCI1.SCR.BIT.TIE){}
IR(SCI1,TXI1) = 0;
while(0 == SCI1.SSR.BIT.TEND){}
SCI1.SCR.BIT.TE = 0;
}
这里有一个问题需要大家在使用的时候思考并解决,在通讯过程中因串口丢失数据会导致DMA接收对不齐,也就是上一次的接收和下一次的接收内容会拼在仪器产生一个DMA接收中断,且该次中断的数据无效,并且只要一出现对不齐,如果不采取措施的话,那么以后永远都对不齐了。这个问题大家自行解决,也可以在评论区分享自己的见解。
相关问答
STM32中 DMA 有什么好处?用和不用当然都可以发送。不用DMA发送是需要单片机实时参与,由单片机一个一个地发送数据并进行监控。但是如果用DMA,设置了起始地址,数据大小等参数后,就直接...
5通道 dma 是啥?在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省...
DMA 是什么,有什么功能?DMA(DirectMemoryAccess,直接内存存取)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。否则,CPU需要从...
stm32系列 单片机 区别?1、内核:51单片机采用的是51Core,8Bit@2MHzMax(分频后),0.06DMIPS;STM32采用的是ARMCortex-M3,32Bit@72MHz,1.25DMIPS2、地...
单片机 通讯协议有哪些?1、单片机与其他单片机或芯片级的通讯协议有:RS232、IIC、SPI、并口(I/O)、DMA(如msp430、ARM);2、单片机通过电缆与PC或其他设备通讯协议有:RS232、RS485...
单片机 如何通过ADC模块采集模拟信号?朋友们好,我是电子及工控技术,我来回答这个问题。众所周知单片机是一种超大规模的集成电路,它只能“读懂”并处理数字信号,对于连续量的模拟信号则无能为力。...
单片机 和cpu区别?一、不同的指代1、CPU:作为计算机系统的操作和控制核心,是信息处理和程序操作的最终执行单元。2、单片机:又称mcu,是适当降低中央处理器的频率和规格,将存...
单片机 控制卡原理图你说的是Rabbit5000吗。Rabbit5000是第一个具备16位内部总线架构的Rabbit微处理器,对于使用外扩16位内存设备提供了明显的性能提升。它也支持8...
手机的CPU算 单片机 么?手机芯片也是单片机,不过这个单片机功能比一般的单片机强大很多。它们大多是32位的单片机,大多是ARM内核。不像我们平时用的都是4位或者是8位的,而且它们可以...
s3c2410是 单片机 吗?S3C2410处理器是Samsung公司基于ARM公司的ARM920T处理器核,采用FBGA封装,采用0.18um制造工艺的32位微控制器。该处理器拥有:独立的16KB指令Cache和16KB数据Ca...