This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28388D: The interrupt for eqep only runs once, then it stops functioning

Part Number: TMS320F28388D

Hello,

This is a program, that I merged from eqep_ex1_freq_cal.

Everything works well when they are seperated, but when I merge these two files together,

other interrupts functions normally, but the interrupt for eqep seems to only operate once.

Can somebody tell me whats wrong?

The first file is my program.

The second file is eq

5516.cm_common_config_c28x.c
//#############################################################################
//
// FILE:   cm_common_config_c28x.c
//
// TITLE:  C28x Common Configurations to be used for the CM Side.
//
//! \addtogroup driver_example_list
//! <h1>C28x Common Configurations</h1>
//!
//! This example configures the GPIOs and Allocates the shared peripherals
//! according to the defines selected by the users.
//!
//
//#############################################################################
//
//
// $Copyright:
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################

//
// Included Files
//
#include "IQmathLib.h"
#include "driverlib.h"
#include "device.h"
#include "pi.h"
#include "pid.h"
#include "math.h"

//
// Defines
//
#define TB_CLK    DEVICE_SYSCLK_FREQ / 2        // ePWM Time base clock is SYSCLK/2
#define PWM_CLK   5000U                      // PWM frequency as 5 kHz
#define PRD_VAL   (TB_CLK / (PWM_CLK * 2))  // Calculate value period value
#define UNIT_PERIOD  10000U // Specify the unit timeout period in
#define myEPWM1_BASE    EPWM1_BASE
#define myEQEP0_BASE    EQEP1_BASE
#define base1    EPWM1_BASE
#define base2   EPWM2_BASE
#define EPWM_TIMER_TBPRD    625U
#define EQEP1   EQEP1_BASE                                  //0x00005100U
#define EQEP2   EQEP2_BASE                                  //0x00005140U
#define INT_myEQEP0 INT_EQEP1
#define INT_myEQEP0_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP5
//Added 07/12
#ifdef __TMS320C28XX_CLA__
#pragma CODE_SECTION(PI_init,"Cla1Prog2");
#endif
#define IPC_CMD_READ_MEM   0x1001
#define IPC_CMD_RESP       0x2001
#define TEST_PASS          0x5555
#define TEST_FAIL          0xAAAA
// Base/max frequency is 10 kHz
#define BASE_FREQ       10000
// See Equation 5 in eqep_ex1_calculation.c
#define FREQ_SCALER_PR  (((DEVICE_SYSCLK_FREQ / 128) * 8) / (2 * BASE_FREQ))
#pragma DATA_SECTION(sendDataC28, "MSGRAM_CPU_TO_CM")
typedef struct
{
    uint32_t freqScalerPR;  // Parameter: Scaler converting 1/N cycles to a
                            // GLOBAL_Q freq (Q0) - independently with global Q
    uint32_t baseFreq;      // Parameter: Maximum freq

    _iq freqPR;             // Output: Freq in per-unit using capture unit
    int32_t freqHzPR;       // Output: Freq in Hz, measured using Capture unit

} FreqCal_Object;

typedef FreqCal_Object *FreqCal_Handle;


//
// Functions
//
void Board_init(void);                                      // setup for the board
void EPWM_init(uint32_t base);                              // setup for epwm
__interrupt void IPC_ISR1(void);
__interrupt void cpuTimer0ISR(void);                        // setup for cpu0 interrupt
__interrupt void cpuTimer1ISR(void);                        // setup for cpu1 interrupt
__interrupt void cpuTimer2ISR(void);                        // setup for cpu2 interrupt
void initCPUTimers(void);                                   // setup for cpu interrupt
void configCPUTimer(uint32_t cpuTimer, uint32_t period);    // setup for cpu interrupt
void setCPU(void);                                          // setup for cpu interrupt
void EQEP_init(uint32_t base);                              // setup for eqep
__interrupt void INT_myEQEP2_ISR(void);                     // setup for eqep
__interrupt void INT_myEQEP0_ISR(void);
void setGPIO(void);                                         // setup for GPIOs
void INTERRUPT_init(void);                                  // init interrupt
void FreqCal_calculate(FreqCal_Handle, uint32_t);
//__interrupt void IPC_ISR1(void);

//
//Global Variables
//
uint32_t oldcount = 0;          //eqep1, stores the previous position of the clock
int32_t freq_Right = 0;         //eqep1, measured freq
uint32_t count = 0;             //eqep1, check if eqep1 is operating
uint32_t oldcount2 = 0;         //eqep2, stores the previous position of the clock
int32_t freq_Left =0;           //eqep2, measured freq
uint32_t count2 = 0;            //eqep2, check if eqep2 is operating
uint32_t IPCCount1 = 0;
uint32_t cpuTimer0IntCount = 0; //cpuTimer0, check if cpuTimer0 is operating
uint32_t cpuTimer1IntCount = 0; //cpuTimer1, check if cpuTimer1 is operating
uint32_t cpuTimer2IntCount = 0; //cpuTimer2, check if cpuTimer2 is operating
uint32_t eqep1Count = 0;
uint32_t eqep2Count = 0;
int targetRPM_Left = 0;         //cpuTimer1, get the input RPM of the left wheel
int targetRPM_Right = 0;        //cpuTimer1, get the input RPM of the right wheel
uint16_t dutycycle_Left = 0;    //epwm, turn the input RPM into the dutycycle of pwm
uint16_t dutycycle_Right = 0;   //epwm, turn the input RPM into the dutycycle of pwm
const float32_t freq1 = 5000.0; //??
float32_t tmpLeft = 0;          //??
float32_t tmpRight = 0;         //??
float32_t kp=0.75;
float32_t ki=0.06;
float32_t kd=0.45;
PID_Obj handle_Left = {0, 0, 0, 0, 0, 0, 0, -20, 80};
PID_Obj handle_Right = {0, 0, 0, 0, 0, 0, 0, -20, 80};
int temp = 0;
FreqCal_Object freqLeft =
{
    FREQ_SCALER_PR,  // freqScalerPR
    BASE_FREQ,       // baseFreq
    0, 0,   // Initialize outputs to zero
};
FreqCal_Object freqRight =
{
    FREQ_SCALER_PR,  // freqScalerPR
    BASE_FREQ,       // baseFreq
    0, 0,   // Initialize outputs to zero
};

//Added 07/12
float sendDataC28[10];
uint32_t pass;
float receiveDataC28[9];

//vehicle Added 07/12
const float rw = 0.08; //radius of wheel
const float R = 0.17; //half distance of two wheel
float controlmatrix[2][2];
float inv_controlmatrix[2][2];

//parameters Added 07/12
float feedBackGainEpsilon = 1;
float feedBackGainB = 0.01;

float sideBysideOmegaGain = 15;

float v_max = 0.25;
float w_max = 0.5;
int tmp1 = 0;


typedef struct point
{
    float set_x[4];
    float set_y[4];
    float set_t[4];
    int point_number;

}via_point;
int path_type = 0;
const float RS_EPS = 1e-4;

void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Boot CM core
    //
#ifdef _FLASH
    Device_bootCM(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
#else
    Device_bootCM(BOOTMODE_BOOT_TO_S0RAM);
#endif

    //
    // Disable pin locks and enable internal pull-ups.
    //
    Device_initGPIO();

#ifdef ETHERNET
    //
    // Set up EnetCLK to use SYSPLL as the clock source and set the
    // clock divider to 2.
    //
    // This way we ensure that the PTP clock is 100 MHz. Note that this value
    // is not automatically/dynamically known to the CM core and hence it needs
    // to be made available to the CM side code beforehand.
    SysCtl_setEnetClk(SYSCTL_ENETCLKOUT_DIV_2, SYSCTL_SOURCE_SYSPLL);

    //
    // Configure the GPIOs for ETHERNET.
    //

    //
    // MDIO Signals
    //
    GPIO_setPinConfig(GPIO_105_ENET_MDIO_CLK);
    GPIO_setPinConfig(GPIO_106_ENET_MDIO_DATA);

    //
    // Use this only for RMII Mode
    //GPIO_setPinConfig(GPIO_73_ENET_RMII_CLK);
    //

    //
    //MII Signals
    //
    GPIO_setPinConfig(GPIO_109_ENET_MII_CRS);
    GPIO_setPinConfig(GPIO_110_ENET_MII_COL);

    GPIO_setPinConfig(GPIO_75_ENET_MII_TX_DATA0);
    GPIO_setPinConfig(GPIO_122_ENET_MII_TX_DATA1);
    GPIO_setPinConfig(GPIO_123_ENET_MII_TX_DATA2);
    GPIO_setPinConfig(GPIO_124_ENET_MII_TX_DATA3);

    //
    //Use this only if the TX Error pin has to be connected
    //GPIO_setPinConfig(GPIO_46_ENET_MII_TX_ERR);
    //

    GPIO_setPinConfig(GPIO_118_ENET_MII_TX_EN);

    GPIO_setPinConfig(GPIO_114_ENET_MII_RX_DATA0);
    GPIO_setPinConfig(GPIO_115_ENET_MII_RX_DATA1);
    GPIO_setPinConfig(GPIO_116_ENET_MII_RX_DATA2);
    GPIO_setPinConfig(GPIO_117_ENET_MII_RX_DATA3);
    GPIO_setPinConfig(GPIO_113_ENET_MII_RX_ERR);
    GPIO_setPinConfig(GPIO_112_ENET_MII_RX_DV);

    GPIO_setPinConfig(GPIO_44_ENET_MII_TX_CLK);
    GPIO_setPinConfig(GPIO_111_ENET_MII_RX_CLK);

    //
    //Power down pin to bring the external PHY out of Power down
    //
    GPIO_setDirectionMode(108, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(108, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(108,1);

    //
    //PHY Reset Pin to be driven High to bring external PHY out of Reset
    //

    GPIO_setDirectionMode(119, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(119, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(119,1);
#endif

#ifdef MCAN
    //
    // Setting the MCAN Clock.
    //
    SysCtl_setMCANClk(SYSCTL_MCANCLK_DIV_4);

    //
    // Configuring the GPIOs for MCAN.
    //
    GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANRXA);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANTXA);
#endif

#ifdef CANA
    //
    // Configuring the GPIOs for CAN A.
    //
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);

    //
    // Allocate Shared Peripheral CAN A to the CM Side.
    //
    SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_A,0x1U);
#endif

#ifdef CANB
    //
    // Configuring the GPIOs for CAN B.
    //
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXB);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXB);

    //
    // Allocate Shared Peripheral CAN B to the CM Side.
    //
    SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_B,0x1U);
#endif

#ifdef UART
    //
    // Configure GPIO85 as the UART Rx pin.
    //
    GPIO_setPinConfig(GPIO_85_UARTA_RX);
    GPIO_setDirectionMode(85, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(85, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(85, GPIO_QUAL_ASYNC);

    //
    // Configure GPIO84 as the UART Tx pin.
    //
    GPIO_setPinConfig(GPIO_84_UARTA_TX);
    GPIO_setDirectionMode(84, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(84, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(84, GPIO_QUAL_ASYNC);
#endif

#ifdef USB
#ifdef USE_20MHZ_XTAL
    //
    // Set up the auxiliary PLL so a 60 MHz output clock is provided to the USB module.
    // This fixed frequency is required for all USB operations.
    //
    SysCtl_setAuxClock(SYSCTL_AUXPLL_OSCSRC_XTAL |
                       SYSCTL_AUXPLL_IMULT(48) |
                       SYSCTL_REFDIV(2U) | SYSCTL_ODIV(4U) |
                       SYSCTL_AUXPLL_DIV_2 |
                       SYSCTL_AUXPLL_ENABLE |
                       SYSCTL_DCC_BASE_0);
#else
    //
    // Set up the auxiliary PLL so a 60 MHz output clock is provided to the USB module.
    // This fixed frequency is required for all USB operations.
    //
    SysCtl_setAuxClock(SYSCTL_AUXPLL_OSCSRC_XTAL |
                       SYSCTL_AUXPLL_IMULT(48) |
                       SYSCTL_REFDIV(2U) | SYSCTL_ODIV(5U) |
                       SYSCTL_AUXPLL_DIV_2 |
                       SYSCTL_AUXPLL_ENABLE |
                       SYSCTL_DCC_BASE_0);
#endif

    //
    // Allocate Shared Peripheral USB to the CM Side.
    //
    SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_USBA, 1);

    GPIO_setPinConfig(GPIO_0_GPIO0);
    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
    GPIO_setMasterCore(0, GPIO_CORE_CM);

    //
    // Set the master core of GPIOs to CM.
    //
    GPIO_setMasterCore(42, GPIO_CORE_CM);
    GPIO_setMasterCore(43, GPIO_CORE_CM);
    GPIO_setMasterCore(46, GPIO_CORE_CM);
    GPIO_setMasterCore(47, GPIO_CORE_CM);
    GPIO_setMasterCore(120, GPIO_CORE_CM);
    GPIO_setMasterCore(121, GPIO_CORE_CM);

    //
    // Set the USB DM and DP GPIOs.
    //
    GPIO_setAnalogMode(42, GPIO_ANALOG_ENABLED);
    GPIO_setAnalogMode(43, GPIO_ANALOG_ENABLED);

    //
    // Set the direction for VBUS and ID.
    //
    GPIO_setDirectionMode(46, GPIO_DIR_MODE_IN);
    GPIO_setDirectionMode(47, GPIO_DIR_MODE_IN);

    //
    // Configure the Power Fault.
    //
    GPIO_setMasterCore(120, GPIO_CORE_CM);
    GPIO_setDirectionMode(120, GPIO_DIR_MODE_IN);

    //
    // Configure the External Power Signal Enable.
    //
    GPIO_setMasterCore(121, GPIO_CORE_CM);
    GPIO_setDirectionMode(121, GPIO_DIR_MODE_OUT);
    GPIO_writePin(121, 1);

    //
    // Set the CM Clock to run at 120MHz.
    // The CM Clock is a fractional multiple of the AUXPLL Clock (120 Mhz) from
    // which the USB Clock (60 MHz) is derived.
    //
    SysCtl_setCMClk(SYSCTL_CMCLKOUT_DIV_1, SYSCTL_SOURCE_AUXPLL);
#endif

    //Modified
    Interrupt_initModule();
    Interrupt_initVectorTable();

    IPC_clearFlagLtoR(IPC_CPU1_L_CM_R, IPC_FLAG_ALL);
    IPC_registerInterrupt(IPC_CPU1_L_CM_R, IPC_INT1, IPC_ISR1);
    //IPC_sync(IPC_CPU1_L_CM_R, IPC_FLAG31);

    Board_init();

    EINT;
    ERTM;

    while(1);
}

void Board_init(void) {
    EALLOW;

    setGPIO();
    EQEP_init(EQEP1_BASE);
    EQEP_init(EQEP2_BASE);
    INTERRUPT_init();
    setCPU();
    EPWM_init(base1);
    EPWM_init(base2);

    EDIS;
}

void setGPIO(void) {
    //EQEP1
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_11_EQEP1_B);
    GPIO_setPadConfig(11, GPIO_PIN_TYPE_STD);

    //EQEP2
    GPIO_setPinConfig(GPIO_54_EQEP2_A);
    GPIO_setPadConfig(54, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_55_EQEP2_B);
    GPIO_setPadConfig(55, GPIO_PIN_TYPE_STD);

    //EPWM1
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);

    //EPWM2
    GPIO_setPinConfig(GPIO_2_EPWM2A);
    GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);

    //set GPIO1 for reverse switch left
    GPIO_setPinConfig(GPIO_1_GPIO1);
    GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(1, GPIO_DIR_MODE_OUT);

    //set GPIO3 for reverse switch right
    GPIO_setPinConfig(GPIO_3_GPIO3);
    GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(3, GPIO_DIR_MODE_OUT);

    //set GPIO8 for forward switch left
    GPIO_setPinConfig(GPIO_8_GPIO8);
    GPIO_setPadConfig(8, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(8, GPIO_DIR_MODE_OUT);

    //set GPIO9 for forward switch right
    GPIO_setPinConfig(GPIO_9_GPIO9);
    GPIO_setPadConfig(9, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(9, GPIO_DIR_MODE_OUT);
}

void EPWM_init(uint32_t base) {
    // setup TBCLK for EPWM
    EPWM_setTimeBasePeriod(base, EPWM_TIMER_TBPRD);
    EPWM_setPhaseShift(base, 0U);
    EPWM_setTimeBaseCounter(base, 0U);
    EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN);
    EPWM_disablePhaseShiftLoad(base);

    // setup epwm prescalar
    EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_4, EPWM_HSCLOCK_DIVIDER_4);

    // setup compare
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, 1*EPWM_TIMER_TBPRD/100);

    // setup actions
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
}

void EQEP_init(uint32_t base) {
    // disable, clear all flags and interrupt
    EQEP_disableInterrupt(base,
        (EQEP_INT_GLOBAL            |
        EQEP_INT_POS_CNT_ERROR      |
        EQEP_INT_PHASE_ERROR        |
        EQEP_INT_DIR_CHANGE         |
        EQEP_INT_WATCHDOG           |
        EQEP_INT_UNDERFLOW          |
        EQEP_INT_OVERFLOW           |
        EQEP_INT_POS_COMP_READY     |
        EQEP_INT_POS_COMP_MATCH     |
        EQEP_INT_STROBE_EVNT_LATCH  |
        EQEP_INT_INDEX_EVNT_LATCH   |
        EQEP_INT_UNIT_TIME_OUT      |
        EQEP_INT_QMA_ERROR));
    EQEP_clearInterruptStatus(base,
        (EQEP_INT_GLOBAL            |
        EQEP_INT_POS_CNT_ERROR      |
        EQEP_INT_PHASE_ERROR        |
        EQEP_INT_DIR_CHANGE         |
        EQEP_INT_WATCHDOG           |
        EQEP_INT_UNDERFLOW          |
        EQEP_INT_OVERFLOW           |
        EQEP_INT_POS_COMP_READY     |
        EQEP_INT_POS_COMP_MATCH     |
        EQEP_INT_STROBE_EVNT_LATCH  |
        EQEP_INT_INDEX_EVNT_LATCH   |
        EQEP_INT_UNIT_TIME_OUT      |
        EQEP_INT_QMA_ERROR));
    EQEP_SourceSelect source_myEQEP0 =
    {
        EQEP_SOURCE_DEVICE_PIN,         // eQEPA source
        EQEP_SOURCE_DEVICE_PIN,     // eQEPB source
        EQEP_SOURCE_DEVICE_PIN,     // eQEP Index source
    };

    // Selects the source for eQEPA/B/I signals
    EQEP_selectSource(base, source_myEQEP0);
    // Set the strobe input source of the eQEP module.
    EQEP_setStrobeSource(base,EQEP_STROBE_FROM_GPIO);
    // Sets the polarity of the eQEP module's input signals.
    EQEP_setInputPolarity(base,false,false,false,false);
    // Configures eQEP module's quadrature decoder unit.
    EQEP_setDecoderConfig(base, (EQEP_CONFIG_UP_COUNT | EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE));
    // Set the emulation mode of the eQEP module.
    EQEP_setEmulationMode(base,EQEP_EMULATIONMODE_RUNFREE);
    // Configures eQEP module position counter unit.
    EQEP_setPositionCounterConfig(base,EQEP_POSITION_RESET_IDX,4294967295U);
    // Sets the current encoder position.
    EQEP_setPosition(base,0U);
    // Enables the eQEP module unit timer.
    EQEP_enableUnitTimer(base,2000000U);
    // Disables the eQEP module watchdog timer.
    EQEP_disableWatchdog(base);
    // Configures the quadrature modes in which the position count can be latched.
    EQEP_setLatchMode(base,(EQEP_LATCH_UNIT_TIME_OUT|EQEP_LATCH_RISING_STROBE|EQEP_LATCH_RISING_INDEX));
    // Set the quadrature mode adapter (QMA) module mode.
    EQEP_setQMAModuleMode(base,EQEP_QMA_MODE_BYPASS);
    // Disable Direction Change During Index
    EQEP_disableDirectionChangeDuringIndex(base);
    // Enables individual eQEP module interrupt sources.
    EQEP_enableInterrupt(base,(EQEP_INT_UNIT_TIME_OUT));
    // Configures the mode in which the position counter is initialized.
    EQEP_setPositionInitMode(base,(EQEP_INIT_DO_NOTHING));
    // Sets the software initialization of the encoder position counter.
    EQEP_setSWPositionInit(base,true);
    // Sets the init value for the encoder position counter.
    EQEP_setInitialPosition(base,0U);
    // Enables the eQEP module.
    EQEP_enableModule(base);
    // Configures eQEP module edge-capture unit.
    EQEP_setCaptureConfig(base,EQEP_CAPTURE_CLK_DIV_128,EQEP_UNIT_POS_EVNT_DIV_8);
    // Enables the eQEP module edge-capture unit.
    EQEP_enableCapture(base);
}

void INTERRUPT_init() {
    // Interrupt Setings for INT_myEQEP0
    Interrupt_register(INT_myEQEP0, &INT_myEQEP0_ISR);
    Interrupt_enable(INT_myEQEP0);

    // Interrupt Settings for INT_myEQEP2
    Interrupt_register(INT_EQEP2, &INT_myEQEP2_ISR);
    Interrupt_enable(INT_EQEP2);

    //Interrupt Setting for cpuTimer0ISR
    Interrupt_register(INT_TIMER0, &cpuTimer0ISR);
    Interrupt_enable(INT_TIMER0);

    //Interrupt Setting for cpuTimer1ISR
    Interrupt_register(INT_TIMER1, &cpuTimer1ISR);
    Interrupt_enable(INT_TIMER1);

    //Interrupt Setting for cpuTimer2ISR
    Interrupt_register(INT_TIMER2, &cpuTimer2ISR);
    Interrupt_enable(INT_TIMER2);
}

void setCPU() {
    initCPUTimers();

    cpuTimer0IntCount = 0;
    cpuTimer1IntCount = 0;
    cpuTimer2IntCount = 0;

    configCPUTimer(CPUTIMER0_BASE, 10000);
    configCPUTimer(CPUTIMER1_BASE, 10000);
    configCPUTimer(CPUTIMER2_BASE, 10000);

    CPUTimer_enableInterrupt(CPUTIMER0_BASE);
    CPUTimer_enableInterrupt(CPUTIMER1_BASE);
    CPUTimer_enableInterrupt(CPUTIMER2_BASE);

    CPUTimer_startTimer(CPUTIMER0_BASE);
    CPUTimer_startTimer(CPUTIMER1_BASE);
    CPUTimer_startTimer(CPUTIMER2_BASE);
}

void initCPUTimers(void) {
    CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFF);
    CPUTimer_setPeriod(CPUTIMER1_BASE, 0xFFFFFFFF);
    CPUTimer_setPeriod(CPUTIMER2_BASE, 0xFFFFFFFF);

    CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);
    CPUTimer_setPreScaler(CPUTIMER1_BASE, 0);
    CPUTimer_setPreScaler(CPUTIMER2_BASE, 0);

    CPUTimer_stopTimer(CPUTIMER0_BASE);
    CPUTimer_stopTimer(CPUTIMER1_BASE);
    CPUTimer_stopTimer(CPUTIMER2_BASE);

    CPUTimer_reloadTimerCounter(CPUTIMER0_BASE);
    CPUTimer_reloadTimerCounter(CPUTIMER1_BASE);
    CPUTimer_reloadTimerCounter(CPUTIMER2_BASE);

    cpuTimer0IntCount = 0;
    cpuTimer1IntCount = 0;
    cpuTimer2IntCount = 0;
}

void configCPUTimer(uint32_t cpuTimer, uint32_t period) {
    uint32_t temp, freq = DEVICE_SYSCLK_FREQ;

    //
    // Initialize timer period:
    //
    temp = ((freq / 1000000) * period);
    CPUTimer_setPeriod(cpuTimer, temp);

    //
    // Set pre-scale counter to divide by 1 (SYSCLKOUT):
    //
    CPUTimer_setPreScaler(cpuTimer, 0);

    //
    // Initializes timer control register. The timer is stopped, reloaded,
    // free run disabled, and interrupt enabled.
    // Additionally, the free and soft bits are set
    //
    CPUTimer_stopTimer(cpuTimer);
    CPUTimer_reloadTimerCounter(cpuTimer);
    CPUTimer_setEmulationMode(cpuTimer,
                              CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);
    CPUTimer_enableInterrupt(cpuTimer);

    //
    // Resets interrupt counters for the three cpuTimers
    //
    if (cpuTimer == CPUTIMER0_BASE) {
        cpuTimer0IntCount = 0;
    }
    if (cpuTimer == CPUTIMER1_BASE) {
        cpuTimer1IntCount = 0;
    }
    if (cpuTimer == CPUTIMER2_BASE) {
        cpuTimer2IntCount = 0;
    }
}

__interrupt void INT_myEQEP0_ISR(void) {
    FreqCal_calculate(&freqLeft, EQEP1_BASE);
    eqep1Count++;
    EQEP_clearInterruptStatus(myEQEP0_BASE,EQEP_INT_UNIT_TIME_OUT|EQEP_INT_GLOBAL);
}

__interrupt void INT_myEQEP2_ISR(void) {
    FreqCal_calculate(&freqRight, EQEP2_BASE);
    eqep2Count++;
    EQEP_clearInterruptStatus(EQEP2,EQEP_INT_UNIT_TIME_OUT|EQEP_INT_GLOBAL);
}

__interrupt void cpuTimer0ISR(void) {
    /*
    //send what
    sendDataC28[0] = 0;
    sendDataC28[1] = 0;
    sendDataC28[2] = 0;
    sendDataC28[3] = 0;
    IPC_sendCommand(IPC_CPU1_L_CM_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
                    IPC_CMD_READ_MEM, (uint32_t)sendDataC28, 10);

    IPC_waitForAck(IPC_CPU1_L_CM_R, IPC_FLAG0);
    if(IPC_getResponse(IPC_CPU1_L_CM_R) == TEST_PASS){
        pass = 1;
    }
    else{
        pass = 0;
    }
    */

    cpuTimer0IntCount++;
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

__interrupt void cpuTimer1ISR(void) {
    PID_setGains(&handle_Left, kp, ki, kd);
    PID_setGains(&handle_Right, kp, ki, kd);
    //step.1-1 turn rpm into dutycycle
    //available zone [Forward:10~80 RPM, Backward:6~20 RPM]
    if (targetRPM_Left<0){
        //PID_run_parallel [handle, DesireValue, FeedbackValue, FeedforwardValue, Pointer to the output]
        PID_run_parallel(&handle_Left, targetRPM_Left, -freq_Left/4, 0, &tmpLeft);
        dutycycle_Left = (1-(-tmpLeft*0.0165+0.1928))*100;
    }
    else{
        PID_run_parallel(&handle_Left, targetRPM_Left, freq_Left/4, 0, &tmpLeft);
        dutycycle_Left = (1-(tmpLeft*0.0041+0.2963))*100;
    }
    if (targetRPM_Right<0){
        PID_run_parallel(&handle_Right, targetRPM_Right, -freq_Right/4, 0, &tmpRight);
        dutycycle_Right = (1-(-tmpRight*0.0171+0.1928))*100;
    }
    else{
        PID_run_parallel(&handle_Right, targetRPM_Right, freq_Right/4, 0, &tmpRight);
        dutycycle_Right = (1-(tmpRight*0.0041+0.2996))*100;
    }

    if (dutycycle_Left>=70){
        EPWM_setCounterCompareValue(base1, EPWM_COUNTER_COMPARE_A, 99*EPWM_TIMER_TBPRD/100);
        PID_setUi(&handle_Left, 0);
    }
    else{
        EPWM_setCounterCompareValue(base1, EPWM_COUNTER_COMPARE_A, dutycycle_Left*EPWM_TIMER_TBPRD/100);
    }
    if (dutycycle_Right>=70){
        EPWM_setCounterCompareValue(base2, EPWM_COUNTER_COMPARE_A, 99*EPWM_TIMER_TBPRD/100);
        PID_setUi(&handle_Right, 0);
    }
    else{
        EPWM_setCounterCompareValue(base2, EPWM_COUNTER_COMPARE_A, dutycycle_Right*EPWM_TIMER_TBPRD/100);
    }
    //step.1-2 decide the direction
    //the direction for the left wheel
    if (targetRPM_Left>0){
        GPIO_writePin(8,1);
        GPIO_writePin(1,0);
    }
    else if (targetRPM_Left<0){
        GPIO_writePin(8,0);
        GPIO_writePin(1,1);
    }
    else{
        GPIO_writePin(8,0);
        GPIO_writePin(1,0);
    }
    //the direction for the right wheel
    if (targetRPM_Right>0){
        GPIO_writePin(9,1);
        GPIO_writePin(3,0);
    }
    else if (targetRPM_Right<0){
        GPIO_writePin(9,0);
        GPIO_writePin(3,1);
    }
    else{
        GPIO_writePin(9,0);
        GPIO_writePin(3,0);
    }

    //step.2 let f2838x generate the dutycycle we want

    cpuTimer1IntCount++;
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

__interrupt void cpuTimer2ISR(void) {
    cpuTimer2IntCount++;
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

__interrupt void IPC_ISR1() {
    uint32_t command, addr, data;
    int i;
    bool status = false;
    IPC_readCommand(IPC_CPU1_L_CM_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,
                    &command, &addr, &data);
    if(command == IPC_CMD_READ_MEM)
    {
        status = true;
        for(i=0; i<data; i++)
        {
            receiveDataC28[i] = *((float *)addr + i);
        }
    }
    if(status)
    {
        IPC_sendResponse(IPC_CPU1_L_CM_R, TEST_PASS);
    }
    else
    {
        IPC_sendResponse(IPC_CPU1_L_CM_R, TEST_FAIL);
    }
    IPC_ackFlagRtoL(IPC_CPU1_L_CM_R, IPC_FLAG1);
    //Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);
    IPCCount1++;
}

void
FreqCal_calculate(FreqCal_Object *p, uint32_t base)
{
    uint32_t temp;
    //
    // **** Frequency calculation using eQEP capture counter ****
    //
    // Check for unit position event
    //
    if((EQEP_getStatus(base) & EQEP_STS_UNIT_POS_EVNT) != 0)
    {
        //
        // No capture overflow
        //
        if((EQEP_getStatus(base) & EQEP_STS_CAP_OVRFLW_ERROR) == 0)
        {
            temp = (uint32_t)EQEP_getCapturePeriodLatch(base);
        }
        else
        {
            //
            // Capture overflow, saturate the result
            //
            temp = 0xFFFF;
        }

        //
        // p->freqPR = X / [(t2 - t1) * 10kHz]
        //
        p->freqPR = _IQdiv(p->freqScalerPR, temp);
        temp = p->freqPR;

        if(temp > _IQ(1))
        {
            p->freqPR = _IQ(1);
        }
        else
        {
            p->freqPR = temp;
        }

        //
        // Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
        // p->freqHzPR = (p->freqPR) * 10kHz = X / (t2 - t1)
        //
        p->freqHzPR = _IQmpy(p->baseFreq, p->freqPR);

        //
        // Clear unit position event flag and overflow error flag
        //
        EQEP_clearStatus(base, (EQEP_STS_UNIT_POS_EVNT |
                                      EQEP_STS_CAP_OVRFLW_ERROR));
    }
    Interrupt_clearACKGroup(INT_myEQEP0_INTERRUPT_ACK_GROUP);
}
eqep_ex1_freq_cal.c
//#############################################################################
//
// FILE:   eqep_ex1_freq_cal.c
//
// TITLE:  Frequency Measurement Using eQEP
//
//! \addtogroup driver_example_list
//! <h1>Frequency Measurement Using eQEP</h1>
//!
//! This example will calculate the frequency of an input signal using the eQEP
//! module.  ePWM1A is configured to generate this input signal with a
//! frequency of 5 kHz. It will interrupt once every period and call the
//! frequency calculation function. This example uses the IQMath library to
//! simplify high-precision calculations.
//!
//! In addition to the main example file, the following files must be included
//! in this project:
//! - \b eqep_ex1_calculation.c - contains frequency calculation function
//! - \b eqep_ex1_calculation.h - includes initialization values for frequency
//!                               structure
//!
//! The configuration for this example is as follows
//! - Maximum frequency is configured to 10KHz (baseFreq)
//! - Minimum frequency is assumed at 50Hz for capture pre-scalar selection
//!
//! \b SPEED_FR: High Frequency Measurement is obtained by counting the
//! external input pulses for 10ms (unit timer set to 100Hz).
//! \f[ SPEED\_FR = \frac{Count\ Delta}{10ms} \f]
//!
//! \b SPEED_PR: Low Frequency Measurement is obtained by measuring time
//! period of input edges. Time measurement is averaged over 64 edges for
//! better results and the capture unit performs the time measurement using
//! pre-scaled SYSCLK.
//!
//! Note that the pre-scaler for capture unit clock is selected such that the
//! capture timer does not overflow at the required minimum frequency. This
//! example runs indefinitely until the user stops it.
//!
//! For more information about the frequency calculation see the comments at
//! the beginning of eqep_ex1_calculation.c and the XLS file provided with the
//! project, eqep_ex1_calculation.xls.
//!
//! \b External \b Connections \n
//! - Connect GPIO20/eQEP1A to GPIO0/ePWM1A
//!
//! \b Watch \b Variables \n
//! - \b freq.freqHzFR - Frequency measurement using position counter/unit
//!   time out
//! - \b freq.freqHzPR - Frequency measurement using capture unit
//!
//
//#############################################################################
//
//
// $Copyright:
// Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//#############################################################################

//
// Included Files
//
#include "driverlib.h"
#include "device.h"
#include "IQmathLib.h"
#include "eqep_ex1_calculation.h"
#include "board.h"


//
// Defines
//
#define TB_CLK    DEVICE_SYSCLK_FREQ / 2       // Time base clock is SYSCLK/2
#define PWM_CLK   5000                      // We want to output at 5 kHz
#define PRD_VAL   (TB_CLK / (PWM_CLK * 2))  // Calculate value period value
                                            // for up-down count mode

// Base/max frequency is 10 kHz
#define BASE_FREQ       10000
// See Equation 5 in eqep_ex1_calculation.c
#define FREQ_SCALER_PR  (((DEVICE_SYSCLK_FREQ / 128) * 8) / (2 * BASE_FREQ))
// See Equation 2 in eqep_ex1_calculation.c
#define FREQ_SCALER_FR  ((BASE_FREQ * 2) / 100)

//
// Function Prototypes
//
void initEPWM(void);
__interrupt void epwmISR(void);

//
// Globals
//
FreqCal_Object freq =
{
    FREQ_SCALER_PR,  // freqScalerPR
    BASE_FREQ,       // baseFreq
    0, 0,   // Initialize outputs to zero
};
uint32_t count =0;  // counter to check measurement gets saturated
uint32_t pass=0, fail =0; // Pass or fail indicator

//
// Main
//
void main(void)
{
    //
    // Initialize device clock and peripherals
    //
    Device_init();
    
    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Board Initialization
    // Setup eQEP1, configuring the unit timer and quadrature capture units
    //
    Board_init();

    //
    // Initialize GPIOs for use as EPWM1A and EQEP1A
    //
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);

    //
    // Interrupts that are used in this example are re-mapped to ISR functions
    // found within this file.
    //
    Interrupt_register(INT_EPWM1, &epwmISR);

    //
    // Setup ePWM1 to generate a 5 kHz signal to be an input to the eQEP
    //
    initEPWM();

    //
    // Enable interrupts required for this example
    //
    Interrupt_enable(INT_EPWM1);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Setup eQEP1, configuring the unit timer and quadrature capture units
    //
   // initEQEP();  -- >change with Board_init(); soon

    //
    // Loop indefinitely
    //
    while(1)
    {
        ;
    }
}


//
// initEPWM - Function to configure ePWM1 to generate a 5 kHz signal.
//
void
initEPWM(void)
{
    //
    // Disable the ePWM time base clock before configuring the module
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Set phase shift to 0 and clear the time base counter
    //
    EPWM_setPhaseShift(EPWM1_BASE, 0);
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0);

    //
    // Disable the shadow load; the load will be immediate instead
    //
    EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
                                             EPWM_COUNTER_COMPARE_A);
    EPWM_disableCounterCompareShadowLoadMode(EPWM1_BASE,
                                             EPWM_COUNTER_COMPARE_B);

    //
    // Set the compare A value to half the period value, compare B to 0
    //
    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, PRD_VAL/2);
    //
    // Set action qualifier behavior on compare A events
    // - EPWM1A --> 1 when CTR = CMPA and increasing
    // - EPWM1A --> 0 when CTR = CMPA and decreasing
    //
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);

    //
    // Configure EPWM1B to be complementary to EPWM1A
    //
    EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_FED,
                                  EPWM_DB_POLARITY_ACTIVE_LOW);
    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_FED, true);
    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_RED, true);

    //
    // Enable interrupt when the counter is equal to 0
    //
    EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(EPWM1_BASE);

    //
    // Interrupt on first event
    //
    EPWM_setInterruptEventCount(EPWM1_BASE, 1);

    //
    // Set the time base clock prescaler to /1
    //
    EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_1);

    //
    // Set the period value; don't shadow the register
    //
    EPWM_setPeriodLoadMode(EPWM1_BASE, EPWM_PERIOD_DIRECT_LOAD);
    EPWM_setTimeBasePeriod(EPWM1_BASE, PRD_VAL);

    //
    // Put the time base counter into up-down count mode
    //
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);

    //
    // Sync the ePWM time base clock
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
}

//
// ePWM1 ISR- interrupts once per ePWM period
//
__interrupt void
epwmISR(void)
{
    //
    // Checks for events and calculates frequency.
    //
    FreqCal_calculate(&freq);

    //
    // Clear interrupt flag and issue ACK
    //
    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

//
// End of File
//

ep_ex1_freq_cal.c

  • The EQEP is inited on line 515, and the interrupt is initted on line 594, the interrupt funtion is on line 695.

  • Hi Hao-Yu,

    EQEP ex 1 uses the ePWM module to generate interrupts for frequency calculation, this is why you are not seeing the eQEP interrupts. It is better to use ex4 (frequency) or ex5 (speed & direction) as reference because these two examples use the unit timer within the eQEP module to generate periodic eQEP interrupts. Please let me know if you need further clarification or assistance

    Regards,

    Peter

  • Hi Peter,

    I think your answer solved my problem, but I have a few more questions. Since I have been trying to measure low frequency pulse with the resolution to be 1. First I've tried to use ex4 (interrupt frequency) to measure, but I found out that changing the resolution to 1 requires long clock unit timer (200000000U). So everytime when the input frequency changes, I takes 2 seconds to get to the correct frequency, but it is accurate. And ex1 can reach the correct frequency fast, but it seems to have a dead zone for measuring low frequency pulses, it stops getting accurate at about 95Hz, is there a way to solve this problem? 

    Thanks for answering my question!!!

    Best regards,

    Hao-Yu 

  • Also I have tried to use epwm interrupt, but it still only function once, I'm not sure what's wrong. I have compared it to the ex1 code, and it's the same.

    //#############################################################################
    //
    // FILE:   cm_common_config_c28x.c
    //
    // TITLE:  C28x Common Configurations to be used for the CM Side.
    //
    //! \addtogroup driver_example_list
    //! <h1>C28x Common Configurations</h1>
    //!
    //! This example configures the GPIOs and Allocates the shared peripherals
    //! according to the defines selected by the users.
    //!
    //
    //#############################################################################
    //
    //
    // $Copyright:
    // Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    #include "pi.h"
    #include "pid.h"
    #include "math.h"
    #include "IQmathLib.h"
    
    //
    // Defines
    //
    #define TB_CLK    DEVICE_SYSCLK_FREQ / 2        // ePWM Time base clock is SYSCLK/2
    #define PWM_CLK   5000                      // PWM frequency as 5 kHz
    #define PRD_VAL   (TB_CLK / (PWM_CLK * 2))  // Calculate value period value
    #define UNIT_PERIOD  10000U // Specify the unit timeout period in
    #define myEPWM1_BASE    EPWM1_BASE
    #define myEQEP0_BASE    EQEP1_BASE
    #define base1    EPWM1_BASE
    #define base2   EPWM2_BASE
    #define EPWM_TIMER_TBPRD    625U
    #define EQEP1   EQEP1_BASE                                  //0x00005100U
    #define EQEP2   EQEP2_BASE                                  //0x00005140U
    #define INT_myEQEP0 INT_EQEP1
    #define INT_myEQEP0_INTERRUPT_ACK_GROUP INTERRUPT_ACK_GROUP5
    //Added 07/12
    #ifdef __TMS320C28XX_CLA__
    #pragma CODE_SECTION(PI_init,"Cla1Prog2");
    #endif
    #define IPC_CMD_READ_MEM   0x1001
    #define IPC_CMD_RESP       0x2001
    #define TEST_PASS          0x5555
    #define TEST_FAIL          0xAAAA
    // Added 0805 for using epwm interrupt to trigger
    // Base/max frequency is 10 kHz
    #define BASE_FREQ       10000
    // See Equation 5 in eqep_ex1_calculation.c
    #define FREQ_SCALER_PR  (((DEVICE_SYSCLK_FREQ / 128) * 8) / (2 * BASE_FREQ))
    typedef struct
    {
        uint32_t freqScalerPR;  // Parameter: Scaler converting 1/N cycles to a
                                // GLOBAL_Q freq (Q0) - independently with global Q
        uint32_t baseFreq;      // Parameter: Maximum freq
    
        _iq freqPR;             // Output: Freq in per-unit using capture unit
        int32_t freqHzPR;       // Output: Freq in Hz, measured using Capture unit
    
    } FreqCal_Object;
    
    typedef FreqCal_Object *FreqCal_Handle;
    #pragma DATA_SECTION(sendDataC28, "MSGRAM_CPU_TO_CM")
    
    //
    // Functions
    //
    void Board_init(void);                                      // setup for the board
    void EPWM_init(uint32_t base);                              // setup for epwm
    void EPWM_init_interrupt(uint32_t base);
    __interrupt void IPC_ISR1(void);
    __interrupt void cpuTimer0ISR(void);                        // setup for cpu0 interrupt
    __interrupt void cpuTimer1ISR(void);                        // setup for cpu1 interrupt
    __interrupt void cpuTimer2ISR(void);                        // setup for cpu2 interrupt
    __interrupt void epwmISR3(void);                            // setup for epwm3 interrupt
    // __interrupt void epwmISR4(void);
    void initCPUTimers(void);                                   // setup for cpu interrupt
    void configCPUTimer(uint32_t cpuTimer, uint32_t period);    // setup for cpu interrupt
    void setCPU(void);                                          // setup for cpu interrupt
    void EQEP_init(uint32_t base);                              // setup for eqep
    void setGPIO(void);                                         // setup for GPIOs
    void INTERRUPT_init(void);                                  // init interrupt
    void FreqCal_calculate(FreqCal_Handle, uint32_t);
    //__interrupt void IPC_ISR1(void);
    
    //
    //Global Variables
    //
    uint32_t oldcount = 0;          //eqep1, stores the previous position of the clock
    int32_t freq_Right = 0;         //eqep1, measured freq
    uint32_t count = 0;             //eqep1, check if eqep1 is operating
    uint32_t oldcount2 = 0;         //eqep2, stores the previous position of the clock
    int32_t freq_Left =0;           //eqep2, measured freq
    uint32_t count2 = 0;            //eqep2, check if eqep2 is operating
    uint32_t IPCCount1 = 0;
    uint32_t cpuTimer0IntCount = 0; //cpuTimer0, check if cpuTimer0 is operating
    uint32_t cpuTimer1IntCount = 0; //cpuTimer1, check if cpuTimer1 is operating
    uint32_t cpuTimer2IntCount = 0; //cpuTimer2, check if cpuTimer2 is operating
    uint32_t epwmCount = 0;
    uint32_t epwm2Count = 0;
    int targetRPM_Left = 0;         //cpuTimer1, get the input RPM of the left wheel
    int targetRPM_Right = 0;        //cpuTimer1, get the input RPM of the right wheel
    uint16_t dutycycle_Left = 0;    //epwm, turn the input RPM into the dutycycle of pwm
    uint16_t dutycycle_Right = 0;   //epwm, turn the input RPM into the dutycycle of pwm
    const float32_t freq1 = 5000.0; //??
    float32_t tmpLeft = 0;          //??
    float32_t tmpRight = 0;         //??
    float32_t kp=0.75;
    float32_t ki=0.06;
    float32_t kd=0.45;
    PID_Obj handle_Left = {0, 0, 0, 0, 0, 0, 0, -20, 80};
    PID_Obj handle_Right = {0, 0, 0, 0, 0, 0, 0, -20, 80};
    int temp = 0;
    FreqCal_Object freqLeft =
    {
        FREQ_SCALER_PR,  // freqScalerPR
        BASE_FREQ,       // baseFreq
        0, 0,   // Initialize outputs to zero
    };
    FreqCal_Object freqRight =
    {
        FREQ_SCALER_PR,  // freqScalerPR
        BASE_FREQ,       // baseFreq
        0, 0,   // Initialize outputs to zero
    };
    
    //Added 07/12
    float sendDataC28[10];
    uint32_t pass;
    float receiveDataC28[9];
    
    //vehicle Added 07/12
    const float rw = 0.08; //radius of wheel
    const float R = 0.17; //half distance of two wheel
    float controlmatrix[2][2];
    float inv_controlmatrix[2][2];
    
    //parameters Added 07/12
    float feedBackGainEpsilon = 1;
    float feedBackGainB = 0.01;
    
    float sideBysideOmegaGain = 15;
    
    float v_max = 0.25;
    float w_max = 0.5;
    int tmp1 = 0;
    
    
    typedef struct point
    {
        float set_x[4];
        float set_y[4];
        float set_t[4];
        int point_number;
    
    }via_point;
    int path_type = 0;
    const float RS_EPS = 1e-4;
    
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Boot CM core
        //
    #ifdef _FLASH
        Device_bootCM(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
    #else
        Device_bootCM(BOOTMODE_BOOT_TO_S0RAM);
    #endif
    
        //
        // Disable pin locks and enable internal pull-ups.
        //
        Device_initGPIO();
    
    #ifdef ETHERNET
        //
        // Set up EnetCLK to use SYSPLL as the clock source and set the
        // clock divider to 2.
        //
        // This way we ensure that the PTP clock is 100 MHz. Note that this value
        // is not automatically/dynamically known to the CM core and hence it needs
        // to be made available to the CM side code beforehand.
        SysCtl_setEnetClk(SYSCTL_ENETCLKOUT_DIV_2, SYSCTL_SOURCE_SYSPLL);
    
        //
        // Configure the GPIOs for ETHERNET.
        //
    
        //
        // MDIO Signals
        //
        GPIO_setPinConfig(GPIO_105_ENET_MDIO_CLK);
        GPIO_setPinConfig(GPIO_106_ENET_MDIO_DATA);
    
        //
        // Use this only for RMII Mode
        //GPIO_setPinConfig(GPIO_73_ENET_RMII_CLK);
        //
    
        //
        //MII Signals
        //
        GPIO_setPinConfig(GPIO_109_ENET_MII_CRS);
        GPIO_setPinConfig(GPIO_110_ENET_MII_COL);
    
        GPIO_setPinConfig(GPIO_75_ENET_MII_TX_DATA0);
        GPIO_setPinConfig(GPIO_122_ENET_MII_TX_DATA1);
        GPIO_setPinConfig(GPIO_123_ENET_MII_TX_DATA2);
        GPIO_setPinConfig(GPIO_124_ENET_MII_TX_DATA3);
    
        //
        //Use this only if the TX Error pin has to be connected
        //GPIO_setPinConfig(GPIO_46_ENET_MII_TX_ERR);
        //
    
        GPIO_setPinConfig(GPIO_118_ENET_MII_TX_EN);
    
        GPIO_setPinConfig(GPIO_114_ENET_MII_RX_DATA0);
        GPIO_setPinConfig(GPIO_115_ENET_MII_RX_DATA1);
        GPIO_setPinConfig(GPIO_116_ENET_MII_RX_DATA2);
        GPIO_setPinConfig(GPIO_117_ENET_MII_RX_DATA3);
        GPIO_setPinConfig(GPIO_113_ENET_MII_RX_ERR);
        GPIO_setPinConfig(GPIO_112_ENET_MII_RX_DV);
    
        GPIO_setPinConfig(GPIO_44_ENET_MII_TX_CLK);
        GPIO_setPinConfig(GPIO_111_ENET_MII_RX_CLK);
    
        //
        //Power down pin to bring the external PHY out of Power down
        //
        GPIO_setDirectionMode(108, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(108, GPIO_PIN_TYPE_PULLUP);
        GPIO_writePin(108,1);
    
        //
        //PHY Reset Pin to be driven High to bring external PHY out of Reset
        //
    
        GPIO_setDirectionMode(119, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(119, GPIO_PIN_TYPE_PULLUP);
        GPIO_writePin(119,1);
    #endif
    
    #ifdef MCAN
        //
        // Setting the MCAN Clock.
        //
        SysCtl_setMCANClk(SYSCTL_MCANCLK_DIV_4);
    
        //
        // Configuring the GPIOs for MCAN.
        //
        GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANRXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_MCANTXA);
    #endif
    
    #ifdef CANA
        //
        // Configuring the GPIOs for CAN A.
        //
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
    
        //
        // Allocate Shared Peripheral CAN A to the CM Side.
        //
        SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_A,0x1U);
    #endif
    
    #ifdef CANB
        //
        // Configuring the GPIOs for CAN B.
        //
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXB);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXB);
    
        //
        // Allocate Shared Peripheral CAN B to the CM Side.
        //
        SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_CAN_B,0x1U);
    #endif
    
    #ifdef UART
        //
        // Configure GPIO85 as the UART Rx pin.
        //
        GPIO_setPinConfig(GPIO_85_UARTA_RX);
        GPIO_setDirectionMode(85, GPIO_DIR_MODE_IN);
        GPIO_setPadConfig(85, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(85, GPIO_QUAL_ASYNC);
    
        //
        // Configure GPIO84 as the UART Tx pin.
        //
        GPIO_setPinConfig(GPIO_84_UARTA_TX);
        GPIO_setDirectionMode(84, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(84, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(84, GPIO_QUAL_ASYNC);
    #endif
    
    #ifdef USB
    #ifdef USE_20MHZ_XTAL
        //
        // Set up the auxiliary PLL so a 60 MHz output clock is provided to the USB module.
        // This fixed frequency is required for all USB operations.
        //
        SysCtl_setAuxClock(SYSCTL_AUXPLL_OSCSRC_XTAL |
                           SYSCTL_AUXPLL_IMULT(48) |
                           SYSCTL_REFDIV(2U) | SYSCTL_ODIV(4U) |
                           SYSCTL_AUXPLL_DIV_2 |
                           SYSCTL_AUXPLL_ENABLE |
                           SYSCTL_DCC_BASE_0);
    #else
        //
        // Set up the auxiliary PLL so a 60 MHz output clock is provided to the USB module.
        // This fixed frequency is required for all USB operations.
        //
        SysCtl_setAuxClock(SYSCTL_AUXPLL_OSCSRC_XTAL |
                           SYSCTL_AUXPLL_IMULT(48) |
                           SYSCTL_REFDIV(2U) | SYSCTL_ODIV(5U) |
                           SYSCTL_AUXPLL_DIV_2 |
                           SYSCTL_AUXPLL_ENABLE |
                           SYSCTL_DCC_BASE_0);
    #endif
    
        //
        // Allocate Shared Peripheral USB to the CM Side.
        //
        SysCtl_allocateSharedPeripheral(SYSCTL_PALLOCATE_USBA, 1);
    
        GPIO_setPinConfig(GPIO_0_GPIO0);
        GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
        GPIO_setMasterCore(0, GPIO_CORE_CM);
    
        //
        // Set the master core of GPIOs to CM.
        //
        GPIO_setMasterCore(42, GPIO_CORE_CM);
        GPIO_setMasterCore(43, GPIO_CORE_CM);
        GPIO_setMasterCore(46, GPIO_CORE_CM);
        GPIO_setMasterCore(47, GPIO_CORE_CM);
        GPIO_setMasterCore(120, GPIO_CORE_CM);
        GPIO_setMasterCore(121, GPIO_CORE_CM);
    
        //
        // Set the USB DM and DP GPIOs.
        //
        GPIO_setAnalogMode(42, GPIO_ANALOG_ENABLED);
        GPIO_setAnalogMode(43, GPIO_ANALOG_ENABLED);
    
        //
        // Set the direction for VBUS and ID.
        //
        GPIO_setDirectionMode(46, GPIO_DIR_MODE_IN);
        GPIO_setDirectionMode(47, GPIO_DIR_MODE_IN);
    
        //
        // Configure the Power Fault.
        //
        GPIO_setMasterCore(120, GPIO_CORE_CM);
        GPIO_setDirectionMode(120, GPIO_DIR_MODE_IN);
    
        //
        // Configure the External Power Signal Enable.
        //
        GPIO_setMasterCore(121, GPIO_CORE_CM);
        GPIO_setDirectionMode(121, GPIO_DIR_MODE_OUT);
        GPIO_writePin(121, 1);
    
        //
        // Set the CM Clock to run at 120MHz.
        // The CM Clock is a fractional multiple of the AUXPLL Clock (120 Mhz) from
        // which the USB Clock (60 MHz) is derived.
        //
        SysCtl_setCMClk(SYSCTL_CMCLKOUT_DIV_1, SYSCTL_SOURCE_AUXPLL);
    #endif
    
        //Modified
        Interrupt_initModule();
        Interrupt_initVectorTable();
    
        IPC_clearFlagLtoR(IPC_CPU1_L_CM_R, IPC_FLAG_ALL);
        IPC_registerInterrupt(IPC_CPU1_L_CM_R, IPC_INT1, IPC_ISR1);
        // IPC_sync(IPC_CPU1_L_CM_R, IPC_FLAG31);
    
        Board_init();
    
        EINT;
        ERTM;
    
        while(1) {;}
    }
    
    void Board_init(void) {
        EALLOW;
    
        setGPIO();
        EPWM_init(base1);
        EPWM_init(base2);
        EQEP_init(EQEP1_BASE);
        EQEP_init(EQEP2_BASE);
        EPWM_init_interrupt(EPWM3_BASE);
        INTERRUPT_init();
        setCPU();
    
        EDIS;
    }
    
    void setGPIO(void) {
        //EQEP1
        GPIO_setPinConfig(GPIO_20_EQEP1_A);
        GPIO_setPadConfig(20, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_11_EQEP1_B);
        GPIO_setPadConfig(11, GPIO_PIN_TYPE_STD);
    
        //EQEP2
        GPIO_setPinConfig(GPIO_54_EQEP2_A);
        GPIO_setPadConfig(54, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_55_EQEP2_B);
        GPIO_setPadConfig(55, GPIO_PIN_TYPE_STD);
    
        //EPWM1
        GPIO_setPinConfig(GPIO_0_EPWM1A);
        GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    
        //EPWM2
        GPIO_setPinConfig(GPIO_2_EPWM2A);
        GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);
    
        //set GPIO1 for reverse switch left
        GPIO_setPinConfig(GPIO_1_GPIO1);
        GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(1, GPIO_DIR_MODE_OUT);
    
        //set GPIO3 for reverse switch right
        GPIO_setPinConfig(GPIO_3_GPIO3);
        GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(3, GPIO_DIR_MODE_OUT);
    
        //set GPIO8 for forward switch left
        GPIO_setPinConfig(GPIO_8_GPIO8);
        GPIO_setPadConfig(8, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(8, GPIO_DIR_MODE_OUT);
    
        //set GPIO9 for forward switch right
        GPIO_setPinConfig(GPIO_9_GPIO9);
        GPIO_setPadConfig(9, GPIO_PIN_TYPE_STD);
        GPIO_setDirectionMode(9, GPIO_DIR_MODE_OUT);
    }
    
    void EPWM_init_interrupt(uint32_t base) {
        //
        // Disable the ePWM time base clock before configuring the module
        //
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        //
        // Set phase shift to 0 and clear the time base counter
        //
        EPWM_setPhaseShift(base, 0);
        EPWM_setTimeBaseCounter(base, 0);
    
        //
        // Disable the shadow load; the load will be immediate instead
        //
        EPWM_disableCounterCompareShadowLoadMode(base,
                                                 EPWM_COUNTER_COMPARE_A);
        EPWM_disableCounterCompareShadowLoadMode(base,
                                                 EPWM_COUNTER_COMPARE_B);
    
        //
        // Set the compare A value to half the period value, compare B to 0
        //
        EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, PRD_VAL/2);
        //
        // Set action qualifier behavior on compare A events
        // - EPWM1A --> 1 when CTR = CMPA and increasing
        // - EPWM1A --> 0 when CTR = CMPA and decreasing
        //
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    
        //
        // Configure EPWM1B to be complementary to EPWM1A
        //
        EPWM_setDeadBandDelayPolarity(base, EPWM_DB_FED,
                                      EPWM_DB_POLARITY_ACTIVE_LOW);
        EPWM_setDeadBandDelayMode(base, EPWM_DB_FED, true);
        EPWM_setDeadBandDelayMode(base, EPWM_DB_RED, true);
    
        //
        // Enable interrupt when the counter is equal to 0
        //
        EPWM_setInterruptSource(base, EPWM_INT_TBCTR_ZERO);
        EPWM_enableInterrupt(base);
    
        //
        // Interrupt on first event
        //
        EPWM_setInterruptEventCount(base, 1);
    
        //
        // Set the time base clock prescaler to /1
        //
        EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_1,
                               EPWM_HSCLOCK_DIVIDER_1);
    
        //
        // Set the period value; don't shadow the register
        //
        EPWM_setPeriodLoadMode(base, EPWM_PERIOD_DIRECT_LOAD);
        EPWM_setTimeBasePeriod(base, PRD_VAL);
    
        //
        // Put the time base counter into up-down count mode
        //
        EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN);
    
        //
        // Sync the ePWM time base clock
        //
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    }
    
    void EPWM_init(uint32_t base) {
        // setup TBCLK for EPWM
        EPWM_setTimeBasePeriod(base, EPWM_TIMER_TBPRD);
        EPWM_setPhaseShift(base, 0U);
        EPWM_setTimeBaseCounter(base, 0U);
        EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN);
        EPWM_disablePhaseShiftLoad(base);
    
        // setup epwm prescalar
        EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_4, EPWM_HSCLOCK_DIVIDER_4);
    
        // setup compare
        EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, 1*EPWM_TIMER_TBPRD/100);
    
        // setup actions
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
        EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    }
    
    void EQEP_init(uint32_t base) {
        //myEQEP0 initialization
    
        EQEP_SourceSelect source_myEQEP0 =
        {
            EQEP_SOURCE_DEVICE_PIN,         // eQEPA source
            EQEP_SOURCE_DEVICE_PIN,     // eQEPB source
            EQEP_SOURCE_DEVICE_PIN,     // eQEP Index source
        };
        // Selects the source for eQEPA/B/I signals
        EQEP_selectSource(base, source_myEQEP0);
        // Set the strobe input source of the eQEP module.
        EQEP_setStrobeSource(base,EQEP_STROBE_FROM_GPIO);
        // Sets the polarity of the eQEP module's input signals.
        EQEP_setInputPolarity(base,false,false,false,false);
        // Configures eQEP module's quadrature decoder unit.
        EQEP_setDecoderConfig(base, (EQEP_CONFIG_UP_COUNT | EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE));
        // Set the emulation mode of the eQEP module.
        EQEP_setEmulationMode(base,EQEP_EMULATIONMODE_RUNFREE);
        // Configures eQEP module position counter unit.
        EQEP_setPositionCounterConfig(base,EQEP_POSITION_RESET_1ST_IDX,4294967295U);
        // Sets the current encoder position.
        EQEP_setPosition(base,0U);
        // Enables the eQEP module unit timer.
        EQEP_enableUnitTimer(base,2000000U);
        // Disables the eQEP module watchdog timer.
        EQEP_disableWatchdog(base);
        // Configures the quadrature modes in which the position count can be latched.
        EQEP_setLatchMode(base,(EQEP_LATCH_UNIT_TIME_OUT|EQEP_LATCH_RISING_STROBE|EQEP_LATCH_RISING_INDEX));
        // Set the quadrature mode adapter (QMA) module mode.
        EQEP_setQMAModuleMode(base,EQEP_QMA_MODE_BYPASS);
        // Disable Direction Change During Index
        EQEP_disableDirectionChangeDuringIndex(base);
        // Configures the mode in which the position counter is initialized.
        EQEP_setPositionInitMode(base,(EQEP_INIT_DO_NOTHING));
        // Sets the software initialization of the encoder position counter.
        EQEP_setSWPositionInit(base,true);
        // Sets the init value for the encoder position counter.
        EQEP_setInitialPosition(base,0U);
        // Enables the eQEP module.
        EQEP_enableModule(base);
        // Configures eQEP module edge-capture unit.
        EQEP_setCaptureConfig(base,EQEP_CAPTURE_CLK_DIV_128,EQEP_UNIT_POS_EVNT_DIV_8);
        // Enables the eQEP module edge-capture unit.
        EQEP_enableCapture(base);
    }
    
    void INTERRUPT_init() {
        //Interrupt Setting for epwmISR3
        Interrupt_register(INT_EPWM3, &epwmISR3);
        Interrupt_enable(INT_EPWM3);
    
        /*
        Interrupt_register(INT_EPWM4, &epwmISR4);
        Interrupt_enable(INT_EPWM4);
        */
    
        //Interrupt Setting for cpuTimer0ISR
        Interrupt_register(INT_TIMER0, &cpuTimer0ISR);
        Interrupt_enable(INT_TIMER0);
    
        //Interrupt Setting for cpuTimer1ISR
        Interrupt_register(INT_TIMER1, &cpuTimer1ISR);
        Interrupt_enable(INT_TIMER1);
    
        //Interrupt Setting for cpuTimer2ISR
        Interrupt_register(INT_TIMER2, &cpuTimer2ISR);
        Interrupt_enable(INT_TIMER2);
    }
    
    void setCPU() {
        initCPUTimers();
    
        cpuTimer0IntCount = 0;
        cpuTimer1IntCount = 0;
        cpuTimer2IntCount = 0;
    
        configCPUTimer(CPUTIMER0_BASE, 10000);
        configCPUTimer(CPUTIMER1_BASE, 10000);
        configCPUTimer(CPUTIMER2_BASE, 10000);
    
        CPUTimer_enableInterrupt(CPUTIMER0_BASE);
        CPUTimer_enableInterrupt(CPUTIMER1_BASE);
        CPUTimer_enableInterrupt(CPUTIMER2_BASE);
    
        CPUTimer_startTimer(CPUTIMER0_BASE);
        CPUTimer_startTimer(CPUTIMER1_BASE);
        CPUTimer_startTimer(CPUTIMER2_BASE);
    }
    
    void initCPUTimers(void) {
        CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFF);
        CPUTimer_setPeriod(CPUTIMER1_BASE, 0xFFFFFFFF);
        CPUTimer_setPeriod(CPUTIMER2_BASE, 0xFFFFFFFF);
    
        CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);
        CPUTimer_setPreScaler(CPUTIMER1_BASE, 0);
        CPUTimer_setPreScaler(CPUTIMER2_BASE, 0);
    
        CPUTimer_stopTimer(CPUTIMER0_BASE);
        CPUTimer_stopTimer(CPUTIMER1_BASE);
        CPUTimer_stopTimer(CPUTIMER2_BASE);
    
        CPUTimer_reloadTimerCounter(CPUTIMER0_BASE);
        CPUTimer_reloadTimerCounter(CPUTIMER1_BASE);
        CPUTimer_reloadTimerCounter(CPUTIMER2_BASE);
    
        cpuTimer0IntCount = 0;
        cpuTimer1IntCount = 0;
        cpuTimer2IntCount = 0;
    }
    
    void configCPUTimer(uint32_t cpuTimer, uint32_t period) {
        uint32_t temp, freq = DEVICE_SYSCLK_FREQ;
    
        //
        // Initialize timer period:
        //
        temp = ((freq / 1000000) * period);
        CPUTimer_setPeriod(cpuTimer, temp);
    
        //
        // Set pre-scale counter to divide by 1 (SYSCLKOUT):
        //
        CPUTimer_setPreScaler(cpuTimer, 0);
    
        //
        // Initializes timer control register. The timer is stopped, reloaded,
        // free run disabled, and interrupt enabled.
        // Additionally, the free and soft bits are set
        //
        CPUTimer_stopTimer(cpuTimer);
        CPUTimer_reloadTimerCounter(cpuTimer);
        CPUTimer_setEmulationMode(cpuTimer,
                                  CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);
        CPUTimer_enableInterrupt(cpuTimer);
    
        //
        // Resets interrupt counters for the three cpuTimers
        //
        if (cpuTimer == CPUTIMER0_BASE) {
            cpuTimer0IntCount = 0;
        }
        if (cpuTimer == CPUTIMER1_BASE) {
            cpuTimer1IntCount = 0;
        }
        if (cpuTimer == CPUTIMER2_BASE) {
            cpuTimer2IntCount = 0;
        }
    }
    
    __interrupt void epwmISR3(void) {
        epwmCount++;
        FreqCal_calculate(&freqLeft, EQEP1_BASE);
    
        EPWM_clearEventTriggerInterruptFlag(EPWM3_BASE);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP2);
    }
    
    /*
    __interrupt void epwmISR4(void) {
        epwm2Count++;
        FreqCal_calculate(&freqRight, EQEP2_BASE);
    
        EPWM_clearEventTriggerInterruptFlag(EPWM4_BASE);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP2);
    }
    */
    
    __interrupt void cpuTimer0ISR(void) {
        /*
        //send what
        sendDataC28[0] = 0;
        sendDataC28[1] = 0;
        sendDataC28[2] = 0;
        sendDataC28[3] = 0;
        IPC_sendCommand(IPC_CPU1_L_CM_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
                        IPC_CMD_READ_MEM, (uint32_t)sendDataC28, 10);
    
        IPC_waitForAck(IPC_CPU1_L_CM_R, IPC_FLAG0);
        if(IPC_getResponse(IPC_CPU1_L_CM_R) == TEST_PASS){
            pass = 1;
        }
        else{
            pass = 0;
        }
        */
    
        cpuTimer0IntCount++;
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    }
    
    __interrupt void cpuTimer1ISR(void) {
        PID_setGains(&handle_Left, kp, ki, kd);
        PID_setGains(&handle_Right, kp, ki, kd);
        //step.1-1 turn rpm into dutycycle
        //available zone [Forward:10~80 RPM, Backward:6~20 RPM]
        if (targetRPM_Left<0){
            //PID_run_parallel [handle, DesireValue, FeedbackValue, FeedforwardValue, Pointer to the output]
            PID_run_parallel(&handle_Left, targetRPM_Left, -freq_Left/4, 0, &tmpLeft);
            dutycycle_Left = (1-(-tmpLeft*0.0165+0.1928))*100;
        }
        else{
            PID_run_parallel(&handle_Left, targetRPM_Left, freq_Left/4, 0, &tmpLeft);
            dutycycle_Left = (1-(tmpLeft*0.0041+0.2963))*100;
        }
        if (targetRPM_Right<0){
            PID_run_parallel(&handle_Right, targetRPM_Right, -freq_Right/4, 0, &tmpRight);
            dutycycle_Right = (1-(-tmpRight*0.0171+0.1928))*100;
        }
        else{
            PID_run_parallel(&handle_Right, targetRPM_Right, freq_Right/4, 0, &tmpRight);
            dutycycle_Right = (1-(tmpRight*0.0041+0.2996))*100;
        }
    
        if (dutycycle_Left>=70){
            EPWM_setCounterCompareValue(base1, EPWM_COUNTER_COMPARE_A, 99*EPWM_TIMER_TBPRD/100);
            PID_setUi(&handle_Left, 0);
        }
        else{
            EPWM_setCounterCompareValue(base1, EPWM_COUNTER_COMPARE_A, dutycycle_Left*EPWM_TIMER_TBPRD/100);
        }
        if (dutycycle_Right>=70){
            EPWM_setCounterCompareValue(base2, EPWM_COUNTER_COMPARE_A, 99*EPWM_TIMER_TBPRD/100);
            PID_setUi(&handle_Right, 0);
        }
        else{
            EPWM_setCounterCompareValue(base2, EPWM_COUNTER_COMPARE_A, dutycycle_Right*EPWM_TIMER_TBPRD/100);
        }
        //step.1-2 decide the direction
        //the direction for the left wheel
        if (targetRPM_Left>0){
            GPIO_writePin(8,1);
            GPIO_writePin(1,0);
        }
        else if (targetRPM_Left<0){
            GPIO_writePin(8,0);
            GPIO_writePin(1,1);
        }
        else{
            GPIO_writePin(8,0);
            GPIO_writePin(1,0);
        }
        //the direction for the right wheel
        if (targetRPM_Right>0){
            GPIO_writePin(9,1);
            GPIO_writePin(3,0);
        }
        else if (targetRPM_Right<0){
            GPIO_writePin(9,0);
            GPIO_writePin(3,1);
        }
        else{
            GPIO_writePin(9,0);
            GPIO_writePin(3,0);
        }
    
        //step.2 let f2838x generate the dutycycle we want
    
        cpuTimer1IntCount++;
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    }
    
    __interrupt void cpuTimer2ISR(void) {
        cpuTimer2IntCount++;
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    }
    
    __interrupt void IPC_ISR1() {
        uint32_t command, addr, data;
        int i;
        bool status = false;
        IPC_readCommand(IPC_CPU1_L_CM_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,
                        &command, &addr, &data);
        if(command == IPC_CMD_READ_MEM)
        {
            status = true;
            for(i=0; i<data; i++)
            {
                receiveDataC28[i] = *((float *)addr + i);
            }
        }
        if(status)
        {
            IPC_sendResponse(IPC_CPU1_L_CM_R, TEST_PASS);
        }
        else
        {
            IPC_sendResponse(IPC_CPU1_L_CM_R, TEST_FAIL);
        }
        IPC_ackFlagRtoL(IPC_CPU1_L_CM_R, IPC_FLAG1);
        //Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);
        IPCCount1++;
    }
    
    void FreqCal_calculate(FreqCal_Object *p, uint32_t base) {
        uint32_t temp;
        //
        // **** Frequency calculation using eQEP capture counter ****
        //
        // Check for unit position event
        //
        if((EQEP_getStatus(base) & EQEP_STS_UNIT_POS_EVNT) != 0)
        {
            //
            // No capture overflow
            //
            if((EQEP_getStatus(base) & EQEP_STS_CAP_OVRFLW_ERROR) == 0)
            {
                temp = (uint32_t)EQEP_getCapturePeriodLatch(base);
            }
            else
            {
                //
                // Capture overflow, saturate the result
                //
                temp = 0xFFFF;
            }
    
            //
            // p->freqPR = X / [(t2 - t1) * 10kHz]
            //
            p->freqPR = _IQdiv(p->freqScalerPR, temp);
            temp = p->freqPR;
    
            if(temp > _IQ(1))
            {
                p->freqPR = _IQ(1);
            }
            else
            {
                p->freqPR = temp;
            }
    
            //
            // Q0 = Q0 * GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
            // p->freqHzPR = (p->freqPR) * 10kHz = X / (t2 - t1)
            //
            p->freqHzPR = _IQmpy(p->baseFreq, p->freqPR);
    
            //
            // Clear unit position event flag and overflow error flag
            //
            EQEP_clearStatus(base, (EQEP_STS_UNIT_POS_EVNT |
                                          EQEP_STS_CAP_OVRFLW_ERROR));
        }
    }
    

  • Hi Hao-Yu,

    When you used ex4 with eqep interrupts, were your interrupts functioning correctly? It would be difficult to debug your code as it looks like the configurations are the same, but I will have to look into more detail. Can you try stepping through your code to see why the interrupt only occurs once? 

    Regarding your note about it only being accurate for high frequency pulses, this is due to the approach used to estimate the frequency. Typically in motor sensing applications, different techniques are used depending on if it is measuring a high-frequency input vs. a low-frequency input, and the software dynamically changes depending on the incoming signal. The eQEP's edge capture unit is designed for measuring low-frequency inputs, and you can find more information about that in the TRM's eQEP chapter. I believe there is example code for this dynamic switching in the motor control sdk

    Regards,

    Peter

  • Hi Peter,

    I am trying to ex1 in the program this time. Because EPWM1 and EPWM2 are used, so I tried to use EPWM3 instead.

    Line496, I init epwm3 for the interrupt. And I init EQEP on line 595. Then I init the interrupt on line 644. Last, the interrupt function is on line 746.

    I'll try to find something from the TRM's eQEP chapter too, thanks.

    Regards,

    Hao-YU

  • Hi Peter,

    I found out what is the mistake!!! I made a typo on line 751, in the interrupt of epwmISR, I accidentally typed "INTERRUPT_ACK_GROUP2", and it should be "INTERRUPT_ACK_GROUP3". After changing this, it works!!! But I'd like to ask what's the difference between each INTERRUPT_ACK_GROUPx? And I'll mark the question as solved.

    Thanks for your help!!!

    Best Regards,

    Hao-Yu

  • Hi Hao-Yu,

    Glad you were able to resolve the issue! Regarding your question about the INTERRUPTs, this is known as PIE channel mapping and each peripheral has a muxed signal connected to the CPU with which it can use to issue interrupts. If you configure the incorrect one, then you would not have the correct connection and would not be able to issue interrupts, hence the behavior you saw. You can read more about interrupts in the C2000 Academy Deep Dive module, it goes fairly in-depth while providing an easy-to read explanation.

    Regards,

    Peter