?經(jīng)常有STM32開發(fā)者基于STM32CubeMx進(jìn)行配置并生成基于HAL庫的初始化代碼,當(dāng)涉及到DMA功能時(shí),發(fā)現(xiàn)DMA功能無效,但從配置操作及代碼本身又似乎找不出原因來的情況。此情此景 往往挺令人抓狂的。
比方曾有人反饋,他使用STM32F4系列芯片進(jìn)行產(chǎn)品開發(fā),通過STM32CubeMx配置并生成初始化代碼,使用了UART的DMA傳輸。但他發(fā)現(xiàn)DMA根本不工作。后來他無意中發(fā)現(xiàn),是因?yàn)樗谟脩舸a里不經(jīng)意地調(diào)整過UART外設(shè)和DMA外設(shè)初始化代碼的前后順序,當(dāng)他重新調(diào)整二者的先后順序后就一切正常了【此時(shí)DMA初始化代碼在前,UART初始化代碼在后】。他想知道這個(gè)順序是怎么影響DMA功能的。
我順手拿了塊STM32F334的Nucleo板,開啟UART1/UART3的數(shù)據(jù)通信功能,使用DMA進(jìn)行數(shù)據(jù)的循環(huán)傳輸。UART1發(fā)送數(shù)據(jù),UART3接收數(shù)據(jù)?;赟TM32CubeMx配置后生成初始化代碼,添加用戶代碼。如下圖所示:
經(jīng)測試驗(yàn)證,發(fā)現(xiàn)基于UART1/3的DMA傳輸功能是正常的。
結(jié)合客戶的反饋,我將DMA與UART初始化順序前后調(diào)換下,如下圖:
果真發(fā)現(xiàn)DMA不工作了,UART1/UART3之間也沒有數(shù)據(jù)通信。UART1/3的數(shù)據(jù)寄存器內(nèi)容維持0值而沒有任何變化,尤其作為發(fā)送端的UART1的數(shù)據(jù)寄存器也毫無動(dòng)靜。
看來,DMA和UART的初始化代碼的順序的確影響到了二者的功能,也就是說如果代碼是基于現(xiàn)有CubeMX生成的初始化代碼,二者的初始化順序不能隨意調(diào)整,那到底怎么回事呢?
首先查看這兩個(gè)初始化代碼內(nèi)容,試圖找到蛛絲馬跡。很遺憾,并未很快發(fā)現(xiàn)原因。后來,當(dāng)再次查看DMA初始化函數(shù)MX_DMA_Init();的具體內(nèi)容時(shí),發(fā)現(xiàn)代碼其實(shí)很簡單,就兩個(gè)動(dòng)作:
一個(gè)動(dòng)作是開啟DMA外設(shè)的時(shí)鐘,另一個(gè)就是使能DMA相關(guān)的中斷矢量控制。
既然這樣,我嘗試將該DMA初始化函數(shù)體位置依然保持放在UART初始化代碼的后面,但將DMA初始化函數(shù)里的那句開啟DMA外設(shè)時(shí)鐘的代碼提取出來,并移至UART初始化代碼之前,據(jù)此進(jìn)行驗(yàn)證。這次,結(jié)果就一切正常了。
看來,基于現(xiàn)有初始化代碼,這個(gè)DMA時(shí)鐘的開啟要放在UART初始化代碼之前,那是為什么呢?感覺UART的配置跟DMA時(shí)鐘沒有啥關(guān)系啊。
繼續(xù)挖掘原因!
再回頭細(xì)看UART的初始化代碼,在UART初始化函數(shù)的一個(gè)子函數(shù)HAL_UART_MspInit()那里發(fā)現(xiàn)了端倪。
MX_USART1_UART_Init()==》HAL_UART_Init()==》HAL_UART_MspInit();
因?yàn)槲覀冮_啟了跟UART傳輸事件相關(guān)的DMA功能,在HAL_UART_MspInit();函數(shù)里不僅有對與UART相關(guān)的GPIO的復(fù)用功能配置,而且,還有跟UART事件相關(guān)的DMA配置??磥鞺ART的初始化還是跟DMA有關(guān)聯(lián)的。
結(jié)合上面DMA初始化函數(shù)里的那句開啟DMA外設(shè)時(shí)鐘代碼,到這里基本明白怎么回事了。
因?yàn)槲覀冊赨ART初始化代碼里要做跟DMA有關(guān)的配置,如果不事先將DMA外設(shè)的時(shí)鐘開啟,加上UART初始化函數(shù)里也沒有開啟DMA外設(shè)時(shí)鐘的代碼,那么,在UART初始化代碼進(jìn)行有關(guān)DMA的配置操作就沒法保證有效。
到此,開篇中提到的因?yàn)镈MA和UART初始化代碼順序影響DMA功能的原因應(yīng)該說揭曉了。
在做嵌入式開發(fā)過程中,很多的初始化配置都是基于硬件本身的,有些初始化順序可能有硬件方面的時(shí)序要求。關(guān)于這些,各芯片手冊中一般都會有明確描述和說明。我們在編寫初始化代碼時(shí)須遵循相關(guān)規(guī)定。當(dāng)然,有些配置順序可能還得結(jié)合具體應(yīng)用,實(shí)際體會后而做靈活調(diào)整。
回到文中案例,一般來說,STM32CubeMx在生成初始化代碼時(shí)已經(jīng)考慮到初始化時(shí)序這點(diǎn)了,只是用戶在整理代碼過程中可能無意調(diào)整了二者的初始化順序而不自知,再加上我們對初始化代碼本身缺乏足夠的了解而可能一度陷入困境。
據(jù)個(gè)人體驗(yàn),在實(shí)際應(yīng)用中,當(dāng)我們基于CubeMx來回調(diào)整配置時(shí),這個(gè)順序也可能會被打亂。請注意這點(diǎn)。說實(shí)在的,這個(gè)地方非常隱蔽,即使知道有這么回事也還是可能忘記或忽略。當(dāng)因此而出現(xiàn)DMA傳輸異常時(shí),如果不是基于代碼做跟蹤調(diào)試或閱讀是很難找到問題癥結(jié)的,因?yàn)榕渲貌僮骱退{(diào)用的庫函數(shù)代碼本身是沒有問題的。核心問題就是初始化代碼的執(zhí)行順序。
比方這兩天連續(xù)有人反饋,他們使用STM32芯片的ADC并啟用DMA傳輸時(shí),都是因?yàn)檫@個(gè)原因使得ADC數(shù)據(jù)無法被DMA取走而產(chǎn)生異常。總之,在現(xiàn)有情況下, 保證DMA初始化代碼放在其它與DMA有關(guān)的各個(gè)外設(shè)初始化之前就不會有類似問題。比方就像下面的樣子:
關(guān)于這個(gè)話題,三年前我已經(jīng)在此分享過了。這個(gè)過程中,依然陸續(xù)也有人會遇到這個(gè)問題,我覺得有必要再分享之,所以在這里再分享一遍,以資提醒,愿君在開發(fā)過程中少一份坎坷。
三年,算來沒完沒了的新冠疫情也持續(xù)近三年了,真難??!我在此放一首加油曲在下方,愿一切盡快正常起來!
審核編輯:湯梓紅
-
STM32
+關(guān)注
關(guān)注
2264文章
10854瀏覽量
354296 -
uart
+關(guān)注
關(guān)注
22文章
1219瀏覽量
101118 -
dma
+關(guān)注
關(guān)注
3文章
556瀏覽量
100344 -
STM32F4
+關(guān)注
關(guān)注
3文章
194瀏覽量
27974 -
stm32cubemx
+關(guān)注
關(guān)注
5文章
280瀏覽量
14713
原文標(biāo)題:STM32CubeMx的初始配置順序與DMA傳輸異常之提醒
文章出處:【微信號:stmcu832,微信公眾號:茶話MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論