分享到plurk 分享到twitter 分享到facebook

版本 07d35ea971496b1d6f5e303194cb0ab5ab671972

embedded/PWM

Changes from 07d35ea971496b1d6f5e303194cb0ab5ab671972 to current

---
title: Pulse-Width Modulation (PWM)
toc: yes
...

Introduction
============
- Pulse-Width Modulation, 又稱pulse-duration modulation(PDM),其利用在頻率不變的狀態下, 改變工作週期大小, 使整體平均電壓值上升或下降, 藉此間歇性電壓及功率切換以節省能源及控制等效果.
- Pulse-Width Modulation, 又稱pulse-duration modulation(PDM),是將脈波轉為類比信號的"一種技術",利用在頻率不變的狀態下, 改變工作週期大小, 使整體平均電壓值上升或下降, 藉此間歇性電壓及功率切換以節省能源及控制等效果.

.. image:: /PWM_intr.PNG
- 因PWM需要透過Timer來實現, 後面會稍作簡介
![](/PWM_intr.PNG)

-  duty cycle
  在一個信號週期裡,代表1的正脈衝的持續時間與脈衝總周期的比值。舉例來說,發出訊號1秒鐘,之後99秒沒有訊號,這是一個週期;之後又是發出一秒鐘的訊號,如此循環下去。而該訊號的工作週期就是1/(1+99)=1%。 

- PWM會較省電的原因
   因為一般類比電壓要降低電壓輸出需靠增加電阻,源頭輸出電壓"持續"都為同一電壓,不過利用電阻改變最後輸出電壓,而PWM他靠的是一段時間內輸出的頻率來模擬類比電壓,"不需要持續的輸出",故不會將電浪費在電阻上,即可達到省電效果。

- STM32內部要產生PWM訊號時,需要透過Timer來實現。 

Clock control
==============
- 在學習Timer前, 先瞭解系統clock是如何產生的, 以及給Timer的clock值.

- A part of clock tree (STM32F407xx Reference mamual  - p. 576)
- A part of clock tree

.. image:: /Timer_clock.png
[#]_

- HSE clock (High speed external clock signal)
.. [#] [ Clock tree](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 212

我們使用Crystal resonator作為外部震盪, 其頻率為8Hz(由STM32f4 discovery user manual 可知)
![](/Timer_clock.png)

- 我們使用Crystal resonator作為外部震盪, 其頻率為8MHz(由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
  - 參閱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 = SYSCLK / 1 = 168MHz
       - 此行設定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** 之值

PLL(Phase-Lockedloop) 鎖相迴路
----------------------------------------

![](/embedded/pll.png)

若 Fin 訊號為一頻率參考訊號,Fdout 為除頻器的輸出訊號,PLL(Phase-Lockedloop)的動作就是藉由相位頻率偵測器(PFD)偵測其兩訊號的相位差(領先或落後),然後再將此訊息送進電荷充放器。電荷充放器會根據此領先或落後的訊號下達充電或放電的命令,接著訊號經過低通濾波器後將會轉換成一低頻的控制電壓以改變壓控震盪器的震盪頻率,再經由除頻器作除頻動作後,回授給相位頻率偵測器,也就是藉著這些一次次的回授動作而使輸出到達一個穩定的頻率。


Timer 與 counter的差異
----------------------------------------

- timer與counter的差別:本質上timer和counter幾乎是一樣的東西,底層都是一個硬體counter,如果是按照規律的時間跳表,那就是timer;如果是按照不規律的事件訊號跳表,那就是counter
  

Timers
=======

Basic timers 基本定時器(TIM6 和 TIM7)
- 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.
- 用途: 最多有**四個**獨立通道可用於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.  
- 用途: 最多有**兩個**獨立通道可用於 input capture, output compare, PWM generation(Edge and Center-aligned Mode) and one-pulse mode output.  

General-purpose timers 通用定時器(TIM2 to TIM5) (STM32F407xx Reference mamual  - p. 576)
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.  
- 用途: 最多有**四個**獨立通道可用於 input capture, output compare, PWM generation(Edge and Center-aligned Mode) and one-pulse mode output.  


Clock Selection
------------------------------------------------------

- Block diagram
  - in Adavanced-control timers & General-purpose timers
![](/BD)of GP timer.png

.. image:: /BD of GP timer.png
- TIMx_CHx
  - 每個TIMER會對應到4個channel,這些channel會mapping到STM32F429上面的pin腳
  - 這裡以TIM4為範例 對應到STM32上的腳位分別是PD12、PD13、PD14、PD15   Reference 

- clock來源 : 內部clock(CK_INT)、外部clock模式1(TIx)、外部clock模式2(ETR)、內部觸發輸入(ITRx)。
   
- Counter modes (STM32F407xx Reference mamual  - p. 579)    
![](/TIM_CHx.png)

Counting Mode
- clock來源 : 
  
  - Internal clock(CK_INT)
    - HSI (High-Speed Internal):16MHz,RC電路
    - SMS = 000 (in TIMx_SMCR)

  - External clock mode1: external input pin(TIx)
    - 在input每次的rising or falling edge時 counter 計數
    - SMS = 111 (in TIMx_SMCR)
    - 此時利用到SMCR的TS[2:0]來選擇輸入源
    - ITR0.1.2.3, TI1 Edge Detector , TIFP1 , T2FP2 , ETRF

![](/ITR.jpg)

  - External clock mode2:
    - 在input每次的rising or falling edge時 counter 計數
    - ECE=1(in TIMx_SMCR external clock enable)
    - input來源為ETRF signal (external trigger filtered)

  - Internal trigger inputs(ITRx): 
    - 使用另一個timer作為prescaler來產生除頻後之clock
    - 舉例 : 用Timer 1 的(update event)當做Timer 2 的prescaler

![](/ITRx.png)

Counter Modes
=============
[#]_

up counting mode
----------------
.. code-block:: prettyprint linenums
.. [#] [ 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   (software R/W, even when the counter is running), 計數器目前數到的值

- TIMx_PSC: Prescaler Register   (software R/W, even when the counter is running), 除頻數

- TIMx_ARR: 16-bit Auto-Reload Register   (software R/W, even when the counter is running), 存放計數起始值(下數)或最大值(上數)。如果value = null,則counter會被block住。

- 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 ,TIMx_ARR is not buffered (直接把值轉入shadow register), 

    - ARPE = 1 ,TIMx_ARR is buffered (UEV產生時才將值轉入shadow register)

- Repetition counter在下列三種情況下會遞減:遞減了(TIMx_RCR+1)次,就會觸發update event(UEV)
 1. edge-aligned 上數時,發生overflow
 2. edge-aligned 下數時,發生underflow
 3. center-aligned mode, overflow 或 underflow

![](/embedded/Timer_UEV_and_RCR_relation_example.png)

 - Update Event(UEV)發生時會做的事情有:
    1. 會把所有的reg. update
        - 把preload value(RCR) 載入到 repetition counter
        - 把preload value(ARR) 載入到 auto-reload shadow reg.
        - 把preload value(PSC) 載入到 the buffer of the prescaler

    2. set update flag(UIF in SR  reg) 

 - Update Event (UEV)發生的時機:
    - 由UDIS(開關)及URS(發生時機)決定
        1. UDIS:
          - UDIS = 0, update enable 
            - preload value 會被載入至 shadow registers

          - UDIS = 1, update disable
            - 不產生update event , shadow registers 保持原本的值(ARR,PSC,CCRx)。
            - 但如果此時UG = 1, counter及prescaler還是會reiniitialized(重新計數的意思,重新開始)

        2. URS:
          - URS = 0, 
            - 計數時,發生overflow或是underflow
            - setting UG(update generation) : UG bit 可以透過sw來設定(auto cleared by hw)
              - UG = 1, reinitialize the counter and generates an update of the reg.(重新計數的意思,重新開始)
            - update generation through slave mode controller

          - URS=1,
            - 只有發生overflow或是underflow才會產生update interrupt

Prescaler Description
-----------------------

[#]_

.. [#] [ Clock tree](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 578

```c   
   TIM_TimeBaseInitStruct.TIM_Prescaler = PRES_VALUE - 1; 
```

- 可除頻範圍1 ~ 65536(Set it in TIMx_PSC register)

- example: prescaler control register設為1,但須等 update event產生才會載入至prescaler buffer, 因此下一個計數週期才會依據該值來除頻.

![](/Timer_prescaler_description.PNG)

Upcounting mode
----------------
```c
   TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; 
```

.. image:: /Timer_upcounting.png
- 由0數至TIMx_ARR register之值, 然後再回到0並產生overflow event(update event), 此時auto-reload shadow register將會更新為TIMx_ARR之值.
   
  - 可藉由設定UDIS bit = 1來關閉UEV, 可用於避免正在更改preload register內容時, 剛好發生UEV而將舊的值轉移至shadow register中
########

down counting mode
------------------
.. code-block:: prettyprint linenums
- Example: TIMx_ARR = 0x36, prescaler buffer  = 1

![](/Timer_upcounting.png)
########

- Example: TIMx_ARR = 0x36, ARPE = 0

![](/Timer_upcount_ARPE0.PNG)
########

- Example: TIMx_ARR = 0x36, ARPE = 1

![](/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
------------------
```c
   TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down; 
```

.. image:: /countdown.png
![](/countdown.png)

center aligned mode
Center-aligned mode
-------------------
.. code-block:: prettyprint linenums

```c
   TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_CenterAligned1; 
```

.. image:: /center_aligned.png
![](/center_aligned.png)

Timer Mode
==========
Functional Modes
=================

Input capture mode
------------------
當一個input capture事件發生,TIMx_CCR會儲存觸發訊號當下的counter值,並且CCxIF (interrupt flag)會被硬體自動設定為1,代表發生了input capture事件。這時,我們可以設定中斷處理或DMA request。

[#]_

.. [#] [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暫存器),所以會使用到兩個通道。
- 我們可以透過此mode來得知input 進來的PWM period 及 duty cycle
  - 設定有三件事情要注意:

    1. Two ICx signals are mapped on the same TIx input.(下面的例子就是都map到 Tl1 )

    2. These 2 ICx signals are active on edges with opposite polarity. (兩個負責儲存相反的極性(下面的例子CCR1 & 存active時的counter值,CCR2存inactive時的counter值)

    3. One of the two TIxFP signals is selected as trigger input and the slave mode controller is configured in reset mode.

- 由下圖可知,
  - 當TI1 active(拉起)時,IC1 會capture,CCR1就會儲存CNT當下的值(也就是4),
  - 然後接著,當TI1 inactive(降下)時,IC2 會capture,CCR2就會儲存CNT當下的值(也就是2)。
  - 這樣我們可以由CCR1得知pwm的period從CCR2得知pwm的duty cycle。

![](/embedded/Timer_pwm_input_mode.png)

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

```c
    TIM_OCInitStruct.TIM_OCPolarity = TIM_ForcedAction_InActive
    TIM_OCInitStruct.TIM_OCPolarity = TIM_ForcedAction_Active
```

- 在輸出模式下,輸出比較信號能夠直接由軟體強制設為有效(active)或是無效(inactive)的狀態,而無視輸出比較暫存器和計數器之間的比較結果。

- 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
    - 對應

```c
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
```

Output compare mode
-------------------
[#]_

**PWM mode**
.. [#] [PWM input mode](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 594

```c
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Toggle
```

- 用來控制你想要輸出的訊號或是用來指示一段給定的時間已到。

- 在此模式下,UEV對OCxREF、OCx是沒有作用的。

- pwm mode(綠色框框內)又可分為PWM mode 1 & PWM mode 2

[#]_

.. [#] [TIMx_CCMR1](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 621

![](/embedded/OC1M(output)compare mode).png


**PWM mode:分為 edge-aligned & center-aligned mode**

------------

[#]_

.. [#] [PWM mode](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 595

- PWM edge-aligned mode

  - OCxREF即是我們要輸出的pwm訊號。
  
  - interrupt flag:CNT matches CCR
 
  - CCR > ARR時,上數發生overflow時或在下數發生underflow時。

  - 下圖是PWM1(由CCMR的OC1M決定), 上數(由CR1的DIR bit決定):

![](/embedded/Timer_EdgeAligned_PWM_ARR8.png)

 - 在此PWM edge-aligned mode下,有一個要注意的地方:
    - 當設定為PWM2且下數時,會無法產生出 0% PWM。

- 目的 : 
    - 產生一個由TIMx_ARR暫存器決定頻率:PWM Frequency = counter clock / (auto reload value(TIMx_ARR)+1)
    - 由TIMx_CCRx暫存器決定工作週期的PWM信號:PWM Duty Cycle = compare reg. value(TIMx_CCRx)*100 / (auto reload value(TIMx_ARR)+1)

- PWM center-aligned mode
  - OCxREF即是我們要輸出的pwm訊號。
  - TIMx_CR1 的 CMS 能決定interrupt flag(CCxIF)要在何時立起來(set to 1)
    - interrupt flag:
               1. CNT matches CCR
               2. CCR > ARR時,上數發生overflow時或在下數發生underflow時。

  - 下圖一樣是 PWM mode 1,但為 center-aligned mode(即上數完下數,下數完上數)

![](/embedded/Timer_CenterAligned_PWM_ARR8.png)

- PWM configuration

     - TIM_ClockDivision  - 採樣頻率基準,當連續採樣到N個有效電平時,才當作一次有效電平。
     - TIM_Prescaler  :  將TIMxCLK除以(TIM_Prescaler + 1)

     - TIM_Prescaler  -  將TIMxCLK除以(TIM_Prescaler+1)
     - TIM_CounterMode  :  選擇計數模式

     - TIM_CounterMode  -  選擇計數模式
     - TIM_Period  :  TIMx_ARR,counter 週期

     - TIM_Period  -  TIMx_ARR,counter 週期
     - TIM_OCPolarity: 設置輸出極性 

     - TIM_OCMode  - PWM模式
     - TIM_OCMode: PWM模式

       - PWM 1 Mode : 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為1,否則輸出為0;在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為0,否則輸出為1。
       - PWM 1 Mode : 

       - PWM 2 Mode : 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為0,否則輸出為1;在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為1,否則輸出為0。
         - 在向**上**計數,**TIMx_CNT<TIMx_CCRx**時,輸出為1,否則輸出為0;
         - 在向**下**計數,**TIMx_CNT>TIMx_CCRx**時,輸出為0,否則輸出為1。

     - TIM_Pulse  -  TIMx_CCRx,脈衝寬度
       - PWM 2 Mode : 

     - TIM_OCPolarity  -  設置輸出極性,例如:TIM_OCPolarity_High PWM輸出關閉時默認為低電位。 
         - 在向**上**計數,**TIMx_CNT<TIMx_CCRx**時,輸出為0,否則輸出為1;
         - 在向**下**計數,**TIMx_CNT>TIMx_CCRx**時,輸出為1,否則輸出為0。

     - TIM_Pulse:  即TIMx_CCRx暫存器,設定脈衝寬度
    
     - **輸出脈波週期 = (TIM_Period+1) * (TIM_Prescaler+1) * (TIM_ClockDivision+1) / TIMxCLK **
     - **輸出脈波週期 = (TIM_Period + 1) * (TIM_Prescaler + 1) / TIMxCLK **

  - 以LED為例:
- Example: PWM mode 1, 向上計數並以LED為例:

.. image:: /timer.png
![](/timer.png)

  - TIM_Prescaler = 500-1, TIM_Period = 1680-1 , TIMxCLK=84MHz
  - TIM_Prescaler = 500-1, TIM_Period = 1680-1 , TIMxCLK = 84MHz

  - 輸出脈波週期 = (TIM_Period+1) * (TIM_Prescaler+1)  / TIMxCLK
  - 輸出脈波週期 = (TIM_Period + 1) * (TIM_Prescaler + 1)  / TIMxCLK
           
    -         = (1680-1+1) * (500-1+1) /84000000 = 0.01 s(100Hz)
    -         = ( 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, 中央對齊計數方式:

![](/中央對齊.png)


PWM realize ADC and DAC
=======================
[#]_

.. [#] [PWM實現ADC與DAC](http://www.xjtudll.cn/Exp/143/)額外補充

PWM realize ADC :
-------------------

![](/PWM實現ADC.png)

- principle brief:

     - 利用PWM可控制duty_cycle之特性,配合電阻和電容的濾波電路即可產生小於VDD之任意電壓值( U1= 5* ( D1 / (D1+D2) ) )。

     - 再利用OPA比較類比輸入和PWM所產生的輸入壓即可得知現在所輸入類比訊號值。


RC circuit's response to a PWM signal:
------------------------------------------

[#]_

.. [#] [What is the RC circuit's response to a PWM signal?](http://www3.nd.edu/~lemmon/courses/ee224/web-manual/web-manual/lab8a/node5.html)reference

![](/embedded/RC_equation.png)
![](/embedded/PWM_wave.png)
![](/embedded/response_of_PWM.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:
------------------

![](/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
```c
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB , ENABLE );//Enalbe AHB for GPIOB
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE );//Enable APB for TIM4
```

GPIO_Configuration
--------------------

.. code-block:: prettyprint linenums

```c
    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_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4); // set GPIOB_Pin6 to AF_TIM4
    
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6
    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 );  
    GPIO_Init( GPIOB, &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
```c
    void TIM_Configuration(void)
    {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM_OCInitStruct;

    // 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; 
    // Let PWM frequency equal 50Hz.
        TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV4;
    TIM_TimeBaseInitStruct.TIM_Period = 1680 - 1;   //84000000/1680*1000=50hz  20ms for cycle
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1000 - 1; 
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;    
    TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
    
    TIM_OCStructInit( &TIM_OCInitStruct );reset TIM_OCStructInit
    TIM_OCStructInit( &TIM_OCInitStruct );
    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
    // Initial duty cycle equals 0%. Value can range from zero to 65535.
    //TIM_Pulse = TIM4_CCR1 register (16 bits)
    TIM_OCInitStruct.TIM_Pulse = 0; //(0=Always Off, 65535=Always On)
 
    TIM_Cmd( TIM4, ENABLE ); //Enables  TIM4 peripheral
    TIM_OC1Init( TIM4, &TIM_OCInitStruct ); // Channel 1  LED
    
    TIM_Cmd( TIM4, ENABLE );
    }
```

-----------------------------------------------------------

PWM control
demo1 PWM_LED
--------------------

.. 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   
```c
  RCC_Configuration();
  TIM_Configuration();
  GPIO_Configuration();
	
  int n=1;
  int brightness=0;
	
  while(1)
  {	
    if (((brightness + n) >= 1680) || ((brightness + n) <= 0))
    n = -n; // if  brightness maximum/maximum change direction
  
    brightness += n;
    TIM4->CCR1 = brightness; // set brightness
    
    //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
    int i;
    for(i=0;i<200000;i++);  // about 1.6M instruction ->0.1sec
  }
```

-----------------------------------------------------------
 
  return(0); // System will implode
  }  
![](/pwm_servo_pic.png)

demo2 PWM_SERVO
--------------------

```c
  void demo2(void)
  {	
  volatile int i; 
  RCC_Configuration();
  TIM_Configuration();
  GPIO_Configuration();

   while(1)  // Do not exit
   {
   TIM4->CCR1=pulse; //ang0 //pulse=42
	
   for(i=0;i<30000000;i++);  
	
   //TIM4->CCR1=pulse+84; //ang90
   TIM4->CCR1=pulse+168; //ang180
	
   for(i=0;i<30000000;i++);  // delay
   }
  }
```

-----------------------------------------------------------

Demo video
==========
1. [伺服馬達 0~90度 ](https://www.youtube.com/watch?v=VqC9MU66_8A)
2. [伺服馬達 0~180度 ](https://www.youtube.com/watch?v=wWvxnqRv5_w)
3. [PWM呼吸燈 ](https://www.youtube.com/watch?v=cdTIS62fxU8)

補充
=============

* http://youtu.be/RHzLguvuOKY
* http://youtu.be/guG6MdLIwfI  (LED 3 4 5 6依序 亮-暗 轉換)
PWM先高後低和先低後高 在Motor上表現有什麼差別?
--------------------------------------------------

* http://youtu.be/ygELIXJFHM8
* http://youtu.be/jJfebbbMDPw  (透過外接 BUTTON 調整 LED亮度)
* http://youtu.be/bFRWfXI_k5Q  (透過PWM使MOTOR達到快慢快慢變化)
  - 在Motor剛要啟動時,因為先高後低是在duty cycle的前半段先供電,而先低後高則是到duty cycle的後半段才供電,在Motor的表現上 先高後低的啟動速度會比先低後高還要快一點

補充
=============
1. PWM較省電?
可變電阻分為兩類(variable resistor):
--------------------------------------

   因為一般類比電壓要降低電壓輸出需靠增加電阻,源頭輸出電壓"持續"都為同一電壓,不過利用電阻改變最後輸出電壓,而PWM他靠的是一段時間內輸出的頻率來模擬類比電壓,"不需要持續的輸出",故不會降電浪費在電阻上,即可達到省電效果。
   
   例如:使用9V電池來給一燈泡供電,連接電池跟燈泡時間為50ms,斷開電池和燈泡時間為50ms。1秒鐘(1000ms)過後,會重複此過程10次,燈泡將會連接到一個4.5V電池(9V電池的50%)上一樣。
- (1)可變電阻器:電阻可調整。

2. overflow 和 UEV UIF的關係
- (2)半可變電阻器:為調整電阻後可以固定。

    UEV occurs everytime an overflow occurs, and UIF is a flag triggered when overflow occurs, if you don't clean the flag, it will remain   triggered. 
![](/可變電阻.jpg)

3. 向上計數和向下計數的差別
- 用處:

   以四位元向上計數器為例,由四個JK正反器串接而成,輸出DCBA由0000依據二進位的變化至1111。下一個脈波來時,又回到0000。依此類推故此計數器可由0計數到15。而向下計數器與向上計數器不同點是下一級的CLK接於前一級的Q,輸出DCBA由1111向下計數到0000,待下一個時脈輸入時又變為1111,再依序變化。
  - (1)可變電阻:用於阻值需要常常改變的電路用, 像音量控制, 搖桿, 類比指針式三用電表的最大值調整等.

4. timer 和 RTC的差別
  - (2)半可變電阻:多用於微調用或一次設定好後除非又偏差才需要調整的電路, 像類比指針式三用電表的歸零值調整等.

    The system timer is what makes everything in the computer run at the same speed. 
- [Reference ](http://wiki.dzsc.com/info/7527.html)

    For example, your CPU won't look for a fresh batch of data while the Memory is still trying to feed it the last batch.The Real Time Clock tells the system what day/time it is.
Clock Tree
-----------

5. TIM_OCMode (timer output compare mode)
- Clock Tree 是把 Clock Source 分配到每個Device讓它的Skew minimize。
- 一般的邏輯閘fan out都有上限﹐一推20就可能會推不上去拉,所以需要長tree 1推10,每個再推10個.就像樹狀圖一樣,這就是clock tree。

.. image:: /TIM_OCMode.png
![](/ClockTree_SYSCLK.PNG)

6. PWM先高後低和先低後高 在步進馬達上表現有什麼差別?
- 為保證所有周邊裝置能夠得到期望的頻率, 所以先將頻率倍頻至最高需求頻率(Ethernet PTP clock), 其餘周邊裝置再除頻至所需之clock.

   在馬達剛要啟動時,因為先高後低是在duty cycle的前半段先供電,而先低後高則是到duty cycle的後半段才供電,在馬達的表現上 先高後低的啟動速度會比先低後高還要快一點
- 先倍頻在除頻係因倍頻與除頻的電路設計上的差異, 因PLL設計較為複雜, 而prescaler則以counter即可實現, 所以設計上不會直接將Oscillator產生之頻率倍頻至各裝置所需之頻率.

7. 改成中央對齊計數方式會怎麼樣?
![](/before)PLL.PNG

.. image:: /中央對齊.png
Reference
=============

- http://blog.csdn.net/scarlettsp/article/details/6656588 
- http://zh.wikipedia.org/zh-tw/%E8%84%88%E8%A1%9D%E5%AF%AC%E5%BA%A6%E8%AA%BF%E8%AE%8A
- http://ppt.cc/nIAF
- http://www.google.com.tw/url?sa=t&rct=j&q=pwm&source=web&cd=10&cad=rja&ved=0CFMQFjAJ&url=http%3A%2F%2Fwww.vr.ncue.edu.tw%2Fesa%2Fa1001%2FPWM.pdf&ei=S3OoUO6pOafcmAWWiIGQDw&usg=AFQjCNE_7pw6paGQzH7kSwkwD2witqcC-A
- http://hi.baidu.com/snic_k/item/0f045e3288e6683d2e20c42b
- 陳志旺(2012),STM32 嵌入式微控制器快速上手,中國:電子工業出版社。
- http://blog.sina.com.cn/s/blog_76c545390100ovfj.html
  
  P.155  8.3.3 計數器模式
[#]_

範例程式
=============
.. [#] [N倍頻電路](/N倍頻電路.ppt)

- https://github.com/PJayChen/STM32f4_discovery_TIM_PWM_Output
- PLL之前要先除頻原因為

  依序點亮LED
  - 在頻率合成器中,只用除頻器並不足以產生適當的頻率,必須配合 N 倍頻電路才能產生更多樣的輸出頻率。
      
  - 例如以10 MHz 之參考頻率,若只用除頻器是無法獲得 3 MHz, 4 MHz, 6 MHz, 7 MHz, 8 MHz, 9 MHz 等頻率,然而若搭配 N 倍頻電路,則要產生上述頻率並不困難

- https://gitcafe.com/embedded2012/P-coolod/blob/master/Lab-6/discoveryF4/TIM_PWM_Output/main.c
  
  此程式為依序更改 LED 3 4 5 6(利用PD12 13 14 15 作PWM應用)亮度 由暗漸漸轉亮 再由亮漸漸轉暗
TIx XOR
--------

- 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亮暗改變.(以下圖說明)
.. [#] [ITx XOR](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf) p. 602

.. image:: /embedded/PWM-GPIO_test_Explain_figure.png
![](/Tim_input_xor.PNG)

- XOR設置目的為:有三個輸入的信號(例如霍爾感測器)。
  - 霍爾感測器物理意義為電壓與磁力成正比,所以可以藉由霍爾感測器得出的電壓算出Motor的轉速。
  - 霍爾感測器將磁場的變化轉化為電壓的變化(換能器),可以量測磁場(有些只能量單極(S)有些可量雙極(S.N)),當帶有磁場之物體經過霍爾感測器時,會輸出電壓之變化 http://ppt.cc/qP~7 

Setup Time
-----------

![](/part)of counter wave.PNG

[Ref. 數位IC設計, 陳培殷教授, slide 40, 41 ](http://dic.csie.ncku.edu.tw/vlsi_2013/CHAPTER-5.pdf)

![](/DFF_setup_time.PNG)

Motor Principle
-------------------

![](/motor1.jpg)

- 直流有刷馬達

  - 電池正極(電刷)接通到右下側的鐵芯,而使右下側為N,左上為N,兩邊互相與永久磁鐵相斥,故鐵芯順時鐘旋轉

  - 當鐵芯過半旋轉,鐵芯N極與左永久電極相吸而使鐵芯旋轉至水平

  - 此時因集電環缺口與電刷接觸,鐵芯不帶有磁性,但因慣性定律而使鐵芯繼續順時針旋轉

  - 集電環與電刷再次接觸,鐵芯帶有磁性,根據安培右手定則(剛剛的N變為S,S變為N)依此類推以上4個步驟,鐵芯維持順時鐘旋轉

- 直流無刷馬達

  -有刷馬達的鐵芯(轉子)會跟著電流而造成磁場變化,左.右兩個永久磁鐵(定子)的N.S極固定 無刷馬達的鐵芯(轉子)的N.S極固定,左右兩線圈會隨著電流而有磁場變化

  - 當鐵芯的S極與霍爾感測計最接近(磁力最強)時,造成霍爾元件A端輸出較大電壓至電晶體,因超過BJT的空乏區而使左邊的電晶體導通(I1)故L1帶有磁性,右手定則L1的右側為S極,鐵芯逆時針旋轉(定子S.轉子N相互吸引)

  - 轉子的N.S極此時呈水平位置對霍爾元件的磁通密度下降,A.B兩端並不會輸出電壓,但因慣性定律轉子仍繼續旋轉(逆時鐘)。

  - 轉子的N極此時雨或爾元件最接近,造成B端輸出較大電壓倒通電晶體,L2線圈的左側呈現S極並與轉子的N極吸引,鐵心逆時鐘旋轉,依此類推以上3個步驟。


![](/motor2.jpg)


- 直流馬達 '有刷' . '無刷'比較

  - 直流馬達(DC Motor)的好處為在控速方面比較簡單,只須控制電壓大小即可控制轉速,但此類馬達不宜在高溫、易燃等環境下操作,而且由於馬達中需要以碳刷作為電流變換器(Commutator)的部件(有刷馬達),所以需要定期清理炭刷磨擦所產生的污物。無碳刷之馬達稱為無刷馬達,相對於有刷,無刷馬達因為少了碳刷與軸的摩擦因此較省電也比較安靜。製作難度較高、價格也較高。

Reference
=============

Website
--------

- [張晏甄同學hackpad Timer筆記 ](http://blog.csdn.net/scarlettsp/article/details/6656588)
- [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 計數器模式