stm32 DMA數(shù)據(jù)搬運 操作寄存器+庫函數(shù)
一個完整的微控制器通常由CPU、存儲器和外設等組件構(gòu)成。這些組件一般在結(jié)構(gòu)和功能上都是獨立的,而各個組件的協(xié)調(diào)和交互就由CPU完成。如此一來,CPU作為整個芯片的核心,其處理的工作量是很大的。如果CPU先從A外設拿到一個數(shù)據(jù)送給B外設使用,同時C外設又需要D外設提供一個數(shù)據(jù)。。。這樣的數(shù)據(jù)搬運工作將使CPU的負荷顯得相當繁重。
嚴格的說,搬運數(shù)據(jù)只是CPU的比較不重要的一種工作。CPU最重要的工作室進行數(shù)據(jù)運算,從加減乘除到一些高級的運算,包括浮點、積分、微分、FFT等。CPU還需要負責復雜的中斷申請和響應,以保證芯片的實時性能。
理論上常見的控制外設,比如Usart、I2C、SPI甚至是USB等通信接口,單純的利用CPU進行協(xié)議模擬也是可以實現(xiàn)的,比如51單片機經(jīng)常使用I/O口模擬I2C協(xié)議通信。但這樣既浪費了CPU的資源,同時實現(xiàn)后的性能表現(xiàn)往往和使用專門的硬件模塊實現(xiàn)的效果相差甚遠。從這個角度來看,各個外設控制器的存在,無疑降低了CPU的負擔,解放了CPU的資源。
數(shù)據(jù)搬運這一工作占用了大部分的CPU資源,成為了降低CPU的工作效率的主要原因之一。于是需要一種硬件結(jié)構(gòu)分擔CPU這一職能 —— DMA。
從數(shù)據(jù)搬運的角度看,如果要把存儲地址A的數(shù)值賦給另外一個地址上B的變量,CPU實現(xiàn)過程為首先讀出A地址上的數(shù)據(jù)存儲在一個中間變量,然后再轉(zhuǎn)送到B地址的變量上。使用DMA則不需要中間變量,直接將A地址的數(shù)值傳送到B地址的變量里。無疑減輕了CPU的負擔,也提高了數(shù)據(jù)搬運的效率。
stm32中 DMA1有7個通道,DMA2有5個通道。DMA掛載的時鐘為AHB總線,其時鐘為72Mhz,所以可以實現(xiàn)高速數(shù)據(jù)搬運。
stm32的DMA1通道一覽表
本例實現(xiàn)使用CPU和DMA搬運同一組數(shù)據(jù),通過計時,比較兩者的搬運效率。
直接操作寄存器
DMA的中斷狀態(tài)寄存器(DMA_ISR):
TEIFx:通道x的傳輸錯誤標志(x = 1 … 7) (Channel x transfer error flag) 硬件設置這些位。在DMA_IFCR寄存器的相應位寫入’1’可以清除這里對應的標志位。
0:在通道x沒有傳輸錯誤(TE); 1:在通道x發(fā)生了傳輸錯誤(TE)。
HTIFx:通道x的半傳輸標志(x = 1 … 7) (Channel x half transfer flag) 硬件設置這些位。在DMA_IFCR寄存器的相應位寫入’1’可以清除這里對應的標志位。
0:在通道x沒有半傳輸事件(HT); 1:在通道x產(chǎn)生了半傳輸事件(HT)。
TCIFx:通道x的傳輸完成標志(x = 1 … 7) (Channel x transfer complete flag) 硬件設置這些位。在DMA_IFCR寄存器的相應位寫入’1’可以清除這里對應的標志位。
0:在通道x沒有傳輸完成事件(TC); 1:在通道x產(chǎn)生了傳輸完成事件(TC)。
DMA_IFCR中斷標志清除寄存器:
結(jié)構(gòu)類似DMA_ISR。
CTEIFx:清除通道x的傳輸錯誤標志(x = 1 … 7) (Channel x transfer error clear) 這些位由軟件設置和清除。 0:不起作用 1:清除DMA_ISR寄存器中的對應TEIF標志。
CHTIFx:清除通道x的半傳輸標志(x = 1 … 7) (Channel x half transfer clear) 這些位由軟件設置和清除。 0:不起作用 1:清除DMA_ISR寄存器中的對應HTIF標志。
CTCIFx:清除通道x的傳輸完成標志(x = 1 … 7) (Channel x transfer complete clear) 這些位由軟件設置和清除。 0:不起作用 1:清除DMA_ISR寄存器中的對應TCIF標志。
CGIFx:清除通道x的全局中斷標志(x = 1 … 7) (Channel x global interrupt clear) 這些位由軟件設置和清除。 0:不起作用 1:清除DMA_ISR寄存器中的對應的GIF、TEIF、HTIF和TCIF標志。
DMA通道配置寄存器(DMA_CCRx):
MEM2MEM:存儲器到存儲器模式 (Memory to memory mode) 該位由軟件設置和清除。 0:非存儲器到存儲器模式; 1:啟動存儲器到存儲器模式。
PL:通道優(yōu)先級 (Channel priority level) 這些位由軟件設置和清除。00:低 01:中 10:高 11:最高
MSIZE:存儲器數(shù)據(jù)寬度 (Memory size) 這些位由軟件設置和清除。 00:8位 01:16位 10:32位 11:保留
PSIZE:外設數(shù)據(jù)寬度 (Peripheral size) 這些位由軟件設置和清除。 00:8位 01:16位 10:32位 11:保留
MINC:存儲器地址增量模式 (Memory increment mode) 該位由軟件設置和清除。 0:不執(zhí)行存儲器地址增量操作 1:執(zhí)行存儲器地址增量操作
PINC:外設地址增量模式 (Peripheral increment mode) 該位由軟件設置和清除。 0:不執(zhí)行外設地址增量操作 1:執(zhí)行外設地址增量操作
CIRC:循環(huán)模式 (Circular mode) 該位由軟件設置和清除。 0:不執(zhí)行循環(huán)操作 1:執(zhí)行循環(huán)操作
DIR:數(shù)據(jù)傳輸方向 (Data transfer direction) 該位由軟件設置和清除。 0:從外設讀 1:從存儲器讀
TEIE:允許傳輸錯誤中斷 (Transfer error interrupt enable) 該位由軟件設置和清除。 0:禁止TE中斷 0:允許TE中斷
HTIE:允許半傳輸中斷 (Half transfer interrupt enable) 該位由軟件設置和清除。 0:禁止HT中斷 0:允許HT中斷
TCIE:允許傳輸完成中斷 (Transfer complete interrupt enable) 該位由軟件設置和清除。 0:禁止TC中斷 0:允許TC中斷
EN:通道開啟 (Channel enable) 該位由軟件設置和清除。 0:通道不工作 1:通道開啟
DMA通道x傳輸數(shù)量寄存器(DMA_CNDTRx)(x = 1…7)
低16位有效。這個寄存器控制通道每次傳輸?shù)臄?shù)據(jù)量,數(shù)據(jù)傳輸數(shù)量為0至65535。該寄存器會隨著傳輸?shù)倪M行而遞減,為0表示已經(jīng)發(fā)送完成。
DMA外設地址寄存器(DMA_CPARx)
32位寄存器。外設數(shù)據(jù)寄存器的基地址,作為數(shù)據(jù)傳輸?shù)脑椿蚰繕恕?/div>
看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
DMA存儲地址寄存器(DMA_CMARx)
存儲器地址[31:0],存儲器地址作為數(shù)據(jù)傳輸?shù)脑椿蚰繕恕?/div>
代碼如下: (system.h 和stm32f10x_it.h等相關(guān)代碼參照stm32 直接操作寄存器開發(fā)環(huán)境配置)
User/main.c
#include#include "system.h"#include "usart.h" #include "dma.h"#include "tim.h" #include "string.h"#define LED1 PAout(4)#define LED2 PAout(5)#define LED3 PAout(6)void Gpio_Init(void);//數(shù)據(jù)源uc32 SRC_Const_Buffer[32] ={ 0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,0x21314,0x15161718,0x191A1B1C,0x1D1E1F20,0x21324,0x25262728,0x292A2B2C,0x2D2E2F30,0x31324,0x35363738,0x393A3B3C,0x3D3E3F40,0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,0x51525354,0x65758,0x595A5B5C,0x5D5E5F60,0x61626364,0x65768,0x696A6B6C,0x6D6E6F70,0x71727374,0x75768,0x797A7B7C,0x7D7E7F80};//目標位置u32 DST_Buffer[32];int main(void){ u8 i=0;u16 StartTime=0,CPUSpendTime=0,DMASpendTime=0;;Rcc_Init(9); //系統(tǒng)時鐘設置Usart1_Init(72,9600);Tim_Init(TIM_2,65535,71); //初始化TIM2定時器,設定重裝值和分頻值,計時時間為1us/次Dma_Init(DMA1_Channel1,(u32)SRC_Const_Buffer,(u32)DST_Buffer); //初始化DMA,外設地址示例 &USART1->DRNvic_Init(1,0,DMA1_Channel1_IRQChannel,4); //設置搶占優(yōu)先級為0,響應優(yōu)先級為0,中斷分組為4Gpio_Init();StartTime = TIM2->CNT;while(i<32) //CPU搬運{DST_Buffer[i]=SRC_Const_Buffer[i];i++;}CPUSpendTime = TIM2->CNT - StartTime;printf("rn the CPU spend : %dus! rn",CPUSpendTime);if(strncmp((const char *)SRC_Const_Buffer,(const char *)DST_Buffer,32) ==0) //驗證傳輸效果,判斷兩數(shù)組是否相同{printf("rn CPU Transmit Success! rn");}else{printf("rn CPU Transmit Fail! rn");}i=0;while(i<32) //清空目標數(shù)組,準備DMA搬運{DST_Buffer[i]=0;i++;} StartTime = TIM2->CNT;Dma_Enable(DMA1_Channel1,32);//DMA搬運while( DMA1_Channel1 -> CNDTR != 0); //等待傳輸完成DMASpendTime= TIM2->CNT - StartTime;printf("rn the DMA spend : %dus! rn",DMASpendTime);if(strncmp((const char *)SRC_Const_Buffer,(const char *)DST_Buffer,32) ==0) //驗證傳輸效果,判斷兩數(shù)組是否相同{printf("rn DMA Transmit Success! rn");}else{printf("rn DMA Transmit Fail! rn");} while(1); }void Gpio_Init(void){RCC->APB2ENR=1<<2; //使能PORTA時鐘 GPIOA->CRL&=0x0FFFF; // PA0~3設置為浮空輸入,PA4~7設置為推挽輸出GPIOA->CRL=0x34; //USART1 串口I/O設置GPIOA -> CRH&=0xFFFFF00F; //設置USART1 的Tx(PA.9)為第二功能推挽,50MHz;Rx(PA.10)為浮空輸入GPIOA -> CRH=0x008B0; }
User/stm32f10x_it.c
本文引用地址:http://www.ex-cimer.com/article/201611/318034.htm#include "stm32f10x_it.h"#include "system.h"#include "stdio.h"#define LED1 PAout(4)#define LED2 PAout(5)#define LED3 PAout(6)#define LED4 PAout(7)void DMAChannel1_IRQHandler(void) //和啟動文件有關(guān),STM32F10x.s中 和 STM32F10x_md.s DMA中斷接口函數(shù)不同{if( DMA1 ->ISR & (1<<1)) //傳輸完成中斷{LED1 = 1;DMA1->IFCR = 1<<1; //清除傳輸完成中斷}if( DMA1 ->ISR & (1<<2)) //半傳輸完成中斷{DMA1 ->IFCR = 1<<2; //清除半傳輸完成中斷}if( DMA1 ->ISR & (1<<3)) //傳輸錯誤中斷{LED4 =1 ;DMA1 ->IFCR = 1<<3; //清除傳輸錯誤中斷}DMA1 ->IFCR = 1<<0; //清除此通道的中斷}
Library/src/dma.c
#include#include "system.h"#include "dma.h"http://DMA通道初始化函數(shù)//傳輸方向:存儲器 -> 存儲器模式 ,32位數(shù)據(jù)模式,存儲器增量模式//參數(shù)說明:// DMA_CHx :選擇DMA控制器通道,DMA1有1-7,DMA2有1-4// P_Adress :外設地址// M_Adress :存儲器地址void Dma_Init(DMA_Channel_TypeDef * DMA_CHx,u32 P_Address ,u32 M_Address){RCC->AHBENR = 1<<0;DMA_CHx -> CCR &= 0xFFFF0; //復位 DMA_CHx -> CCR = 1<<1; //允許傳輸完成中斷//DMA_CHx -> CCR = 1<<2; //允許半傳輸中斷DMA_CHx -> CCR = 1<<3; //允許傳輸錯誤中斷 讀寫一個保留的地址區(qū)域,將會產(chǎn)生DMA傳輸錯誤 //設定數(shù)據(jù)傳輸方向DMA_CHx -> CCR = 0<<4; //設定數(shù)據(jù)傳輸方向 0:從外設讀 1:從存儲器讀DMA_CHx -> CCR = 0<<5; //0:不執(zhí)行循環(huán)操作 1:執(zhí)行循環(huán)操作 //設定地址增量DMA_CHx -> CCR = 1<<6; //0:不執(zhí)行外設地址增量操作 1:執(zhí)行外設地址增量操作DMA_CHx -> CCR = 1<<7; //0:不執(zhí)行存儲器地址增量操作 1:執(zhí)行存儲器地址增量操作 //設定外設數(shù)據(jù)寬度 SDMA_CHx -> CCR = 0<<8; //外設數(shù)據(jù)寬度,由[9:8]兩位控制DMA_CHx -> CCR = 1<<9; //00:8位 01:16位 10:32位 11:保留 //設定存儲數(shù)據(jù)寬度DMA_CHx -> CCR = 0<<10; //存儲器數(shù)據(jù)寬度,由[11:10]兩位控制DMA_CHx -> CCR = 1<<11; //00:8位 01:16位 10:32位 11:保留 //設定為中等優(yōu)先級DMA_CHx -> CCR = 1<<12; //通道優(yōu)先級,由[13:12]兩位控制DMA_CHx -> CCR = 1<<13; //00:低 01:中 10:高 11:最高 DMA_CHx -> CCR = 1<<14; //0:非存儲器到存儲器模式; 1:啟動存儲器到存儲器模式。 //必須配置好通道后配置地址DMA_CHx -> CPAR = (u32)P_Address; //設定外設寄存器地址DMA_CHx -> CMAR = (u32)M_Address; //設定數(shù)據(jù)存儲器地址}//DMA通道使能//參數(shù)說明:// DMA_CHx :選擇DMA控制器通道,DMA1有1-7,DMA2有1-4// Number :數(shù)據(jù)傳輸量void Dma_Enable(DMA_Channel_TypeDef * DMA_CHx,u16 Number){DMA_CHx -> CCR &= ~(1<<0); //關(guān)閉上一次DMA傳輸DMA_CHx -> CNDTR = Number; //數(shù)據(jù)傳輸量DMA_CHx -> CCR = 1<<0; //開始DMA傳輸 }
Library/inc/dma.h
#includevoid Dma_Init(DMA_Channel_TypeDef * DMA_CHx,u32 P_Adress ,u32 M_Address);void Dma_Enable(DMA_Channel_TypeDef * DMA_CHx,u16 Number);
直接操作寄存器輸出:
the CPU spend : 972us!
CPU Transmit Success!
the DMA spend : 5us!
DMA Transmit Success!
庫函數(shù)操作
mian.c
#include "stm32f10x.h"#include "stdio.h"#include "string.h"#define PRINTF_ON 1#define BufferSize 32vu16 LeftDataCounter;vu32 Tick;uc32 SRC_Const_Buffer[BufferSize] = { 0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,0x21314,0x15161718,0x191A1B1C,0x1D1E1F20,0x21324,0x25262728,0x292A2B2C,0x2D2E2F30,0x31324,0x35363738,0x393A3B3C,0x3D3E3F40,0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,0x51525354,0x65758,0x595A5B5C,0x5D5E5F60,0x61626364,0x65768,0x696A6B6C,0x6D6E6F70,0x71727374,0x75768,0x797A7B7C,0x7D7E7F80};u32 DST_Buffer[BufferSize];u8 i=0,DMASpendTime=0,CPUSpendTime=0;void RCC_Configuration(void);void GPIO_Configuration(void);void NVIC_Configuration(void);void USART_Configuration(void);void DMA_Configuration(void);int main(void){RCC_Configuration();GPIO_Configuration();NVIC_Configuration();USART_Configuration();DMA_Configuration();SysTick_Config(72);Tick = 0;while(i
stm32f10x_it.c
#include "stm32f10x_it.h"#include "stdio.h"extern vu32 Tick;extern vu16 LeftDataCounter;void SysTick_Handler(void){Tick++;}void DMA1_Channel6_IRQHandler(void){LeftDataCounter = DMA_GetCurrDataCounter(DMA1_Channel6); //獲取剩余待傳輸數(shù)據(jù)DMA_ClearITPendingBit(DMA1_IT_GL6);}
庫函數(shù)輸出:
Transmit Success!
the CPU spend : 68us!
the DMA spend : 7us!
關(guān)鍵詞:
stm32DMA數(shù)據(jù)搬運操作寄存器庫函
評論