¿Qué instrucción en el STM32 consume la menor cantidad de energía?

El módulo ADC del STM32 se usa en mi aplicación, que es muy sensible al consumo de energía.

En esta aplicación, se requiere que el ADC funcione solo a 20 muestras por segundo. Usar el DMA usa más energía de lo que esperaba. Decidí hacer que funcionara en modo de muestra única haciendo que una tarea (FreeRTOS) desencadenara una conversión y esperara a que se realizara cada 50 ms.

Aquí está mi código:

 u16 i;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
 ADC_Cmd(ADC1, ENABLE);
 for(i=0;i<sizeof(ADC_Channel_Table)/sizeof(u8);i++)
 {
     ADC_RegularChannelConfig(ADC1, ADC_Channel_Table[i], 1, ADC_SampleTime_71Cycles5);
     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
     {
     }
     ADCConvertedValue[i] = ADC_GetConversionValue(ADC1);
 }
 ADC_Cmd(ADC1, DISABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);

Donde "sizeof(ADC_Channel_Table)" es 5 porque se muestrean 5 canales.

El tiempo de muestra es ADC_SampleTime_239Cycles5 (en realidad, 256 ciclos donde se incluye el tiempo de conversión). 5 canales por lo tanto requiere alrededor de 1500 ciclos. El reloj ADC es de 12 MHz y 1500 ciclos son aproximadamente 120 µs.

Y mira el código:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
{
}

Esto significa que la CPU se mantiene ocupada esperando a que se realice la conversión, y el tiempo de espera es de 120 µs en total.

120 µs es grande ya que la CPU debe esperar tanto tiempo y esto desperdicia energía, pero este nivel de tiempo es demasiado pequeño para el RTOS. El RTOS no puede utilizar un tiempo tan pequeño.

Así que quiero insertar algunas instrucciones de "ahorro de energía" en el ciclo de espera.

Por ejemplo:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
{
    __ASM("NOP");__ASM("NOP");__ASM("NOP");__ASM("NOP");
}

Pero NOP consume la misma cantidad de energía que cualquier otra instrucción que haya probado.

¿Qué instrucción puedo insertar en mi ciclo while que consuma la menor cantidad de energía?

¿Ha considerado deshacerse del RTOS?
Ojalá haya interpretado correctamente lo que OP ha querido preguntar.
Creo que @AleksiTorhamo tiene la respuesta correcta. Está sondeando cuándo debería estar durmiendo y usando interrupciones para ayudarse a despertarse. Esto reduciría el consumo de energía dinámico de su procesador.
¿Qué parte de este código proporciona una frecuencia de muestreo de 50 ms?

Respuestas (6)

Si desea ahorrar energía, ponga la MCU en reposo. Las instrucciones relevantes son WFI y WFE: espera por interrupción y espera por evento, respectivamente.

WFI se explica por sí mismo: se activa cuando recibe una interrupción. (¡Sin embargo, la interrupción debe estar habilitada!)

WFE podría merecer un poco más de explicación. Para usarlo, probablemente sea suficiente saber que si configura SEVONPEND, una interrupción que no está habilitada en el NVIC califica como un evento. Entonces, si habilita la interrupción de ADC en el periférico pero no en el NVIC, puede esperar a que se complete con WFE. Todavía use el bucle con la verificación de bandera, ya que puede haber otros eventos que despierten la MCU. (Simplemente reemplace los NOP con un WFE) Como de costumbre, para obtener información más detallada, consulte el manual de referencia.

Probablemente también desee seleccionar qué tan profundo desea ir al sueño, pero la forma en que se hace puede depender de la MCU STM32 específica que esté utilizando. Al menos en un modelo, las banderas relevantes eran PDDS, LPDS y SLEEPDEEP. Sin duda querrá leer la sección correspondiente del manual de referencia en cualquier caso.

Probablemente aún desee el bucle con WFI y WFE, en caso de que se habilite más de una interrupción.
@abligh ¡Muy cierto!
Y cuando pone la CPU en reposo, ¿el ADC continuará con la conversión? Sólo curioso...
@AliChen En general, eso dependerá del chip y de qué tan profundo sea el modo de suspensión que se seleccionó. En caso de duda, consulte el manual de referencia del chip que está utilizando. En todos los chips que recuerdo haber visto, el modo de suspensión más ligero detendrá el núcleo, pero mantendrá todos los periféricos en funcionamiento, a menos que indique lo contrario (por ejemplo, borrando el bit LPEN del periférico relevante). En los modos de suspensión más profundos, los periféricos generalmente también se detienen, pero todo depende del chip y el periférico específicos; Algunos periféricos en algunos chips también pueden seguir funcionando en modos de suspensión más profundos.
Esa es la pregunta. No en general, pero en este MCU muy particular. El OP no pregunta si dormir o no dormir durante 50 ms entre muestras. Su pregunta es si puede ahorrar algo más de energía durante 120 us de tiempo de conversión de ADC haciendo algo más que sondear su bandera de fin de conversión.
@AliChen Y la respuesta fue sí, si realmente se molestó en leer mi respuesta o comentario. Pero, como dije, dependerá de la MCU específica. Y el OP no mencionó una MCU específica (o "muy particular", como usted dice), a pesar de lo que afirma. Y sin conocer la MCU exacta, no puedo dar una respuesta exacta.
@AleksiTorhamo, entonces tal vez, tal vez, en lugar de dar una respuesta trivial y obvia, debería molestarse y hacerle a OP esta pregunta más importante, ¿continuará ADC la conversión si pone la MCU en reposo?

Intentemos responder la pregunta opuesta para explicar por qué NOPno ahorra energía. El Cortex-M3 es un procesador diseñado para ser pequeño y relativamente simple: no tiene muchos de los circuitos diseñados para realizar tareas dedicadas (cachés, coma flotante, predicción de bifurcaciones), o donde los tiene, son implementaciones limitadas a obtenga el mayor éxito al menor costo.

La mayoría de las instrucciones avanzan a través de la tubería de 3 etapas y realizan cantidades similares de trabajo. Obtención de instrucciones, decodificación y operación de ALU. Para aumentar la potencia, tal vez podríamos agregar una transferencia de datos (que enciende más lógica fuera del núcleo, pero lo más probable es que detenga toda la tubería ya que el núcleo está en orden). Tal vez podríamos usar la división de un solo ciclo justo después de hacer una transferencia de datos; allí posiblemente podría obtener dos partes adicionales de actividad al mismo tiempo. Sin embargo, tal vez hacer esto reducirá la actividad del archivo de registro, por lo que no todo ayuda a alcanzar la potencia máxima.

Aunque hay alguna variación de instrucción a instrucción (y una buena cantidad de esfuerzo de diseño para optimizar esto), la mayor parte de la potencia activa no depende demasiado de las instrucciones. Claro, llenar la tubería con varios NOPdetendrá cualquier actividad de alternar, pero la tubería aún avanza. Detener la tubería (para una transferencia de datos lenta) hará mucho más, pero el único estado bien definido en el que puede confiar para ser óptimo será WFIy los diversos estados de suspensión.

Los núcleos más grandes tendrán mucho más pico-a-media porque una mayor proporción de su silicio estará inactiva en un bucle inactivo previsto y precargado (y probablemente más otra lógica activa en el chip, que a menudo también puede ser controlada por reloj/energía). )

Por supuesto, hay muchos periféricos fuera de la CPU que también consumen energía en estos dispositivos, cada uno de los cuales tiene su propio control de reloj.

Si está satisfecho con las muestras cada 62,5 ms o 31,25 ms (en lugar de 50 ms), puede usar la función de alarma RTC para activar el STM32 y ponerlo en modo de espera/detenerse entre conversiones. Esto ahorrará energía de forma masiva, especialmente si configura el ADC para pasar al modo de bajo consumo después de la conversión (esto puede depender de la serie STM32). Si inicia una conversión, luego entra en modo de espera/parada, una vez que se despierte, la conversión se completará de todos modos. Esto agrega una latencia de una muestra y requiere que procese la muestra antes de iniciar una nueva muestra, pero dependiendo de su aplicación, esto puede ser factible.

Fluir:

Inicie la conversión ADC y habilite la alarma RTC

Entrar en modo de parada/modo de espera

Una vez que RTC haya despertado el microcontrolador, tome el valor de conversión de ADC

Procesar muestra (almacenar/filtrar, etc.)

¡Iniciar proceso de nuevo!

Los modos de parada y espera utilizan muy poca energía, por lo que dependiendo de su aplicación, este puede ser un método adecuado.

Buscaría usar un temporizador para iniciar la conversión y una interrupción para recopilar el resultado.

El núcleo de la CPU puede dormir hasta que los datos estén disponibles.

Como alternativa a dormir, es posible que pueda configurar el generador de reloj para que solo proporcione al núcleo uno de cada 2, 4, 8, etc. relojes que ingresan al chip. Si la CPU necesita realizar muchas operaciones que requieren seis ciclos de código, pero solo se puede activar una vez cada 64 ciclos debido a limitaciones de hardware externo, reducir la velocidad de la CPU a 1/8 puede ser justo lo que necesita. Si bien el uso de un modo inactivo con activación de interrupción puede ser mejor que dejar la CPU a toda velocidad, es posible que la CPU deba pasar muchos ciclos para cada evento configurando las transiciones inactiva/activada. Algunos controladores tienen opciones para establecer velocidades por separado para la línea principal versus los controladores de interrupción, de modo que incluso si la línea principal reduce la CPU a 1/8 de velocidad, los controladores de interrupción funcionarán a velocidad normal. Sin embargo, no creo que sea una característica muy común. De lo contrario, tú

  1. Configure un temporizador con un intervalo de 1/20 s para iniciar una conversión
  2. Habilite la interrupción ADC y maneje el resultado allí

O si un ligero jitter del reloj no es problema.

  1. Configure un temporizador FreeRTOS de 50 ms. son eficientes
  2. Habilite la interrupción ADC y maneje el resultado allí

De lo contrario, para poner la MCU en suspensión, simplemente coloque asm("WFI") en el bucle inactivo de FreeRTOS.

Tengo una situación similar, pero acabo de alinear todo con el temporizador de tic de 1 ms de FreeRTOS.