Herman Roebbers werkt sinds het midden van de jaren tachtig aan embedded systemen en parallel rekenen. Hij heeft een tweedaagse workshop ontwikkeld over het begrijpen en verminderen van energiegebruik van embedded systemen. Achtergrondkennis wordt hier gecombineerd met hands-on sessies om de inzichten op echte hardware te valideren en te experimenteren. Deze workshop wordt door Altran en via The High Tech Institute en T2prof gegeven.

27 October 2015

De laatste jaren is er steeds meer behoefte om zuiniger om te springen met energie. In dit artikel gaat Herman Roebbers van Altran in op de achtergronden van energieverbruik in embedded systemen en hoe we dat kunnen verminderen.

Een van de belangrijke trends binnen de elektronica van de afgelopen jaren is om steeds zuiniger om te gaan met energie. Enerzijds wordt dit gestuurd vanuit overheden (bijvoorbeeld met Energystar), anderzijds vanuit de behoefte om meer te doen met dezelfde of kleinere hoeveelheid energie (denk aan de accuduur van mobiele telefoons en de batterijlevensduur van een iot-knooppunt). Het belang van energiezuinigheid wordt ook geïllustreerd door het feit dat chipfabrikanten heel veel reclame maken met hun zuinige chips. Er is zelfs een standaardmaat voor zuinigheid van ingebedde processoren: de Eembc Ulpbench.

Het is belangrijk om in te zien dat het energieverbruik een systeemzaak is. En een zaak van afwegen en compromissen sluiten. Energieverbruik kan door software worden teruggedrongen, maar de grens van wat haalbaar is, wordt uiteindelijk bepaald door de hardware. Het is daarmee ook een multidisciplinaire aangelegenheid, waarbij zowel de softwarediscipline als de hardwarediscipline bij het ontwerp betrokken moeten worden (zie tabel).

Architectuurniveau Mechanisme Domein
Stroombeheer werkt op al deze niveaus Applicatie Geen busy waiting, gebeurtenisgestuurd, gebruik dma, hardware-eventmechanisme, enzovoorts Software
Besturingssysteem Power-api, operation performance points-api
Driver Suspend/resume-api
Bord Dynamic voltage en frequency scaling, power gating via i/o-pin, controlling voltage regulator via i/o of I2C Software/hardware
Chip Power gating, clock gating, klokfrequentiebeheer
Dynamic power switching, adaptive voltage scaling, static leakage management Hardware
Ip-blok/chip Power gating state retention Hardware
Ip-blok/rtl Automatische power/clock gating
Transistor Body bias

De maatregelen om energie te sparen, zullen ook per type systeem verschillen. In de wereld van het iot wordt vooral gezocht naar manieren om de radio, de belangrijkste verbruiker in een systeem, zo kort mogelijk aan te zetten. Dit leidt tot niet-standaard protocollen die veel zuiniger kunnen zijn dan de gebruikelijke technologieën. Onder meer bij het Holst Centre wordt daar onderzoek naar gedaan.

In dit artikel richten we ons op kleinere embedded systemen zoals sensorknooppunten. Karakteristiek hiervoor is dat deze een groot deel van de tijd in slaap zijn. Afhankelijk van de functionaliteit die tijdens slaap nog actief moet zijn, kunnen ze in meer of minder diepe slaap worden gebracht.

 advertorial 

Live Q&A with ASML during the online Software-Centric Systems Conference

Next week, on 5 November 2020, the Software-Centric Systems Conference will take place as a virtual event. Wei Li (ASML) will end the day with a live Q&A about “Software in accelerating technology adoption in the semiconductor industry”. With your online ticket, you will have access to the livestream and the on-demand videos. Register now!

Timer-tik

Om iets zinnigs met het energieverbruik te kunnen doen, moeten we het eerst kunnen meten. Hiervoor kunnen we simultaan stroom en spanning bepalen en het product uitrekenen. Vermenigvuldigd met de duur van het meetinterval krijgen we de geconsumeerde energie.

Daarbij moet echter wel worden aangenomen dat beide waarden niet veranderen tussen metingen door. Dat gaat lang niet altijd op. Daarom kunnen we ook direct de hoeveelheid lading meten die de applicatie consumeert. In het geval van ultra-low power ligt het minimale stroomverbruik in de orde van nanoampères, terwijl het gebruik in volle actie gemakkelijk in de tientallen milliampères kan lopen. Een bruikbaar meetsysteem moet dus een groot dynamisch bereik combineren met een nauwkeurigheid van rond de twee procent en een samplefrequentie van enige kilohertz. Hiervoor zijn verschillende oplossingen beschikbaar, sommige heel goedkoop en sommige behoorlijk prijzig.

In het ideale geval zetten we het systeem gebeurtenisgestuurd op. Dat wil zeggen dat we alleen iets doen als daar aanleiding toe is en voor de rest van de tijd zo diep slapen als praktisch mogelijk is – wat niet per se hetzelfde is als zo diep mogelijk slapen. Meestal is het namelijk zo dat diepere slaap gepaard gaat met langere tijden om weer goed wakker te worden, dus hoe díép we kunnen slapen wordt mede bepaald door hoe láng we kunnen slapen. Dit is overigens weer sterk afhankelijk van hoe goed de fabrikant zijn best heeft gedaan om snel wakker te kunnen worden. De tijd benodigd voor ontwaken kan variëren van enkele micro- tot honderden milliseconden.

In de praktijk wordt software voor kleine systemen doorgaans zonder besturingssysteem, direct op de hardware geschreven. Dit is vaak een hoofdlus die eindeloos wordt doorlopen. We kunnen soms al heel eenvoudig tientallen procenten besparen door een tijdje te gaan slapen tussen de iteraties. Dit kan bijvoorbeeld door een timer te zetten aan het einde van de lus en de cpu te laten slapen tot de timer afloopt.

Wanneer er wel een besturingssysteem in het spel is, werkt die meestal met een zogenaamde timer-tik. Het os kijkt elk interval van deze tik of er een andere taak dan de huidige actief moet worden. Een standaard waarde voor bijvoorbeeld Linux is tien milliseconden. De timer tikt echter ook als het systeem niets te doen heeft. Bij opensource besturingssystemen zoals Freertos of Linux kunnen we daarom al heel simpel besparen door het systeem te compileren met een configuratieoptie die de standaard timer-tik met idle-taak vervangt door een getimede slaapopdracht totdat de volgende timer afloopt (voor Freertos is dat configUSE_TICKLESS_IDLE; voor Linux is dat CONFIG_NO_HZ_IDLE voor kernelversie > 3.10 – daar staat het al standaard zo ingesteld – of CONFIG_NO_HZ in oudere kernels – niet standaard actief).

In het algemeen geldt: hoe nieuwer de processorarchitectuur of de productfamilie, hoe meer mogelijkheden er zijn om energie te sparen. Soms zijn er wel tientallen slaapmodi, waardoor we de draad kunnen kwijtraken. Maar in grote lijnen geldt dat we het beste de mogelijkheden kunnen benutten die de hardware biedt.

In stapjes

In den beginne (fase 1) was er in een systeem één baas over de bus: de cpu. Dat was de enige die toegang had tot het geheugen of de randapparaten. Om te zien of een gebeurtenis is opgetreden, is er een simpel programmalusje:

while (! gebeurtenis_opgetreden()) {
  /* afvragen, actief wachten, niet efficiënt */
}

Dit stukje code houdt de cpu bezig, evenals het codegeheugen. Deze dragen beide significant bij aan het energieverbruik, helemaal wanneer de code in flashgeheugen ligt (en niet wordt gecachet).

Fase 2 is de introductie van dma (direct memory access, rechtstreekse geheugentoegang). Nu hebben we twee busmasters: de dma-eenheid kan zelfstandig een geheugen- of randapparaattoegang realiseren (wel nadat de cpu de dma-eenheid heeft geprogrammeerd). Beide busmasters hebben nooit tegelijk toegang tot de bus om conflicten te voorkomen. De cpu programmeert de dma-eenheid om een aantal transacties tussen geheugen en randapparaat te doen, of tussen geheugenlocaties onderling. Als de transactie is afgewikkeld, wordt een interrupt gegenereerd voor de cpu. De cpu kan zich in de tussentijd met andere dingen bezighouden. Hij kan bijvoorbeeld de status van de variabele controleren in de interruptroutine om te zien of de transactie is afgerond. Hier is de pseudocode van de completion-interrupt:

void ISR_dma_klaar(void) {
  ... /* clear interruptbron */
  klaar = 1;
}

Het hoofdprogramma:

klaar = 0;
stel_peripherals_en_dma_in()
while (! klaar) {
  __delay_cycles(CHECK_INTERVAL); /* gaat niet naar de bus */
}

Hier vragen we weer een variabele op, maar niet continu. De __delay_cycles()-functie voert nop-instructies uit gedurende CHECK_INTERVAL. Dit houdt de databus vrij zodat de dma-eenheid geen last heeft van de cpu. De cpu blijft nog wel instructies uit het geheugen lezen.

Een relatief recente mogelijkheid van cpu’s is het stoppen van de klok totdat een interrupt optreedt. Dit vereist ondersteuning door de cpu in de vorm van een speciale instructie die meestal wfi heet (wait for interrupt). De bijbehorende code van het hoofdprogramma (de interruptroutine blijft hetzelfde):

klaar = 0;
stel_peripherals_en_dma_in();
while (! klaar) {
  wait_for_interrupt(); /* speciale instructie, cpu slaapt */
  /* gaat hier verder nadat interruptroutine is uitgevoerd */
}

In dit geval is de cpu gestopt totdat de interrupt optreedt. Dit bespaart op twee manieren energie: de cpu verstookt geen energie meer en er worden geen instructies meer uit het codegeheugen gelezen. De meeste nieuwe cpu’s kennen dit trucje inmiddels.

Nog wat nieuwer is de mogelijkheid om de cpu op een gebeurtenis (event) te laten wachten. Dit is vergelijkbaar met wait for interrupt, maar in dit geval is het uitvoeren van een interruptroutine niet nodig om de cpu weer te starten. Het feit dat een interrupt actief wordt, is een gebeurtenis op zich, ook al is de bijbehorende interrupt gemaskeerd.

In combinatie met een mechanisme om hardwaregebeurtenissen te laten genereren van randapparaat naar randapparaat kan een hele serie activiteiten zonder tussenkomst van de cpu door hardware worden afgewikkeld. Diverse fabrikanten hanteren verschillende namen voor een dergelijk mechanisme (event router, Peripheral Reflex System). Onder meer Arm Cortex-cpu’s bieden een wfe-instructie (wait for event) aan.

Figuur 1: Bij het hoog worden van een gpio-pin start automatisch een ad-conversie, waarna onder dma het resultaat naar het geheugen wordt geschreven en vervolgens na een vast aantal metingen een seintje naar de cpu gaat om de verzamelde data te gaan afhandelen.

Figuur 1 geeft aan hoe een dergelijke infrastructuur kan worden gebruikt om automatisch bij het hoog worden van een gpio-pin een ad-conversie te starten, na conversie onder dma het resultaat naar het geheugen te schrijven en na een vast aantal metingen een seintje naar de cpu te sturen om de verzamelde data te gaan afhandelen. De cpu programmeert de dma-eenheid, de relaties tussen producenten en consumenten van gebeurtenissen, en de afhandeling van de dma_klaar-gebeurtenis alvorens te gaan slapen of iets anders te gaan doen:

stel_peripherals_en_dma_in {
  Programmeer dma-eenheid voor transfer van adc-resultaatregister naar geheugen
  Laat opgaande flank op gio een signaal produceren
  Zorg dat start van ad-conversie dit signaal consumeert
  Laat afronden van ad-conversie een signaal consumeren
  Zorg dat de dma-trigger dit signaal consumeert (lees adc-resultaat en schrijf dit in het geheugen)
  Laat afronden van dma-transfer een dma_klaar-signaal genereren voor de cpu
}
start dma-transfer
wait_for_event(); /* cpu slaapt, lower power mode */

Ten opzichte van de vorige methode heeft deze het extra voordeel dat er geen overhead is van het uitvoeren van een of meer interruptroutines. Daardoor kan de cpu ook sneller op de gebeurtenis reageren dan via een interrupt (hoewel dat meestal geen probleem is).

Figuur 2: De energy control unit beheert autonoom de overgangen tussen de verschillende energietoestanden.

Als laatste infrastructurele voorziening is er nog de energy control unit, die autonoom de overgangen tussen de verschillende energietoestanden beheert (Figuur 2). Dit is een uitbreiding op de vorige situatie, die nóg meer energie kan sparen. De energiebesturingseenheid kan (afhankelijk van de uitvoering) autonoom allerlei energiegerelateerde huishouding doen: omzetten van pintoestanden en uitgangswaardes als functie van energiemodus, automatisch beheer van klokken naar peripherals, automatische power gating van randapparaten op basis van databeschikbaarheid, enzovoorts. Sommige van deze zaken, zoals het herprogrammeren van pinnen, zouden ook met software gerealiseerd kunnen worden, maar andere zijn alleen via hardware te bereiken. Mits goed ingesteld, zorgt deze eenheid ervoor dat het systeem naar een diepere slaaptoestand kan tijdens het wachten.

stel_hardware_in_op_genereren_van_gebeurtenissen();
configureer_energiehuishouding_tijdens_wachten(); /* dit is het extraatje*/
start dma-transfer
wait_for_event(); /* cpu slaapt, lower power mode */

We sparen energie, want de cpu gebruikt geen energie meer, we hebben ook geen geheugentoegang meer nodig om instructies op te halen en we hebben geen interruptoverhead meer. Hierdoor kunnen we het systeem zo diep in slaap brengen als de gebruikte randapparaten toelaten. We kunnen in deze toestand soms duizenden malen minder energie verbruiken dan met de cpu aan.

Conclusie moet zijn dat we pas echt energie kunnen besparen als we al deze mogelijkheden ook in onze software benutten. We kunnen dat in stapjes doen in de volgorde waarin deze mogelijkheden zijn genoemd; het hoeft niet allemaal in één keer.

Uiteenlopende karakteristieken

Er zijn nog veel meer factoren die in meer of mindere mate invloed kunnen hebben op het energieverbruik. Ik noem er een paar: uitschakelen van ongebruikte randapparaten, klokken/oscillatoren en geheugenbanken (flash/sram/dram/fram), tijdens slaap overschakelen naar een laagfrequente oscillator (32 kHz), rekenwerk en communicatie op een zo hoog mogelijke frequentie uitvoeren (meestal, dit hangt af van de relatie tussen frequentie en energieverbruik) en de instellingen van i/o-pinnen (vooral van niet-aangesloten pinnen) kunnen aan de hardwarekant meespelen.

Hoe lang het systeem met beperkte energie kan functioneren, is ook afhankelijk van de eigenschappen van de batterij of energieoogster. Verschillende batterijtypes reageren duidelijk anders op uiteenlopende karakteristieken van de belasting. We kunnen deze wetenschap gebruiken om onze activiteiten anders te verdelen in de tijd of een ander batterijtype te kiezen. Een aantal fabrikanten levert simulators die bij een gekozen batterijtype en energieverbruiksprofiel kunnen vertellen hoe lang de batterij meegaat.

Ook aan de softwarekant is er nog veel meer te bereiken. Voor het schrijven van nieuwe software zijn er allerlei technieken om rekening te houden met energieverbruik. Daarnaast kunnen we kritieke of vaak gebruikte data of code in een zuiniger type geheugen plaatsen. En de keuze en instellingen van een compiler kunnen tientallen procenten schelen.

Kortom: met relatief eenvoudige maatregelen is het energieverbruik van een embedded systeem vaak al heel aardig in te dammen. Voor echte ultra-low power is echter een goed begrip van het totale systeem een vereiste.

Edited by Pieter Edelman