YTM32B1ME05 ADC不稳问题
-
问题描述
最近在使用YTM32B1ME05的ADC模块时时遇到了一个问题,使用了ADC0和ADC1两个模块,固定通过eTMR的一个通道触发采集,周期大概在1ms,测试发现采集到的AD值会一直跳动,排查发现和切换TMU和ADC_CHSELx的配置有关系,请问下这里有什么需要注意和的地方吗?如何解决?
原理图 VREF:

不切换配置
void user_adc_start_conversion(void) { tmu_target_module_t targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; /* Configure ADC channel selection based on PWM index */ if(adcInst[UserAdcParams.pwmIndex][0] == ADC1_INST) { // ADC1->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; // targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; } else { // ADC0->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; // targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; } /* Update TMU target module directly without reinitializing entire TMU * This is more efficient than TMU_DRV_Init which resets all target modules */ TMU->MUX[3] = 0; TMU->MUX[4] = 0; TMU_SetTrigSourceForTargetModule(TMU, TMU_TRIG_SOURCE_eTMR0_EXT_TRIG, targetModule); }结果如图,基本在2938~2948之内,波动比较小

周期切换TMU
void user_adc_start_conversion(void) { tmu_target_module_t targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; /* Configure ADC channel selection based on PWM index */ if(adcInst[UserAdcParams.pwmIndex][0] == ADC1_INST) { // ADC1->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; } else { // ADC0->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; } /* Update TMU target module directly without reinitializing entire TMU * This is more efficient than TMU_DRV_Init which resets all target modules */ TMU->MUX[3] = 0; TMU->MUX[4] = 0; TMU_SetTrigSourceForTargetModule(TMU, TMU_TRIG_SOURCE_eTMR0_EXT_TRIG, targetModule); }结果如图

周期切换ADC通道
注意通道0和1不切换,只切换2和3
void user_adc_start_conversion(void) { tmu_target_module_t targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; /* Configure ADC channel selection based on PWM index */ if(adcInst[UserAdcParams.pwmIndex][0] == ADC1_INST) { // ADC1->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; ADC1->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; ADC1->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; } else { // ADC0->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; ADC0->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; ADC0->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; } /* Update TMU target module directly without reinitializing entire TMU * This is more efficient than TMU_DRV_Init which resets all target modules */ TMU->MUX[3] = 0; TMU->MUX[4] = 0; TMU_SetTrigSourceForTargetModule(TMU, TMU_TRIG_SOURCE_eTMR0_EXT_TRIG, targetModule); }结果如图,抖动的比较厉害

用到的函数
/** * @brief Print latest ADC samples in JustFloat-like format */ void user_adc_print_samples(void) { uint8_t frame[4U * sizeof(float) + 4U]; uint32_t offset = 0U; if(!sendFlag) { return; } sendFlag = false; for(uint8_t idx = 0U; idx < 4U; idx++) { float f = (float)adcSapleResult[idx]; (void)memcpy(&frame[offset], &f, sizeof(float)); offset += (uint32_t)sizeof(float); } (void)memcpy(&frame[offset], c_justfloat_tail, sizeof(c_justfloat_tail)); offset += (uint32_t)sizeof(c_justfloat_tail); /* Send with LINFlexD UART polling, instance = 2 */ LINFlexD_UART_DRV_SendDataPolling(2U, frame, offset); } /** * @brief ADC0 interrupt handler * @return none */ void ADC0_IRQHandler(void) { ADC_DRV_ClearEoseqFlagCmd(0); adcSapleResult[0] = ADC_DRV_ReadFIFO(0); adcSapleResult[1] = ADC_DRV_ReadFIFO(0); adcSapleResult[2] = ADC_DRV_ReadFIFO(0); adcSapleResult[3] = ADC_DRV_ReadFIFO(0); adcSapleSum = adcSapleResult[0] + adcSapleResult[1] + adcSapleResult[2] + adcSapleResult[3]; updateAdcResult(adcSapleSum >> 2); UserAdcParams.boardSupplyVolt.rawAdcValue = ADC_DRV_ReadFIFO(0); UserAdcParams.ledSupplyVolt.rawAdcValue = ADC_DRV_ReadFIFO(0); } /** * @brief ADC1 interrupt handler * @return none */ void ADC1_IRQHandler(void) { ADC_DRV_ClearEoseqFlagCmd(1); adcSapleResult[0] = ADC_DRV_ReadFIFO(1); adcSapleResult[1] = ADC_DRV_ReadFIFO(1); adcSapleResult[2] = ADC_DRV_ReadFIFO(1); adcSapleResult[3] = ADC_DRV_ReadFIFO(1); adcSapleSum = adcSapleResult[0] + adcSapleResult[1] + adcSapleResult[2] + adcSapleResult[3]; updateAdcResult(adcSapleSum >> 2); sendFlag = true; } -
在ADC中断中每次读8次FIFO可以解决
-
quanfeng 忘记说了,下午重新验证了下,发现并没有通道错位情况,数据还是一样波动比较大。
代码如下:
/** * @brief ADC0 interrupt handler * @return none */ void ADC0_IRQHandler(void) { uint32_t adcSampleSum = 0U; uint8_t expectedChannel = adcInst[UserAdcParams.pwmIndex][1]; uint8_t validCnt = 0U; ADC_DRV_ClearEoseqFlagCmd(0); adcSampleSum = 0U; for(uint8_t readCnt = 0U; readCnt < 8U; readCnt++) { adcSampleResult[readCnt].u32DualWord = ADC0->FIFO; if(readCnt < 4U) { if(adcSampleResult[readCnt].parts.u16ChnIndex == expectedChannel) { adcSampleSum += adcSampleResult[readCnt].parts.u16ChnResult; validCnt++; } else { misMatchFlag = true; } } } if (validCnt > 0U) { updateAdcResult((uint16_t)(adcSampleSum / validCnt)); } else { updateAdcResult(0x8000); } if(adcSampleResult[4].parts.u16ChnIndex == ADC_INPUTCHAN_EXT17) { UserAdcParams.boardSupplyVolt.rawAdcValue = adcSampleResult[4].parts.u16ChnResult; }else{ misMatchFlag = true; } if(adcSampleResult[5].parts.u16ChnIndex == ADC_INPUTCHAN_EXT18) { UserAdcParams.ledSupplyVolt.rawAdcValue = adcSampleResult[5].parts.u16ChnResult; }else{ misMatchFlag = true; } } /** * @brief ADC1 interrupt handler * @return none */ void ADC1_IRQHandler(void) { uint32_t adcSampleSum = 0U; uint8_t expectedChannel = adcInst[UserAdcParams.pwmIndex][1]; uint8_t validCnt = 0U; ADC_DRV_ClearEoseqFlagCmd(1); for(uint8_t readCnt = 0U; readCnt < 8U; readCnt++) { adcSampleResult[readCnt].u32DualWord = ADC1->FIFO; if(readCnt < 4U){ if(adcSampleResult[readCnt].parts.u16ChnIndex == expectedChannel) { adcSampleSum += adcSampleResult[readCnt].parts.u16ChnResult; validCnt++; } else { misMatchFlag = true; } } } if (validCnt > 0U) { updateAdcResult((uint16_t)(adcSampleSum / validCnt)); } else { updateAdcResult(0x8000); } }进不到misMatchFlag 为true情况,采集到的数据波动比较大。

-
ADC0配置:

ADC1配置

代码
void user_adc_start_conversion(void) { tmu_target_module_t targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; /* Configure ADC channel selection based on PWM index */ if(adcInst[UserAdcParams.pwmIndex][0] == ADC1_INST) { // ADC1->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC1->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC1_EXT_TRIG; } else { // ADC0->CHSEL[0] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[1] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[2] = adcInst[UserAdcParams.pwmIndex][1]; // ADC0->CHSEL[3] = adcInst[UserAdcParams.pwmIndex][1]; targetModule = TMU_TARGET_MODULE_ADC0_EXT_TRIG; } /* Update TMU target module directly without reinitializing entire TMU * This is more efficient than TMU_DRV_Init which resets all target modules */ TMU->MUX[3] = 0; TMU->MUX[4] = 0; TMU_SetTrigSourceForTargetModule(TMU, TMU_TRIG_SOURCE_eTMR0_EXT_TRIG, targetModule); }结果如下

快速上手云途开发生态
发帖前请查看
帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...





