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:配置 ADC 触发频率

Guru**** 2410620 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1115177/tms320f280025c-configure-adc-trigger-frequency

器件型号:TMS320F280025C

您好!

我对 ADC 有疑问、在我的项目中、我使用3个 ePWM 进行半导体控制、并将 ADC 与一个 ePWM 通道同步以解决状态机问题。 我已经定义了几个对应于 ADC 每个输入的 SOC、它们是链式的、但我想在切断另一个 ePWM 的一段时间内获得几个样本。 我尝试以不同于其他 ePWM 的方式配置 TBPRD 寄存器、但它不起作用。 在本例中、我不会输入中断。 知道我已经在转换结束时配置了中断。

目前、采样工作正常、但频率未达到所需频率、我希望在开关周期中具有更多的点


如果我在用于 ADC 同步的 ePWM 通道上设置更高的频率、为什么它不起作用?

谢谢

/**ePWM initialization with phase shift*/
void epwm_init(uint32_t base, uint16_t phi)
{
    /**Parameters*/
    EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP);
    EPWM_setTimeBasePeriod(base, EPWM_TBPRD);
    EPWM_setTimeBaseCounter(base, 0U);
    EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_4, EPWM_HSCLOCK_DIVIDER_4);
    /**Set up shadowing*/
    EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);

    /**Set actions
    For boost assembly*/
    EPWM_setActionQualifierAction(base, SPWM_TOP, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(base, SPWM_TOP, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    /**For buck assembly*/
    EPWM_setActionQualifierAction(base, SPWM_BOT, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    EPWM_setActionQualifierAction(base, SPWM_BOT, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    EPWM_setActionQualifierContSWForceAction(SPWM_U, SPWM_BOT, EPWM_AQ_SW_OUTPUT_LOW);
    EPWM_setActionQualifierContSWForceAction(SPWM_V, SPWM_BOT, EPWM_AQ_SW_OUTPUT_LOW);
    EPWM_setActionQualifierContSWForceAction(SPWM_W, SPWM_BOT, EPWM_AQ_SW_OUTPUT_LOW);
    EPWM_setActionQualifierContSWForceAction(SPWM_U, SPWM_TOP, EPWM_AQ_SW_OUTPUT_LOW);
    EPWM_setActionQualifierContSWForceAction(SPWM_V, SPWM_TOP, EPWM_AQ_SW_OUTPUT_LOW);
    EPWM_setActionQualifierContSWForceAction(SPWM_W, SPWM_TOP, EPWM_AQ_SW_OUTPUT_LOW);

    if(base == SPWM_FOR_ADC)
    {
->      EPWM_setTimeBasePeriod(base, EPWM_TBPRD);
        /**Initialize PWM to add samples ADC in loop close regulation*/
        EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, CMPA_EPWM_ADC);
    }

    /**Configure ePMWs*/
    // Todo comments to explain
    if(phi == 0)
    {
        EPWM_disablePhaseShiftLoad(base);
        EPWM_setPhaseShift(base, phi);
        EPWM_enableSyncOutPulseSource(base, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO);
    }
    else
    {
        uint16_t tbphs = epwm_get_tbphs_from_phi(base, phi);
        EPWM_setSyncInPulseSource(base, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
        EPWM_enablePhaseShiftLoad(base);
        EPWM_selectPeriodLoadEvent(base, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_setPhaseShift(base, tbphs);
        EPWM_setTimeBaseCounter(base, tbphs);
    }
}

ADC configuration

/**
 * Configure ADC set pulse at End Of Conversion to enter on interrupt when ADC register is full
 */
void adc_config(uint32_t adc_base)
{
    /**
     * Enable ADC with external reference A4 (3V)
     */
    ADC_setVREF(adc_base, ADC_REFERENCE_EXTERNAL, ADC_REFERENCE_3_3V);

    ADC_setPrescaler(adc_base, ADC_CLK_DIV_1_0);

    /**
     * Set pulse ADCINTx at the end of conversion
     */
    ADC_setInterruptPulseMode(adc_base, ADC_PULSE_END_OF_CONV);

    if(adc_base == ADCA_BASE)
    {
        /**
         * Configure the SOC to occur on the first up-count event
         */
        EPWM_setADCTriggerSource(SPWM_FOR_ADC, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
        /**
         * Sets the SOC event count that determines the number of events that have to occur before an SOC is issued.
         */
        EPWM_setADCTriggerEventPrescale(SPWM_FOR_ADC, EPWM_SOC_A, PRESCALE_COUNT_ADC_SOC);

        EPWM_enableADCTrigger(SPWM_FOR_ADC, EPWM_SOC_A);
    }

    ADC_enableConverter(adc_base);

    /**
     * Delay to allow ADC time to power up
     */
    DEVICE_DELAY_US(ADC_DELAY_POWERUP_US);
}

/**
 * Corresponding module ADCx -> SOC -> pin.
 * Enchainement des SOC une fois la conversion terminée sur un SOC. SOC0 will start at 1 / PWM_FREQ and an another SOC0 at 1 / PWM_FREQ after.
 * See notes for ADC_ACQPS_WINDOW details.
 * Two conversions per SOC : the first on ADCA and the other on ADCC.
 */
void adc_init_soc(void)
{
    /**MU_TRAC_BATT_FLT with pin ADCINA3*/
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN3, ADC_ACQPS_WINDOW);

    /**MU_FUEL_CELL_FLT with pin ADCINA2*/
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN2, ADC_ACQPS_WINDOW);

    /**MI_TRAC_BATT_FLT with pin ADCINA14*/
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN14, ADC_ACQPS_WINDOW);

    /**MU_FUEL_CELL_PCH_FLT with pin ADCINA0*/
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN0, ADC_ACQPS_WINDOW);

    /**MU_TRAC_BATT_PCH_FLT with pin ADCINC6*/
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN6, ADC_ACQPS_WINDOW);

    /**MT_COLD_PLATE_FLT with pin ADCINC0*/
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN0, ADC_ACQPS_WINDOW);

    /**MI_L_U_FLT with pin ADCINC14*/
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN14, ADC_ACQPS_WINDOW);

    /**MI_L_V_FLT with pin ADCINC8*/
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN8, ADC_ACQPS_WINDOW);

    /**MI_L_W_FLT with pin ADCINC10*/
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER4, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN10, ADC_ACQPS_WINDOW);

    /**Corresponding EOC to ADCINTX pulse to enter on interrupt for read ADCRESULTx registers. Refer to ADCINTSEL1N2 and ADCRESULTx registers.*/
    ADC_setInterruptSource(ADCC_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER4);

    ADC_enableInterrupt(ADCC_BASE, ADC_INT_NUMBER1);

    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
}

/**Enter on interrupt when SOC4 on ADCC will end. Only average samples in interrupt and not conversion to have more time available.
   See requirement REQ_SYST0006*/
__interrupt void isr_adc(void)
{
    //
    // Save IER register on stack
    //
    //volatile uint16_t tempPIEIER = HWREGH(PIECTRL_BASE + PIE_O_IER1);

    //
    // Set the global and group priority to allow CPU interrupts
    // with higher priority
    //
    /*IER |= M_INT1;
    IER &= MINT1;
    HWREGH(PIECTRL_BASE + PIE_O_IER1) &= MG1_3;

    //
    // Enable Interrupts
    //
    Interrupt_clearACKGroup(0xFFFFU);
    __asm("  NOP");
    EINT;*/

    /**Read samples results in ADCARESULT registers and stock them.*/
    MU_TRAC_BATT_PCH_FLT_SAMPLE = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
    MT_COLD_PLATE_FLT_SAMPLE = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER1);
    MI_L_U_FLT_SAMPLE = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER2);
    MI_L_V_FLT_SAMPLE = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER3);
    MI_L_W_FLT_SAMPLE = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER4);
    MU_TRAC_BATT_FLT_SAMPLE = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
    MU_FUEL_CELL_FLT_SAMPLE = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
    MI_TRAC_BATT_FLT_SAMPLE = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER2);
    MU_FUEL_CELL_PCH_FLT_SAMPLE = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER3);

    average();

    /**Clear the interrupt flag*/
    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);

    /**Check if overflow has occurred*/
    if(ADC_getInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER1) == true)
    {
        ADC_clearInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
    }

    /**Acknowledge the interrupt, see PIE Interrupt Vectors table*/
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);

    //
    // Disable interrupts and restore registers saved:
    //
    /*DINT;
    HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER;*/
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Damien:

    我在 ADC_CONFIG 函数上注意到、ADC 预分频器设置为 ADC_CLK_DIV_1_0。  F280025C 最大 SYSCLK 为100MHz。  您的代码中没有看到时钟设置、但我假设 F280025C 配置为在100MHz 的 SYSCLK 上运行。  当 ADC 预分频器设置为 DIV1时、如果 SYSCLK 设置为100MHz、ADC 的时钟频率为100MHz、这将超出规格。  ADC 最大时钟为50MHz。  请先确认 SYSCLK 和所需的 ADC 时钟设置是否正确、然后我们可以稍后使用 ePWM 检查采样频率。

    此致、

    Joseph

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Joseph、

    是的、SYSCLK 时钟设置为100MHz、我希望 ADC 首先以其最大频率运行、以便稍后查看是否需要降低。 我没有注意 ADC 的最大频率50MHz。 我设置 ADC_setPrescaler (ADC_base、ADC_CLK_DIV_2_0)。

    谢谢

    Damien

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Damien:

    我无法轻松地从您的代码中得知 ePWM SOC 触发的发生速度有多快。  另请注意、SOC4上只有 ADCC 被配置为转换结束时的中断、但是在 ISR 中、ADCA 和 ADCC 的结果都被读取。  这不奏效。  您需要单独配置 ADCA 和 ADCC 模块(用于预分频器和 SOC 设置)、并且每个 ADC ISR 应按模块进行。  在这种情况下、只有 ADCC 转换会在 SOC4发送转换结束信号时触发 ISR。  ISR 内部对 ADCA 的读取可能无效、因为它不是由任何中断或转换结束触发的。

    此致、

    Joseph

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Joseph、

    好的、感谢反馈、我会解决这个问题、但是我能否配置比其他 ePWM 更高的频率 ePWM (用于 MOS 控制)来使我的 ADC 与其同步、因此我在一个开关周期内会有更多的 SOC 重复? 这是一种不做的方法?

    明天我将在工作中尝试所有这些。

    谢谢

    Damien

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Damien:

    是的、您应该能够以更高的 ePWM 速率触发。  您需要注意的是 ADC 转换的速度、以便与 ePWM SOC 的转换频率保持一致。  查看数据表中的 ADC 时序图作为参考 (图7-35)。 TSH 将是代码中的 ADC_ACQPS_WINDOW 变量。 tLAT 是转换发生所需的时间、结果在 ADCRESULT 寄存器中有效、因此本质上总转换时间为 TSH + tLAT。  ePWM SOC 应略长于此转换时间。

    此致、

    Joseph