Sí tienes un proyecto alrededor de un STM32, en concreto el STM32F103, que funciona con baterías o paneles solares, te interesa reducir el consumo todo lo posible, para aumentar la vida de tu batería. Así que en esta entrada vamos a ver cómo usar los modos de bajo consumo en un STM32, Standby, Stop y Sleep con el framework STM32CubeMX.
Formas de bajar el consumo de un STM32
Existen diferentes formas de bajar el consumo de un microcontrolador STM32, además de los modos de bajo consumo que comentaremos más adelante, podemos usar otras técnicas. Tenemos que tener en cuenta que la bluepill puede llegar a consumo alrededor de 2-4 micro amperios, un consumo prácticamente despreciable (cualquier batería se va a auto-descargar más rápido que eso).
Generalmente en nuestro proyecto, tenemos además del microcontrolador, sensores o actuadores. Estos dispositivos extras pueden llegar a consumir algunos mA incluso sin hacer nada, en comparación los sensores pueden ser nuestra principal fuente de gasto, así que antes de trabajar con los modos de bajo consumo es necesario hacer un análisis de cual es el consumo de los dispositivos conectados. Lo ideal sería alimentar los sensores/actuadores solo cuando sea necesario. Es decir, encender la alimentación del dispositivo, leer el dato y apagarlo.
Además, es importante quitar o desactivar todos los LEDs/sensores cuando no se están usando. En el caso de la bluepill, el LED que indica que hay alimentación, consume él solo 2mA. Por lo que por mucho que pongamos nuestro microcontrolador en modo bajo consumo, el mínimo va a ser 2mA del LED.

Otro factor a tener en cuenta, son los reguladores de voltaje: estos reguladores generalmente tienen una corriente de funcionamiento, por lo que es importante elegir reguladores con una Quiescent Current baja. Por ejemplo, para ver lo importante que es elegir el regulador bien, si comparamos las corrientes de reposo del AMS1117 con el MCP1700: Tenemos que el AMS1117 tiene entre 5 y 10mA, mientras que el MCP1700 tiene un máximo de 4 microamperio, es decir la misma batería duraría 1000 veces más!.
Una vez que ya hemos optimizado todo lo que rodea el microcontrolador, el siguiente paso es usar los modos de bajo consumo del micro. La diferencia de tener el microcontrolador en modo normal (10mA) a tenerlo en modo Stop (~30uA), puede alargar mucho la eficiencia de tu sistema. Por otro lado, se puede bajar la velocidad del reloj, desactivar relojes de dispositivos que no estás usando, o poner los GPIO en modo analógico.
Qué son los modos de bajo consumo
En este caso nos vamos a centrar en el STM32F103 y sus modo de ejecución: run, sleep, stop y standby. En la siguiente imagen, podemos ver todos los componentes del STM32 y sus alimentaciones. Teniendo en cuenta las alimentaciones podemos ver que hay varias formas de ejecución:
- Modo Run: Es el modo en el que arranca el STM32 por defecto, en este modo todos los componentes se pueden usar y están alimentados (hay que encenderlos para que funcionen). Además, todos los relojes están funcionando.
- Modo Sleep: Es el primer modo de bajo consumo, en este modo se desactiva el reloj de la CPU, sin embargo todo los periféricos siguen funcionando (NVIC, SysTick, ….).
- Modo Stop: el siguiente modo de bajo consumo en el cual se apagan todos los relojes tanto los del dominio 1.8V como los relojes HSI y HSE. Esto significa que los periféricos están apagados y no se puede interactuar con ellos desde el exterior. Sin embargo, se mantiene la alimentación del dominio 1.8V (significa que el valor de los registros se mantiene durante el modo stop).
- Modo Standby : el de menor consumo, en este modo se apaga prácticamente todo y cuando se recupera de este modo, es cómo si se reiniciase el microcontrolador y empieza desde el principio (No sigue desde donde lo dejaste).

A continuación vamos a ver ejemplos de cómo usar los modos de bajo consumo en una bluepill: cómo poner los diferentes modos, y cómo recuperar el control. En los ejemplos de bajo consumo del STM32 vamos a ver casos sencillos y qué pueden ser útiles, pero no vamos a entrar en profundidad en todos y cada una de las posibilidades.

Cómo usar el modo Sleep
Qué hace el modo Sleep
El modo Sleep es el primero de todos los modos de bajo consumo: la reducción de consumo en este caso no es excesiva, pero a cambio tenemos todos los periféricos funcionando. Únicamente deja de ejecutar instrucciones la CPU. Cómo podemos ver el consumo puede bajar hasta 5.5mA y 3mA si lo tenemos funcionando a 8MHz. En este modo, nos puede interesar desactivar los relojes de los periféricos que no queremos usar mientras duerme, para así ahorrar aún más consumo.

Para salir del modo Sleep se puede configurar para esperar una interrupción (WFI: Wait for Interrupt) o esperar a un evento (WFE: Wait for Event).
Código de ejemplo de Sleep en STM32
Todo el código está basado en un proyecto de cubeMX funcionando sobre platformIO, así que aquí solo voy a poner el código del main. Vamos a ver cómo hacer el parpadeo del LED usando el modo Sleep con una interrupción externa EXTI. Lo que vamos a hacer es decirle al micro que se quede dormido hasta que detecte alguna interrupción (cualquiera) aunque en nuestro caso vamos a hacerlo con un pulsador. Queremos que: cuando detecte un flanco de subida en un pin, se despierte, parpadee el LED y se vuelva a dormir.
Vamos a usar una configuración de reloj del cubeMX para bajo consumo es:

int main(void){ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pin : PB5 */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); while(1){ HAL_SuspendTick(); HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI); HAL_ResumeTick(); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); } }

Cómo usar el Stop
Qué hace el modo Stop
El modo Stop es el siguiente modo de bajo consumo, en este ya podemos obtener consumos tan bajos como decenas de micro amperios. En este caso, ya no tenemos disponible ningún periférico, así que no podemos, por ejemplo despertar con una interrupción UART. Sin embargo, los registros guardarán el valor que tenían antes de entrar al modo Stop, es decir, sí una GPIO la teníamos a valor ALTO, seguirá en ese valor.

Para volver del modo Stop, podemos usar, igual en el caso del sleep, una interrupción. En este caso el código es prácticamente similar, solo cambia una línea.
Código de ejemplo de Stop en STM32
int main(void){ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pin : PB5 */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); while(1){ HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); HAL_ResumeTick(); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); }

Cómo usar el modo StandBy
Qué hace el modo Standby
El modo Standby es el modo más agresivo para reducir el consumo de potencia del STM32. En este modo nuestro microcontrolador reduce su consumo al mínimo, así como su funcionalidad. En este modo no tenemos acceso a las interrupciones externas (EXTI), la CPU y todos los relojes están apagados. Los datos que tuviéramos en la RAM y el estado de los registros los hemos perdido. De hecho, cuando “despertemos” del modo Standby el microcontrolador se va a reiniciar y va a empezar desde el principio, reconfigurando todo.
En el modo Standby solo podemos activar: el IWDG(Independent watchdog), el RTC (Real-time clock), el oscilador RC interno (LSI) y el oscilador de 32.768KHz externo. Dado que no tenemos nada del microcontrolador funcionando, despertarlo no es tan sencillo. No podemos esperar a interrupciones en pines o periférico (UART/DMA …), en este caso solo tenemos las siguientes opciones para despertarlo:
- Reset externo: es decir interactural con el pint NRST.
- Un reset del IWDG
- Un flanco de subida en el pin WKUP (WakeUp pin)
- O una alarma del RTC
Código de ejemplo de Standby en STM32 con RTC
En este caso vamos a usar la alarma del RTC ya que el proyecto en el que estoy trabajando, necesita dormir la bluepill durante periodos de minutos, y eso no lo podemos conseguir con el resto de periféricos. Para ello necesitamos activar el RTC en el cubeMX y obtener su inicialización MX_RTC_Init()
. Además, una cosa importante es que tenemos que resetear los flags que avisan que venimos de un standby (líneas 12 a 16).
int main(void){ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); MX_RTC_Init(); /* Si venimos de un standby tenemos que limpiar algunos flags */ if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) { __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); } GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); RTC_TimeTypeDef rtcTime; RTC_AlarmTypeDef rtcAlarm; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); while(1){ // Ponemos la hora actual a 00:00:00 HAL_RTC_WaitForSynchro(&hrtc); rtcTime.Hours = 0; rtcTime.Minutes = 0; rtcTime.Seconds = 0; HAL_RTC_SetTime(&hrtc,&rtcTime, RTC_FORMAT_BCD); // Configuramos la alarma a las 00:00:10 rtcAlarm.Alarm = RTC_ALARM_A; rtcAlarm.AlarmTime = rtcTime; rtcAlarm.AlarmTime.Seconds = 10; HAL_RTC_SetAlarm_IT(&hrtc, &rtcAlarm, RTC_FORMAT_BCD); // Entramos en Standby HAL_PWR_EnterSTANDBYMode(); } }

Conclusiones: Qué modo de bajo consumo me interesa
Habéis visto algunos ejemplos de cómo entrar a modo bajo consumo del STM32F103 con la bluepill. Las medidas que veis en el multímetro pueden ser afectadas por varias cosas, pero nos podemos quedar con el descenso de consumo que hemos tenido de 10mA en modo normal a tan solo 76 uA en el modo más ahorrador…
Sleep | Stop | Standby | |
---|---|---|---|
Consumo medido | 2 mA | 300 uA | 76 uA |
Perifericos | Todos (UART/SPI/Relojes…) | Interrupciones y algunos perifericos | Solo RTC y IWDG |
Guarda RAM y registros | Sí | Sí | No |
Cuanto tarda en despertar | Muy poco | Depende del Internal Regulator (de poco a medio) | Mucho |
Con esto, creo que ya tenéis bastante información para adentraros en el mundo del Low power. Recuerda, que si quieres ver en que voy a usar estó, lo puedes encontrar en mi canal de Youtube!
0 comentarios