---
# System prepended metadata

title: 'F2812的Event Manager : QEP'
tags: [F2812]

---

[TOC]

# 前言
- 本篇以實現Event Manager的QEP功能為目標，介紹QEP設定
- 見 <Event Manager(EV)Reference Guide> 3.5節 和 <手把手教你DSP> 12.5節
- F2812 有兩個QEP電路可直接判斷計數，想實現更多QEP功能只能靠軟體方式判斷計數完成

# EV 的 QEP

## QEP 簡介
- 見[新訓FPGA](https://hackmd.io/gcwxE_ENSviIpOjB_HLSuQ#%E6%96%B0%E8%A8%93%E9%A0%85%E7%9B%AE3-%E2%80%93-QEP)
- DSP內置的QEP電路能偵測編碼器A、B相的變化並且判別計數增減，解析度能提升到編碼器脈衝數的4倍
- 每個 EV 各有一個QEP電路，每個QEP各有兩支接腳
    - EVA : <font color="red">CAP1_QEP1、CAP2QEP2</font>
    - EVB : <font color="red">CAP4_QEP3、CAP5QEP4</font>

## 工作原理

### QEP結構
- EVA的QEP對應<font color="red"> EV_timer2 </font>的計數， EVB的QEP對應<font color="red"> EV_timer4 </font>的計數
- CAPCONx 的 bit 13、14 控制接腳CAPx_QEPy 引腳是否作為捕獲功能的輸入，但從架構圖來看接腳式直接進去QEP電路的，因此不用做QEP輸入始能的相關操作
- TxCON 的 bit 4、5 決定 timer 的計數時鐘來源是否來自QEP
- ![image](https://hackmd.io/_uploads/H1tpvGEmye.png =80%x)
- ![image](https://hackmd.io/_uploads/ByqRPfVQJe.png =80%x)

### 暫存器設定
- TxCON 的 TCLKS (bit 5、4) 設為(1, 1)可設定計時器基於QEP輸入
- 先前已經知道TxCNT會計數到T2PR - 1的值便歸零，可以設定
    <p class="text-center">
        T2PR的值 = 編碼器 pulse 數 *4 -1
    </p>
    如此計數到T2PR的值也剛好旋轉一圈

# QEP實作範例

## 設定流程
- 選用EVA的QEP，設定timer2 控制暫存器
    - 時鐘源選QEP
    - 計數模式改為 directional-up/down mode
    - timer2 預除頻設為1
    - 啟用timer2
- 設定設定timer2 週期暫存器
- GPIO設定為QEP輸入

## 範例程式
``` 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 A pin 8 as QEP input .
    GpioMuxRegs.GPAMUX.bit.CAP1Q1_GPIOA8 = 1;
    GpioMuxRegs.GPADIR.bit.GPIOA8 = 0;

    // Set GPIO A pin 9 as QEP input 
    GpioMuxRegs.GPAMUX.bit.CAP2Q2_GPIOA9 = 1
    GpioMuxRegs.GPADIR.bit.GPIOA9 = 0;
    EDIS;
}

void init_eva_timer2(void){
    // Using for QEP.
    //---------------------------------------------------------------------------

    // Set the Period for the GP timer 2
    EvaRegs.T2PR = ENCODER_PULSE * 4;        // Period
    EvaRegs.T2CNT = 0;        // Set the counter for GP timer 2

    //---------------------------------------------------------------------------
    // directional-Up/-Down count mode.
    // Input clock prescaler = x/1.
    // Then Timer enable.
    // EvaRegs.T2CON.all = 0xD870; // 11-0-11-000-0-1-11-00-0-0
    EvaRegs.T2CON.bit.FREE = 1;
    EvaRegs.T2CON.bit.SOFT = 1;
    EvaRegs.T2CON.bit.TMODE = DIR_UP_DOWN_COUNTING_MODE;
    EvaRegs.T2CON.bit.TPS = GPTIM_PRESCALAR_1;
    EvaRegs.T2CON.bit.TCLKS10 = GPTIM_CLK_SRC_QEPINTERNAL;
    EvaRegs.T2CON.bit.TENABLE = GPTIM_ENABLE;
}
interrupt void eva_timer1_isr(void){

    // ISR Task
    //---------------------------------------------------------------------------
    count = EvaRegs.T2CNT;
    EvbRegs.T3CMPR = count*10;

    // Enable more interrupts from this timer
    //---------------------------------------------------------------------------
    EvaRegs.EVAIMRA.bit.T1PINT = 1;

    // Clear Interrupt Flag
    //---------------------------------------------------------------------------
    // Note: To be safe, use a mask value to write to the entire
    // EVAIFRA register.  Writing to one bit will cause a read-modify-write
    // operation that may have the result of writing 1's to clear
    // bits other then those intended.
    EvaRegs.EVAIFRA.bit.T1PINT = 1;

    //---------------------------------------------------------------------------
    // Acknowledge interrupt to receive more interrupts from PIE group 2
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

    return;
}
```

