|
1. Collegamento tra i livelli superiori e inferiori Nella sezione precedente, abbiamo parlato dell'uso degli ADC e campionato il sensore di temperatura integrato sul chip. Nei progetti reali, il numero di sensori è spesso elevato e deve essere elaborata una grande quantità di dati di conversione. Spostare questi dati metterà molta pressione sulla CPU. Per liberare la CPU e darle l'energia per fare altro, il DMA (Direct Memory Access) può tornare utile~ La seguente introduzione è tratta dal Tutorial di Pratica Tecnologica Zigbee: DMA è un'abbreviazione di accesso diretto alla memoria, che è "accesso diretto alla memoria". Si tratta di una modalità di trasmissione dati ad alta velocità in cui unità periferiche come i ricetrasmettitori ADC/UART/RF e la memoria possono scambiare dati direttamente sotto il controllo del "controller DMA" senza poco intervento della CPU. Oltre a fare un po' di elaborazione all'inizio e alla fine del trasferimento dati, la CPU può svolgere altri lavori durante il trasferimento. In questo modo, la CPU e queste interazioni dati lavorano in parallelo la maggior parte del tempo. Di conseguenza, l'efficienza complessiva del sistema può essere notevolmente migliorata.
Come si può vedere dall'introduzione, il DMA può essere usato in molti scenari. Questo esperimento coinvolge solo la trasmissione DMA più semplice e mira a dimostrare l'uso generale della DMA. Per quanto riguarda l'applicazione della DMA in altri scenari, sarà implementata in esperimenti completi in futuro. 2. Esperimento di trasmissione DMA(1) Introduzione all'esperimentoCaratteri dell'arraysourceStringIl contenuto viene trasferito nell'array di caratteri tramite DMAdestString, il risultato della conversione viene visualizzato sul PC tramite la porta seriale. (2) Diagramma di flusso del programma
(3) Codice sorgente sperimentale e analisi/*
Descrizione sperimentale: Il contenuto della sourceString dell'array di caratteri viene trasferito all'array di caratteri destString tramite DMA, e il risultato della conversione viene visualizzato sul PC tramite la porta seriale.
*/
#include
#define guidato P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma campi di bit=invertiti
typedef struct
{
senza firmatura CharSRCADDRH; //源地址高8位
senza firmatura CharSRCADDRL; //源地址低8位
senza firmatura CharDESTADDRH; //目的地址高8位
senza firmatura CharDESTADDRL; //目的地址低8位
senza firmatura CharVLEN:3; //长度域模式选择
senza firmatura CharLENH:5; //传输长度高字节
senza firmatura CharLENL:8; //传输长度低字节
senza firmatura CharDIMENSIONE DELLA PAROLA :1; //字节(byte)或字(word)传输
senza firmatura CharTMODE:2; //传输模式选择
senza firmatura CharTRIGG:5; //触发事件选择
senza firmatura CharSRCINC:2; //源地址增量:-1/0/1/2
senza firmatura CharDESTINC :2; //目的地址增量:-1/0/1/2
senza firmatura CharIRQMASK :1; //中断屏蔽
senza firmatura CharM8:1; //7或8bit传输长度,仅在字节传输模式下适用
senza firmatura CharPRIORITÀ:2; //优先级 }DMA_CFG; #pragma campi di bit=predefinito
/*系统时钟初始化
-------------------------------------------------------*/
Voidxtal_init(Void)
{ SONNO &= ~0x04; //都上电
mentre(! (SONNO &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Scegli un oscillatore a cristallo a 32MHz SONNO |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
Voidled_init(Void)
{ P1SEL =0x00; P1 è la normale porta I/O P1DIR |=0x0F; Uscita P1.0 P1.1 P1.2 P1.3
Led1 =1; //关闭所有LED Led2 =1; led3 =1; Led4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
VoidUart0Init(senza firmatura CharStopBits,senza firmatura CharParità)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Seleziona UART0 come prima posizione opzionale, cioè da RXD a P0.2 e da TXD a P0.3
U0CSR =0xC0; Imposta la modalità UART e abilita l'accettatore
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Parità; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
Void Uart0Send(senza firmatura Chardati)
{
mentre(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = dati;
}
/*UART0发送字符串
-------------------------------------------------------*/
VoidUart0SendString(senza firmatura Char*s)
{
mentre(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
Voidmain(Void)
{ DMA_CFG dmaConfig; //定义配置结构体
senza firmatura CharsourceString[]="Sono la Stringa Sorgente!"; //源字符串
senza firmatura ChardestString[dimensione(sourceString)] ="Sono la StringaDest!"; //目的字符串
Chario;
Charerrore=0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sourceString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(senza firmatura Char)((senza firmatura int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(senza firmatura Char)((senza firmatura int)&sourceString);
dmaConfig.DESTADDRH=(senza firmatura Char)((senza firmatura int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(senza firmatura Char)((senza firmatura int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(senza firmatura Char)((senza firmatura int)dimensione(sourceString) >>8); //传输长度 dmaConfig.LENL=(senza firmatura Char)((senza firmatura int)dimensione(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Nessun trigger (può essere inteso come triggering manuale)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(senza firmatura Char)((senza firmatura int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(senza firmatura Char)((senza firmatura int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
mentre(! (DMAIRQ&0x01)); //等待传输结束
per(i=0; io <dimensione(sourceString); i++) //校验传输的正确性 {
se(sourceString!=destString) error++; }
se(errore==0) //将结果通过串口传输到PC { Uart0SendString("Corretto!"); Uart0SendString(destString); //传输后的目的字符数组 }
altrimenti Uart0SendString("Errore!");
mentre(1);
}
Il processo base per usare la DMA è:Configura DMA → Abilita la configurazione → Inizia il trasferimento DMA → aspetta che il trasferimento DMA finisca.Le seguenti sono rispettivamente: (1) Configurare DMA: Prima di tutto, la DMA deve essere configurata, ma la configurazione della DMA è particolare: invece di assegnare direttamente valori ad alcuni SFR, definisce una struttura esternamente, le assegna valori e poi assegna gli 8 bit alti del primo indirizzo di questa strutturaDMA0CFGH, dandogli un numero inferiore di 8 cifreDMA0CFGL。 (Per istruzioni dettagliate nella struttura di configurazione, si prega di consultare il manuale cinese CC2430) Consigli CC2430Ci sono due punti da chiarire sulla definizione di struct di configurazione nel codice sorgente sopra: (1) Dominio bitario Quando si definisce questa struczione, si usano molti due punti (:), seguiti da un numero, chiamato "campo di bit": Il dominio bit significa che l'informazione non deve occupare un byte intero quando è memorizzata, ma occupa solo pochi o un bit binario. Ad esempio, quando si memorizza una grandezza di commutazione, ci sono solo due stati, 0 e 1, e si può usare un bit binario. Per risparmiare spazio di archiviazione e rendere più semplice l'elaborazione, C fornisce una struttura dati chiamata "campo bit" o "campo bit". Il cosiddetto "campo di bit" divide i binari in un byte in diverse regioni e descrive il numero di bit in ciascuna regione. Ogni dominio ha un nome di dominio, permettendo operazioni per nome di dominio nel programma. Questo permette di rappresentare diversi oggetti in un campo binario di byte. (2) Funzioni comuni astratte I lettori attenti scopriranno che assegnare un valore a una struct spesso comporta l'assegnazione di un valore di tipo int senza segno a 16 bit a due valori di tipo di carattere non firmato a 8 bit, come segue: dmaConfig.SRCADDRH=(senza firmatura Char)((senza firmatura int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(senza firmatura Char)((senza firmatura int)&sourceString);
Per questo tipo di funzione frequentemente utilizzata, potremmo anche astrarla come funzione generale, come segue: #define SET_WORD(destH,destL,word)
fare{ destH=(senza firmatura Char)((senza firmatura int)Parola >>8); destL=(senza firmatura Char)((senza firmatura int)parola); }mentre(0)
In futuro, ogni volta che sarà necessario eseguire un'operazione di divisione simile, potrai chiamarla direttamente, come segue: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Abilita la configurazione: Innanzitutto, il primo indirizzo della struttura&dmaConfigGli 8 bit alti/bassi sono assegnati rispettivamente alla SFRDMA0CFGHeDMA0CFGL(dove 0 rappresenta la configurazione per il canale 0, CC2430 contiene 5 canali DMA, qui viene utilizzato il canale 0). SìDMAARM.0Assegnare un valore di 1 per abilitare la configurazione del canale 0 in modo che il canale 0 sia in modalità di lavoro. (3) Abilitare la trasmissione DMA:A destraDMAREQ.0Assegna un valore 1 per avviare la trasmissione DMA del canale 0. (4) Attendere la trasmissione del DMA:Dopo la trasmissione della DMA del canale 0, l'interrupt verrà attivato e la bandiera di interruzione del canale 0 verrà attivataDMAIRQ.0sarà impostato automaticamente a 1. Ogni carattere delle due stringhe viene poi confrontato e il risultato della verifica viene inviato al PC. (4) Risultati sperimentaliPrima apri lo strumento di debug della porta seriale, poi inizia il debug CC2430, e apparirà la seguente schermata:
TroveraidestStringIl contenuto è stato completamente rivelatosourceStringpieno. Fatto~ 3. ConclusioneQuesta sezione introduce l'uso della DMA, anche se è molto semplice, ma credo tu abbia compreso l'uso base della DMA, e puoi anche analizzarla con calma quando ti troverai a dover affrontare in futuro scenari d'uso complessi. Non importa quanto sia valido un desktop, si bloccherà e, allo stesso modo, un sistema embedded inevitabilmente ristagnerà. Nella sezione successiva, presenteremo un metodo molto efficace di reset sistematico: i watchdog.
|