|
1. Viršutinio ir apatinio lygių sujungimas Ankstesniame skyriuje kalbėjome apie ADC naudojimą ir ėmėme lusto temperatūros jutiklio mėginius. Faktiniuose projektuose jutiklių skaičius dažnai yra didelis ir reikia apdoroti didelį kiekį konversijos duomenų. Perkėlus šiuos duomenis, procesorius bus labai apkrautas. Siekiant atlaisvinti procesorių ir suteikti jam energijos daryti kitus dalykus, DMA (tiesioginė atminties prieiga) gali būti naudinga ~ Šis įvadas yra ištrauka iš "Zigbee" technologijos praktikos pamokos: DMA yra tiesioginės prieigos prie atminties santrumpa, kuri yra "tiesioginė prieiga prie atminties". Tai didelės spartos duomenų perdavimo režimas, kuriame periferiniai įrenginiai, tokie kaip ADC/UART/RF siųstuvai-imtuvai ir atmintis, gali keistis duomenimis tiesiogiai valdomi "DMA valdiklio" be mažo procesoriaus įsikišimo. Be to, kad duomenų perdavimo pradžioje ir pabaigoje procesorius gali atlikti ir kitus darbus. Tokiu būdu procesorius ir šios duomenų sąveikos didžiąją laiko dalį veikia lygiagrečiai. Dėl to galima labai pagerinti bendrą sistemos efektyvumą.
Kaip matote iš įžangos, DMA gali būti naudojamas daugelyje scenarijų. Šis eksperimentas apima tik paprasčiausią DMA perdavimą ir siekiama parodyti bendrą DMA naudojimą. Kalbant apie DMA taikymą kituose scenarijuose, ateityje jis bus įgyvendintas atliekant išsamius eksperimentus. 2. DMA perdavimo eksperimentas(1) Įvadas į eksperimentąMasyvo simboliaisourceStringTurinys perkeliamas į simbolių masyvą per DMAdestString, konvertavimo rezultatas rodomas kompiuteryje per nuoseklųjį prievadą. (2) Programos eigos schema
(3) Eksperimentinis šaltinio kodas ir analizė/*
Eksperimentinis aprašymas: Simbolių masyvo sourceString turinys perkeliamas į simbolių masyvą destString per DMA, o konvertavimo rezultatas rodomas kompiuteryje per nuoseklųjį prievadą.
*/
#include
#define led1 P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma bitfields=reversed
typedef struktūra
{
nepasirašytas anglisSRCADDRH; //源地址高8位
nepasirašytas anglisSRCADDRL; //源地址低8位
nepasirašytas anglisDESTADDRH; //目的地址高8位
nepasirašytas anglisDESTADDRL; //目的地址低8位
nepasirašytas anglisVLEN :3; //长度域模式选择
nepasirašytas anglisLENH:5; //传输长度高字节
nepasirašytas anglisLENL :8; //传输长度低字节
nepasirašytas anglisŽODŽIO DYDIS:1; //字节(byte)或字(word)传输
nepasirašytas anglisTMODE :2; //传输模式选择
nepasirašytas anglisTRIG:5; //触发事件选择
nepasirašytas anglisSRCINC :2; //源地址增量:-1/0/1/2
nepasirašytas anglisDESTINC :2; //目的地址增量:-1/0/1/2
nepasirašytas anglisIRQMASK :1; //中断屏蔽
nepasirašytas anglisM8 :1; //7或8bit传输长度,仅在字节传输模式下适用
nepasirašytas anglisPRIORITETAS :2; //优先级 }DMA_CFG; #pragma bitfields=numatytasis
/*系统时钟初始化
-------------------------------------------------------*/
tuščiaxtal_init (tuščia)
{ MIEGAS &= ~0x04; //都上电
Nors(! (MIEGO IR0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Pasirinkite 32 MHz kristalinį osciliatorių MIEGO REŽIMAS |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
tuščialed_init (tuščia)
{ P1SEL =0x00; P1 yra įprastas įvesties / išvesties prievadas P1DIR |=0x0F; P1.0 P1.1 P1.2 P1.3 išėjimas
Šviesos diodas1 =1; //关闭所有LED LED2 =1; led3 =1; LED4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
tuščiaUart0Init(nepasirašytas anglisStopBits,nepasirašytas anglisParitetas)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Pasirinkite UART0 kaip pirmąją pasirenkamą padėtį, tai yra, RXD į P0.2 ir TXD į P0.3
U0CSR =0xC0; Nustatykite UART režimą ir įjunkite priėmėją
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Paritetas; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
tuščia Uart0Siųsti(nepasirašytas anglisduomenys)
{
Nors(U0CSR &0x01); //等待UART空闲时发送数据 U0DBUF = duomenys;
}
/*UART0发送字符串
-------------------------------------------------------*/
tuščiaUart0SendString(nepasirašytas anglis*s)
{
Nors(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
tuščiapagrindinis(tuščia)
{ DMA_CFG dmaConfig; //定义配置结构体
nepasirašytas anglissourceString[]="Aš esu šaltinis!"; //源字符串
nepasirašytas anglisdestString[dydis(šaltinisEilutė)] ="Aš esu destString!"; //目的字符串
anglisi;
anglisklaida =0;
xtal_init (); //系统时钟初始化 led_init (); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(šaltinis); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(nepasirašytas anglis)((nepasirašytas int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(nepasirašytas anglis)((nepasirašytas int)&sourceString);
dmaConfig.DESTADDRH=(nepasirašytas anglis)((nepasirašytas int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(nepasirašytas anglis)((nepasirašytas int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(nepasirašytas anglis)((nepasirašytas int)dydis(šaltinisEilutė) >>8); //传输长度 dmaConfig.LENL=(nepasirašytas anglis)((nepasirašytas int)dydis(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Nėra trigerio (gali būti suprantamas kaip rankinis paleidimas)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(nepasirašytas anglis)((nepasirašytas int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(nepasirašytas anglis)((nepasirašytas int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ =0x00; //清中断标志 DMAREQ =0x01; //启动DMA传输
Nors(! (DMAIRQ&0x01)); //等待传输结束
dėl(i =0; i <dydis(šaltinisEilutė); i++) //校验传输的正确性 {
jei(šaltinisEilutė!=destString) klaida++; }
jei(klaida ==0) //将结果通过串口传输到PC { Uart0SendString("Teisingai!"); Uart0SendString(destString); //传输后的目的字符数组 }
kitaip Uart0SendString("Klaida!");
Nors(1);
}
Pagrindinis DMA naudojimo procesas yra toks:Konfigūruoti DMA → Įgalinti konfigūraciją → Pradėti DMA perkėlimą → Palaukite, kol DMA perkėlimas bus baigtas.Atitinkamai: (1) Konfigūruoti DMA: Visų pirma, DMA turi būti sukonfigūruotas, tačiau DMA konfigūracija yra ypatinga: užuot tiesiogiai priskyrusi reikšmes kai kuriems SFR, ji apibrėžia struktūrą išoriškai, priskiria jai reikšmes ir tada priskiria aukštus 8 bitus pirmojo šios struktūros adresoDMA0CFGH, suteikiant jam mažesnį 8 skaitmenų skaičiųDMA0CFGL。 (Išsamias instrukcijas konfigūracijos struktūroje rasite CC2430 kinų vadove) CC2430 patarimaiYra du dalykai, kuriuos reikia paaiškinti apie konfigūracijos struktūrų apibrėžimą aukščiau pateiktame šaltinio kode: (1) Bitų domenas Apibrėžiant šią struktūrą, naudojama daug dvitaškių (:), po kurių seka skaičius, vadinamas "bitų lauku": Bitų domenas reiškia, kad saugoma informacija neturi užimti viso baito, o užima tik kelis ar vieną dvejetainį bitą. Pavyzdžiui, saugant perjungimo kiekį, yra tik dvi būsenos, 0 ir 1, ir galite naudoti vieną bito dvejetainį failą. Siekiant sutaupyti vietos saugykloje ir palengvinti apdorojimą, C pateikia duomenų struktūrą, vadinamą "bitų lauku" arba "bitų lauku". Vadinamasis "bitų laukas" padalija dvejetainius failus baite į kelis skirtingus regionus ir apibūdina bitų skaičių kiekviename regione. Kiekvienas domenas turi domeno vardą, leidžiantį atlikti operacijas pagal domeno vardą programoje. Tai leidžia pavaizduoti kelis skirtingus objektus baitų dvejetainiame bitų lauke. (2) Abstrakčios bendros funkcijos Dėmesingi skaitytojai pastebės, kad reikšmės priskyrimas struktūrai dažnai apima 16 bitų nepasirašyto int tipo reikšmės priskyrimą dviem 8 bitų nepasirašyto simbolio tipo reikšmėms, kaip nurodyta toliau: dmaConfig.SRCADDRH=(nepasirašytas anglis)((nepasirašytas int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(nepasirašytas anglis)((nepasirašytas int)&sourceString);
Tokio tipo dažnai naudojamoms funkcijoms taip pat galėtume ją abstrahuoti kaip bendrąją funkciją taip: #define SET_WORD(destH,destL,žodis)
daryti{ destH=(nepasirašytas anglis)((nepasirašytas int)žodis >>8); destL=(nepasirašytas anglis)((nepasirašytas int)žodis); }Nors(0)
Ateityje, kai jums reikės atlikti panašią padalijimo operaciją, galėsite ją paskambinti tiesiogiai, taip: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Įgalinti konfigūraciją: Pirma, pirmasis statinio adresas&dmaConfigAukštas / žemas 8 bitai priskiriami atitinkamai SFRDMA0CFGHirDMA0CFGL(kur 0 reiškia 0 kanalo konfigūraciją, CC2430 yra 5 DMA kanalai, čia naudojamas 0 kanalas). TaipDMAARM.0Priskirkite reikšmę 1, kad įgalintumėte kanalo 0 konfigūraciją, kad kanalas 0 veiktų darbo režimu. (3) Įgalinkite DMA perdavimą:Į dešinęDMAREQ.0Priskirkite reikšmę 1, kad pradėtumėte 0 kanalo DMA perdavimą. (4) Palaukite, kol bus perduotas DMA:Perdavus 0 kanalo DMA, bus suaktyvintas pertraukimas ir suveiks 0 kanalo pertraukimo vėliavaDMAIRQ.0bus automatiškai nustatyta į 1. Tada palyginamas kiekvienas dviejų eilučių simbolis ir patikrinimo rezultatas siunčiamas į kompiuterį. (4) Eksperimento rezultataiPirmiausia atidarykite nuosekliojo prievado derinimo įrankį, tada paleiskite CC2430 derinimą ir pasirodys šis ekranas:
RasitedestStringTurinys buvo visiškai atskleistassourceStringužpildytas. Atlikta ~ 3. IšvadaŠiame skyriuje pristatomas DMA naudojimas, nors jis yra labai paprastas, tačiau manau, kad supratote pagrindinį DMA naudojimą ir taip pat galite ramiai jį analizuoti, kai ateityje susidursite su sudėtingais jo naudojimo scenarijais. Kad ir koks geras darbalaukis būtų, jis užšals, o įterptoji sistema neišvengiamai sustings. Kitame skyriuje pristatysime labai efektyvų sistemingo atstatymo metodą: sargybinius šunis.
|