(三)stm32之串口通信DMA傳輸完成中斷
一、DMA功能簡介
首先嘮叨一下DMA的基本概念,DMA的出現(xiàn)大大減輕了CPU的工作量。在硬件系統(tǒng)中,主要由CPU(內(nèi)核)、外設(shè)、內(nèi)存(SRAM)、總線等結(jié)構(gòu)組成,數(shù)據(jù)經(jīng)常要在內(nèi)存和外設(shè)之間,外設(shè)和外設(shè)之間轉(zhuǎn)移。例如:CPU需要處理從外設(shè)采集回來的數(shù)據(jù),CPU需要先將數(shù)據(jù)從ADC外設(shè)的寄存器讀取到內(nèi)存中(變量)去,然后進(jìn)行運(yùn)算處理,這是一般的解決方法。CPU的資源是非常寶貴的,我們可以設(shè)法把轉(zhuǎn)移的工作交給其他部件來完成,CPU把更多的資源用于數(shù)據(jù)運(yùn)算和中斷響應(yīng)上,如此DMA便登場了。DMA正是為CPU分擔(dān)數(shù)據(jù)轉(zhuǎn)移工作,因為DMA的存在,CPU才被解放出來,它可以在數(shù)據(jù)轉(zhuǎn)移的同時進(jìn)行數(shù)據(jù)運(yùn)算,相應(yīng)中斷,大大提高了效率。
二、DMA的主要特性
三、DMA中斷特性
四、DMA之串口通信
我們實(shí)現(xiàn)一個簡單的功能,在DMA中處理串口通信,把數(shù)據(jù)轉(zhuǎn)移的工作交給DMA,DMA把數(shù)據(jù)從內(nèi)存(數(shù)組)到外設(shè)(串口)的轉(zhuǎn)移,在main函數(shù)中不斷進(jìn)行閃燈操作,這樣我們可以看到DMA在工作的時候CPU也在工作。非常有必要復(fù)習(xí)一下DMA的對應(yīng)關(guān)系,我們知道stm32總共有2個DMA控制器(DMA1有7個通道,DMA2有5個通道),每個通道專門用來管理來自一個或多個外設(shè)對存儲器訪問的請求,還有一個仲裁器來協(xié)調(diào)DMA請求的優(yōu)先級(優(yōu)先級分:很高、高、中等、低),這可不是隨便對應(yīng)的。
1、LED初始化程序如下:
1234567891011121314151617voidLED_GPIO_Config(void){/*定義一個GPIO_InitTypeDef類型的結(jié)構(gòu)體*/GPIO_InitTypeDef GPIO_InitStructure;/*開啟LED的外設(shè)時鐘*/RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);/*選擇要控制的GPIOB引腳*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;/*設(shè)置引腳模式為通用推挽輸出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;/*設(shè)置引腳速率為50MHz */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*調(diào)用庫函數(shù),初始化GPIOB0*/GPIO_Init(GPIOB, &GPIO_InitStructure);/* 關(guān)閉所有l(wèi)ed燈 */GPIO_SetBits(GPIOB, GPIO_Pin_14);}這個地方地方?jīng)]什么要注意的,唯一要注意的就是輸入輸出模式,我們按需求這樣配就好了。
2、串口初始化
123456789101112131415161718192021222324252627voidUSART3_Config(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;/* config USART3 clock */RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE);/* USART1 GPIO config *//* Configure USART1 Tx (PA.09) as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure USART1 Rx (PA.10) as input floating */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);/* USART1 mode config */USART_InitStructure.USART_BaudRate = 38400;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART3, &USART_InitStructure);USART_Cmd(USART3, ENABLE);}3、DMA初始化
123456789101112131415161718192021222324252627282930313233343536voidUSART3_DMA_Config(void){DMA_InitTypeDef DMA_InitStructure;/*開啟DMA時鐘*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//NVIC_Config(); //配置DMA中斷//NVIC_Configuration();/*設(shè)置DMA源:串口數(shù)據(jù)寄存器地址*/DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;/*內(nèi)存地址(要傳輸?shù)淖兞康闹羔?*/DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;/*方向:從內(nèi)存到外設(shè)*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;/*傳輸大小DMA_BufferSize=SENDBUFF_SIZE*/DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;/*外設(shè)地址不增*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/*內(nèi)存地址自增*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/*外設(shè)數(shù)據(jù)單位*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;/*內(nèi)存數(shù)據(jù)單位 8bit*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;/*DMA模式:不斷循環(huán)*/DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;/*優(yōu)先級:中*/DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;/*禁止內(nèi)存到內(nèi)存的傳輸 */DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;/*配置DMA1的2通道*/DMA_Init(DMA1_Channel2, &DMA_InitStructure);//DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE); //配置DMA發(fā)送完成后產(chǎn)生中斷/*使能DMA*/DMA_Cmd (DMA1_Channel2,ENABLE);}在這里我們要注意以下幾點(diǎn):
(1)DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;這里對應(yīng)USART數(shù)據(jù)寄存器地址,這個地址我們是這樣定義的:#define USART3_DR_Base 0x40004804,這個值是怎么算出來的呢?我們可以查看stm32存儲器映射表:
USART3的起始地址是0x40004800,我們查看stm32串口數(shù)據(jù)寄存器偏移地址為0x04
因此我們可以計算到USART3數(shù)據(jù)寄存器地址為0x40004804
(2)我們數(shù)據(jù)傳輸方向內(nèi)存(變量)到外設(shè)(串口),所以DMA方向為內(nèi)存到外設(shè)
(3)DMA傳輸模式有兩種:DMA_Mode_Normal(普通模式),DMA只傳輸一次;DMA_Mode_Circular(循環(huán)模式),DMA循環(huán)傳輸,比如在AD采集時要配置成循環(huán)模式。
4、主函數(shù)
123456789101112131415161718192021222324252627intmain(void){/* USART1 config 115200 8-N-1 */USART3_Config();USART3_DMA_Config();LED_GPIO_Config();printf("rn usart3 DMA TX 測試 rn");{ ui