Espruino on ESP8266 WiFi
Note: This page documents running the Espruino firmware on the ESP8266 board. To find out how to connect an ESP8266 board to another Espruino board (as a Wifi Adaptor) please see this page instead
Warning: Espruino on the ESP8266 defaults to 115200 baud on its serial interface. This means you will need to adjust this setting in the IDE if you use that. (Other Espruino ports default to 9600 baud.)
Contents
- Quick links
- Features
- Flashing
- Build Content
- Limitations
- Pinout
- WiFi
- GPIO Pins
- digitalPulse implementation
- setWatch implementation
- analogRead implementation
- analogWrite implementation
- SPI Implementation
- Serial port
- Serial Numbers
- Software Serial
- System time
- Saving code to flash
- Flash map and access
- Main loop processing
- Performance
- Loading Espruino
- Power Consumption
- Open Issues
- Further reading
- Official Espruino Boards
Quick links
- Download the latest ESP8266 firmware release
- Download 'cutting edge' ESP8266 firmwares - these may not always work
- Tutorial on flashing the esp8266
- Espruino ESP8266 Forum
- Using Wifi on the ESP8266
- Gitter chat about Espruino (not focused on esp8266 but lots of esp8266 chatter)
Features
- 24mm x 16mm
- 17 GPIO pins (11 usable): 1 serial, 1 SPI, 1 I2C
- 1 Analog input (0..1V)
- Built-in Wifi
- Soft Serial
- Soft PWM
- None of the GPIO are 5 volt tolerant!
- 1600/1700 JS variables
Flashing
If you have a Chromium-based web browser it's possible to flash your ESP32 device direct from the browser! Click here to flash Espruino to your board
Otherwise see the Tutorial on flashing the esp8266
Build Content
content *) | espruino_2v00_esp8266 | espruino_2v00_esp8266_4mb | |
---|---|---|---|
Modules | NET TELNET CRYPTO, only SHA1 NEOPIXEL Storage |
NET TELNET GRAPHICS CRYPTO only SHA1 NEOPIXEL Storage |
|
JS variables | 1700 | 1600 | |
save pages | 4 x 4096 byte | 48 x 4096 byte | |
getState() | {"sdkVersion": "2.2.1(6ab97e9)", "cpuFrequency": 160, "freeHeap": 10672, "maxCon": 10, "flashMap": "512KB:256/256", "flashKB": 512, "flashChip": "0xXX 0x4013"} |
{"sdkVersion": "2.2.1(6ab97e9)", "cpuFrequency": 160, "freeHeap": 12416, "maxCon": 10, "flashMap": "4MB:1024/1024", "flashKB": 4096, "flashChip": "0xXX 0x4016"} |
|
getFreeFlash() | n/a use 'Storage' module to save data |
[{ "addr": 2097152, "length": 1048576 }, { "addr": 3145728, "length": 262144 }, { "addr": 3407872, "length": 262144}, { "addr": 3670016, "length": 262144 }, { "addr": 3932160, "length": 262144 }] |
|
chip_id and flash_size | 4013-4015 use --flash_size 512KB |
4016-4018 use --flash_size 4MB-c1 |
|
max image size | 468 KB | 812 KB |
*) travis build after 2018-10-23 12:00
Limitations
The following features are only partially or not supported by Espruino on the ESP8266:
- No hardware I2C, however, the software I2C works OK.
- No hardware PWM, software PWM works OK.
- No DAC: the esp8266 does not have a DAC.
- Sofware Serial works OK.
- GPIO16 is now supported in Espruino as a D16 without watch but with all software functiontions like PWM/I2C/SPI/etc
The main limitations of Espruino on the esp8266 come from two factors:
- The esp8266 does not have rich I/O peripheral interfaces, this means protocols need to be run in software, which not only may be slower but keeps the CPU busy and not attending to other things. As a result, the esp8266 just cannot drive as man peripherals as a good ARM processor.
- The esp8266 uses FreeRTOS with non-preemptible tasks and has extremely limited code space for interrupt handlers, as a result, it is not possible to handle certain peripherals at interrupt time and a task has to be scheduled instead, which would be OK if tasks were pre-emptible, but they are not. This means that functions like digitalPulse have to use busy-waiting between edge transitions instead of being interrupt driven.
In general the above limitations can be overcome by writing C code and loading it into a custom Espruino build. The current state of the esp8266 Espruino port could also certainly be improved and contributions are always appreciated!
Pinout
Hover the mouse over a pin function for more information. Clicking in a function will tell you how to use it in Espruino.
- Purple boxes show pins that are used for other functionality on the board. You should avoid using these unless you know that the marked device is not used.
- ! boxes contain extra information about the pin. Hover your mouse over them to see it.
- 3.3v boxes mark pins that are not 5v tolerant (they only take inputs from 0 - 3.3v, not 0 - 5v).
- GND is ground (0v).
- ADC is an Analog to Digital Converter (for reading analog voltages)
- USART is a 2 wire peripheral for Serial Data.
Note: You need a good 3.3v regulator with a solid power supply. If you get errors as soon as Wifi starts it's probably because the power is insufficient. A 500-600mA regulator with at least 22uF capacitor is recommended.
WiFi
The ESP8266's Wifi implementation supports both a simple access point mode and a station mode. The station mode is highly recommended for normal operation as the access point mode is very limited. It supports 4 stations max and offers no routing between stations.
The default initial configuration is for an access point with an SSID like ESP_123ABC
to show
up.
Using the wifi is documented in the Wifi library reference. The "getting started" is:
var wifi = require("Wifi");
wifi.connect(ssid, {password:password}, function(e) {
if (e) {
console.log('error during connect:',e);
wifi.disconnect();
} else {
console.log('connected to',ssid);
wifi.stopAP();
//wifi.save();
}
});
You may want to add wifi.setHostname("espruino")
.
Once you're happy with your connection, you can use wifi.save()
to persist it, so you don't have
to reconnect each time you reset your ESP8266.
Please see the Using the ESP8266 with Wifi tutorial for the recommended way to use the esp8266 with Wifi.
To make HTTP requests, use the HTTP library.
Code for a simple get request can be found in the docs for the get()
method.
In terms of power consumption, the esp8266 uses about 60mA minimum when in AP mode, with power spikes in the 100-300mA range when transmitting. When in station mode and the station supports power save (often visible as a "DTIM period" setting in the access point) then the esp8266 will bounce between ~15mA and ~60mA most of the time when not transmitting, if power-save is enabled (see Wifi library), otherwise it will stay at ~70mA. If the Wifi is turned off it will consume around 15mA. Lower power modes (e.g. sleeping) is not currently supported in the Espruino port.
Beware that TCP connections can require a lot of memory for buffers, thus "your mileage may vary" if you use many connections and/or receive a lot of data. The memory for these buffers comes out of the heap using malloc, they are separate from the memory used by JavaScript. Thus you can run out of JavaScript memory (Espruino prints "Out of memory!") and you can run out of heap memory (the system tends to crash in those situations).
In order to reduce memory requirements, Espruino uses LwIP configured with a MSS of 536, this means that all TCP packets can have at most 536 bytes of payload as opposed to the typical 1460 bytes. On the transmission end, LwIP seems to allow for 3 packets to be in-flight (it has to keep data that is sent until it receives an acknowledgment from the receiver). On the reception end, it advertises a TCP window of 4 times the MSS, i.e. 2144 bytes, and Espruino tells LwIP to stop incoming data when it has two unconsumed buffers. The net result is that up to 6*536 = 3216 bytes may arrive and need to be buffered on a connection. If multiple connections are active these buffer requirements can add up quickly!
GPIO Pins
The esp8266 GPIO pins support totem-pole and open-drain outputs, and they support a weak internal pull-up resistor (in the 20KOhm-50KOhm range). The Espruino D0 through D15 pins map directory to GPIO0 through GPIO15 on the esp8266. Remember that GPIO6 through GPIO11 are used for the external flash chip and are therefore not really available. Also, GPIO0 and GPIO2 must be pulled-up at boot and GPIO15 must be pulled-down at boot.
GPIO16 is now supported in Espruino. Do not use it if you use deep sleep
digitalPulse implementation
The digitalPulse
function is implemented by using the hardware time.
So you can do fancy things like this and no watchdog timeout will kick in and reset the chip.
`digitalPulse(D12,1,[1,2,3,4,5,6,7,8,9,10]);
digitalPulse(D12,1,[10,20,30,40,50,60,70,80,90,100]);`
Note: This also means that digitalPulse(D0,1,10);digitalPulse(D0,0,10);digitalPulse(D0,1,10);
will not
produce 10ms pulses, because the time taken to execute the JS code for the function calls will increase the
pulse length. Instead, you need to do digitalPulse(D0,1,[10,10,10])
.
setWatch implementation
The setWatch implementation uses interrupts to capture incoming pulse edges and queues them. The queue can hold 16 elements, so setWatch will lose transitions if javascript code does not run promptly.
analogRead implementation
The esp8266 ADC function is available on pin A0 or without a pin. Using a digital pin will return NaN
Possible ways to call analogRead() and the returns:
analogRead(A0);
=0.0029296875
analogRead();
=0.0029296875
analogRead(D0);
=NaN
analogWrite implementation
With the implementation of hardware timer it's possible to generate stable pwm signals by software
`analogWrite(D12, 0.5, {freq:1000, soft:true});
analogWrite(D13, 0.5, {freq:500, soft:true});
analogWrite(D14, 0.5, {freq:2000, soft:true});`
I2C Implementation
The I2C interface is implemented in software because the esp8266 does not have hardware support for I2C (contrary to what the datasheet seems to imply). The software implementation has the following limitations:
- operates at approx 300Khz
- is master-only
- support clock stretching since 1v92 (a method by which slaves can slow down the master)
The I2C interface can be bound to almost any pin pair, but you should avoid GPIO15 because it needs to be pulled-down at boot time and the I2C bus needs pull-up resistors. The pins chosen for I2C are configured to be open-drain outputs and an external pull-up resistor is required on each of the two pins. Remember that esp8266 pins are not 5v compatible!
SPI Implementation
Both the software SPI and hardware SPI implementations can be used. The software SPI works on any GPIO pins but operates at a fixed clock rate of about 1Mhz. The hardware SPI operates on baud rates as low as 100kHz and as high as 4Mhz (this is limited by the way the clock dividers are calculated, the HW is capable of going faster, but given the software overheads around it there is not much point to it). The hardware SPI uses the pins shown in the board layout (CLK:D14, MISO:D12, MOSI:D13, CS:D15).
Serial port
The esp8266 has two UARTS. UART0 (Serial1
) uses gpio1 for TX and gpio3 for RX and is used by
the Espruino JavaScript console. It can be used for other things once the Espruino console
is moved to another device. For instance calling LoopbackA.setConsole()
will move the console
to 'loopback' (where is can be accessed using LoopbackB
), and will free up Serial1
for
use like any normal Espruino Serial port.
UART1 (Serial2
) uses gpio2 for TX and RX is not totally usable due to being used for the SDIO
flash chip. UART1 TX is used for debugging and can be used for application purposes, but RX is
not available.
Serial Numbers
The esp8266 does not have a serial number. It does have two mac addresses "burned-in", which one can use for identification purposes.
getSerial()
returns the MAC address of the STA interface.
Software Serial
With the implementation of hardware timer it's now possible to use the Espruino software implementation
`var s = new Serial();
s.setup(9600,{tx:D12,rx:D13});
s.write('Hello');`
System time
The esp8266 has two notions of system time implemented in the SDK by
system_get_time()
and system_get_rtc_time()
. The former has 1µs
granularity and comes off the CPU cycle counter, the latter has approx
57µs granularity and comes off the RTC clock. Both are
32-bit counters and thus need some form of roll-over handling in software
to produce a JsSysTime.
While the RTC clock may look attractive, it is not clear that it really is. The RTC runs off an internal RC oscillator or something similar and the SDK provides functions to calibrate it WRT the crystal oscillator. It does not run off a 32khz crystal like a proper RTC. In addition, due to some smart engineering a reset of the esp8266 chip resets the RTC, thus, even during deep sleep, where the RTC wakes up the processor, the RTC counter is lost. The conclusion is that it's about as close to worthless as it gets...
The implementation uses the system timer for jshGetSystemTime()
and
related functions and uses the rtc timer only at start-up to initialize
the system timer to the best guess available for the current date-time.
From a JavaScript perspective, we can get and set the system time using
the JS functions called getTime()
and setTime()
. These get and take
a time in seconds (float).
Saving code to flash
With the implementation of buildin module Storge it's simple to store any type of object you can think of.
Currently 16KB for 512KB ESPs and 192KB for 4MB ESPs of flash are reserved to save JS code to flash using the save() function. The total JS memory is larger (22400 bytes) so if you filled up the JSvars you will need compression to work well. Some simple tests show that "it should fit" but it's certainly possible that some combinations of stuff doesn't. In that case you're a bit out of luck.
If the save() area contains something that crashes Espruino or otherwise doesn't let you reset the system you can disable whatever is saved by flashing blank.bin to the last 4KB block of the save area (0x7A000).
Flash map and access
Note: if you are looking for a free flash area to use, call ESP8266.getFreeFlash
,
which will return a list of available areas (see docs).
The esp8266 modules come with varying flash chip sizes. The flash layout for each size is slightly different. There are a number of random tidbits to know about flash layout:
- There are two binary formats in use: the non-OTA and the OTA update format. The non-OTA has no 2nd stage bootloader, starts at 0x0000 in flash, and has two binary blobs: one for data and one for instructions (+ read-only data). The OTA format has a 2nd stage bootloader at 0x0000 and then a single binary blob for the first firmware image at 0x1000. There is a 2nd binary blob up after the first one to provide the two firmware images necessary for a safe OTA update. All this is described in the Espressif IOT SDK User Manual.
- The hardware can memory-map 1MBytes of flash, but it has to be read on word (4-byte) boundaries, it cannot be written using the memory map.
- Every flash layout has a 16KB "system param" area in which the SDK stores settings, including RF parameters and wifi settings
- The Espruino firmware uses over 400KB, which is far more than fits into an OTA-capable flash layout on modules that have only 512KB of flash. Therefore Over-The-Air upgrades of the Espruino firmware cannot be supported on these modules.
In order to produce a single flash image for all esp8266 modules some trickery has been used. The key concepts are:
- All modules use the OTA firmware format with a second-stage bootloader and the two binary images allowing for upgrades (these are called user1.bin and user2.bin by Espressif).
- On modules with 1MB of flash or more the standard OTA flash layout is used with two 512KB application partitions. On modules with more than 1MB of flash, the flash beyond 1MB can be used for a forthcoming spiffs filesystem.
- On modules with 512KB of flash, a somewhat tricked layout is used. The SDK is told to use an OTA layout with two 256KB firmwares but in fact a single 400KB+ firmware is loaded and care is used not to conflict with the 2x256KB layout.
The result of all this is the following:
Start | Start | Length | Function |
---|---|---|---|
0x000000 | 0 | 4KB | Bootloader with flash type/size header |
0x001000 | 4KB | 468KB | Espruino firmware, first partition |
0x076000 | 472KB | 4KB | SDK RF calibration save area on 512KB modules |
0x077000 | 476KB | 4KB | EEPROM emulation |
0x078000 | 480KB | 12KB | Espruino save() area |
0x07B000 | 492KB | 4KB | Espruino system and wifi settings |
0x07C000 | 496KB | 16KB | 512KB flash: Espressif SDK system params, else unused |
0x080000 | 512KB | 4KB | SDK RF calibration save area on 1MB and larger modules |
0x081000 | 516KB | 472KB | Espruino firmware, second partition |
0x0F7000 | 988KB | 4KB | Unused |
0x0F8000 | 992KB | 16KB | Unused |
0x0FC000 | 996KB | 16KB | 1MB flash: Espressif SDK system params, else unused |
0x100000 | 1MB | approx 1MB-3MB flash unused on 2MB-4MB modules | |
0x1FC000 | 2032KB | 16KB | 2MB flash: Espressif SDK system params, else unused |
0x3FC000 | 4080KB | 16KB | 4MB flash: Espressif SDK system params, else unused |
The Espressif SDK system params area is composed of:
Offset | Size | Function |
---|---|---|
0x0000 | 4KB | RF parameter values (default in esp_init_data_default.bin) |
0x1000 | 4KB | ? |
0x2000 | 4KB | Wifi and other system parameters (clear using blank.bin) |
0x3000 | 4KB | ? |
Note that the SDK RF calibration save area was added with SDK1.5.4 patch 1.
The ESP8266
library provides a getFreeFlash
function that returns an array of free flash areas should you want to
use the EEPROM emulation class or read/write flash directly.
Main loop processing
Espruino has the concept of a "main loop" which is executed to perform an iteration of work. Since the ESP8266 SDK needs control to be returned to itself to handle wifi, the current design and implementation returns to the SDK whenever there is no JS work to be done.
By using a task queue, the SDK is asked to invoke the Espruino main loop again as soon as possible. When the SDK does not have anything to do this takes about 200us. Ways to improve this are being investigated.
One important effect of this overall strategy is that running javascript code without any iterruption will starve the SDK Wifi processing and will cause a chip reset.
Performance
Espruino sets the esp8266 clock to 160Mhz by default, but this can be changed back to
the default 80Mhz from JavaScript using require("ESP8266").setCPUFreq(80) or
E.setClock(80)`.
The benefits of the lower clock frequency are assumed to be lower power consumption
by the CPU and operation at lower voltages, but this has not been confirmed!
The table below shows some measurements taken using an esp-12 module on the mandelbrot and
qsort_4 benchmarks in the benchmarks directory and on some code that displays lots of characters
on a HD44780 display attached via an MCP23008 which involves a lot of I2C operations. In the table
-Os
refers to the gcc compiler optimization level and AI
refers to enabling the
Espruino ALWAYS_INLINE compiler attribute, which tries to guide which functions to inline, and
NR
refers to a non-release build with asserts left in.
The conclusion is that builds with just -Os and 160Mhz clock frequency are the best.
Settings | Mandelbrot | Quicksort | Display | Code Size |
---|---|---|---|---|
-Os, 80Mhz | 70ms | 365ms | 623ms | 440KB |
-Os, 160Mhz | 38ms | 191ms | 354ms | |
-Os, 80Mhz, AI | 74ms | 469ms | 693ms | 477KB |
-Os, 160Mhz, AI | 47ms | 319ms | 463ms | |
-O1, 80Mhz, AI | 66ms | 393ms | 681ms | 486KB |
-O1, 160Mhz | 39ms | 241ms | 444ms | |
-Os, 80Mhz, NR | 90ms | 494ms | 886ms | 454KB |
-Os, 160Mhz, NR | 52ms | 293ms | 568ms |
Loading Espruino
Espruino can be loaded into the esp8266 using any of the flashing techniques applicable to the esp8266 itself. A variety of tools are available to assist with this.
The Espruino ESP8266 firmware is now distributed alongside all the other firmwares on the Espruino Website.
Power Consumption
Parameter | Typical | Unit |
---|---|---|
Tx 802.11b, CCK 11Mbps, Pout=+17dBm | 170 | mA |
Tx 802.11g,OFDM 54Mbps,Pout=+15dBm | 140 | mA |
Tx 802.11n, MCS7, Pout=+13dBm | 120 | mA |
Rx 802.11b, 1024 bytes packet length, -80dBm | 50 | mA |
Rx 802.11g, 1024 bytes packet length, -70dBm | 56 | mA |
Rx 802.11n, 1024 bytes packet length, -65dBm | 56 | mA |
Modem-Sleep | 15 | mA |
Light-Sleep | 0.5 | mA |
Power save mode DTIM 1 | 1.2 | mA |
Power save mode DTIM 3 | 0.9 | mA |
Deep-Sleep | 10 | uA |
Power OFF | 0.5 | uA |
Currently ESP8266 can support three low power modes: Light Sleep, Modem Sleep and Deep Sleep.
Modem-Sleep requires the CPU to be working, as in PWM or I2S applications. According to 802.11 standards (like U-APSD), it saves power to shut down the Wi-Fi Modem circuit while maintaining a Wi-Fi connection with no data transmission.
During Light-Sleep, the CPU may be suspended in applications like Wi-Fi switch. Without data transmission, the Wi-Fi Modem circuit can be turned off and CPU suspended to save power according to the 802.11 standard (U-APSD).
Deep-Sleep does not require Wi-Fi connection to be maintained. For application with long time lags between data transmission, e.g. a temperature sensor that checks the temperature every 100s. E.g. sleep 300s and waking up to connect to the AP (taking about 0.3~1s), the overall average current is less than 1mA.
Source: http://bbs.espressif.com/viewtopic.php?t=133
Open Issues
The authoritative list of open issues is on github. Some of the top-level issues at the time of writing are:
- Support sleep mode
- Provide more memory, like more JSvars and heap)
Further reading
The esp8266 has its own community, free books, videos and more. For esp8266 questions not related to Espruino, it is recommended to research using those resources.
Official Espruino Boards
This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.