<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學(xué)習(xí)筆記之SPI_DMA寄存器級(jí)操作

          STM32學(xué)習(xí)筆記之SPI_DMA寄存器級(jí)操作

          作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏

          一、實(shí)驗(yàn)?zāi)繕?biāo)

          學(xué)會(huì)配置STM32SPI寄存器和DMA寄存器,實(shí)現(xiàn)STM32的SPI1與SPI2通信功能,每次發(fā)送一字節(jié)數(shù)據(jù),并可多次發(fā)送,如果接收的數(shù)據(jù)正確,則點(diǎn)亮LED燈。

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

          二、實(shí)驗(yàn)?zāi)康?/h2>

          加入DMA的SPI通信相對(duì)于普通SPI通信有什么好處?ST給SPI加了DMA功能出于什么目的?我覺(jué)得這是很重要的一個(gè)問(wèn)題,一直邊學(xué)習(xí)邊想。以下是我的看法:

          減少CPU負(fù)荷?我想這應(yīng)該是DMA最主要的功能,可是對(duì)于SPI通信來(lái)說(shuō),其實(shí)大部分時(shí)候我們需要根據(jù)發(fā)送的指令->目標(biāo)器件的應(yīng)答來(lái)決定下一個(gè)指令,所以此時(shí)CPU還是需要一直等待每次通信的結(jié)束。而且像SD卡的操作,是一個(gè)順序流的指令操作過(guò)程,用中斷也不容易控制。那到底加入了DMA有什么好處?仔細(xì)查看了STM32F10xxx的用戶(hù)手冊(cè),發(fā)現(xiàn)這么一行字“連續(xù)和非連續(xù)傳輸:當(dāng)在主模式下發(fā)送數(shù)據(jù)時(shí),如果軟件足夠快,能夠在檢測(cè)到每次TXE的上升沿(或TXE中斷),并立即在正在進(jìn)行的傳輸結(jié)束之前寫(xiě)入SPI_DR寄存器,則能夠?qū)崿F(xiàn)連續(xù)的通信;此時(shí),在每個(gè)數(shù)據(jù)項(xiàng)的傳輸之間的SPI時(shí)鐘保持連續(xù),同時(shí)BSY位不會(huì)被清除。如果軟件不夠快,則會(huì)導(dǎo)致不連續(xù)的通信;這時(shí),在每個(gè)數(shù)據(jù)傳輸之間會(huì)被清除”以及

          也就是說(shuō)如果連續(xù)傳輸而不使用DMA的話(huà),需要CPU不停檢測(cè)TXE并很快地置入SPI->DR的值,對(duì)于復(fù)雜程序的話(huà)這是很難達(dá)到的,而如果使用DMA,就可以輕易實(shí)現(xiàn)連續(xù)傳輸,CPU只需等待其完成就好。我想到的一個(gè)應(yīng)用就是在寫(xiě)SD卡的時(shí)候,每次寫(xiě)一個(gè)塊512字節(jié),就可以用到,能提高SD卡的寫(xiě)入數(shù)據(jù)速率。

          其次還可以降低功耗,記得數(shù)字集成電路老師說(shuō)過(guò)一句話(huà)“軟件上降低數(shù)字電路功耗的一個(gè)方法就是減少電平轉(zhuǎn)換。”那么連續(xù)通信的時(shí)候,像SPI的BSY電平轉(zhuǎn)換會(huì)大大減少!

          最后一點(diǎn),雖然效果不大,就是如果不是用DMA,那么CPU的工作就是搬運(yùn)工,把SPI->DR的內(nèi)容搬到內(nèi)存存儲(chǔ)起來(lái),而如果使用DMA,就省略了這個(gè)環(huán)節(jié)!

          我想,為什么實(shí)現(xiàn)同一個(gè)功能,有的執(zhí)行起來(lái)很流暢,有的卻很卡,應(yīng)該和這些小細(xì)節(jié)的減載有關(guān)吧。

          這次先把SPI基本通信寫(xiě)出來(lái),然后再寫(xiě)SPI的連續(xù)通信,并看能不能用到SD卡讀寫(xiě)上。

          三、SPI&DMA分析

          1、這里先說(shuō)明一下SPI的全雙工通信(高手略過(guò)哈)

          SPI全雙工通信的特點(diǎn):一邊發(fā)送一邊接收,硬件上只有一個(gè)SPI->DR寄存器和兩個(gè)緩沖器(發(fā)送緩沖器和接收緩沖器),主模式(從模式類(lèi)似):SPI->DR會(huì)先讀發(fā)送緩沖器,并通過(guò)MOSI管腳(Master output Slave Input)一位一位地發(fā)送出去,在發(fā)送的過(guò)程中,SPI->DR的數(shù)據(jù)會(huì)左移(如果是高位先發(fā)送),并且會(huì)從MISO(Master input Slave output)讀入數(shù)據(jù)填補(bǔ)SPI->DR左移后的空缺。傳完8比特后,SPI->DR再把數(shù)據(jù)并行寫(xiě)入接收緩沖寄存器。所以,SPI1與SPI2的通信過(guò)程如下:

          配置SPI寄存器的時(shí)候,需要注意以下幾點(diǎn):

          (1)nss的配置:如果是單主單從,使用nss軟件管理,除了用MSTR配置主從設(shè)備,還要設(shè)置SSM和SSI,只有在SSM位為1時(shí),SSI位才有意義。

          (2)主從設(shè)備的數(shù)據(jù)幀格式,時(shí)鐘沿讀寫(xiě)模式要一致;

          (3)SPI的寄存器也需要開(kāi)啟DMA使能;

          (4)SPI雖然可以發(fā)送16bit數(shù)據(jù),可是只支持8bitDMA!

          2、再說(shuō)一下DMA

          DMA——Direct Memory Access,直接內(nèi)存存取,作用是獨(dú)立于CPU,直接建立內(nèi)存與外設(shè)的通信通道。

          SPI的DMA操作,就是在SPI->TXE為1時(shí),會(huì)向?qū)?yīng)的DMA通道發(fā)出請(qǐng)求,DMA通道會(huì)發(fā)出應(yīng)答信號(hào),SPI收到應(yīng)答信號(hào)后撤銷(xiāo)請(qǐng)求信號(hào),DMA撤銷(xiāo)應(yīng)答信號(hào),并把內(nèi)存值置入發(fā)送緩沖,SPI傳送開(kāi)始。接收過(guò)程與上面類(lèi)似。

          DMA配置的部分說(shuō)明:

          (1)需要使能RCC寄存器的SPI和DMA時(shí)鐘,至于輔助時(shí)鐘,查過(guò)網(wǎng)上的討論,有人說(shuō)一些外設(shè)如果沒(méi)有開(kāi)啟輔助時(shí)鐘會(huì)不能用,但SPI不需要;

          (2)DMA的存儲(chǔ)器地址(memorybaseaddr):即變量地址。我們?cè)诔绦蛑卸x的每個(gè)變量,都有對(duì)應(yīng)的內(nèi)存地址,你想把SPI的接收發(fā)送數(shù)據(jù)存在哪個(gè)變量,就將對(duì)應(yīng)變量的地址賦給DMA存儲(chǔ)器地址寄存器。如u8 SPI1_TX_Buff的地址是(u32)&SPI1_TX_Buff;u8 SPI1_TX_Buff[512]的地址是(u32)SPI1_TX_Buff。

          (3)DMA循環(huán)模式:有些資料會(huì)譯為DMA的循環(huán)緩存模式,我覺(jué)得不太準(zhǔn)確,這里循環(huán)的意思是指DMA的傳輸數(shù)量計(jì)數(shù)器會(huì)重置初值,由于DMA每傳一個(gè)數(shù)據(jù),傳輸數(shù)量計(jì)數(shù)器減一,只有在傳輸數(shù)量計(jì)數(shù)器的值不為零時(shí),才會(huì)響應(yīng)請(qǐng)求。在循環(huán)模式下,當(dāng)傳輸計(jì)數(shù)器的值減為0后,會(huì)重新裝載;而內(nèi)存(緩存)地址則不管循環(huán)非循環(huán)模式,都會(huì)在每次傳輸完成后重置為基地址。所以,如果我們把DMA設(shè)置會(huì)正常模式,那么在下次傳輸前,只需對(duì)DMA的傳輸數(shù)量計(jì)數(shù)器重新寫(xiě)入就行。

          循環(huán)模式一般用于數(shù)據(jù)更新,比如ADC采用需要不停更新數(shù)據(jù)。

          (4)DMA的外設(shè)地址:正點(diǎn)原子的串口DMA實(shí)驗(yàn)中,在寫(xiě)外設(shè)地址時(shí),都會(huì)用一個(gè)變量緩存再寫(xiě)入,否則程序就運(yùn)行不正確,他也不知道為什么,而ST庫(kù)函數(shù)的example中對(duì)于外設(shè)地址也都是重新define的,所以外設(shè)地址最好還是采用#define SPI1_DR_Addr ( (u32)0x4001300C )定義的好。

          至于外設(shè)地址,可以先從STM32的用戶(hù)手冊(cè)“2.3存儲(chǔ)器映像”得到起始地址+對(duì)應(yīng)外設(shè)所在目錄的“寄存器地址映像”標(biāo)識(shí)的偏移地址。例如:從“2.3存儲(chǔ)器映像”得到SPI1起始地址0x40013000,從SPI所在目錄的“寄存器地址映像”得到SPI->DR的偏移量為0x0C,那么SPI1_DR_Addr就是0x4001300C;

          (5)DMA通道開(kāi)啟順序:按照下圖的數(shù)字序號(hào)依次開(kāi)啟,才能確保數(shù)據(jù)正確發(fā)送。比如①的SPI2_TX_Buff對(duì)應(yīng)的是DMA通道5.

          (6)正常模式的第二次發(fā)送:DMA發(fā)送的時(shí)候只需使能DMA就可以開(kāi)始傳送,但是第二次傳送之前,需要進(jìn)行以下步驟:

          1、關(guān)閉DMA通道;

          2、清除DMA傳輸完成標(biāo)志以及重置CNDTR傳輸數(shù)量計(jì)數(shù)器;

          3、開(kāi)啟DMA通道,等待傳輸完成。

          四、實(shí)驗(yàn)結(jié)果

          利用SPI1和SPI2進(jìn)行兩次數(shù)據(jù)傳輸,并比較SPI1_RX與SPI2_TX,SPI2_RX與SPI1_TX,數(shù)據(jù)相同點(diǎn)亮LED燈。

          在某個(gè)論壇看到有人說(shuō)把SPI的速度設(shè)置為2分頻傳輸數(shù)據(jù)不正確,分析原因是DMA反應(yīng)不過(guò)來(lái)。我也試了一下,傳輸正常,數(shù)據(jù)正確。(SPI傳輸速率是用JLINK仿真查看寄存器的)

          哦,對(duì)了,期間還吃過(guò)一個(gè)虧,害我調(diào)了好久,就是下面的語(yǔ)句:

          while( ( DMA1->ISR & (1<<17) ) == 0 ) ; //等待通道5傳輸完成

          我寫(xiě)成:

          while( DMA1->ISR & (1<<17) == 0 ) ; //等待通道5傳輸完成

          由于“==”的優(yōu)先級(jí)比“&”高,所以會(huì)先執(zhí)行“(1<<17) == 0”,結(jié)果是0,再與上DMA1->ISR,那么相當(dāng)于while直接跳過(guò)了,讀不到數(shù)據(jù)!很低級(jí)的錯(cuò)誤!所以提醒后來(lái)者,看起來(lái)可加可不加的括號(hào),還是要加上去的好!

          還有一個(gè)問(wèn)題,一直在想DMA傳輸,那么硬件怎么認(rèn)為一次傳輸?shù)慕Y(jié)束而停止以及怎樣才能開(kāi)啟新一次的傳輸。我覺(jué)得最關(guān)鍵就是DMA的傳輸數(shù)量計(jì)數(shù)器以及DMA的傳輸完成標(biāo)志。只要DMA的計(jì)數(shù)器不為零,就能響應(yīng)請(qǐng)求傳輸,此時(shí)就算傳輸完成標(biāo)志置位,也能進(jìn)行DMA響應(yīng),只不過(guò)你不知道什么時(shí)候完成罷了。所以每次傳輸開(kāi)始前,程序需要清除標(biāo)志位并檢測(cè)到該標(biāo)志位置位,才知道一次傳輸是否完成!

          續(xù):終于把SPI的DMA弄完了,實(shí)現(xiàn)了連續(xù)發(fā)送和讀取的功能,DMA開(kāi)辟512字節(jié)的數(shù)組作為內(nèi)存存儲(chǔ)數(shù)據(jù)(所以連續(xù)發(fā)送最大的數(shù)據(jù)量也是512,當(dāng)然可以在宏定義里面更改),通過(guò)num控制要寫(xiě)入或讀入的數(shù)據(jù)量,源代碼中有3個(gè)函數(shù),一個(gè)函數(shù)是讀寫(xiě)一體的,一個(gè)函數(shù)是只發(fā)送模式,一個(gè)函數(shù)是只接收模式,都通過(guò)測(cè)試。唯一的缺陷就是沒(méi)有進(jìn)行錯(cuò)誤檢測(cè),特別說(shuō)明一下,我把清標(biāo)志位是放在函數(shù)前面而不是函數(shù)后面,就是想函數(shù)執(zhí)行完,標(biāo)志位依然還在,我們可以以此來(lái)判斷是否有錯(cuò)誤。在這里和大家分享一下小經(jīng)驗(yàn)。

          (1)怎么測(cè)試?最好的測(cè)試方法我覺(jué)得就是雙機(jī)通訊了,由于實(shí)驗(yàn)室資源比較好,所以我得以有兩個(gè)STM32(非MiniSTM32,用的是AG嵌入式開(kāi)發(fā)板)進(jìn)行測(cè)試,所以以上代碼都是通過(guò)雙擊測(cè)試的,不過(guò)我只整理了SPI1主機(jī)源代碼,需要的自己稍微改一下就可以,程序中有注釋?zhuān)?/p>

          (2)用雙機(jī)測(cè)試的時(shí)候,剛開(kāi)始我沒(méi)有共地,導(dǎo)致數(shù)據(jù)可以接收,但是數(shù)據(jù)錯(cuò)誤!所以緊記,當(dāng)你使用兩個(gè)器件通訊或交互時(shí),一定要先檢查兩個(gè)器件是否共地,甚至共源!

          (3)如果只有一個(gè)STM32其實(shí)也可以測(cè)試,就是把MISO和MOSI短接,但這個(gè)測(cè)試方法,用來(lái)測(cè)試SPI1_ReceiveSendByte(u16 num)就比較方便,用來(lái)測(cè)試只發(fā)送和只接收模式就需要改一下函數(shù)咯。

          (4)弄了這么久的SPI_DMA,也不知道用處大不大,總之弄完了,呵呵,也算比較了解SPI總線(xiàn)和DMA了,接下來(lái)想試試原子哥的新的SD卡函數(shù),原來(lái)AG嵌入式開(kāi)發(fā)板也是移植原子哥的舊版,也是有些卡初始化失敗,我還以為是我的卡有問(wèn)題呢?還有就是文件系統(tǒng),前陣子只弄了基本的讀寫(xiě),準(zhǔn)備把FATFS文件系統(tǒng)寫(xiě)得完善一點(diǎn)~

          最后,附上源代碼。(使用的不是MiniSTM32,所以大家在測(cè)試時(shí)只需要改一下LED驅(qū)動(dòng)。)
          第一個(gè)源代碼是基礎(chǔ)的,實(shí)現(xiàn)一個(gè)字節(jié)在SPI1&SPI2的傳送;
          第二個(gè)是函數(shù)化的代碼咯,發(fā)送隨意數(shù)量的8bit數(shù)據(jù),數(shù)量小于512;



          關(guān)鍵詞: STM32SPIDMA寄存

          評(píng)論


          技術(shù)專(zhuān)區(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); })();