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 采样时间

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1425665/am2432-am2432-adc-sampling-time

器件型号:AM2432

工具与软件:

您好:

我已按计时器验证 ADC 采集时间、结果有点奇怪。

在单次触发模式下、将捕获8个通道、触发器 FIFO 阈值设置为15 (8*2-1)、从 ADC 启动到进入中断的时间约为9us。

但同样、采集1个通道后、触发 FIFO 阈值设置为1 (1*2-1)、从启动 ADC 到进入中断大约需要50us。

我的问题:

1.为什么收集通道较少,但时间延长;

2.根据数据手册、采样频率是4Msps、请帮助我们确认9us 采样时间是否合理;

3、是否有措施加快采样时间。

我的程序如下、计时开始和结束于 hal_adc_trigger ()和  App_adcGetData ():

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

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

    您好、Walker Li:

    我正在查看您的问题,您可能会在一两天内得到回复。

    此致、Anil。

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

    好的、期待您的回复。

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

    您好、Walker Li

    默认情况下、ADC 仅连接到25MHz 时钟  。

    您能否确认您的设置中 ADC 时钟选择多路复用器值的值是多少?

    如果您将 Mux 选择值更改为1、则 ADC 将仅以60MHz 运行以获得4Msps。

    尝试将 Mux 时钟选择从0更改为1并检查结果 。

    请看下面的图片。

    多路复用器时钟选择寄存器是 CTRL MMR。 因此、该存储器位置具备锁定和解锁机制。

    锁定 CTRL_MMR 后、用户将无法更改多路复用器选择。

    因此、 我们可以使用锁定机制来更改时钟选择、您  可以尝试下面的代码。

      有关锁保护的详细信息、请参阅以下章节。

        /* set ADC clock source */
        SOC_controlModuleUnlockMMR(SOC_DOMAIN_ID_MAIN, 2);
        *(volatile uint32_t*)AddrTranslateP_getLocalAddr(0x43008510U) = 0x01;
        SOC_controlModuleLockMMR(SOC_DOMAIN_ID_MAIN, 2);

    此致、

    Anil。

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

    我按照建议添加了陈述、但测试发现 ADC 未运行。 您是否需要在运行前启用 PLL 时钟? 如何启用 PLL 时钟?

    int32_t hal_adc_init(void)
    {
        uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR;
    
        /* set ADC clock source */
        SOC_controlModuleUnlockMMR(SOC_DOMAIN_ID_MAIN, 2);
        *(volatile uint32_t*)AddrTranslateP_getLocalAddr(0x43008510U) = 0x01;
        SOC_controlModuleLockMMR(SOC_DOMAIN_ID_MAIN, 2);
        App_adcInit(baseAddr);
        App_adcConfig(baseAddr);
        /* Set EOI to generate next interrupt if any */
        ADCWriteEOI(baseAddr);
        App_adcStart(baseAddr);
    
        return MT_OK;
    }

    此外、我发现在程序运行时、有时 ADC 中断会突然无法触发(可以通过 ADCREGS_FIFO0WC 观察到可以正常更新 ADC FIFO)、此时 PWM、ECAP 和其他中断是正常的。 请您告诉我这种情况的可能原因、 它是否与中断抢占有关、以及如何避免或解决它。

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

    您好、 Walker Li

    在对时钟选择进行调制后、我能够正确运行 ADC 示例。

    我们不需要配置 PLL 设置、只需要更新 ADC 多路复用器选择。

    由于所有 PLL 均由 DMSC 软件配置。

    您能否确认您的代码和示例代码之间的区别?

    此致、

    Anil。

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

    尊敬的 Walker。

    请检查 Anil 的回复并提供您的状态吗?

    非常感谢!

    Yong