嵌入式成长轨迹49 【Zigbee项目】【CC2430基础实验】【DMA】
DMA控制器
CC2430 内置一个存储器直接存取(DMA) 控制器。该控制器可以用来减轻 8051 CPU核传送数据时的负担,实现CC2430在高效利用电源的条件下的高性能。只需要CPU 极少的干预,DMA控制器就可以将数据从ADC或RF收发器传送到存储器。DMA控制器匹配所有的DMA传送,
确保DMA请求和CPU 存取之间按照优先等级协调、合理地进行。DMA控制器含有若干可编程设置的DMA信道,用来实现存储器一存储器的数据传送。
DMA 控制器控制数据传送超过整个外部数据存储器空间。由于SFR 寄存器映射到DMA存储器空间,使得DMA信道的操作能够减轻CPU 的负担。例如,从存储器传送数据到USART,按照定下来的周期在ADC和存储器之间传送数据;通过从存储器中传送一组参数到I/O 口的输出寄存器,产生需要得到的I/O 波形。使用DMA可以保持CUP 在休眠(即低能耗模式下)与外部设备之闻传送数据,这就降低了整个系统的能耗。 ’
DMA控制器的主要性能如下:
●5 个独立的 DMA信道
●3 个可以配置的 DMA信道优先级;
●3 1个可以配置的传送触发事件;
●源地址和目标地址的独立控制;
●3 种传送模式:单独传送、数据块传送和重复传送;
●支持数据从可变长域传送到固定长度域;
●既可以工作在字(word-size) 模式,又可以工作在字节(byte-size)模式。
l. DMA 操作
DMA控制器有5 个信道,即 DMA信道0 ~4 。每个 DMA信道能够从DMA.存储器空间传送数据到外部数据(XDATA) 空间。
当DMA信道配置完毕后,在允许任何传送初始化之前,必须进入工作状态。DMA信道通过将DMA信道工作状态寄存器中指定位(即DMAARM) 置1 ,就可以进入工作状态。
一旦DMA.信道进入工作状态,当设定的DMA.触发事件发生时,传送就开始了。可能的DMA.触发事件有3 1 个,例如 UARS、传送、计数器溢出等。DMA.信道要使用的触发事件在配置DMA信道时设置,所有的这些触发事件如表6-1 4所列。
补充一点,为了通过 DMA触发事件开始DMA传送,用户软件可以设置对应的 DMAREQ位,使DMA传送开始
2.DMA配置参数
DMA的安装和控制由用户软件完成。DMA信道能够使用之前,必须配置参数。每个DMA信道的特性都与下列参数有关:源地址、不标地址、传送长度、可变长度(VLEN)设置、优先级别、触发事件、源地址和目标地址增量、DMA传送模式、字节传送或字传送、中断屏蔽和设置M8模式。
(l )源地址
DMA 信道要读的数据的首地址。
(2 )目标地址
DMA 信道从源地址读出的要写数据的首地址。用户必须确认该目标地址可写。
(3 )传送长度
在DMA信道重新进入工作状态或者解除工作状态之前,以及预警 CPU 即将有中断请求到
来之前,要传送的长度。可以在配置DMA.参数时设置该长度,或者将DMA.读出的第一个字
节/ 字用作该长度。
(4 )可变长度(VLEN) 设置
DMA 信道可以利用源数据中的第一个字节或字(对于字,使用[1 2 :O]位)作为传送长度。使用可变长度传送时,要给出不同的传送字节长度。在任何情况下,都是设置传送长度(LEN)为传送的最大长度。注意,仅在选择字节长度传送数据时才可以使用M8位模式。可以同 VLEN一起设置的选项如下:
·要传送的字节/ 字的长度,设置在第1 字节/ 字+1处;
·要传送的字节/ 字的长度,设置在第l 字节/ 字处;
·要传送的字节/ 字的长度,设置在第1 字节/ 字+2处;
·要传送的字节/ 字的长度,设置在第1 字节/ 字+3处。
(5 )优先级别
DMA 传送的优先级别与每个 DMA.存取岛相关,而且对每个 DMA。信道可以配置。DMA优先级别用于判定同时发生的多个内部存储器请求中的哪一个优先级最高,以及DMA 存储器存取的优先级别是否超过同时发生的CPU 存储器存取的优先级别。在同属内部关系的情况下,采用轮转调度(rounld-robin) 方案应对所有的请求,确认存取对象。
DMA优先级有3 级:
·高级:最高内部优先级别。DMA存取总是优于CPU 存取。
·保证级:中等内部优先级别。保证 DMA存取至少在每秒一次的尝试中优于CPU 存取.
·低级:最低内部优先级别。DMA存取总是劣于CPU 存取。
(6 )触发事件
可以设置每个DMA.信道接受单个事件的触发。这样一来,就可以判定DMA 信道会接受哪一个事件的触发。
(7 )源地址和目标地址增量
当DMA 信道进入工作状态或者重新进入工作状态时,源地址和目标地址传送到内部地址指针。其地址增量可能有下列4 种:
●增量为 0 :每次传送之后,地址指针将保持不变。
●增量为 l :每次传送之后,地址指针将加上 1 。
●增量为 2 :每次传送之后,地址指针将加上 2 。
●减量为1:每次传送之后,地址指针将减去1。
(8 )DMA传送模式
共有4 种DMA。传送模式:
●单一模式:每当触发时,发生单一 DMA传送;此后,DMA信道等待下一个触发。完成指定的传送长度后,传送结束,通报CPU 解除DMA信道的工作状态。
●阻塞(Block)模式:每当触发时,若干 DMA传送按照指定的传送长度尽快传送;此后,通报CPU 解除DMA信道的工作状态。
●重复的单一模式:每当触发时,发生单一 DMA传送;此后,DMA信道等待下一个触发。完成指定的传送长度后,传送结束,通报CPU DMA 信道重新进入工作状态。
●重复的阻塞(Block)模式;每当触发时,若干DMA传送按照指定的传送长度尽快传 送;此后多通报CPU DMA 信道重新进入工作状态。
(9 )字节传送或字传送
判定已经完成的传送究竟是 8 位(字节)还是16 位(字)。
(10 )中断屏蔽
在完成DMA传送的基础上,该DMA信道能够产生一个中断到CPU 。但是,该中断可以
被屏蔽位IRQMASK 所屏蔽。
(11 )设置 M8模式
这个域的值,决定是否采用 7 位还是8 位长的字节来传送数据。此模式仅仅适用于字节传送。
3. DMA 配置安装
DMA. 的参数(诸如地址模式、传送模式和优先级别等)必须在DMA信道进人工作状态之前有效。参数不直接通过SFR 寄存器配置,而是通过写入存储器中特殊的DMA配置数据结构中配置。对于每个 DMA信道,需要有它自己的 DMA配置数据结构。DMA配置数据结构可以存放在由用户软件设定的任何位置,而地址通过DMAxCFGH :DMAxCFGi(x=0~1 )送到 DMA控制器。一旦DMA信道进入工作状态粤DMA.控制器就会读取该信道的配置数据结构。
需要注意的是,指定DMA.配置数据结构开始地址的方法十分重要。这些地址对于DMA信道0 和DMA。信道1~4 是不同的:
●DMAOcFGH:DMAOCFGI。给出DMA.信道O 配置数据结构的开始地址;
●DMAl CFGH:DMAI CFGI。给出 DMA。信道 l 配置数据结构的开始地址,其后跟着信道2---4 的配置数据结构。
4. 停止DMA传送
停止正在运行的DMA传送有两种方法:
●将1 写入DMAARM-ABORT,就会取消所有进入工作状态的DMA.信道;
●将0 写入DMA信道对应的进人工作状态位(即DMAARM。DMAARMx),就会停止 该DMA信道。
5.DMA中断
每个DMA.信道可以配置为一旦完成DMA.传送,就产生中断到CPU 。该功能由 IRQMASK 位在信道配置时实现。当中断产生时,特殊功能寄存器DMAIRQ中所对应的中断标志位置1 。
一旦DMA.信道完成传送,不管在信道配置中IRQMASK 位是何值,中断标志都会置1 。这样,当重新进人工作状态时,软件总是能够检测(以及清除)这个寄存器,使IRQMASK 已经
置1 。
6.DMA配置数据结构
对于每个DMA信道,DMA数据结构由8 个字节组成
1 /***************************************** 2 // For: CC1110 in PS 3 // emot.h 4 *****************************************/ 5 #ifndef EMOT_H 6 #define EMOT_H 7 8 #include <ioCC1110.h> 9 10 /***************************************** 11 //定义类型 12 *****************************************/ 13 typedef unsigned char BOOL; 14 15 // Data 16 typedef unsigned char BYTE; 17 typedef unsigned short WORD; 18 typedef unsigned long DWORD; 19 20 // Unsigned numbers 21 typedef unsigned char UINT8; 22 typedef unsigned char INT8U; 23 typedef unsigned short UINT16; 24 typedef unsigned short INT16U; 25 typedef unsigned long UINT32; 26 typedef unsigned long INT32U; 27 28 // Signed numbers 29 typedef signed char INT8; 30 typedef signed short INT16; 31 typedef signed long INT32; 32 33 #define uchar unsigned char 34 #define uint unsigned int 35 36 /***************************************** 37 //定义常量 38 *****************************************/ 39 #ifndef FALSE 40 #define FALSE 0 41 #endif 42 43 #ifndef TRUE 44 #define TRUE 1 45 #endif 46 47 #ifndef NULL 48 #define NULL 0 49 #endif 50 51 #ifndef HIGH 52 #define HIGH 1 53 #endif 54 55 #ifndef LOW 56 #define LOW 0 57 #endif 58 59 /***************************************** 60 //中断 61 *****************************************/ 62 #define DISABLE_ALL_INTERRUPTS() (IEN0 = IEN1 = IEN2 = 0x00) 63 64 /***************************************** 65 //LED 使能控制 66 *****************************************/ 67 #define LED_ENABLE(val) \ 68 do{ \ 69 if(val==1) \ 70 { \ 71 P1SEL &= ~0X03; \ 72 P1DIR |= 0X03; \ 73 RLED = 1; \ 74 GLED = 1; \ 75 } \ 76 else \ 77 { \ 78 P1DIR &= ~0X03; \ 79 } \ 80 }while(0) 81 82 #define RLED P1_0 83 #define GLED P1_1 84 85 /***************************************** 86 //时钟相关寄存器 87 *****************************************/ 88 // Macro for getting the clock division factor 89 #define CLKSPD (CLKCON & 0x07) 90 91 // Macro for getting the timer tick division factor. 92 #define TICKSPD ((CLKCON & 0x38) >> 3) 93 94 // Macro for checking status of the crystal oscillator 95 #define XOSC_STABLE (SLEEP & 0x40) 96 97 // Macro for checking status of the high frequency RC oscillator. 98 #define HIGH_FREQUENCY_RC_OSC_STABLE (SLEEP & 0x20) 99 100 /***************************************** 101 //选择主时钟,关闭不用的时钟 102 *****************************************/ 103 #define SET_MAIN_CLOCK_SOURCE(source) \ 104 do { \ 105 if(source) { \ 106 CLKCON |= 0x40; /*RC*/ \ 107 while(!HIGH_FREQUENCY_RC_OSC_STABLE); /*待稳*/ \ 108 SLEEP |= 0x04; /*关掉不用的*/ \ 109 } \ 110 else { \ 111 SLEEP &= ~0x04; /*全开*/ \ 112 while(!XOSC_STABLE);/*待稳*/ \ 113 asm("NOP"); \ 114 CLKCON &= ~0x47; /*晶振*/ \ 115 SLEEP |= 0x04; /*关掉不用的*/ \ 116 } \ 117 }while (0) 118 119 #define CRYSTAL 0 120 #define RC 1 121 122 /***************************************** 123 //选择低速时钟 124 *****************************************/ 125 #define SET_LOW_CLOCK(val) \ 126 do{ \ 127 CLKCON |= (val)?(CLKCON|0X80):(CLKCON & ~0X80); \ 128 }while(0) 129 130 131 132 //Macro for setting the clock tick for timer3 or 4 133 #define TIMER3_START(val) \ 134 (T##timer##CTL = (val) ? T##timer##CTL | 0X10 : T##timer##CTL&~0X10) 135 136 #define TIMER3_SET_CLOCK_DIVIDE(timer,val) \ 137 do{ \ 138 T##timer##CTL &= ~0XE0; \ 139 (val==2) ? (T##timer##CTL|=0X20): \ 140 (val==4) ? (T##timer##CTL|=0x40): \ 141 (val==8) ? (T##timer##CTL|=0X60): \ 142 (val==16)? (T##timer##CTL|=0x80): \ 143 (val==32)? (T##timer##CTL|=0xa0): \ 144 (val==64) ? (T##timer##CTL|=0xc0): \ 145 (val==128) ? (T##timer##CTL|=0XE0): \ 146 (T##timer##CTL|=0X00); /* 1 */ \ 147 }while(0) 148 149 //Macro for setting the mode of timer3 or 4 150 #define TIMER3_SET_MODE(timer,val) \ 151 do{ \ 152 T##timer##CTL &= ~0X03; \ 153 (val==1)?(T##timer##CTL|=0X01): /*DOWN */ \ 154 (val==2)?(T##timer##CTL|=0X02): /*Modulo */ \ 155 (val==3)?(T##timer##CTL|=0X03): /*UP / DOWN */ \ 156 (T##timer##CTL|=0X00); /*free runing */ \ 157 }while(0) 158 159 160 #define SET_POWER_MODE(mode) \ 161 do { \ 162 if(mode == 0) { SLEEP &= ~0x03; } \ 163 else if (mode == 3) { SLEEP |= 0x03; } \ 164 else { SLEEP &= ~0x03; SLEEP |= mode; } \ 165 PCON |= 0x01; \ 166 asm("NOP"); \ 167 }while (0) 168 169 /***************************************** 170 //开启电池板上的按键 171 *****************************************/ 172 #define USE_KEY_ON_BT() \ 173 do{ \ 174 P1DIR &= ~0X0C; /*按键在P12 P13*/\ 175 P1INP &= ~0x0c; //上、下拉 \ 176 P2INP |= 0x40; \ 177 }while(0) 178 179 /***************************************** 180 //延时程序 181 *****************************************/ 182 #define DELAY(val) \ 183 do{ \ 184 uint jj; \ 185 for(jj=0;jj<val;jj++); \ 186 for(jj=0;jj<val;jj++); \ 187 for(jj=0;jj<val;jj++); \ 188 for(jj=0;jj<val;jj++); \ 189 for(jj=0;jj<val;jj++); \ 190 }while(0) 191 192 193 #endif //EMOT_H
1 /********************************************************************* 2 * DMA.c 3 * 目标芯片:CC1110F32 功能:配置DMA 4 */ 5 6 #include <emot.h> 7 struct setdata{ 8 uchar SRCADDRH; 9 UINT8 SRCADDRL; 10 UINT8 DESTADDRH; 11 UINT8 DESTADDRL; 12 UINT8 VLEN3_LEN5; 13 UINT8 LEN; 14 UINT8 WORDSIZE_TMODE2_TRIG5; 15 UINT8 SRCINC2_DESTICN2_IRQMASK_M8_PRIORITY2; 16 }DMA_CFG_DATA={ 17 0x00, 18 0x00, 19 0x00, 20 0x00, 21 0x00, 22 0x00, 23 0x00, 24 }; 25 26 /********************************************************************* 27 *设源地址 28 */ 29 #define SET_DMA_SRCADDR(para1,para2) \ 30 do{ \ 31 DMA_CFG_DATA.SRCADDRH=para1;/*源地址高位*/ \ 32 DMA_CFG_DATA.SRCADDRL=para2;/*源地址低位*/ \ 33 }while(0); 34 35 /********************************************************************* 36 *设目标地址高位 37 */ 38 #define SET_DMA_DESTADDR(para1,para2) \ 39 do{ \ 40 DMA_CFG_DATA.DESTADDRH=para1;/*目标地址高位*/ \ 41 DMA_CFG_DATA.DESTADDRL=para2;/*目标地址低位*/ \ 42 }while(0); 43 44 /********************************************************************* 45 *设定数据长度 46 */ 47 #define SET_DMA_LEN(para1) \ 48 do{ \ 49 DMA_CFG_DATA.LEN=para1; \ 50 51 52 /********************************************************************* 53 *设定传输长度 54 */ 55 #define SET_DMA_TR_LEN(para1) DMA_CFG_DATA.VLEN=(para1<<5) 56 57 /********************************************************************* 58 * 59 */
1 //dma main.c 2 #include <emot.h> 3 #include <dma.c> 4 5 6 void main() 7 { 8 DMA_CFG_DATA.LEN = 0X00; 9 for(;;); 10 }