assemblyiotesp8266esp32esp8266wifi

Programming esp32 and esp8266


How do i program an ESP32 or an ESP8266 module using assembly? I don't want to use arduino ide. I figured a way to program atmel chips with assembly. I wanted to learn how to program esp32 and esp8266 in assembly.


Solution

  • The tools can be easily found. I installed a pre-built tarball.

    This is a mix of C and asm but you can do this all asm.

    This is for an esp8266.

    vectors.s

    .section .init
    .globl _start
    _start:
        call0 notmain
        ill
    .balign 0x100
    .globl dummy
    dummy:
        ret.n
        
    .balign 0x10
    .globl PUT32
    PUT32:
        memw
        s32i.n a3,a2,0
        ret.n
        
    .balign 0x10
    .globl GET32
    GET32:
        memw
        l32i.n a2,a2,0
        ret.n
    

    so.c

    #define GPIO_ENSET      0x60000310
    #define GPIO_OUTSET     0x60000304
    #define GPIO_OUTCLR     0x60000308
    #define IOMUX_GPIO2     0x60000838
    
    void dummy ( unsigned int );
    void PUT32 ( unsigned int, unsigned int );
    unsigned GET32 ( unsigned int );
    void notmain ( void )
    {
        unsigned int ra;
        unsigned int rx;
        ra=GET32(IOMUX_GPIO2);
        ra&=(~0x130);
        PUT32(IOMUX_GPIO2,ra);
        PUT32(GPIO_ENSET,1<<2);
        while(1)
        {
            PUT32(GPIO_OUTSET,1<<2);
            for(rx=0;rx<800000;rx++) dummy(rx);
            PUT32(GPIO_OUTCLR,1<<2);
            for(rx=0;rx<800000;rx++) dummy(rx);
        }
    }
    

    so.ld

    MEMORY
    {
        bob : ORIGIN = 0x40100000, LENGTH = 0x1000
        ted : ORIGIN = 0x3FFE8000, LENGTH = 0x1000
    }
    SECTIONS
    {
        .init : { *(.init*) } > bob
        .literal : { *(.literal*) } > bob
        .text : { *(.text*) } > bob
        .rodata : { *(.rodata*) } > bob
        .data : { *(.data*) } > ted
        .bss : { *(.bss*) } > ted
    }
    

    build

    xtensa-lx106-elf-as --warn --fatal-warnings vectors.s -o vectors.o
    xtensa-lx106-elf-gcc -Wall -O2 -ffreestanding -c so.c -o so.o
    xtensa-lx106-elf-ld -nostdlib -nostartfiles -T so.ld vectors.o so.o -o so.elf
    xtensa-lx106-elf-objdump -D so.elf > so.list
    xtensa-lx106-elf-objcopy so.elf so.bin -O binary
    

    disassembly

    Disassembly of section .init:
    
    40100000 <_start>:
    40100000:   001385          call0   4010013c <notmain>
        ...
    
    40100100 <dummy>:
    40100100:   f00d        ret.n
        ...
    
    40100110 <PUT32>:
    40100110:   0020c0          memw
    40100113:   0239        s32i.n  a3, a2, 0
    40100115:   f00d        ret.n
        ...
    
    40100120 <GET32>:
    40100120:   0020c0          memw
    40100123:   0228        l32i.n  a2, a2, 0
    40100125:   f00d        ret.n
    
    Disassembly of section .literal:
    
    40100128 <.literal>:
    40100128:   0838        l32i.n  a3, a8, 0
    4010012a:   106000          and a6, a0, a0
    4010012d:   03              .byte 0x3
    4010012e:   046000          extui   a6, a0, 0, 1
    40100131:   03              .byte 0x3
    40100132:   006000          rsil    a0, 0
    40100135:   35              .byte 0x35
    40100136:   000c        movi.n  a0, 0
    40100138:   0308        l32i.n  a0, a3, 0
    4010013a:   00              .byte 00
    4010013b:   60              .byte 0x60
    
    Disassembly of section .text:
    
    4010013c <notmain>:
    4010013c:   e0c112          addi    a1, a1, -32
    4010013f:   61c9        s32i.n  a12, a1, 24
    40100141:   fff9c1          l32r    a12, 40100128 <GET32+0x8>
    40100144:   7109        s32i.n  a0, a1, 28
    40100146:   0c2d        mov.n   a2, a12
    40100148:   51d9        s32i.n  a13, a1, 20
    4010014a:   41e9        s32i.n  a14, a1, 16
    4010014c:   31f9        s32i.n  a15, a1, 12
    4010014e:   fffd05          call0   40100120 <GET32>
    40100151:   cfae32          movi    a3, 0xfffffecf
    40100154:   103230          and a3, a2, a3
    40100157:   0c2d        mov.n   a2, a12
    40100159:   fffb45          call0   40100110 <PUT32>
    4010015c:   fff421          l32r    a2, 4010012c <GET32+0xc>
    4010015f:   430c        movi.n  a3, 4
    40100161:   fffac5          call0   40100110 <PUT32>
    40100164:   fff3f1          l32r    a15, 40100130 <GET32+0x10>
    40100167:   fff3d1          l32r    a13, 40100134 <GET32+0x14>
    4010016a:   fff3e1          l32r    a14, 40100138 <GET32+0x18>
    4010016d:   430c        movi.n  a3, 4
    4010016f:   0f2d        mov.n   a2, a15
    40100171:   fff9c5          call0   40100110 <PUT32>
    40100174:   0c0c        movi.n  a12, 0
    40100176:   0c2d        mov.n   a2, a12
    40100178:   cc1b        addi.n  a12, a12, 1
    4010017a:   fff845          call0   40100100 <dummy>
    4010017d:   f59cd7          bne a12, a13, 40100176 <notmain+0x3a>
    40100180:   430c        movi.n  a3, 4
    40100182:   202ee0          or  a2, a14, a14
    40100185:   fff885          call0   40100110 <PUT32>
    40100188:   0c0c        movi.n  a12, 0
    4010018a:   0c2d        mov.n   a2, a12
    4010018c:   cc1b        addi.n  a12, a12, 1
    4010018e:   fff705          call0   40100100 <dummy>
    40100191:   f59cd7          bne a12, a13, 4010018a <notmain+0x4e>
    40100194:   fff546          j   4010016d <notmain+0x31>
    

    And then due to how this was done, you can't use esptool.py to prep the file, so I made my own, taking the output here:

    hexdump -C so.bin 
    00000000  85 13 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    *
    00000100  0d f0 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    00000110  c0 20 00 39 02 0d f0 00  00 00 00 00 00 00 00 00  |. .9............|
    00000120  c0 20 00 28 02 0d f0 00  38 08 00 60 10 03 00 60  |. .(....8..`...`|
    00000130  04 03 00 60 00 35 0c 00  08 03 00 60 12 c1 e0 c9  |...`.5.....`....|
    00000140  61 c1 f9 ff 09 71 2d 0c  d9 51 e9 41 f9 31 05 fd  |a....q-..Q.A.1..|
    00000150  ff 32 ae cf 30 32 10 2d  0c 45 fb ff 21 f4 ff 0c  |.2..02.-.E..!...|
    00000160  43 c5 fa ff f1 f3 ff d1  f3 ff e1 f3 ff 0c 43 2d  |C.............C-|
    00000170  0f c5 f9 ff 0c 0c 2d 0c  1b cc 45 f8 ff d7 9c f5  |......-...E.....|
    00000180  0c 43 e0 2e 20 85 f8 ff  0c 0c 2d 0c 1b cc 05 f7  |.C.. .....-.....|
    00000190  ff d7 9c f5 46 f5 ff                              |....F..|
    00000197
    

    turning it into this

    hexdump -C so.esp.bin 
    00000000  e9 01 00 00 00 00 10 40  00 00 10 40 98 01 00 00  |.......@...@....|
    00000010  85 13 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    *
    00000110  0d f0 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    00000120  c0 20 00 39 02 0d f0 00  00 00 00 00 00 00 00 00  |. .9............|
    00000130  c0 20 00 28 02 0d f0 00  38 08 00 60 10 03 00 60  |. .(....8..`...`|
    00000140  04 03 00 60 00 35 0c 00  08 03 00 60 12 c1 e0 c9  |...`.5.....`....|
    00000150  61 c1 f9 ff 09 71 2d 0c  d9 51 e9 41 f9 31 05 fd  |a....q-..Q.A.1..|
    00000160  ff 32 ae cf 30 32 10 2d  0c 45 fb ff 21 f4 ff 0c  |.2..02.-.E..!...|
    00000170  43 c5 fa ff f1 f3 ff d1  f3 ff e1 f3 ff 0c 43 2d  |C.............C-|
    00000180  0f c5 f9 ff 0c 0c 2d 0c  1b cc 45 f8 ff d7 9c f5  |......-...E.....|
    00000190  0c 43 e0 2e 20 85 f8 ff  0c 0c 2d 0c 1b cc 05 f7  |.C.. .....-.....|
    000001a0  ff d7 9c f5 46 f5 ff 00  00 00 00 00 00 00 00 ae  |....F...........|
    000001b0
    

    I will let you figure that out, tool sources are available.

    https://github.com/espressif/esptool

    If this link stops working then search for "esptool.py" to hopefully find one.

    Then flash it:

    esptool.py --port /dev/ttyUSB5 write_flash -fm qio 0x00000 so.esp.bin
    

    I am using a cheap nodemcu clone. I bought 5 of them for $15 on Amazon. Don't need extra wires/usb-uart, etc.

    Changing these

    for(rx=0;rx<800000;rx++)
    

    to/from

    for(rx=0;rx<400000;rx++)
    

    and see the led blink rate change.

    You can easily write this in only assembly by poking the few registers yourself.