ESP32 and MicroPython

Nick Moore
@mnemote

ESP32

original image: aliexpress.com

original image: zeptobars.com

original image: zeptobars.com

original image: zeptobars.com

Originally the ESP8266 came to prominence as a WiFi controller for AVR and similar, but ...

ArduinoESP8266RPi 2
AVR
ATMega328P
Tensilica
Xtensa LX106
ARM
Cortex A53
8 bit32 bit32 bit
1 core1 core4 core
20 MHz80-160 MHz900 MHz
2 KB RAM160 KB RAM1 GB RAM
32 KB Flash4 MB FlashMicroSDHC

New: ESP32

ArduinoESP8266ESP32RPi 2
AVR
ATMega328P
Tensilica
Xtensa LX106
Tensilica
Xtensa LX6
ARM
Cortex A53
8 bit32 bit32 bit32 bit
1 core1 core2 core4 core
20 MHz80-160 MHz240 MHz900 MHz
2 KB RAM160 KB RAM520 KB RAM1 GB RAM
32 KB Flash4 MB Flash16 MB FlashMicroSDHC

ESP32 Features

ESP32 Modules

WROOM-32 or ESP-32S

original image: espressif.com

ESP32 Boards

Sparkfun ESP32 Thing / ESP32-DevKitC / AdaFruit HUZZAH32

original images: sparkfun.com and espressif.com and adafruit.com

Programming the ESP32

esptool

github: espressif/esptool

$ git clone https://github.com/espressif/esptool.git
$ cd esptool
$ python setup.py install

pypi and ubuntu repositories are not up to date here ...

ESP-IDF

github: espressif/esp-idf

IoT Development Framework

C SDK for building programs to run on ESP32

Contains LWIP, examples, instructions for building toolchain

$ git clone --recursive https://github.com/espressif/esp-idf.git

MicroPython

micropython.org

MicroPython

MicroPython Platforms

For more background, see
Damien's talk about the Kickstarter campaign
from PyConAU 2016

Development of esp32 port was sponsored in part by
Microbric Pty Ltd

Getting MicroPython

Use esptool to load onto board:

$ export ESPTOOL_PORT=/dev/ttyUSB0
$ export ESPTOOL_BAUD=115200
$ export ESPTOOL_FS=detect
$ esptool write_flash 0 \
    esp32-20170604-v1.8.7-964-g62d40e8b.bin

MicroPython REPL

$ miniterm.py /dev/ttyUSB0 115200 --raw
MicroPython v1.8.7-964-g62d40e8b on 2017-06-04; ESP module with ESP32
Type "help()" for more information.
>>> dir()
['uos', 'gc', '__name__', 'bdev']
>>> print("Hello, World!")
Hello, World!
>>> 2**100
1267650600228229401496703205376
>>> import os
>>> os.listdir(".")
['boot.py']
>>>

MicroPython I/O — 1

>>> import machine
>>> import time
>>> pin5 = machine.Pin(5, machine.Pin.OUT)
>>> while True:
...     pin5.value(0)
...     time.sleep(0.5)
...     pin5.value(1)
...     time.sleep(0.5)

MicroPython I/O — 2

import machine

class Servo:
    def __init__(self, pin):
        self.pwm = machine.PWM(pin)
        self.pwm.freq(50)

    def set(self, pos):
        pulse_us = 1000 + 1000 * min(1,max(pos,0))
        self.pwm.duty(int(pulse_us * self.pwm.freq() * 0.001024))

pin5 = machine.Pin(5, machine.Pin.OUT)
srv5 = Servo(pin5)
srv5.set(0.25)
srv5.set(0.9)

MicroPython WiFi

>>> import network
>>> sta_if = network.WLAN(network.STA_IF)
>>> sta_if.active(True)
>>> sta_if.scan()
>>> sta_if.isconnected()
False
>>> sta_if.connect("my_ap", "my_password")
>>> sta_if.isconnected()
True
>>> sta_if.ifconfig()
('10.107.1.124', '255.255.255.0', '10.107.1.1', '10.107.1.1')

    

MicroPython Sockets

>>> import socket
>>> sock = socket.socket(socket.AF_INET)
>>> sock.bind(('0.0.0.0', 80))
>>> sock.listen(5)
>>> sock.accept()
(<socket state=2 timeout=-1 incoming=0 off=0>, ('10.107.1.4', 37464))

Copying Files

github: nickzoic/mpy-utils

What doesn't MicroPython have?

Contributing to MicroPython

github: micropython/micropython-esp32

$ git clone https://github.com/micropython/micropython-esp32
$ git clone --recursive https://github.com/espressif/esp-idf 
$ wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-59.tar.gz
$ tar xzf xtensa-esp32-elf-linux64-1.22.0-59.tar.gz 
$ export ESPIDF=`realpath esp-idf`
$ export PATH=`realpath xtensa-esp32-elf/bin`:$PATH
$ cd micropython-esp32
$ make -C mpy-cross
$ make -C esp32
    

MicroPython ESP32 Repo Files

ACKNOWLEDGEMENTS    esp32/     minimal/    teensy/
bare-arm/           esp8266/   mpy-cross/  tests/
cc3200/             examples/  pic16bit/   tools/
CODECONVENTIONS.md  extmod/    py/         unix/
CONTRIBUTING.md     lib/       qemu-arm/   windows/
docs/               LICENSE    README.md   zephyr/
drivers/            logo/      stmhal/

MicroPython ESP32 Repo — Files (Docs)

ACKNOWLEDGEMENTS    esp32/     minimal/    teensy/
bare-arm/           esp8266/   mpy-cross/  tests/
cc3200/             examples/  pic16bit/   tools/
CODECONVENTIONS.md  extmod/    py/         unix/
CONTRIBUTING.md     lib/       qemu-arm/   windows/
docs/               LICENSE    README.md   zephyr/
drivers/            logo/      stmhal/

Documentation, Examples, Tests

MicroPython ESP32 Repo — Files (Shared)

ACKNOWLEDGEMENTS    esp32/     minimal/    teensy/
bare-arm/           esp8266/   mpy-cross/  tests/
cc3200/             examples/  pic16bit/   tools/
CODECONVENTIONS.md  extmod/    py/         unix/
CONTRIBUTING.md     lib/       qemu-arm/   windows/
docs/               LICENSE    README.md   zephyr/
drivers/            logo/      stmhal/

Shared between ports

MicroPython ESP32 Repo — Files (Ports)

ACKNOWLEDGEMENTS    esp32/     minimal/    teensy/
bare-arm/           esp8266/   mpy-cross/  tests/
cc3200/             examples/  pic16bit/   tools/
CODECONVENTIONS.md  extmod/    py/         unix/
CONTRIBUTING.md     lib/       qemu-arm/   windows/
docs/               LICENSE    README.md   zephyr/
drivers/            logo/      stmhal/

Ports to specific platforms

MicroPython ESP32 Repo — Files (Ports)

ACKNOWLEDGEMENTS    esp32/     minimal/    teensy/
bare-arm/           esp8266/   mpy-cross/  tests/
cc3200/             examples/  pic16bit/   tools/
CODECONVENTIONS.md  extmod/    py/         unix/
CONTRIBUTING.md     lib/       qemu-arm/   windows/
docs/               LICENSE    README.md   zephyr/
drivers/            logo/      stmhal/

The ESP32 port!

esp32 port — Files

esp32.custom_common.ld  modesp.c        mphalport.c
fatfs_port.c            modmachine.c    mphalport.h
gccollect.c             modmachine.h    qstrdefsport.h
gccollect.h             modnetwork.c    README.md
help.c                  modsocket.c     sdkconfig.h
machine_pin.c           modules/        uart.c
main.c                  moduos.c        uart.h
Makefile                modutime.c
memory.h                mpconfigport.h

README and Makefile

esp32 port — Files (Modules)

esp32.custom_common.ld  modesp.c        mphalport.c
fatfs_port.c            modmachine.c    mphalport.h
gccollect.c             modmachine.h    qstrdefsport.h
gccollect.h             modnetwork.c    README.md
help.c                  modsocket.c     sdkconfig.h
machine_pin.c           modules/        uart.c
main.c                  moduos.c        uart.h
Makefile                modutime.c
memory.h                mpconfigport.h

Modules implemented in C

How do C modules work? — 1

>>> import esp
>>> dir(esp)
['__name__', 'flash_read', 'flash_write', 'flash_erase',
 'flash_size', 'flash_user_start']
>>> esp.flash_size()
4194304

How do C modules work? — 2

esp-idf/components/spi_flash/include/esp_spi_flash.h

/**
 * @brief  Get flash chip size, as set in binary image header
 *
 * @note This value does not necessarily match real flash size.
 *
 * @return size of flash chip, in bytes
 */
size_t spi_flash_get_chip_size();

How do C modules work? — 3

esp32/modesp.c

#include "esp_spi_flash.h"

STATIC mp_obj_t esp_flash_size(void) {
    return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
}

How do C modules work? — 4

esp32/modesp.c

#include "esp_spi_flash.h"

STATIC mp_obj_t esp_flash_size(void) {
    return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
}

How do C modules work? — 5

esp32/modesp.c

#include "esp_spi_flash.h"

STATIC mp_obj_t esp_flash_size(void) {
    return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);

How do C modules work? — 6

esp32/modesp.c

#include "esp_spi_flash.h"

STATIC mp_obj_t esp_flash_size(void) {
    return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);

STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
    { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
};
    

How do C modules work? — 7

esp32/modesp.c

#include "esp_spi_flash.h"

STATIC mp_obj_t esp_flash_size(void) {
    return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);

STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
    { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
};
STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);

const mp_obj_module_t esp_module = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t*)&esp_module_globals,
};

How do C modules work? — 8

esp32/mpconfigport.h

extern const struct _mp_obj_module_t esp_module;

#define MICROPY_PORT_BUILTIN_MODULES \
    { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \

esp32/Makefile

SRC_C = \
        modesp.c \

How do C modules work? — 9

>>> import esp
>>> dir(esp)
['__name__', 'flash_read', 'flash_write', 'flash_erase',
 'flash_size', 'flash_user_start']
>>> esp.flash_size()
4194304

Summary

If you're interested in Microcontrollers / IoT / Robotics:

PyCon AU

original image: 2017.pycon-au.org

Questions / Comments

Nick Moore
Mnemote Pty Ltd

Slides:

Content and images © Mnemote Pty Ltd except where otherwise noted