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: Configure ADC trigger frequency

Part Number: TMS320F280025C

Hi,

I have a question regarding the ADC, in my project I use 3 ePWMs for semi conductor control, and I synchronize the ADC to one ePWM channel for state machine issues. So I have defined several SOCs that correspond to each input of the ADC, these are chained but I would like to get several samples on a period of cutting of the other ePWM. I tried to configure the TBPRD register differently from the other ePWMs but it doesn't work. In this case I don't enter an interrupt. Knowing that I have configured the interrupt on the end of conversion.

Currently the sampling works but not at the desired frequency I wish to have more points on a switch period


Why it does not work if I put a higher frequency on the ePWM channel used for the ADC synchronization?

Thanks

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

  • Hi Damien,

    I noticed on adc_config function that the ADC prescaler is set to ADC_CLK_DIV_1_0.  F280025C max SYSCLK is 100MHz.  Have not seen the clock setup in your code but i am assuming that F280025C is configured to run at SYSCLK of 100MHz.  With an ADC prescaler set to DIV1, and if SYSCLK is set at 100MHz, ADC is clocked at 100MHz, which will be out of spec.  ADC max clock is 50MHz.  Please confirm SYSCLK and desired ADC clock settings to be correct first then we can check on sampling frequency with EPWM later.

    Regards,

    Joseph

  • Hi Joseph,

    Yes the sysclk clock is set to 100MHz, I want the ADC to run at its maximum frequency at first to see later if the need to decrease is felt. I had not paid attention to the maximum frequency of 50MHz for the ADC. I set ADC_setPrescaler(adc_base, ADC_CLK_DIV_2_0).

    Thanks

    Damien

  • Hi Damien,

    I cannot easily tell from your code how fast the EPWM SOC triggers are occurring.  Also noticed that only ADCC has been configured for interrupt for the end of conversion on SOC4, however in the ISR the results for both ADCA and ADCC are being read.  This will not work.  You need to configure ADCA and ADCC modules separately (for prescaler and SOC set up) and each ADC ISR should be per module.  What is happening with this case is that only ADCC conversions will trigger the ISR when SOC4 sends the end of conversion signal.  The reads for ADCA inside the ISR will probably be invalid since it is not triggered by any interrupt or end of conversion.

    Regards,

    Joseph

  • Hi joseph,

    OK, thanks for the feedback, I'll fix that, but can I configure a higher frequency ePWM than my other ePWMs (for MOS control) to synchronize my ADC to it, so I'll have more SOCs repeating over a switching period ? It's a way of doing no ?

    I'm trying all this tomorrow at work.

    Thanks

    Damien

  • Hi Damien,

    Yes, you should be able to trigger at a higher EPWM rate.  What you need to take note of is how fast an ADC conversion would take place such that this would be consistent with conversion frequency for EPWM SOC.  Take a look at the ADC timing diagrams in the datasheet as reference (Figure 7-35).  tSH will be ADC_ACQPS_WINDOW variable in your code.  tLAT would be the time it takes for the conversion to take place and results to be valid in the ADCRESULT register so essentially total conversion time is tSH + tLAT.  The EPWM SOC should be slightly longer than this conversion time.

    Regards,

    Joseph