Hi Geoffrey & Greg,
I apologise I don't have time to provide more in-depth help, but I
pulled down nuttx git master and worked through the steps required to
flash & run code. At the moment my nuttx esp32 doesn't start up fully
(something goes wrong configuring serial output), but I thought I'd post
the little bit that I had.
I've attached 3 small patches:
- Patch 1 temporarily moves all data from flash to IRAM, which allows
nuttx to run without needing to set up flash cache mappings.
... At this stage the nuttx image is small enough to be entirely
memory-resident, once board support is more mature you can add flash
cache mapping code to run from SPI flash after initial boot. There are
at least two possible approaches you could take: You can add the flash
cache mapping code into nuttx directly, so it is self-contained - early
nuttx initialisation runs from IRAM and enables flash cache, and then
off you go. Or you can use the esp-idf software bootloader & partition
table scheme, and have nuttx be an esp-idf "app" - which allows
interoperability with the esp-idf system but makes you reliant on the
esp-idf design for these parts. Both are possible.
- Patch 2 flushes the UART TX buffer in the esp32 serial shutdown
routine. The ROM bootloader does not flush the FIFO before handing over
to user code, so some of this output is not currently seen when the UART
is reconfigured in early stages of startup.
- Patch 3 changes the openocd config file's default flash voltage from
1.8V to 3.3V. This is not necessary right now, but may save some
hard-to-debug moments down the track (3.3V-only flash running at 1.8V
often half-works and does weird things...)
To build/flash without using openocd:
1) Configure nuttx for esp32-core and build as usual
2) Clone the esp32 branch of esptool.py somewhere:
git clone -b feature/esp32_v20_refactor
https://github.com/espressif/esptool.git
(ESP32 support is not in the master branch yet, although I'm working on
this!)
You will also need Python 2.x & pyserial, the esptool README on github
has more details.
3) Convert the nuttx ELF file to the esp32 ROM bootloader's image format:
esptool.py --chip esp32 elf2image --flash_mode dio --flash_size 4MB -o
./nuttx-esp32.bin ./nuttx
4) Flash to the ESP32 over serial at offset 0x1000 (this is the address
read by the ESP32 ROM bootloader):
esptool.py --port COMx --baud 921600 write_flash -z --flash_mode dio
0x1000 nuttx-esp32.bin
(The -z and the --baud are optional but improve flashing speed quite a bit.)
5) Connect to the serial port at 115200bps, press the "Reset" button on
the ESP32 board (sometimes marked "EN")
6) Output from the ROM bootloader will look something like this:
ets Jun 8 2016 00:22:57
rst:0x10 (RTCWDT_RTC_RESET),boot:0x16 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0x00
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3ffb08b8,len:84
load:0x3ffb0910,len:6200
load:0x40080400,len:132
load:0x40080484,len:50732
load:0x400c0000,len:0
entry 0x4008041c
In the above output, some helpful things:
- The"mode: DIO" indicates SPI flash access mode (matches the esptool.py
--flash_mode argument). DIO mode is necessary with the current ESP32
Core boards, their flash chip doesn't work with QIO. If QIO is set then
the next few lines will have junk addresses, and the image won't load
correctly.
- The load: lines have load addresses and lengths taken from the ELF, ie
they match the output of 'xtensa-esp32-elf-objdump -h nuttx'
- The 'entry' line shows the entry point (address of nuttx __start function)
- If you don't apply Patch 2 to flush the FIFO, output will be cut off
somewhere in the middle of the second-last line, because the FIFO isn't
empty when the UART is disabled by user code.
To build/flash using openocd:
- It should be possible to bypass esptool.py entirely, use gdb to 'load'
the RAM-only nuttx ELF file, and then execute 'set $pc=__start' to set
the PC and continue/step directly into nuttx. This causes my openocd to
become very unhappy, I'm not sure why at the moment. I've CCed Jeroen
who is our esp32 openocd guru, he may have some advice.
- Similarly, it's possible to compile in a " __asm__ __volatile__
("break 0, 0");" in the code to trip a breakpoint. This works for me,
gdb halts on the breakpoint, but I can't step for some reason.
openocd works in the esp-idf environment, so I'm guessing this is either
something peculiar to my hardware, or something else needed when setting
"ESP32_RTOS" to "none".
One last thing to note, the ROM linker script includes an "ets_printf"
function which has the same signature as printf. You can use this as an
alternative for early boot debugging, until openocd is working smoothly.
Angus