案例1:STM32U575的TIMER+GPDMA輸出PWM異常
有人使用STM32U575的TIMER加上DMA做PWM輸出。具體就是利用某TIMER的一個通道的比較事件觸發DMA,通過DMA修改CCR值來實現指定占空比的PWM輸出。
對于很多STM32用戶來說,這個應用算是比較常見的做法了。可當他使用CubeMx完成配置,生成工程添加相應用戶代碼后,發現輸出跟預期不一致。
而當他使用STM32F1或STM32G0系列來實現時又沒有任何問題。其實,定時器基本配置都差不多,都是調用ST提供的HAL庫函數HAL_TIM_PWM_Start_DMA()。該函數的原型就是下面樣子:
鑒于該用戶的反饋,我找了STM32H563的開發板,也來做些驗證測試。使用TIM1,快速對其做配置,開啟通道1比較事件的DMA請求及PWM輸出,讓DMA動態修改CCR1來改變PWM輸出占空比。使用CubeMx進行配置:
創建工程后,稍微添加點用戶代碼后即可進行測試。下面數組里有10個數據,對應10個不同占空比的脈沖。
我期望輸出下面的波形:
當我基于上面配置及用戶代碼運行程序后,發現輸出卻是這樣的:
顯然跟我的預期相差甚遠。那是怎么回事呢?
我也順便找了塊STM32G4的開發板,快速地驗證了該功能,輸出跟預期完全吻合。那STM32U5有什么特別的地方呢?后來經過快速瀏覽手冊和閱讀庫函數,終于還是發現了問題原因所在。
不管我們使用哪個STM32系列,實現上述功能,使用HAL庫的話,調用的庫函數都是一樣的。都是前面提到過的HAL_TIM_PWM_Start_DMA(),【注:最后都會調用HAL_DMA_Start_IT】,在這個函數里有個Length變量。該變量在STM32U5系列的HAL庫里的約定含義跟其它系列,比如F4/G4/G0等的不太一樣。
在STM32U5系列庫函數里,該Length變量表示的是一輪【塊】傳輸過程中DMA從源搬到目的的數據所對應的字節數;【下面截圖來自STM32U5系列HAL庫,注釋中特地強調以字節為單位】
而在F4/G4/G0這些系列的庫函數里,該變量表示的則是DMA從源搬到目的的數據個數【見下面函數注釋】;
當然,我們也可以從STM32參考手冊里的寄存器定義看出差別來。在STM32U5系列GPDMA里描述DMA傳輸長度的寄存器是GPDMA_CxBR1,其中字段BNDT[15:0]表述塊傳輸過程中從源傳輸到目的的數據字節數。
而在STM32G4/F4系列里,描述DMA傳輸長度的寄存器是DMA_CNDTRx。
明確表示該長度為DMA傳輸的數據個數,一輪【塊】最多傳輸64K個數據。
介紹到這里,我們就基本明白了,為什么同樣的操作及函數,STM32F4/G4/G0/F1系列表現正常,而STM32U5表現異常了?;氐介_頭,現在源數據寬度為16位,希望一輪傳輸10個數據,那對應的傳輸字節數就是10*2。當我把上面的那個DAM啟動函數里的Length調整20時輸出也的確正常了。
也就是說,對于STM32U5系列,這個Length應設置成傳輸的數據個數乘以源數據寬度即可。當然,別的系列是否也有類似問題不好說,具體應用時我們稍微留意下??傊龅絾栴}時不能完全死守經驗,必要的閱讀手冊和閱讀函數也是必要的。
案例2:基于TIMER Burst DMA實現PWM輸出異常
有人使用STM32G4系列芯片開發產品,用到基于STM32定時器的DMA BURST傳輸。他使用定時器TIM1的更新事件同時修改其3個輸出通道的PWM占空比并保持同步輸出。如下圖所示:
可是,他在調試過程中發現個非常奇怪的現象。感覺只要接上STLINK調試器,輸出就不正常。主要體現就是TIM1的3路PWM輸出不再保持同步,如下圖所示的情形:
結合他的反饋和本人經驗,我覺得問題可能不是出在連接調試器上,而很可能與打開PC端IDE的寄存器窗口有關。經了解,他當時使用的IDE是ARM MDK,調試過程中也的確一直打開了相關TIMER的寄存器觀察串口。
當他嘗試把TIMER1的寄存器視窗關閉后,重新運行代碼,3路輸出就恢復同步輸出了,完全符合預期??磥?,輸出正常與否跟接不接STLINK調試器是沒有關系的,根本原因是打開了TIMER的寄存器視窗。
那問題來了,TIMER的寄存器觀察窗口被打開后怎么就影響到PWM輸出呢?
這里可以有個初步判斷,因為芯片的調試組件不時地訪問TIMER的某些寄存器而影響到PWM輸出了。TIMER的寄存器這么多,具體是哪個或哪幾個寄存器因為調試組件的訪問而被影響其內容,進而影響到PWM輸出呢?
快速瀏覽一遍TIM1的寄存器,并沒有立即發現或鎖定哪個寄存器因被讀取后會明顯影響當前定時器的正常運行的。后來,他干脆就將那些TIMER寄存器一個個地試,看看到底哪個寄存器因為中途被讀取后會影響到當前PWM輸出。功夫不負有心人,最后發現跟寄存器TIMx_DMAR有關!
剛才前面說過了,他現在是使用STM32定時器的DMA BURST傳輸。該類傳輸涉及到2個專門的寄存器,分別是TIMx_DCR 和 TIMx_DMAR。
其中,DCR寄存器配置BURST長度和每次發起Burst傳輸時參與傳輸的定時器的第一個寄存器位置。DMAR寄存器專門用來提供DMA訪問定時器寄存器時的地址,我們可以將DMAR寄存器看成一個地址指針,DMA訪問DMAR寄存器時所獲得的外設地址【即定時器寄存器地址】由算式(TIMx_CR1地址)+(DBA+DMA 索引號)x 4來決定。
其中,DBA、DBL在DCR寄存器中配置好了的,是固定值。DMA索引號在0~DBL之間依次動態變化。具體到本案例應用,DBL等于2。
為什么當開啟寄存器觀察窗口后,DMAR寄存器被調試組件訪問后會影響到此處Burst傳輸呢?關于這點,我是這樣理解的。本來DMAR寄存器是專門給DMA訪問來實現定時器寄存器與內存間的Burst傳輸的。在這個過程中,DMA Index基于DMA訪問自動調整從而實現Burst傳輸。如果說,在這個過程中調試組件也參與進來對DMAR寄存器進行訪問,這時可能導致DMA Index變更的混亂,從而導致對定時器寄存器訪問序列的混亂,最后導致3路PWM輸出的混亂。
審核編輯:劉清
-
寄存器
+關注
關注
31文章
5336瀏覽量
120230 -
PWM
+關注
關注
114文章
5181瀏覽量
213799 -
STM32
+關注
關注
2270文章
10895瀏覽量
355739 -
定時器
+關注
關注
23文章
3246瀏覽量
114719 -
PWM輸出
+關注
關注
1文章
66瀏覽量
5135 -
HAL庫
+關注
關注
1文章
121瀏覽量
6217
原文標題:STM32 TIMER+DMA輸出PWM異常二案例
文章出處:【微信號:stmcu832,微信公眾號:茶話MCU】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論