一、前言
DMA會在不同的寄存器/ram/存儲設備之間建立通道,自動傳輸數據,以達到解放CPU的目的。
比如你想用DAC模塊去輸出一段特定的波形,就要讓CPU將預設的數值不斷寫入DAC的寄存器。這時CPU被DAC任務長期占用,系統處理其他任務和響應其他事件的能力被大幅降低。
在實際應用里,經常有一些繁重的讀寫操作。這些操作不需要經過計算,卻依然占用了大量的CPU資源,遇到這種情況就要考慮使用DMA了。
我開發板上的stm芯片上共有7個dma通道,它可以建立7個DMA連接。但是DMA控制器只有一個,所以同時只能有一個DMA連接被相應。
二、DMA的初始化
針對每一個DMA頻道,都要初始化它的控制寄存器,來看一下DMA的init結構體的原型:
/**
* @brief DMA Configuration Structure definition
*/
typedef struct
{
uint32_t Direction; /*!< Specifies if the data will be transferred from memory to peripheral,
from memory to memory or from peripheral to memory.
This parameter can be a value of @ref DMA_Data_transfer_direction */
uint32_t PeriphInc; /*!< Specifies whether the Peripheral address register should be incremented or not.
This parameter can be a value of @ref DMA_Peripheral_incremented_mode */
uint32_t MemInc; /*!< Specifies whether the memory address register should be incremented or not.
This parameter can be a value of @ref DMA_Memory_incremented_mode */
uint32_t PeriphDataAlignment; /*!< Specifies the Peripheral data width.
This parameter can be a value of @ref DMA_Peripheral_data_size */
uint32_t MemDataAlignment; /*!< Specifies the Memory data width.
This parameter can be a value of @ref DMA_Memory_data_size */
uint32_t Mode; /*!< Specifies the operation mode of the DMAy Channelx.
This parameter can be a value of @ref DMA_mode
@note The circular buffer mode cannot be used if the memory-to-memory
data transfer is configured on the selected Channel */
uint32_t Priority; /*!< Specifies the software priority for the DMAy Channelx.
This parameter can be a value of @ref DMA_Priority_level */
} DMA_InitTypeDef;
Direction的值表示通道類型,外設到ram、ram到外設、ram到ram。
PeriphInc和MemInc表示外設和ram地址要不要遞增。像上述的DAC例子,ram的地址一定是遞增的,而外設寄存器的地址則無需遞增。
PeriphDataAlignment和MemDataAlignment表示外設和ram的字節寬度,有一個字節,半字和全字。這將決定上面的增量模式里,一次讀取數據的大小。
Mode有兩種,普通和循環。普通模式下一次DMA請求處理完成后就不再傳輸數據。
Priority是DMA頻道的優先級,一共4個,如果優先級相同,頻道號小的通道率先被響應。
這些屬性被設置完畢后,在Init函數里會將它寫入控制寄存器。
/* Get the CR register value */
tmp = hdma->Instance->CCR;
/* Clear PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR bits */
tmp &= ((uint32_t)~(DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE | \
DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC | \
DMA_CCR_DIR));
/* Prepare the DMA Channel configuration */
tmp |= hdma->Init.Direction |
hdma->Init.PeriphInc | hdma->Init.MemInc |
hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment |
hdma->Init.Mode | hdma->Init.Priority;
/* Write to DMA Channel CR register */
hdma->Instance->CCR = tmp;
三、DMA通道的建立
在初始化完畢后,只需要將源地址、起始地址、傳輸總長寫入寄存器,再使能該頻道即可。
HAL_StatusTypeDef HAL_DMA_Start (DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
這個DMA_HandleTypeDef *hdma是用C實現面向對象設計的一個典型的例子。當我們創建一個DMA頻道時,必須要先建立一個DMA_HandleTypeDef類型的結構體變量,這個行為實際上就是創建了一個DMA類的實例。
typedef struct __DMA_HandleTypeDef
{
DMA_Channel_TypeDef *Instance; /*!< Register base address */
DMA_InitTypeDef Init; /*!< DMA communication parameters */
HAL_LockTypeDef Lock; /*!< DMA locking object */
HAL_DMA_StateTypeDef State; /*!< DMA transfer state */
void *Parent; /*!< Parent object state */
void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer complete callback */
void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA Half transfer complete callback */
void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer error callback */
__IO uint32_t ErrorCode; /*!< DMA Error code */
} DMA_HandleTypeDef;
這個結構體除了包含有init結構體、鎖、DMA寄存器指針、狀態變量、錯誤變量之外,還包含了一些callback函數的指針。它甚至有一個父類指針,只要將該指針指向一些adc、uart等外設的handle類,就等于完成了繼承。
除了有init和start函數外、HAL里還提供常規的DMA中斷處理函數,等待DMA傳輸,獲取DMA狀態的一些函數,結構上與前面的adc、flash等類似,就不做敘述了。
四、例子
來看一個串口用dma收發的例子。
首先是寫收發兩個頻道的控制寄存器:
/*##-3- Configure the DMA ##################################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = USARTx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/* Configure the DMA handler for reception process */
hdma_rx.Instance = USARTx_RX_DMA_CHANNEL;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the UART handle */
__HAL_LINKDMA(huart, hdmarx, hdma_rx);
然后掉用串口的DMA函數這個函數內部會調用DMA_START_IT()函數來進行DMA請求。
/*##-2- Start the transmission process #####################################*/
/* User start transmission data through "TxBuffer" buffer */
if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aTxBuffer, TXBUFFERSIZE) != HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
/*##-3- Put UART peripheral in reception process ###########################*/
/* Any data received will be stored in "RxBuffer" buffer : the number max of
data received is 10 */
if (HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
上面的HAL_LINKDMA宏是用來關聯兩個類的。
#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD_, __DMA_HANDLE_) \
do{ \
(__HANDLE__)->__PPP_DMA_FIELD_ = &(__DMA_HANDLE_); \
(__DMA_HANDLE_).Parent = (__HANDLE__); \
} while(0)
上一篇:S29GL128P norflash 讀寫擦除問題
下一篇:stm32.cube(十)——單HAL模塊的結構
推薦閱讀
史海拾趣
隨著公司業務的不斷發展,宇陽科技在產能擴張和全球布局方面也取得了顯著進展。公司在深圳、東莞、安徽等地建立了多個生產基地,引進了先進的生產線和檢測設備,確保了產品的高品質和穩定供應。同時,宇陽科技還積極拓展海外市場,與全球多家知名企業建立了長期穩定的合作關系。
ETA-USA一直注重技術創新和研發實力的提升。公司擁有一支高素質的研發團隊和先進的研發設施,不斷推出具有競爭力的新產品和解決方案。同時,ETA-USA還積極與高校、科研機構等合作,共同推動電子技術的創新和發展。
進入20世紀50年代,隨著太空技術的興起,福特汽車公司開始關注衛星通信的潛力。雖然福特并未直接參與衛星的發射或制造,但它通過資助相關科研機構和大學的研究項目,間接推動了衛星通信技術的發展。這些研究為后來的全球衛星通信系統提供了重要的理論基礎和技術支持。
在半導體領域,技術創新是企業持續發展的關鍵。谷峰公司深知這一點,不斷加大研發投入,致力于新技術的研發與應用。其中,SGT(Super Junction Technology)技術的成功研發,是谷峰發展歷程中的一個重要里程碑。SGT技術以其低內阻、高效率的特點,成為高頻應用的理想選擇,極大地提升了谷峰產品的市場競爭力。此外,谷峰還推出了多款高性能的碳化硅MOSFET產品,進一步鞏固了其在功率半導體領域的領先地位。
為了確保產品質量,FILTRONETICS始終將質量管理放在首位。公司建立了完善的質量管理體系,從原材料采購、生產制造到產品檢測、售后服務等各個環節都嚴格把關。同時,公司還引入了先進的檢測設備和技術手段,對產品進行全方位的質量檢測和控制。這些措施不僅確保了產品的穩定性和可靠性,也提升了公司的品牌形象和市場聲譽。
帝特在國內市場取得一定成績后,開始積極拓展國際市場。公司在中國區開設了廣州、深圳分公司,并在泰國和馬來西亞等地設立了分公司和專賣店。通過全球化的戰略布局,帝特的產品銷售網絡遍布東南亞、中東、非洲和美洲等國家和地區,公司的知名度和市場份額均得到了顯著提升。
我的是2410的芯片,現在要驅動TX18D16VM1CAA的LCD,可是現在已經把分頻值設到最低了還是會抖動,什么原因? 聽人說好像是加電壓什么的,我設置的是24位的TFT模式,怎么操作啊~ … 查看全部問答∨ |
wince 中 壓縮與非壓縮dll xip dll 與非xip dll 由于嵌入式系統的特定要求,ce必須比桌面系統更有效的使用和節省物理內存,采用有rom文件系統與ram文件系統。可以在rom中存放壓縮的與非壓縮的文件,前者中的可執行文件(dll,exe)必須解壓到ram才可使用,后者如果在支持線性訪問的介質(如nor fl ...… 查看全部問答∨ |
以下是我配置boa的過程: 配置boa: #cd /opt/EmbedSky/boa-0.94.13/src #./configure 說明:本來按照該配置腳本的提示是可以直接設置成交叉編譯的環境的,不過,經過實際試驗后發現 那樣是行不通的,無奈只能用這個笨方法了。 ...… 查看全部問答∨ |
我是應屆畢業生!從大三開始學習嵌入式!都是自己在摸索!參加過嵌入式的競賽!有項目經驗! 個人本身也寫過驅動!簡單的字符設備驅動,flash的驅動!自己也正在看Linux內核!(情景分析+源代碼) 精通C/C++語言!熟悉JAVA(做過項目拿過獎)再者, ...… 查看全部問答∨ |
本帖最后由 ddllxxrr 于 2016-1-7 17:13 編輯 本來打算在論壇求一塊TI C2000DSP學習一下,后來 壇友站內信聯系到我,愿意把C2000的板子贈送給我學習,真是感激不盡。 后來QQ一聊才知道原來還是我上屆的學長呀,世界真 ...… 查看全部問答∨ |
Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem &nb ...… 查看全部問答∨ |
【設計工具】《Xilinx 可編程邏輯器件的高級應用與設計技巧》 Xilinx公司是全球最大的可編程邏輯器件制造商,也是FPGA器件的發明者,特別是在通信技術領域,Xilinx不僅是一個提供通信器件的供應商,還積極地參與通信標準的制定,提供系統集成和系統解決方案等。為了滿足和適應市場的需要,該公司不斷地推出高性能 ...… 查看全部問答∨ |
各位大俠,這是一個電機驅動電路,RL是負載電機,我用個200K的電阻代替。PWM信號是單片機輸過來的, 頻率是10K,現在我調節PWM的占空比,負載端的電壓穩定在12V。 如果我把三個電容:C1、C2、EC1都去掉,則負載端的電壓是一個隨PWM信號變化的方 ...… 查看全部問答∨ |
設計圖如下, 由于硬件已經實現,無法更改,還望大神多多幫忙。 源代碼如下 //--------------------------------------- // AD0809 by maomaochong // Date: 2011/8/31 // Time: 15:54 // Function: ADDA-ADDC connect to P2.0-P2.2 to cho ...… 查看全部問答∨ |
用的是微雪的STM32F407z的開發板,攝像頭是OV9655,用隨板的示例程序測試只顯示已初始化成功,LCD上并無成像,是怎么回事啊?攝像頭,板子和lcd屏都沒問題! 我是新手,解答請詳細點,在此拜謝各位大神! ps:附主程序 #include "stm32f4xx.h ...… 查看全部問答∨ |