Skip to content

Instantly share code, notes, and snippets.

@felipeasimos
Created September 16, 2020 16:31
Show Gist options
  • Save felipeasimos/4adfcbeed485a99df62a773da104296b to your computer and use it in GitHub Desktop.
Save felipeasimos/4adfcbeed485a99df62a773da104296b to your computer and use it in GitHub Desktop.
# Nodemcu
sources: \
https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf \
github repos: \
https://github.com/pfalcon/esp-open-sdk
The Nodemcu board purpose is mostly to work as a facilitator for the
use of the esp8266 chip.
## NONOS SDK
The Non-OS SDK provides a set of applications programming interfaces (API)
for core ESP8266 functions.
### Main Components
The main file is `user_main.c`, it is where the `void user_init(void)`
definition should go.
In version 2.0.0 of the SDK, `void user_rf_pre_init(void)` and
`uint32 user_rf_cal_sector_set(void)` also need to be added to
`user_main.c`.
### Code Structure
Since its is an SDK without OS, there is no scheduling
mechanism, and has 4 types of functions:
* __Application Functions__
* Usual C functions, used in embedded C programming.
* Must be called by another function.
* Apllication functions with `ICACHE_FLASH_ATTR` attribute
fetch and execute programs from the flash. `IRAM_ATTR` functions
are stored in iRAM prior to execution.
* __Callback Functions__
* Functions that are not called by directly from the user program.
* Executed by Non-OS SDK core when an event occurs.
* Callback functions are set using the `register_cb` API.
* Callbacks should not occupy the CPU for more than 15 ms.
* Callbacks can't be called more frequently than 5 ms (they
just can't, it isn't fast enough).
* __Interrupt Service Routines (ISRs)__
* Callback functions of special type.
* Called when hardware interrupt occurs.
* Must be attributed as `IRAM_ATTR`.
* __User Tasks__
* Can be classified according to three priority levels: 0, 1, 2.
* Non-OS SDK can support up to 3 tasks at a time, one priority level
per task.
* Set using the `system_os_task()` API.
* Must not take longer than 500 ms.
#### Execution time
IMPORTANT NOTE FROM THE DOCS: "Non-OS SDK does not preempt tasks or
switch context. Users are responsible for the proper execution of
code and the user code must not occupy the CPU on a particular
function for too long. This can cause a watchdog reset and prompt
ESP8266 to reset."
If for some reason a task really must take longer than 500 ms
(this is not the exact value), `system_soft_wdt_feed()` API
must be called to reset the _Watch Dog Timer (WDT)_. Disabling
the _WDT_ is not recommended.
To avoid blocking the CPU, please use the system timer task
instead of using loops.
Try not occupying the CPU for more than 15 ms in callbacks.
### System Performance
* ESP8266 runs at 80 MHz. The CPU can be configured to run
at 160 MHz in high performance applications.
* Higher Clock frequency and disabled sleep modes consume
more energy.
* Code attributed with `ICACHE_FLASH_ATTR` is generally
executed slower than the code marked with `IRAM_ATTR`. However,
like most embedded plataforms, the iRAM is really limited.
* The flash mode and frquency directly impact the
performance. Setting flash to a higher frequency and QIO mode
may perform better, but costs more energy.
### System Memory
* ESP8266 supports primary external QSPI flash memory
of up to 128 Mbits for code and storage. Secondary
chips may also be used for user storage.
* There is no internal non-volatile storage for
code or data.
* 160 KBytes of RAM:
* 64 Kb iRAM (32 Kb for `IRAM_ATTR`, 32 Kb `ICACHE_FLASH_ATTR`).
* 96 Kb dRAM (80Kb for SDK+HEAP, 16 Kb for ROM).
* RAM and flash must be 4 word-aligned.
* Casting pointers directly is not recommended, use `os_memcpy` or other
API instead.
## Setup
We need three things:
* Toolchain, to compile our programs
* Flasher
* SDK
### Toolchain
To facilitate the building of the toolchain, let's clone the
`esp-open-sdk` and use it.
The README.md has all the necessary information for building the
toolchain. There are two main options:
* `make STANDALONE=y` - SDK and Toolchain are "merged". Only the IoT SDK,
that comes with the repository, will be used.
* `make STANDALONE=n` - Toolchain and SDK are build separately.
We will go with the `make STANDALONE=n` option, so we can use other
SDK if we want to.
After that is done (it can take like 30 min), we will add the Xtensa
toolchain to our PATH, so we can call it from anywhere. You many want to
add this to your `.bashrc`:
```
PATH=$PATH:$(ESP_OPEN_SDK)/xtensa-lx106-elf/bin
```
### Flasher
We need a program to flash our code to the ESP8266. We will use `esptool`.
It is really simple to install in some linux distros:
```
pip install esptool.py
```
With it you can erase the chip memory with
`esptool.py --port /dev/ttyUSB0 erase_flash`.
### SDK
Just download the SDK. We will use the SDK files when compiling.
## Compiling
To compile we will modify the `Makefile` of the `blinky` example
in `esp-open-sdk`:
```
SDK_BASE = /home/felipe/Coding/nodemcu/ESP8266_NONOS_SDK_FREEWIFI
INIT_DATA = $(firstword $(wildcard $(SDK_BASE)/bin/esp_init_*default*.bin))
BLANK = $(SDK_BASE)/bin/blank.bin
CC = xtensa-lx106-elf-gcc
CFLAGS = -I. -mlongcalls -I$(SDK_BASE)/include
LDLIBS = -nostdlib -Wl,--start-group -lmain -lnet80211 -lwpa -llwip -lpp -lphy -lc -lssl -lcrypto -Wl,--end-group -lgcc
LDFLAGS = -T$(SDK_BASE)/ld/eagle.app.v6.ld -L$(SDK_BASE)/lib
TARGET = main
$(TARGET)-0x00000.bin: $(TARGET)
esptool.py elf2image $^
$(TARGET): $(TARGET).o
$(TARGET).o: $(TARGET).c
flash: $(TARGET)-0x00000.bin
esptool.py write_flash 0x00000 $(TARGET)-0x00000.bin \
0x10000 $(TARGET)-0x10000.bin \
0x3fb000 $(BLANK) \
0x3fc000 $(INIT_DATA) \
0x3fe000 $(BLANK) \
-fm dio
debug: CFLAGS+= -S
debug:
$(CC) $(CFLAGS) $(TARGET).c -o $(TARGET).S
clean:
rm -f $(TARGET)*[^c] $(TARGET)
erase:
esptool.py erase_flash
```
You may change `INIT_DATA` and `SDK_BASE` to the proper values:
* `INIT_DATA` - Data to be put in the chip for proper initialization of it. You actually don't
need to flash it everytime, since it won't change between development-compile-flash cycles (it
comes from the SDK, you only need to change it if you change the SDK).
* `SDK_BASE` - Path to the sdk, where we can find the linker script and binaries.
You may get some errors related to `user_pre_init`, `user_config.h`, `user_rf_cal_sector_set`
or `user_rf_pre_init`:
* `user_pre_init` - Some SDK versions require this function to exists, just add it with an
empty body.
* `user_config.h` - The SDK require a `user_config.h` file. It can be empty though, so just
do a `touch user_config.h`.
* `user_rf_pre_init`/`user_rf_cal_sector_set` - Some SDK versions require these functions also.
Check examples from the SDK to get more info.
More information, "check Non-OS SDK Introduction" section [here](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf).
You may also get `undefined reference` for library functions like `aes_wrap`. Just
add the libraries based on [this](https://github.com/AutomationD/esp-alt-sdk/issues/24).
You may also get a `Fatal exception(0)` when connecting to the board in the
74880 baud rate (try this baud rate if you are seeing garbage being printed
rapidly!) or a error from `make` saying a file wasn't found. It probably means
that you uploaded one of the generated binaries to the wrong address. This can
happen when scwitching SDK versions, as v1.0.0 writes to `0x40000` and v3.3 writes
to `0x10000`. Just change everywhere you see `0x10000` to `0x40000` in the `Makefile`;
## Flashing
First we need to flash the `esp_init_data_default.bin`, which is usually
in the `bin/` subdirectory for the SDKs:
```
esptool.py --port /dev/ttyUSB0 write_flash 0x3FC000 ESP8266_NONOS_SDK/bin/esp_init_data_default.bin
```
The address `0x3FC000` is just the top address of the flash memory
subtracted by `0x3FFF`. You can do this subtraction for every flash
memory size to get the right address. The idea is just to put this
data at the top of the memory. More info [here](https://nodemcu.readthedocs.io/en/dev/flash/).
However, the `Makefile` we saw before handles it all with the `flash` rule.
Mind that the you **NEED** to flash the binaries to the addresses
specified in their names, which may vary from a SDK version to another.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment