某STM32用戶開(kāi)發(fā)產(chǎn)品,用到ADC模塊,通過(guò)定時(shí)器更新事件觸發(fā)AD轉(zhuǎn)換,轉(zhuǎn)換結(jié)果由DMA搬運(yùn)到指定的內(nèi)存區(qū)域。DMA工作在正常模式(即非循環(huán)模式),每當(dāng)傳輸完畢一批數(shù)據(jù)后在傳輸完成中斷里設(shè)置傳輸結(jié)束標(biāo)志,應(yīng)用代碼對(duì)該標(biāo)志進(jìn)行監(jiān)視。
當(dāng)檢查到該有效標(biāo)志時(shí),說(shuō)明采集到了預(yù)定的轉(zhuǎn)換數(shù)據(jù)。將數(shù)據(jù)處理后,軟件產(chǎn)生TIMER更新事件,以保證計(jì)數(shù)器從0開(kāi)始計(jì)數(shù)【注:這里選用的向上計(jì)數(shù)模式】。然后清除更新事件標(biāo)志、ADC轉(zhuǎn)換完成標(biāo)志位EOC ,關(guān)閉DMA后對(duì)DMA進(jìn)行再配置,然后重新使能DMA進(jìn)行第二次傳輸。
調(diào)試中發(fā)現(xiàn),對(duì)于第二次DMA傳輸,每次一使能DMA 就立即搬運(yùn)一個(gè)數(shù)據(jù)。按理說(shuō)應(yīng)該延時(shí)一個(gè)定時(shí)器更新周期后才會(huì)搬運(yùn)首次數(shù)據(jù)才對(duì)。因?yàn)檐浖梦籙G位后,用來(lái)觸發(fā)ADC的TIMer是從0開(kāi)始計(jì)數(shù)的,需要計(jì)數(shù)到溢出才會(huì)觸發(fā)AD轉(zhuǎn)換。他想不明白的是TIM已經(jīng)復(fù)位從0開(kāi)始計(jì)數(shù)了,該清的標(biāo)志位都清除了,還有什么原因?qū)е翫MA不等TIMER觸發(fā)就立即先行搬運(yùn)一個(gè)數(shù)據(jù)呢。
該問(wèn)題源于某STM32論壇,但用戶沒(méi)有貼出任何代碼。這里模擬他的應(yīng)用場(chǎng)景做個(gè)測(cè)試驗(yàn)證,并試圖找出相關(guān)原因。
我這里也設(shè)計(jì)了兩輪DMA傳輸,照樣使用TIMER更新事件觸發(fā)ADC轉(zhuǎn)換。第一輪DMA傳輸傳輸3個(gè)AD轉(zhuǎn)換結(jié)果到某內(nèi)存地址,第二輪傳輸5個(gè)轉(zhuǎn)換結(jié)果到另一內(nèi)存位置。
先使用Stm32CubeMx基于STM32F411Discovery板進(jìn)行基本的初始化配置。配置都很簡(jiǎn)單。
ADC配置,這里只選擇1個(gè)常規(guī)通道用于測(cè)試,選擇TIM2的觸發(fā)輸出啟動(dòng)AD轉(zhuǎn)換,并開(kāi)啟ADC的DMA傳輸功能,DMA工作在Normal模式?!居布螦DC輸入通道我直接連VDD了】
TIMER配置,這里選擇TIM2,其更新事件做為觸發(fā)輸出用來(lái)啟動(dòng)ADC。
配置完畢后生成初始化代碼,然后添加用戶代碼。
這里準(zhǔn)備了幾個(gè)內(nèi)存變量.
我在第一次DMA傳輸完成后立即關(guān)閉定時(shí)器,在開(kāi)啟第二輪DMA傳輸前,不讓定時(shí)器有機(jī)會(huì)再次觸發(fā)ADC產(chǎn)生EOC事件??纯从袩o(wú)他說(shuō)到的情形發(fā)生。
我把用戶代碼分成兩部分,分別用紅框、綠框區(qū)分。
第一部分由基本的初始化函數(shù)、開(kāi)啟ADC外設(shè)及其DMA功能、對(duì)第一次DMA傳輸做配置并使能DMA、等待3次ADC轉(zhuǎn)換結(jié)束。
第二部分代碼的功能主要關(guān)閉定時(shí)器、關(guān)閉DMA,第二次對(duì)DMA進(jìn)行配置,再開(kāi)啟DMA功能并啟動(dòng)定時(shí)器?!疚野褦帱c(diǎn)打在箭頭所指的地方,即待啟動(dòng)計(jì)數(shù)器的那句代碼處】
基于上述代碼測(cè)試,沒(méi)有發(fā)現(xiàn)一使能第二次DMA傳輸就先傳一個(gè)數(shù)據(jù)的現(xiàn)象。這時(shí)定時(shí)器也沒(méi)被啟動(dòng),DMA處于就緒待命狀態(tài)。【結(jié)果如下圖】
那客戶反饋的情況到底是怎么回事呢?
因?yàn)闆](méi)見(jiàn)到用戶具體的代碼,他說(shuō)過(guò)在DMA做完第一次傳輸后,還對(duì)定時(shí)器做了復(fù)位。那我們不妨在第一次DMA傳輸結(jié)束后,增加對(duì)定時(shí)器的復(fù)位操作,看看結(jié)果會(huì)怎么樣。
我將第二部分代碼稍作修改如下【見(jiàn)下圖中A處代碼】:
基于調(diào)整過(guò)的代碼進(jìn)行測(cè)試,還真發(fā)現(xiàn)了一使能第二次DMA傳輸時(shí)就先傳一個(gè)數(shù)據(jù)的現(xiàn)象。可是此時(shí)定時(shí)器仍未啟動(dòng),DMA怎么就開(kāi)始傳輸數(shù)據(jù)了呢。【結(jié)果如下圖所示】
當(dāng)然,單純從DMA傳輸功能來(lái)講,它跟定時(shí)器是否啟動(dòng)并沒(méi)有必然聯(lián)系。對(duì)于被使能了的DMA,只要有合適的DMA請(qǐng)求出現(xiàn),它就行使職能。具體到這里,應(yīng)該是有EOC事件出現(xiàn)了才會(huì)發(fā)生DMA傳輸?shù)摹D沁@個(gè)EOC事件從哪里來(lái)的呢?
我們不妨先理一理:
第一次DMA傳輸完成后不可能還有待處理EOC事件存在。在第一次DMA傳輸過(guò)程中,每次DMA讀取ADC數(shù)據(jù)就保證EOC被清零了,DMA傳輸完成后又立即關(guān)閉了定時(shí)器,本案例里也沒(méi)有別的事情影響定時(shí)器的迅速關(guān)閉。按理說(shuō)在兩次DMA傳輸之間不會(huì)有定時(shí)器更新事件觸發(fā)AD轉(zhuǎn)換,更何況在使能第二次DMA前還專門做了EOC的清除操作。
看起來(lái)的確有點(diǎn)奇怪,怎么感覺(jué)有個(gè)DMA請(qǐng)求,用客戶的話說(shuō),好像潛伏在哪里一樣?
目前的代碼跟剛開(kāi)始的比,多了個(gè)定時(shí)器的復(fù)位操作。難道這個(gè)復(fù)位操作會(huì)導(dǎo)致ADC轉(zhuǎn)換而生成EOC事件?說(shuō)到這,它還真有這本事。
因?yàn)檐浖绞綄?duì)定時(shí)器進(jìn)行復(fù)位也可以產(chǎn)生更新事件,它正好能啟動(dòng)AD轉(zhuǎn)換【AD轉(zhuǎn)換功能一直都沒(méi)關(guān)閉過(guò)】從而產(chǎn)生EOC事件。如果EOC標(biāo)志沒(méi)有及時(shí)清除的話,就可以在下次DMA傳輸剛被使能,即使計(jì)數(shù)器還沒(méi)被啟動(dòng)的條件下觸發(fā)一次DMA傳輸。
分析到這里,感覺(jué)找到問(wèn)題原因了。但是,似乎還是有點(diǎn)不對(duì)勁。因?yàn)榧词苟〞r(shí)器復(fù)位動(dòng)作產(chǎn)生更新事件而觸發(fā)ADC轉(zhuǎn)換,進(jìn)而產(chǎn)生EOC事件, 但我們?cè)诙〞r(shí)器復(fù)位動(dòng)作之后還特意做過(guò)對(duì)EOC標(biāo)志的清除?!鞠聢D中的第二個(gè)紅圈內(nèi)的代碼】
難道說(shuō)這個(gè)清除EOC標(biāo)志的操作有問(wèn)題?
先確認(rèn)代碼寫法本身,沒(méi)有問(wèn)題。再看邏輯和時(shí)序上問(wèn)題。
通過(guò)進(jìn)一步的調(diào)試,在下圖所示代碼處放了3個(gè)斷點(diǎn)單步運(yùn)行,的確發(fā)現(xiàn)定時(shí)器復(fù)位事件觸發(fā)了ADC轉(zhuǎn)換,EOC被置位。在后續(xù)代碼中也發(fā)現(xiàn)EOC被清零了。有意思的是,當(dāng)開(kāi)著下圖所示3個(gè)斷點(diǎn)來(lái)運(yùn)行時(shí),那個(gè)奇怪的現(xiàn)象就消失了,那潛伏的DMA請(qǐng)求似乎遁形了。
如果取消上面的第1、第2個(gè)斷點(diǎn)后運(yùn)行代碼,那個(gè)現(xiàn)象立即又重現(xiàn),潛伏的又激活了。
反復(fù)驗(yàn)證到這里,基本上明白是怎么回事了。
毫無(wú)疑問(wèn),定時(shí)器的復(fù)位操作導(dǎo)致AD轉(zhuǎn)換而產(chǎn)生了EOC事件。代碼里雖然有對(duì)EOC的清除操作,但該操作相對(duì)ADC而言,太早了點(diǎn)。即在針對(duì)EOC做刪除操作時(shí),ADC可能還在忙著轉(zhuǎn)換,離產(chǎn)生EOC事件還早呢。這正好可以解釋為什么在復(fù)位操作代碼后放個(gè)斷點(diǎn)再刪除EOC就有效的情形。
既然這樣,我在清除EOC操作代碼的前面加一句EOC標(biāo)志查詢等待,以保證后續(xù)的清除操作可靠有效。我將代碼再次做了調(diào)整。見(jiàn)下圖中方框內(nèi)代碼。
就修改過(guò)的代碼進(jìn)行驗(yàn)證,那個(gè)現(xiàn)象徹底消失。后續(xù)的第二輪DMA傳輸也規(guī)規(guī)矩矩了。
到此,本應(yīng)用案例分享結(jié)束。最后,稍作小結(jié)并做些提醒:
1、針對(duì)STM32定時(shí)器的軟件復(fù)位操作可以產(chǎn)生更新事件,其效果等同于定時(shí)器溢出導(dǎo)致的更新事件。
2、我們編寫代碼,尤其這種嵌入式代碼時(shí),除了保證代碼基本的正常邏輯外,各個(gè)硬件本身操作時(shí)序、響應(yīng)時(shí)間參數(shù)等也須多加關(guān)注。
3、結(jié)合本案例,在第一次DMA傳輸完成后為第二次DMA做準(zhǔn)備時(shí),建議先關(guān)閉計(jì)數(shù)器,否則可能會(huì)給我們的應(yīng)用帶來(lái)些隱患,本案例中探討的問(wèn)題,就是其中隱患之一。限于篇幅和主題,這里就不啰嗦了,后面若有合適案例再行交流。
-
adc
+關(guān)注
關(guān)注
99文章
6533瀏覽量
545537 -
STM32
+關(guān)注
關(guān)注
2271文章
10923瀏覽量
357247 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3255瀏覽量
115237
原文標(biāo)題:DMA觸發(fā)請(qǐng)求異常之案例分享
文章出處:【微信號(hào):stmcu832,微信公眾號(hào):茶話MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論