Getting Started With The ESP8266 WIFI Microcontroller
ESP8266 is a powerful, WIFI enabled, 32-bit microcontroller which is available for just a few dollars. Given its versatility, it is not surprising that it is becoming very popular for InternetOfThings-type application, and will likely continue to do so. It has a strong and helpful community of users behind it, and new applications and tools are being developed very rapidly.
The difficulty that I had in getting started was that there was no central source for the required information; I ended up spending quite some time searching, trolling through forums, reading source code and various other documentation in order to get up and running, and to glean some idea about how things work, and what is going on in general.
Anwyay, here I will document the various steps that I took to:
- Wire up the hardware
- Test the module with AT commands
- Install the C SDK
- Flash the device
- Set up for development with NodeMCU Lua environment
1. The ESP-01 Module
There are several different modules available, each with different form-factors and with various pin outs. The one we will be using is known as the ESP-01, and makes accessible just enough pins to make it usable, as show here:
|VCC||3.3V (3.6V Max)|
|TXD||UART TX line|
|RXD||UART RX line|
|CH_PD||Chip Power Down (Pull high for chip active)|
|GPIO0||General Purpose I/O 0 *|
|GPIO1||General Purpose I/O 1 *|
|RST||Reset (pull LOW to reset)|
The device requires a nominal 3.3V supply, but will operate from a signifigantly lower voltage. I have heard reports successful operation at as low as 1.8v, but have not tested this myself.
Note that the device is not 5V tolerant. Level conversion is required when interfacing with 5V devices.
TXD and RXD are the serial transmit and receive lines.
CH_PD is the chip enable line. This should be pulled high.
A low pulse on RST will reset the device.
If GPIO0 is pulled low on startup, the device will enter its bootloader mode whereby FLASH data can be uploaded via the serial port. For normal operation it should be pulled high (or left floating).
If GPIO2 is low on startup, the device will not start. For normal operation, it should be pulled high (or left floating).
If GPI00 or GPIO2 are being used as outputs, care needs to be taken that they are not being pulled low by the circuitry that they are connected to.
2. Connecting to the Serial Port
As mentioned above, the TXD and RXD lines need to be driven with 3.3v logic levels, so a max2323 module (with 3.3v Vcc) can be used to conver theses level to RS232.
Alternatively, if a USB to serial converter is used, it must be one that is capable of 3.3v logic levels, such as the one shown at left which is labeled CP2102. The solder pad marked with the yellow line near top is bridged to set the level to 3.3v.
The TXD and RXD lines need to be crossed. That is, TXD on the USB module nees to be connected to RXD on the ESP8266 module, and RXD to TXD.
Note that the USB to serial converter cannot supply enough current via it’s Vcc pin to operate the ESP8266. A seperate power supply must be used.
3. Testing the Module: AT Commands
The module is supplied with the ‘AT’ firmware which allows it to be controlled via AT commands issued over the serial port (similiar to old modems). The idea being that an Aurdino etc can WIFI-enable itself by issuing commands to the ESP8266, but this seems kind of pointless given that the ESP8266 is a much more powerful processor; by installing custom firmware on the ESP8266, the Aurdino more or less becomes unnecessary.
Anyway, we’ll use AT commands here to connect the ESP8266 to the local WIFI and test that everything it is working.
Connect the modules as shown, and configure your serial terminal program for 115200,N,8,0. (Apparently, some older modules use 9600 baud).
RST pin (not shown on diagram) should also be connected to 3.3V, although I found that things still worked when it was left floating.
For a quick lash up, ‘dupont’ style jumper cables work fine.
3.1. Initial Test
By default, the AT firmware is configured to initialise the ESP8266 as a WIFI access point, and it includes a DHCP server to assign IP numbers to the devices that connect to it.
Listing the local access points shows that the ESP8266 is working as expected, with ssid of ESP_9D915B:
~>sudo iwlist scan | grep ssid -i
Using NetworkManager (or whatever you use to connect your PC to an access point) we can connect to the ESP_9D915B access point, and check that an IP number has been assigned, and then we can ping the ESP8266:
wlan0 Link encap:Ethernet HWaddr 1c:4b:d6:78:6b:8d inet addr:192.168.4.2 Bcast:192.168.4.255 Mask:255.255.255.0 inet6 addr: fe80::1e4b:d6ff:fe78:6b8d/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:705438 errors:0 dropped:0 overruns:0 frame:0 TX packets:590920 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:688774640 (688.7 MB) TX bytes:112196991 (112.1 MB)
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.4.1 0.0.0.0 UG 0 0 0 wlan0
192.168.4.0 0.0.0.0 255.255.255.0 U 9 0 0 wlan0
PING 192.168.4.1 (192.168.4.1) 56(84) bytes of data.
64 bytes from 192.168.4.1: icmp_seq=1 ttl=64 time=0.143 ms
The ESP8266 has IP number 192.168.4.1 and has assigned the PC 192.168.4.2 and all is well.
3.2. Connecting the ESP8266 to an Access Point.
To configure the ESP8266 to connect to a local access point, we use a terminal program (such as minicom) to send AT commands to the ESP8266 via its serial port.
Note that the AT firmware expects lines to be terminated with the two character sequence ‘\r\n’,
so you may need to configure the terminal program to automatically append the ‘\n’.
I could not get this to work when using minicom on Linux, but found that typing CTRL-M CTRL-J to end the line was a satisfactory workaround.
If you now type
AT followed by ENTER (or CTRL-M CTRL-J) into the terminal program, you should see the ESP8266 respond with an
You can now try some other AT commands:
AT+RSTto reset the device.
AT+GMRto show the firware versions
The ESP8266 can be configured as a WIFI access-point, a station, or both. To prepare for connection to the local access-point, issue the command
AT+CWMODE=3, which sets it to be both. Then, the
AT+CWLAP command causes the ESP8266 to list the nearby networks:
Which shows the encryption method, the ssid string, the rssi (signal strength) in dBm, the mac address, and the channel number.
Finally, we connect to the local access-point with the command:
The LAN runs dhcp, so we check that an IP address has been assigned with
To set a static IP, use the
AT+CIPSTA="192.168.101.108" command. It is unclear on how the gateway and netmask etc are set, but persumably this is possible.
Note that the AT firmware saves the settings in the ESP8266’s flash memory, meaning that configuration is retained after the device is reset.
It is further possible to use other AT commands to configure the ESP8266 to connect to a TCP or UDP host as a client, or to act as a server. See here for the full list of AT commands.
4. Cross Compiler Tools and C SDK Installation.
Espressif, the ESP8266’s manufacturer, provide the source code for the gcc cross-compiler tool chain, and for their C SDK (Note that some parts of the SDK are closed source, and distributed as object code only).
Unfortunately, due to its relative newness and being rapidly changing, installing it all is quite fiddly, error prone, and tedious, but fortunately, pfalcon has come to the rescue and combined everything into his single esp-open-sdk package which can be installed on Linux quite effortlessly. We will be using it here.
First, we need to ensure that the standard GNU development tools are installed. For Ubuntu 14.04:
>sudo apt-get install make unrar autoconf automake libtool gcc g++ gperf \
flex bison texinfo gawk ncurses-dev libexpat-dev python sed
Create a directory for everything to go in:
Then, download, build and install:
>git clone https://github.com/pfalcon/esp-open-sdk
This will take some time, but when it is done everything is installed in the
esp-open-sdk subdirectory, which has three important subdirectories:
esptool which we will look at now.
gcc and the other GNU tool chain utilities. The
bin/ directory should be added to the search path, with something like this:
This contains the SDK and the various other bits and pieces required to build user applications:
- As usual,
lib/subdirectories contain the C header files and the object-code library files.
- PDF documentation for the API is in the
examples/atsubdirectory contains the source code for the AT firmware that we were using previously.
examples/IoT_Demodemonstrates the use of much of the API and the device’s capabilities- very handy to base your code on, especially when first starting out.
bin/subdirectory contains the ESP8266 binary files, ready for uploading to the device. We’ll look closer at these in the next section
This contains the
esptool.py python utility which is the community-developed tool used for uploading the binaries to the ESP8266’s flash memory, as well as for assembling the binaries from the gcc-generated
elf-format files. For ease of access, you can copy
/usr/bin/local or somewhere else on the search path.
Note that Espressif provide their own
esptool (a binary exe and without the .py extension) which works similiary to
esptool.py but is not as fully featured.
esp-open-skd has replaced its use with
esptool.py. You might come across it if you are compiling third-party applications, so don’t get confused.
4.3.1. Flashing Code to the Device
For practise, we’ll reflash the device with the AT firmware which is in the
bin/at subdirectory. First, put the ESP8266 into bootloader mode by pulling GPIO0 line low, and reset, and then:
>esptool.py write_flash 0x00000 boot_v1.2.bin 0x01000 at/user1.512.new.bin 0x3e000 blank.bin 0x7e000 blank.bin
boot_v1.2.bin is the Espressif SDK and other operating-system like code, and it gets written to the device’s flash starting at address 0×00000; as far as I know, this only has to be reflashed if Espressif release a new version of the SDK for example.
at/user1.512.new.bin is the user application code, being the AT firmware in this case, and it is written starting at address 0×01000. The application code should always be written at this address.
blank.bin file contains all 0xFF bytes and is the size of one flash sector of 4096 bytes. It is written to the addresses wherein the flash needs to be erased. The 0×7e000 sector is used by the SDK to store it persistent data, and presumably 0×3e000 is used by the AT application.
5. Development Jig
When frequently flashing during development, plugging wires in and out quickly became tedious so I decided to build the little board described here so I could just flick a switch and push reset instead.
The reset line is pulled up gently via the 10k resistor as the capacitor charges, this should prevent any problems with voltage spikes etc when the power is applied. The push button across the capacitor is used to reset the device.
The toggle switch selects between flash mode and normal running mode. To change mode, the switch is set to the appropiate position and then the reset button is pushed.
The 10k pullup and push button on the GPIO2 line isn’t necessary, but might come in handy.
The jig was knocked up quickly on a piece of matrix board using point-to-point wire-wrap-and-solder technique.
The module mounts into two rows of 4-pin female pin-headers set adjacent to each other, which allow for easy insertion and removal.
There is space at right to add adapters for the various other ESP8266 modules.
6. NodeMCU Lua Interpreter
NodeMCU is a Lua interpreter that runs on the ESP8266. It allows for rapid development of simple applications in an Aurdino like manner, and without the overhead of having to get up to speed with the C API. For many small, non-speed critical applications, such as my telnet controlled relay, it would appear to be a good choice. It is currently under constant development, with new features being added frequently.
Installing it is as simple as:
>git clone https://github.com/nodemcu/nodemcu-firmware.git
then, reset the device into flash mode, and:
then, with serial connected and set to 9600 baud, reset the device and you should be greeted with the lua prompt and you can start typing in commands:
NodeMCU 0.9.5 build 20150213 powered by Lua 5.1.4
lua: cannot open init.lua
> print("hello lua")
> > print(node.heap())
The node.heap() method shows that there is 21kB available for our Lua programs.
To connect to access point:
Note that the wifi settings stored in the flash memory and are retained across device resets.
See the GitHub readme for lots of code snippets demonstrating NocdeMCU’s features; a rudimentry webserver can be implemented in half a dozen or so lines. The API Documentaion is available also on GitHub.
6.1. Developing Applications with NodeMCU
As, no doubt, can be imagined, when trying to develop an application by constantly typing in lua commands, or trying to cut-and-paste, at the serial console is a very painful experience, but NodeMCU helps us withh its spiffs flash file-system which allows for Lua code to be stored in the files and loaded as required.
A file can be written and then executed with something like:
> file.open("heap.lua", "a+")
luatool: Automating File Uploads
4refr0nt has written the luatool python utility that allows for lua source code files to be rapidly uploaded to the the device. It works by simply encasing the source file’s contents in
file.write('') calls which are written to the device’s serial port, just as if you had typed them, but much quicker of course.
>luatool.py --port /dev/ttyUSB0 --src main.lua --dest main.lua --verbose
->file.open("main.lua", "w+") -> ok
->file.writeline([[ip = wifi.sta.getip()]]) -> ok
->file.writeline([[print(ip))]]) -> ok
->file.flush() -> ok
->file.close() -> ok
luatool-src: Uploading Lua Code
I’ve hacked the
luatool to allow it to upload Lua source files directly to the interpreter, ie not write it to a file, and just as if you had typed each line. It’s avaliable here.
>luatool-src.py -f test.lua
->function hello(name) -> ok
->print ("hello "+name) -> ok
->end -> ok
--->>> All done <<<---
6.1.3. Development Process
While writing code, I found it easiest to use
luatool-src.py to upload the function, class, or whatever that you are currently working on, then, when it is debugged and finished, use
luatool to write it as a file to flash, and then repeat until the application is completed.
At startup, NodeMCU will automatically call the file
init.lua if it exists, and hence to automatically start the application. One thing to watch out for is that if an error in
init.lua causes the device to reset, then it will just continue on in a reset loop until you reflash the device.
To avoid this situation, it is handy to use a timer to give a few seconds delay before calling the main program. If there is a problem, then during this delay it is possible to quickly paste
file.remove('init.lua') into the terminal, which will give you back control after the next restart. For example, in
print ("Starting in ".. 7 .." seconds ...")
tmr.alarm(1,7000, 0, dofile("broken.lua"))
6.1.5. Compiling .lua Files to .lc Lua Bytecode
.lua file is stored in the flash, the NodeMCU lua compiler can be called to write a corresponding
.lc lua-bytecode file. A
.lc file will load faster and use less heap memory than an
.lua file. For example:
6.1.6. Using the C Preprocessor
Lua, being intended for small, embedded systems doesn’t include niceties like being able to define constants or conditional compilation, for example. I have found it useful to name my source files with a
.lpp extension and then include C preprocessor directives such as
#define along with the Lua code. The
Makefile, then runs the
.lpp files though the preprocessor to generate the
.lua files. Like this:
LPP_SOURCES=cmd.lpp startup.lpp init.lua control.lpp
%.lua: %.lpp (cpp | grep -v ‘^#’) > $@ < $<
I hope that by documenting my getting up to speed with the ESP8266 will help others do similiarly, but without the time involved with having to source all the required information from various sources. Please leave a comment via the link below to let me know how you go, or if you have questions, or corrections etc.