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.

LAUNCHXL-F28379D: F28379D Launchpad ePWM UpDown mode bug

Part Number: LAUNCHXL-F28379D

Hello,

I want to create two PWMs on ePWM1 that work in updown mode (I need updown mode because I want to add software deadtime). PWMs are inverted, so when one is high, the other one is low and vice versa. Now, my error is the following: When using updown mode, I can't change duty cycle of one PWM over a certain threshold (around 62%) and I can't lower the other PWM under around 37%. Also, freq of both PWMs is bad, it gets lowered. I can't get the needed duty cycle even if I put duty cycle lower than 62%. So if I want 50% on both PWMs, I will get like 40% on one and like 60% on the other, with freq being 1.7k instead of 2.5k on both. Now, if I use up mode, everything works fine, but I need updown mode. I'm measuring using oscilloscope. Here's my code:

#include "epwm_device.h"

interrupt void isr_epwm2(void)
{
    PieCtrlRegs.PIEACK.bit.ACK3 = 1;

    EPwm2Regs.ETCLR.bit.INT = 1;
    EPwm2Regs.ETCLR.bit.SOCA = 1;
}

void init_epwm()
{
    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0;

    //reset PWM1
    DevCfgRegs.SOFTPRES2.bit.EPWM1 = 1;
    DevCfgRegs.SOFTPRES2.bit.EPWM1 = 0;

    //reset PWM2
    DevCfgRegs.SOFTPRES2.bit.EPWM2 = 1;
    DevCfgRegs.SOFTPRES2.bit.EPWM2 = 0;

    EDIS;

    //konfiguracija ePWM1
    //podesi takt ePWM modula
    EPwm1Regs.TBCTL.bit.CLKDIV = 0; //delilac takta 1

    //pauziraj PWM tokom pauze u debagovanju
    EPwm1Regs.TBCTL.bit.FREE_SOFT = 0;

    //pocetni smer brojanja na gore
    EPwm1Regs.TBCTL.bit.PHSDIR = START_COUNT_UP;

    //omoguci TBPHS registar
    EPwm1Regs.TBCTL.bit.PHSEN = 1;

    //simetricni PWM (up-down count mode)
    EPwm1Regs.TBCTL.bit.CTRMODE = CTR_UPDOWN;

    //pocetna faza 0, period 10000 taktova
    EPwm1Regs.TBPHS.all = EPWM1_PHASE;
    EPwm1Regs.TBPRD = EPWM1_PERIOD;

    //podesi compare registre
    //registar A mora biti veci za 1000 zbog mrtvog vremena
    EPwm1Regs.CMPA.bit.CMPA = EPWM1_CMPA;
    EPwm1Regs.CMPB.bit.CMPB = EPWM1_CMPB;

    //kanal A - na uzlaznoj ivici HIGH, na silaznoj LOW
    //kanal B - suprotno
    EPwm1Regs.AQCTLA.bit.CAU = AQ_HIGH;
    EPwm1Regs.AQCTLA.bit.CAD = AQ_LOW;
    EPwm1Regs.AQCTLB.bit.CBU = AQ_LOW;
    EPwm1Regs.AQCTLB.bit.CBD = AQ_HIGH;

    // konfiguracija EPWM2
    EPwm2Regs.TBCTL.bit.CLKDIV = 0;     // delilac takta 1
    EPwm2Regs.TBCTL.bit.FREE_SOFT = 0;  // blokiraj tokom debug pauze
    EPwm2Regs.TBCTL.bit.PHSDIR = START_COUNT_DOWN;     // pocetna faza na gore
    EPwm2Regs.TBCTL.bit.PHSEN = 1;      // omoguci registar faze
    EPwm2Regs.TBCTL.bit.CTRMODE = CTR_UP;    // up count mod

    // pocetna faza 0, period 10000 taktova
    EPwm2Regs.TBPHS.all = EPWM2_PHASE;
    EPwm2Regs.TBPRD = EPWM2_PERIOD;

    // pusti ADC1 SOC na svakom maksimumu brojaca
    EPwm2Regs.ETSEL.bit.SOCAEN = 1; // ukljuci SOC A
    EPwm2Regs.ETSEL.bit.SOCASEL = 1; // na svaku nulu
    EPwm2Regs.ETPS.bit.SOCAPRD = 1;

    // prekid da resetuje flagove
    EPwm2Regs.ETSEL.bit.INTEN = 1; // ukljuci EPWM2INT
    EPwm2Regs.ETSEL.bit.INTSEL = 1; // na svaku nulu
    EPwm2Regs.ETPS.bit.INTPRD = 1;

    // debug
    EPwm2Regs.AQCTLA.bit.ZRO = AQ_TOGGLE; // toggle na nulu

    //pustanje kloka na PWMove
    EALLOW;

    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;

    EDIS;
}

  • If header file is needed as well:

    #ifndef EPWM_DEVICE_H_
    #define EPWM_DEVICE_H_
    
    #include "F2837xD_device.h"
    
    interrupt void isr_epwm2(void);
    
    void init_epwm();
    
    //User defines
    #define EPWM1_PHASE 0
    #define EPWM1_PERIOD 10000
    #define EPWM1_CMPA 5000
    #define EPWM1_CMPB 4000
    
    #define EPWM2_PHASE 0
    #define EPWM2_PERIOD 10000
    
    enum {
        START_COUNT_DOWN,
        START_COUNT_UP
    };
    
    enum {
        CTR_UP,
        CTR_DOWN,
        CTR_UPDOWN,
        CTR_FREEZE
    };
    
    enum {
        AQ_NOTHING,
        AQ_LOW,
        AQ_HIGH,
        AQ_TOGGLE
    };
    
    #endif /* EPWM_DEVICE_H_ */

  • Your ePWM setup is incorrect. Please look at the code below:

    It has DEADBAND MODULE USED to invert the second PWM.

    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    #define EPWM_TIMER_TBPRD    2000UL
    
    //
    // Function Prototypes
    //
    void initEPWMWithoutDB(uint32_t epwm_base);
    void initEPWMGPIO(void);
    void setupEPWMActiveHigh(uint32_t epwm_base);
    void setupEPWMActiveLow(uint32_t epwm_base);
    void setupEPWMActiveHighComplementary(uint32_t epwm_base);
    void setupEPWMActiveLowComplementary(uint32_t epwm_base);
    void setupEPWMOutputSwap(uint32_t epwm_base);
    
    void main(void)
    {
    
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Disable pin locks and enable internal pull-ups.
        //
        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();
    
        //
        // Configure ePWMs
        //
        initEPWMGPIO();
    
        //
        // Disable sync(Freeze clock to PWM as well)
        //
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        //
        // Initialize ePWM1
        //
        initEPWMWithoutDB(EPWM1_BASE);
    
        //
        // Initialize ePWM2 Active High
        //
        initEPWMWithoutDB(EPWM2_BASE);
        setupEPWMActiveHigh(EPWM2_BASE);
    
        //
        // Initialize ePWM3 Active Low
        //
        initEPWMWithoutDB(EPWM3_BASE);
        setupEPWMActiveLow(EPWM3_BASE);
    
        //
        // Initialize ePWM4 Active High Complimentary
        //
        initEPWMWithoutDB(EPWM4_BASE);
        setupEPWMActiveHighComplementary(EPWM4_BASE);
    
        //
        // Initialize ePWM5 Active Low Complimentary
        //
        initEPWMWithoutDB(EPWM5_BASE);
        setupEPWMActiveLowComplementary(EPWM5_BASE);
    
        //
        // Initialize ePWM6 Output Swap (switch A and B outputs)
        //
        initEPWMWithoutDB(EPWM6_BASE);
        setupEPWMOutputSwap(EPWM6_BASE);
    
        //
        // Enable sync and clock to PWM
        //
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
    
        //
        // Enable Global Interrupt (INTM) and real time interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // IDLE loop. Just sit and loop forever (optional):
        //
        for(;;)
        {
            NOP;
        }
    
    
    }
    
    
    void setupEPWMOutputSwap(uint32_t epwm_base)
    {
    
        //
        // Disable RED
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, false);
    
        //
        // Disable FED
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, false);
    
        //
        // Switch Output A with Output B
        //
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, true);
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, true);
    
    }
    
    void setupEPWMActiveHigh(uint32_t epwm_base)
    {
        //
        // Use EPWMA as the input for both RED and FED
        //
        EPWM_setRisingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
    
        //
        // Set the RED and FED values
        //
        EPWM_setFallingEdgeDelayCount(epwm_base, 200);
        EPWM_setRisingEdgeDelayCount(epwm_base, 400);
    
        //
        // Do not invert the delayed outputs (AH)
        //
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_HIGH);
    
        //
        // Use the delayed signals instead of the original signals
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, true);
    
        //
        // DO NOT Switch Output A with Output B
        //
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, false);
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, false);
    
    }
    
    void setupEPWMActiveLowComplementary(uint32_t epwm_base)
    {
        //
        // Use EPWMA as the input for both RED and FED
        //
        EPWM_setRisingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
    
        //
        // Set the RED and FED values
        //
        EPWM_setFallingEdgeDelayCount(epwm_base, 200);
        EPWM_setRisingEdgeDelayCount(epwm_base, 400);
    
        //
        // Invert only the Rising Edge delayed output (ALC)
        //
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_LOW);
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_HIGH);
    
        //
        // Use the delayed signals instead of the original signals
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, true);
    
        //
        // DO NOT Switch Output A with Output B
        //
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, false);
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, false);
    
    }
    
    
    void setupEPWMActiveHighComplementary(uint32_t epwm_base)
    {
        //
        // Use EPWMA as the input for both RED and FED
        //
        EPWM_setRisingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
    
        //
        // Set the RED and FED values
        //
        EPWM_setFallingEdgeDelayCount(epwm_base, 200);
        EPWM_setRisingEdgeDelayCount(epwm_base, 400);
    
        //
        // Invert only the Falling Edge delayed output (AHC)
        //
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
    
        //
        // Use the delayed signals instead of the original signals
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, true);
    
        //
        // DO NOT Switch Output A with Output B
        //
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, false);
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, false);
    
    }
    
    
    
    void setupEPWMActiveLow(uint32_t epwm_base)
    {
        //
        // Use EPWMA as the input for both RED and FED
        //
        EPWM_setRisingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(epwm_base, EPWM_DB_INPUT_EPWMA);
    
        //
        // Set the RED and FED values
        //
        EPWM_setFallingEdgeDelayCount(epwm_base, 200);
        EPWM_setRisingEdgeDelayCount(epwm_base, 400);
    
        //
        // INVERT the delayed outputs (AL)
        //
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_LOW);
        EPWM_setDeadBandDelayPolarity(epwm_base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
    
        //
        // Use the delayed signals instead of the original signals
        //
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(epwm_base, EPWM_DB_FED, true);
    
        //
        // DO NOT Switch Output A with Output B
        //
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_A, false);
        EPWM_setDeadBandOutputSwapMode(epwm_base, EPWM_DB_OUTPUT_B, false);
    
    }
    
    
    //
    // initEPWM - Configure ePWM1
    //
    void initEPWMWithoutDB(uint32_t epwm_base)
    {
        //
        // Set-up TBCLK
        //
        EPWM_setTimeBasePeriod(epwm_base, EPWM_TIMER_TBPRD);
        EPWM_setPhaseShift(epwm_base, 0U);
        EPWM_setTimeBaseCounter(epwm_base, 0U);
        EPWM_setTimeBaseCounterMode(epwm_base, EPWM_COUNTER_MODE_UP_DOWN);
        EPWM_disablePhaseShiftLoad(epwm_base);
    
        //
        // Set ePWM clock pre-scaler
        //
        EPWM_setClockPrescaler(epwm_base,
                               EPWM_CLOCK_DIVIDER_4,
                               EPWM_HSCLOCK_DIVIDER_4);
    
        //
        // Set up shadowing
        //
        EPWM_setCounterCompareShadowLoadMode(epwm_base,
                                             EPWM_COUNTER_COMPARE_A,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
        //
        // Set-up compare
        //
        EPWM_setCounterCompareValue(epwm_base, EPWM_COUNTER_COMPARE_A, EPWM_TIMER_TBPRD/4);
        EPWM_setCounterCompareValue(epwm_base, EPWM_COUNTER_COMPARE_B, 3*EPWM_TIMER_TBPRD/4);
    
        //
        // Set actions
        //
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_LOW,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_HIGH,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_NO_CHANGE,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_LOW,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    
    
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_B,
                                          EPWM_AQ_OUTPUT_LOW,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_B,
                                          EPWM_AQ_OUTPUT_HIGH,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_B,
                                          EPWM_AQ_OUTPUT_NO_CHANGE,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
        EPWM_setActionQualifierAction(epwm_base,
                                          EPWM_AQ_OUTPUT_B,
                                          EPWM_AQ_OUTPUT_LOW,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
    
    }
    
    //
    // initEPWMGPIO - Configure ePWM GPIO
    //
    void initEPWMGPIO(void)
    {
        //
        // Disable pull up on GPIO 0 configure them as PWM1A
        //
        GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_0_EPWM1A);
    
        //
        // Disable pull up on GPIO 1 configure them as PWM1B
        //
        GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_1_EPWM1B);
    
        //
        // Disable pull up on GPIO 2 configure them as PWM2A
        //
        GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_2_EPWM2A);
    
        //
        // Disable pull up on GPIO 3 configure them as PWM2B
        //
        GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_3_EPWM2B);
    
        //
        // Disable pull up on GPIO 4 configure them as PWM3A
        //
        GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_4_EPWM3A);
    
        //
        // Disable pull up on GPIO 5 configure them as PWM3B
        //
        GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_5_EPWM3B);
    
        //
        // Disable pull up on GPIO 6 configure them as PWM4A
        //
        GPIO_setPadConfig(6, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_6_EPWM4A);
    
        //
        // Disable pull up on GPIO 7 configure them as PWM4B
        //
        GPIO_setPadConfig(7, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_7_EPWM4B);
    
        //
        // Disable pull up on GPIO 8 configure them as PWM5A
        //
        GPIO_setPadConfig(8, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_8_EPWM5A);
    
        //
        // Disable pull up on GPIO 9 configure them as PWM5B
        //
        GPIO_setPadConfig(9, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_9_EPWM5B);
    
        //
        // Disable pull up on GPIO 10 configure them as PWM6A
        //
        GPIO_setPadConfig(10, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_10_EPWM6A);
    
        //
        // Disable pull up on GPIO 11 configure them as PWM6B
        //
        GPIO_setPadConfig(11, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_11_EPWM6B);
    
    }
    

  • I used your code and made a code that works, but just simply for a learning opportunity, why doesn't the code I posted work?

  • Well look at the registers that I'm writing to vs the ones you have.

    Step 1, I would set PHSEN to 0.

    Nima