---
# System prepended metadata

title: 'F2812的Event Manager : 比較與 PWM'
tags: [F2812]

---

[TOC]

# 前言
- 本篇以實現PWM輸出為目標，主要介紹EV_Timer的PWM輸出、和比較單元的PWM輸出，見 手把手12.2.5和12.3節
- 微處理器的比較功能可以在 timer 計時到特定時刻時翻轉電平，產生PWM波形
- F2812 最多可以有16個 PWM 輸出 Channel
- EV 可以有兩種PWM產生方法
    1. 使用 timer 內的比較暫存器
    2. 使用比較單元的比較暫存器，能進一步做到死區時間控制
- 這邊主要介紹timer 內的比較暫存器生成的PWM，比較單元的生成方式相同，只是相關控制與比較暫存器在比較單元內。

# PWM 簡介
-  基礎概念見[微處理器基礎](https://hackmd.io/6Rj1vNC5S2ya2y2MNScFbg?both#%E5%AE%9A%E6%99%82%E8%88%87%E8%A8%88%E6%99%82%E5%8A%9F%E8%83%BD)或自己查

## 生成原理
- 非對稱PWM波形
    - 藉由比較 Counter 和 Compare 的值輸出高或低電位，調整Compare的值可以調整Duty Cycle
    - 一個計時週期內的PWM波形不是對稱於週期中心
    - 計數模式使用<font color="red">up counting mode</font>
    - ![image](https://hackmd.io/_uploads/Hk4JfEEmJx.png)
- 對稱PWM波形
    - 輸出原理與上述相同
    - 因為Counter 計數方式改為 "上下數" 的模式，一個計時週期內的PWM波形對稱於週期中心
    - 計數模式使用 <font color="red">continuous up/down counting mode</font>
    - ![image](https://hackmd.io/_uploads/B1Y3fEN71e.png)

## 死區控制的PWM
- 這部分可自行參考<手把手教你DSP> 12.3

</br>
</br>

# 使用 timer 內的比較暫存器生成PWM

## 暫存器設定
- TxCON 暫存器的TECMPR位(bit 1)設為 1 可以使能比較功能 
- TxCMPR 暫存器儲存要比較的值
- GPTCONx 暫存器的TCMPOE位 設為1，可以使能比較輸出功能
- GPTCONx 暫存器的TxPIN位 決定PWM輸出極性
    - 低/高 電平有效表示計數值大於比較值時維持 低/高電平
    - 強制 高/低 就是一直維持 高/低 電平
    - ![image](https://hackmd.io/_uploads/rk7h4S471g.png)

# PWM輸出範例

## 設定流程
- 選擇EVB timer3 的比較暫存器輸出非對稱PWM，設定T3CON暫存器
    - 時鐘源選內部時鐘
    - 計數模式改為 up counting mode
    - timer3 預除頻設為1
    - 使能timer3的比較功能
    - 啟用timer3
- 設定T3PR暫存器，決定PWM的週期
- 設定GPTCONB 的TCMPOE位，使能比較輸出功能
- 把GPTCONB 的T3PIN位設為低電平有效，也就是當計數值大於比較值時，腳位輸出低電位
- 設定GPIO腳位為PWM輸出

## 範例程式
``` c++=
//======== GPTCONx Parameter ===========

    // Compare Output enable
    #define GPTIM_CO_ENABLE 1
    #define GPTIM_CO_DISABLE 0

    // Compare Polarity
    #define GPTIM_CP_FORCED_LOW 0
    #define GPTIM_CP_EFF_LOW 1
    #define GPTIM_CP_EFF_HIGH 2
    #define GPTIM_CP_FORCED_HIGH 3

//======== TxCON Parameter ===========
    #define UP_DOWN_COUNTING_MODE 1
    #define UP_COUNTING_MODE  2
    #define DIR_UP_DOWN_COUNTING_MODE  3

    #define GPTIM_PRESCALAR_1 0
    #define GPTIM_PRESCALAR_2 1
    #define GPTIM_PRESCALAR_4 2
    #define GPTIM_PRESCALAR_8 3
    #define GPTIM_PRESCALAR_16 4

    #define GPTIM_ENABLE 1
    #define GPTIM_DISABLE 0

    #define GPTIM_CLK_SRC_INTERNAL 0
    #define GPTIM_CLK_SRC_EXTERNAL 1
    #define GPTIM_CLK_SRC_RESERVED 2
    #define GPTIM_CLK_SRC_QEPINTERNAL 3

    #define GPTIM_CAP_ENABLE 1
    #define GPTIM_CAP_DISABLE 0


void GPIO_select(void){     // for IMU GPIO pin select

    EALLOW;

    //---------------------------------------------------------------------------
    // Set GPIO B pin 6 as output PWM.
    GpioMuxRegs.GPBMUX.bit.T3PWM_GPIOB6 = 1;
    GpioMuxRegs.GPBDIR.bit.GPIOB6 = 1;

    EDIS;
}

void init_evb_timer3(void){
    // Using for PWM
    // Initialize EVB Timer3:

    //---------------------------------------------------------------------------
    // Count up, internal clk/1 (HSPCLK/10 = 25MHz), enable Timer
    // EvbRegs.T3CON.all = 0xD871; // 11-0-10-000-0-1-00-00-1-0
    EvbRegs.T3CON.bit.FREE = 1;
    EvbRegs.T3CON.bit.SOFT = 1;
    EvbRegs.T3CON.bit.TMODE = UP_COUNTING_MODE;
    EvbRegs.T3CON.bit.TPS = GPTIM_PRESCALAR_1;
    EvbRegs.T3CON.bit.TCLKS10 = GPTIM_CLK_SRC_INTERNAL;
    EvbRegs.T3CON.bit.TECMPR = GPTIM_CAP_ENABLE;
    EvbRegs.T3CON.bit.TENABLE = GPTIM_ENABLE;

    // PWM frequency = (clk/1) / 5000  =  5 kHz
    EvbRegs.T3PR = 5000-1;

    // Timer3 counter reset
    EvbRegs.T3CNT = 0x0000;

    // Timer3 compare value
    EvbRegs.T3CMPR = 0x0000;

    // Compare Output Enable
    EvbRegs.GPTCONB.bit.TCMPOE = GPTIM_CO_ENABLE;

    // Timer3 Compare Output Polarity = active low
    EvbRegs.GPTCONB.bit.T3PIN = GPTIM_CP_EFF_LOW;

}

```
