Home > Espressif, Hardware, Testing > How to Write ESP8266 Firmware from Scratch (using ESP Bare Metal SDK and C Language)

How to Write ESP8266 Firmware from Scratch (using ESP Bare Metal SDK and C Language)

CNXSoft: This is a guest post by Alexander Alashkin, software engineer in Cesanta, working on Mongoose Embedded Web Server.

Espressif’s ESP8266 had quite an evolution. Some may even call it controversial. It all started with ESP8266 being a WiFi module with a basic UART interface. But later it became clear that it’s powerful enough for embedded system. It’s essentially a module that can be used for running full-fledged applications.


Espressif realized this as well and released an SDK. As first versions go, it was full of bugs but since has become significantly better. Another SDK was released which offered FreeRTOS ported to ESP. Here, I want to talk about the non-OS version. Of course, there are third-party firmwares which offer support for script language to simplify development (just Google for these), but ESP8266 is still a microchip (emphasis on MICRO) and using script language might be overkill. So what we are going to come back to is the ESP SDK and bare C. You’ll be surprised, it’s easier than it looks!

First steps

To develop firmware you’ll need:

  1. ESP8266 connected to your computer via USB.
    There are a lot of articles how to connect an ESP to a computer. You will need several Dupont cables and a UART-to-USB adapter. If you have a Arduino board you can use it as UART-to-USB. Google “connect esp8266 to computer” – there are a lot of articles about this.
  1. SDK.  I suggest using this one: https://github.com/pfalcon/esp-open-sdk

Download it and follow its readme to build. There is nothing extraordinary in this process, all you need is to install prerequisites and invoke “make”.

In general, this SDK is intended for *nix systems, but there is a port for Windows as well.

In short, to start development you should have an ESP device available as /dev/ttyUSB0 (/dev/ttyACM0 if you use Arduino or COMn in Windows) and the SDK installed in a certain path.


In C int main() is an entry point to a program. But, in the case of ESP the entry point is void user_init(). This function must be used only for initialization, not for long-running logic.

Here an example:

Note, that all we do in user_init is calling the system_init_done_cb API function. This function accepts one parameter, which is a pointer to function which will be called once all system modules will be properly initialized. You can put your initialization code in user_init too, but you can face problems with some system function (like WiFi), just because appropriate modules aren’t initialized yet. Thus, it is better to use system_init_done_cb and perform initialization in the callback function.

Beware of the dog

ESP8266 has a watchdog functionality. And there is NO documented API to control it (there is some undocumented stuff, but out of scope for this tutorial). Its timeout is 1 second.

What does that mean? It means, that you have to return the control flow to system every second, otherwise the device will be rebooted. This code leads to the device reboot:

In general, watchdog is not evil, it helps if the program hangs. And, 1 second is not so small as it sounds. Just keep this fact in mind.

Doing something

Taking what we learned about the watchdog into account, we face an obvious question: where can I run my tasks?

The simplest answer is in timers. The timer API is very simple in ESP.

If the last parameter of the os_time_arm function is 0, the timer callback will be invoked only once. If it’s 1, it will be called repeatedly until the os_timer_disarm is called.

And, finally, we have a place to put our code: The start_timer_cb function.

Our task here is to make an LED blink. Some ESP boards have an LED attached to GPIO16, if your board doesn’t have it, you can attach an LED to any free GPIO.

As you remember start_timer_cb is a timer callback function, and it is called every 5 seconds. On first call on variable is 0 and we set GPIO16 to high – as result LED will be turned on. On second call we set GPIO16 to low – and LED is turned off. And so on and so on.

Building the project

Now it is time to build our project. Let’s say, we have only one source file – main.c. I cannot recommend using makefiles which are used for building examples. They are too complicated and a bit weird. So, I’d suggest to write your own (simple!) makefile.

Here are steps:

  1. Compile main.c to main.o.
    Use xtensa-lx106-elf-gcc compiler which is a part of esp-open-sdk.
  2. Link project.
    Linker to use – the same xtensa-lx106-elf-gcc. Libraries to link with are: c gcc hal m pp phy net80211 wpa main

Also, you need to supply the linker script (.ld file). Choose one from esp-open-sdk that matches the flash size of your device. After this step you’ll have .elf file.

  1. Convert .elf file to .bin

For this, use esptool.py script from esp-open-sdk. Run it like this:

If everything is ok, you should have 3 files in <output dir> with names like 0x00000.bin, 0x11000.bin 0x66000.bin.


The final step is to put our firmware onto the device. For this we will use the esptool again, but now we should use write_flash option. Like this:

You should use real filenames from the previous step. And, if everything is still OK, the LED attached to the device will start to blink every 5 seconds.

Next steps

Writing the firmware for any device is a huge topic. Working with ESP8266 is no exception. So, the purpose of this article is only to highlight the direction. There are a lot of different APIs in the ESP8266 SDK: WiFi, GPIO, TCP/UDP and more. Make sure to check out the documentation fully here. It’s also good to check out the examples by firmware providers and esp-open-sdk. If you want to start with an example, check out this one which goes through running Mongoose Embedded Web Server on ESP8266.

  1. October 7th, 2016 at 16:53 | #1

    Checkout esp-link, it is a good base to start with, it has already many features, you could be inspired by their makefiles etc…

  2. Narog
    October 7th, 2016 at 17:30 | #2

    From the same guy of esp-link check the Espruino port for ESP8266.



  3. Harley
    October 7th, 2016 at 17:35 | #3

    If someone is looking for a more out-of-the-box firmware or a firmware to improve on then can recommend ESP Easy (by ESP8266nu team)




    Hint to CNXSoft; Hard to find good reviews of the ESPEasy firmware by ESP8266.nu 😉

    Another somewhat similar firmware that is not as polished is Espurna https://bitbucket.org/xoseperez/espurna as made by Xose “Tinkerman” Pérez http://tinkerman.cat/tag/sonoff/

  4. October 7th, 2016 at 18:15 | #4

    Thanks for the comments guys – appreciate it! So I work with Mongoose Embedded Web Server and Mongoose IoT Platform and yeah, there is some out of the box stuff there. So you can get IoT ready in just a few minutes really.

  5. Hòa Tiến
    October 7th, 2016 at 21:58 | #5

    HI Alexander Alashkin!
    Please post mode guide, i interested in ESP SDK to build fw. Thanks very much your guide. I very happy.

  6. October 8th, 2016 at 05:06 | #6

    Great job !!!

  7. Drone
    October 10th, 2016 at 12:58 | #7

    Who decided jumper wires and ribbon cables were suddenly named “Dupont” cables? Is that some kind of Maker thing?

  8. October 10th, 2016 at 20:04 | #8

    I was asked about Mongoose.

    In short:
    Mongoose Firmware provides a professional grade firmware for ESP8266 – quick start is at https://mongoose-iot.com/docs/#/quickstart/

  9. December 28th, 2016 at 08:30 | #9

    I love the wemos boards! Thanks for the great tutorial!

  1. No trackbacks yet.