2019-09-11 01:33 AM
Hello,
I'm observing a stability issue on the internal voltage reference while using STOP mode.
I'm using STM32L431, with :
- VCC=1.9V
- VCC_AN=2.8V
- internal reference set at 2.5V with output buffer enabled in low impedance mode, decoupled with 100nF+1µF on VREF+ pin
- in normal operation, clocked with HSI, 16MHz, voltage scaling 2
- wakeup timer clocked in LSE mode by an external precision 32K oscillator
- ADC and DAC are used
For the moment, I'm just testing the basic application task that measure two sensors periodically.
Each 488µs, the MCU wakes up, turn on sensors power, enable and set DAC outputs (independent, used for sensor compensation), wait for sensor front end stabilization and perform an acquisition cycle (one measure for each sensor, and another measure of battery, in oversampling mode 4x, final resolution 12 bits), send data over UART (for monitoring), then go back to sleep.
Sleep corresponds to STOP2 mode, and is enabled by "HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);".
ADC, VREF and VREF buffer stay enabled during sleep mode to get full analog operation 20µs after wakeup.
Total duration in active mode is about 50µs.
Mains portions of code are given below, please ask for other functions if needed.
This is what I'm observing when plugging scope on the VREF output (that is not connected to anything else except decoupling capas, and internal ADC/DAC) : at each wakeup, the reference rises of a little voltage step. Once arrived to a certain amount, it returns to the init value, and then continues to rise slowly, step by step, at each cycle, and so on...Full peak to peak amplitude between min and max levels is 200mV !
The rise step seems not dependent on the wakeup period : either for 488µs or 244µs period, the number of wakeup cycles is identical (28-29 cycles).
But, the rise step depends on how long the DAC stay enabled. If I keep it enabled for an additionnal 25µs, I still do observe a variation in VREF when toggling it on, but it does not accumulate cycle after cycle, I mean at next cycle it does not increase.
This only happens if STOP mode is enabled. If I keep the same code and I use simple wakeup timer flag polling, even with the exact same measurement operations and DAC toggling on/off, I don't see any effect on VREF that is stable.
So, I tried to keep DAC enabled in STOP2 mode, without the additionnal delay : the problem is solved, I don't observe the VREF increase. The overconsumption in sleep mode is low, about 1µA, because I don't use the DAC output buffer, I have external high speed low Iq opamps for that. And the DAC opamp buffers outputs are connected to a high impedance node that does not increase consumption.
BUT : I read on the ref manual that DAC must be disabled in STOP2 mode. Why ? In the power mode description section, I see something different : "ADC, DAC, VREF buffer can consume power during STOP2 mode".....
When watching the DAC output, once sleep mode is entered, the output value is not maintained and decrease "slowly" to 0. When stop mode is exited, it returns to its previously set value, without affecting the VREF like it did if I had to power it up before !
So, my questions :
- what may cause this VREF behavior when toggling DAC on/off and using STOP2 mode too quickly ? Is it related to some rush current during DAC startup that impact VREF, and a wired VREF generation that accumulate errors until a check is performed and VREF is reset ? I see in the errata a mention to a brownout reset that may occurs if delay between two STOP mode is too low ; this is not the case here, but may it be a side effect ?
- what may be the risk to use DAC in STOP2 mode ?
Thanks
This is the portion of code that does not work (sleep mode, voltage reference not stable) :
// Set wakeup timer
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 7, RTC_WAKEUPCLOCK_RTCCLK_DIV2); // 488µs
// Pause systick
HAL_SuspendTick();
while (1)
{
// Enter STOP2 mode
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
// Clear flag and WDT
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
WdtReset();
DAC_Write_Channel_1(1024);
DAC_Write_Channel_2(1024);
DAC_enable_output();
Sensor_power_on();
Timer1us(2);
Instru_amp_enable();
Timer1us(25); // stabilization delay
// Start conversion
__HAL_ADC_CLEAR_FLAG(&hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS | ADC_FLAG_OVR));
SET_BIT(hadc.Instance->CFGR, ADC_CFGR_DMAEN);
HAL_DMA_Start(hadc.DMA_Handle, (uint32_t)&(hadc.Instance->DR), (uint32_t)adc_buffer, 3);
LL_ADC_REG_StartConversion(hadc.Instance);
// Wait for conversion complete
while (__HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOS) == 0);
//Timer1us(25); // optionnal delay that make the VREF stable
Sensor_power_off();
Instru_amp_disable();
DAC_disable_output();
// Clear flags
__HAL_ADC_CLEAR_FLAG(&hadc, (ADC_FLAG_EOS | ADC_FLAG_EOC));
// Switch DMA to READY state to not perturb HAL functions
hdma_adc.State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(&hdma_adc);
// Send results to plotter
test_buffer[0] = (uint8_t)(adc_buffer[0]>>8);
test_buffer[1] = (uint8_t)(adc_buffer[0]);
test_buffer[2] = (uint8_t)(adc_buffer[1]>>8);
test_buffer[3] = (uint8_t)(adc_buffer[1]);
HAL_UART_Transmit(&huart_usbhs, test_buffer, 4, 10);
}
Macros and functions :
// DAC
#define DAC_enable_output() (hdac.Instance->CR = (DAC_CR_EN1 | DAC_CR_EN2))
#define DAC_disable_output() (hdac.Instance->CR = 0)
#define DAC_Write_Channel_1(a) (hdac.Instance->DHR12R1 = a)
#define DAC_Write_Channel_2(a) (hdac.Instance->DHR12R2 = a)
// Initialization code for voltage reference
HAL_SYSCFG_EnableVREFBUF(); // Enable the Internal Voltage Reference buffer
HAL_SYSCFG_VREFBUF_HighImpedanceConfig(SYSCFG_VREFBUF_HIGH_IMPEDANCE_DISABLE); // Configure the internal voltage reference buffer high impedance mode
/* DAC1 init function */
static void MX_DAC1_Init(void)
{
DAC_ChannelConfTypeDef sConfig;
/**DAC Initialization
*/
hdac1.Instance = DAC1;
if (HAL_DAC_Init(&hdac1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**DAC channel OUT1 config
*/
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**DAC channel OUT2 config
*/
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}