08.05.2018 Views

Elektor Electronics 2018 03 04

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

On trouve ici deux particularités importantes. D’abord la section<br />

(vide ici) .bss, dont l’absence fait que, même si le processeur<br />

ULP trouve le fichier, il refuse sans commentaire de l’exécuter.<br />

Ensuite, nous avons une séquence qui crée une variable globale<br />

partagée entre l’ULP et Xtensa. Nous pouvons alors poursuivre<br />

avec le code effectif :<br />

entry:<br />

/* Code goes into .text section */<br />

.text<br />

.global entry<br />

move r3, acti_count<br />

ld r0, r3, 0<br />

add r0, r0, 1<br />

st r0, r3, 0<br />

Les processeurs ULP sont des machines à 16 bits. À la<br />

lecture, une partie du registre n’est pas prise en compte. Pour<br />

commencer, nous décalons l’adresse de acti_count dans le<br />

demi-registre R3, que nous utilisons pour lire la valeur. Celle-ci<br />

est incrémentée avec add et réécrite dans acti-count.<br />

Pour finir, nous réveillons le côté Xtensa. Ici, nous avons une<br />

petite diffculté : les commandes de réveil ne sont acceptées<br />

qu’une fois que le noyau a été arrêté avec succès. C’est pourquoi<br />

notre code n’exécute wake que lorsque le SOC (système sur<br />

puce) a confirmé sa mise en sommeil dans le registre concerné :<br />

de l’ULP du côté C.<br />

Ici, la situation exige une réflexion approfondie. La partie<br />

Xtensa du microcontrôleur contient une quantité de registres<br />

dont la préservation du contenu exige une dépense d’énergie<br />

considérable. Pour minimiser cette dépense, Espressif coupe<br />

l’alimentation des registres, ce qui entraîne malheureusement la<br />

perte de leur contenu. La première action de notre programme<br />

est donc de déterminer la cause du réveil :<br />

void app_main() {<br />

//Init check<br />

esp_sleep_wakeup_cause_t cause =<br />

esp_sleep_get_wakeup_cause();<br />

if (cause != ESP_SLEEP_WAKEUP_ULP) {<br />

printf("Clean boot\n");<br />

init_ulp_program();<br />

} else {<br />

printf("Start caused by ULP\n");<br />

printf("Counter %u \n", ulp_acti_count &<br />

UINT16_MAX);<br />

}<br />

Il est important ici de masquer le contenu de ulp_acti_<br />

count qui, comme tous les registres de Xtensa, a une largeur<br />

de 32 bits. Comme l’ULP ne peut écrire que dans les seize<br />

premiers, il faut masquer le reste qui est « indéfini ».<br />

exit:<br />

halt<br />

/* Check if the SoC has said INRI already */<br />

READ_RTC_REG(RTC_CNTL_DIAG0_REG, 19, 1)<br />

and r0, r0, 1<br />

jump exit, eq<br />

wake<br />

WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_<br />

ULP_CP_SLP_TIMER_EN, 0)<br />

halt<br />

halt<br />

Côté C<br />

Ensuite, nous retournons au programme hello_world_main.c<br />

dans lequel nous incluons quelques fichiers d’en-tête :<br />

#include "esp_sleep.h"<br />

#include "nvs.h"<br />

#include "nvs_flash.h"<br />

#include "soc/rtc_cntl_reg.h"<br />

#include "soc/rtc_io_reg.h"<br />

#include "soc/sens_reg.h"<br />

#include "soc/soc.h"<br />

#include "driver/gpio.h"<br />

#include "driver/rtc_io.h"<br />

#include "esp32/ulp.h"<br />

#include "ulp_main.h"<br />

ulp_main est créé par Makefile : le fichier prépare les contenus<br />

nécessaires au traitement ou au dialogue avec le programme<br />

Trop compliqué !<br />

Si l’on rechigne à travailler au niveau de make (ou si l’on a<br />

affaire à de très vieux exemples de code), on peut utiliser les<br />

macros (mais elles ont depuis été abandonnées par Espressif).<br />

Dans ce cas, un programme ULP est produit à partir d’un<br />

tableau d’instructions :<br />

const ulp_insn_t program[] = {<br />

I_MOVI(R3, 16),<br />

I_LD(R0, R3, 0),<br />

I_LD(R1, R3, 1),<br />

I_ADDR(R2, R0, R1),<br />

I_ST(R2, R3, 2),<br />

I_HALT()<br />

};<br />

La suite est constituée d’une séquence de code C plus ou<br />

moins standard qui calcule la taille du programme en instructions<br />

et fournit le résultat pour exécution. Il faut prendre<br />

garde à toujours faire le calcul de size comme indiqué cidessous<br />

– certaines macros sont interprétées par deux instructions<br />

séparées :<br />

size_t load_addr = 0;<br />

size_t size = sizeof(program)/sizeof(ulp_insn_t);<br />

ulp_process_macros_and_load(load_addr, program,<br />

&size);<br />

ulp_run(load_addr);<br />

www.elektormagazine.fr mars/avril <strong>2018</strong> 35

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!