|
1. Connecting the upper and lower levels In the previous section, we talked about the use of ADCs and sampled the on-chip temperature sensor. In actual projects, the number of sensors is often large and a large amount of conversion data is to be processed. Moving this data will put a lot of strain on the CPU. In order to free up the CPU and give it the energy to do other things, DMA (Direct Memory Access) can come in handy~ The following introduction is excerpted from the Zigbee Technology Practice Tutorial: DMA is an abbreviation for direct memory access, which is "direct memory access". This is a high-speed data transmission mode in which peripheral units such as ADC/UART/RF transceivers and memory can exchange data directly under the control of the "DMA controller" without little CPU intervention. In addition to doing a little processing at the beginning and end of the data transfer, the CPU can do other work during the transfer. This way, the CPU and these data interactions are working in parallel most of the time. As a result, the overall efficiency of the system can be greatly improved.
As you can see from the introduction, DMA can be used in many scenarios. This experiment involves only the simplest DMA transmission and aims to demonstrate the general use of DMA. As for the application of DMA in other scenarios, it will be implemented in comprehensive experiments in the future. 2. DMA transmission experiment(1) Introduction to the experimentArray characterssourceStringThe content is transferred to the character array via DMAdestString, the conversion result is displayed on the PC through the serial port. (2) Program flow chart
(3) Experimental source code and analysis/*
Experimental Description: The contents of the character array sourceString are transferred to the character array destString through DMA, and the conversion result is displayed on the PC through the serial port.
*/
#include
#define led1 P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma bitfields=reversed
typedef struct
{
unsigned charSRCADDRH; //源地址高8位
unsigned charSRCADDRL; //源地址低8位
unsigned charDESTADDRH; //目的地址高8位
unsigned charDESTADDRL; //目的地址低8位
unsigned charVLEN :3; //长度域模式选择
unsigned charLENH :5; //传输长度高字节
unsigned charLENL :8; //传输长度低字节
unsigned charWORDSIZE :1; //字节(byte)或字(word)传输
unsigned charTMODE :2; //传输模式选择
unsigned charTRIG :5; //触发事件选择
unsigned charSRCINC :2; //源地址增量:-1/0/1/2
unsigned charDESTINC :2; //目的地址增量:-1/0/1/2
unsigned charIRQMASK :1; //中断屏蔽
unsigned charM8 :1; //7或8bit传输长度,仅在字节传输模式下适用
unsigned charPRIORITY :2; //优先级 }DMA_CFG; #pragma bitfields=default
/*系统时钟初始化
-------------------------------------------------------*/
voidxtal_init(void)
{ SLEEP &= ~0x04; //都上电
while(! (SLEEP &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Choose a 32MHz crystal oscillator SLEEP |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
voidled_init(void)
{ P1SEL =0x00; P1 is the normal I/O port P1DIR |=0x0F; P1.0 P1.1 P1.2 P1.3 output
led1 =1; //关闭所有LED led2 =1; led3 =1; led4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
voidUart0Init(unsigned charStopBits,unsigned charParity)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Select UART0 as the first optional position, that is, RXD to P0.2 and TXD to P0.3
U0CSR =0xC0; Set to UART mode and enable the acceptor
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Parity; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
void Uart0Send(unsigned chardata)
{
while(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = data;
}
/*UART0发送字符串
-------------------------------------------------------*/
voidUart0SendString(unsigned char*s)
{
while(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
voidmain(void)
{ DMA_CFG dmaConfig; //定义配置结构体
unsigned charsourceString[]="I'm the sourceString!"; //源字符串
unsigned chardestString[sizeof(sourceString)] ="I'm the destString!"; //目的字符串
chari;
charerror=0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sourceString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(unsigned char)((unsigned int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(unsigned char)((unsigned int)&sourceString);
dmaConfig.DESTADDRH=(unsigned char)((unsigned int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(unsigned char)((unsigned int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(unsigned char)((unsigned int)sizeof(sourceString) >>8); //传输长度 dmaConfig.LENL=(unsigned char)((unsigned int)sizeof(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; No trigger (can be understood as manual triggering)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(unsigned char)((unsigned int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(unsigned char)((unsigned int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
while(! (DMAIRQ&0x01)); //等待传输结束
for(i=0; i <sizeof(sourceString); i++) //校验传输的正确性 {
if(sourceString!=destString) error++; }
if(error==0) //将结果通过串口传输到PC { Uart0SendString("Correct!"); Uart0SendString(destString); //传输后的目的字符数组 }
else Uart0SendString("Error!");
while(1);
}
The basic process of using DMA is:Configure DMA → Enable configuration → Start DMA transfer → Wait for the DMA transfer to finish.The following are respectively: (1) Configure DMA: First of all, DMA must be configured, but the configuration of DMA is special: instead of directly assigning values to some SFRs, it defines a structure externally, assigns values to it, and then assigns the high 8 bits of the first address of this structureDMA0CFGH, giving it a lower 8 digitsDMA0CFGL。 (For detailed instructions in the configuration structure, please refer to the CC2430 Chinese manual) CC2430 TipsThere are two points to clarify about the definition of configuration structs in the source code above: (1) Bit domain When defining this struct, a lot of colons (:) are used, followed by a number, which is called "bit field": Bit domain means that information does not need to occupy a full byte when stored, but only occupies a few or one binary bit. For example, when storing a switching quantity, there are only two states, 0 and 1, and you can use one bit binary. To save storage space and make processing easier, C provides a data structure called "bit field" or "bit field". The so-called "bit field" divides the binaries in a byte into several different regions and describes the number of bits in each region. Each domain has a domain name, allowing operations by domain name in the program. This allows several different objects to be represented in a byte binary bitfield. (2) Abstract common functions Attentive readers will find that assigning a value to a struct often involves assigning a 16-bit unsigned int type value to two 8-bit unsigned char type values, as follows: dmaConfig.SRCADDRH=(unsigned char)((unsigned int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(unsigned char)((unsigned int)&sourceString);
For this type of frequently used function, we might as well abstract it as a general function, as follows: #define SET_WORD(destH,destL,word)
do{ destH=(unsigned char)((unsigned int)word >>8); destL=(unsigned char)((unsigned int)word); }while(0)
In the future, whenever you need to perform a similar splitting operation, you can call it directly, as follows: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Enable configuration: First, the first address of the structure&dmaConfigThe high/low 8 bits are assigned to SFR respectivelyDMA0CFGHandDMA0CFGL(where 0 represents the configuration for channel 0, CC2430 contains 5 DMA channels, channel 0 is used here). YesDMAARM.0Assign a value of 1 to enable the configuration of channel 0 so that channel 0 is in working mode. (3) Enable DMA transmission:RightDMAREQ.0Assign a value of 1 to start the DMA transmission of channel 0. (4) Wait for the DMA to be transmitted:After the DMA of channel 0 is transmitted, the interrupt will be triggered, and the interrupt flag of channel 0 will be triggeredDMAIRQ.0will be automatically set to 1. Each character of the two strings is then compared and the verification result is sent to the PC. (4) Experimental resultsFirst, open the serial port debugging tool, and then start CC2430 debugging, and the following screen will appear:
You will finddestStringThe content has been completely revealedsourceStringfilled. Done~ 3. ConclusionThis section introduces the use of DMA, although it is very simple, but I think you have understood the basic use of DMA, and you can also analyze it calmly when encountering its complex usage scenarios in the future. No matter how good a desktop is, it will freeze, and similarly, an embedded system will inevitably stagnate. In the next section, we will introduce a very effective method of systematic reset: watchdogs.
|