I had some troubles setting up a development environtment using the RTOS-SDK. There are a number of options I have tried but they all seem to complicated for me. For me it is important to understand what is happening all the way from compiling, linking and deploying the executable.
I tried the official RTOS SDK from expressif and the esp-open-rtos SDK. I had troubles getting them to work, I guess mainly because I prefer working in Windows. For me I also think that their build system are to complicated, but maybe I am just stupid.
For me a development environment should be quite simple:
- Toolchain (compiler and linker)
- Build automation tool (for instance make)
- A tool to transfer the executable image to ESP8266
- An SDK for the target plattform
- An editor of some sort to edit code.
You develop some code, build it (compile and link), and then build an executable and transfer to development environment. Every step should be easy to understand, and of course as the project becomes more complicated, the build process will be more complicated, but I want a really simple project (f.i. “Hello World”) to have a really simple build system in order to understand every detail of it.
Let me explain how my system is setup.
Please note that you have to use an x64 version of windows for this setup to work, this is because the prebuilt compiler is x64.
First of all we must have a toolchain. When you try google it you will find numerous sites describing how you build it from source. That is probably very easy using a Linux workstation of some sort, but I always have troubles doing that on Windows. I would rather just download prebuild binaries from somewhere.
Eventually I found prebuilt binaries (build for x64): xtensa-lx106-elf-141114.7z
Download and extract to a folder, mine is: c:\xtensa-lx106-elf
Make sure to add bin folder to your PATH.
Install MinGW which is a minimal build environment for gcc, make sure to a add bin folder to your path.
Tool to transfer firmware to ESP8266 (esptool.py)
There is an excelent tool created in python to communicate with the ESP8266, to be able to use it we have to install python.
Please NOTE, install Python 2 (and not Python 3)
And also the tool (this is a single python file, save to some good place:, mine is:C:\projekt\esp8266\esptool.py) : esptool.py
Obtain the RTOS-SDK from expressif. I have cloned it by using git, which is very convinient when updating, but you can also just download it from github
First install git
.. and then clone the RTOS-SDK from expressif.
- Create a directory where you want the SDK, mine is c:\project\esp8266\SDK
- start cmd.exe
- And execute: git clone https://github.com/espressif/ESP8266_RTOS_SDK.git
You can use any texteditor that you want (even notepad), but I use ConText It is very lightweight, but still have code highligt for C/C++ (and many other languages)
Making it all work!
Ok, that was hopefully quite simple. Now we will make it all work.
The process of getting your code to work on the ESP8266 includes the following steps:
- Write the source
- Compile the source to object files
- Link your object file with object files from the SDK to produce a binary image
- Extract the parts from the binary image which should land in different areas of the ESP8266 memory space
- Transfer the parts to the ESP8266
All these steps is done by using a makefile. I have a makefile which I use for every project i write, and it is based on a Makefile I found somewhere. I am really sorry that I cannot remeber where I found it, I would really like to give the original author credit, since this was the part I had most trouble with trying the official SDK and open SDK.
Here it is:
# Com port to dev board
PORT = COM3
SDKBASE = C:/esp8266/SDK/ESP8266_RTOS_SDK
PYTHON = C:/Python27/python.exe
ESPTOOLPY = C:/esp8266/tools/esptool/esptool.py
TOOLCHAINHOME = C:/esp8266/xtensa-lx106-elf
AR = xtensa-lx106-elf-ar
CC = xtensa-lx106-elf-gcc
CPP = xtensa-lx106-elf-gcc
LD = xtensa-lx106-elf-gcc
NM = xt-nm
OBJCOPY = xtensa-lx106-elf-objcopy
OD = xtensa-lx106-elf-objdump
ESPTOOL ?= $(PYTHON) $(ESPTOOLPY)
INCLUDES = -I $(SDKBASE)/include
INCLUDES += -I $(SDKBASE)/include/espressif
INCLUDES += -I $(SDKBASE)/extra_include
INCLUDES += -I $(SDKBASE)/include/lwip
INCLUDES += -I $(SDKBASE)/include/lwip/lwip
INCLUDES += -I $(SDKBASE)/include/lwip/ipv4
INCLUDES += -I $(SDKBASE)/include/lwip/ipv6
INCLUDES += -I $(TOOLCHAINHOME)/xtensa-lx106-elf/include
# don’t change -Os (or add other -O options) otherwise FLASHMEM and FSTR data will be duplicated in RAM
CFLAGS = -g -save-temps -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals
CFLAGS += -D__ets__
CFLAGS += -DICACHE_FLASH
CFLAGS += -fno-exceptions
#CFLAGS += -fno-threadsafe-statics
#CFLAGS += -fno-use-cxa-atexit
LDFLAGS = -nostdlib -Wl,–no-check-sections -u call_user_start -Wl,-static
LDFLAGS += -Wl,–gc-sections
LD_SCRIPT = eagle.app.v6.ld
#LD_SCRIPT = eagle.app.v6.new.2048.ld
SDK_LIBDIR = -L$(SDKBASE)/lib
SDK_LDDIR = $(SDKBASE)/ld
# linking libgccirom.a instead of libgcc.a causes reset when working with flash memory (ie spi_flash_erase_sector)
# linking libcirom.a causes conflicts with come std c routines (like strstr, strchr…)
LIBS = -lmain -lgcc -lfreertos -lnet80211 -lphy -lwpa -lcrypto -llwip -lpp -lminic -lhal
#-lminic -lm -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lmain -lfreertos -llwip -lcrypto
OBJ = user_main.o
SRCDIR = ./src/
TARGET_OUT = app.out
.PHONY: all flash clean flashweb flashdump flasherase
$(LD) $(SDK_LIBDIR) -T$(SDK_LDDIR)/$(LD_SCRIPT) -Wl,-M >out.map $(LDFLAGS) -Wl,–start-group $(LIBS) libuser.a -Wl,–end-group -o $@
@$(OD) -h -j .data -j .rodata -j .bss -j .text -j .irom0.text $@
@$(OD) -t -j .text $@ >_text_content.map
@$(OD) -t -j .irom0.text $@ >_irom0_text_content.map
@$(ESPTOOL) elf2image $@
$(AR) cru $@ $^
%.o: $(SRCDIR)%.c $(wildcard $(SRCDIR)*.h)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
%.o: $(SRCDIR)%.cpp $(wildcard $(SRCDIR)*.h)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
flash: $(TARGET_OUT)-0x00000.bin $(TARGET_OUT)-0x20000.bin
@-$(ESPTOOL) –port $(PORT) write_flash 0x00000 $(TARGET_OUT)-0x00000.bin 0x20000 $(TARGET_OUT)-0x20000.bin
# @python binarydir.py $(WEBDIR) webcontent.bin $(MAXWEBCONTENT)
# @-$(ESPTOOL) –port $(PORT) write_flash $(WEBCONTENTADDRS) webcontent.bin
@-$(ESPTOOL) –port $(PORT) read_flash 0x0000 0x80000 flash.dump
@xxd flash.dump > flash.hex
@-$(ESPTOOL) –port $(PORT) erase_flash
@rm -f *.a
@rm -f *.o
@rm -f *.out
@rm -f *.bin
@rm -f *.ii
@rm -f *.s
@rm -f *.expand
@rm -f *.map
@rm -f *.dump
@rm -f *.hex
Ok, lets test it all.
- Create a folder for your project, mine is c:\project\test1
- Create a new empty textfile and name it “Makefile” (no suffix), and copy the above content to it.
- Create a new folder named “src”, mine is c:\project\test1\src
- Create a new sourcefile within that folder, named user_main.cpp, mine is:c:\project\test1\src\user_main.cpp
Add the following to it:
extern void uart_div_modify(int,int);
* Simple task that prints "Hello world" every second
void helloTask(void *pvParameters)
vTaskDelay(1000 / portTICK_RATE_MS);
* This is entry point for user code
void ICACHE_FLASH_ATTR user_init(void)
// Set UART speed to 115200
uart_div_modify(0, UART_CLK_FREQ / 115200);
ret = xTaskCreate(helloTask, (const signed char *)"rx", 256, NULL, 2, &t);
And now build it, start cmd.exe.
Go to the folder with your project, mine: c:\project\test1\
And execute command: “make”
xtensa-lx106-elf-gcc -g -save-temps -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -fno-exceptions -I C:/projekt/tester/esp_iot_rtos_sdk/include -I C:/projekt/tester/esp_iot_rtos_sdk/include/espressif -I C:/projekt/tester/esp_iot_rtos_sdk/extra_include -I C:/projekt/tester/esp_iot_rtos_sdk/include/lwip -I C:/projekt/tester/esp_iot_rtos_sdk/include/lwip/lwip -I C:/projekt/tester/esp_iot_rtos_sdk/include/lwip/ipv4 -I C:/projekt/tester/esp_iot_rtos_sdk/include/lwip/ipv6 -I C:/xtensa-lx106-elf/xtensa-lx106-elf/include -c src/user_main.cpp -o user_main.o
xtensa-lx106-elf-ar cru libuser.a user_main.o
xtensa-lx106-elf-gcc -LC:/projekt/tester/esp_iot_rtos_sdk/lib -TC:/projekt/tester/esp_iot_rtos_sdk//ld/eagle.app.v6.ld -Wl,-M >out.map -nostdlib -Wl,–no-check-sections -u call_user_start -Wl,-static -Wl,–gc-sections -Wl,–start-group -lmain -lgcc -lfreertos -lnet80211 -lphy -lwpa -lcrypto -llwip -lpp -lminic -lhal libuser.a -Wl,–end-group -o app.out
app.out: file format elf32-xtensa-le
Idx Name Size VMA LMA File off Algn
0 .data 000003ac 3ffe8000 3ffe8000 000000e0 2**4
CONTENTS, ALLOC, LOAD, DATA
1 .rodata 00000294 3ffe83b0 3ffe83b0 00000490 2**4
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .bss 00006af0 3ffe8648 3ffe8648 00000728 2**4
3 .text 000064cc 40100000 40100000 00000724 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .irom0.text 0003bb88 40220000 40220000 00006bf0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
And now you have the binary blobs ready to transfer to ESP8266. To transfer issue command:
Writing at 0x00000000… (3 %) reply
Writing at 0x00000400… (7 %) reply
Writing at 0x00000800… (11 %) reply
Writing at 0x00000c00… (14 %) reply
Writing at 0x00001000… (18 %) reply
Writing at 0x00001400… (22 %) reply
Writing at 0x00001800… (25 %) reply
Writing at 0x00001c00… (29 %) reply
And then connect your favorite terminal (I use CoolTerm) to COM3 and you vill see “Hello World”!