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