<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          stm32之DMA徹底研究

          作者: 時(shí)間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
          在做實(shí)驗(yàn)之前,首先必須明白什么是DMA,DMA的作用又體現(xiàn)在哪里。
          DMA,即直接內(nèi)存存儲(chǔ),在一些數(shù)據(jù)的傳輸中,采用DMA方式,從而將CPU解放出來。讓CPU有足夠的時(shí)間處理其他的事情。
          stm32使用DMA的相關(guān)操作:
          1、DMA的配置
          要配置的有DMA傳輸通道選擇,傳輸?shù)某蓡T和方向、普通模式還是循環(huán)模式等等。
          void DMA_Configuration(void)
          {
          DMA_InitTypeDef DMA_InitStructure;
          //DMA設(shè)置:
          //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
          //方向:內(nèi)存-->外設(shè)
          //每次傳輸位:8bit
          //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
          //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
          //DMA模式:一次傳輸,非循環(huán)
          //優(yōu)先級(jí):中
          DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
          DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設(shè)作為DMA的目的端
          DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設(shè)地址不增加
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內(nèi)存地址自增1
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
          //DMA_Mode_Normal(只傳送一次), DMA_Mode_Circular (不停地傳送)
          DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優(yōu)先級(jí)為中等)
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel4, &DMA_InitStructure);
          }
          注:
          1、傳輸通道:通過查表,串口1的發(fā)送對(duì)應(yīng)的是DMA的通道4,所以此處選擇通道4.
          2、DMA傳輸方式:
          (1) DMA_Mode_Normal,正常模式,當(dāng)一次DMA數(shù)據(jù)傳輸完后,停止DMA傳送,對(duì)于上例而言,就是DMA_PeripheralDataSize_Byte個(gè)字節(jié)的傳送完成后,就停止傳送。
          (2) DMA_Mode_Circular
          循環(huán)模式,當(dāng)傳輸完一次后,重新接著傳送,永不停息。
          2、外設(shè)的DMA方式設(shè)置
          將串口1設(shè)置成DMA模式:
          USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
          3、待傳輸數(shù)據(jù)的定義和初始化
          #define SENDBUFF_SIZE 10240
          vu8 SendBuff[SENDBUFF_SIZE];
          for(i=0;i{
          SendBuff[i] = i%10+0;
          }
          4、開始DMA傳輸(使能對(duì)應(yīng)的DMA通道)
          DMA_Cmd(DMA1_Channel4, ENABLE);
          5、DMA傳輸?shù)耐瓿?/div>
          while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
          {
          LED_1_REV; //LED翻轉(zhuǎn)
          Delay(); //浪費(fèi)時(shí)間
          }
          當(dāng)傳輸完成后,就會(huì)跳出上面的死循環(huán)。
          下面是九九的一個(gè)例程,測試過,可以運(yùn)行!
          /******************************************************************************
          * 本文件實(shí)現(xiàn)串口發(fā)送功能(通過重構(gòu)putchar函數(shù),調(diào)用printf;或者USART_SendData()
          * 這里是一個(gè)用串口實(shí)現(xiàn)大量數(shù)據(jù)傳輸?shù)睦?,使用了DMA模塊進(jìn)行內(nèi)存到USART的傳輸
          * 每當(dāng)USART的發(fā)送緩沖區(qū)空時(shí),USART模塊產(chǎn)生一個(gè)DMA事件,
          * 此時(shí)DMA模塊響應(yīng)該事件,自動(dòng)從預(yù)先定義好的發(fā)送緩沖區(qū)中拿出下一個(gè)字節(jié)送給USART
          * 整個(gè)過程無需用戶程序干預(yù),用戶只需啟動(dòng)DMA傳輸傳輸即可
          * 在仿真器調(diào)試時(shí),可以在數(shù)據(jù)傳輸過程中暫停運(yùn)行,此時(shí)DMA模塊并沒有停止
          * 串口依然發(fā)送,表明DMA傳輸是一個(gè)獨(dú)立的過程。
          * 同時(shí)開啟接收中斷,在串口中斷中將數(shù)據(jù)存入緩沖區(qū),在main主循環(huán)中處理
          * 作者:jjldc(九九)
          * 代碼硬件基于萬利199元的EK-STM32F開發(fā)板,CPU=STM32F103VBT6
          *******************************************************************************/
          /* Includes ------------------------------------------------------------------*/
          #include "stm32f10x_lib.h"
          #include "stdio.h"
          /* Private typedef -----------------------------------------------------------*/
          /* Private define ------------------------------------------------------------*/
          #define USART1_DR_Base 0x40013804
          /* Private macro -------------------------------------------------------------*/
          /* Private variables ---------------------------------------------------------*/
          #define SENDBUFF_SIZE 10240
          vu8 SendBuff[SENDBUFF_SIZE];
          vu8 RecvBuff[10];
          vu8 recv_ptr;
          /* Private function prototypes -----------------------------------------------*/
          void RCC_Configuration(void);
          void GPIO_Configuration(void);
          void NVIC_Configuration(void);
          void DMA_Configuration(void);
          void USART1_Configuration(void);
          int fputc(int ch, FILE *f);
          void Delay(void);
          /* Private functions ---------------------------------------------------------*/
          /*******************************************************************************
          * Function Name : main
          * Description : Main program.
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          int main(void)
          {
          u16 i;
          #ifdef DEBUG
          debug();
          #endif
          recv_ptr = 0;

          本文引用地址:http://www.ex-cimer.com/article/201611/318279.htm

          RCC_Configuration();
          GPIO_Configuration();
          NVIC_Configuration();
          DMA_Configuration();
          USART1_Configuration();

          printf("rnSystem Start...rn");
          printf("Initialling SendBuff... rn");
          for(i=0;i{
          SendBuff[i] = i%10+0;
          }
          printf("Initial success!rnWaiting for transmission...rn");
          //發(fā)送去數(shù)據(jù)已經(jīng)準(zhǔn)備好,按下按鍵即開始傳輸
          while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

          printf("Start DMA transmission!rn");

          //這里是開始DMA傳輸前的一些準(zhǔn)備工作,將USART1模塊設(shè)置成DMA方式工作
          USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
          //開始一次DMA傳輸!
          DMA_Cmd(DMA1_Channel4, ENABLE);

          //等待DMA傳輸完成,此時(shí)我們來做另外一些事,點(diǎn)燈
          //實(shí)際應(yīng)用中,傳輸數(shù)據(jù)期間,可以執(zhí)行另外的任務(wù)
          while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
          {
          // LED_1_REV; //LED翻轉(zhuǎn)
          Delay(); //浪費(fèi)時(shí)間
          }
          //DMA傳輸結(jié)束后,自動(dòng)關(guān)閉了DMA通道,而無需手動(dòng)關(guān)閉
          //下面的語句被注釋
          //DMA_Cmd(DMA1_Channel4, DISABLE);

          printf("rnDMA transmission successful!rn");


          /* Infinite loop */
          while (1)
          {
          }
          }
          /*******************************************************************************
          * Function Name : 重定義系統(tǒng)putchar函數(shù)int fputc(int ch, FILE *f)
          * Description : 串口發(fā)一個(gè)字節(jié)
          * Input : int ch, FILE *f
          * Output :
          * Return : int ch
          * 這個(gè)是使用printf的關(guān)鍵
          *******************************************************************************/
          int fputc(int ch, FILE *f)
          {
          //USART_SendData(USART1, (u8) ch);
          USART1->DR = (u8) ch;

          /* Loop until the end of transmission */
          while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
          {
          }

          return ch;
          }
          /*******************************************************************************
          * Function Name : Delay
          * Description : 延時(shí)函數(shù)
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          void Delay(void)
          {
          u32 i;
          for(i=0;i<0xF0000;i++);
          return;
          }
          /*******************************************************************************
          * Function Name : RCC_Configuration
          * Description : 系統(tǒng)時(shí)鐘設(shè)置
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          void RCC_Configuration(void)
          {
          ErrorStatus HSEStartUpStatus;
          //使能外部晶振
          RCC_HSEConfig(RCC_HSE_ON);
          //等待外部晶振穩(wěn)定
          HSEStartUpStatus = RCC_WaitForHSEStartUp();
          //如果外部晶振啟動(dòng)成功,則進(jìn)行下一步操作
          if(HSEStartUpStatus==SUCCESS)
          {
          //設(shè)置HCLK(AHB時(shí)鐘)=SYSCLK
          RCC_HCLKConfig(RCC_SYSCLK_Div1);
          //PCLK1(APB1) = HCLK/2
          RCC_PCLK1Config(RCC_HCLK_Div2);
          //PCLK2(APB2) = HCLK
          RCC_PCLK2Config(RCC_HCLK_Div1);
          //FLASH時(shí)序控制
          //推薦值:SYSCLK = 0~24MHz Latency=0
          // SYSCLK = 24~48MHz Latency=1
          // SYSCLK = 48~72MHz Latency=2
          FLASH_SetLatency(FLASH_Latency_2);
          //開啟FLASH預(yù)取指功能
          FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
          //PLL設(shè)置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
          RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
          //啟動(dòng)PLL
          RCC_PLLCmd(ENABLE);
          //等待PLL穩(wěn)定
          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
          //系統(tǒng)時(shí)鐘SYSCLK來自PLL輸出
          RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
          //切換時(shí)鐘后等待系統(tǒng)時(shí)鐘穩(wěn)定
          while(RCC_GetSYSCLKSource()!=0x08);

          /*
          //設(shè)置系統(tǒng)SYSCLK時(shí)鐘為HSE輸入
          RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
          //等待時(shí)鐘切換成功
          while(RCC_GetSYSCLKSource() != 0x04);
          */
          }
          //下面是給各模塊開啟時(shí)鐘
          //啟動(dòng)GPIO
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
          RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,
          ENABLE);
          //啟動(dòng)AFIO
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
          //啟動(dòng)USART1
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
          //啟動(dòng)DMA時(shí)鐘
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

          }

          /*******************************************************************************
          * Function Name : GPIO_Configuration
          * Description : GPIO設(shè)置
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          void GPIO_Configuration(void)
          {
          GPIO_InitTypeDef GPIO_InitStructure;
          //PC口4567腳設(shè)置GPIO輸出,推挽 2M
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
          GPIO_Init(GPIOC, &GPIO_InitStructure);
          //KEY2 KEY3 JOYKEY
          //位于PD口的3 4 11-15腳,使能設(shè)置為輸入
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |
          GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
          GPIO_Init(GPIOD, &GPIO_InitStructure);
          //USART1_TX
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
          GPIO_Init(GPIOA, &GPIO_InitStructure);

          //USART1_RX
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
          GPIO_Init(GPIOA, &GPIO_InitStructure);

          }
          /*******************************************************************************
          * Function Name : NVIC_Configuration
          * Description : NVIC設(shè)置
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          void NVIC_Configuration(void)
          {
          NVIC_InitTypeDef NVIC_InitStructure;
          #ifdef VECT_TAB_RAM
          // Set the Vector Table base location at 0x20000000
          NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
          #else /* VECT_TAB_FLASH */
          // Set the Vector Table base location at 0x08000000
          NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
          #endif
          //設(shè)置NVIC優(yōu)先級(jí)分組為Group2:0-3搶占式優(yōu)先級(jí),0-3的響應(yīng)式優(yōu)先級(jí)
          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
          //串口接收中斷打開
          NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
          NVIC_Init(&NVIC_InitStructure);
          }

          /*******************************************************************************
          * Function Name : USART1_Configuration
          * Description : NUSART1設(shè)置
          * Input : None
          * Output : None
          * Return : None
          *******************************************************************************/
          void USART1_Configuration(void)
          {
          USART_InitTypeDef USART_InitStructure;

          USART_InitStructure.USART_BaudRate = 9600;
          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_Tx | USART_Mode_Rx;
          USART_Init(USART1, &USART_InitStructure);

          USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

          USART_Cmd(USART1, ENABLE);
          }


          void DMA_Configuration(void)
          {
          DMA_InitTypeDef DMA_InitStructure;
          //DMA設(shè)置:
          //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
          //方向:內(nèi)存-->外設(shè)
          //每次傳輸位:8bit
          //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
          //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
          //DMA模式:一次傳輸,非循環(huán)
          //優(yōu)先級(jí):中
          DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
          DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設(shè)作為DMA的目的端
          DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設(shè)地址不增加
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內(nèi)存地址自增1
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal(只傳送一次), DMA_Mode_Circular (不停地傳送)
          DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優(yōu)先級(jí)為中等)
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel4, &DMA_InitStructure);
          }
          需要說明的是,由于DMA傳輸不需要CPU的參與。
          所以在調(diào)試的時(shí)候會(huì)發(fā)現(xiàn),在我們單步停止的時(shí)候,串口依然不停地向外發(fā)送數(shù)據(jù)。



          關(guān)鍵詞: STM32DM

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁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); })();