Le ESP32

En 2020, Espressif décline sa gamme de SoC ESP32 en 3 familles de produits.
L’ESP32-S2 est la nouvelle génération de SoC. Il est animé par un processeur Xtensa LX7 single-core 32-bit pouvant être cadencé jusqu’à 240MHz.
L’ESP32-SOLO-1 destiné à des applications nécessitant peu de puissance et sur batterie est toujours présent.
Enfin, la famille d’origine constituée des modèles WROOM et WROVER s’agrandie avec 4 nouvelles déclinaisons.
Au total, les fabricants pourront choisir parmi 21 modèles

WROVER Les modules WROVER sont équipés d’un mémoire PSRAM pour les applications nécessitant des traitements numériques lourds (vidéo, détection faciale, FFT…).
Les nouveaux ESP32-S2 Single Core disposent de 2MB de PSRAM, les modèles WROOM ne disposent pas de PSRAM.
Les modules ESP32 Dual Core passe à la V3 (ESP32-D0WD-V3) et proposent 4, 8 ou 16 MB de mémoire flash ainsi que 8MB de PSRAM pour les WROVER.
L’ESP32 dispose de quelques centaines de kilo-octets de RAM interne embarquée directement dans le SoC (SRAM).
Si cette quantité de RAM est insuffisante, par exemple pour des applications de traitement vidéo ou de traitement du signal (FFT…), il est possible d’exploiter de la RAM externe (la PSRAM) accessible via le bus SPI.
ESP8266 vs ESP32 L'ESP8266 offre un processeur 32 bit cadencé a 80 Mhz alors que l'ESP32 propose un double coeur 32 bit cadencé entre 160 et 240 Mhz.
L'ESP32 offre aussi en prime une connectivité bluetooth.
L'ESP32 est le successeur de l'ESP8266. Les specs des deux puces sont proches mais naturellement l'ESP32 est légerement supérieur avec son coeur en plus.
 ESP8266ESP32
DRAM96KB328k
Flash4MB4MB (suivant versions)
Frequence80Mhz160 a 240 Mhz
SRAM64KB520Kb
GPIO1736
Analog GPIO118

L'ESP32 comporte :

Jeu d'instructions du coprocesseur ESP32 ULP L'ESP32 possède 4 registres à usage général de 16 bits, R0, R1, R2, R3.
Il a également un registre de compteur de 8 bits (stage_cnt) qui peut être utilisé pour implémenter des boucles.
L'ESP32 peut accéder à 8ko de la région mémoire RTC_SLOW_MEM.
La mémoire est adressée en unités de 32 bits, il peut également accéder aux registres de périphériques dans les périphériques RTC_CNTL, RTC_IO et SENS.
Toutes les instructions sont de 32 bits. Les instructions de saut, les instructions ALU, le registre périphérique et les instructions d'accès à la mémoire sont exécutées en 1 cycle.
Les instructions qui fonctionnent avec des périphériques (TSENS, ADC, I²C) prennent un nombre variable de cycles, en fonction du fonctionnement du périphérique.

Remarque sur l'adressage

Les instructions JUMP, ST, LD de l'ESP32 qui prennent le registre comme argument (adresse de saut, adresse de base de stockage / chargement) s'attendent à ce que l'argument soit exprimé en mots de 32 bits.

Remarque sur le temps d'exécution des instructions

L'ESP32 est cadencé à partir de RTC_FAST_CLK, qui est normalement dérivé de l'oscillateur interne à 8 MHz.
Les applications qui ont besoin de connaître la fréquence d'horloge exacte peuvent la calibrer par rapport à l'horloge XTAL principale.

Les instructions arithmétiques et logiques
InstructionSyntaxeDescriptionExemple
AddADD Rdst,Rsrc1,Rsrc2
ADD Rdst,Rsrc1,imm
L'instruction ajoute un registre source à un autre registre source ou à une valeur signée de 16 bits et stocke le résultat dans le registre de destination.
1:ADD R1, R2, R3     ;R1 = R2 + R3
2:ADD R1, R2, 0x1234 ;R1 = R2 + 0x1234
3:.set value1, 0x03  ;constant value1=0x03
  ADD R1, R2, value1 ;R1 = R2 + value1
4:.global label      ;declaration of variable label
  ADD R1, R2, label  ;R1 = R2 + label
    ...              ;
  label: nop         ;definition of variable label
SubSUB Rdst,Rsrc1,Rsrc2
SUB Rdst,Rsrc1,imm
L'instruction soustrait le registre source d'un autre registre source ou soustrait une valeur signée 16 bits d'un registre source, et stocke le résultat dans le registre de destination.
1:SUB R1, R2, R3     ;R1 = R2 - R3
2:SUB R1, R2, 0x1234 ;R1 = R2 - 0x1234                ;
3:.set value1, 0x03  ;constant value1=0x03
  SUB R1, R2, value1 ;R1 = R2 - value1
4:.global label      ;declaration of variable label
  SUB R1, R2, label  ;R1 = R2 - label
             ....
  label:   nop       ;definition of variable label
AndAND Rdst,Rsrc1,Rsrc2
AND Rdst,Rsrc1,imm
L'instruction effectue un ET logique d'un registre source et d'un autre registre source ou d'une valeur signée 16 bits et stocke le résultat dans le registre de destination.
1:AND R1, R2, R3     ;R1 = R2 & R3
2:AND R1, R2, 0x1234 ;R1 = R2 & 0x1234
3:.set value1, 0x03  ;constant value1=0x03
  AND R1, R2, value1 ;R1 = R2 & value1
4:.global label      ;declaration of variable label
  AND R1, R2, label  ;R1 = R2 & label
             ....
  label:   nop       ;definition of variable label
OrOR Rdst,Rsrc1,Rsrc2
OR Rdst,Rsrc1,imm
L'instruction effectue un OU logique d'un registre source et d'un autre registre source ou d'une valeur signée 16 bits et stocke le résultat dans le registre de destination.
1: OR R1, R2, R3     ;R1 = R2 \| R3
2: OR R1, R2, 0x1234 ;R1 = R2 \| 0x1234
3: .set value1, 0x03 ;constant value1=0x03
   OR R1, R2, value1 ;R1 = R2 \| value1
4: .global label     ;declaration of variable label
   OR R1, R2, label  ;R1 = R2 \|label
   ....
  label:   nop       ;definition of variable label
LshLSH Rdst,Rsrc1,Rsrc2
LSH Rdst,Rsrc1,imm
L'instruction effectue un décalage logique vers la gauche du registre source vers le nombre de bits d'un autre registre source ou une valeur signée 16 bits et stocke le résultat dans le registre de destination.
1:LSH R1, R2, R3     ;R1 = R2 << R3
2:LSH R1, R2, 0x03   ;R1 = R2 << 0x03
3:.set value1, 0x03  ;constant value1=0x03
  LSH R1, R2, value1 ;R1 = R2 << value1
4:.global label      ;declaration of variable label
  LSH R1, R2, label  ;R1 = R2 << label
         ....
  label:   nop       ;definition of variable label
RshRSH Rdst,Rsrc1,Rsrc2
RSH Rdst,Rsrc1,imm
L'instruction effectue un décalage logique vers la droite du registre source vers le nombre de bits d'un autre registre source ou une valeur signée 16 bits et stocke le résultat dans le registre de destination.
1:RSH R1, R2, R3     ;R1 = R2 >> R3
2:RSH R1, R2, 0x03   ;R1 = R2 >> 0x03
3:.set value1, 0x03  ;constant value1=0x03
  RSH R1, R2, value1 ;R1 = R2 >> value1
4:.global label      ;declaration of variable label
  RSH R1, R2, label  ;R1 = R2 >> label
         ....
  label:   nop       ;definition of variable label
NopNOPAucune opération n'est effectuée. Seul le PC est incrémenté1:NOP

Pour l'ensemble des instructions arithmétiques et logiques, 2 cycles pour exécuter, 4 cycles pour récupérer l'instruction suivante.


Les instructions de mémoire
InstructionSyntaxeOpérandeDescriptionExemple
MoveMOVE Rdst,Rsrc
MOVE Rdst,imm
Rdst - Registre R [0..3]
Rsrc - Registre R [0..3]
Imm - valeur signée 16 bits
L'instruction se déplace vers la valeur du registre de destination à partir du registre source ou de la valeur signée 16 bits.
1:MOVE R1, R2       ;R1 = R2
2:MOVE R1, 0x03     ;R1 = 0x03
3:.set value1, 0x03 ;constant value1=0x03
  MOVE R1, value1   ;R1 = value1
4:.global label     ;declaration of label
  MOVE R1, label    ;R1 = address_of(label) / 4
  ...
  label:  nop       ;definition of label
ST ST Rsrc,Rdst,décalage Rsrc - R[0..3], contient la valeur 16 bits à stocker
Rdst - R[0..3], adresse de la destination, en mots de 32 bits
Décalage - valeur signée 10 bits, décalage en octets
L'instruction stocke la valeur 16 bits de Rsrc dans le demi-mot inférieur de la mémoire avec l'adresse Rdst+offset.
Le demi-mot supérieur est écrit avec le compteur de programme courant (PC), exprimé en mots, décalé vers la gauche de 5 bits
Mem[Rdst+offset/4]{31:0}={PC[10:0],5'b0,Rsrc[15:0]}
1:       ST  R1, R2, 0x12   ;MEM[R2+0x12] = R1
2:      .data               ;Data section definition
Addr1:  .word 123           ;Define label Addr1 16 bit
         .set offs, 0x00    ;Define constant offs
         .text              ;Text section definition
         MOVE R1, 1         ;R1 = 1
         MOVE R2, Addr1     ;R2 = Addr1
         ST   R1, R2, offs  ;MEM[R2+0] = R1
                            ;MEM[Addr1+0] will be 32'h600001
LD LD Rsrc,Rdst,décalage Rdst - R[0..3], destination
Rsrc - R[0..3], contient l'adresse de destination, en mots de 32 bits
Décalage - valeur signée 10 bits, décalage en octets
L'instruction charge le demi-mot inférieur de 16 bits de la mémoire avec l'adresse Rsrc+offset dans le registre de destination Rdst:
Rdst[15:0]=Mem[Rsrc+offset/4][15:0]
1:        LD  R1, R2, 0x12       ;R1 = MEM[R2+0x12]
2:        .data                  ;Data section definition
  Addr1:  .word     123          ;Define label Addr1 16 bit
          .set      offs, 0x00   ;Define constant offs
          .text                  ;Text section definition
          MOVE      R1, 1        ;R1 = 1
          MOVE      R2, Addr1    ;R2 = Addr1 / 4 
          ;(address of label is converted into words)
          LD        R1, R2, offs ;R1 = MEM[R2 +  0]
                                 ;R1 will be 123

Pour l'ensemble des instructions mémoire, 2 cycles pour exécuter, 4 cycles pour récupérer l'instruction suivante.


Les instructions de saut
InstructionSyntaxeOpérandeDescriptionExemple
JumpJUMP Rdst
JUMP ImmAddr
JUMP Rdst,Condition
JUMP ImmAddr, Condition
Rdst - Registre R [0..3] contenant l'adresse à laquelle sauter (exprimée en mots de 32 bits)
ImmAddr - adresse 13 bits (exprimée en octets), alignée sur 4 octets
Condition :
  • EQ - saute si le résultat de la dernière opération ALU était nul
  • OV - saute si la dernière ALU a défini un indicateur de débordement
L'instruction fait sauter à l'adresse spécifiée. Le saut peut être inconditionnel ou basé sur un indicateur ALU.
1:        JUMP    R1        
;Jump to address in R1 (address in R1 is in 32-bit words)
2:        JUMP    0x120, EQ 
;Jump to address 0x120 (in bytes) if ALU result is zero
3:        JUMP    label     
;Jump to label
          ...
  label:  nop               
  ;Definition of label
4:        .global label     
;Declaration of global label
          MOVE    R1, label 
;R1 = label (value loaded into R1 is in words)
          JUMP    R1
;Jump to label
          ... 
  label:  nop               
;Definition of label
JumprJUMPR Step,Threshold,Condition Step - décalage relatif par rapport à la position actuelle, en octets
Threshold - valeur de seuil pour l'état de la branche
Condition :
  • EQ (égal) - saute si valeur dans R0 == seuil
  • LT (inférieur à) - saut si valeur dans R0 <seuil
  • LE (inférieur ou égal) - saut si valeur dans R0 <= seuil
  • GT (supérieur à) - saut si valeur dans R0> seuil
  • GE (supérieur ou égal) - saut si valeur dans R0> = seuil
L'instruction fait un saut vers une adresse relative si la condition est vraie. La condition est le résultat de la comparaison de la valeur du registre R0 et de la valeur de seuil.
1:pos:    JUMPR       16, 20, GE
;Jump to address (position + 16 bytes) if value in R0 >= 20
2:        ;Down counting loop using R0 register
          MOVE        R0, 16       
          ; load 16 into R0
  label:  SUB         R0, R0, 1    
          ; R0--
          NOP
          ; do something
          JUMPR       label, 1, GE 
          ; jump to label if R0 >= 1
JumpsJUMPS Step,Threshold,Condition Step - décalage relatif par rapport à la position actuelle, en octets
Threshold - valeur de seuil pour l'état de la branche
Condition :
  • EQ (égal) - saute si valeur dans R0 == seuil
  • LT (inférieur à) - saut si valeur dans R0 <seuil
  • LE (inférieur ou égal) - saut si valeur dans R0 <= seuil
  • GT (supérieur à) - saut si valeur dans R0> seuil
  • GE (supérieur ou égal) - saut si valeur dans R0> = seuil
L'instruction fait un saut vers une adresse relative si la condition est vraie. La condition est le résultat de la comparaison de la valeur du registre de comptage et de la valeur de seuil.
1:pos:    JUMPS     16, 20, EQ     
; Jump to (position + 16 bytes) if stage_cnt == 20

2:        
;Up counting loop using stage count register
          STAGE_RST                  
          ;set stage_cnt to 0
  label:  STAGE_INC  1               
          ;stage_cnt++
          NOP                        
          ;do something
          JUMPS       label, 16, LT  
          ;jump to label if stage_cnt < 16
STAGE_RSTSTAGE_RST Pas d'opérandes L'instruction définit le registre de comptage d'étapes sur 0.
1:       STAGE_RST     
        ; Reset stage count register
STAGE_INC STAGE_INC Valeur Valeur - valeur 8 bits L'instruction incrémente le registre de comptage d'étages d'une valeur donnée.
1:        STAGE_INC      10          
;stage_cnt += 10
2:        
;Up counting loop example:
          STAGE_RST                  
          ;set stage_cnt to 0
  label:  STAGE_INC  1      
          ;stage_cnt++
          NOP
          ;do something
          JUMPS  label, 16, LT   
          ;jump to label if stage_cnt < 16
STAGE_DEC STAGE_DEC Valeur Valeur - valeur 8 bits L'instruction incrémente le registre de comptage d'étages d'une valeur donnée.
1:        STAGE_DEC      10          
;stage_cnt -= 10
2:        
;Up counting loop example:
          STAGE_RST                  
          ;set stage_cnt to 0
          STAGE_INC  16
          ;increment stage_cnt to 16
  label:  STAGE_DEC  1      
          ;stage_cnt--
          NOP
          ;do something
          JUMPS label, 0, GT  
          ;jump to label if stage_cnt > 0
HALT HALT Pas d'opérandes L'instruction arrête le coprocesseur ULP et redémarre le temporisateur de réveil ULP, s'il est activé.
1:       HALT  
        ;Halt the coprocessor
WAKE WAKE Pas d'opérandes L'instruction envoie une interruption de l'ULP au contrôleur RTC.
1: is_rdy_for_wakeup:
        ;Read RTC_CNTL_RDY_FOR_WAKEUP bit
        READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
        AND r0, r0, 1
        JUMP is_rdy_for_wakeup, eq    
;        Retry until the bit is set
        WAKE                          
;        Trigger wake up
        REG_WR 0x006, 24, 24, 0       
;        Stop ULP timer (clear RTC_CNTL_ULP_CP_SLP_TIMER_EN)
        HALT                          
;        Stop the ULP program
        ; After these instructions, SoC will wake up,
        ; and ULP will not run again until started by the main program.
SLEEPSLEEP sleep_reg sleep_reg -0..4, sélectionne l'un des registres SENS_ULP_CP_SLEEP_CYCx_REG L'instruction sélectionne laquelle des SENS_ULP_CP_SLEEP_CYCx_REG valeurs de registre (x = 0..4) doit être utilisée par le temporisateur de réveil ULP comme période de réveil.
Par défaut, la valeur de SENS_ULP_CP_SLEEP_CYC0_REG est utilisée.
1:SLEEP     1         
; Use period set in SENS_ULP_CP_SLEEP_CYC1_REG
2:.set sleep_reg, 4 
;   Set constant
  SLEEP  sleep_reg    
;Use period set in SENS_ULP_CP_SLEEP_CYC4_REG
WAITWAIT CyclesCycles - nombre de cycles d'attente L'instruction retarde pour un nombre donné de cycles.
1:        WAIT     10
    ;Do nothing for 10 cycles
2:        .set  wait_cnt, 10  
    ;Set a constant
          WAIT  wait_cnt
     ;wait for 10 cycles
TSENS TSENS Rdst, Wait_Delay Rdst - Registre de destination R[0..3], le résultat sera stocké dans ce registre
Wait_Delay - nombre de cycles utilisés pour effectuer la mesure
L'instruction effectue une mesure à l'aide de TSENS et stocke le résultat dans un registre à usage général.
1:        TSENS     R1, 1000 
  ;Measure temperature sensor for 1000 cycles,
  ;and store result to R1
ADC ADC Rdst, Sar_sel, MuxRdst - Registre de destination R[0..3], le résultat sera stocké dans ce registre
Sar_sel - Sélectionnez ADC: 0 = SARADC1, 1 = SARADC2
Mux - PAD sélectionné, le pad SARADC [Mux + 1] est activé
L'instruction effectue des mesures à partir de l'ADC.
1:        ADC      R1, 0, 1
; Measure value using ADC1 pad 2 
;and store result into R1
I2C_RD I2C_RD Sub_addr, High, Low, Slave_selSub_addr - Adresse dans l'esclave I2C à lire.
High , Low - Définit la plage de bits à lire. Les bits en dehors de la plage [High, Low] sont masqués.
Slave_sel - Index de l'adresse d'esclave I2C à utiliser.
I2C_RDl'instruction lit un octet de l'esclave I2C avec index Slave_sel.
L'adresse de l'esclave (au format 7 bits) doit être définie à l'avance dans le champ de registre SENS_I2C_SLAVE_ADDRx ,
où 8 bits de résultat de lecture sont stockés dans le registre R0 == Slave_sel
1:        I2C_RD      0x10, 7, 0, 0
;Read byte from sub-address 0x10 of slave 
;with address set in SENS_I2C_SLAVE_ADDR0
I2C_WR I2C_WR Sub_addr, Value, High, Low, Slave_selSub_addr - Adresse dans l'esclave I2C à lire.
Valeur - valeur 8 bits à écrire.
High , Low - Définit la plage de bits à lire. Les bits en dehors de la plage [High, Low] sont masqués.
Slave_sel - Index de l'adresse d'esclave I2C à utiliser.
I2C_WRL'instruction écrit un octet dans l'esclave I2C avec index Slave_sel.
L'adresse de l'esclave (au format 7 bits) doit être définie à l'avance dans le champ de registre SENS_I2C_SLAVE_ADDRx ,
où x == Slave_sel
1:        I2C_WR      0x20, 0x33, 7, 0, 1
; Write byte 0x33 to sub-address 0x20 of slave 
;with address set in SENS_I2C_SLAVE_ADDR1.
REG_RD REG_RD Addr , haut, basAddr - Adresse de registre, en mots de 32 bits
Haut - Numéro de bit de fin de registre
Low - Numéro de bit de démarrage du registre
L'instruction lit jusqu'à 16 bits à partir d' un registre périphérique dans un registre à usage général:
R0 = REG[Addr][High:Low]
1:        REG_RD      0x120, 7, 4
;load 4 bits: R0 = {12'b0, REG[0x120][7:4]}
REG_WR REG_WR Addr , haut, bas, DataAddr - Adresse de registre, en mots de 32 bits
Haut - Numéro de bit de fin de registre
Low - Numéro de bit de démarrage du registre
Data - Valeur à écrire, 8 bits
L'instruction écrit jusqu'à 8 bits à partir d' une valeur de données immédiates dans un registre périphérique:
REG[Addr][High:Low] = data
1:        REG_WR      0x120, 7, 0, 0x10
; set 8 bits: REG[0x120][7:0] = 0x10

Pour l'ensemble des instructions mémoire, 2 cycles pour exécuter, 2 cycles pour récupérer l'instruction suivante