Bei modernen 32-bit-MCUs haben Software-Entwickler viel Freiheit bei der Nutzung der Speicherblöcke. Die MCU bietet eine Mischung aus nichtflüchtigem Flash-Speicher für die Langzeit-Code- und Datenspeicherung. Hinzu kommt SRAM für temporäre Daten. Meist ist der Energieverbrauch beim Flash-Speicherzugriff höher als beim SRAM-Zugriff. Das Lesen aus dem Flash übertrifft das Lesen aus dem SRAM normalerweise um das Dreifache. Das Schreiben in den Flash erfordert das Löschen ganzer Blöcke und das erneute Beschreiben mit langen Sequenzen, was hohe Spannungspulse erfordert und mehr Energie verbraucht. Bei den meisten Anwendungen ist das Schreiben in den Flash jedoch unregelmäßig und beeinträchtigt den durchschnittlichen Energieverbrauch eher selten.
Ein weiterer Faktor beim Flash-Energieverbrauch ist die Verteilung der Zugriffe seitens des Prozessors. In jedem Flash-Speicherblock befinden sich mehrere Seiten (Pages), die bis zu 4 KB groß sein können. Um den Zugriff zu ermöglichen, muss jede Seite aktiviert werden; nicht genutzte Seiten können in einem Energiesparzustand verbleiben.
Wenn ein regelmäßig abgerufener Code-Bereich zwei Flash-Seiten umfasst anstatt nur einer, erhöht sich der Energieaufwand beim Lesen. Die Umverteilung von Speicher zur Platzierung regelmäßig abgerufener Code-Bereiche und Daten auf eigene (diskrete) Seiten kann den Energieverbrauch im Laufe der Zeit senken, ohne dabei die Hardware verändern zu müssen.
Meist ist es sinnvoll, Funktionen in das SRAM zu kopieren, wenn sie öfters benötigt werden. Die Funktionen werden dann von dort gelesen anstatt aus dem Flash.
Code-Optimierung
Energieoptimierung kann auch die Code-Effizienz betreffen. Seit Jahrzehnten konzentrieren sich Entwickler von Embedded-Systemen darauf, den Code hinsichtlich geringer Speichergröße zu optimieren, wenn es auf hohe Rechenleistung ankommt. Energieoptimierung bietet hier einen komplett neuen Ansatz. Dabei ist die Nutzung des On-Chip-Cache entscheidend, der mittlerweile in allen 32-bit-Plattformen vorhanden ist.
Eine Optimierung für Codegröße belässt mehr Funktionen im Cache, was die Geschwindigkeit erhöht und den Energieverbrauch senkt. Funktionsaufrufe und Verzweigungen, die zur Reduzierung der Applikationsgröße verwendet werden (durch Wiederverwendung gängigen Codes), können zu unbeabsichtigten Konflikten zwischen Codebereichen der gleichen Cache-Zeile sorgen. Dies kann zu sogenanntem „Cache Thrashing“ sowie zu vermehrtem Aktivieren von Flash Pages führen, wenn Befehle aus dem Hauptspeicher geholt werden müssen.
Da Code während der Lebensdauer eines Produkts regelmäßig überarbeitet wird, macht es Sinn, diesen kompakt genug zu erstellen, dass er in den Cache passt, aber keine Verzweigungen erzeugt oder Funktionen aufruft. Zurück zum Rauchmelder: Selbst wenn der Alarm einmal pro Woche ausgelöst wird (z.B. durch zu viel Rauch beim Kochen), sind das nur 520 Ereignisse von 315 Millionen während der 10-jährigen Lebensdauer des Rauchmelders. Die meiste Zeit veranlasst der Code nur eine Sensorwert-Erfassung. Dabei wird festgestellt, dass der Schwellenwert nicht überschritten ist; der Prozessor-Core wird in den Sleep-Zustand zurückgebracht, bis er über den System-Timer wieder aktiviert wird.
Aus allen Sensorablesungen, die ein Rauchmelder durchführt, führen weniger als 0,0002 % zur Ausführung des Alarm auslösenden Codes. Die restlichen 99,9998 % der Code-Ausführung decken die Sensorableseschleife ab. Entscheidend für einen minimalen Stromverbrauch ist dann, dass dieser Code direkt aus dem Cache betrieben werden kann. Da der übrige Code eher unregelmäßig läuft, lässt sich dieser mit herkömmlichen Techniken optimieren.