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.

DRV8329AEVM: 参照DRV8329AEVM控制流程设计新开发板

Part Number: DRV8329AEVM
Other Parts Discussed in Thread: DRV8329, CSD19506KTT, UCC27284, , C2000WARE

半桥栅极驱动器用3个UCC27284替换DRV8329+CSD19506KTT控制BLDC,问题如下:

1、在hal.c中配置PWM, 实测EPWM3无波形,其他两相有PWM波

// GPIO227->EPWM3A->M1_UH
GPIO_setPinConfig(GPIO_227_EPWM3_A);
GPIO_setDirectionMode(227, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(227, GPIO_PIN_TYPE_STD);

// GPIO230->EPWM3B->M1_UL
GPIO_setPinConfig(GPIO_230_EPWM3_B);
GPIO_setDirectionMode(230, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(230, GPIO_PIN_TYPE_STD);

// GPIO0->EPWM1A->M1_VH
GPIO_setPinConfig(GPIO_0_EPWM1_A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);

// GPIO1->EPWM1B->M1_VL
GPIO_setPinConfig(GPIO_1_EPWM1_B);
GPIO_setDirectionMode(1, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);


// GPIO2->EPWM2_A->M1_WH
GPIO_setPinConfig(GPIO_2_EPWM2_A);
GPIO_setDirectionMode(2, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);

// GPIO3->EPWM2_B->M1_WL
GPIO_setPinConfig(GPIO_3_EPWM2_B);
GPIO_setDirectionMode(3, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);

2、参照DRV8329AEVM控制流程,换成非SPI接口的UCC27284,软件怎么移植,能否提供参考文档

谢谢

  • 软件基于c2000\C2000Ware_MotorControl_SDK_4_02_01_00\solutions\universal_motorcontrol_lab\f280013x工程

  • 您好,您的问题我们需要升级到英文论坛寻求帮助,如有答复将尽快回复您。

  • 您好,

    抱歉回复晚了。

    1)请问您使用的C2000器件是什么-是 F280013x 吗?

    2)用于 ePWM3与 ePWM1和2的 ePWM 配置代码是否有差异? 如果是基于通用电机控制实验,还请检查是否使用了 ePWM6而不是 ePWM3 -几种不同的 C2000/逆变器器件组合就是该问题。

    3)如果您想了解通用电机控制实验室代码的移植,UMCL 用户指南中有一个部分讨论了如何移植到其他 C2000 MCU 和逆变器板。 

  • 感谢Cherry Zhou支持。 现在三组PWM波形出来。但是PWM波中的死区配置没起作用。PWM波使用的ePWM1,ePWM2,ePWM3,

    代码里也确认对DB有配置,麻烦看看为什么没起作用呢。代码如下:

    void HAL_setupPWMs(HAL_MTR_Handle handle)
    {

    HAL_MTR_Obj *obj = (HAL_MTR_Obj *)handle;
    uint16_t cnt;

    uint16_t pwmPeriodCycles = (uint16_t)(USER_M1_PWM_TBPRD_NUM);
    uint16_t numPWMTicksPerISRTick = USER_M1_NUM_PWM_TICKS_PER_ISR_TICK;

    // disable the ePWM module time base clock sync signal
    // to synchronize all of the PWMs
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    // turns off the outputs of the EPWM peripherals which will put the power
    // switches into a high impedance state.
    EPWM_forceTripZoneEvent(obj->pwmHandle[0], EPWM_TZ_FORCE_EVENT_OST);
    EPWM_forceTripZoneEvent(obj->pwmHandle[1], EPWM_TZ_FORCE_EVENT_OST);
    EPWM_forceTripZoneEvent(obj->pwmHandle[2], EPWM_TZ_FORCE_EVENT_OST);

    for(cnt=0; cnt<3; cnt++)
    {
    // 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_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_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_LOW,
    EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);

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

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

    // 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);

    #endif //!MOTOR1_ISBLDC

    // 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_enableInterrupt(obj->pwmHandle[0]);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);

    // ADC SOC trigger for the 1st dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[1],
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_U_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[1], EPWM_SOC_A);

    // ADC SOC trigger for the 2nd dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[1],
    EPWM_SOC_B,
    EPWM_SOC_TBCTR_U_CMPD);

    EPWM_enableADCTrigger(obj->pwmHandle[1], EPWM_SOC_B);

    // ADC SOC trigger for the 3rd dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[2],
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[2], EPWM_SOC_A);

    // ADC SOC trigger for the 4th dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[2],
    EPWM_SOC_B,
    EPWM_SOC_TBCTR_D_CMPD);

    EPWM_enableADCTrigger(obj->pwmHandle[2], EPWM_SOC_B);
    #else //!(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)
    // setup the Event Trigger Selection Register (ETSEL)
    EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO);

    EPWM_enableInterrupt(obj->pwmHandle[0]);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);
    #endif // !(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)

    // setup the Event Trigger Prescale Register (ETPS)
    if(numPWMTicksPerISRTick > 15)
    {
    numPWMTicksPerISRTick = 15;
    }
    else if(numPWMTicksPerISRTick < 1)
    {
    numPWMTicksPerISRTick = 1;
    }

    EPWM_setInterruptEventCount(obj->pwmHandle[0], numPWMTicksPerISRTick);

    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_B,
    numPWMTicksPerISRTick);

    #if defined(MOTOR1_DCLINKSS)
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[1], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[1], EPWM_SOC_B,
    numPWMTicksPerISRTick);

    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[2], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[2], EPWM_SOC_B,
    numPWMTicksPerISRTick);
    #endif //MOTOR1_DCLINKSS

    // 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);

    // write the PWM data value for ADC trigger
    #if defined(MOTOR1_DCLINKSS)
    EPWM_clearADCTriggerFlag(obj->pwmHandle[1], EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[1], EPWM_SOC_B);

    EPWM_clearADCTriggerFlag(obj->pwmHandle[2], EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[2], EPWM_SOC_B);

    EPWM_setCounterCompareValue(obj->pwmHandle[1],
    EPWM_COUNTER_COMPARE_C, pwmPeriodCycles>>1);
    EPWM_setCounterCompareValue(obj->pwmHandle[1],
    EPWM_COUNTER_COMPARE_D, pwmPeriodCycles>>1);

    EPWM_setCounterCompareValue(obj->pwmHandle[2],
    EPWM_COUNTER_COMPARE_C, pwmPeriodCycles>>1);
    EPWM_setCounterCompareValue(obj->pwmHandle[2],
    EPWM_COUNTER_COMPARE_D, pwmPeriodCycles>>1);

    #endif //MOTOR1_DCLINKSS


    return;

  • 您好,

    但是PWM波中的死区配置没起作用。

    请问您能否具体再说明一下是如何判断其不起作用? 在示波器中看到的哪种行为指示 DB 子模块未正确配置?

    此外,您发送的代码中有4个大括号{和3个右大括号},因此不太可能正确编译-同样由于这个原因,我们无法分辨 for 循环的结尾在哪里。 

  • 感谢Cherry Zhou支持。找到原因了,是DB模块配置的死区太小,示波器上展开波形都不明显。我把死区时间加大就明显了。现在PWM波控制BLDC还有一个问题,查阅各种资料了解到每一组PWM波需要做成互补波形并带死区配置,防止同一组MOS同时导通导致短路,根据TI的Universal Motor Control Project and Lab User’s Guide开发文档三组PWM波的相位是要错开的,但是对3组波形的相位差距怎么配置没有找到,导致我现在的3组PWM波的高变的相位完全相同,MOS管工作异常,拉动输入电源频繁波动。请指点一下驱动三相BLDC的PWM波相位需要配置成什么样子,怎么配置。下面贴出TI开发板PWM设置的完整函数,其中宏定义用的是MOTOR1_DCLINKSS,

    void HAL_setupPWMs(HAL_MTR_Handle handle)
    {
    HAL_MTR_Obj *obj = (HAL_MTR_Obj *)handle;
    uint16_t cnt;

    uint16_t pwmPeriodCycles = (uint16_t)(USER_M1_PWM_TBPRD_NUM);
    uint16_t numPWMTicksPerISRTick = USER_M1_NUM_PWM_TICKS_PER_ISR_TICK;

    // disable the ePWM module time base clock sync signal
    // to synchronize all of the PWMs
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    // turns off the outputs of the EPWM peripherals which will put the power
    // switches into a high impedance state.
    EPWM_forceTripZoneEvent(obj->pwmHandle[0], EPWM_TZ_FORCE_EVENT_OST);
    EPWM_forceTripZoneEvent(obj->pwmHandle[1], EPWM_TZ_FORCE_EVENT_OST);
    EPWM_forceTripZoneEvent(obj->pwmHandle[2], EPWM_TZ_FORCE_EVENT_OST);

    #if defined(BSXL8323RS_REVA) || defined(BSXL8323RH_REVB) || \
    defined(BSXL8353RS_REVA) || defined(BSXL8316RT_REVA) || \
    defined(BSXL3PHGAN_REVA) || defined(HVMTRPFC_REV1P1) || \
    defined(DRV8329AEVM_REVA)

    for(cnt=0; cnt<3; cnt++)
    {
    // 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_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_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);

    #if defined(MOTOR1_ISBLDC)
    // 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_LOW,
    EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);

    // setup the Action-qualifier Continuous Software Force Register (AQCSFRC)
    EPWM_setActionQualifierContSWForceAction(obj->pwmHandle[cnt],
    EPWM_AQ_OUTPUT_B,
    EPWM_AQ_SW_OUTPUT_LOW);

    // setup the Dead-Band Generator Control Register (DBCTL)
    EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_RED, false);
    EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_FED, false);

    #else //!MOTOR1_ISBLDC


    #if defined(MOTOR1_DCLINKSS)
    // 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_LOW,
    EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);

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

    EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
    EPWM_AQ_OUTPUT_A,
    EPWM_AQ_OUTPUT_HIGH,
    EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
    #else // !(MOTOR1_DCLINKSS)
    // 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);

    #endif // !(MOTOR1_DCLINKSS)

    // 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);

    #endif //!MOTOR1_ISBLDC

    // 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);
    }

    // BSXL8323RS_REVA || BSXL8323RH_REVB || BSXL8353RS_REVA || \
    // BSXL8316RT_REVA || BSXL3PHGAN_REVA || HVMTRPFC_REV1P1 || \
    // DRV8329AEVM_REVA
    #else
    #error The PWM is not configured for motor_1 control
    #endif // boards

    #if defined(MOTOR1_ISBLDC)
    // setup the Event Trigger Selection Register (ETSEL)
    EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO);

    EPWM_disableInterrupt(obj->pwmHandle[0]);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_B, EPWM_SOC_TBCTR_U_CMPB);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_B);
    #elif defined(MOTOR1_DCLINKSS)
    // setup the Event Trigger Selection Register (ETSEL)
    EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO);

    EPWM_enableInterrupt(obj->pwmHandle[0]);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);

    // ADC SOC trigger for the 1st dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[1],
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_U_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[1], EPWM_SOC_A);

    // ADC SOC trigger for the 2nd dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[1],
    EPWM_SOC_B,
    EPWM_SOC_TBCTR_U_CMPD);

    EPWM_enableADCTrigger(obj->pwmHandle[1], EPWM_SOC_B);

    // ADC SOC trigger for the 3rd dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[2],
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[2], EPWM_SOC_A);

    // ADC SOC trigger for the 4th dc-link current sampling
    EPWM_setADCTriggerSource(obj->pwmHandle[2],
    EPWM_SOC_B,
    EPWM_SOC_TBCTR_D_CMPD);

    EPWM_enableADCTrigger(obj->pwmHandle[2], EPWM_SOC_B);
    #else //!(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)
    // setup the Event Trigger Selection Register (ETSEL)
    EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO);

    EPWM_enableInterrupt(obj->pwmHandle[0]);

    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC);

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);
    #endif // !(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)

    // setup the Event Trigger Prescale Register (ETPS)
    if(numPWMTicksPerISRTick > 15)
    {
    numPWMTicksPerISRTick = 15;
    }
    else if(numPWMTicksPerISRTick < 1)
    {
    numPWMTicksPerISRTick = 1;
    }

    EPWM_setInterruptEventCount(obj->pwmHandle[0], numPWMTicksPerISRTick);

    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[0], EPWM_SOC_B,
    numPWMTicksPerISRTick);

    #if defined(MOTOR1_DCLINKSS)
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[1], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[1], EPWM_SOC_B,
    numPWMTicksPerISRTick);

    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[2], EPWM_SOC_A,
    numPWMTicksPerISRTick);
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[2], EPWM_SOC_B,
    numPWMTicksPerISRTick);
    #endif //MOTOR1_DCLINKSS

    // 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);

    // write the PWM data value for ADC trigger
    #if defined(MOTOR1_DCLINKSS)
    EPWM_clearADCTriggerFlag(obj->pwmHandle[1], EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[1], EPWM_SOC_B);

    EPWM_clearADCTriggerFlag(obj->pwmHandle[2], EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(obj->pwmHandle[2], EPWM_SOC_B);

    EPWM_setCounterCompareValue(obj->pwmHandle[1],
    EPWM_COUNTER_COMPARE_C, pwmPeriodCycles>>1);
    EPWM_setCounterCompareValue(obj->pwmHandle[1],
    EPWM_COUNTER_COMPARE_D, pwmPeriodCycles>>1);

    EPWM_setCounterCompareValue(obj->pwmHandle[2],
    EPWM_COUNTER_COMPARE_C, pwmPeriodCycles>>1);
    EPWM_setCounterCompareValue(obj->pwmHandle[2],
    EPWM_COUNTER_COMPARE_D, pwmPeriodCycles>>1);

    #endif //MOTOR1_DCLINKSS
    return;

    }

  • 好的,另外的问题我们跟进给工程师看下,应该会在下周工作日给到您答复。

  • 您好,

    • 要查找单个 ePWM 高侧和低侧之间的死区(在 ePWM 时钟节拍中),请在 hal.h 文件中搜索 MTR1_PWM_DBRED_CNT 和 MTR1_PWM_DBFED_CNT。 默认值通常是没有问题的,但如果更改了这些值,请确保它们彼此相等。 
    • 对于三相输出,容易混淆的地方是,Universal Lab中的三组 PWM 波形及类似波形在该过程中的任何点都不会手动偏移。 相反的是,因为电机的三相由于电机的性质而相互偏移,来自 ADC 的测量值将会反映这一点。 对于三个不同的 ADC 值,SVGEN_run() 空间矢量调制例程和 HAL_writePWMData() PWM CMPx 计算函数将始终会导致三个 ePWM 之间的 CMPx 值存在明显差异。 

    如果计算出的三个电流相位彼此同相,请检查下 ADC 采样硬件和软件或用于单分流器重建例程的参数。 这里有些地方可能会有问题。 您能否分享下从示波器观察到的波形? 

  • 感谢Cherry Zhou回复。我现在按照TI开发文档,设置系统编译级别是DMC_BUILDLEVEL=1,这个阶段只是检测MCU PWM波形输出和ADC采样,不涉及采样后波形计算。我想确认这个阶段3组PWM正常波形是什么样子。我现在的PWM波确认了带死区。

  • 您好,

    非常开心看到DB已被确认。

    在build level1中,根据 Universal Motor Control Lab user's guide PWM 波形不会偏移:

  • 感谢Cherry Zhou回复。 从你贴的开发文档的图看出,3组PWM的波形相位相同,每一组波形互补并且带死区。仔细对比我的波形图可以确认PWM波设置正确了。问题正如你上面的分析,应该出现在软件ADC的配置或者是硬件问题。先从ADC软件角度找原因。关于ADC配置问题有以下疑问,请解答:

    1、ADC_BASE问题,如下,如果复用脚选A4是否就应该配置ADCA_BASE?如果服用脚选C14是否就应该配置ADCC_BASE?两种随意配置吗?

    #define MTR1_VU_ADC_BASE      ADCA_BASE // ADCA-A6*
    #define MTR1_VV_ADC_BASE      ADCA_BASE // ADCC-A3*/C5
    #define MTR1_VW_ADC_BASE     ADCA_BASE // ADCA-A2*/C9
    #define MTR1_VDC_ADC_BASE   ADCA_BASE // ADCA-A15*/C7
    #define MTR1_POT_ADC_BASE   ADCC_BASE // ADCC-C6*

    2、ADC_NUMBER问题,如下,看不懂每一路SOC NUMBER是怎么配置的。为什么ADCA-A6* 配成ADC_SOC_NUMBER1 ,ADCA-A15*/C7却配置成                  ADC_SOC_NUMBER4? 

    #define MTR1_VU_ADC_SOC_NUM      ADC_SOC_NUMBER1 // ADCA-A6* -SOC1
    #define MTR1_VV_ADC_SOC_NUM      ADC_SOC_NUMBER2 // ADCC-A3*/C5 -SOC2
    #define MTR1_VW_ADC_SOC_NUM     ADC_SOC_NUMBER3 // ADCA-A2*/C9 -SOC3
    #define MTR1_VDC_ADC_SOC_NUM   ADC_SOC_NUMBER4 // ADCA-A15*/C7 -SOC4
    #define MTR1_POT_ADC_SOC_NUM   ADC_SOC_NUMBER4 // ADCC-C6* -SOC4

    3、中断配置问题,如下,MTR1_ADC_INT_BASE为什么配置成ADCA_BASE ,和ADC采样的引脚有关吗?MTR1_ADC_INT_NUM为什么配置成NUMBER1,        和ADC采样的引脚有关吗?MTR1_ADC_INT_SOC 为什么配置成ADC_SOC_NUMBER4 ,和ADC采样的引脚有关吗?

    // interrupt
    #define MTR1_PWM_INT_BASE     MTR1_PWM_U_BASE // EPWM1

    #define MTR1_ADC_INT_BASE      ADCA_BASE // ADCA-A15 -SOC4
    #define MTR1_ADC_INT_NUM       ADC_INT_NUMBER1 // ADCA_INT1-SOC4
    #define MTR1_ADC_INT_SOC       ADC_SOC_NUMBER4 // ADCA_INT1-SOC4

    4、IDC问题,如下,代码里还有IDC的配置,请问IDC是什么功能,是否必须配置?

    #define MTR1_IDC1_TRIGGER_SOC   ADC_TRIGGER_EPWM2_SOCA // EPWM2_SOCA
    #define MTR1_IDC2_TRIGGER_SOC   ADC_TRIGGER_EPWM2_SOCB // EPWM2_SOCB
    #define MTR1_IDC3_TRIGGER_SOC   ADC_TRIGGER_EPWM6_SOCA // EPWM6_SOCA
    #define MTR1_IDC4_TRIGGER_SOC   ADC_TRIGGER_EPWM6_SOCB // EPWM6_SOCB
    #endif // !FAST_DCLINKSS

    #define MTR1_IDC1_ADC_BASE    ADCC_BASE // ADCC-A11/C0*
    #define MTR1_IDC2_ADC_BASE    ADCC_BASE // ADCC-A11/C0*
    #define MTR1_IDC3_ADC_BASE    ADCC_BASE // ADCC-A11/C0*
    #define MTR1_IDC4_ADC_BASE    ADCC_BASE // ADCC-A11/C0*

    #define MTR1_IDC1_ADCRES_BASE   ADCCRESULT_BASE // ADCC-A11/C0*
    #define MTR1_IDC2_ADCRES_BASE   ADCCRESULT_BASE // ADCC-A11/C0*
    #define MTR1_IDC3_ADCRES_BASE   ADCCRESULT_BASE // ADCC-A11/C0*
    #define MTR1_IDC4_ADCRES_BASE   ADCCRESULT_BASE // ADCC-A11/C0*

    以上疑问是我根据自己的板子做了ADC配置之后,在build level1中debug,    motorVars_M1.ISRCount不刷新,而用开发包原来的配置是可以刷新的。

  • 已转达给工程师。

  • 您好,请参阅以下答复:

    您的问题大多数与 ADC 外设基本原理有关。 建议您通读 C2000 Academy chapter 4. Analog Subsystems, section 1, Analog to Digital Converter (ADC)-并非每个问题都有详细解答,但其提供了一套很好的基准知识,可解决 ADC 问题。 此外, F280013x TRM ADC chapter 一章是非常有用的资源。 

    1、ADC_BASE问题,如下,如果复用脚选A4是否就应该配置ADCA_BASE?如果服用脚选C14是否就应该配置ADCC_BASE?两种随意配置吗?

    本质上,F280013x MCU 有2个不同的 ADC 外设- ADCA 和 ADCC。 每个外设都可以访问不同的引脚集。 要执行模数转换,您使用的 ADC 外设必须进行正确配置。

    这意味着如果您想转换引脚 A6上的模拟信号,您需要使用 ADCA。 如果您要转换 C5上的模拟信号,则需要使用 ADCC。 两个 ADC 外设确实共用几个引脚(例如引脚 A7/C3),从而允许它们转换相同的输入信号,但是它们是不同的外设。

    2、ADC_NUMBER问题,如下,看不懂每一路SOC NUMBER是怎么配置的。为什么ADCA-A6* 配成ADC_SOC_NUMBER1 ,ADCA-A15*/C7却配置成                  ADC_SOC_NUMBER4? 

    C2000 Academy ADC 部分可以很好地回答您的问题。 基本上每个 ADC 可配置为进行多达16次转换。 为了便于使用,ADC 文档主要通过 SOC 启动转换来指代每次转换。 要转换引脚 A6,您需要在 ADCA 上设置1个 SOC,但您可以选择任一种。

    例如,假设我要转换引脚 A6,并且我已经任意决定使用 ADCA SOC12。 现在我需要在 ADCA.ADCSOC12CTL寄存器中设置正确的配置值。 ADCSOC12CTL[CHSEL] = 0x6,因为它是 ADCA 输入6,ADCSOC12CTL[TRIGSEL]允许我可以决定该转换何时发生。

    对于Universal Motor Control Lab,我们已在 hal. 文件中为您设置了所有适当的 driverlib 函数。 您所需要做的就是确保正确设置预定义即可(如 MTR1_VU_ADC_SOC_NUM)。

    要将 MTR1 VU 设置为输入引脚 A6,通道 SOC12,您需要设置:

    #define MTR1_VU_ADC_BASE    ADCA_BASE // ADCA-A6* // Pin *A*6 requires ADC*A*
    #define MTR1_VU_ADC_SOC_NUM ADC_SOC_NUMBER12 // ADCA-A6* -SOC12 // In our example, we're arbitrarily setting SOC12
    #define MTR1_ADC_TRIGGER_SOC    ADC_TRIGGER_EPWM1_SOCA // EPWM1_SOCA // This configures ePWM1 SOCA as the trigger for all of motor 1's SOCs.

    3、中断配置问题,如下,MTR1_ADC_INT_BASE为什么配置成ADCA_BASE ,和ADC采样的引脚有关吗?MTR1_ADC_INT_NUM为什么配置成NUMBER1,        和ADC采样的引脚有关吗?MTR1_ADC_INT_SOC 为什么配置成ADC_SOC_NUMBER4 ,和ADC采样的引脚有关吗?

    a. 对于 ADC,中断通常在任意选择的 SOC 完成转换时触发。 我们想要在电机1的一个 SOC 结束时触发 motor1CtrlISR ()。

    --MTR1_ADC_INT_BASE 必须与我们要用于触发的 SOC 相同的 ADC (ADCA 或 ADCC)。 如上所述,SOC 与特定 ADC 相关联,这意味着我们要使用的引脚通常决定我们必须使用什么基极。 在这种情况下,我们要使用由 ADCA SOC4转换的引脚 A15,因此我们选择 MTR1_ADC_INT_base 作为 ADCA_BASE。

    b. 每个 ADC 可以生成多达4个中断(ADCINT1至 ADCINT4)。 我们只需要1个,因此只选择第一个开放时隙 ADCINT1。 这意味着我们选择 MTR1_ADC_INT_NUM 为 ADC_INT_NUMBER1。 

    c. 我们基本上可以选择任意 SOC 来触发中断,只要确信在开始中断之前所有必要的转换都已经结束即可。 一般来说,这意味着你要将中断设置为最低优先级的 SOC -尽管需要仔细检查代码以确保正确无误,但我们可以确定这是通用实验室的功能,或者至少是非常相似的功能。 由于我们希望触发 SOC4,因此将 MTR1_ADC_INT_SOC 设置为 ADC_SOC_Number4。 

    4、IDC问题,如下,代码里还有IDC的配置,请问IDC是什么功能,是否必须配置?

    MTR1_IDCx 是通用电机控制实验室使用的惯例,用来指用于转换单分流器硬件的通道。 您在代码中会注意到每个 IDC SOC 都指向同一引脚,但由不同的事物触发。 这只是意味着我们要在几个不同的时间点测量同一个引脚。 要了解其配置方式,请在 hal.c 文件中搜索 MOTOR1_DCLINKSS。 在这些#if defined(MOTOR1_DCLINKSS)部分中,您可以找到与单分流器硬件相关的特定配置。 

    如果您还有其他有关 ADC 的问题,尤其是如果问题与 ADC 相关的术语相关,我们强烈建议您通读 TRM,它可以帮助您解决很多问题。