2018-04-23 09:00 AM
Hello,
I'm using STM32L071RBT6 MCU, encounter a strange issue. when MCU power on, using ADC channel 0 to monitor external battery voltage, the result is OK. but once system waked up from STOP mode, ADC converter behavior is abnormal, the sampling value random varied from 0 ~ 2000. following is my STOP method, can give me some hint?
/* ADC init function */
static void MX_ADC_Init(void){ADC_ChannelConfTypeDef sConfig;
HAL_ADCEx_EnableVREFINT();/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/ hadc.Instance = ADC1; hadc.Init.OversamplingMode = DISABLE; hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV16; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DMAContinuousRequests = ENABLE; hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerFrequencyMode = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; if (HAL_ADC_Init(&hadc) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }/**Configure for the selected ADC regular channel to be converted.
*/ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }/**Configure for the selected ADC regular channel to be converted.
*/ sConfig.Channel = ADC_CHANNEL_1; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }}
/***********************************************************************
* trigger MCU enter stop mode
*/
void powerSaving(void){
//config GPIO to analog mode (zero consumption for every analog GPIO)
lightLed(LED_GREEN, false);
//HAL_ADC_DeInit(&hadc);
//clear wakeup flag
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
//call power function to enter ''STOP'' mode
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
//after stop, program continue run from here
//config RCC
SystemClock_Config();
//sysclkConfig_after_stop();
//adc init
HAL_ADC_DeInit(&hadc);
MX_ADC_Init();
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
//config GPIO
}
// following is ADC sampling methods:static volatile uint16_t adcValue[5][2];
/**************************************************************************************** Get battery voltage*/static void handleBattVoltageFetch(void){ if (ADC_IS_CONVERSION_ONGOING_REGULAR(&hadc) == SET) return; //enable MOSFET HAL_GPIO_WritePin(BATT_ADC_EN_GPIO_Port, BATT_ADC_EN_Pin, GPIO_PIN_SET); osDelay(100); //start timer osTimerStart(myMotoTimerHandle, 500); //set batt vol ADC enable flag setAdcControlFlag(BATT_VOL_ADC_EN); //start ADC HAL_ADC_Start_DMA(&hadc, (uint32_t*)adcValue, sizeof(adcValue)/sizeof(uint16_t));}/***************************************************************************************
* ADC completed, calculate voltage value*/static void handleBattVolAdcAvail(void){ HAL_ADC_Stop_DMA(&hadc); //disable MOSFET HAL_GPIO_WritePin(BATT_ADC_EN_GPIO_Port, BATT_ADC_EN_Pin, GPIO_PIN_RESET); if (xTimerIsTimerActive(myMotoTimerHandle)){ osTimerStop(myMotoTimerHandle); }uint32_t vol = 0;
for (int i=0;i<5;i++){ vol += adcValue[i][1] & 0xfff;#ifdef DEBUG_LOG_LEVEL_1 printf(''val[%d][0] = %d, val[%d][1] = %d\n'', i, adcValue[i][0], i, adcValue[i][1]); osDelay(10);#endif } vol = (vol * 67 * VDDA_VOLTAGE) / (20 * 5 * 4096); sensorData.voltageData.batteryVoltage = vol; if (vol > BATTERY_VOLTAGE_WARNING) sensorData.voltageData.flag = (uint8_t)BATT_INFO; else if (vol >= BATTERY_VOLTAGE_LOW) sensorData.voltageData.flag = (uint8_t)BATT_WARNING; else sensorData.voltageData.flag = (uint8_t)BATT_LOW; sensorData.flag |= DATA_UPDATE_VOLTAGE; //inform mainApp that vol data is ready osSignalSet(mainAppTaskHandle, SIG_MAINAPP_VOL_DATA_OK);}/****************************************************************************************
* ADC DMA convert completed callback*/void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle){ uint32_t val; if (isVolAdcEn()){ //check Voltage HAL_ADC_Stop_DMA(&hadc); osSignalSet(sensorTaskHandle, SIG_SENSOR_VOL_AVAIL); }}2018-04-23 10:19 AM
I think you should restart the reference after wakeup:
HAL_ADCEx_EnableVREFINT();
and wait until it stabilizes before making acquisitions.
2018-04-23 09:56 PM
Max, thanks for your reply, according to your suggestion, I add HAL_ADCEx_EnableVREFINT() after system wakeup, unfortunately, problem still exist.
2018-04-23 10:27 PM
Don't know the HAL code.
I would compare the ADC register settings before stop mode, and afterwards.
And perhaps other registers that influence the ADC operation.
2018-04-24 08:14 AM
do you have a calibrate function ?
on the 'F091 the ADC readings change dramatically after a calibrate.
2018-04-24 08:23 PM
TJ, yes, every wakeup from stop, I will do a ADC calibration, is this wrong?
2018-04-24 09:48 PM
it sounds like you are scanning more than one channel after stop.
oooo yes, dont use the highest clock and highest speed conversion, the result is noisy.ADCs
Are you using the DMA ? , it seems very stable and reliable.
All my projects use the ADC DMA circular buffer function to scan all the ADCs.
I write a table of 14 ADCs, 16 rows deep.
after every line conversion the Interrupt copies the DMA buffer(32bytes) to the next row in my table.
then I add all 16 rows for each channel. It takes about 5uSec in that interrupt.
That gives me an oversampled 16bit total for each channel.
That offers you some extra stability in the reading,
You can shift it down 2/3/4.. bits if you need a more stable value.
I don't use stop, sorry for the lack of knowledge....
Bill Gates never used stop. and he said 256k Ram is all you will ever need.
2018-04-25 08:56 AM
thanks TJ for share your experience,
yes, I using 2 ADC channels, and I have a 2X10 bytes array, using DMA circle reading ADC data, every DMA interrupt, I calculate the average value of 5 samplings of every channel.
since my device is using for low-power consumption scenario, device will wake-up periodic, so have to use STOP mode.
Anyhow, I will try to downgrade the ADC clk frequency see whether can kill this problem.
2018-04-25 10:32 AM
I downgrade ADC CLK from HSI-16M to HSI- 4M, (prescale by 16, sampling time 79.5), issue still exist.
2018-04-25 06:52 PM
go much slower, check out the results,
or else its your problematic programatic issue..
you are doing a cal on wake ?
run your DMA cycle a few times, see if it stabilizes.
My ADC-DMA runs continuously without issue.