STM32----摸石头过河系列(五)
今天總結(jié)一下DMA(Direct Memory Access,直接存儲(chǔ)器存儲(chǔ)),在以往我們從串口讀取數(shù)據(jù)到內(nèi)存的流程是,cpu通過串口讀取導(dǎo)數(shù)據(jù),然后CPU再將數(shù)據(jù)寫入固定的內(nèi)存。這種讀取方式占用了大量的cpu資源,如果數(shù)據(jù)量非常大,CPU將耗費(fèi)大量的時(shí)間來(lái)進(jìn)行數(shù)據(jù)的讀寫操作。因此DMA應(yīng)運(yùn)而生。DMA的作用是啥呢?從名字能看出來(lái)一二,它可以直接從串口讀取數(shù)據(jù)存儲(chǔ)在內(nèi)存中,幾乎不占用CPU的資源。打個(gè)比方來(lái)說(shuō),一個(gè)砌墻的工人,他的主要工作是砌墻,但他首先需要耗費(fèi)大量時(shí)間去搬磚到自己身邊,然后才開始砌墻,這樣他砌墻的進(jìn)度肯定很慢。現(xiàn)在砌墻的工人不自己去搬磚了,他雇傭了另外一個(gè)人來(lái)幫助他去把磚搬過來(lái),在搬之前砌墻的工人告訴搬磚的工人,他要去哪里搬磚、搬什么樣的磚、搬磚的速度、搬過來(lái)后放在那里等問題。這樣雖然在開始耗費(fèi)了點(diǎn)時(shí)間去告訴搬磚工人一些要求,看起來(lái)比較繁瑣,其實(shí)這些所占用的時(shí)間比起自己去搬磚耗費(fèi)的時(shí)間少多了。在這個(gè)例子中,砌墻的工人就是我們所說(shuō)的CPU,磚就是需要讀寫數(shù)據(jù),搬磚工人就是DMA,DMA的引入為CPU讀寫數(shù)據(jù)節(jié)省了大量的時(shí)間,CPU只需要在開始耗費(fèi)極少的時(shí)間對(duì)DMA進(jìn)行相關(guān)的配置,就可以去做其他的事情。
我在做實(shí)驗(yàn)的過程中,遇到了很多狗血的bug,不過最終都得以解決。今天做的實(shí)驗(yàn)是利用DMA通過USART1向發(fā)送數(shù)據(jù),同時(shí)LED持續(xù)點(diǎn)亮,當(dāng)發(fā)送數(shù)據(jù)完成時(shí),進(jìn)入中斷將LED熄滅,從而來(lái)驗(yàn)證DMA工作時(shí)CPU可以去做別的事情,而沒有影響。下面來(lái)總結(jié)一下DMA的開發(fā)流程:
根據(jù)以上步驟進(jìn)行先關(guān)的配置,其他的比如串口和LED的配置在前面已經(jīng)配置過了直接把USART和LED的配置文件添加在該項(xiàng)目中即可。下面來(lái)看代碼,代碼中只有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;//存儲(chǔ)數(shù)據(jù)的地址是否自動(dòng)增加dma_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//數(shù)據(jù)到達(dá)的地址是否自動(dòng)增加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)先級(jí)DMA_Init(DMA1_Channel4,&dma_struct);//初始化DMA_Cmd(DMA1_Channel4,ENABLE);//使能DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//中斷配置并使能}SendBuff數(shù)組存儲(chǔ)的是要發(fā)送的數(shù)據(jù),兩個(gè)函數(shù)為中斷配置函數(shù),在前面的外部中斷中已經(jīng)配置過了。第二個(gè)函數(shù)為DMA的配置函數(shù),與其他外設(shè)的配置類似,先定義一個(gè)結(jié)構(gòu)體,然后開啟時(shí)鐘。這個(gè)DMA1的時(shí)鐘和之前的都不一樣,在AHB上,配置時(shí)需要注意。
在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)志位} }在實(shí)驗(yàn)的過程中,編譯出現(xiàn)symbol multiply defined錯(cuò)誤的原因,因?yàn)樵趚xx.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----摸石头过河系列(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习 | 聚类评估指标
- 下一篇: 突破传统生物3D打印技术局限-王秀杰/C