有人使用STM32F4系列開發(fā)產(chǎn)品,程序運(yùn)行過程中需要不時地對外輸出一串驅(qū)動脈沖,并要求這幾串脈沖的頻率可變、占空比固定。他想到使用基于STM32定時器的DMA BURST傳輸。具體點(diǎn)說,他期望不時地通過TIM3的CH1輸出一串頻率可變、占空比固定的脈沖然后停下來。這個思路在原理上是沒問題的,可是他在測試過程中發(fā)現(xiàn)怎么也折騰不出預(yù)期的效果。
他目前使用的芯片是STM32F401,雖有點(diǎn)老舊,但我查看了手冊,確認(rèn)該芯片的TIM3是支持基于TIMER事件實(shí)現(xiàn)TIME寄存器與內(nèi)存間的DMA BURST傳輸?shù)摹<疵總€TIMER事件可以申請多個DMA請求從而實(shí)現(xiàn)定時器寄存器與內(nèi)存間的批量數(shù)據(jù)傳輸。要知某個STM32 TIMER是否支持上述功能,只需查看STM32參考手冊的相關(guān)定時器的寄存器中有無TIMx_DCR和TIMx_DMAR寄存器的介紹。
既然支持,為什么實(shí)現(xiàn)不了呢?關(guān)于這個功能我們還需要注意幾點(diǎn):
1、所選擇的TIMER必須支持基于定時器事件的DMABURST傳輸功能。
2、觸發(fā)事件必須是來自參與DMA傳輸?shù)亩〞r器事件,不能是別的定時器事件。比方說你想實(shí)現(xiàn)TIM1的寄存器與內(nèi)存間的DMA BURST傳輸,觸發(fā)事件不能是來自TIM2、TIM3這些非TIM1的事件。
3、定時器DMA Burst傳輸時,用來被BURST訪問的定時器寄存器應(yīng)該是同一定時器的而且是地址連續(xù)的寄存器,不可跳躍訪問。比方說像下面某TIMER的4個比較寄存器物理地址是安排在一起的,而CH2恰好因?yàn)槟承┰驔]有被用上。
如果你僅對CH1/CH3/CH4三個通道的比較寄存器的值做BURST訪問,此時盡管CH2沒有被用上,BURST訪問的傳輸個數(shù)應(yīng)該是4而不是3。
4、STM32 HAL庫里的例程或函數(shù)重點(diǎn)在演示相應(yīng)的功能或特性,但它不能包羅萬象或保證適用于任何場景。有些時候我們可能需要在現(xiàn)有庫函數(shù)的前提下適當(dāng)?shù)刈鲂┱{(diào)整來滿足需求。
結(jié)合這幾點(diǎn),我們一起排查下。第1點(diǎn)、第2點(diǎn)已經(jīng)核對過了,沒問題。看看第3點(diǎn),即設(shè)置BURST傳輸個數(shù)。下圖是F40x系列TIM2~TIM5的內(nèi)存地址映射圖。
現(xiàn)在使用者真正需要用到的寄存器只有TIM3->ARR和TIM3->CCR1兩個寄存器,但二者中間還有個預(yù)留空位【其它高級定時器的RCR寄存器的位置】也必須算進(jìn)來,即這里BURST傳輸個數(shù)應(yīng)該是3而不是2。
再看看上面提到的第4點(diǎn)要注意的地方。這點(diǎn)我就不過多解釋了,ST提供的HAL庫例程及相關(guān)函數(shù)只能實(shí)現(xiàn)1次BURST傳輸?shù)墓δ?,如果要?shí)現(xiàn)多次BURST傳輸就得在其代碼基礎(chǔ)上做些調(diào)整,更多細(xì)節(jié)可以參考我之前分享的那篇《STM32定時器BURST傳輸介紹及示例》。不過,在那篇的演示例程里我使用的是DMA Circular模式,現(xiàn)在的用戶則要使用DMA Normal模式。采用Normal模式和采用Circular模式基于現(xiàn)有HAL庫函數(shù)組織代碼還略有差異,若沒處理好這點(diǎn)小差異,可能讓你完全出不來想要的結(jié)果。
下面我使用STM32G4芯片的TIM3-CH1演示上面用戶的功能。每次輸出5個脈沖,3次輸出為一個循環(huán),同一循環(huán)中的3次輸出的頻率各不相同,占空比一樣。【為什么沒用STM32F401芯片,是因?yàn)榇藭r手上沒有帶該芯片的開發(fā)板。不過演示功能的配置及代碼基本一樣?!?/p>
我使用CubeMx對TIM3進(jìn)行配置,參考配置如下:
開啟TIM3基于更新事件的DMA傳輸功能并做相關(guān)配置。
配置完成,生成初始化工程,添加用戶代碼。
我準(zhǔn)備了3串脈沖的ARR/CCR1的值,分別以數(shù)組PulseData1[]、PulseData2[]、PulseData3[]來存放,占空比都設(shè)置為50%。顯然數(shù)組行中間的0值用于前面提到過的預(yù)留字,此處無實(shí)際作用。另外,每個數(shù)組中的第6行數(shù)據(jù)其實(shí)是關(guān)閉當(dāng)前通道PWM輸出,具體應(yīng)用時注意結(jié)合所選擇的PWM模式及極性選擇。
下面是參考用戶代碼。代碼在手機(jī)模式下可左右滑動。
/* USER CODE BEGIN PD */ #define ARR1 (10000U) #define ARR2 (20000U) #define ARR3 (40000U) #defineCount(18) //3 * 6 uint16_t PulseData1[]={ ARR1,0,ARR1*0.5, ARR1,0,ARR1*0.5, ARR1,0,ARR1*0.5, ARR1,0,ARR1*0.5, ARR1,0,ARR1*0.5,// ARR1,0,0}; uint16_t PulseData2[]={ ARR2,0,ARR2*0.5, ARR2,0,ARR2*0.5, ARR2,0,ARR2*0.5, ARR2,0,ARR2*0.5, ARR2,0,ARR2*0.5,// ARR2,0,0, }; uint16_t PulseData3[]={ ARR3,0,ARR3*0.5, ARR3,0,ARR3*0.5, ARR3,0,ARR3*0.5, ARR3,0,ARR3*0.5, ARR3,0,ARR3*0.5,//5 ARR3,0,0, }; /* USER CODE END PD */
主循環(huán)測試代碼如下:
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_TIM3_Init(); /* USER CODE BEGIN 2 */ __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE); TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_1,TIM_CCx_ENABLE); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ htim3.DMABurstState=HAL_DMA_BURST_STATE_READY; hdma_tim3_up.State = HAL_DMA_STATE_READY ; __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE); HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData1, TIM_DMABURSTLENGTH_3TRANSFERS,Count); TIM3->EGR = TIM_EGR_UG; __HAL_TIM_ENABLE(&htim3); HAL_Delay(150);//Preparedforthe next5 Pulses __HAL_TIM_DISABLE(&htim3); // HAL_DMA_Abort(&hdma_tim3_up); htim3.DMABurstState = HAL_DMA_BURST_STATE_READY; hdma_tim3_up.State = HAL_DMA_STATE_READY ; __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE); HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData2, TIM_DMABURSTLENGTH_3TRANSFERS,Count); TIM3->EGR = TIM_EGR_UG; __HAL_TIM_ENABLE(&htim3); HAL_Delay(150);//Prepared for the next 5 Pulses __HAL_TIM_DISABLE(&htim3); // HAL_DMA_Abort(&hdma_tim3_up); htim3.DMABurstState = HAL_DMA_BURST_STATE_READY; hdma_tim3_up.State = HAL_DMA_STATE_READY ; __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE); HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData3, TIM_DMABURSTLENGTH_3TRANSFERS,Count); TIM3->EGR = TIM_EGR_UG; __HAL_TIM_ENABLE(&htim3); HAL_Delay(150);//Prepared for the next 5 Pulses __HAL_TIM_DISABLE(&htim3); // HAL_DMA_Abort(&hdma_tim3_up); } /* USER CODE END 3 */ }
編譯、除錯后,運(yùn)行程序可以看到我所期望的結(jié)果。即我每隔一會兒就發(fā)出5個脈沖,3次為1個循環(huán)。測試代碼都放在這里,供參考使用。這里不逐句解釋了,具體使用時結(jié)合庫代碼來研究即可。
最后,補(bǔ)充一下有關(guān)上篇《利用非對稱PWM模式體驗(yàn)編碼器功能》文中3個變量如何使用ARM MDK IDE自帶邏輯分析儀的配置,我把配置截圖放于此供有需要的人參考。
這里的CNT_value連續(xù)記錄TIM2計(jì)數(shù)器的值,這里為Analog量。
Level_PA8記錄GPIOA_PIN8的電平情況,1或0兩個值之一,為Bit量。
Level_PA9跟Level_PA8是完全相同的數(shù)據(jù)類型,顯示的是GPIOA_PIN9的電平。顯然,邏輯分析儀配置里關(guān)于Level_PA9的顯示算式的屏蔽數(shù)應(yīng)該是0x00000200,右移位為9。我是在SYSTICK的毫秒中斷里讀取GPIOA->IDR的值即管腳電平到變量Level_PA8和Level_PA9的?!鞠聢D中Core Clock填寫芯片支持的最高主頻】
審核編輯:劉清
-
寄存器
+關(guān)注
關(guān)注
31文章
5343瀏覽量
120443 -
定時器
+關(guān)注
關(guān)注
23文章
3250瀏覽量
114881 -
dma
+關(guān)注
關(guān)注
3文章
561瀏覽量
100604 -
STM32F4
+關(guān)注
關(guān)注
3文章
194瀏覽量
28064
原文標(biāo)題:為何實(shí)現(xiàn)不了定時器DMA Burst傳輸?
文章出處:【微信號:stmcu832,微信公眾號:茶話MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論