Burst介紹:
DMA控制器可以生成單次傳輸或增量突發傳輸,傳輸的節拍數為4、8或16。
為了確保數據一致性,構成突發傳輸的每組傳輸都是不可分割的:AHB傳輸被鎖定,AHB總線矩陣的仲裁器在突發傳輸序列期間不會撤銷DMA主設備的授權。
作用:
可以通過Burst進行多個寄存器的同時修改,在M2P時同時配置多個定時器。
burst會占用總線直到數據發完為止,此期間CPU打斷不了,但是不連續的節拍之間CPU依然可以打斷
問題剖析:
需要STM32輸出變頻且不同脈沖數量的PWM波形,具體要求如下:
交替輸出兩組參數:
參數組1:頻率較高(ARR=1000),輸出3個脈沖(RCR=2)。
參數組2:頻率較低(ARR=5000),輸出2個脈沖(RCR=1)。
實現方式:通過DMA Burst功能,在一次定時器事件中批量修改多個寄存器(ARR、RCR、CCR),無需CPU干預。
STM32的TIM模塊支持DMA Burst功能,允許通過單次定時器事件觸發多次DMA傳輸,從而批量更新多個寄存器。其核心硬件模塊如下:
(1) 關鍵寄存器
TIMx_DCR(DMA控制寄存器):
DBSS (DMA Burst Source Selection):選擇觸發DMA Burst的事件源(如定時器更新事件)。
DBL (DMA Burst Length):設置一次DMA Burst傳輸的數據個數(例如3次傳輸,對應修改ARR、RCR、CCR)。
DBA (DMA Burst Address):設置DMA傳輸的起始寄存器地址偏移(例如ARR寄存器的地址偏移為0x2C)。
TIMx_DMAR(DMA地址寄存器):
DMA通過訪問此寄存器,將數據寫入目標寄存器(如ARR、RCR、CCR)。
(2) 工作原理
觸發事件:定時器產生指定事件(如更新事件TIM_UPDATE)。
DMA請求:事件觸發DMA Burst傳輸,DMA控制器根據TIMx_DCR配置的傳輸次數(DBL)和起始地址(DBA),將內存中的數據連續寫入多個寄存器。
自動更新參數:寄存器值被修改后,定時器立即使用新參數生成PWM波形。
理解關鍵參數:
Burst Size與傳輸次數的關系
在STM32的DMA Burst模式中,Burst Size 表示 單次突發傳輸(Burst)中連續傳輸的數據單元個數,而 傳輸總次數 由以下兩個參數共同決定:
Burst Size(突發傳輸單元數):例如設置為4,表示一次突發傳輸4個數據單元。
Data Width(數據寬度):每個數據單元的大小(字節、半字或字)。
NDTR(Number of Data):DMA傳輸的總數據單元數(需在代碼中動態設置)。
公式:
總傳輸次數 = NDTR / Burst Size
例如:若NDTR=12,Burst Size=4,則總傳輸次數為3次(每次突發傳輸4個單元)。
這里我們讓DMA Burst輸出一次,一次傳四個數據單元的值(實際上只用三個,但是mx中只可以配4increment,第四個數據傳0即可),輸出的脈沖個數通過傳入的四個單元值中RCR 的值決定;
PWM參數定義
ARR (Auto-Reload Register):決定PWM頻率。
頻率公式:PWM頻率 = 定時器時鐘 / (ARR + 1)
示例:
pulse1[0] = 1000 → 頻率 = 100MHz / 1001 ≈ 99.9 kHz
pulse2[0] = 5000 → 頻率 = 100MHz / 5001 ≈ 20 kHz
RCR (Repetition Counter Register):控制脈沖個數。
脈沖個數公式:脈沖數 = RCR + 1
示例:
pulse1[1] = 2 → 輸出3個脈沖
pulse2[1] = 1 → 輸出2個脈沖
CCR (Capture/Compare Register):決定占空比。
占空比公式:占空比 = CCR / (ARR + 1)
示例:
pulse1[2] = 500 → 占空比 ≈ 50%
pulse2[2] = 2500 → 占空比 ≈ 50%
參數結構:
uint32_t pulse1[3] = {1000, 2, 500}; // ARR=1000, RCR=2, CCR=500
uint32_t pulse2[3] = {5000, 1, 2500}; // ARR=5000, RCR=1, CCR=2500
CubeMX設置:
在CubeMX中配置Burst Size
打開DMA Settings標簽頁,選擇對應的DMA通道。
設置 Burst Size 為 4 Increment(根據需求選擇1/4/8/16)。
設置 Data Width 為 Word(32位,與TIM寄存器位寬一致)。
勾選 Increment Address(內存地址遞增)。
選擇 Mode 為 Normal 或 Circular。(若需持續傳輸,選擇Circular模式并且設置足夠大的NDTR)
每次DMA Burst需傳輸3個寄存器值(ARR、RCR、CCR)。
每個寄存器為32位(4字節),共需傳輸12字節。
Burst Size = 4 Increment(每次傳輸4個數據單元,但實際僅用3個,最后一個填充0)。
Data Width = Word(32位)。
NDTR = 3(傳輸3個數據單元)。
HAL_DMA_Start_IT()函數原型:
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
?代碼實現:
uint32_t pulse_data[4] = {1000, 2, 500, 0}; // 第4個數據填充0
HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse_data, (uint32_t)&TIM1->DMAR, 3);// NDTR=3
交替輸出的實現
(1) 中斷切換模式
第一次傳輸:DMA傳輸pulse1到TIM寄存器。
傳輸完成中斷:在中斷回調函數中重新配置DMA,傳輸pulse2。
循環觸發:重復上述過程,實現交替輸出。
(2) 雙緩沖模式
配置雙緩沖:使能DMA雙緩沖,設置兩組內存地址(pulse1和pulse2)。
自動切換:DMA傳輸完當前緩沖區后,自動切換到下一組參數,無需CPU干預。
關鍵代碼片段(基于HAL庫)
// 1. DMA傳輸完成中斷回調函數
void HAL_TIM_DMADelayPulseCplt(DMA_HandleTypeDef *hdma) {// 切換參數組static uint8_t is_pulse1 = 0;if (is_pulse1) {HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse1, (uint32_t)&TIM1->DMAR, 3);} else {HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse2, (uint32_t)&TIM1->DMAR, 3);}is_pulse1 = !is_pulse1;
}// 2. 主函數初始化
int main(void) {// 初始化定時器和DMAHAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_DMA_Start_IT(&hdma_tim1, (uint32_t)pulse1, (uint32_t)&TIM1->DMAR, 3);while (1) {// 其他任務}
}