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-26 02:11 AM
I've seen this issue raised by several uses of Mbed and the mDot/xDot devices which contain an STM32. I can only find these two references now:
https://os.mbed.com/questions/52467/Cant-read-ADC-after-WakeUp-from-deepslee/
https://os.mbed.com/questions/78300/xDot-ADC-problem-when-coming-out-of-slee/
and both suggest the HSI has to be explicitly re-enabled, but it looks like you're already calling
SystemClock_Config
(). I thought there was another solution along the lines having to manually reconfigure something but can't find it now.2018-04-26 05:06 AM
Probably not directly relevant but maybe something interesting in this thread :
2018-04-28 05:36 AM
yes, after wake-up, I have called HSI init, this patch seems do not work on my board. I am trying to do ADC register value comparation before and after STOP.
2018-04-29 01:44 AM
I have print all ADC and DMA register before and after wakeup, no any finding. following is the output of ADC & DMA register values comparation before and after waekup from stop.
I am suspecting whether this is a STM32L071RB chipset bug now.
Start to fetch battery voltageval[0][0] = 1671, val[0][1] = 1536val[1][0] = 1673, val[1][1] = 1535val[2][0] = 1675, val[2][1] = 1536val[3][0] = 1674, val[3][1] = 1535val[4][0] = 1671, val[4][1] = 1535 Voltage result->s 4144mvBefore STOP
before adc-deinitADC->ISR : 0x00000808HADC->IER : 0x00000000HADC->CR : 0x10000000HADC->CFGR1 : 0x00002002HADC->CFGR2 : 0x00000000HADC->TR : 0x0FFF0000HADC->CHSELR : 0x00000003HADC->DR : 0x000005FFHADC->CALFACT: 0x0000003DHDMA->CCR : 0x000015AEHDMA->CNDTR: 0x0000000AHDMA->CPAR : 0x40012440HDMA->CMAR : 0x200025FCHafter adc-dinitADC->ISR : 0x00000000HADC->IER : 0x00000000HADC->CR : 0x00000000HADC->CFGR1 : 0x00000000HADC->CFGR2 : 0x00000000HADC->TR : 0x00000000HADC->CHSELR : 0x00000000HADC->DR : 0x00000000HADC->CALFACT: 0x00000000HDMA->CCR : 0x00000000HDMA->CNDTR: 0x00000000HDMA->CPAR : 0x00000000HDMA->CMAR : 0x00000000HEnter STOP
wakeup from STOP
after stop, before adc-init
ADC->ISR : 0x00000000HADC->IER : 0x00000000HADC->CR : 0x00000000HADC->CFGR1 : 0x00000000HADC->CFGR2 : 0x00000000HADC->TR : 0x00000000HADC->CHSELR : 0x00000000HADC->DR : 0x00000000HADC->CALFACT: 0x00000000HDMA->CCR : 0x00000000HDMA->CNDTR: 0x00000000HDMA->CPAR : 0x00000000HDMA->CMAR : 0x00000000Hafter adc-reinitADC->ISR : 0x00000800HADC->IER : 0x00000000HADC->CR : 0x10000000HADC->CFGR1 : 0x00002002HADC->CFGR2 : 0x00000000HADC->TR : 0x0FFF0000HADC->CHSELR : 0x00000003HADC->DR : 0x0000003EHADC->CALFACT: 0x0000003EHDMA->CCR : 0x000015A0HDMA->CNDTR: 0x00000000HDMA->CPAR : 0x00000000HDMA->CMAR : 0x00000000HEcho:gvol
Start to fetch battery voltage
val[0][0] = 1669, val[0][1] = 4095val[1][0] = 2047, val[1][1] = 2047val[2][0] = 2047, val[2][1] = 2047val[3][0] = 2047, val[3][1] = 2047val[4][0] = 2047, val[4][1] = 2047 Voltage result->s 6630mv2018-05-02 01:13 AM
thanks all of person's help, finially, I found the fix. if I enable ultra low power mode, this issue disappeared, although I don't understand the real reason.
HAL_PWREx_EnableUltraLowPower();
2018-05-02 05:11 AM
Thanks very much for the follow-up, and thanks to Thomas for digging up a thread I was thinking of. There's definitely some peculiarities related to the ADC and sleep modes in the STM32 family. Hopefully threads like this will help others find a solution.
2023-10-17 12:57 PM - edited 2023-10-17 12:57 PM
I just wanted to bump this for the mods.
Has anyone found a solution? In any configuration if we enable ULP, after STOP wakeup the vref seems corrupt.
2023-10-30 10:04 AM
Try disabling the ULP before ADC calibration and enable when you are done with the ADC.
This worked for us:
void ADC_Start() {
LL_PWR_DisableUltraLowPower();
HAL_ADCEx_EnableVREFINT(); //Wait for vref to start
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
HAL_ADC_Start_DMA(&hadc, (uint32_t*) &ADC_raw, adc_Channels);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
HAL_ADC_Stop_DMA(hadc);
LL_PWR_EnableUltraLowPower();
}
2024-09-02 03:25 AM
@Head
After several hours I have found what was wrong.
When I switch to Ultra Low Power Mode I had to switch IO ports to alternative function mode too ( to save some current ).
And that was the reason.
On PB0 or PB1 ( don't remember ) I have Vref out with few uA ability to drive with pull down on same pin.
So when I swich port to alternate function I have pull down on Vref and it is not able to restart properly due to load.
It is enough to not switch I/o port to AF before entering ULP. Instead AF , input is enough.
Adam