版本 ad5635191d382ee45758d765360f5caf5b6cd16f
Pulse-Width Modulation (PWM)
Introduction
- Pulse-Width Modulation, 又稱pulse-duration modulation(PDM),其利用在頻率不變的狀態下, 改變工作週期大小, 使整體平均電壓值上升或下降, 藉此間歇性電壓及功率切換以節省能源及控制等效果.
.. image:: /PWM_intr.PNG
PWM會較省電的原因 因為一般類比電壓要降低電壓輸出需靠增加電阻,源頭輸出電壓“持續”都為同一電壓,不過利用電阻改變最後輸出電壓,而PWM他靠的是一段時間內輸出的頻率來模擬類比電壓,“不需要持續的輸出”,故不會將電浪費在電阻上,即可達到省電效果。
STM32內部要產生PWM訊號時,需要透過Timer來實現。
Clock control
在學習Timer前, 先瞭解系統clock是如何產生的, 以及給Timer的clock值.
A part of clock tree
[#]_
.. [#] Clock tree<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 212
.. image:: /Timer_clock.png
- 我們使用Crystal resonator作為外部震盪, 其頻率為8Hz(由STM32f4 discovery user manual 可知)
[#]_
.. [#] system_stm32f4xx.c<https://github.com/PJayChen/STM32f4_discovery_TIM_PWM_Output/blob/master/TIM_PWM_Output/system_stm32f4xx.c>
_
APBx timer clocks 計算
參閱system_stm32f4xx.c
line 341 RCC->CR |= ((uint32_t)RCC_CR_HSEON);
- enable HSE(High Speed External clock)
line 374 ~ 379 配置與啟動PLL
line 146 ~ 151, 可知
- PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
- SYSCLK = PLL_VCO / PLL_P
- 並定義 PLL_M = 8, PLL_N = 336, PLL_P = 2 而外部晶體頻率為8MHz
- -> PLL_VCO = (8MHz / 8) * 336 = 336MHz
- -> SYSCLK = 336MHz / 2 = 168MHz
line 365 RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
- 此行設定HCLK(High speed external clock signal) = SYSCLK / 1 = 168MHz
line 372 RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
- 此行設定APB1 peripheral clocks為 HCLK / 4 = 42MHz
而由上圖可知
APB1 timer clocks = APB1 peripheral clocks * 2 = 84MHz
該clock亦為後面Timer章節提及的 CK_INT 之值
Timers
Timer 和 RTC的差別
- Timer可被用於多種用途, 其中包含量測輸入訊號之pulse寬度, 或產生輸出波形。
- Real-Time Clock(RTC)是負責記錄時間的專用積體電路,出現在需要長期使用時鐘的電子設備中。[#]_
.. [#] RTC introducion<http://wiki.csie.ncku.edu.tw/embedded/RTC#introduction>
_
Basic timers 基本定時器(TIM6 和 TIM7)
[#]_
.. [#] TIM6 和 TIM7<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 678
具有 16-bit auto-reload upcounter driven by a programmable prescaler
用途: Synchronization circuit to trigger the DAC(內部連接至DAC)
Advanced-control timers 高級控制定時器(TIM1 和 TIM8)
[#]_
.. [#] TIM1 和 TIM8<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 507
具有 16-bit up, down, up/down auto-reload counter driven by a programmable prescaler which allowing dividing the counter clock frequency either by any factor between 1 and 65536(2^16).
用途: 最多有四個獨立通道可用於input capture, output compare, PWM generation(Edge and Center-aligned Mode) and one-pulse mode output.
與TIM2&TIM5之差異: 可以 Break input to put the timer’s output signals in reset state or in a known state
General-purpose timers 通用定時器(TIM9 to TIM14)
[#]_
.. [#] TIM9 to TIM14<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 637
具有16-bit auto-reload up counter.
以及16-bit programmable prescaler used to divide the counter clock frequency by any factor between 1 and 65536.
用途: 最多有兩個獨立通道可用於 input capture, output compare, PWM generation(Edge and Center-aligned Mode) and one-pulse mode output.
General-purpose timers 通用定時器(TIM2 to TIM5)
[#]_
.. [#] TIM2 to TIM5<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 576
具有16-bit (TIM3 & TIM4) or 32-bit (TIM2 & TIM5) up, down, up/dowm auto-reload counter.
以及16-bit programmable prescaler used to divide the counter clock frequency by any factor between 1 and 65536.
用途: 最多有四個獨立通道可用於 input capture, output compare, PWM generation(Edge and Center-aligned Mode) and one-pulse mode output.
Block diagram
.. image:: /BD of GP timer.png
clock來源 :
Internal clock(CK_INT)
External clock mode1: external input pin(TIx)
External clock mode2: external trigger input(ETR) available on TIM2, TIM3 and TIM4 only
Internal trigger inputs(ITRx): 使用另一個timer作為prescaler來產生除頻後之clock
Counter Modes
[#]_
.. [#] Counter Modes<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 579
Registers
TIMx_CNT: Counter Register, 計數器目前數到的值
TIMx_PSC: Prescaler Register (software R/W), 除頻數
TIMx_ARR: Auto-Reload Register (software R/W), 存放計數起始(下數)或最大(上數)值
UEV: 當計數器overflow or underflow, 將會產生update event(UEV), 此時會把 Auto-Reload Register (software write)內容放入 Auto-Reload shadow register (hardware write)
auto-reload preload enable bit(ARPE) in the TIMx_CR1 register之值設定是否直接放入shadow register,
ARPE = 0 直接把值轉入shadow register,
ARPE = 1 UEV產生時才將值轉入shadow register
Prescaler Description
[#]_
.. [#] Clock tree<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 578
.. code-block:: prettyprint linenums
TIM_TimeBaseInitStruct.TIM_Prescaler = PRES_VALUE - 1;
可除頻範圍1 ~ 65536(Set it in TIMx_PSC register)
example: prescaler control register設為1,但須等 update event產生才會載入至prescaler buffer, 因此下一個計數週期才會依據該值來除頻.
.. image:: /Timer_prescaler_description.PNG
Upcounting mode
.. code-block:: prettyprint linenums
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
由0數至TIMx_ARR register之值, 然後再回到0並產生overflow event(update event), 此時auto-reload shadow register將會更新為TIMx_ARR之值.
- 可藉由設定UDIS bit = 1來關閉UEV, 可用於避免正在更改preload register內容時, 剛好發生UEV而將舊的值轉移至shadow register中
Example: TIMx_ARR = 0x36, prescaler buffer = 1
.. image:: /Timer_upcounting.png
- Example: TIMx_ARR = 0x36, ARPE = 0
.. image:: /Timer_upcount_ARPE0.PNG
- Example: TIMx_ARR = 0x36, ARPE = 1
.. image:: /Timer_upcount_ARPE1.PNG
UEV(clear by hardware) occurs every time an overflow occurs, and UIF is a flag triggered when overflow occurs, if you don’t clean the flag, it will remain triggered(clear by software).
Downcounting mode
.. code-block:: prettyprint linenums
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down;
.. image:: /countdown.png
Center-aligned mode
.. code-block:: prettyprint linenums
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
.. image:: /center_aligned.png
Functional Modes
Input capture mode
[#]_
.. [#] Input capture mode<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 592
- 目的 : 用來計算某外部信號特定狀態發生的時間點
- 用途 : 脈波寬測量, 頻率量測
- 可以設定外部觸發信號的型式,並使用外部觸發(ICx signal)來觸動一個Timer的栓鎖動作,這時候counter計數值則會存入TIMx_CCRx暫存器。
PWM input mode
[#]_
.. [#] PWM input mode<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 593
- 為Input capture mode的一個特例,此模式能夠量測到TI1上的PWM訊號週期(存於TIMx_CCR1暫存器)和工作週期(存於TIMx_CCR2暫存器),所以會使用到兩個通道。
Forced output mode
[#]_
.. [#] Forced output mode<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 594
.. code-block:: prettyprint linenums
TIM_OCInitStruct.TIM_OCPolarity = TIM_ForcedAction_InActive
TIM_OCInitStruct.TIM_OCPolarity = TIM_ForcedAction_Active
- 在輸出模式下,輸出比較信號能夠直接由軟體強制設為有效(active)或是無效(inactive)的狀態,而無視輸出比較暫存器和計數器之間的比較結果。
.. image:: /timer output stage.PNG
TIMx_CCMRx = 100 -> force inactive level -> ocxref force low
TIMx_CCMRx = 101 -> force active level -> ocxref force high
而OCx又會受到CCxP bit (TIM_OCPolarity)影響
- CCxP = 0 (TIM_OCPolarity = TIM_OCPolarity_Low) -> OCx = ocxref (default)
- CCxP = 1 (TIM_OCPolarity = TIM_OCPolarity_High) -> OCx = !ocxref
- 對應
.. code-block:: prettyprint linenums
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
Output compare mode
[#]_
.. [#] PWM input mode<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 594
.. code-block:: prettyprint linenums
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Toggle
- 此項功能是用來控制一個輸出波形或是用來指示一段給定的時間已到。
Detail of OC1M[2:0] in the TIMx_CCMR1 Register
[#]_
.. [#] TIMx_CCMR1<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 621
.. image:: /OC1M(output compare mode).png
PWM mode
[#]_
.. [#] PWM mode<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 595
目的 : 產生一個由TIMx_ARR暫存器決定頻率、由TIMx_CCRx暫存器決定工作週期的PWM信號。
PWM configuration
TIM_Prescaler : 將TIMxCLK除以(TIM_Prescaler + 1)
TIM_CounterMode : 選擇計數模式
TIM_Period : TIMx_ARR,counter 週期
TIM_OCPolarity: 設置輸出極性
TIM_OCMode: PWM模式
PWM 1 Mode :
- 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為1,否則輸出為0;
- 在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為0,否則輸出為1。
PWM 2 Mode :
- 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為0,否則輸出為1;
- 在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為1,否則輸出為0。
TIM_Pulse: 即TIMx_CCRx暫存器,設定脈衝寬度
輸出脈波週期 = (TIM_Period + 1) * (TIM_Prescaler + 1) / TIMxCLK
Example: PWM mode 1, 向上計數並以LED為例:
.. image:: /timer.png
TIM_Prescaler = 500-1, TIM_Period = 1680-1 , TIMxCLK = 84MHz
輸出脈波週期 = (TIM_Period + 1) * (TIM_Prescaler + 1) / TIMxCLK
= ( 1680 - 1 +1 ) * ( 500 - 1 + 1 ) / 84000000 = 0.01s(100Hz)
0.01 s 遠小於人眼視覺暫留的時間(0.1~0.4s),因此上圖的PWM 1 duty cycle(75%)>PWM 2 duty cycle(25%),PWM 1 Mode看起來會比PWM 2 Mode亮。
Example: PWM mode 1, 中央對齊計數方式:
.. image:: /中央對齊.png
PWM realize ADC and DAC
[#]_
.. [#] PWM實現ADC與DAC<http://www.xjtudll.cn/Exp/143/>
_額外補充
PWM realize ADC :
.. image:: /PWM實現ADC.png
principle brief:
利用PWM可控制duty_cycle之特性,配合電阻和電容的濾波電路即可產生小於VDD之任意電壓值( U1= 5* ( D1 / (D1+D2) ) )。
再利用OPA比較類比輸入和PWM所產生的輸入壓即可得知現在所輸入類比訊號值。
RC value design:
.. image:: /RC值設計.png
.. image:: /RE值設計2.png
ADC transform :
- 首先讓PWM的duty_cycle從小開始增大(即是控制RCC暫存器從小到大),當PWM所產生的電壓小於類比輸入則OPA輸出依然都是正值,而一當PWM所產生的電壓大於類比的輸入OPA即會變輸出負值,而由負轉正的瞬間RCC所存的值即是我們所要求的數位電壓值。
- ADC之解析度則是由控制PWM的duty_cycle的暫存器大小而決定,EX:STM32 TIM4 的RCC為16bit 而AD解析度就為16bit。
featrue of PWM realize ADC:
- 利用RC濾波會產生漣波誤差,因此ADC的經度較不準。
- PWM產生和RC濾波都需要時間因此其ADC轉換較慢,較適合ADC轉換速率不高的產品。
- 由於U1電壓是由小加到大,因此電壓較小的類比訊號會較快轉換(即取樣頻率不固定)。
- AD轉換頻率可藉由加快加單晶片速度而提升。
PWM realize DAC:
.. image:: /PWM實現DAC.png
principle brief:
觀念和利用PWM實現AD相同,利用RC濾波電路將不同duty cycle的PWM訊號轉類比訊號,只是其OPA當作一電壓隨偶器。
電壓隨偶器 : 電壓不變傳到下一級
Code_section
[#]_
.. [#] Demo Codes main.c<https://github.com/PJayChen/STM32f4_discovery_TIM_PWM_Output/blob/master/TIM_PWM_Output/main.c>
_
RCC_Configuration
.. code-block:: prettyprint linenums
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOD , ENABLE );//Enalbe AHB for GPIOD
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE );//Enable APB for TIM4
GPIO_Configuration
.. code-block:: prettyprint linenums
GPIO_InitTypeDef GPIO_InitStructure;//Create GPIO_InitStructure
GPIO_StructInit(&GPIO_InitStructure); // Reset GPIO_structure
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4); // set GPIOD_Pin12 to AF_TIM4
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4); // set GPIOD_Pin13 to AF_TIM4
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4); // set GPIOD_Pin14 to AF_TIM4
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4); // set GPIOD_Pin15 to AF_TIM4
// Setup Blue & Green LED on STM32-Discovery Board to use PWM.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; //PD12->LED3 PD13->LED4 PD14->LED5 PD15->LED6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Alt Function - Push Pull
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOD, &GPIO_InitStructure );
TIM_Configuration
.. code-block:: prettyprint linenums
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//Create TIM Time Base Init structure
TIM_OCInitTypeDef TIM_OCInitStruct;//Create TIM Output Compare Init structure
// Let PWM frequency equal 100Hz. ( 84MHz / 1680 /500 = 100Hz )
// Let period equal 1600. Therefore, timer runs from zero to 1600.
TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );//reset TIM_TimeBaseStructInit
TIM_TimeBaseInitStruct.TIM_Period = 1680 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 500 - 1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
TIM_OCStructInit( &TIM_OCInitStruct );//reset TIM_OCStructInit
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
// TIM4_CCR register (16 bits). Value can range from zero to 65535.
// TIM_Pulse = Compare Capture register(CCR) = 1680 ( duty_cycle = 100%)
TIM_OCInitStruct.TIM_Pulse = 1680; //(0=Always Off, >1680 =Always On)
TIM_OC1Init( TIM4, &TIM_OCInitStruct ); // set TIM_OCInitStruce to TIM4_channel1
TIM_OC2Init( TIM4, &TIM_OCInitStruct ); // set TIM_OCInitStruce to TIM4_channel2
TIM_OC3Init( TIM4, &TIM_OCInitStruct ); // set TIM_OCInitStruce to TIM4_channel3
TIM_OC4Init( TIM4, &TIM_OCInitStruct ); // set TIM_OCInitStruce to TIM4_channel4
TIM_Cmd( TIM4, ENABLE ); //Enables TIM4 peripheral
PWM control
.. code-block:: prettyprint linenums
while(1) // Do not exit { if(brightness + n <= 0) who_run = (who_run + 1) % 4;
if (((brightness + n) >= 3000) || ((brightness + n) <= 0))
n = -n; // if brightness maximum/maximum change direction
brightness += n;
//Light LEDs in turn
switch(who_run){
case 0:
TIM4->CCR1 = brightness - 1; // set brightness
break;
case 1:
TIM4->CCR2 = brightness - 1; // set brightness
break;
case 2:
TIM4->CCR3 = brightness - 1; // set brightness
break;
case 3:
TIM4->CCR4 = brightness - 1; // set brightness
break;
}
for(i=0;i<10000;i++); // delay
}
return(0); // System will implode }
Demo video
輪流點亮LED <http://youtu.be/ygELIXJFHM8>
_透過PWM使MOTOR達到快慢快慢變化 <http://youtu.be/bFRWfXI_k5Q>
_
補充
PWM先高後低和先低後高 在Motor上表現有什麼差別?
- 在Motor剛要啟動時,因為先高後低是在duty cycle的前半段先供電,而先低後高則是到duty cycle的後半段才供電,在Motor的表現上 先高後低的啟動速度會比先低後高還要快一點
可變電阻分為兩類(variable resistor):
(1)可變電阻器:電阻可調整。
(2)半可變電阻器:為調整電阻後可以固定。
用處:
(1)可變電阻:用於阻值需要常常改變的電路用, 像音量控制, 搖桿, 類比指針式三用電表的最大值調整等.
(2)半可變電阻:多用於微調用或一次設定好後除非又偏差才需要調整的電路, 像類比指針式三用電表的歸零值調整等.
Reference <http://www.wretch.cc/blog/ltivsled/22468459>
_
Clock Tree
- Clock Tree 是把 Clock Source 分配到每個Device讓它的Skew minimize
.. image:: /ClockTree_SYSCLK.PNG
為保證所有周邊裝置能夠得到期望的頻率, 所以先將頻率倍頻至最高需求頻率(Ethernet PTP clock), 其餘周邊裝置再除頻至所需之clock.
先倍頻在除頻係因倍頻與除頻的電路設計上的差異, 因PLL設計較為複雜, 而prescaler則以counter即可實現, 所以設計上不會直接將Oscillator產生之頻率倍頻至各裝置所需之頻率.
.. image:: /before PLL.PNG
[#]_
.. [#] N倍頻電路</N倍頻電路.ppt>
_
PLL之前要先除頻原因為
在頻率合成器中,只用除頻器並不足以產生適當的頻率,必須配合 N 倍頻電路才能產生更多樣的輸出頻率。
例如以10 MHz 之參考頻率,若只用除頻器是無法獲得 3 MHz, 4 MHz, 6 MHz, 7 MHz, 8 MHz, 9 MHz 等頻率,然而若搭配 N 倍頻電路,則要產生上述頻率並不困難
TIx XOR
[#]_
.. [#] ITx XOR<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>
_ p. 602
.. image:: /Tim_input_xor.PNG
The TI1S bit in the TIMx_CR2 register, allows the input filter of channel 1 to be connected to the output of a XOR gate, combining the three input pins TIMx_CH1, TIMx_CH2 and TIMx_CH3.
The XOR output can be used with all the timer input functions such as trigger or input capture.
An example of this feature used to interface Hall sensors is given in Section 13.3.18 below.
Setup Time
.. image:: /part of counter wave.PNG
Ref. 數位IC設計, 陳培殷教授, slide 40, 41 <http://dic.csie.ncku.edu.tw/vlsi_2013/CHAPTER-5.pdf>
_
.. image:: /DFF_setup_time.PNG
範例程式
輪流點亮LED <https://github.com/PJayChen/STM32f4_discovery_TIM_PWM_Output>
_藉由button改變duty cycle <https://gitcafe.com/embedded2012/P-coolod/blob/master/Lab-6/discoveryF4/GPIO_test/main.c>
_
此程式碼利用PB4 5作Output pin持續輸出高態電壓,PA2 3作Input Pin接收來在output pin的電壓輸入,並設定負緣觸發中斷,中斷觸發以改變duty cycle佔空比,電壓高低態變化則利用外接button,當按下button則電壓 高->低 ,PA2 3接收到變化便會觸發中斷,透過改變Timer來做duty cycle佔空比的改變,以達到LED亮暗改變.(以下圖說明)
.. image:: /embedded/PWM-GPIO_test_Explain_figure.png
Reference
Website
Shadow register <http://blog.csdn.net/scarlettsp/article/details/6656588>
_Wikipedia-PWM<http://en.wikipedia.org/wiki/Pulse-width_modulation>
_TIM_ClockDivision功用說明<http://blog.sina.com.cn/s/blog_76c545390100ovfj.html>
_PWM實現ADC與DAC<http://www.xjtudll.cn/Exp/143/>
_UNIVERSITA' DI BOLOGNA 的Timer 教材<http://www-micrel.deis.unibo.it/LABARCH/slidecorso2013/Lab4_2013.pdf>
_
Books
- Keil MDK ARM 原理與實作,MDK研究團隊編著,台科大圖書。
- 陳志旺(2012),STM32 嵌入式微控制器快速上手,中國:電子工業出版社。 P.155 8.3.3 計數器模式