Saturday, March 31, 2018

A Guide to ESP8266 RTOS-SDK


 # Introduction  


Recently, I have been wanting to play around with my — not heavily used — ESP8266 chips. I know, building the environment to program these little chips is not necessarily a hard task. You can simply open your Arduino IDE, install the Arduino core for ESP8266 WiFi chip and then you are ready to write some code and burn your firmware into the chip, no problem.

That was the first thing I did. Using the examples I suddenly was able to blink some LEDs, to print some "Hello World" messages, etc. The Arduino environment is great and has a huge community around it. However, it is just one of many software platforms available for the ESP8266.

Essentially, the Software Development Kits (SDKs) for the ESPs can be classified into: NON-OS SDK and RTOS SDK. The former provides APIs for functionalities such TCP/IP stack, hardware interfaces and it uses timers and callback functions to perform events and tasks. The later uses a Real-Time Operating System (RTOS) as small-scale operating system to manage multi-threading.

I really wanted to experiment with the official ESP8266 RTOS SDK as it is the native way of programming these chips and supports FreeRTOS. But first, I had to install everything.
  

# Building the Compiler


This step is not that hard, you just clone and make the esp-open-sdk. All the requirements and dependencies are very well documented, just follow the steps given in the repository. Do not forget to keep the command to set PATH variable  at the end of build process

Remark: when building the compiler I had to unset LD_LIBRARY_PATH system variable. The script that builds the compiler will complain if the variable is set.

$ unset LD_LIBRARY_PATH

# Hello World and Blink


First, clone the RTOS SDK repository.

$ git clone https://github.com/espressif/ESP8266_RTOS_SDK.git

Copy the "project_template" folder to your workspace.

$ cp -R ESP8266_RTOS_SDK/examples/project_template YOUR_WORKSPACE_PATH/hello_project

Open  ./gen_misc.sh file (or .bat for Windows). Insert the PATH command you previously saved and modify the SDK_PATH and BIN_PATH variables. Save it.

$ export PATH=YOUR_PATH_TO/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
$ export SDK_PATH=YOUR_PATH_TO/ESP8266_RTOS_SDK
$ export BIN_PATH=YOUR_PATH_TO/ESP8266_RTOS_SDK/bin

In this example we will need to use the uart and gpio APIs. To use them, we need to build the driverlib.

$ cd ESP8266_RTOS_SDK/driver_lib
$ ./make_lib driver

Copy the driver folder to your project folder.

$ cp -R ./driver YOUR_WORKSPACE_PATH/hello_project

Go back to the "hello_project" folder and modify the Makefile.
Add the "driver" folder to SUBDIRS.

SUBDIRS=    \
user        \
sample_lib  \
driver      \ 


Add the libdriver.a to COMPONENTS_eagle.app.v6.

COMPONENTS_eagle.app.v6 =   \
user/libuser.a              \
sample_lib/libsample.a      \
driver/libdriver.a

Save it.

Finally, open the "user/user_main.c" file.

#include "esp_common.h"
#include <stdio.h>
#include "uart.h"
#include "gpio.h"

uint32 user_rf_cal_sector_set(void)
{
    flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;
        case FLASH_SIZE_64M_MAP_1024_1024:
            rf_cal_sec = 2048 - 5;
            break;
        case FLASH_SIZE_128M_MAP_1024_1024:
            rf_cal_sec = 4096 - 5;
            break;
        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}


// Printf hello world every two seconds
void hello(void *pvParameters) 
{ 
    while(1)
    {
        printf("Hello multi-threading world!\r\n");
        vTaskDelay(2000/portTICK_RATE_MS);
    }
    vTaskDelete(NULL); 
}

// Blink the led @1Hz
void blink(void *pvParameters) 
{ 
    while (1) 
    {
        printf("[LED] On\r\n");
        GPIO_OUTPUT_SET(2, 1);
        vTaskDelay(500/portTICK_RATE_MS);

        printf("[LED] Off\r\n");
        GPIO_OUTPUT_SET(2, 0);
        vTaskDelay(500/portTICK_RATE_MS);
    } 
    vTaskDelete(NULL); 
}

// "Main" function
void user_init(void)
{
    // Change the default value of the baudrate to 115200 (printf uses UART0)
    UART_SetBaudrate(UART0, BIT_RATE_115200); 
    // GPIO2 set as IO
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
    // Hello and Blink tasks
    xTaskCreate(hello, "hello", 256, NULL, 2, NULL); 
    xTaskCreate(blink, "blink", 256, NULL, 2, NULL); 
}

Alright, everything is ready now. It is time to compile our code!

# Compiling


Again, cd to your "hello_project" folder and run "gen_misc.sh".

$ ./gen_misc.sh

Press 'Y' to start the process. You will be prompted some parameters, choose the options that suit your specific ESP8266 chip.

In my case the chip runs at 80MHz and has 4MB of flash memory. 

Please check SDK_PATH & BIN_PATH, enter (Y/y) to continue:
Y

STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)
enter (0/1/2, default 0):
0 
 
STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)
enter (0/1/2/3, default 2):
3

STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)
enter (0/1/2/3, default 0):
2 
 
STEP 5: choose spi size and map
    0= 512KB( 256KB+ 256KB)
    2=1024KB( 512KB+ 512KB)
    3=2048KB( 512KB+ 512KB)
    4=4096KB( 512KB+ 512KB)
    5=2048KB(1024KB+1024KB)
    6=4096KB(1024KB+1024KB)
    7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board
    8=8192KB(1024KB+1024KB)
    9=16384KB(1024KB+1024KB)
enter (0/2/3/4/5/6/7/8/9, default 0):
6

Notice that the parameters you choose depends on the chip you are using!

After a lot of output you will see:

Generate eagle.flash.bin and eagle.irom0text.bin successully in BIN_PATH
eagle.flash.bin-------->0x00000
eagle.irom0text.bin---->0x20000
!!!

Great! You've done it!
Now you just need to flash your new firmware into the chip.

# Downloading the Firmware



Let's install esptool the easy way.

$ pip install esptool

Now run the flashing command and download your firmware. 

$ esptool.py -p /dev/ttyUSB0 -b 115200 write_flash -fs 4MB -fm dio 0x0 ../bin/eagle.flash.bin 0x20000 ../bin/eagle.irom0text.bin 

Again, you must adapt the command above to suit your chip.
  • -p: USB Port (COM ports for Windows);
  • -b: Baudrate;
  • write_flash: esptool command to write the firmware into the flash memory;
  • -fs: flash size (4 MB in my case);
  • -fm: flash mode (the datasheet of your part should describe the mode);

If you are having any issue, make sure you are using the correct flags for your chip and read the esptool docs.

$ esptool.py -p /dev/ttyUSB0 -b 115200 write_flash -fs 4MB -fm dio 0x00000 ../bin/eagle.flash.bin 0x20000 ../bin/eagle.irom0text.bin 
esptool.py v2.3.1
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash params set to 0x024f
Compressed 32896 bytes to 23098...
Wrote 32896 bytes (23098 compressed) at 0x00000000 in 2.1 seconds (effective 128.3 kbit/s)...
Hash of data verified.
Compressed 244728 bytes to 176155...
Wrote 244728 bytes (176155 compressed) at 0x00020000 in 15.6 seconds (effective 125.8 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

# Results


After flashing the LED starts blinking.


Let's check our USB port.

$ minicom -D /dev/ttyUSB0 -b 115200

We can see the messages sent by the ESP8266. It Works!

connected with MY_WIFI, channel 9
dhcp client start...
[LED] Off
[LED] On
[LED] Off
Hello multi-threading world!
[LED] On
[LED] Off
[LED] On
[LED] Off
Hello multi-threading world!

Yay! The LED attached to GPIO 2 is blinking and we are getting our messages! Success!
 

No comments:

Post a Comment