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.

AM2432: AM2432: ADC interrupt suddenly fail to trigger

Part Number: AM2432


Tool/software:

Hello:

When we use adc, there is a problem of occasional interruption loss. Please help us check it:

1. We trigger adc (one-shot mode) in pwm interrupt with pwm priority 7 and adc priority 1. There are timer interrupt and gpio interrupt in the program, and their interrupt priority is 7;

2. ADC interrupts can be triggered normally at startup, but in subsequent runs adc interrupts are lost and cannot be recovered;

3. In our tests, this problem can occur when running for 30 minutes, two hours, eight hours, etc;

4. When the problem occurs:

a. The timer, pwm, gpio and other interruptions can be triggered normally;

b. The freertos can run only idle tasks;

c. ADC_FIFO0WC can be updated, so the adc should still be sampling normally, but the interrupt has not been triggered;

d. Even if HwiP_enableInt() is called to re-enable an adc interrupt, the interrupt cannot be restored.

My program is as follows:

uint16_t adc_original_buff[APP_ADC_NUM_CH];
int32_t adc_buff[APP_ADC_NUM_CH];
float curr_result[3];
static HwiP_Object gAdcHwiObject;
HwiP_Params hwiPrms;
volatile uint32_t adc_start_ns = 0;
volatile uint32_t adc_interval_ns = 0;

void App_adcGetData(void)
{
    uint32_t voltageLvl;
    uint32_t id;
    uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR;
    uint32_t i = 0;
    uint32_t fifoData = 0;
    uint32_t fifoWordCnt;

    if(is_float_zero(gUserParams_float.adc_gain) == MT_TRUE)
    {
        gUserParams_float.adc_gain = 0.15f;
    }

    /* Get FIFO data */
    fifoWordCnt = ADCGetFIFOWordCount(baseAddr, ADC_FIFO_NUM_0);
    for (i = 0U; i < fifoWordCnt; i++)
    {
        fifoData = ADCGetFIFOData(baseAddr, ADC_FIFO_NUM_0);
        id  = ((fifoData & ADC_FIFODATA_ADCCHNLID_MASK) >>
                    ADC_FIFODATA_ADCCHNLID_SHIFT);
        fifoData = ((fifoData & ADC_FIFODATA_ADCDATA_MASK) >>
                    ADC_FIFODATA_ADCDATA_SHIFT);
        adc_original_buff[id] = (uint16_t)fifoData;

        if((id > 2) && (id < 6))
        {
            voltageLvl  = fifoData * (uint32_t) (V_ADC_REF * 1000);
            voltageLvl /= (uint32_t) ADC_GET_RANGE(CONFIG_ADC0_NUM_BITS);
            if(Old_m_state == MC_STATE_CALIBRATION)
            {
                //1650 = 3.3V * 1000 / 2
                adc_buff[id] = voltageLvl - 1650;
            }
            else
            {
                adc_buff[id] = voltageLvl - 1650 - hal_hwParams_u32_t.PhaseCurrOffset[id - 3];
            }
            curr_result[id - 3] = (adc_buff[id] * 1.0f / 1000.0f) / gUserParams_float.adc_gain;
        }
        else
        {
            adc_buff[id] = fifoData;
        }
    }
    adc_interval_ns = clock_cal_interval(adc_start_ns, clock_get_ns());
}

void App_adcISR(void *handle)
{
    uint32_t status;
    uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR;

    /* Get interrupt status and clear */
    status = ADCGetIntrStatus(baseAddr);
    ADCClearIntrStatus(baseAddr, status);

    App_adcGetData();

    /* Set EOI to generate next interrupt if any */
    ADCWriteEOI(baseAddr);
}

void App_adcConfig(uint32_t baseAddr)
{
    adcStepConfig_t adcConfig;
    uint32_t        chCnt, adcStep;

    /* Enable interrupts */
    ADCEnableIntr(baseAddr, ADC_INTR_SRC_FIFO0_THRESHOLD);

    /*
     * Configure all ADC Steps
     */
    /* Initialize ADC configuration params */
    adcConfig.mode             = ADC_OPERATION_MODE_SINGLE_SHOT;
    adcConfig.openDelay        = 0x0U;
    adcConfig.sampleDelay      = 0U;
    adcConfig.rangeCheckEnable = 0U;
    adcConfig.averaging        = ADC_AVERAGING_NONE;
    adcConfig.fifoNum          = ADC_FIFO_NUM_0;

    /* Configure all required steps - Step 1 to N mapped to Channel 1 to N */
    for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++)
    {
        adcConfig.channel = ADC_CHANNEL_1 + chCnt;
        adcStep = ADC_STEP_1 + chCnt;   /* Step -> Channel one to one mapped */
        ADCSetStepParams(baseAddr, adcStep, &adcConfig);
    }

    ADCStepIdTagEnable(baseAddr, TRUE);
    ADCSetCPUFIFOThresholdLevel(baseAddr, ADC_FIFO_NUM_0, APP_ADC_NUM_CH * 2);

    /* Step enable */
    for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++)
    {
        adcStep = ADC_STEP_1 + chCnt;   /* Step -> Channel one to one mapped */
        ADCStepEnable(baseAddr, adcStep, TRUE);
    }
}

static void App_adcInit(uint32_t baseAddr)
{
    /* Clear All interrupt status */
    ADCClearIntrStatus(baseAddr, ADC_INTR_STATUS_ALL);

    /* Register & enable interrupt */
    HwiP_Params_init(&hwiPrms);
    hwiPrms.intNum = CONFIG_ADC0_INTR;
    hwiPrms.callback = &App_adcISR;
    hwiPrms.priority = 1U;
    HwiP_construct(&gAdcHwiObject, &hwiPrms);

    /* Power up AFE */
    ADCPowerUp(baseAddr, TRUE);

    /* Wait for 4us at least */
    ClockP_usleep(5U);

    /* Do the internal calibration */
    ADCInit(baseAddr, FALSE, 0U, 0U);
}

static void App_adcStart(uint32_t baseAddr)
{
    adcSequencerStatus_t status;

    /* Check if FSM is idle */
    ADCGetSequencerStatus(baseAddr, &status);
    while ((ADC_ADCSTAT_FSM_BUSY_IDLE != status.fsmBusy) &&
           ADC_ADCSTAT_STEP_ID_IDLE != status.stepId)
    {
        ADCGetSequencerStatus(baseAddr, &status);
    }
    /* Start ADC conversion */
    ADCStart(baseAddr, TRUE);
}

int32_t hal_adc_init(void)
{
    uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR;

    App_adcInit(baseAddr);
    App_adcConfig(baseAddr);
    /* Set EOI to generate next interrupt if any */
    ADCWriteEOI(baseAddr);
    App_adcStart(baseAddr);

    return MT_OK;
}

void hal_adc_trigger(void)
{
    uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR;
    uint32_t                chCnt, adcStep;

    /* Step enable */
    for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++)
    {
        adcStep = ADC_STEP_1 + chCnt;   /* Step -> Channel one to one mapped */
        ADCStepEnable(baseAddr, adcStep, TRUE);
    }

    adc_start_ns = clock_get_ns();
    App_adcStart(baseAddr);
}

Please help us confirm:

1. Whether there is any problem with adc configuration and use;

2. During adc normal interrupt processing, we will pause and start the timer, whether there will be the problem of interrupt nesting;

3. Whether there are other factors that cause adc interrupt anomalies.

Thanks.