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.

TMS320F28379D: Different Behavior Between Identically Configured ePWM Modules on Core 2

Part Number: TMS320F28379D

I have a project that makes use of all 12 PWM modules by CPU2. All are configured nearly identically, however only PWM<7-12> appear to work when probing the output, the 12 output pins corresponding to PWM<1-6> are either high or low with no switching.

Below shown is the configuration for EPWM6, but nearly the same configuration is used for all.

void init()
{
    // PWM H
    GPIO_setPadConfig(10, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_10_EPWM6A);
    GPIO_setMasterCore(10, GPIO_CORE_CPU2);
    // PWM L
    GPIO_setPadConfig(11, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_11_EPWM6B);
    GPIO_setMasterCore(11, GPIO_CORE_CPU2);
    
    SysCtl_selectCPUForPeripheral(SYSCTL_CPUSEL0_EPWM, 6, SYSCTL_CPUSEL_CPU2);
    
    base = EPWM6_BASE;
    
    EPWM_setTimeBasePeriod(base, 1000);
    EPWM_setPhaseShift(base, 0U);
    EPWM_setTimeBaseCounter(base, 0U);
    EPWM_disableInterrupt(base);
    
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, 0U);
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_B, 0U);
    
    EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN);
    EPWM_disablePhaseShiftLoad(base);
    EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
    
    EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
    EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
    
    EPWM_setInterruptSource(base, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(base);
    EPWM_setInterruptEventCount(base, 10);
    Interrupt_enable(INT_EPWM6);

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
}

__interrupt void pwm_isr(void)
{
    // new_val as placeholder for this demo
    EPWM_setCounterCompareValue(EPWM6_BASE, EPWM_COUNTER_COMPARE_A, new_val);
    EPWM_setCounterCompareValue(EPWM6_BASE, EPWM_COUNTER_COMPARE_B, new_val);

    EPWM_clearEventTriggerInterruptFlag(EPWM6_BASE);

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

Note: the SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC) call is included above for completeness. In reality, it isn't called until all PWMs are setup.

I initially thought something could be going wrong with the interrupt configuration and handling, however if I disable the interrupts for PWM<1-6> and update their compare registers from the ISRs of PWM<7-12> it still doesn't work.

  • Owen, All ePWM assigned to CPU2?

    All configuration done on CPU2 for the EPWM regs?

    What is the difference between EPWM1-6 configs and EPWM7-12?

  • Nima, all ePWMs are assigned to CPU2. In pulling all the config information together into one function (shown above) the fact that CPU1 is running lines 4-12 was lost. In my actual program, CPU1 delegates all the ePWM modules to CPU2 and sets the GPIO configurations. 

    The ePWM module configuration all happens on CPU2. There should be no difference between any of the ePWM configs - they all use the exact same code as shown above (in my project, it's parameterized so I can just pass in a different base address). 

    Here is the actual init_pwm() function from my project:

    void init_epwm(uint32_t base, bool ie)
    {
    	// Set-up TBCLK
    	EPWM_setTimeBasePeriod(base, EPWM_TIMER_TBPRD);
    	EPWM_setPhaseShift(base, 0U);
    	EPWM_setTimeBaseCounter(base, 0U);
    	EPWM_disableInterrupt(base);
    
    	// Set Compare values
    	EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, 0U);
    	EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_B, 0U);
    
    	// Set up counter mode
    	EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN);//EPWM_COUNTER_MODE_UP);
    	EPWM_disablePhaseShiftLoad(base);
    	EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
    
    	// Set up shadowing
    	EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
    	EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
    	// Set actions - PWM A/B are configured to be inverse from one another, based on the CMPA register
    	EPWM_setActionQualifierAction(base,
    											EPWM_AQ_OUTPUT_A,
    											EPWM_AQ_OUTPUT_LOW,
    											EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    	EPWM_setActionQualifierAction(base,
    											EPWM_AQ_OUTPUT_A,
    											EPWM_AQ_OUTPUT_HIGH,
    											EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    
    
    	EPWM_setActionQualifierAction(base,
    											EPWM_AQ_OUTPUT_B,
    											EPWM_AQ_OUTPUT_HIGH,
    											EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    	EPWM_setActionQualifierAction(base,
    											EPWM_AQ_OUTPUT_B,
    											EPWM_AQ_OUTPUT_LOW,
    											EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
    
    	// Select INT on Time base counter zero event,
    	// Enable INT, generate INT on Nth event
    	if(ie)
    	{
    		EPWM_setInterruptSource(base, EPWM_INT_TBCTR_ZERO);
    		EPWM_enableInterrupt(base);
    		EPWM_setInterruptEventCount(base, EPWM_ISR_EVENT_COUNT);
    	}
    }

    Here is a code snippet showing how the PWMs are delegated to their respective motor groups:

    	switch (m_num)
    	{
    	case M1:
    		pwm1_base = EPWM12_BASE;
    		pwm2_base = EPWM11_BASE;
    		pwm3_base = EPWM8_BASE;
    		break;
    	case M2:
    		pwm1_base = EPWM7_BASE;
    		pwm2_base = EPWM10_BASE;
    		pwm3_base = EPWM9_BASE;
    		break;
    	case M3:
    		pwm1_base = EPWM6_BASE;
    		pwm2_base = EPWM5_BASE;
    		pwm3_base = EPWM2_BASE;
    		break;
    	case M4:
    		pwm1_base = EPWM4_BASE;
    		pwm2_base = EPWM3_BASE;
    		pwm3_base = EPWM1_BASE;
    		break;
    
    	}

    Here is a code snippet showing when the init_epwm() function is called (for M1, M2, M3, and M4 separately).

    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
    	init_epwm(pwm1_base, true); // ie only for first PWM in group
    	init_epwm(pwm2_base, false);
    	init_epwm(pwm3_base, false);
    
    
    	switch (m_num)
    	{
    		case M1:
    				Interrupt_register(INT_EPWM12, &m1_pwm_isr)
    				Interrupt_enable(INT_EPWM12);
    				break;
    		case M2:
    				Interrupt_register(INT_EPWM7, &m2_pwm_isr);
    				Interrupt_enable(INT_EPWM7);
    				break;
    		case M3:
    				Interrupt_register(INT_EPWM6, &m3_pwm_isr);
    				Interrupt_enable(INT_EPWM6);
    				break;
    		case M4:
    				Interrupt_register(INT_EPWM4, &m4_pwm_isr);
    				Interrupt_enable(INT_EPWM4);
    				break;
    	}

    Here are the ISRs for each of the 4 PWM interrupts:

    __interrupt void m1_pwm_isr(void)
    {
        m1_tick();
    	// Clear INT flag for this timer
    	EPWM_clearEventTriggerInterruptFlag(EPWM12_BASE);
    
    	// Acknowledge interrupt group
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    __interrupt void m2_pwm_isr(void)
    {
        m2_tick();
    	// Clear INT flag for this timer
    	EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE);
    
    	// Acknowledge interrupt group
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    __interrupt void m3_pwm_isr(void)
    {
        m3_tick();
    	// Clear INT flag for this timer
    	EPWM_clearEventTriggerInterruptFlag(EPWM6_BASE);
    
    	// Acknowledge interrupt group
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }
    
    __interrupt void m4_pwm_isr(void)
    {
        m4_tick();
    	// Clear INT flag for this timer
    	EPWM_clearEventTriggerInterruptFlag(EPWM4_BASE);
    
    	// Acknowledge interrupt group
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }

    It should be noted that there are no issues with the ePWM modules associated with M1 and M2 - just M3 and M4 (PWM<1-6>) don't seem to work (the output doesn't switch, but is driven). 

  • Owen,

    I just checked and they all are accessible on CPU2. There must be a small logic error in your code that causes this. Can you create a small project with only the NON working EPWM (only one EPWM) and test it out?

    Nima

  • Nima, all of the PWM modules work in a separate test project. My issue was not with PWM configuration, but with my PWM ISR taking too long which was not updating the PWMs associated with M3 and M4 (coincidentally PWM<1-6>). The issue has been resolved.

    Thanks again!

  • Owen,

    Thank you for writing back! I'm glad everything is resolved. I have closed the thread.

    Nima