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

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > STM32中USART的DMA 實(shí)現(xiàn)

          STM32中USART的DMA 實(shí)現(xiàn)

          作者: 時(shí)間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
          對(duì)于沒玩過DMA 的朋友,這里簡(jiǎn)單說一下DMA,用自己的語(yǔ)言說吧,那就是,從某個(gè)位置
          傳輸數(shù)據(jù)到某個(gè)位置,如果不用DMA,那要CPU參與操作,一個(gè)字節(jié)一個(gè)字節(jié)地搬,效率高
          點(diǎn)的,就一個(gè)字一個(gè)字地搬.但當(dāng)你用了DMA 后,那就是只需要設(shè)置:A.從哪里開始搬; B,
          搬到哪里去;C以字節(jié)方式搬還是半字還是字;D:一共搬多少個(gè).之后,啟動(dòng)DMA.CPU內(nèi)部
          就會(huì)開始搬數(shù)據(jù)了,整個(gè)搬數(shù)據(jù)的過程都不需要指令的參與,唯一要做的,就是檢測(cè)什么時(shí)
          候搬完.你可以掃描寄存器,也可以用中斷.這里,我使用了中斷.
          具體設(shè)置功能看注釋就可以明白了.注意一點(diǎn)就是,有一個(gè)設(shè)置:
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
          這個(gè)是外設(shè)的地址不遞增.也就是說,每次搬動(dòng),都是從源頭,也就是USART1的DR寄存器
          搬,但內(nèi)存地址卻是遞增的:
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

          這個(gè)歷程實(shí)現(xiàn)了 接受 串口的數(shù)據(jù) 寫到FLASH 之中工作,而DMA的作用在于將 串口收寄存器 USART1->DR 的 數(shù)據(jù)寫到內(nèi)存之中 比如某個(gè)數(shù)組之中 u8 USART1_DMA_Buf1[512]; 寫滿512個(gè)字節(jié)之后將進(jìn)入DMA中斷(通道5)在這里修改DMA 的內(nèi)存寫入入口
          u8 USART1_DMA_Buf2[512]; ,同時(shí)標(biāo)記 下次的入口Free_Buf_No=BUF_NO1; 與 Buf_Ok=TRUE; 證明已有數(shù)據(jù)準(zhǔn)備完成。這時(shí)CUP將USART1_DMA_Buf1中的數(shù)據(jù)寫入FLASH .

          又抄了一點(diǎn)

          這次使用的是雙緩沖,也有人
          叫乒乓緩沖.因?yàn)橐话闱闆r下,串口的數(shù)據(jù)DMA 傳輸進(jìn)BUF1 的過程中,是不建議對(duì)
          BUF1 進(jìn)行操作的.但由于串口數(shù)據(jù)是不會(huì)等待的直傳,所以你總不能等BUF1 滿了,
          才往FLASH 上寫,因?yàn)檫@時(shí)候串口數(shù)據(jù)依舊是源源不斷.于是,使用雙緩沖就變的理
          所當(dāng)然了.當(dāng)BUF1 滿了的時(shí)候,就馬上設(shè)置DMA的目標(biāo)為BUF2,并且BUF1的數(shù)據(jù)
          往25F080上灌.當(dāng)串口DMA寫滿了BUF2的時(shí)候,再設(shè)置DMA的目標(biāo)為BUF1,此時(shí)
          再操作BUF2寫進(jìn)25F080.如此一直循環(huán),就好像打乒乓球那樣吧,所以就叫乒乓緩沖.
          用這個(gè)方法的速度極限就是,你必須確保兩點(diǎn)a.DMA 灌滿了BUF1 的時(shí)候,會(huì)發(fā)生中
          斷,此時(shí)切換DMA 的目標(biāo)緩沖為BUF2,而且切換的過程必須在新的串口數(shù)據(jù)溢出之
          前完成.b.在DMA的BUF1滿之前,另外一個(gè)有數(shù)據(jù)的BUF2必須能全部寫進(jìn)25F080,
          其中包括了遇到新的扇區(qū)邊界而要刷除扇區(qū)的操作時(shí)間!!
          可以看出,BUF的增大,并不能夠很大程度的提升速度極限.



          假設(shè) USART 與 FLASH 的 底層驅(qū)動(dòng)已經(jīng)寫好了。 點(diǎn)擊查看。
          /************DMA方式傳輸***************************/

          #defineSRC_USART1_DR (&(USART1->DR)) //串口接收寄存器作為源頭

          //DMA目標(biāo)緩沖,這里使用雙緩沖
          u8USART1_DMA_Buf1[512];
          u8USART1_DMA_Buf2[512];
          boolBuf_Ok;//BUF是否已經(jīng)可用
          BUF_NOFree_Buf_No; //空閑的BUF號(hào)typedefenum{BUF_NO1=0,BUF_NO2=1}BUF_NO;


          DMA_InitTypeDefDMA_InitStructure;

          voidUSART_DMAToBuf1(void)
          {
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//開DMA時(shí)鐘
          DMA_DeInit(DMA1_Channel5);//將DMA的通道1寄存器重設(shè)為缺省值
          DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR; //源頭BUF既是 (&(USART1->DR))
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1; //目標(biāo)BUF 既是要寫在哪個(gè)個(gè)數(shù)組之中
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外設(shè)作源頭//外設(shè)是作為數(shù)據(jù)傳輸?shù)哪康牡剡€是來源
          DMA_InitStructure.DMA_BufferSize = 512; //DMA緩存的大小 單位在下邊設(shè)定
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設(shè)地址寄存器不遞增
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內(nèi)存地址遞增
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設(shè)字節(jié)為單位
          DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //內(nèi)存字節(jié)為單位
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循環(huán)緩存模式
          DMA_InitStructure.DMA_Priority = DMA_Priority_High; //4優(yōu)先級(jí)之一的(高優(yōu)先)VeryHigh/High/Medium/Low
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非內(nèi)存到內(nèi)存
          DMA_Init(DMA1_Channel5, &DMA_InitStructure);//根據(jù)DMA_InitStruct中指定的參數(shù)初始化DMA的通道1寄存器

          DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); //DMA5傳輸完成中斷


          USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能USART1的接收DMA請(qǐng)求
          /*****************************************************************************************************************************************************/
          //初始化BUF標(biāo)志
          Free_Buf_No=BUF_NO2;//因?yàn)?DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
          Buf_Ok=FALSE;//此時(shí)沒有數(shù)據(jù)準(zhǔn)備完成 當(dāng)然FALSE
          DMA_Cmd(DMA1_Channel5, ENABLE); //正式允許DMA

          }

          再來看看DMA中斷:

          //u16DataCounter;
          externDMA_InitTypeDefDMA_InitStructure;
          voidDMA1_Channel5_IRQHandler(void)
          {
          if(DMA_GetITStatus(DMA1_IT_TC5))//通道5傳輸完成中斷TC還有傳輸 過半中斷HT 錯(cuò)誤中斷TE 全局中斷GL
          {
          //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);//獲取剩余長(zhǎng)度,一般都為0,調(diào)試用
          DMA_ClearITPendingBit(DMA1_IT_GL5);//清除全部中斷標(biāo)志

          //轉(zhuǎn)換可操作BUF
          if(Free_Buf_No==BUF_NO1)
          {
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
          DMA_Init(DMA1_Channel5, &DMA_InitStructure);
          Free_Buf_No=BUF_NO2;
          }
          else
          {
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;
          DMA_Init(DMA1_Channel5, &DMA_InitStructure);
          Free_Buf_No=BUF_NO1;
          }
          Buf_Ok=TRUE;//有準(zhǔn)備好的數(shù)據(jù)了

          }
          }

          寫FLASH的操作
          while(1)
          {
          if(Buf_Ok==TRUE)
          {
          LED1_ON;//一個(gè)標(biāo)記
          Buf_Ok=FALSE;//操作了準(zhǔn)備好的數(shù)據(jù)
          if((addr%4096)==0) //跨越一個(gè)扇區(qū),則需要先刷除
          {
          SST25SectorErase(addr);
          sector_count++;
          }
          if(Free_Buf_No==BUF_NO1)
          SST25Write(addr,USART1_DMA_Buf1,512);
          else
          SST25Write(addr,USART1_DMA_Buf2,512);
          addr+=512;
          Timer1=5000;//時(shí)間重置
          LED1_OFF;
          }

          //檢測(cè)超時(shí)開了定時(shí)器
          if(Timer1==0)//五秒內(nèi)沒準(zhǔn)備好的數(shù)據(jù)
          {
          //獲取長(zhǎng)度
          len=512-DMA_GetCurrDataCounter(DMA1_Channel5);
          //寫入最后數(shù)據(jù)
          if(Free_Buf_No==BUF_NO1)
          SST25Write(addr,USART1_DMA_Buf2,len);
          else
          SST25Write(addr,USART1_DMA_Buf1,len);
          addr+=len;

          break;
          }
          }



          還是很簡(jiǎn)單的。
          有一點(diǎn)比較困擾 就是 FlagStatus標(biāo)志位 與 ITStatus中斷標(biāo)志位 的區(qū)別。 其實(shí)就 DMA 來說 DMA_IT值 與 DMA_FLAG值 是一樣的
          甚至2者值的獲取 都是讀 DMA ISR register 的值 清除也是設(shè)置 DMA_IFCR 寄存器來清除的所以貌似沒有區(qū)別.........同理這個(gè)問題在別的中斷也存在但我還不可保證 IT 與FLAG 的值總是相同的這個(gè)存在也許是為了兼容但一定有其意義務(wù)必不可混用即使有時(shí)用錯(cuò)也正確.....


          關(guān)鍵詞: STM32USARTDM

          評(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); })();