Is a microcontroller from Espressif Systems and contains WiFi.
ESP32 is a dual core 160MHz-240MHz CPU where as the ESP8266 is a single core that runs at 80MHz. Both are 32-bits processors. ESP32 is the successor
The microcontroller unit on these chips are from Xtensa.
I've got a SparkFun development board ESP8266 Thing.
Serial Basic board
+--------+ +----------+
|(I²C)GND|-- --|GND |
|(I²C)3V3|-- --|CTS |
|(I²C)SDA|-- --|VCC +----+ V
|(I²C)SCL|-- --|TX0 |USB |
| DTR|-- --|RX1 +----+
| TXO|-- --|DTR |
| RX0|-- +----------+
| 3V3|--
| NC|--
| GND|--
+--------+
GND = Ground (I²C) GND = Ground
SDA = Serial Data (I²C) CTS = Clear to Send (I²C). Clear To Send (the receiver side is ready)
SCL = Serial Clock (I²C) VCC = Voltage Common Collector (I²C) . Power input of the device
DTR = Data Terminal Ready TX0 = Transmit output
TX0 = Transmit output 0 RX1 = Recieve input
3V3 = 3.3 Volage DTR = Data Terminal Ready (device ready to received/initiate communication)
NC = Not Connected to anything
From the serial basic board the connections look like this:
- Ground which is connected to ground.
- CTS is connected to NC (why?)
- VCC is connected to 3V3 which I think makes sense
- TX0 is connected to RX0
- RX1 is connected to TX0
- DTR is connected to DTR (I guess this means they are connected)?
We can use one USB cable if we connect the 3V3 to the (I²C)3V3 above:
This is a USB to serial board similar to FTDI Basic. Computers used to have RS-232 9-pin or 25-pin serial ports on the back for connecting to peripherals. In the late 90's USB began to take over and has the advantage of supplying power to the attached peripheral and more. An USB to serial bridge is a way to emulate the software interface of a serial port via standard drivers and allows the user to treat the USB device as though it were a standard serial port.
This is a cross compiler toolchain I think.
This is the chips are from Xtensa.
Download and unpack: https://dl.espressif.com/dl/xtensa-lx106-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz
This contains compilers/assemblers, linkers and tools like, as
, gcc
, g++
nm
, ld
, objdump
ets. All are specific used for cross compiling. The
can be found in the bin
directory:
$ ls bin/
xtensa-lx106-elf-addr2line xtensa-lx106-elf-cpp xtensa-lx106-elf-gcc-ar xtensa-lx106-elf-gdb xtensa-lx106-elf-objdump
xtensa-lx106-elf-ar xtensa-lx106-elf-ct-ng.config xtensa-lx106-elf-gcc-nm xtensa-lx106-elf-gprof xtensa-lx106-elf-ranlib
xtensa-lx106-elf-as xtensa-lx106-elf-elfedit xtensa-lx106-elf-gcc-ranlib xtensa-lx106-elf-ld xtensa-lx106-elf-readelf
xtensa-lx106-elf-c++ xtensa-lx106-elf-g++ xtensa-lx106-elf-gcov xtensa-lx106-elf-ld.bfd xtensa-lx106-elf-size
xtensa-lx106-elf-cc xtensa-lx106-elf-gcc xtensa-lx106-elf-gcov-dump xtensa-lx106-elf-nm xtensa-lx106-elf-strings
xtensa-lx106-elf-c++filt xtensa-lx106-elf-gcc-8.4.0 xtensa-lx106-elf-gcov-tool xtensa-lx106-elf-objcopy xtensa-lx106-elf-strip
So this allows us to compiler and link assembler, C, C++ programs into machine code that can execute on a xtensa processor
We need to add the this bin directory to our PATH. I've done this in a setenv.sh file.
This is a
$ git clone --recursive https://github.com/espressif/ESP8266_RTOS_SDK.git
`
```console
$ . ./setenv.sh
python -m pip install --user -r $IDF_PATH/requirements.txt
This section will take a closer look at the example project that is part of the SDK which can be used as a template.
Start by copying the hello_world example:
$ cp -r $IDF_PATH/examples/get-started/hello_world .
$ cd hello_world
$ ls
CMakeLists.txt main Makefile README.md
If we take a closer look at the Makefile it simply includes .IDF_PATH)/make/project.mk and simlarliy for the CMake file.
There is a help
target with some details about the targets available.
$ make help
Toolchain path: /home/danielbevenius/work/iot/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Welcome to Espressif IDF build system. Some useful make targets:
make menuconfig - Configure IDF project
make defconfig - Set defaults for all new configuration options
make all - Build app, bootloader, partition table
make flash - Flash app, bootloader, partition table to a chip
make clean - Remove all build output
make size - Display the static memory footprint of the app
make size-components, size-files - Finer-grained memory footprints
make size-symbols - Per symbol memory footprint. Requires COMPONENT=<component>
make erase_flash - Erase entire flash contents
make erase_otadata - Erase ota_data partition; First bootable partition (factory or OTAx) will be used on next boot.
This assumes this project's partition table is the one flashed on the device.
make monitor - Run idf_monitor tool to monitor serial output from app
make simple_monitor - Monitor serial output on terminal console
make list-components - List all components in the project
make app - Build just the app
make app-flash - Flash just the app
make app-clean - Clean just the app
make print_flash_cmd - Print the arguments for esptool when flash
make check_python_dependencies - Check that the required python packages are installed
See also 'make bootloader', 'make bootloader-flash', 'make bootloader-clean',
'make partition_table', etc, etc.
So we need to connect the device and I'm using USB to do this. This will be
discovered by the system and we can get details about this new device in a few
ways. One is to use dmesg
.
$ dmesg -w
-w
is the follow flag so we should be able to see the new device showing up
in the console:
[696846.518822] usb 1-2: new full-speed USB device number 43 using xhci_hcd
[696846.646023] usb 1-2: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.64
[696846.646037] usb 1-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[696846.646042] usb 1-2: Product: USB Serial
[696846.694744] usbcore: registered new interface driver ch341
[696846.694755] usbserial: USB Serial support registered for ch341-uart
[696846.694772] ch341 1-2:1.0: ch341-uart converter detected
[696846.695431] usb 1-2: ch341-uart converter now attached to ttyUSB0
Notice that we find the device for this and in this case it is ttyUSB0
.
$ file /dev/ttyUSB0
/dev/ttyUSB0: character special (188/0)
We can find out details about this USB device using the device number
above
which is in this case is 43
:
$ lsusb -v -s 43
Bus 001 Device 043: ID 1a86:7523 QinHeng Electronics CH340 serial converter
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 255 Vendor Specific Class
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x1a86 QinHeng Electronics
idProduct 0x7523 CH340 serial converter
bcdDevice 2.64
iManufacturer 0
iProduct 2 USB Serial
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0027
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 98mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 1
bInterfaceProtocol 2
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 1
We can update the sdkconfig file and set CONFIG_ESPTOOLPY
to be
/dev/ttyUSB0
. This can be done with make menuconfig
.
Now we should be able to flash
the device with this projects code:
$ make flash
...
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)...
esptool.py v2.4.0
Traceback (most recent call last):
File "/home/danielbevenius/.local/lib/python3.9/site-packages/serial/serialposix.py", line 322, in open
self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
PermissionError: [Errno 13] Permission denied: '/dev/ttyUSB0'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py", line 3034, in <module>
_main()
File "/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py", line 3027, in _main
main()
File "/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py", line 2735, in main
esp = chip_class(args.port, initial_baud, args.trace)
File "/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/esptool/esptool.py", line 212, in __init__
self._port = serial.serial_for_url(port)
File "/home/danielbevenius/.local/lib/python3.9/site-packages/serial/__init__.py", line 90, in serial_for_url
instance.open()
File "/home/danielbevenius/.local/lib/python3.9/site-packages/serial/serialposix.py", line 325, in open
raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyUSB0: [Errno 13] Permission denied: '/dev/ttyUSB0'
make: *** [/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/Makefile.projbuild:76: flash] Error 1
This was because while I added my user to the dailout group I had not restarted a session. But this can be done using:
$ sudo usermod -a -G dialout $USER
$ su - $USER
Don't forget to run the setenv.sh
script as well.
$ make flash
Toolchain path: /home/danielbevenius/work/iot/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Project is not inside a git repository, or git repository has no commits
will not use 'git describe' to determine PROJECT_VER.
App "hello-world" version: 1
Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)...
esptool.py v2.4.0
Connecting........_____....._____....._____....._____....._____....._____....._____
A fatal error occurred: Failed to connect to ESP8266: Timed out waiting for packet header
make: *** [/home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/components/esptool_py/Makefile.projbuild:76: flash] Error 2
To see what flash does we can use the print_flash_cmd
target:
$ make print_flash_cmd
Toolchain path: /home/danielbevenius/work/iot/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
--flash_mode dio --flash_freq 40m --flash_size 2MB 0x0 bootloader/bootloader.bin 0x10000 hello-world.bin 0x8000 partitions_singleapp.bin
$ make flash
Toolchain path: /home/danielbevenius/work/iot/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Project is not inside a git repository, or git repository has no commits
will not use 'git describe' to determine PROJECT_VER.
App "hello-world" version: 1
Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)...
esptool.py v2.4.0
Connecting........_____....._____....._____....._____.....__
Chip is ESP8266EX
Features: WiFi
MAC: c8:2b:96:09:23:82
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 10432 bytes to 7025...
Wrote 10432 bytes (7025 compressed) at 0x00000000 in 0.6 seconds (effective 133.7 kbit/s)...
Hash of data verified.
Compressed 169296 bytes to 108461...
Wrote 169296 bytes (108461 compressed) at 0x00010000 in 9.6 seconds (effective 141.5 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 83...
Wrote 3072 bytes (83 compressed) at 0x00008000 in 0.0 seconds (effective 1817.3 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
$ make monitor
Toolchain path: /home/danielbevenius/work/iot/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: esp-2020r3-49-gd5524c1
Compiler version: 8.4.0
Python requirements from /home/danielbevenius/work/iot/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
MONITOR
--- idf_monitor on /dev/ttyUSB0 74880 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jan 8 2013,rst cause:2, boot mode:(3,7)
load 0x40100000, len 7040, room 16
tail 0
chksum 0xe2
load 0x3ffe8408, len 24, room 8
tail 0
chksum 0x6b
load 0x3ffe8420, len 3324, room 8
tail 4
chksum 0x4c
csum 0x4c
I (44) boot: ESP-IDF v3.4-49-g0f200b46 2nd stage bootloader
I (44) boot: compile time 09:30:13
I (45) qio_mode: Enabling default flash chip QIO
I (52) boot: SPI Speed : 40MHz
I (59) boot: SPI Mode : QIO
I (65) boot: SPI Flash Size : 2MB
I (71) boot: Partition Table:
I (77) boot: ## Label Usage Type ST Offset Length
I (88) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (99) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (111) boot: 2 factory factory app 00 00 00010000 000f0000
I (122) boot: End of partition table
I (129) esp_image: segment 0: paddr=0x00010010 vaddr=0x40210010 size=0x1cc68 (117864) map
0x40210010: _stext at ??:?
I (182) esp_image: segment 1: paddr=0x0002cc80 vaddr=0x4022cc78 size=0x07210 ( 29200) map
I (193) esp_image: segment 2: paddr=0x00033e98 vaddr=0x3ffe8000 size=0x00544 ( 1348) load
I (193) esp_image: segment 3: paddr=0x000343e4 vaddr=0x40100000 size=0x00080 ( 128) load
I (207) esp_image: segment 4: paddr=0x0003446c vaddr=0x40100080 size=0x050c0 ( 20672) load
I (227) boot: Loaded app from partition at offset 0x10000
Hello world!
This is ESP8266 chip with 1 CPU cores, WiFi, silicon revision 1, 2MB external flash
Restarting in 10 seconds...
Restarting in 9 seconds...
Restarting in 8 seconds...
Restarting in 7 seconds...
Restarting in 6 seconds...
Restarting in 5 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
Restarting in 1 seconds...
Restarting in 0 seconds...
Restarting now.
ets Jan 8 2013,rst cause:2, boot mode:(3,7)
load 0x40100000, len 7040, room 16
tail 0
chksum 0xe2
load 0x3ffe8408, len 24, room 8
tail 0
chksum 0x6b
load 0x3ffe8420, len 3324, room 8
tail 4
chksum 0x4c
csum 0x4c
I (83) boot: ESP-IDF v3.4-49-g0f200b46 2nd stage bootloader
I (83) boot: compile time 09:30:13
I (83) qio_mode: Enabling default flash chip QIO
I (99) boot: SPI Speed : 40MHz
I (112) boot: SPI Mode : QIO
I (124) boot: SPI Flash Size : 2MB
I (137) boot: Partition Table:
I (148) boot: ## Label Usage Type ST Offset Length
I (171) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (194) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (218) boot: 2 factory factory app 00 00 00010000 000f0000
I (241) boot: End of partition table
I (254) esp_image: segment 0: paddr=0x00010010 vaddr=0x40210010 size=0x1cc68 (117864) map
0x40210010: _stext at ??:?
I (337) esp_image: segment 1: paddr=0x0002cc80 vaddr=0x4022cc78 size=0x07210 ( 29200) map
I (351) esp_image: segment 2: paddr=0x00033e98 vaddr=0x3ffe8000 size=0x00544 ( 1348) load
I (359) esp_image: segment 3: paddr=0x000343e4 vaddr=0x40100000 size=0x00080 ( 128) load
I (387) esp_image: segment 4: paddr=0x0003446c vaddr=0x40100080 size=0x050c0 ( 20672) load
I (423) boot: Loaded app from partition at offset 0x10000
Hello world!
This is ESP8266 chip with 1 CPU cores, WiFi, silicon revision 1, 2MB external flash
Restarting in 10 seconds...
$ sudo cat /proc/tty/driver/usbserial [sudo] password for danielbevenius: usbserinfo:1.0 driver:2.0 0: module:ch341 name:"ch341-uart" vendor:1a86 product:7523 num_ports:1 port:0 path:usb-0000:00:14.0-2
$ statserial /dev/ttyUSB0
Device: /dev/ttyUSB0
Signal Pin Pin Direction Status Full
Name (25) (9) (computer) Name
----- --- --- --------- ------ -----
FG 1 - - - Frame Ground
TxD 2 3 out - Transmit Data
RxD 3 2 in - Receive Data
RTS 4 7 out 1 Request To Send
CTS 5 8 in 0 Clear To Send
DSR 6 6 in 0 Data Set Ready
GND 7 5 - - Signal Ground
DCD 8 1 in 0 Data Carrier Detect
DTR 20 4 out 1 Data Terminal Ready
RI 22 9 in 0 Ring Indicator
AT which I think stands for Attention
are commands that can be send by a host
to an ESP chip which will respond back with either OK
or ERROR
.
The commands can be for Wifi, TCP/IP, Bluetooth LE, Bluetooth, MQTT, HTTP, and
Ethernet.
So if we write software that is flashed onto an ESP8266 device, it would then issue AT commands to the WiFi device. This was a little confusing for me initially (at least I think I've understood this now). For example, in Drogue IoT there is a driver for ESP8266 in src/drivers/wifi/esp8266/mod.rs:
async fn configure(&self, notifications: &dyn SocketsNotifier) -> Result<(), DriverError> {
// Initialize
let mut inner = self.inner.lock().await;
let driver_error = |_| DriverError::UnableToInitialize;
inner
.send_recv(b"ATE0\r\n", notifications)
.await
.map_err(driver_error)?;
inner
.send_recv(b"AT+CIPMUX=1\r\n", notifications)
.await
.map_err(driver_error)?;
inner
.send_recv(b"AT+CIPRECVMODE=1\r\n", notifications)
.await
.map_err(driver_error)?;
inner
.send_recv(b"AT+CWMODE_CUR=1\r\n", notifications)
.await
.map_err(driver_error)?;
Ok(())
}
The first comand sent is ATE0
which is disabling echo. Next, we are sending
AT+CIPMUX
which is for configuring single of multi IP connection. 1 meams
multi.
So inner.send_recv is an async function, which means that it returns a future,
which will be of type impl Future<output=Result<AtResponse, DriverError>
. This
is the awaited, which will drive the future to completion and return the Result.
We then call .map_err on the Result to map the error, if there is one, to the
type DriverError::UnableToInitialize.
There is some code duplication here which we might be able to avoid.
To connect to a network there has to be a WiFi link. An ESP8266 can act as a station (which connects to some network), or an access point for other wireless devices/stations can connect to it.
An ESP can be used as AP-only, Station-only, or AP+Station mode.
AP (Access Point) or WAP (Wireless Access Point).