0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

串口DMA其實(shí)一點(diǎn)兒都不難

朱老師物聯(lián)網(wǎng)大講堂 ? 2024-04-29 08:10 ? 次閱讀

DMA一種在嵌入式實(shí)時(shí)任務(wù)處理中常用的功能。而UART發(fā)送數(shù)據(jù)包,使用DMA方式能大量減輕CPU處理的時(shí)間,使其CPU資源不被大量浪費(fèi),尤其在UART收發(fā)大量數(shù)據(jù)包(如高頻率收發(fā)指令)時(shí)具有明顯優(yōu)勢(shì)。

一、簡(jiǎn)述DMA

ecb153ba-05bc-11ef-9118-92fbcf53809c.pngDMA:Direct Memory Access,直接內(nèi)存存取/訪問。簡(jiǎn)單來說就是內(nèi)存RAM直接和其他設(shè)備(外設(shè))進(jìn)行數(shù)據(jù)交互,而不需要CPU參與的一種控制器。DMA它允許不同速度的硬件裝置來溝通,而不需要依賴于 CPU 的大量中斷負(fù)載。否則,CPU 需要從來源把每一片段的數(shù)據(jù)復(fù)制到緩存器,然后把它們?cè)俅螌懟氐叫碌牡胤?。在這個(gè)過程中,CPU不能做其他的工作。

二、DMA的優(yōu)點(diǎn)

ecb153ba-05bc-11ef-9118-92fbcf53809c.pngDMA在系統(tǒng)中的角色好比一個(gè)公司的員工,CPU好比是公司的老板?;氐経ART發(fā)送數(shù)據(jù),同樣的道理,CPU只需要簡(jiǎn)單的操作(“安排任務(wù)”),就可把一串?dāng)?shù)據(jù)包丟給DMA直接發(fā)送,最后發(fā)送完成,收到一個(gè)發(fā)送完成中斷,通知CPU發(fā)送完成即可。說到這里相信大部分人都明白了,老板可以親自開車或者坐飛機(jī)送快遞,完成這件事情,但會(huì)耽擱老板很多時(shí)間。同樣,如果我們使用UART自己發(fā)送,CPU就會(huì)不停仲裁發(fā)送結(jié)果,占據(jù)CPU大量資源。在RTOS中,特別是有大量任務(wù)需要處理的時(shí)候,UART使用DMA發(fā)送就會(huì)帶來很大方便。使用裸機(jī)運(yùn)行的相同,尤為突出。

三、實(shí)例代碼:DMA發(fā)送配置

ecb153ba-05bc-11ef-9118-92fbcf53809c.png本文使用STM32F4 MCU、標(biāo)準(zhǔn)外設(shè)庫為例給大家簡(jiǎn)單講述一下配置。

01

USART配置

USART(COM)宏定義:

/* COMM通信 */#define COMM_COM USART2#define COMM_COM_CLK RCC_APB1Periph_USART2#define COMM_COM_TX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART TX#define COMM_COM_TX_PIN GPIO_Pin_5#define COMM_COM_TX_GPIO_PORT GPIOD#define COMM_COM_TX_SOURCE GPIO_PinSource5#define COMM_COM_TX_AF GPIO_AF_USART2#define COMM_COM_RX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART RX#define COMM_COM_RX_PIN GPIO_Pin_6#define COMM_COM_RX_GPIO_PORT GPIOD#define COMM_COM_RX_SOURCE GPIO_PinSource6#define COMM_COM_RX_AF GPIO_AF_USART2#define COMM_COM_IRQn USART2_IRQn#define COMM_COM_Priority 9 //優(yōu)先級(jí)#define COMM_COM_BaudRate 115200 //波特率#define COMM_COM_IRQHandler USART2_IRQHandler //中斷函數(shù)接口(見stm32f4xx_it.c)

USART配置:

/************************************************函數(shù)名稱 :USART_COMM_Configuration功 能 :通信串口配置參 數(shù) :無返 回 值 :無作 者 :strongerHuang*************************************************/void USART_COMM_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* 時(shí)鐘配置 */ RCC_AHB1PeriphClockCmd(COMM_COM_TX_GPIO_CLK | COMM_COM_RX_GPIO_CLK, ENABLE); if((USART1 == COMM_COM) || (USART6 == COMM_COM)) RCC_APB2PeriphClockCmd(COMM_COM_CLK, ENABLE); else RCC_APB1PeriphClockCmd(COMM_COM_CLK, ENABLE);
/* 復(fù)用配置 */ GPIO_PinAFConfig(COMM_COM_TX_GPIO_PORT, COMM_COM_TX_SOURCE, COMM_COM_TX_AF); GPIO_PinAFConfig(COMM_COM_RX_GPIO_PORT, COMM_COM_RX_SOURCE, COMM_COM_RX_AF);
/* 引腳配置 */ GPIO_InitStructure.GPIO_Pin = COMM_COM_TX_PIN; //USART Tx GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復(fù)用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(COMM_COM_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = COMM_COM_RX_PIN; //USART Rx GPIO_Init(COMM_COM_RX_GPIO_PORT, &GPIO_InitStructure);
/* NVIC配置 */ NVIC_InitStructure.NVIC_IRQChannel = COMM_COM_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_COM_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* USART配置 */ USART_InitStructure.USART_BaudRate = COMM_COM_BaudRate; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //傳輸位數(shù) USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位 USART_InitStructure.USART_Parity = USART_Parity_No ; //校驗(yàn)位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)功能 USART_Init(COMM_COM, &USART_InitStructure);
USART_ClearFlag(COMM_COM, USART_FLAG_RXNE | USART_FLAG_TC); USART_ITConfig(COMM_COM, USART_IT_RXNE, ENABLE); //接收中斷
USART_DMACmd(COMM_COM, USART_DMAReq_Tx, ENABLE); //使能DMA
USART_Cmd(COMM_COM, ENABLE); //使能USART}


02

DMA配置

DMA宏定義:

/* COMM_DMA */#define COMM_DR_ADDRESS ((uint32_t)USART2 + 0x04)#define COMM_DMA DMA1#define COMM_DMA_CLK RCC_AHB1Periph_DMA1#define COMM_TX_DMA_CHANNEL DMA_Channel_4#define COMM_TX_DMA_STREAM DMA1_Stream6#define COMM_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF6#define COMM_TX_DMA_IRQn DMA1_Stream6_IRQn#define COMM_TX_DMA_Priority 8 //優(yōu)先級(jí)#define COMM_TX_DMA_IRQHandler DMA1_Stream6_IRQHandler //中斷函數(shù)接口(見stm32f4xx_it.c)#define COMM_TX_DMA_IT_TCIF DMA_IT_TCIF6

DMA配置:

/************************************************函數(shù)名稱 :USART_COMM_DMA_Configuration功 能 :通信串口的DMA配置參 數(shù) :無返 回 值 :無作 者 :strongerHuang*************************************************/void USART_COMM_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* 使能時(shí)鐘 */ RCC_AHB1PeriphClockCmd(COMM_DMA_CLK, ENABLE);
/* NVIC配置 */ NVIC_InitStructure.NVIC_IRQChannel = COMM_TX_DMA_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_TX_DMA_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
/* DMA配置 */ DMA_DeInit(COMM_TX_DMA_STREAM); DMA_InitStructure.DMA_Channel = COMM_TX_DMA_CHANNEL; //DMA通道 DMA_InitStructure.DMA_PeripheralBaseAddr = COMM_DR_ADDRESS; //外設(shè)地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; //內(nèi)存地址(待傳入參數(shù)) DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //傳輸方向 DMA_InitStructure.DMA_BufferSize = 0; //傳輸長(zhǎng)度(待傳入?yún)?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; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //數(shù)據(jù)寬度 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //循環(huán)模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //優(yōu)先級(jí) DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(COMM_TX_DMA_STREAM, &DMA_InitStructure);
DMA_ClearFlag(COMM_TX_DMA_STREAM, COMM_TX_DMA_FLAG_TCIF); DMA_ITConfig(COMM_TX_DMA_STREAM, DMA_IT_TC, ENABLE); //使能DMA傳輸完成中斷
DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //初始化禁止}

03

DMA發(fā)送UART數(shù)據(jù)包

DMA發(fā)送函數(shù):

/************************************************函數(shù)名稱 :COMM_SendBufByDMA功 能 :通信串口通過DMA發(fā)送數(shù)據(jù)參 數(shù) :Buf ------ 數(shù)據(jù)(地址) Length --- 數(shù)據(jù)長(zhǎng)度(字節(jié))返 回 值 :無作 者 :strongerHuang*************************************************/void COMM_SendBufByDMA(uint8_t *Buf, uint16_t Length){ DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //關(guān)閉DMA //內(nèi)存地址 DMA_MemoryTargetConfig(COMM_TX_DMA_STREAM, (uint32_t)Buf, DMA_Memory_0); DMA_SetCurrDataCounter(COMM_TX_DMA_STREAM, Length); //設(shè)置DMA傳輸長(zhǎng)度 DMA_Cmd(COMM_TX_DMA_STREAM, ENABLE); //使能DMA}

細(xì)心的朋友會(huì)發(fā)現(xiàn),這個(gè)發(fā)送函數(shù)其實(shí)很簡(jiǎn)單,當(dāng)然,這里是使用STM32F4芯片,其他芯片也差不多,原理類似。HAL庫同樣可以完成。
關(guān)于DMA發(fā)送完成中斷,可根據(jù)實(shí)際情況,如果使用RTOS,一般發(fā)送數(shù)據(jù)是一個(gè)任務(wù),這個(gè)任務(wù)會(huì)OS等待(檢測(cè))發(fā)送完成信號(hào)(即DMA發(fā)送完成中斷)。

本文轉(zhuǎn)載自公眾號(hào)|strongerHuang

如有侵權(quán) |聯(lián)系刪除

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1557

    瀏覽量

    76711
  • dma
    dma
    +關(guān)注

    關(guān)注

    3

    文章

    565

    瀏覽量

    100733
  • 數(shù)據(jù)包
    +關(guān)注

    關(guān)注

    0

    文章

    265

    瀏覽量

    24424
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    ZYNQ基礎(chǔ)---AXI DMA使用

    前言 在ZYNQ中進(jìn)行PL-PS數(shù)據(jù)交互的時(shí)候,經(jīng)常會(huì)使用到DMA,其實(shí)在前面的ZYNQ學(xué)習(xí)當(dāng)中,也有學(xué)習(xí)過DMA的使用,那就是通過使用自定義的IP,完成HP接口向內(nèi)存寫入和讀取數(shù)據(jù)的方式。同樣
    的頭像 發(fā)表于 01-06 11:13 ?207次閱讀
    ZYNQ基礎(chǔ)---AXI <b class='flag-5'>DMA</b>使用

    救助,定義個(gè)大一點(diǎn)的數(shù)組導(dǎo)致編譯不通過問題。

    本例使用 CSU-IDE V6.0.6 ,單片機(jī)為CSU38F20,發(fā)現(xiàn)在改大數(shù)組的時(shí)候編譯不通過,請(qǐng)各位大神指教。具體問題描述如下: 正常情況: 串口收發(fā)緩沖區(qū)定義小一點(diǎn)沒有問題,如下
    發(fā)表于 01-01 15:43

    光纖外面的皮破了一點(diǎn)有關(guān)系嗎

    光纖外面的皮破了一點(diǎn),在般情況下,只要光纖的纖芯沒有受到損傷,對(duì)通信通常是沒有影響的。光纖的外皮主要起保護(hù)作用,能夠防止光纖受到機(jī)械損傷、腐蝕、潮濕等外部環(huán)境的損害。如果外皮破損,但纖芯仍然保持
    的頭像 發(fā)表于 11-25 10:04 ?524次閱讀

    求推薦帶寬高的單電源儀表放大器?

    有沒有帶寬高一點(diǎn)兒的單電源儀表放大器
    發(fā)表于 09-23 06:56

    大功率貼片電感的電感值偏大一點(diǎn)可以用嗎

    電子發(fā)燒友網(wǎng)站提供《大功率貼片電感的電感值偏大一點(diǎn)可以用嗎.docx》資料免費(fèi)下載
    發(fā)表于 09-20 11:33 ?0次下載

    VCA810可變?cè)鲆娣糯笃靼碢DF的原理圖來設(shè)計(jì),怎么效果一點(diǎn)都不好呢?

    VCA810可變?cè)鲆娣糯笃?,按著PDF的原理圖來設(shè)計(jì),怎么效果一點(diǎn)都不好呢,跟理論值差好遠(yuǎn)啊,增益變化根本不成線性,調(diào)了好久了,實(shí)在沒有辦法!
    發(fā)表于 09-14 06:18

    電感碎了一點(diǎn)點(diǎn)能正常用嗎

    電子發(fā)燒友網(wǎng)站提供《電感碎了一點(diǎn)點(diǎn)能正常用嗎.docx》資料免費(fèi)下載
    發(fā)表于 09-04 11:32 ?0次下載

    HMC470控制電平改變,但是HMC470的衰減倍數(shù)還是一點(diǎn)都不變,為什么?

    HMC470控制電平改變,但是芯片的衰減倍數(shù)還是一點(diǎn)都不變 芯片是根據(jù)芯片的幾個(gè)引腳的輸入改變衰減倍數(shù)的 HMC470芯片是LCC封裝的,就是那種四周有16個(gè)引腳的,引腳在芯片的正下方,芯片大小
    發(fā)表于 09-03 06:47

    【GD32F303紅楓派開發(fā)板使用手冊(cè)】第十六講 USART-DMA串口收發(fā)實(shí)驗(yàn)

    在前面ADC章節(jié)中,我們介紹了DMA的工作原理,這里就不多做介紹。從GD32F303用戶手冊(cè)中可以查到,各串口的TX和RX分別對(duì)應(yīng)DMA的不同通道,比如USART0的TX對(duì)應(yīng)DMA0的
    的頭像 發(fā)表于 06-15 09:54 ?1151次閱讀
    【GD32F303紅楓派開發(fā)板使用手冊(cè)】第十六講 USART-<b class='flag-5'>DMA</b><b class='flag-5'>串口</b>收發(fā)實(shí)驗(yàn)

    stm32 adc1和串口2同時(shí)使用DMA出錯(cuò)的原因?

    stm32f103r8t6adc1使用dma方式采集數(shù)據(jù)串口2使用dma方式收發(fā)串口發(fā)送沒有問題,串口接收只要adc1使用
    發(fā)表于 04-22 08:08

    串口dma可不可以做成dma雙緩沖形式?

    我想問串口dma可不可以做成dma雙緩沖形式
    發(fā)表于 04-17 06:08

    用CUBE生成的freertos LWIP串口DMA程序不能正常運(yùn)行怎么解決?

    frrertosconfig.h里面有個(gè) #define configTOTAL_HEAP_SIZE((size_t)50000),如果這個(gè)值定義成47104就可以正常使用串口收發(fā)DMA,但是LWIP就PING不通了,這個(gè)值改大一點(diǎn)
    發(fā)表于 04-15 06:35

    STM32F407串口DMA發(fā)送卡死在HAL_DMA_GetState怎么解決?

    使用五路串口DMA收發(fā)數(shù)據(jù),但是在發(fā)送的時(shí)候,到了while(HAL_DMA_GetState( hdma_usart3_tx) != HAL_DMA_STATE_READY);的時(shí)候
    發(fā)表于 03-06 08:29

    如何用DMA的方式讀寫串口數(shù)據(jù)?

    串口接收(或者發(fā)送)的數(shù)據(jù)比較大,如果用中斷逐字節(jié)從FIFO讀數(shù)據(jù)太耗時(shí)了,光盤里的找不到有關(guān)DMA讀寫串口的demo
    發(fā)表于 01-17 07:35

    用AT32F437ZMT7配置串口7的彈性dma接收直配不好,dma的接收中斷直進(jìn)不去是為什么?

    我用AT32F437ZMT7 配置串口7的彈性dma 接收直配不好,dma的接收中斷直進(jìn)不去 想問
    發(fā)表于 01-16 07:12