一.前言
目標要求:系統時鐘 8Mhz,6 個 PWM 脈沖。
二.實現方式
實現上述目標的方法有很多種,比如兩個定時器級連,定時器定時中斷翻轉 IO 口,等等,這里使用 DMA 的方式去實現。
2.1 參考基于 F1 標準外設庫
軟件環境:STM32F10x_StdPeriph_Lib_V3.5.0 版本的標準外設庫函數中的 Project->STM32F10x_StdPeriph_Examples->TIM->DMABurst 的示例代碼; 硬件環境:STM32F10V-128K-EVAL,MCU型號為 STM32F103VBT6; 該示例的代碼稍微解釋下,就會明白 DMA 的寄存器的作用。部分代碼如下: 
TIM1_DMAR_ADDRESS 地址的定義:

DMA 的初始化:
逐個寄存器簡要說明:
DMA_PeripheralBaseAddr

該語句是對寄存器 DMA_CPARx 賦值,存入要操作的是哪種外設,該外設的數據寄存器的基地址,它作 為數據傳輸的源或目標,在此例中,是作為數據傳輸的目標的基地址。
通道 5,它的 CPAR 值是 0x40012C4C,表明通道 5 的寄存器偏移地址 DMA_CPAR5 是 0x10+0d20 * 4 = 0x60,所以 DMA_CPAR5 的真實地址是 0x40020000 +0x60 = 0x40020060,該地址里面存儲的是 
0x40012C4C,是 TIM1_DMAR 的地址。即可以理解為操作的是 TIM1 的外設。

DMA_MemoryBaseAddr
該語句是對寄存器 DMA_CMARx 賦值,設置的是相應通道的存儲器的基地址,作為數據傳輸的源或目 標,在此例中,是作為數據傳輸的源的基地址。(uint32_t)SRC_Buffer; DMA_DIR 數據傳輸方向,從外設讀或者從存儲器讀,該示例中是從存儲器讀;外設作為目標地址。

DMA_BufferSize
定義數據傳輸的數量,指示剩余的待傳輸字節數目,寄存器內容在每次 DMA 傳輸后遞減。 DMA_PeripheralInc,DMA_MemoryInc 該示例中,不執行外設地址增量操作,執行存儲器地址增量操作。DMA_PeripheralDataSize,DMA_MemoryDataSize 定義外設數據寬度,存儲器數據寬度。
DMA_Mode 分為非循環模式和循環模式,
在非循環模式中,在數據傳輸結束后,DMA_CNDTRx 寄存器的內容會變為 0,此時無論通道是否開啟, 都不會發生任何數據傳輸。 在循環模式中,在數據傳輸結束后,DMA_CNDTRx 寄存器的內容會自動加載變為之前配置的數值, 重新開始數據傳輸。
DMA_Priority,DMA_M2M 本例中,通道優先級設為高,啟動非存儲器到存儲器模式。 2.2 基于 Cube 庫函數的可控 PWM 脈沖 直接打開\STM32Cube_FW_L0_V1.1.0\Projects\STM32L053R8-Nucleo\Examples\TIM\TIM_DMABurst 中的示例項目,修改配置符合自己當初的設想:選取 Timer2 的 channel1(PA5),系統時鐘通過 HSI 的分頻倍頻,通過 PLL 實現系統時鐘為 8MHz。GPIO 口的設置: Max output speed 的速度為 High。定時器 PWM 模式的設置:向上計數,計數時鐘為 8MHz,占空比 50%。 
GPIO 口的設定:
這里要記住一點,如果參數設置中,周期和占空比寄存器設定的計數值已經達到最小,當再使用 DMA 
產生中斷時,可能會來不及響應。允許的話,可以利用分頻 Prescaler 先對定時計數器的時鐘分頻。 定時器的配置:
DMA 的配置:

其中,對于 DMA 配置中,BUFFER_SIZE 是代表要向目標地址發送的數據的個數。
上述需要在程序中添加設置 TIM2_DMAR_Address 的偏移索引地址,在定時器的章節可以看到。 不需要打開 DMA 傳輸完成的中斷。 
下面的是啟動 DMA 傳輸,利用定時器的更新事件(TIM_UP 指定時器的周期,TIM_CH1 指占空比)去觸 發 DMA 傳輸數據。
這兒傳輸的方向是將 aSRC_Buffer 數組中數值,逐個向 TIM_DAMBase_CR1 寄存器中寫入,控制定 
時器的計數使能位,達到控制 PWM 個數的目的。
BUFFER_SIZE 的數值為 6,目的是產生 6 個脈沖。 運行程序:
|