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.

TMS320F280025C: Use DMA for ePWM with twice the speed

Part Number: TMS320F280025C


Tool/software:

Hi,

I need the possibility to run the ePWM module with the DMA but 2 times faster. The Background is that I want to update the ePWM module with the DMA for center aligned PWM. 

FOC (Field Oriented Control) is done with around 20kHz and the PWM is at 40kHz. Now to count for the phase delay for a highspeed application, the DMA should already contain 4 sets of PWM. So I want the update for center aligned PWM also in the middle.

I already tried out the epwm_ex9_dma example in the TI examples but I was not able to achieve that. Any ideas how that could be done?

EDIT1: I tried in a first step to update the DMA with every PWM cycle and the FOC ISR at half the speed but I am not able to achieve that:

EPWM init (From Universal Motor Control):

    // USER_M1_NUM_PWM_TICKS_PER_ISR_TICK = 2        
           
    uint16_t       pwmPeriodCycles = (uint16_t)(USER_M1_PWM_TBPRD_NUM);
    uint16_t       pwmPeriodBCCycles = (uint16_t)(USER_M1_BC_TBPRD_NUM);
    uint16_t       numPWMTicksPerISRTick = USER_M1_NUM_PWM_TICKS_PER_ISR_TICK;
        
        // setup the Time-Base Control Register (TBCTL)
        EPWM_setTimeBaseCounterMode(obj->pwmHandle[cnt],
                                    EPWM_COUNTER_MODE_UP_DOWN);

        EPWM_disablePhaseShiftLoad(obj->pwmHandle[cnt]);

//        EPWM_setPeriodLoadMode(obj->pwmHandle[cnt], EPWM_PERIOD_SHADOW_LOAD); //EPWM_PERIOD_SHADOW_LOAD //EPWM_PERIOD_DIRECT_LOAD
        EPWM_setPeriodLoadMode(obj->pwmHandle[cnt], EPWM_PERIOD_SHADOW_LOAD); //EPWM_PERIOD_SHADOW_LOAD //EPWM_PERIOD_DIRECT_LOAD

        EPWM_enableSyncOutPulseSource(obj->pwmHandle[cnt],
                                      EPWM_SYNC_OUT_PULSE_ON_SOFTWARE);

        EPWM_setClockPrescaler(obj->pwmHandle[cnt], EPWM_CLOCK_DIVIDER_1,
                                 EPWM_HSCLOCK_DIVIDER_1);

        EPWM_setCountModeAfterSync(obj->pwmHandle[cnt],
                                   EPWM_COUNT_MODE_UP_AFTER_SYNC);

        EPWM_setEmulationMode(obj->pwmHandle[cnt], EPWM_EMULATION_FREE_RUN);

        // setup the Timer-Based Phase Register (TBPHS)
        EPWM_setPhaseShift(obj->pwmHandle[cnt], 0);

        // setup the Time-Base Counter Register (TBCTR)
        EPWM_setTimeBaseCounter(obj->pwmHandle[cnt], 0);

        // setup the Time-Base Period Register (TBPRD)
        // set to zero initially
        EPWM_setTimeBasePeriod(obj->pwmHandle[cnt], 0);

        // setup the Counter-Compare Control Register (CMPCTL)
        EPWM_setCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                             EPWM_COUNTER_COMPARE_A,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO); //EPWM_COMP_LOAD_ON_CNTR_ZERO

        EPWM_setCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                             EPWM_COUNTER_COMPARE_B,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);

        EPWM_setCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                             EPWM_COUNTER_COMPARE_C,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);

        EPWM_setCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                             EPWM_COUNTER_COMPARE_D,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
                // setup the Action-Qualifier Output A Register (AQCTLA)
        EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

        EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);

        EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);

        EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
                 // setup the Dead-Band Generator Control Register (DBCTL)
        EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_FED, true);

        // select EPWMA as the input to the dead band generator
        EPWM_setRisingEdgeDeadBandDelayInput(obj->pwmHandle[cnt],
                                             EPWM_DB_INPUT_EPWMA);

        // configure the right polarity for active high complementary config.
        EPWM_setDeadBandDelayPolarity(obj->pwmHandle[cnt],
                                      EPWM_DB_RED,
                                      EPWM_DB_POLARITY_ACTIVE_HIGH);
                 EPWM_setDeadBandDelayPolarity(obj->pwmHandle[cnt],
                                      EPWM_DB_FED,
                                      EPWM_DB_POLARITY_ACTIVE_LOW);
                // setup the Dead-Band Rising Edge Delay Register (DBRED)
        EPWM_setRisingEdgeDelayCount(obj->pwmHandle[cnt], MTR1_PWM_DBRED_CNT);

        // setup the Dead-Band Falling Edge Delay Register (DBFED)
        EPWM_setFallingEdgeDelayCount(obj->pwmHandle[cnt], MTR1_PWM_DBFED_CNT);
                // setup the PWM-Chopper Control Register (PCCTL)
        EPWM_disableChopper(obj->pwmHandle[cnt]);

        // setup the Trip Zone Select Register (TZSEL)
        EPWM_disableTripZoneSignals(obj->pwmHandle[cnt], HAL_TZSEL_SIGNALS_ALL);
        
            // setup the Event Trigger Selection Register (ETSEL)
    EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO); //EPWM_INT_TBCTR_ZERO

    EPWM_enableInterrupt(obj->pwmHandle[0]);

    //Initial ADC trigger --> used for FOC
    EPWM_setADCTriggerSource(obj->pwmHandle[0], EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC); //EPWM_SOC_TBCTR_D_CMPC
    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);
    
        EPWM_setInterruptEventCount(obj->pwmHandle[0], numPWMTicksPerISRTick);

    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_A,
                                    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_B,
                                    numPWMTicksPerISRTick);
                                    
        // setup the Event Trigger Clear Register (ETCLR)
    EPWM_clearEventTriggerInterruptFlag(obj->pwmHandle[0]);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[0], EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[0], EPWM_SOC_B);

    // since the PWM is configured as an up/down counter, the period register is
    // set to one-half of the desired PWM period
    EPWM_setTimeBasePeriod(obj->pwmHandle[0], pwmPeriodCycles);
    EPWM_setTimeBasePeriod(obj->pwmHandle[1], pwmPeriodCycles);
    EPWM_setTimeBasePeriod(obj->pwmHandle[2], pwmPeriodCycles);

    // write the PWM data value  for ADC trigger
    EPWM_setCounterCompareValue(obj->pwmHandle[0], EPWM_COUNTER_COMPARE_C, 10);
    
    

DMA Init:

    //
    // DMA CH4
    //
    DMA_configAddresses(DMA_CH4_BASE, (uint16_t *)(MTR1_PWM_U_BASE + EPWM_O_CMPA),
                        dma_epwm_config.dmaConfigsCycleU);
    DMA_configBurst(DMA_CH4_BASE, 2, 1, 1); //4 bursts --> One for for each up and down of the center aligned PWM
    DMA_configTransfer(DMA_CH4_BASE, 1, 1, -2); //4 Transfers, CMPAHR  ,   CMPA   ,   CMPBHR  ,   CMPB
    DMA_configMode(DMA_CH4_BASE, DMA_TRIGGER_EPWM1SOCA, DMA_CFG_ONESHOT_DISABLE |
                   DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
                   
        //
    // DMA CH5
    //
    DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(MTR1_PWM_V_BASE + EPWM_O_CMPA),
                        dma_epwm_config.dmaConfigsCycleV);
    DMA_configBurst(DMA_CH5_BASE, 2, 1, 1); //4 bursts --> One for for each up and down of the center aligned PWM
    DMA_configTransfer(DMA_CH5_BASE, 1, 1, -2); //4 Transfers, CMPAHR  ,   CMPA   ,   CMPBHR  ,   CMPB
    DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_EPWM1SOCA, DMA_CFG_ONESHOT_DISABLE |
                   DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT); //Every channel triggers on the 1SOCA or same trigger
                  
        //
    // DMA CH6
    //
    DMA_configAddresses(DMA_CH6_BASE, (uint16_t *)(MTR1_PWM_W_BASE + EPWM_O_CMPA),
                        dma_epwm_config.dmaConfigsCycleW);
    DMA_configBurst(DMA_CH6_BASE, 2, 1, 1); //4 bursts --> One for for each up and down of the center aligned PWM
    DMA_configTransfer(DMA_CH6_BASE, 1, 1, -2); //4 Transfers, CMPAHR  ,   CMPA   ,   CMPBHR  ,   CMPB
    DMA_configMode(DMA_CH6_BASE, DMA_TRIGGER_EPWM1SOCA, DMA_CFG_ONESHOT_DISABLE |
                   DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
                   
    DMA_enableTrigger(DMA_CH6_BASE);

    //Start
    DMA_startChannel(DMA_CH4_BASE);
    DMA_startChannel(DMA_CH5_BASE);
    DMA_startChannel(DMA_CH6_BASE);

Thanks

  • Hi Hans,

    These are the sources for a DMA trigger. If you wanted to generate two DMA transfers within PWM period you should configure another SOC event from the PWM, and use another DMA channel to use this trigger as the source. the bleow snippet can generate SOC_A from the PWM, when TBCTR == CMPC on down event.

    You can generate another trigger to generate a SOC_B on the TBCTR == CMPC up event. Then you will need to configure another DMA channel.

    //Initial ADC trigger --> used for FOC
    EPWM_setADCTriggerSource(obj->pwmHandle[0], EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC); //EPWM_SOC_TBCTR_D_CMPC
    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);