cancel
Showing results for 
Search instead for 
Did you mean: 

ADC behavior abnormal after wake up from STOP mode

dz huang
Associate III
Posted on April 23, 2018 at 18:00

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?

0690X0000060AjyQAE.png0690X0000060AjtQAE.png

/* 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);

}

}
18 REPLIES 18
Heath Raftery
Associate II
Posted on April 26, 2018 at 11:11

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.
Thomas LB
Associate III
Posted on April 26, 2018 at 14:06

Probably not directly relevant but maybe something interesting in this thread :

https://community.st.com/0D50X00009XkYPSSA3

Posted on April 28, 2018 at 12:36

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.  

Posted on April 29, 2018 at 08:44

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 voltage

val[0][0] = 1671, val[0][1] = 1536

val[1][0] = 1673, val[1][1] = 1535

val[2][0] = 1675, val[2][1] = 1536

val[3][0] = 1674, val[3][1] = 1535

val[4][0] = 1671, val[4][1] = 1535

Voltage result->s 4144mv

Before STOP

before adc-deinit

ADC->ISR : 0x00000808H

ADC->IER : 0x00000000H

ADC->CR : 0x10000000H

ADC->CFGR1 : 0x00002002H

ADC->CFGR2 : 0x00000000H

ADC->TR : 0x0FFF0000H

ADC->CHSELR : 0x00000003H

ADC->DR : 0x000005FFH

ADC->CALFACT: 0x0000003DH

DMA->CCR : 0x000015AEH

DMA->CNDTR: 0x0000000AH

DMA->CPAR : 0x40012440H

DMA->CMAR : 0x200025FCH

after adc-dinit

ADC->ISR : 0x00000000H

ADC->IER : 0x00000000H

ADC->CR : 0x00000000H

ADC->CFGR1 : 0x00000000H

ADC->CFGR2 : 0x00000000H

ADC->TR : 0x00000000H

ADC->CHSELR : 0x00000000H

ADC->DR : 0x00000000H

ADC->CALFACT: 0x00000000H

DMA->CCR : 0x00000000H

DMA->CNDTR: 0x00000000H

DMA->CPAR : 0x00000000H

DMA->CMAR : 0x00000000H

Enter STOP

wakeup from STOP

after stop, before adc-init

ADC->ISR : 0x00000000H

ADC->IER : 0x00000000H

ADC->CR : 0x00000000H

ADC->CFGR1 : 0x00000000H

ADC->CFGR2 : 0x00000000H

ADC->TR : 0x00000000H

ADC->CHSELR : 0x00000000H

ADC->DR : 0x00000000H

ADC->CALFACT: 0x00000000H

DMA->CCR : 0x00000000H

DMA->CNDTR: 0x00000000H

DMA->CPAR : 0x00000000H

DMA->CMAR : 0x00000000H

after adc-reinit

ADC->ISR : 0x00000800H

ADC->IER : 0x00000000H

ADC->CR : 0x10000000H

ADC->CFGR1 : 0x00002002H

ADC->CFGR2 : 0x00000000H

ADC->TR : 0x0FFF0000H

ADC->CHSELR : 0x00000003H

ADC->DR : 0x0000003EH

ADC->CALFACT: 0x0000003EH

DMA->CCR : 0x000015A0H

DMA->CNDTR: 0x00000000H

DMA->CPAR : 0x00000000H

DMA->CMAR : 0x00000000H

Echo:gvol

Start to fetch battery voltage

val[0][0] = 1669, val[0][1] = 4095

val[1][0] = 2047, val[1][1] = 2047

val[2][0] = 2047, val[2][1] = 2047

val[3][0] = 2047, val[3][1] = 2047

val[4][0] = 2047, val[4][1] = 2047

Voltage result->s 6630mv
dz huang
Associate III
Posted on May 02, 2018 at 10:13

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();

0690X0000060AsRQAU.png
Posted on May 02, 2018 at 12:11

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.

JWieb
Associate III

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.

JWieb
Associate III

@dz huang 

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();
}

 

 

 

 

@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