Getting started with ESP8266 12E (AI Thinker IoT WIFI module)

I decided to write this down for multiple reasons, but mainly because I have spent a bit of time to dig through this and get started.

First of all, this will only work if you are using this module in particular:

If you're working on a different module - you probably want to read, but do a bit more research yourself. The above is the ESP8266 12E module i've been trying to get to work for past few days.

The module itself comes with a flashed image that works sort of like an old AT modem. Once it boots up, it will start talking over UART (top left two yellow cables on the image) at 115200bps, 8n1. You can use this default image to do the basic programming with arduino etc, but - let's face it: this module is fine working all by itself, and having an arduino controlling it is in most cases pointless; there are GPIO pins available on this baby, there is I2C interface, it draws very little power etc etc.

OK, to the point.

This tool requires 3.3V supply and if you supply 5V well it might work for a while, but no promises. I used 5V with mine for a while and it still works, but I suspect only because i never got it running at this higher voltage for too long.

Wiring is important here. Typically you will want to connect it like this:

VCC = 3.3V
GPIO2 (~LED), RST - Pull up,
GPIO15 - Pull down,
RXD, TXD - to TXD and RXD of your UART endpoint.

Finally, there's GPIO0 (~FLASH), which is used to either boot flash bootrom (GND) or user code (VCC). You will likely want to have a look at datasheet; table 4 is particularly useful.

First and foremost: the bootrom of this baby talks at 74880bps. Yes, you read this right: 74880bps. Most of the tools I tried failed to set the /dev/ttyS0 to this, well, unusual speed. All except for miniterm.py command, that was delivered with python-serial (or pyserial) debian package. This tool is capable of talking 74880bps even on Rasberry Pi, so it's quite good. Why is this important? Well, each time you need to reflash your card or diagnose a (likely) reboot cycle, you need to be able to switch your serial port to 74880bps.


Install this SDK: https://github.com/pfalcon/esp-open-sdk
It comes with everything you would need to get started. There's even a 'blinky' example code that you will want to deploy to your ESP8266. It shows how to write and compile C code for that unit.

Installation takes about 90 minutes on Raspberry Pi. The installer there builds compiler, libraries and tools, and, well, it takes time, but it's worth it. If you haven't already, go get it.


Once you have the toolchain (compiler, linker, ...) available, let's try to build and deploy blinker. It sounds like it's a simple job, but it isn't necessarily.

Inside the esp-open-sdk folder there's 'examples/blinky' project that builds and installs with makefile.
You will want to make a few modifications there:

1. modify 'flash:' target and add parameter --baud 460800 to esptool. You may also want to specify --port /dev/tty## or the like

2. modify 'flash:' target to flash one image extra: append '0x3fc000 esp_init_data_default.bin' at the end. Get the binary file from here. Now this is important to get you past RF calibration. If you're seeing reboot cycle with error:

rf_cal[0] !=0x05,is 0xFF

it is for that exact reason, that your init data file cannot be found by the boot rom. This question explains it in greater detail.

Done? Connect GPIO0 to GND and execute: make clean && make flash.  Finally, connect the GPIO0 to VCC and power-cycle your unit. The led should start blinking.


When building your usercode you may end up seeing a weird flash error that tells you your binary is too large to be flashed to the card. The error indicating this is:

region `iram1_0_seg' overflowed by ...

I hit that after adding maybe 5LOC that were essentially debug prints. Soon after I read I may need to add a compiler flag: -DICACHE_FLASH to get past this error.


If you are stuck and you think you bricked your unit don't fret. I thought I killed mine several times already and it still works. You just need to revert all your changes. You can download the necessary files from github and flash them back to your module. Just bind the GPIO0 to GND and use esptool.py to reflash it:

esptool.py --port /dev/ttyS0 --baud 460800 write_flash 0 boot_v1.1.bin 0x1000 user1.bin 0x7c000 esp_init_data_default.bin 0x7e000 blank.bin

I am not fully confident if the 0x7c000 is the right address for init_data.bin and whether 0x7e000 is the right address for blank.bin. If you are stuck in boot loop despite the above, chances are you should use a different address as explained here: that would be

esptool.py --port /dev/ttyS0 --baud 460800 write_flash 0 boot_v1.1.bin 0x1000 user1.bin 0x3fc000 esp_init_data_default.bin 0x3fe000 blank.bin

When the above works, you will see your unit talk at 115200 over serial port again, and serving your AT commands. More details about this are on NodeMCU website.


You may be tempted to write C++ code now that there's a C++ compiler bundled in, too. It's not going to be simple: the SDK does not include most of the library calls. These calls exist, of course, and can be easily linked by the C compiler, but C++ emits and looks up a bit different symbols and needs to know what it's after. This will all certainly be possible once we have the proper header files - or, if you want, you can create one yourself. Sadly, this means creating an extern for every single call that you want to use.

The API Reference for ESP8266 is here.