找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 18600|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

關(guān)于STM32F0 MCU 多通道ADC的DMA傳輸話題

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:98618 發(fā)表于 2015-12-7 03:17 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
整理:MilerShao

某日,一深圳客戶在用STM32F0芯片開發(fā)新產(chǎn)品,其中用到7個ADC通道,并將AD轉(zhuǎn)換的值通過DMA傳輸?shù)揭粋內(nèi)存數(shù)組里。他反映如果單通道ADC并啟用DMA,數(shù)據(jù)傳輸都很正確,但當(dāng)啟用多通道ADC并啟用DMA傳輸時,發(fā)現(xiàn)數(shù)據(jù)亂了套,結(jié)果是第一個數(shù)據(jù)特別大,后面的數(shù)據(jù)多數(shù)為0。后來通過網(wǎng)上了解到,貌似不少人栽在這里,這里盡力分享交流下。


在聊這個問題前,不妨插入兩個小話題。

一、

記得有一次有個工程師在用STM8S芯片的ADC,跟我說ADC的值當(dāng)輸入電壓較低時數(shù)據(jù)很準(zhǔn)很正確,可當(dāng)輸入電壓高到一定范圍時,數(shù)據(jù)反而變小,似乎并無章法。查看其代碼,其AD使用的是10bit,可他ADC處理函數(shù)返回的數(shù)據(jù)卻8bit的。既然這樣,當(dāng)ADC數(shù)據(jù)大過255時要正確就怪了。

二、

還記得某工程師用STM32F1的芯片開發(fā)產(chǎn)品時問我,是不是用HSI的話,UART波特率就上不了115200。我告知他一般來說,輕松能上。后來細(xì)查其代碼,他不知何時把那個存放UART波特率的數(shù)據(jù)變量定義為16位寬度了,既然這樣最高波特率就過不了64K。


好,回到今天的多通道ADC的DMA傳輸話題。


其實,關(guān)于stm32 多通道ADC的DMA傳輸,ST官方在其傳統(tǒng)外設(shè)固件庫或CUBE工程固件庫里都有現(xiàn)存的項目工程。兩個庫的例程我用基于STM32F072的?桶濉綨UCLEO】做了測試,都可以正常使用。出現(xiàn)上面工程師提到的問題,是因為其有關(guān)數(shù)據(jù)寬度配置不一致導(dǎo)致的誤解和誤判。

因為反映該問題的客戶是基于ST官方的CUBE庫做的。這里就基于cube工程示例項目交流。相關(guān)工程位置如下:

\STM32Cube\Repository\STM32Cube_FW_F0_V1.3.0\Projects\STM32F072RB-Nucleo\Examples\ADC\ADC_Sequencer


例程項目用到3個AD通道。在有關(guān)ADC配置的地方,可以看出其ADC轉(zhuǎn)換的數(shù)據(jù)分辨率為12位,數(shù)據(jù)右對齊,多通道ADC的掃描方向是從小往大,即FORWARD方向掃描。


從有關(guān)DMA配置代碼可以看出,DMA拾取、送達(dá)兩端的數(shù)據(jù)對齊寬度均為半字即16bit;數(shù)據(jù)從外設(shè)搬到存儲器;內(nèi)存地址遞增方式


從官方例程里可以看到一個3元素的數(shù)組用來存儲3個AD通道轉(zhuǎn)換值,數(shù)組元素的數(shù)據(jù)寬度為16位,即半字uint16_t

#define ADCCONVERTEDVALUES_BUFFER_SIZE ((uint32_t) 3)

/* Variable containing ADC conversions results */

__IO uint16_t aADCxConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE];



按照上面的條件進(jìn)行編譯調(diào)試,查看數(shù)組里的轉(zhuǎn)換結(jié)果,并無發(fā)現(xiàn)異常。既沒有第一個數(shù)據(jù)特別大,也沒有后面數(shù)據(jù)為0的異象。分別是3個16位數(shù)據(jù)0x0803,0x06b2,0x05e5,每個數(shù)組變量對應(yīng)一個AD通道的轉(zhuǎn)換值。后面也會用到這幾個數(shù)據(jù),因為是實時調(diào)試截圖,數(shù)據(jù)可能些差異,先行忽略

如果把上面存放ADC數(shù)據(jù)的數(shù)組變量數(shù)據(jù)寬度由16位改為32位,即U16改為U32,其它不變,再來看看結(jié)果。如下圖所示:


呵呵,貌似異象出現(xiàn)了。

數(shù)組里的數(shù)據(jù)出現(xiàn)跟第一種情況明顯不同的布局,數(shù)組第一個數(shù)據(jù)的確是特別大,數(shù)組第2個數(shù)據(jù)擺放的似乎并非程序猿所希望的。結(jié)合上面的測試結(jié)果,大致可以看出該數(shù)組的第2個數(shù)據(jù)是處在第3個轉(zhuǎn)換次序的AD通道的轉(zhuǎn)換值,第3個數(shù)組數(shù)據(jù)里空空如也,是0。通過兩次實驗的比較不難發(fā)現(xiàn),第二種情形下的半字?jǐn)?shù)據(jù),除了0值外,跟第一種情形里的數(shù)據(jù)是一樣的,只是數(shù)組元素的位置有變動。

看到這里估計有人已經(jīng)明白怎么回事了。DMA傳輸?shù)臄?shù)據(jù)寬度跟數(shù)組定義的存儲寬度不一致導(dǎo)致誤會。其實各通道ADC的值并沒有錯【從上面實驗也可以看出】,第2種情況只是把兩個16位寬的ADC值放到一個32位寬的數(shù)組元素里。如果此時簡單地把每個數(shù)組變量里的數(shù)據(jù)當(dāng)做單個通道轉(zhuǎn)換過來的值就是天大的誤解了,因為每個數(shù)組變量存放的數(shù)據(jù)跟單個通道的ADC值不存在一一對應(yīng)關(guān)系了。


上面客戶的問題就是出在這里。為了避免類似誤解和麻煩,DMA配置過程中在定義內(nèi)存數(shù)據(jù)對齊寬度時最好存放AD轉(zhuǎn)換值的存儲變量用同類型的數(shù)據(jù)寬度。

細(xì)心的人可以發(fā)現(xiàn),在ST CUBE庫例程代碼里的DMA相關(guān)配置代碼后面還特意跟了一句注釋:


/* Transfer to memory by half-word to match with buffer variable type: half-word */

這樣做的目的主要是方便后面對ADC轉(zhuǎn)換數(shù)據(jù)的讀取及后續(xù)計算,并不是說數(shù)組存儲變量的數(shù)據(jù)寬度定義跟DMA傳輸數(shù)據(jù)寬度不一致就一定錯了。

對于DMA而言,它只關(guān)心數(shù)據(jù)要存放的起始地址、自己每次搬運數(shù)據(jù)的寬度、單輪循環(huán)搬運的次數(shù)就行。至于緩沖區(qū)存放數(shù)據(jù)的變量類型怎么樣它并不關(guān)心。

下面是我將存放數(shù)據(jù)的數(shù)組變量的數(shù)據(jù)寬度改為8位、數(shù)組元素改為6,其它不動的測試結(jié)果。高位地址對應(yīng)高位數(shù)據(jù)字節(jié)


顯然,當(dāng)把數(shù)組變量類型定義為U8時,DMA將來自AD轉(zhuǎn)換來的每16位源數(shù)據(jù)分別放在2個8數(shù)組變量空間。跟上面第二種情形一樣,每個數(shù)組變量并不對應(yīng)一個AD轉(zhuǎn)換值,而是每個AD值分兩個數(shù)組元素擺放。但從AD變換或DMA傳輸而言,并沒有出錯,結(jié)果都是正確的。

下圖是直接給DMA一個目標(biāo)地址,然后在內(nèi)存區(qū)查看ADC轉(zhuǎn)換出來的數(shù)據(jù)。【高位地址對應(yīng)高位數(shù)據(jù)字節(jié)】結(jié)果也是正常的。



最后順便提下,STM32F0的多通道AD掃描有兩個方向,一般默認(rèn)為FORWARD方向,也可以設(shè)置為BACKWARD方向。有時忽略了也可能給開發(fā)者帶來混亂或困惑,因為有時多通道,換個方向后AD值可能跟預(yù)估的大相徑庭而又無規(guī)律。

本文中的話題,包括開頭中插入的兩個話題,看似跟AD/DMA等有關(guān),實質(zhì)上感覺跟C語言或其它基礎(chǔ)更為密切。



【拋磚引玉 旨在交流,如有錯疏 歡迎賜教】

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:263487 發(fā)表于 2017-12-19 09:22 | 只看該作者
發(fā)現(xiàn)STM32L0的HAl庫(STM32Cube_FW_L0_V1.10.0)中出現(xiàn)了一個問題:
如果將以下的DMA配置過程中在定義內(nèi)存數(shù)據(jù)對齊寬度改了,然后編譯,燒錄后發(fā)現(xiàn)出錯。那以后就再改不回來了。
DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DmaHandle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
比如講上述的DMA_PDATAALIGN_WORD改為DMA_PDATAALIGN_HALFWORD,然后即使再改回DMA_PDATAALIGN_WORD,也是出錯。
回復(fù)

使用道具 舉報

板凳
ID:192996 發(fā)表于 2019-11-29 13:35 | 只看該作者
哇 好人啊 遇到這個問題搞一天,現(xiàn)在豁然開朗,終歸還是基礎(chǔ)不扎實。
回復(fù)

使用道具 舉報

地板
ID:85740 發(fā)表于 2021-11-24 16:02 | 只看該作者
LZQ0056 發(fā)表于 2017-12-19 09:22
發(fā)現(xiàn)STM32L0的HAl庫(STM32Cube_FW_L0_V1.10.0)中出現(xiàn)了一個問題:
如果將以下的DMA配置過程中在定義內(nèi)存 ...


現(xiàn)在最新版是1.7
這個問題很正常,cubeide經(jīng)常會出現(xiàn)修改了代碼無法生效的情況
clean無效
rebuild無效
最后我摸索出來的辦法是,在資源管理器中 ,把鎖有和工程配置有關(guān)的都刪除
包含不限于 Debug文件夾
.settings文件夾
.mxoroject文件
.launch文件
然后重新運行仿真,你會發(fā)現(xiàn),問題解決了
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表