日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《STM32从零开始学习历程》——DMA直接存储区访问理论知识

發布時間:2024/1/1 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《STM32从零开始学习历程》——DMA直接存储区访问理论知识 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

《STM32從零開始學習歷程》@EnzoReventon

DMA—直接存儲區訪問理論知識

本文主要介紹STM32F4 DMA直接存儲區的理論知識部分,本文主要參考手冊為:
[野火EmbedFire]《STM32庫開發實戰指南——基于野火霸天虎開發板》
[正點原子]STM32F4開發指南-庫函數版本_V1.2
[ST]《STM32F4xx中文參考手冊》
在學習野火教程第22章的基礎上進行理解、解讀與拓展,爭取以一種比較好理解的簡述方式向大家介紹這一內容。

1. DMA簡介

DMA(Direct Memory Access, 直接存儲區訪問)是一種獨立于CPU的控制器。它的主要功能是實現數據在“外設寄存器與存儲器之間”、“存儲器與存儲器之間獨立于CPU的高速傳輸。

在這里,外設一般指外設的數據寄存器(如ADC,SPI,I2C,DCMI等外設的數據寄存器);存儲器一般是指片內SRAM、外部存儲器、片內FLASH等。

外設寄存器到存儲器傳輸:就是把外設數據寄存器內容轉移到指定的內存空間中。
存儲器到外設寄存器傳輸:就是把特定存儲區域的內容轉移到外設寄存器中。
存儲器到存儲器傳輸:就是把一個指定存儲區內容拷貝到另一個指定的存儲區中。
注意: DMA1 僅支持① ② ,不支持③。DMA2支持① ② ③。

=============================================================================================

解釋一下為什么DMA1不支持存儲器到存儲器的傳輸:


如上圖所示,DMA2控制器ANB接口都與中間的總線矩陣相連接了,存儲器RAM與總線矩陣相連接,因此DMA2可以實現存儲器與存儲器之間的數據傳輸。
而DMA1,其中一個AHB接口沒有與總線矩陣相連接,固然也就無法實現存儲器與存儲器之間的數據傳輸了。
作為一個固定的知識點記住就好。

2. DMA的主要特點(針對STM32F4)

  • DMA傳輸速率非常高效(原因為2)
  • 實現數據傳輸無需CPU參與,DMA控制器是獨立于CPU的
  • 3. 功能框圖分析


    STM32F4其中一個的DMA控制器框圖如上圖所示,下面我們來詳細講解一下這個框圖。(STM32一共有兩個DMA控制器)

    =============================================================================================

  • 首先我們來看一下DMA框圖的最左邊。如下圖所示:
  • 在上圖中,左邊的叫做通道,右邊的叫做

    好了,那么問題來了,什么是“通道”?什么是“”?

    首先,“”是數據傳輸的一條鏈路,“通道”:emmm不知道怎么解釋,只可意會不可言傳,不同的通道對印著不同的DMA請求。

    緊接著,從上圖看到,對于一個DMA控制器共有8路“”,每一“”,又有8個“通道”!也就是說,對于一個DMA控制共有8 x 8 = 64 路通道可以用來獨立的傳輸數據。

    好了又有問題來了,那么這么多通道怎么用?是不是可以隨便用?
    答案是否定的!
    每一個通道有著不同的傳輸請求映射!如下表所示:

    DMA1:

    外設請求數據流0數據流1數據流2數據流3數據流4數據流5數據流6數據流7
    通道 0SPI3_RXSPI3_RXSPI2_RXSPI2_TXSPI3_TXSPI3_TX
    通道 1I2C1_RXTIM7_UPTIM7_UPI2C1_RXI2C1_TXI2C1_TX
    通道 2TIM4_CH1I2S3_EXT_RXTIM4_CH2CH2 I2S2_EXT_TXI2S3_EXT_TXTIM4_UPTIM4_CH3
    通道 3I2S3_EXT_RXTIM2_UP TIM2_CH3I2C3_RXI2S2_EXT_RXI2C3_TXTIM2_CH1TIM2_CH2 TIM2_CH4TIM2_UP TIM2_CH4
    通道 4UART5_RXUSART3_RXUART4_RXUSART3_TXUART4_TXUSART2_RXUSART2_TXUART5_TX
    通道 5UART8_TXUART7_TXTIM3_CH4 TIM3_UPUART7_RXTIM3_CH1 TIM3_TRIGTIM3_CH2UART8_RXTIM3_CH3
    通道 6TIM5_CH3 TIM5_UPTIM5_CH4 TIM5_TRIGTIM5_CH1TIM5_CH4 TIM5_TRIGTIM5_CH2TIM5_UP
    通道 7TIM6_UPI2C2_RXI2C2_RXUSART3_TXDAC1DAC2I2C2_TX

    DMA2:

    外設請求數據流0數據流1數據流2數據流3數據流4數據流5數據流6數據流7
    通道 0ADC1TIM8_CH1 TIM8_CH2 TIM8_CH3ADC1TIM1_CH1 TIM1_CH2 TIM1_CH3
    通道 1DCMIADC2ADC2SPI6_TXSPI6_RXDCMI
    通道 2ADC3ADC3SPI5_RXSPI5_TXCRYP_OUTCRYP_INHASH_IN
    通道 3SPI1_RXSPI1_RXSPI1_TXSPI1_TX
    通道 4SPI4_RXSPI4_TXUSART1_RXSDIOSART1_RXSDIOUSART1_TX
    通道 5USART6_RXUSART6_RXSPI4_RXSPI4_TXUSART6_TXUSART6_TX
    通道 6TIM1_TRIGTIM1_CH1TIM1_CH2TIM1_CH1TIM1_CH4 TIM1_TRIG TIM1_COMTIM1_UPTIM1_CH3
    通道 7TIM8_UPTIM8_CH1TIM8_CH2TIM8_CH3SPI5_RXSPI5_TXTIM8_CH4 TIM8_TRIG TIM8_COM

    每個外設請求都會占用一個數據流通道,相同外設請求可以占用不同的數據流通道。

    例如:DMA1的數據流0,我選擇使用通道2 I2C1_RX,那么其他7路通道就不可以使用了。
    再例如:DMA1的數據流2,通道1,TIM7_UP與DMA1的數據流4,通道1,TIM7_UP是可以同時使用的。也就是說只要不是同一個數據流就可以了。

    好了,通道 和 流 的基本信息就已經介紹完了,總結一下:

    ① STM32F4共有2個DMA控制器
    ② DMA1不支持存儲器到存儲器傳輸
    ③ 每一個DMA有8路數據流
    ④ 每一路流有8個通道
    ⑤ 每一個通道有特定的功能映射,需要查閱上文的表格進行選擇使用
    ⑥ 每一路流的只能有一個通道使用,一路流有一個以上通道使用是不允許的
    ⑦ 相同功能不同流的通道可以同時使用

    =============================================================================================

  • 這個“仲裁器”:
  • 顧名思義,仲裁器是用來仲裁、評判的,一個DMA控制器有8個數據流,如果在某一時刻,我們使用同一個DMA控制器中的多個數據流進行傳輸數據,那么必然會導致有多個數據流,如果沒有仲裁器,就像是十字路口沒有紅綠燈,會造成擁堵甚至事故,對于數據也是如此,因此需要一個仲裁器來設定數據流的優先傳輸的權力。

    通過仲裁器來設定流的優先級時分為兩個階段,第一階段為軟件階段,第二階段為硬件階段。
    軟件階段: 用戶可以通過配置優先級寄存器,將數據流優先級設定為:非常高,高,中和低四個級別。
    硬件階段: 如果兩個或以上數據流的優先級一樣,則仲裁器優先級設定轉為硬件層面,他們的優先級取決于數據流的編號,編號越低則優先級越高,例如,在軟件層面優先級相同的情況下,數據流1的優先級高于數據流5的優先級。

    =============================================================================================

  • FIFO:
  • 我們要重點的來講一下什么是FIFO,First In First Out。

    首先,FIFO叫做先進先出存儲緩沖區,它介于源與目標之間,是一個數據的中轉站。
    每一個數據流都有4字大小的FIFO。1字 = 4字節 = 32位,4字 = 16字節。

    對于這個緩沖區,存在有兩種數據傳輸模式:第一種為直接模式,第二種為FIFO模式。
    模式的選擇由 DMA_SxFCR寄存器的DMDIS位控制,0為使能直接模式,1為禁止直接模式、開啟FIFO模式。

    直接模式: 數據經過FIFO,不在FIFO中停留,直接將數據傳送到目標地址中。
    FIFO模式: 數據經過FIFO,在FIFO中停留,根據設置的閾值,等到數據量達到了設定的閾值然后再發送到目標地址中。閾值可以設定為1/4,1/2,3/4,1。例如,閾值設定為1/4時,FIFO中的數據量達到16*(1/4)= 4 字節時將數據打包發送到目標地址中。

    對于在FIFO中的數據,是以什么方式進行傳輸的呢?例如,閾值設定為1/4時,FIFO中也存滿了4字節的數據,這4字節的數據怎么打包發送呢?它是4字節全部打包發送還是4字節分四次打包發送呢?這就需要另外一個寄存器進行選擇配置了:DMA_SxCR中的MBURST(存儲器突發傳輸配置)以及PBURST(外設突發傳輸配置),突發模式!

    下一章節將詳細的講解何為突發模式!

    4. DMA數據配置

    1. 突發&節拍的配置


    位 24:23 MBURST:存儲器突發傳輸配置 (Memory burst transfer configuration)
    這些位將由軟件置 1 和清零。
    00:單次傳輸
    01:INCR4(4 個節拍的增量突發傳輸)
    10:INCR8(8 個節拍的增量突發傳輸)
    11:INCR16(16 個節拍的增量突發傳輸)
    這些位受到保護,只有 EN 為“0”時才可以寫入 在直接模式中,當位EN=“1”時,這些位由硬件強制置為 0x0。
    位 22:21 PBURST[1:0]:外設突發傳輸配置 (Peripheral burst transfer configuration)
    這些位將由軟件置 1 和清零。
    00:單次傳輸
    01:INCR4(4 個節拍的增量突發傳輸)
    10:INCR8(8 個節拍的增量突發傳輸)
    11:INCR16(16 個節拍的增量突發傳輸)
    這些位受到保護,只有 EN為“0”時才可以寫入 在直接模式下,這些位由硬件強制置為 0x0。

    這里又來了一個“節拍”的概念,我們來詳細的講一下這是什么。

    MSIZEFIFO級別MBURST=INCR4MBURST=INCR8MBURST=INCR16
    字節1/44個節拍1次突發
    字節1/24個節拍2次突發8個節拍1次突發
    字節3/44個節拍3次突發
    字節14個節拍4次突發8個節拍2次突發16個節拍1次突發
    半字1/4
    半字1/24個節拍1次突發
    半字3/4
    半字14個節拍2次突發8個節拍1次突發
    1/4
    1/2
    3/4
    14個節拍1次突發

    首先,FIFO大小為4個字,FIFO閾值 = FIFO級別 x FIFO大小。
    例如:
    FIFO級別為1/4時,FIFO閾值大小為 4 x(1/4) = 1字 = 4字節。
    FIFO級別為3/4時,FIFO閾值大小為 4 x(3/4) = 3字 = 12字節。

    =============================================================================================
    當目標地址存儲單元為字節時:
    FIFO級別為1/4時:
    當FIFO中存滿4 x(1/4) = 1字 = 4字節時,完成1次突發,4字節數據一次性打包發送給目標地址,每次發送4個字節。

    FIFO級別為1/2時:
    當FIFO中存滿4 x(1/2) = 2字 = 8字節時,完成2次突發,8字節數據分兩次發送給目標地址,每次發送4個字節;
    或者8字節數據一次性發送給目標地址,每次發送8個字節。

    FIFO級別為3/4時:
    當FIFO中存滿4 x(3/4) = 3字 = 12字節時,完成3次突發,12字節數據分三次發送給目標地址,每次發送4個字節。

    FIFO級別為1時:
    當FIFO中存滿4 x 1 = 4字 = 16字節時,可以以4次突發,16字節數據分四次發送給目標地址,每次發送4個字節;
    可以以2次突發,16字節數據分兩次發送給目標地址,每次發送8個字節;
    也可以以1次突發,16字節數據一次性傳輸給目標地址,每次發送16個字節。

    =============================================================================================

    為什么FIFO級別為1/4時不能以8個節拍進行發送呢?

    因為,FIFO的級別為1/4,其閾值為1個字,4個字節,此時FIFO存滿也就4個字節的數據,固然無法實現8個節拍進行發送。

    為什么MSIZE為半字時,無法實現FIFO的級別為1/4以4個字節發送?
    因為,FIFO的級別為1/4,其閾值為1個字,4個字節;如果是4個節拍發送的話,就是4個半字=8個字節發送,此時FIFO最大也就只有4個字節的數據,也便無法實現發送。

    為什么MSIZE為字時,無法實現FIFO的級別為3/4以3個字節發送?
    因為,FIFO的級別為3/4,其閾值為3個字,12個字節;如果實現4個節拍發送的畫,就是4個字=16個字節發送,此時FIFO最大也就12個字節的數據,無法實現發送。

    下面再來解釋下為什么為什么MSIZE為半字時,可以實現FIFO的級別為1/2以8個字節發送?
    因為,FIFO的級別為1/2,其閾值為2個字,8個字節;以4個節拍也就是4個半字=8個字節發送,正好等于FIFO閾值的數據大小(8個字節),所以可以成功發送。

    以此類推!

    =============================================================================================

    PS: 在這里為了更好的理解FIFO閾值配置表格,可以將節拍理解為MSIZE,例如:MSIZE為字節時,FIFO級別為1/4(1個字,4個字節),4個節拍1次突發可以理解為4個字節一次突發;MSIZE為半字時,8個節拍一次突發可以理解為8個半字(4個字,16個字節),FIFO級別為1時(4個字,16個字節),可以實現一次突發。
    也就是說:
    節拍數(MSIZE數)x 突發數 = FIFO級別 x FIFO大小 (FIFO大小固定為4字)
    例如:MSIZE = 半字;FIFO級別為 = 1/2;MBURST = 4個節拍1次突發
    節拍數(MISIZE數)= 半字
    突發數 = 4節拍 x 1次突發 = 4 半字 = 2 字 = 8字節
    那么:節拍數(MSIZE數)x 突發數 = 8 字節
    FIFO閾值 = 1/2 x 4 字 = 2 字 = 8字節
    由此可見 FIFO閾值 = 節拍數(MSIZE數)x 突發數。

    2. 循環模式
    循環模式相對應于一次模式。一次模式就是傳輸一次就停止傳輸,下一次傳輸需要手動控制,而循環模式在傳輸一次后會自動按照相同配置重新傳輸,周而復始直至被控制停止或傳輸發生錯誤。
    可以通過DMA_SxCR 寄存器的CIRC 位可以使能循環模式。

    3. 雙緩沖模式
    設置DMA_SxCR 寄存器的DBM 位為1 可啟動雙緩沖傳輸模式,并自動激活循環模式。
    雙緩沖不應用與存儲器到存儲器的傳輸。雙緩沖模式下,兩個存儲器地址指針都有效,即DMA_SxM1AR寄存器將被激活使用。開始傳輸使用DMA_SxM0AR 寄存器的地址指針所對應的存儲區,當這個存儲區數據傳輸完DMA 控制器會自動切換至DMA_SxM1AR 寄存器的地址指針所對應的另一塊存儲區,如果這一塊也傳輸完成就再切換至DMA_SxM0AR 寄存器的地址指針所對應的存儲區,這樣循環調用。

    4. DMA中斷

    每個DMA 數據流可以在發送以下事件時產生中斷:

  • 達到半傳輸:DMA 數據傳輸達到一半時HTIF 標志位被置1,如果使能HTIE 中斷控制位將產生達到半傳輸中斷;
  • 傳輸完成:DMA 數據傳輸完成時TCIF 標志位被置1,如果使能TCIE 中斷控制位將產生傳輸完成中斷;
  • 傳輸錯誤:DMA 訪問總線發生錯誤或者在雙緩沖模式下試圖訪問“受限”存儲器地址寄存器時TEIF 標志位被置1,如果使能TEIE 中斷控制位將產生傳輸錯誤中斷;
  • FIFO 錯誤:發生FIFO 下溢或者上溢時FEIF 標志位被置1,如果使能FEIE 中斷控制位將產生FIFO 錯誤中斷;
  • 直接模式錯誤:在外設到存儲器的直接模式下,因為存儲器總線沒得到授權,使得先前數據沒有完成被傳輸到存儲器空間上,此時DMEIF 標志位被置1,如果使能DMEIE 中斷控制位將產生直接模式錯誤中斷。
  • 5. 初始化結構體庫函數

    typedef struct {uint32_t DMA_Channel; //通道選擇uint32_t DMA_PeripheralBaseAddr; //外設地址uint32_t DMA_Memory0BaseAddr; //存儲器0 地址uint32_t DMA_DIR; //傳輸方向uint32_t DMA_BufferSize; //數據數目uint32_t DMA_PeripheralInc; //外設遞增uint32_t DMA_MemoryInc; //存儲器遞增uint32_t DMA_PeripheralDataSize; //外設數據寬度uint32_t DMA_MemoryDataSize; //存儲器數據寬度uint32_t DMA_Mode; //模式選擇uint32_t DMA_Priority; //優先級uint32_t DMA_FIFOMode; //FIFO 模式uint32_t DMA_FIFOThreshold; //FIFO 閾值uint32_t DMA_MemoryBurst; //存儲器突發傳輸uint32_t DMA_PeripheralBurst; //外設突發傳輸}

    1) DMA_Channel:
    DMA 請求通道選擇,可選通道0 至通道7,每個外設對應固定的通道,具體設置值需要查表DMA1 各個通道的請求映像和表DMA2 各個通道的請求映像。
    2) DMA_PeripheralBaseAddr:
    外設地址,設定DMA_SxPAR 寄存器的值;一般設置為外設的數據寄存器地址,如果是存儲器到存儲器模式則設置為其中一個存儲區地址。
    ADC3 的數據寄存器ADC_DR 地址為((uint32_t)ADC3+0x4C)。
    3) DMA_Memory0BaseAddr:
    存儲器0 地址,設定DMA_SxM0AR 寄存器值;一般設置為我們自義存儲區的首地址。我們程序先自定義一個16 位無符號整形數組ADC_ConvertedValue[4]用來存放每個通道的ADC 值, 所以把數組首地址(直接使用數組名即可) 賦值給DMA_Memory0BaseAddr。
    4) DMA_DIR:
    傳輸方向選擇,可選外設到存儲器、存儲器到外設以及存儲器到存儲器。它設定DMA_SxCR 寄存器的DIR[1:0] 位的值。ADC 采集顯然使用外設到存儲器模式。
    5) DMA_BufferSize:
    設定待傳輸數據數目,初始化設定DMA_SxNDTR 寄存器的值。這里ADC是采集4 個通道數據,所以待傳輸數目也就是4。
    6) DMA_PeripheralInc:
    如果配置為DMA_PeripheralInc_Enable,使能外設地址自動遞增功能,它設定DMA_SxCR 寄存器的PINC 位的值;一般外設都是只有一個數據寄存器,所以一般不會使能該位。ADC3 的數據寄存器地址是固定并且只有一個所以不使能外設地址遞增。
    7) DMA_MemoryInc:
    如果配置為DMA_MemoryInc_Enable,使能存儲器地址自動遞增功能,它設定DMA_SxCR 寄存器的MINC 位的值;我們自定義的存儲區一般都是存放多個數據的,所以使能存儲器地址自動遞增功能。我們之前已經定義了一個包含4 個元素的數字用來存放數據,使能存儲區地址遞增功能,自動把每個通道數據存放到對應數組元素內。
    8) DMA_PeripheralDataSize:
    外設數據寬度,可選字節(8 位)、半字(16 位) 和字(32 位),它設定DMA_SxCR 寄存器的PSIZE[1:0] 位的值。ADC 數據寄存器只有低16 位數據有效,使用半字數據寬度。
    9) DMA_MemoryDataSize:
    存儲器數據寬度,可選字節(8 位)、半字(16 位) 和字(32 位),它設定DMA_SxCR 寄存器的MSIZE[1:0] 位的值。保存ADC 轉換數據也要使用半字數據寬度,這跟我們定義的數組是相對應的。
    10) DMA_Mode:
    DMA 傳輸模式選擇,可選一次傳輸或者循環傳輸,它設定DMA_SxCR 寄存器的CIRC 位的值。我們希望ADC 采集是持續循環進行的,所以使用循環傳輸模式。
    11) DMA_Priority:
    軟件設置數據流的優先級,有4 個可選優先級分別為非常高、高、中和低,它設定DMA_SxCR 寄存器的PL[1:0] 位的值。DMA 優先級只有在多個DMA 數據流同時使用時才有意義,這里我們設置為非常高優先級就可以了。
    12) DMA_FIFOMode:
    FIFO 模式使能,如果設置為DMA_FIFOMode_Enable 表示使能FIFO 模式功能;它設定DMA_SxFCR 寄存器的DMDIS 位。ADC 采集傳輸使用直接傳輸模式即可,不需要使用FIFO 模式。
    13) DMA_FIFOThreshold:
    FIFO 閾值選擇,可選4 種狀態分別為FIFO 容量的1/4、1/2、3/4 和滿;它設定DMA_SxFCR 寄存器的FTH[1:0] 位;DMA_FIFOMode 設置為DMA_FIFOMode_Disable,那DMA_FIFOThreshold 值無效。ADC 采集傳輸不使用FIFO 模式,設置改值無效。
    14) DMA_MemoryBurst:
    存儲器突發模式選擇,可選單次模式、4 節拍的增量突發模式、8 節拍的增量突發模式或16 節拍的增量突發模式,它設定DMA_SxCR 寄存器的MBURST[1:0] 位的值。ADC 采集傳輸是直接模式,要求使用單次模式。
    15) DMA_PeripheralBurst:
    外設突發模式選擇,可選單次模式、4 節拍的增量突發模式、8 節拍的增量突發模式或16 節拍的增量突發模式,它設定DMA_SxCR 寄存器的PBURST[1:0] 位的值。
    ADC 采集傳輸是直接模式,要求使用單次模式。

    總結

    以上是生活随笔為你收集整理的《STM32从零开始学习历程》——DMA直接存储区访问理论知识的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。