工具与软件:
您好:
使用 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 的中断异常。
谢谢。

