工具与软件:
您好:
使用 ADC 时、偶尔会出现中断丢失的问题。 请帮助我们检查:
1. 我们在 PWM 中断中触发 ADC (单次触发模式)、PWM 优先级为7、ADC 优先级为1。 ;中有定时器中断和 GPIO 中断、它们的中断优先级为7 μ s
2. ADC 中断可在启动时正常触发、但在随后的运行中、ADC 中断会丢失、无法恢复;
3、在我们的测试中,运行30分钟、2小时、8小时等时会出现此问题;
4. 出现问题时:
a.计时器、PWM、GPIO 和其他中断可正常触发;
b. FreeRTOS 只能运行空闲任务;
c. 可以更新 ADC_FIFO0WC、因此 ADC 仍应正常采样、但尚未触发中断;
d. 即使调用 Hwip_enableInt ()来重新启用 ADC 中断,中断也无法恢复。
我的程序如下:
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); }
请帮助我们确认:
1. ADC 的配置和使用是否有问题;
2.在 ADC 正常中断处理过程中,我们将暂停并启动定时器,不管是否存在中断嵌套问题;
3.是否有其他因素会导致 ADC 的中断异常。
谢谢。