|
1. Menghubungkan tingkat atas dan bawah Di bagian sebelumnya, kami berbicara tentang penggunaan ADC dan mengambil sampel sensor suhu on-chip. Dalam proyek aktual, jumlah sensor seringkali besar dan sejumlah besar data konversi harus diproses. Memindahkan data ini akan memberi banyak tekanan pada CPU. Untuk membebaskan CPU dan memberinya energi untuk melakukan hal-hal lain, DMA (Direct Memory Access) dapat berguna~ Pendahuluan berikut dikutip dari Tutorial Praktik Teknologi Zigbee: DMA adalah singkatan dari akses memori langsung, yaitu "akses memori langsung". Ini adalah mode transmisi data berkecepatan tinggi di mana unit periferal seperti transceiver ADC/UART/RF dan memori dapat bertukar data langsung di bawah kendali "pengontrol DMA" tanpa sedikit intervensi CPU. Selain melakukan sedikit pemrosesan di awal dan akhir transfer data, CPU dapat melakukan pekerjaan lain selama transfer. Dengan cara ini, CPU dan interaksi data ini bekerja secara paralel sebagian besar waktu. Akibatnya, efisiensi sistem secara keseluruhan dapat sangat ditingkatkan.
Seperti yang Anda lihat dari pendahuluan, DMA dapat digunakan dalam banyak skenario. Eksperimen ini hanya melibatkan transmisi DMA yang paling sederhana dan bertujuan untuk menunjukkan penggunaan DMA secara umum. Adapun penerapan DMA dalam skenario lain, akan diimplementasikan dalam eksperimen komprehensif di masa depan. 2. Eksperimen transmisi DMA(1) Pengantar percobaanKarakter arraysumberStringKonten ditransfer ke array karakter melalui DMAdestString, hasil konversi ditampilkan di PC melalui port serial. (2) Bagan alir program
(3) Kode sumber dan analisis eksperimental/*
Deskripsi Eksperimental: Konten array karakter sourceString ditransfer ke array karakter destString melalui DMA, dan hasil konversi ditampilkan di PC melalui port serial.
*/
#include
#define led1 P1_0
#define led2 P1_1
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma bitfields = terbalik
typedef struktur
{
tidak ditandatangani arangSRCADDRH; //源地址高8位
tidak ditandatangani arangSRCADDRL; //源地址低8位
tidak ditandatangani arangDESTADDRH; //目的地址高8位
tidak ditandatangani arangDESTADDRL; //目的地址低8位
tidak ditandatangani arangVLEN :3; //长度域模式选择
tidak ditandatangani arangLENH :5; //传输长度高字节
tidak ditandatangani arangLENL :8; //传输长度低字节
tidak ditandatangani arangUKURAN KATA :1; //字节(byte)或字(word)传输
tidak ditandatangani arangTMODE :2; //传输模式选择
tidak ditandatangani arangTRIG :5; //触发事件选择
tidak ditandatangani arangSRCINC :2; //源地址增量:-1/0/1/2
tidak ditandatangani arangDESTINC :2; //目的地址增量:-1/0/1/2
tidak ditandatangani arangIRQMASK :1; //中断屏蔽
tidak ditandatangani arangM8 :1; //7或8bit传输长度,仅在字节传输模式下适用
tidak ditandatangani arangPRIORITAS :2; //优先级 }DMA_CFG; #pragma bitfields=default
/*系统时钟初始化
-------------------------------------------------------*/
kosongxtal_init(kosong)
{ TIDUR &= ~0x04; //都上电
sementara(! (TIDUR &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Pilih osilator kristal 32MHz TIDUR |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
kosongled_init(kosong)
{ P1SEL =0x00; P1 adalah port I/O normal P1DIR |=0x0F; Keluaran P1.0 P1.1 P1.2 P1.3
led1 =1; //关闭所有LED led2 =1; led3 =1; led4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
kosongUart0Init(tidak ditandatangani arangStopBits,tidak ditandatangani arangParitas)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Pilih UART0 sebagai posisi opsional pertama, yaitu RXD ke P0.2 dan TXD ke P0.3
U0CSR =0xC0; Atur ke mode UART dan aktifkan akseptor
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Paritas; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
kosong Uart0Kirim(tidak ditandatangani arangdata)
{
sementara(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = data;
}
/*UART0发送字符串
-------------------------------------------------------*/
kosongUart0SendString(tidak ditandatangani arang*dt)
{
sementara(*s !=0) //依次发送字符串s中的每个字符 Uart0Kirim(*s++);
}
/*主函数
-------------------------------------------------------*/
kosongutama(kosong)
{ DMA_CFG dmaConfig; //定义配置结构体
tidak ditandatangani arangsumberString[]="Saya sumberString!"; //源字符串
tidak ditandatangani arangdestString[ukurandari(sumberString)] ="Aku yang miskin!"; //目的字符串
arangi;
arangkesalahan =0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sumberString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(tidak ditandatangani arang)((tidak ditandatangani int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(tidak ditandatangani arang)((tidak ditandatangani int)&sumberString);
dmaConfig.DESTADDRH=(tidak ditandatangani arang)((tidak ditandatangani int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(tidak ditandatangani arang)((tidak ditandatangani int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(tidak ditandatangani arang)((tidak ditandatangani int)ukurandari(sumberString) >>8); //传输长度 dmaConfig.LENL=(tidak ditandatangani arang)((tidak ditandatangani int)ukurandari(sumberString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Tidak ada pemicu (dapat dipahami sebagai pemicu manual)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITAS=0x02; //传输优先级为高
DMA0CFGH=(tidak ditandatangani arang)((tidak ditandatangani int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(tidak ditandatangani arang)((tidak ditandatangani int)&dmaConfig);
DMAARM =0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
sementara(! (DMAIRQ&0x01)); //等待传输结束
untuk(i=0; i <ukurandari(sumberString); i++) //校验传输的正确性 {
jika(sumberString!=destString) kesalahan++; }
jika(kesalahan==0) //将结果通过串口传输到PC { Uart0SendString("Benar!"); Uart0SendString(destString); //传输后的目的字符数组 }
yang lain Uart0SendString("Kesalahan!");
sementara(1);
}
Proses dasar penggunaan DMA adalah:Mengonfigurasi DMA → Mengaktifkan konfigurasi → Mulai transfer DMA → Tunggu hingga transfer DMA selesai.Berikut ini masing-masing: (1) Konfigurasikan DMA: Pertama-tama, DMA harus dikonfigurasi, tetapi konfigurasi DMA khusus: alih-alih secara langsung menetapkan nilai ke beberapa SFR, DMA mendefinisikan struktur secara eksternal, menetapkan nilai padanya, dan kemudian menetapkan 8 bit tinggi dari alamat pertama struktur iniDMA0CFGH, memberikan 8 digit yang lebih rendahDMA0CFGL。 (Untuk instruksi terperinci dalam struktur konfigurasi, silakan merujuk ke manual bahasa Cina CC2430) CC2430 TipsAda dua poin yang perlu diklarifikasi tentang definisi struktur konfigurasi dalam kode sumber di atas: (1) Domain bit Saat mendefinisikan struktur ini, banyak titik dua (:) digunakan, diikuti oleh angka, yang disebut "bidang bit": Domain bit berarti bahwa informasi tidak perlu menempati byte penuh saat disimpan, tetapi hanya menempati beberapa atau satu bit biner. Misalnya, saat menyimpan kuantitas switching, hanya ada dua status, 0 dan 1, dan Anda dapat menggunakan biner satu bit. Untuk menghemat ruang penyimpanan dan mempermudah pemrosesan, C menyediakan struktur data yang disebut "bidang bit" atau "bidang bit". Apa yang disebut "bidang bit" membagi biner dalam byte menjadi beberapa wilayah yang berbeda dan menggambarkan jumlah bit di setiap wilayah. Setiap domain memiliki nama domain, memungkinkan operasi berdasarkan nama domain dalam program. Hal ini memungkinkan beberapa objek berbeda untuk direpresentasikan dalam bitfield biner byte. (2) Fungsi umum abstrak Pembaca yang penuh perhatian akan menemukan bahwa menetapkan nilai ke struct sering kali melibatkan penetapan nilai tipe int 16-bit yang tidak ditandatangani ke dua nilai tipe char 8-bit yang tidak ditandatangani, sebagai berikut: dmaConfig.SRCADDRH=(tidak ditandatangani arang)((tidak ditandatangani int)&sourceString >>8); //源地址 dmaConfig.SRCADDRL=(tidak ditandatangani arang)((tidak ditandatangani int)&sumberString);
Untuk jenis fungsi yang sering digunakan ini, kita sebaiknya mengabstraksinya sebagai fungsi umum, sebagai berikut: #define SET_WORD(destH,destL,kata)
melakukan{ destH=(tidak ditandatangani arang)((tidak ditandatangani int)kata >>8); destL=(tidak ditandatangani arang)((tidak ditandatangani int)kata); }sementara(0)
Di masa mendatang, setiap kali Anda perlu melakukan operasi pemisahan serupa, Anda dapat memanggilnya secara langsung, sebagai berikut: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Aktifkan konfigurasi: Pertama, alamat pertama struktur&dmaConfig8 bit tinggi/rendah masing-masing ditetapkan ke SFRDMA0CFGHdanDMA0CFGL(di mana 0 mewakili konfigurasi untuk saluran 0, CC2430 berisi 5 saluran DMA, saluran 0 digunakan di sini). YaDMAARM.0Tetapkan nilai 1 untuk mengaktifkan konfigurasi saluran 0 sehingga saluran 0 dalam mode kerja. (3) Aktifkan transmisi DMA:KananDMAREQ.0Tetapkan nilai 1 untuk memulai transmisi DMA saluran 0. (4) Tunggu hingga DMA ditransmisikan:Setelah DMA saluran 0 ditransmisikan, interupsi akan dipicu, dan bendera interupsi saluran 0 akan dipicuDMAIRQ.0akan secara otomatis diatur ke 1. Setiap karakter dari dua string kemudian dibandingkan dan hasil verifikasi dikirim ke PC. (4) Hasil eksperimenPertama, buka alat debugging port serial, lalu mulai debugging CC2430, dan layar berikut akan muncul:
Anda akan menemukandestStringKonten telah sepenuhnya terungkapsumberStringterisi. Selesai~ 3. KesimpulanBagian ini memperkenalkan penggunaan DMA, meskipun sangat sederhana, tetapi saya pikir Anda telah memahami penggunaan dasar DMA, dan Anda juga dapat menganalisisnya dengan tenang saat menghadapi skenario penggunaannya yang kompleks di masa mendatang. Tidak peduli seberapa bagus desktop, itu akan membeku, dan demikian pula, sistem tertanam pasti akan mandek. Di bagian selanjutnya, kami akan memperkenalkan metode reset sistematis yang sangat efektif: pengawas.
|