STM32----摸石头过河系列(五)
今天總結(jié)一下DMA(Direct Memory Access,直接存儲器存儲),在以往我們從串口讀取數(shù)據(jù)到內(nèi)存的流程是,cpu通過串口讀取導(dǎo)數(shù)據(jù),然后CPU再將數(shù)據(jù)寫入固定的內(nèi)存。這種讀取方式占用了大量的cpu資源,如果數(shù)據(jù)量非常大,CPU將耗費(fèi)大量的時間來進(jìn)行數(shù)據(jù)的讀寫操作。因此DMA應(yīng)運(yùn)而生。DMA的作用是啥呢?從名字能看出來一二,它可以直接從串口讀取數(shù)據(jù)存儲在內(nèi)存中,幾乎不占用CPU的資源。打個比方來說,一個砌墻的工人,他的主要工作是砌墻,但他首先需要耗費(fèi)大量時間去搬磚到自己身邊,然后才開始砌墻,這樣他砌墻的進(jìn)度肯定很慢。現(xiàn)在砌墻的工人不自己去搬磚了,他雇傭了另外一個人來幫助他去把磚搬過來,在搬之前砌墻的工人告訴搬磚的工人,他要去哪里搬磚、搬什么樣的磚、搬磚的速度、搬過來后放在那里等問題。這樣雖然在開始耗費(fèi)了點(diǎn)時間去告訴搬磚工人一些要求,看起來比較繁瑣,其實這些所占用的時間比起自己去搬磚耗費(fèi)的時間少多了。在這個例子中,砌墻的工人就是我們所說的CPU,磚就是需要讀寫數(shù)據(jù),搬磚工人就是DMA,DMA的引入為CPU讀寫數(shù)據(jù)節(jié)省了大量的時間,CPU只需要在開始耗費(fèi)極少的時間對DMA進(jìn)行相關(guān)的配置,就可以去做其他的事情。
我在做實驗的過程中,遇到了很多狗血的bug,不過最終都得以解決。今天做的實驗是利用DMA通過USART1向發(fā)送數(shù)據(jù),同時LED持續(xù)點(diǎn)亮,當(dāng)發(fā)送數(shù)據(jù)完成時,進(jìn)入中斷將LED熄滅,從而來驗證DMA工作時CPU可以去做別的事情,而沒有影響。下面來總結(jié)一下DMA的開發(fā)流程:
根據(jù)以上步驟進(jìn)行先關(guān)的配置,其他的比如串口和LED的配置在前面已經(jīng)配置過了直接把USART和LED的配置文件添加在該項目中即可。下面來看代碼,代碼中只有DMA的配置和主函數(shù)。
下面這是dma.c文件中的內(nèi)容:
#include"dma.h"uint16_t SendBuff[SENDSBUFF_SIZE];static void NVIC_Config(void) {NVIC_InitTypeDef nvic_struct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);nvic_struct.NVIC_IRQChannel = DMA1_Channel4_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 1;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct); }void DMA1_Config(void) {DMA_InitTypeDef dma_struct;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);NVIC_Config();dma_struct.DMA_PeripheralBaseAddr = USART1_BASE + 0x04;//數(shù)據(jù)要到達(dá)的地址dma_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//每次發(fā)送數(shù)據(jù)的大小dma_struct.DMA_MemoryBaseAddr = (u32)SendBuff;//數(shù)據(jù)所在的地址dma_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//每次讀取數(shù)據(jù)的大小dma_struct.DMA_BufferSize = SENDSBUFF_SIZE;//總共傳輸?shù)臄?shù)據(jù)的大小dma_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;//存儲數(shù)據(jù)的地址是否自動增加dma_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//數(shù)據(jù)到達(dá)的地址是否自動增加dma_struct.DMA_DIR = DMA_DIR_PeripheralDST;//傳輸?shù)姆较騼?nèi)存到外設(shè)dma_struct.DMA_M2M = DMA_M2M_Disable;//內(nèi)存到內(nèi)存是否允許dma_struct.DMA_Mode = DMA_Mode_Normal;//傳輸方式,發(fā)送一次還是循環(huán)發(fā)送dma_struct.DMA_Priority = DMA_Priority_Medium;//優(yōu)先級DMA_Init(DMA1_Channel4,&dma_struct);//初始化DMA_Cmd(DMA1_Channel4,ENABLE);//使能DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//中斷配置并使能}SendBuff數(shù)組存儲的是要發(fā)送的數(shù)據(jù),兩個函數(shù)為中斷配置函數(shù),在前面的外部中斷中已經(jīng)配置過了。第二個函數(shù)為DMA的配置函數(shù),與其他外設(shè)的配置類似,先定義一個結(jié)構(gòu)體,然后開啟時鐘。這個DMA1的時鐘和之前的都不一樣,在AHB上,配置時需要注意。
在main.c文件中:
#include"led.h" #include"usart.h" #include"dma.h"extern uint16_t SendBuff[SENDSBUFF_SIZE];//引用外部定義的變量 int i;int main(void)//主函數(shù) {GPIO_LED_Config();USART1_Config();DMA1_Config();for(i = 0;i < SENDSBUFF_SIZE;i++)//為發(fā)送數(shù)據(jù)賦值{SendBuff[i] = 0xff;}printf("Send start!");USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);LED(ON);printf("wait interrupt!");while(1); }void DMA1_Channel4_IRQHandler(void)//中斷函數(shù) {printf("into interrupt!");if(DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET)//判斷是否發(fā)送完成{printf("send success");LED(OFF);DMA_ClearFlag(DMA1_FLAG_TC4);//清除標(biāo)志位} }在實驗的過程中,編譯出現(xiàn)symbol multiply defined錯誤的原因,因為在xxx.h中定義了許多變量,xxx.c中調(diào)用xxx.h中的變量,在主文件中也調(diào)用了xxx.h中的變量,導(dǎo)致變量被重復(fù)定義。
解決辦法:不應(yīng)該在xxx.h中定義xxx.c中使用的變量,應(yīng)該在xxx.c中定義所需要的變量,然后再在主程序中將調(diào)用xxx.c中定義的變量使用extern 例:extern u32 test.
總結(jié)
以上是生活随笔為你收集整理的STM32----摸石头过河系列(五)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习 | 聚类评估指标
- 下一篇: 突破传统生物3D打印技术局限-王秀杰/C