那曲檬骨新材料有限公司

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32串口收發(fā)數(shù)據(jù)為什么要使用DMA?有哪些常見問題?

lcdz66 ? 來源:雨飛工作室 ? 2023-08-24 09:57 ? 次閱讀

直接存儲器訪問(Direct Memory Access),簡稱DMA。DMA是CPU一個用于數(shù)據(jù)從一個地址空間到另一地址空間“搬運”(拷貝)的組件,數(shù)據(jù)拷貝過程不需CPU干預,數(shù)據(jù)拷貝結束則通知CPU處理。因此,大量數(shù)據(jù)拷貝時,使用DMA可以釋放CPU資源。

STM32控制器中,芯片采用Cortex-M3架構,總線結構有了很大的優(yōu)化,DMA占用另外的總線,并不會與CPU的系統(tǒng)總線發(fā)生沖突。也就是說,DMA的使用不會影響CPU的運行速度。

DMA數(shù)據(jù)拷貝過程,典型的有:(1)內存—>內存,內存間拷貝;(2)外設—>內存,如uart、spi、i2c等總線接收數(shù)據(jù)過程;(3)內存—>外設,如uart、spi、i2c等總線發(fā)送數(shù)據(jù)過程。

串口有必要使用DMA嗎?

串口(UART)是一種低速的串行異步通信,適用于低速通信場景,通常使用的波特率小于或等于115200bps。對于小于或者等于115200bps波特率的,而且數(shù)據(jù)量不大的通信場景,一般沒必要使用DMA,或者說使用DMA并未能充分發(fā)揮出DMA的作用。對于數(shù)量大,或者波特率提高時,必須使用DMA以釋放CPU資源,因為高波特率可能帶來CPU資源過度浪費的問題。

舉個例子:對于發(fā)送,使用循環(huán)發(fā)送,可能阻塞線程,需要消耗大量CPU資源“搬運”數(shù)據(jù),浪費CPU。對于發(fā)送,使用中斷發(fā)送,不會阻塞線程,但需浪費大量中斷資源,CPU頻繁響應中斷。以115200bps波特率,1s大約傳輸11520字節(jié),大約69us需響應一次中斷,如波特率再提高,將消耗更多CPU資源。對于接收,如仍采用傳統(tǒng)的中斷模式接收,同樣會因為頻繁中斷導致消耗大量CPU資源。因此,在高波特率傳輸場景下,串口非常有必要使用DMA。

DMA應用中的幾個常見問題

1、概念上的誤解

DMA傳輸是在DMA請求下,將數(shù)據(jù)從源端傳輸?shù)侥康亩恕3S腥藢MA請求跟DMA的源端或目的端混為一談。這里,我們可以將DMA傳輸類比成收發(fā)快遞,發(fā)件方即DMA源端,收件方即DMA目的端,而DMA請求端就是呼叫快遞的人。這個呼叫快遞的人可能是發(fā)件方、也可能是收件方,還可能是另外第三方。比方你要發(fā)個快遞,叫快遞的人可能是公司的前臺美眉。

具體到我們STM32應用,比方通過DMA將內存數(shù)據(jù)傳輸給UART DR寄存器發(fā)送出去,源端是存儲相關待發(fā)送數(shù)據(jù)的內存區(qū)域,目的端是UART DR數(shù)據(jù)寄存器。至于DMA請求,可以是UART發(fā)送空事件【TXE】,也可以是定時器的某個周期性觸發(fā)事件等。

在STM32各個系列的參考手冊的DMA章節(jié)部分,都有類似如下的DMA請求映射表。表格里填寫的都只是針對各個DMA傳輸流的DMA請求事件,并非一定是源端或目的端。當然,不排除作為源端或目的端同時又擔當DMA請求角色的可能。

2、配置上容易忽視的問題

我們在做DMA配置時,比較容易忽視兩個小問題。第一個就是源端和目的端的數(shù)據(jù)寬度的定義問題,除了考慮配置滿足實際需要的數(shù)據(jù)寬度外,還要注意將源端、目的端二者數(shù)據(jù)訪問寬度配置一致。不然的話,往往會導致些奇怪的問題。

還有,就是 要注意DMA的傳輸方向別弄錯了,到底是PERIPHERIAL到MEMORY還是MEMORY到PERIPHERIAL或者說是Memory到Memory要配置正確。 尤其是在用CubeMx配置時,這里有個默認配置是PERIPHERIAL到MEMORY。如果說你的真實意圖根本不是從PERIPHERIAL到MEMORY,而你無意中使用了這個默認配置,結果可想而知,DMA傳輸根本沒法正常運行。類似配置方面的小細節(jié)要多加注意,忽略了往往會累死人。

3、DMA傳輸作用范圍問題

前面將DMA傳輸類比成發(fā)快遞,發(fā)快遞時,快遞公司一般也沒法無處不到,那DMA傳輸也有同樣的問題,各個DMA模塊往往有各自的服務范圍。比方以下圖STM32F4的一個框圖為例。DMA1可以輕松訪問右邊黃色標注出來的外設,DMA2可以訪問左邊分數(shù)標注出來的各個外設。如果我們在程序里的DMA配置部分,將DMA1的源端或目的端安排為左邊的粉色標注出來的外設、或者將DMA2的源端/目的端安排為右邊的黃色標注出來的外設,結果一定會讓你失望。因為你期望它訪問它到達不了的地方。

這個地方比較隱蔽,因為我們在代碼里只是根據(jù)DMA請求自行指定源端和目的端,有時會忽視所用DMA的服務范圍。前面提過,各個STM32系列參考手冊里DMA章節(jié)部分都有明確的基于各路DMA傳輸流的DMA請求事件源的描述和展示,但并未指定基于各個DMA請求的源端或目的端。所以我們在基于某個DMA請求來自指定源端或目的端時,一定注意你安排的源/目的端是不是該DMA可以到達的地方,具體要結合手冊中功能框圖和總線訪問架構圖。比方說,下圖是STM32F7系列一個總線訪問框架圖。不難看出,DMA1是訪問不了AHB1外設和AHB2外設的。當然,DMA2訪問AHB1外設和AHB2外設沒有問題。

比方,下圖是STM23H7系列一個總線訪問框架圖,其中BDMA是沒法訪問D1域或D2域的外設及內存的。D2域的DMA1/DMA2沒法訪問D1域中的DTCM/ITCM。D1域中的MDMA沒法訪問D2域中的AHB2外設。

關于這些總線框架性的東西,在我們的STM32應用中也要多加關注。比方有時在做通信數(shù)據(jù)傳輸時發(fā)現(xiàn),使用中斷沒問題,用DMA就失敗。這時不妨查看下DMA訪問的外設或內存區(qū)域到底是不是它所能訪問得到地方,如果不是就需要適當調整下。

4、跟DCache有關的問題

該問題往往跟我們使用帶cache的M7內核的STM32F7或STMH7系列芯片有關,使用DMA傳輸時有時會遇到DMA訪問到的數(shù)據(jù)不是實時的正確數(shù)據(jù)。這往往可能是因為DMA要訪問的內存區(qū)域,跟CPU是共享的,同時又開啟了相關區(qū)域的D-Cache屬性,即CPU訪問該內存區(qū)域數(shù)據(jù)時使用D-Cache,將內存數(shù)據(jù)拷貝到D-Cache。之后,CPU訪問相關數(shù)據(jù)時往往只在Cache里進行。

比如下面的一個基于STM32F7芯片的經(jīng)典示例。首先CPU從flash里拷貝128字節(jié)常量數(shù)據(jù)到片內SRAM,然后通過DMA將SRAM里的這128字節(jié)數(shù)據(jù)拷貝進DTCM內存區(qū)。最后通過CPU將DTCM里的數(shù)據(jù)跟FLASH里的原始數(shù)據(jù)進行比較,這時會發(fā)現(xiàn)比較結果是二者內容根本不一致。這是因為開啟了SRAM的回寫的Cache屬性,第一次將數(shù)據(jù)從flash拷貝進SRAM過程中,數(shù)據(jù)還沒有真正寫進SRAM,還只是放在了Cache。當我們通過DMA將SRAM相關區(qū)域的數(shù)據(jù)拷貝進DTCM內存區(qū)時,并沒有將真正的來自FLASH區(qū)的數(shù)據(jù)拷貝過去,導致最后的數(shù)據(jù)比較失敗。

像這種情況下,我們可以有幾種方案來解決這個問題:

1、在做將數(shù)據(jù)從SRAM拷貝到DTCM區(qū)之前,先做個D-Cache的清除操作【SCB_CleanDCache()】,將D-Cache里的數(shù)據(jù)寫回到實際存儲區(qū)SRAM里。

2、我們可以通過MPU設置SRAM區(qū)域的MPU屬性,將其回寫的Cache屬性【writeback】調整為透寫的Cache屬性【writethrough】。

3、配置SRAM的MPU屬性為shareable共享屬性,令CPU訪問它時不使用D-Cache。

4、將所有涉及到具有Cacheable可緩存屬性的存儲區(qū)域,都使用透寫策略。這點可以通過配置M7內核相關控制寄存器位實現(xiàn)。

再舉個實例,使用STM32F7芯片做UART的通信數(shù)據(jù)接收,UART接收到數(shù)據(jù)后觸發(fā)DMA,DMA將數(shù)據(jù)從UART_DR寄存器拷貝到片內SRAM,CPU再從相應的SRAM區(qū)取走數(shù)據(jù)送到某LCD顯示設備顯示輸出。這時,你很可能會發(fā)現(xiàn)一個奇怪的現(xiàn)象,顯示設備輸出的數(shù)據(jù)永遠都是第一次接收到的數(shù)據(jù),不管UART的發(fā)送方任何改變發(fā)送數(shù)據(jù),顯示出來的數(shù)據(jù)就是不變,只是跟第一次發(fā)送出來的數(shù)據(jù)相比是正確的。這是怎么回事呢?

原因是因為開啟了SRAM的D-Cache屬性,CPU第一次從SRAM讀取數(shù)據(jù)后,同時又將數(shù)據(jù)放到D-Cache里,后面再來讀取SRAM相應地址數(shù)據(jù)時并沒有前往SRAM,而是直接去D-Cache里提取數(shù)據(jù),從而導致每次顯示出來的數(shù)據(jù)總是第一次接收到的數(shù)據(jù),盡管UART那邊后續(xù)接收的數(shù)據(jù)在不停變化,但并沒有對D-Cache里的數(shù)據(jù)做同步更新。這時我們可以在CPU讀取SRAM數(shù)據(jù)前做個D-cache的清除操作,讓實際存儲器數(shù)據(jù)與D-Cache里數(shù)據(jù)同步更新,或者做D-Cache的失效操作,讓CPU無視D-cache直接從SRAM區(qū)讀取數(shù)據(jù),或者說通過MPU配置禁用該SRAM區(qū)的Cache屬性。當然,最終你選用哪種策略,得結合你的實際應用來定。

串口DMA接收不定長數(shù)據(jù)

1、在STM32的DMA資源

STM32F1系列的MCU有兩個DMA控制器(DMA2只存在于大容量產(chǎn)品中),DMA1有7個通道,DMA2有5個通道,每個通道專門用來管理來自于一個或者多個外設對存儲器的訪問請求。還有一個仲裁器來協(xié)調各個DMA請求的優(yōu)先權。

而STM32F4/F7/H7系列的MCU有兩個DMA控制器總共有16個數(shù)據(jù)流(每個DMA控制器8個),每一個DMA控制器都用于管理一個或多個外設的存儲器訪問請求。每個數(shù)據(jù)流總共可以有多達8個通道(或稱請求)。每個通道都有一個仲裁器,用于處理 DMA 請求間的優(yōu)先級。

2、DMA接收數(shù)據(jù)

DMA在接收數(shù)據(jù)的時候,串口接收DMA在初始化的時候就處于開啟狀態(tài),一直等待數(shù)據(jù)的到來,在軟件上無需做任何事情,只要在初始化配置的時候設置好配置就可以了。等到接收到數(shù)據(jù)的時候,告訴CPU去處理即可。

那么問題來了,怎么知道數(shù)據(jù)是否接收完成呢?其實,有很多方法:(1) 對于定長的數(shù)據(jù) ,只需要判斷一下數(shù)據(jù)的接收個數(shù),就知道是否接收完成,這個很簡單。(2) 對于不定長的數(shù)據(jù) ,也有好幾種方法,麻煩的不會介紹,有興趣做復雜工作的同學可以在網(wǎng)上看看別人怎么做,下面這種方法是最簡單的,充分利用了STM32的串口資源,效率也是非常之高:DMA+串口空閑中斷。這兩個資源配合,簡直就是天衣無縫啊,無論接收什么不定長的數(shù)據(jù),管你數(shù)據(jù)有多少,來一個我就收一個,就像廣東人吃“山竹”,來一個吃一個。

STM32串口的狀態(tài)寄存器:

idle

idle說明

當我們檢測到觸發(fā)了串口總線空閑中斷的時候,就知道這一波數(shù)據(jù)傳輸完成了,然后我們就能得到這些數(shù)據(jù),去進行處理即可。 這種方法是最簡單的,根本不需要我們做多的處理,只需要配置好,串口就等著數(shù)據(jù)的到來,DMA也是處于工作狀態(tài)的,來一個數(shù)據(jù)就自動搬運一個數(shù)據(jù)。

串口接收完數(shù)據(jù)是要處理的,那么處理的步驟是怎么樣呢?

暫時關閉串口接收DMA通道,有兩個原因:1.防止后面又有數(shù)據(jù)接收到,產(chǎn)生干擾,因為此時的數(shù)據(jù)還未處理。2.DMA需要重新配置。

清DMA標志位。

從DMA寄存器中獲取接收到的數(shù)據(jù)字節(jié)數(shù)(可有可無)。

重新設置DMA下次要接收的數(shù)據(jù)字節(jié)數(shù)。**注意,數(shù)據(jù)傳輸數(shù)量范圍為0至65535。**這個寄存器只能在通道不工作(DMA_CCRx的EN=0)時寫入。通道開啟后該寄存器變?yōu)橹蛔x,指示剩余的待傳輸字節(jié)數(shù)目。寄存器內容在每次DMA傳輸后遞減。數(shù)據(jù)傳輸結束后,寄存器的內容或者變?yōu)?;或者當該通道配置為自動重加載模式時,寄存器的內容將被自動重新加載為之前配置時的數(shù)值。當寄存器的內容為0時,無論通道是否開啟,都不會發(fā)生任何數(shù)據(jù)傳輸。

給出信號量,發(fā)送接收到新數(shù)據(jù)標志,供前臺程序查詢。

開啟DMA通道,等待下一次的數(shù)據(jù)接收,注意,對DMA的相關寄存器配置寫入,如重置DMA接收數(shù)據(jù)長度,必須要在關閉DMA的條件進行,否則操作無效。

3、注意事項

STM32的IDLE的中斷在串口無數(shù)據(jù)接收的情況下,是不會一直產(chǎn)生的,產(chǎn)生的條件是這樣的,當清除IDLE標志位后,必須有接收到第一個數(shù)據(jù)后,才開始觸發(fā),一斷接收的數(shù)據(jù)斷流,沒有接收到數(shù)據(jù),即產(chǎn)生IDLE中斷。如果中斷發(fā)送數(shù)據(jù)幀的速率很快,MCU來不及處理此次接收到的數(shù)據(jù),中斷又發(fā)來數(shù)據(jù)的話,這里不能開啟,否則數(shù)據(jù)會被覆蓋。有兩種方式解決:(1)在重新開啟接收DMA通道之前,將Rx_Buf緩沖區(qū)里面的數(shù)據(jù)復制到另外一個數(shù)組中,然后再開啟DMA,然后馬上處理復制出來的數(shù)據(jù)。(2) 建立雙緩沖 ,重新配置DMA_MemoryBaseAddr的緩沖區(qū)地址,那么下次接收到的數(shù)據(jù)就會保存到新的緩沖區(qū)中,不至于被覆蓋。

4、程序實現(xiàn)

實驗效果:當外部給單片機發(fā)送數(shù) 據(jù)的時候,假設這幀數(shù)據(jù)長度是1000個字節(jié),那么在單片機接收到一個字節(jié)的時候并不會產(chǎn)生串口中斷,只是DMA在背后默默地把數(shù)據(jù)搬運到你指定的緩沖區(qū)里面。當整幀數(shù)據(jù)發(fā)送完畢之后串口才會產(chǎn)生一次中斷,此時可以利用DMA_GetCurrDataCounter()函數(shù)計算出本次的數(shù)據(jù)接受長度,從而進行數(shù)據(jù)處理。

4.1串口的配置

很簡單,基本與使用串口的時候一致,只不過一般我們是打開接收緩沖區(qū)非空中斷,而現(xiàn)在是打開空閑中斷——USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);。


	/** *@briefUSARTGPIO配置,工作參數(shù)配置 *@param無 *@retval無 */ voidUSART_Config(void) { GPIO_InitTypeDefGPIO_InitStructure; USART_InitTypeDefUSART_InitStructure; //打開串口GPIO的時鐘 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE); //打開串口外設的時鐘 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE); //將USARTTx的GPIO配置為推挽復用模式 GPIO_InitStructure.GPIO_Pin=DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure); //將USARTRx的GPIO配置為浮空輸入模式 GPIO_InitStructure.GPIO_Pin=DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure); //配置串口的工作參數(shù) //配置波特率 USART_InitStructure.USART_BaudRate=DEBUG_USART_BAUDRATE; //配置針數(shù)據(jù)字長 USART_InitStructure.USART_WordLength=USART_WordLength_8b; //配置停止位 USART_InitStructure.USART_StopBits=USART_StopBits_1; //配置校驗位 USART_InitStructure.USART_Parity=USART_Parity_No; //配置硬件流控制 USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None; //配置工作模式,收發(fā)一起 USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //完成串口的初始化配置 USART_Init(DEBUG_USARTx,&USART_InitStructure); //串口中斷優(yōu)先級配置 NVIC_Configuration(); #ifUSE_USART_DMA_RX //開啟串口空閑IDEL中斷 USART_ITConfig(DEBUG_USARTx,USART_IT_IDLE,ENABLE); //開啟串口DMA接收 USART_DMACmd(DEBUG_USARTx,USART_DMAReq_Rx,ENABLE); /*使能串口DMA*/ USARTx_DMA_Rx_Config(); #else //使能串口接收中斷 USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE); #endif #ifUSE_USART_DMA_TX //開啟串口DMA發(fā)送 //USART_DMACmd(DEBUG_USARTx,USART_DMAReq_Tx,ENABLE); USARTx_DMA_Tx_Config(); #endif //使能串口 USART_Cmd(DEBUG_USARTx,ENABLE); }
4.2串口DMA配置
把DMA配置完成,就可以直接打開DMA了,讓它處于工作狀態(tài),當有數(shù)據(jù)的時候就能直接搬運了。

	#ifUSE_USART_DMA_RX staticvoidUSARTx_DMA_Rx_Config(void) { DMA_InitTypeDefDMA_InitStructure; //開啟DMA時鐘 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //設置DMA源地址:串口數(shù)據(jù)寄存器地址*/ DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART_DR_ADDRESS; //內存地址(要傳輸?shù)淖兞康闹羔? DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)Usart_Rx_Buf; //方向:從內存到外設 DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC; //傳輸大小 DMA_InitStructure.DMA_BufferSize=USART_RX_BUFF_SIZE; //外設地址不增 DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //內存地址自增 DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //外設數(shù)據(jù)單位 DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte; //內存數(shù)據(jù)單位 DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //DMA模式,一次或者循環(huán)模式 //DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; DMA_InitStructure.DMA_Mode=DMA_Mode_Circular; //優(yōu)先級:中 DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh; //禁止內存到內存的傳輸 DMA_InitStructure.DMA_M2M=DMA_M2M_Disable; //配置DMA通道 DMA_Init(USART_RX_DMA_CHANNEL,&DMA_InitStructure); //清除DMA所有標志 DMA_ClearFlag(DMA1_FLAG_TC5); DMA_ITConfig(USART_RX_DMA_CHANNEL,DMA_IT_TE,ENABLE); //使能DMA DMA_Cmd(USART_RX_DMA_CHANNEL,ENABLE); } #endif
4.3接收完數(shù)據(jù)處理
因為接收完數(shù)據(jù)之后,會產(chǎn)生一個idle中斷,也就是空閑中斷,那么我們就可以在中斷服務函數(shù)中知道已經(jīng)接收完了,就可以處理數(shù)據(jù)了,但是中斷服務函數(shù)的上下文環(huán)境是中斷,所以,盡量是快進快出,一般在中斷中將一些標志置位,供前臺查詢。在中斷中先判斷我們的產(chǎn)生在中斷的類型是不是idle中斷,如果是則進行下一步,否則就無需理會。

	/** ****************************************************************** *@brief串口中斷服務函數(shù) *@authorjiejie *@versionV1.0 *@date2018-xx-xx ****************************************************************** */ voidDEBUG_USART_IRQHandler(void) { #ifUSE_USART_DMA_RX /*使用串口DMA*/ if(USART_GetITStatus(DEBUG_USARTx,USART_IT_IDLE)!=RESET) { /*接收數(shù)據(jù)*/ Receive_DataPack(); //清除空閑中斷標志位 USART_ReceiveData(DEBUG_USARTx); } #else /*接收中斷*/ if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET) { Receive_DataPack(); } #endif }
4.4Receive_DataPack()
這個才是真正的接收數(shù)據(jù)處理函數(shù),為什么我要將這個函數(shù)單獨封裝起來呢?因為這個函數(shù)其實是很重要的,因為我的代碼兼容普通串口接收與空閑中斷,不一樣的接收類型其處理也不一樣,所以直接封裝起來更好,在源碼中通過宏定義實現(xiàn)選擇接收的方式!更考慮了兼容操作系統(tǒng)的,可能我會在系統(tǒng)中使用dma+空閑中斷,所以,供前臺查詢的信號量就有可能不一樣,可能需要修改,我就把它封裝起來了。

	/************************************************************ *@briefUart_DMA_Rx_Data *@paramNULL *@returnNULL *@authorjiejie *@githubhttps://github.com/jiejieTop *@date2018-xx-xx *@versionv1.0 *@note使用串口DMA接收時調用的函數(shù) ***********************************************************/ #ifUSE_USART_DMA_RX voidReceive_DataPack(void) { /*接收的數(shù)據(jù)長度*/ uint32_tbuff_length; /*關閉DMA,防止干擾*/ DMA_Cmd(USART_RX_DMA_CHANNEL,DISABLE);/*暫時關閉dma,數(shù)據(jù)尚未處理*/ /*清DMA標志位*/ DMA_ClearFlag(DMA1_FLAG_TC5); /*獲取接收到的數(shù)據(jù)長度單位為字節(jié)*/ buff_length=USART_RX_BUFF_SIZE-DMA_GetCurrDataCounter(USART_RX_DMA_CHANNEL); /*獲取數(shù)據(jù)長度*/ Usart_Rx_Sta=buff_length; PRINT_DEBUG("buff_length=%d ",buff_length); /*重新賦值計數(shù)值,必須大于等于最大可能接收到的數(shù)據(jù)幀數(shù)目*/ USART_RX_DMA_CHANNEL->CNDTR=USART_RX_BUFF_SIZE; /*此處應該在處理完數(shù)據(jù)再打開,如在DataPack_Process()打開*/ DMA_Cmd(USART_RX_DMA_CHANNEL,ENABLE); /*(OS)給出信號,發(fā)送接收到新數(shù)據(jù)標志,供前臺程序查詢*/ /*標記接收完成,在DataPack_Handle處理*/ Usart_Rx_Sta|=0xC000; /*  DMA 開啟,等待數(shù)據(jù)。注意,如果中斷發(fā)送數(shù)據(jù)幀的速率很快,MCU來不及處理此次接收到的數(shù)據(jù), 中斷又發(fā)來數(shù)據(jù)的話,這里不能開啟,否則數(shù)據(jù)會被覆蓋。有2種方式解決: 1.在重新開啟接收DMA通道之前,將Rx_Buf緩沖區(qū)里面的數(shù)據(jù)復制到另外一個數(shù)組中, 然后再開啟DMA,然后馬上處理復制出來的數(shù)據(jù)。 2.建立雙緩沖,重新配置DMA_MemoryBaseAddr的緩沖區(qū)地址,那么下次接收到的數(shù)據(jù)就會 保存到新的緩沖區(qū)中,不至于被覆蓋。 */ }
		
			

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • mcu
    mcu
    +關注

    關注

    146

    文章

    17321

    瀏覽量

    352650
  • 控制器
    +關注

    關注

    112

    文章

    16446

    瀏覽量

    179458
  • STM32
    +關注

    關注

    2272

    文章

    10924

    瀏覽量

    357579
  • 串口
    +關注

    關注

    14

    文章

    1557

    瀏覽量

    77044
  • dma
    dma
    +關注

    關注

    3

    文章

    566

    瀏覽量

    100958

原文標題:STM32串口收發(fā)數(shù)據(jù)為什么要使用DMA?有哪些常見問題?

文章出處:【微信號:雨飛工作室,微信公眾號:雨飛工作室】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    STM32串口發(fā)送數(shù)據(jù)和接收數(shù)據(jù)方式總結

    STM32串口發(fā)送數(shù)據(jù)和接收數(shù)據(jù)方式總結
    的頭像 發(fā)表于 09-19 09:14 ?7935次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b>發(fā)送<b class='flag-5'>數(shù)據(jù)</b>和接收<b class='flag-5'>數(shù)據(jù)</b>方式總結

    請問STM32F0串口DMA收發(fā)數(shù)據(jù)怎么實現(xiàn)?

    請問STM32F0串口DMA收發(fā)數(shù)據(jù)怎么實現(xiàn)?
    發(fā)表于 11-18 06:56

    STM32串口配置代碼常見問題是什么?

    STM32串口配置代碼常見問題是什么?
    發(fā)表于 11-18 07:39

    怎么實現(xiàn)STM32串口DMA收發(fā)

    STM32 DMA具有哪些功能?怎么實現(xiàn)STM32串口DMA收發(fā)
    發(fā)表于 12-06 07:27

    如何實現(xiàn)STM32串口DMA收發(fā)數(shù)據(jù)

    串口基本原理是什么?如何實現(xiàn)STM32串口DMA收發(fā)數(shù)據(jù)
    發(fā)表于 02-18 06:18

    STM32串口DMA問題詳解

    昨天晚上在STM32串口DMA的問題上糾結了好長時間,所以今天上午寫篇博客來談談我對串口DMA發(fā)送的理解。
    的頭像 發(fā)表于 10-27 16:16 ?8495次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>DMA</b>問題詳解

    STM32串口DMA發(fā)送數(shù)據(jù)

    一、DMA簡介二、實驗流程了解了DMA之后,我們做一個實驗:STM32采用串口DMA方式,用115200bps或更高速率向上位機連續(xù)發(fā)送
    發(fā)表于 12-07 10:36 ?22次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>DMA</b>發(fā)送<b class='flag-5'>數(shù)據(jù)</b>

    STM32CUBEMX配置教程(九)STM32串口DMA收發(fā)數(shù)據(jù)

    STM32CUBEMX配置教程(九)STM32串口DMA收發(fā)數(shù)據(jù)基于
    發(fā)表于 12-24 18:47 ?24次下載
    <b class='flag-5'>STM32</b>CUBEMX配置教程(九)<b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>DMA</b><b class='flag-5'>收發(fā)</b><b class='flag-5'>數(shù)據(jù)</b>

    STM32F407串口空閑中斷+DMA

    STM32F407串口空閑中斷+DMA空閑中斷,DMA簡介空閑中斷區(qū)別于普通串口中斷的每一字節(jié)數(shù)據(jù)
    發(fā)表于 12-24 18:50 ?29次下載
    <b class='flag-5'>STM32</b>F407<b class='flag-5'>串口</b>空閑中斷+<b class='flag-5'>DMA</b>

    stm32串口

    DMA發(fā)送緩存區(qū)bsp_usart.cbsp_usart.hisr.c基于stm32f103zet6串口發(fā)送使用DMA發(fā)送大致說明USART_Rx_Sbuffer二維數(shù)組 ->
    發(fā)表于 12-24 18:55 ?20次下載
    <b class='flag-5'>stm32</b><b class='flag-5'>串口</b>

    stm32串口DMA數(shù)據(jù)接收不完整問題說明

    stm32串口DMA數(shù)據(jù)接收不完整問題說明最近做了一個項目需要用串口來接收模塊端的應答數(shù)據(jù),由于
    發(fā)表于 12-24 19:37 ?21次下載
    <b class='flag-5'>stm32</b><b class='flag-5'>串口</b><b class='flag-5'>DMA</b><b class='flag-5'>數(shù)據(jù)</b>接收不完整問題說明

    HAL庫STM32串口DMA不定長收發(fā),空閑中斷

    參考了鏈接5中的代碼)1.C語言中volatile關鍵字的學習2.【STM32】HAL庫 STM32CubeMX教程十一—DMA (串口DMA
    發(fā)表于 01-14 10:40 ?19次下載
    HAL庫<b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>DMA</b>不定長<b class='flag-5'>收發(fā)</b>,空閑中斷

    STM32串口收發(fā)數(shù)據(jù)為什么要使DMA

    STM32控制器中,芯片采用Cortex-M3架構,總線結構了很大的優(yōu)化,DMA占用另外的總線,并不會與CPU的系統(tǒng)總線發(fā)生沖突。也就是說,DMA的使用不會影響CPU的運行速度。
    發(fā)表于 02-08 15:52 ?0次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>收發(fā)</b><b class='flag-5'>數(shù)據(jù)</b>為什么<b class='flag-5'>要使</b>用<b class='flag-5'>DMA</b>?

    STM32串口收發(fā)數(shù)據(jù)為什么要使DMA

    CPU處理。因此,大量數(shù)據(jù)拷貝時,使用DMA可以釋放CPU資源,相關文章推薦:詳解STM32中的DMA原理。
    的頭像 發(fā)表于 02-12 13:22 ?6035次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>收發(fā)</b><b class='flag-5'>數(shù)據(jù)</b>為什么<b class='flag-5'>要使</b>用<b class='flag-5'>DMA</b>

    STM32串口中斷及DMA接收常見的幾個問題

    STM32串口中斷及DMA接收常見的幾個問題
    的頭像 發(fā)表于 10-26 16:41 ?3706次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b>中斷及<b class='flag-5'>DMA</b>接收<b class='flag-5'>常見</b>的幾個問題
    神农架林区| 百家乐官网博欲乐城| 圣淘沙百家乐游戏| 大发888游戏平台hg dafa888gw| 百家乐官网开户送18元| 百家乐巴厘岛娱乐城| 澳门金沙| 玩机器百家乐心得| 新利国际娱乐| 杨筠松 24山 土| 博王国际娱乐| 百家乐视频金币| 盛大69棋牌游戏| 百家乐开庄概率| 云鼎娱乐场| 新葡京百家乐现金网| 波密县| 百家乐龙虎桌布| 凯旋门百家乐官网现金网| 百家乐网上漏洞| 单机百家乐官网棋牌| 三星百家乐的玩法技巧和规则| 百家乐官网高手看百家乐官网| 九州百家乐的玩法技巧和规则| 保单百家乐官网游戏机厂家| 狼2老虎机清零密码| 试玩区百家乐官网1000| 免费棋牌游戏| 金榜百家乐现金网| 大宁县| 网上赌百家乐的玩法技巧和规则| 百家乐官网厅| 大发888下载| 百家乐娱乐城体育| 网上百家乐官网骗钱| 金冠娱乐城最新网址| 真人百家乐导航| 百家乐官网自动下注| 德州扑克游戏| 百家乐太阳城 | 百家乐官网老千|