目录
一、实验介绍
直接存取访问(DMA)控制器可以用来减轻8051CPU内核传送数据操作的负担,从而实现在高效利用电源的条件下的高性能。只需要 CPU 极少的干预,DMA 控制器就可以将数据从诸如 ADC 或 RF 收发器的外设单 元传送到存储器。
DMA 控制器协调所有的 DMA 传送,确保DMA 请求和 CPU 存储器访问之间按照优先等级协调、合理地 进行。DMA控制器含有若干可编程的DMA通道,用来实现存储器-存储器的数据传送。
DMA 控制器控制整个 XDATA 存储空间的数据传送。由于大多数SFR寄存器映射到 DMA存储器空间,这些灵活的DMA通道的操作能够以创新的方式减轻CPU的负担,例如,从存储器传送数据到USART,或定期在ADC和存储器之间传送数据样本等等。使用 DMA 还可以保持CPU在低功耗模式下与外设单元之间传送数据,不需要唤醒,这就降低了整个系统的功耗。
- 5 个独立的 DMA 通道;
- 3 个可以配置的 DMA 通道优先级;
- 32 个可以配置的传送触发事件;
- 源地址和目标地址的独立控制;
- 单独传送、数据块传送和重复传送模式;
- 支持传输数据的长域域,设置可变传输长度。
既可以工作在字模式,又可以工作在字节模式。
二、实验目的
- 通过本实验了解CC2530 的DMA相关寄存器的配置;
- 通过本实验了解CC2530的DMA功能的运用及操作。
三、实验设备
3.1、硬件设备
- ZIGBEE开发板
- SmartRF04EB仿真器
- Micro-USB线
3.2、软件环境
- IAR Embedded Workbench for 8051集成开发环境
- 串口调试助手
四、实验原理
4.1、DMA操作
DMA 控制器有5个通道,即DMA通道0到通道4。每个DMA通道能够从DMA 存储器空间的一个位置传送数据到另一个位置。
当DMA 通道配置完毕后,在允许任何传输发起之前,必须进入工作状态。DMA通道通过将DMA 通道工作状态寄存器DMAARM 中指定位置1,就可以进入工作状态。
一旦DMA 通道进入工作状态,当配置的DMA 触发事件发生时,传送就开始了。DMAREQ 位只能在相应的DMA 传输发生时清除。当通道解除准备工作状态时,DMAREQ 位不被清除。
4.2、DMA配置参数
4.2.1、源地址
DMA通道开始读的数据地址。
4.2.2、目标地址
DMA通道从源地址读出要写的数据首地址。
4.2.3、传送数量/数据长度
DMA传送完成之前必须传送的字节或字的个数。
4.2.4、VLEN设置/传送长度
DMA通道可以利用源数据中的第一个字节或字作为传送长度。
在任何情况下,都设置传送长度为传送的最大长度LEN。若首字节或字指明的传输最大长度大于LEN,那么LEN个字节或字将被传送。
当设置为可变长度传输,LEN应设置为允许传输的最大长度加一。
4.2.5、触发事件
设置每个DMA通道接受单个事件的触发。
4.2.6、源和目标增量
当DMA通道进入工作状态胡总和重新进入工作状态时,源地址和目标地址传送到内部地址指针。
增量为0,每次传送后地址指针将保持不变。
增量为1,每次传送后地址指针将加上1个数。
增量为2,每次传送后地址指针将加上2个数。
减量为1,每次传送后地址指针将减去1个数。
在字节模式下,1个数等于一个字节;在字模式下,1个数等于2个字节。
4.2.7、传送模式
指定DMA通道开始传输时如何工作。
单一模式:触发时发生一个DMA传送并等待下一次触发,完成指定长度后传送结束,通报CPU解除DMA通道的工作状态。
块模式:触发时按照传送长度传送DMA传送,通报CPU解除DMA通道的工作状态。
重复的单一模式:触发时发生一个DMA传送并等待下一次触发,完成指定长度后传送结束,通报CPU重新进入DMA通道的工作状态。
重复的块模式:触发时按照传送长度传送DMA传送,报CPU重新进入DMA通道的工作状态。
4.2.8、优先级
DMA优先级对每个DMA通道是可以配置的,分为高级、一般级、低级。
4.2.9、字节或字传送/单次传送长度
判断已完成的传送是8位还是16位。
4.2.10、中断屏蔽
在完成DMA传送的基础上,该通道能够产生一个中断到CPU,该位可以屏蔽中断。
4.2.11、模式8设置
决定采用7位还是8位的字节来传送数据,仅适用于字节传送。
4.3、DMA配置安装
定义结构体。DMA通道参数必须在DMA通道进入工作状态之前配置并激活,通过写入特殊的DMA配置数据结构中配置。


将结构体首地址分别写入DMA0CFGH和DMA0CFGL。
4.4、相关寄存器
DMAARM寄存器用于启动DMA通道。

DMAREG寄存器用于开启DMA通道请求。

DMAIRG寄存器用来判断DMA传送是否完成。

DMA0CFGH/L寄存器用于存放DMA通道0配置地址。

五、实验演示
现在我们要进行DMA配置并传送数据,实现串口输出对应字符。
首先是分别创建dma.c和dma.h文件,在dma.h文件内定义结构体:
#pragma bitfields=reversed
typedef struct
{
uint8_t SRCADDRH; //源地址高8位
uint8_t SRCADDRL; //源地址低8位
uint8_t DESTADDRH; //目的地址高8位
uint8_t DESTADDRL; //目的地址低8位
uint8_t VLEN :3; //可变长度传输模式
uint8_t LENH :5; //传送长度高5位
uint8_t LENL :8; //传送长度低8位
uint8_t WORDSIZE :1; //8位或16位传送,字节或字传送
uint8_t TMODE :2; //传送模式选择
uint8_t TRIG :5; //触发事件选择
uint8_t SRCINC :2; //源地址增量 -1/0/1/2
uint8_t DESTINC :2; //目标地址增量 -1/0/1/2
uint8_t IRQMASK :1; //中断屏蔽
uint8_t M8 :1; //8位传输长度
uint8_t PRIORITY :2; //优先级别
}DMA_DESC;
#pragma bitfields=default
接着在dma.c文件内初始化DMA:
#include "headfile.h"
char srcbuf[] = "Hello World\n"; //源数组
char destbuf[sizeof(srcbuf)]; //目标数组
void dma_init(void)
{
DMA_DESC dmaconfig;
dmaconfig.SRCADDRH = (uint8_t)((uint16_t)&srcbuf >>8) ; //配置源地址
dmaconfig.SRCADDRL = (uint8_t)((uint16_t)&srcbuf & 0xFF); //&0xFF的作用是防止警告
dmaconfig.DESTADDRH = (uint8_t)((uint16_t)&destbuf >>8); //配置目标地址
dmaconfig.DESTADDRL = (uint8_t)((uint16_t)&destbuf & 0xFF);
dmaconfig.VLEN = 0x00; //LEN为传送长度
dmaconfig.LENH = (uint8_t)((uint16_t)sizeof(srcbuf) >>8); //配置传输长度
dmaconfig.LENL = (uint8_t)((uint16_t)sizeof(srcbuf));
dmaconfig.WORDSIZE = 0x00; //字节传送
dmaconfig.TMODE = 0x01; //块传送模式
dmaconfig.TRIG = 0; //手动触发
dmaconfig.SRCINC = 0x01; //源地址增量为1
dmaconfig.DESTINC = 0x01; //目标地址增量为1
dmaconfig.IRQMASK = 0; //中断屏蔽
dmaconfig.M8 = 0x00; //8为字节传送数据
dmaconfig.PRIORITY = 0x02; //高优先级
DMA0CFGH = (uint8_t)((uint16_t)&dmaconfig >>8); //将配置结构体的首地址赋予相关SFR
DMA0CFGL = (uint8_t)((uint16_t)&dmaconfig & 0xFF);
}
在dma.h文件内要加入以下两行代码,用于声明源数组和目标数组为外部数组,方便在main.c内使用:
extern char srcbuf[20];
extern char destbuf[sizeof(srcbuf)];
接着在main.c内输入以下:
#include "iocc2530.h" //头文件
#include "headfile.h"
char buf[20];
void main(void)
{
clk32m_init();
uart0_init();
dma_init();
DMAARM = 0x01; //启动DMA通道0
DMAIRQ = 0x00; //清除所有中断标志位
DMAREQ = 0x01; //DMA通道0传送请求
while((DMAIRQ & 0x01) == 0); //等待DMA通道0传送完成
sprintf(buf,"finish\r\n");
uartsendstring(buf,sizeof(buf)); //传送完成串口输出
uartsendstring(destbuf,sizeof(destbuf)); //检测是否传输完成
while(1);
}
接上Micro-USB线并打开串口调试助手,当上电时将输出以下结果:

有疑问可以加入QQ群交流:324611467
860

被折叠的 条评论
为什么被折叠?



