Get a recent build of Pycopy, a fork of MicroPython that we will be using for this workshop. A build of the current state as of 2019-11-24 is [here](firmware.bin).
Afterwards, get `esptool` and use it to flash your board:
``` sh
pip install esptool
esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py --port /dev/ttyUSB0 --chip esp32 \
write_flash -z 0x1000 firmware.bin
```
You can now connect to your board's REPL with e.g. `screen` or `putty`:
``` sh
screen /dev/ttyUSB0 115200
```
You'll get a command prompt and be able to execute the first commands
``` python
help()
print("Hello, world")
```
A reference of all the default libraries can be found on [readthedocs.io](https://pycopy.readthedocs.io/en/latest/)
### File upload using `ampy`
You can use `ampy` to manage files from the CLI:
``` sh
pip install adafruit-ampy
export AMPY_PORT=/dev/ttyUSB0
# List files
ampy ls
# Print file contents
ampy get boot.py
# Save a file
ampy get boot.py boot.py
# Create some example file
echo "print('hello, world')" > hello.py
# Run a local file
ampy run hello.py
# Save it to the board
ampy put hello.py
# Delete it again
ampy rm hello.py
```
The contents of `boot.py` are run each time the controller resets. It may contain instructions for setting up your network connection, local time, peripherals, etc.
Hello, LED
----------
You can control the builtin LED, which is on pin 5:
``` python
from machine import Pin
led = Pin(5, Pin.OUT)
# The values are inverted, so this turns
# the LED on:
led.off()
# and this turns it off:
led.on()
# You can also use numbers or booleans:
led.value(False)
led.value(1)
```
### Brightness control with PWM
``` python
from machine import PWM
pwm = PWM(led)
# Read the frequency
pwm.freq()
# Set it
pwm.freq(20000)
# Read and set the duty cycle
pwm.duty()
pwm.duty(1023)
pwm.duty(512)
pwm.duty(0)
```
### Reserved pins
- UART: Pins 1 and 3 are TX/RX
- Flash: 6, 7, 8, 11, 16, 17. Messing with these will probably crash your program.
- 34-39 are input only and do not have pullups.
All other pins can be used for PWM.
Pins 2, 4, 12, 13, 14, 15 are connected the the micro-SD slot.
Digital and analog input
------------------------
Use `machine.Pin` for digital input
``` python
from machine import Pin
pin = Pin(4, Pin.IN)
pin.value()
# You can use pullups:
pin = Pin(4, Pin.IN, Pin.PULL_UP)
pin = Pin(4, Pin.IN, Pin.PULL_DOWN)
```
For analog input, use `machine.ADC`. By default, the ADC has an input range of 1.00 V, but this can be changed to up to 3.6 V. Available pins are 32 through 39.
``` python
from machine import Pin, ADC
pin = ADC(Pin(32, Pin.IN, None))
pin.read()
# You can set the resolution, it defaults to 12 bits
pin.width(ADC.WIDTH_10BIT)
pwm = machine.PWM(Pin(5, Pin.OUT))
while True:
pwm.duty(1023 - pin.read())
```
Timers
------
MicroPython on the ESP32 has virtual timers and 4 hardware timers. You can use a lot more virtual timers, but they are more prone to jitter. In either case, you can not allocate memory in a timer, as they are executed from an interrupt context.
Timers execute a callback, which takes the timer as an argument
timer.init(mode = Timer.ONE_SHOT, period = 100, callback = callback)
# Run the callback every second
timer.init(period = 1000, callback = callback)
# After some time
print(data)
timer.deinit()
```
Files
-----
MicroPython has an internal filesystem that is stored after the firmware. You can access it in the usual way:
``` python
import os
os.listdir("/")
print( open("/boot.py").read() )
# Write to a file. Deletes existing content.
f = open("data.txt", "a")
f.write("Hello ")
f.close()
# Append
f = open("data.txt", "a")
f.write("world.\n")
f.close()
print(open("data.txt").read())
```
Sleep modes and power consumption
---------------------------------
When transmitting data to a WLAN, power consumption will be 160 - 260 mA (so use `WLAN.active(false)` when you don't need it). Even with a deactivated modem, the power consumption can still be up to 20 mA when the CPU is running.
### Idle
In idle mode, the CPU is paused but peripherals keep working.
``` python
import machine
# Enter idle mode indefinitely
machine.idle()
```
Execution continues when an interrupt happens, usually after a few milliseconds
### Light sleep
In light sleep, most of the microprocessor will be inactive. Power consumption will be at about 0.8 mA.
``` python
import machine
# Enter light sleep until the next interrupt
machine.lightsleep()
# Enter lightsleep until the next interrupt, but
# at most for one second
machine.lightsleep(1000)
```
### Deep sleep
In deep sleep, most of the RAM and all digital peripherals are turned off. Only the RTC and ULP co-processor stay active. Power consumption is about 10 uA. After deep sleep is exited, the ESP32 will reset.
``` python
import machine
# Same behaviour as with lightsleep
machine.deepsleep()
machine.deepsleep(10000)
# To further reduce power consumption, disable pullups:
After the reset, use `machine.reset_cause()` to check if we were in a deep sleep:
``` python
import machine
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print("Woke up from deep sleep")
```
### RTC
The RTC of the ESP32 is not only used to keep track of time, but can also save up to 2 kiB of data during deep sleep. This memory is still volatile, however, and will be deleted if you use the reset button or remove power
``` python
import machine
rtc = machine.RTC()
rtc.memory('some data')
rtc.memory()
```
Network
-------
To create or connect to a WLAN, we will use the `network` module.
### Creating a network
You can easily create a network with a DHCP server for any clients: