|
1. Свързване на горния и долния етаж В предишната секция говорихме за използването на ADC и взехме проби от температурния сензор на чипа. В реални проекти броят на сензорите често е голям и трябва да се обработват големи количества данни за преобразуване. Преместването на тези данни ще натовари много процесора. За да освободите процесора и да му дадете енергия за други задачи, DMA (Директен достъп до паметта) може да бъде полезен~ Следващото въведение е извадено от Zigbee Technology Practice Tutorial: DMA е съкращение от директен достъп до паметта, което означава "директен достъп до паметта". Това е високоскоростен режим на предаване на данни, при който периферни устройства като ADC/UART/RF трансивъри и памет могат да обменят данни директно под контрола на "DMA контролера" без минимална намеса на процесора. Освен че извършва малко обработка в началото и края на трансфера на данни, процесорът може да извършва и друга работа по време на трансфера. По този начин процесорът и тези взаимодействия с данни работят паралелно през повечето време. В резултат на това общата ефективност на системата може значително да се подобри.
Както се вижда от въведението, DMA може да се използва в много ситуации. Този експеримент включва само най-простото DMA предаване и има за цел да демонстрира общата употреба на DMA. Що се отнася до приложението на DMA в други сценарии, тя ще бъде приложена в цялостни експерименти в бъдеще. 2. Експеримент с DMA предаване(1) Въведение в експериментаСимволи от масиваsourceStringСъдържанието се прехвърля в масива от символи чрез DMAdestString, резултатът от конверсията се показва на компютъра през серийния порт. (2) Схема на потока на програмата
(3) Експериментален изходен код и анализ/*
Експериментално описание: Съдържанието на sourceString на символния масив се прехвърля към символния масив destString чрез DMA, а резултатът от конверсията се показва на компютъра през серийния порт.
*/
#include
#define led1 P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma bitfields=обърнати
typedef Struct
{
без подпис ЧарSRCADDRH; //源地址高8位
без подпис ЧарSRCADDRL; //源地址低8位
без подпис ЧарDESTADDRH; //目的地址高8位
без подпис ЧарDESTADDRL; //目的地址低8位
без подпис ЧарVLEN :3; //长度域模式选择
без подпис ЧарЛЕНХ:5; //传输长度高字节
без подпис ЧарLENL :8; //传输长度低字节
без подпис ЧарРАЗМЕР НА ДУМАТА:1; //字节(byte)或字(word)传输
без подпис ЧарTMODE:2; //传输模式选择
без подпис ЧарТРИГ :5; //触发事件选择
без подпис ЧарSRCINC :2; //源地址增量:-1/0/1/2
без подпис ЧарDESTINC :2; //目的地址增量:-1/0/1/2
без подпис ЧарIRQMASK:1; //中断屏蔽
без подпис ЧарM8 :1; //7或8bit传输长度,仅在字节传输模式下适用
без подпис ЧарПРИОРИТЕТ:2; //优先级 }DMA_CFG; #pragma bitfields=по подразбиране
/*系统时钟初始化
-------------------------------------------------------*/
Празнотаxtal_init(Празнота)
{ СЪН &= ~0x04; //都上电
докато(! (СЪН &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Изберете кристален осцилатор с честота 32MHz СЪН |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
Празнотаled_init(Празнота)
{ P1SEL =0x00; P1 е нормалният I/O порт P1DIR |=0x0F; P1.0 P1.1 P1.2 P1.3 изход
led1 =1; //关闭所有LED led2 =1; led3 =1; LED4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
ПразнотаUart0Init(без подпис ЧарStopBits,без подпис ЧарПаритет)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Изберете UART0 като първа опционална позиция, тоест RXD към P0.2 и TXD към P0.3
U0CSR =0xC0; Настройте на UART режим и активирайте акцептора
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Паритет; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
Празнота Uart0Send(без подпис Чарданни)
{
докато(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = данни;
}
/*UART0发送字符串
-------------------------------------------------------*/
ПразнотаUart0SendString(без подпис Чар*s)
{
докато(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
Празнотаосновно(Празнота)
{ DMA_CFG dmaConfig; //定义配置结构体
без подпис ЧарsourceString[]="Аз съм SourceString!"; //源字符串
без подпис ЧарdestString[размер на(sourceString)] ="Аз съм дестСтрун!"; //目的字符串
Чарi;
Чаргрешка=0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sourceString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(без подпис Чар)((без подпис int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(без подпис Чар)((без подпис int)&sourceString);
dmaConfig.DESTADDRH=(без подпис Чар)((без подпис int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(без подпис Чар)((без подпис int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(без подпис Чар)((без подпис int)размер на(sourceString) >>8); //传输长度 dmaConfig.LENL=(без подпис Чар)((без подпис int)размер на(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Няма задействане (може да се разбира като ръчно задействане)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(без подпис Чар)((без подпис int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(без подпис Чар)((без подпис int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
докато(! (DMAIRQ&0x01)); //等待传输结束
за(i=0; i <размер на(източникString); i++) //校验传输的正确性 {
ако(sourceString!=destString) грешка++; }
ако(грешка==0) //将结果通过串口传输到PC { Uart0SendString("Точно така!"); Uart0SendString(destString); //传输后的目的字符数组 }
Друго Uart0SendString("Грешка!");
докато(1);
}
Основният процес на използване на DMA е:Конфигуриране на DMA → Активиране на конфигурацията → Започнете трансфера на DMA → Изчакайте трансфера за DMA да приключи.Следните са съответно: (1) Конфигуриране на DMA: Първо, трябва да се конфигурира DMA, но конфигурацията на DMA е специална: вместо директно да присвоява стойности на някои SFR, тя дефинира структура външно, присвоява ѝ стойности и след това присвоява високите 8 бита от първия адрес на тази структураDMA0CFGH, което му дава по-ниски 8 цифриDMA0CFGL。 (За подробни инструкции относно конфигурационната структура, моля, вижте китайското ръководство CC2430) Съвети за CC2430Има две точки, които трябва да се изяснят относно дефиницията на конфигурационните структури в горния изходен код: (1) Битов домейн При дефиниране на тази структура се използват много двоеточия (:), последвани от число, наречено "битово поле": Битовият домейн означава, че информацията не трябва да заема цял байт при съхранение, а заема само няколко или един двоичен бит. Например, при съхранение на превключваща величина има само две състояния – 0 и 1, и можете да използвате еднобитов двоичен файл. За да спести място за съхранение и да улесни обработката, C предоставя структура от данни, наречена "битово поле" или "битово поле". Т.нар. "битово поле" разделя бинарните файлове в байт на няколко различни области и описва броя на битовете във всяка област. Всеки домейн има домейн име, което позволява операции по домейн име в програмата. Това позволява няколко различни обекта да бъдат представени в байтово двоично битово поле. (2) Абстрахиране на общи функции Внимателните читатели ще открият, че присвояването на стойност на структура често включва присвояване на 16-битова беззнакова int стойност на две 8-битови незнакови стойности на символ, както следва: dmaConfig.SRCADDRH=(без подпис Чар)((без подпис int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(без подпис Чар)((без подпис int)&sourceString);
За този тип често използвана функция, можем да я абстрахираме като обща функция, както следва: #define SET_WORD(destH,destL,word)
правя{ destH=(без подпис Чар)((без подпис int)дума >>8); destL=(без подпис Чар)((без подпис int)word); }докато(0)
В бъдеще, когато трябва да извършите подобна операция по разделяне, можете да я извикате директно, както следва: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Активиране на конфигурацията: Първо, първият адрес на структурата&dmaConfigВисоките/ниските 8 бита се присвояват съответно на SFRDMA0CFGHиDMA0CFGL(където 0 представлява конфигурацията за канал 0, CC2430 съдържа 5 DMA канала, тук се използва канал 0). ДаDMAARM.0Задайте стойност 1, за да активирате конфигурацията на канал 0 така, че канал 0 да е в работен режим. (3) Активиране на предаване на DMA:ДясноDMAREQ.0Задайте стойност 1, за да започнете DMA предаването на канал 0. (4) Изчакайте DMA да бъде предадено:След като DMA на канал 0 бъде изпратен, прекъсването се задейства и ще се задейства флагът за прекъсване на канал 0DMAIRQ.0ще бъде автоматично настроено на 1. Всеки символ от двата низа се сравнява и резултатът от верификацията се изпраща на компютъра. (4) Експериментални резултатиПърво отворете инструмента за дебъгване на сериен порт, след това започнете отстраняването на грешки в CC2430, и ще се появи следният екран:
Ще намеритеdestStringСъдържанието е напълно разкритоsourceStringзапълнена. Готово~ 3. ЗаключениеТози раздел въвежда използването на DMA, макар че е много просто, но мисля, че сте разбрали основното приложение на DMA и можете да го анализирате спокойно, когато се сблъскате със сложните му сценарии в бъдеще. Без значение колко добър е десктопът, той ще замръзне, а по същия начин вградената система неизбежно ще застине. В следващия раздел ще представим много ефективен метод за систематично нулиране: watchdogs.
|