ESP32 Core v2: Add configuration to supporting linking NuttX for execution out of IRAM.
This commit is contained in:
parent
96e7d1c310
commit
5dfc5f1da5
@ -16,4 +16,15 @@ config ESP32CORE_XTAL_26MHz
|
||||
bool "26MHz"
|
||||
|
||||
endchoice # On-board Crystal Frequency
|
||||
|
||||
config ESP32CORE_RUN_IRAM
|
||||
bool "Run from IRAM"
|
||||
default n
|
||||
---help---
|
||||
The default configuration is set up run from IRAM. However, the
|
||||
current (2016-11-14) OpenOCD for ESP32 does not support writing to
|
||||
FLASH. This option sets up the liner scripts to support execution
|
||||
from IRAM. In this case, OpenOCD can be used to load directly into
|
||||
IRAM.
|
||||
|
||||
endif # ARCH_BOARD_ESP32CORE
|
||||
|
@ -23,7 +23,8 @@ Contents
|
||||
o Serial Console
|
||||
o Buttons and LEDs
|
||||
o SMP
|
||||
o Debug Issues
|
||||
o OpenOCD for the ESP32
|
||||
o Executing and Debugging from FLASH and IRAM
|
||||
o Configurations
|
||||
o Things to Do
|
||||
|
||||
@ -222,8 +223,8 @@ SMP
|
||||
|
||||
3. Assertions. On a fatal assertions, other CPUs need to be stopped.
|
||||
|
||||
Debug Issues
|
||||
============
|
||||
OpenOCD for the ESP32
|
||||
=====================
|
||||
|
||||
First you in need some debug environment which would be a JTAG emulator
|
||||
and the ESP32 OpenOCD software which is available here:
|
||||
@ -335,6 +336,16 @@ Debug Issues
|
||||
|
||||
This should give you a gdb prompt.
|
||||
|
||||
Breakpoints
|
||||
-----------
|
||||
You can set up to 2 hardware breakpoints, which can be anywhere in the
|
||||
address space. Also 2 hardware watchpoints.
|
||||
|
||||
The openocd esp32.cfg file currently forces gdb to use hardware
|
||||
breakpoints, I believe because software breakpoints (or, at least, the
|
||||
memory map for automatically choosing them) aren't implemented yet
|
||||
(as of 2016-11-14).
|
||||
|
||||
JTAG Emulator
|
||||
-------------
|
||||
The documentation indicates that you need to use an external JTAG
|
||||
@ -397,49 +408,74 @@ Debug Issues
|
||||
20 GND N/A GND
|
||||
------------ ----------
|
||||
|
||||
Executing and Debugging from FLASH and IRAM
|
||||
===========================================
|
||||
|
||||
FLASH
|
||||
-----
|
||||
OpenOCD currently doesn't have a FLASH driver for ESP32, so you can load
|
||||
code into IRAM only via JTAG. FLASH-resident sections like .FLASH.rodata
|
||||
will fail to load. The bootloader in ROM doesn't parse ELF, so any imag
|
||||
which is bootloaded from FLASH has to be converted into a custom image
|
||||
format first.
|
||||
|
||||
The tool esp-idf uses for flashing is a command line Python tool called
|
||||
"esptool.py" which talks to a serial bootloader in ROM. A version is
|
||||
supplied in the esp-idf codebase in components/esptool_py/esptool, the
|
||||
"upstream" for that tool is here:
|
||||
|
||||
https://github.com/espressif/esptool/pull/121
|
||||
|
||||
The master branch for esptool.py is currently ESP8266-only (as of 2016-11-14),
|
||||
this PR has the ESP32 support which still needs some final tidying up before
|
||||
it's
|
||||
merged.
|
||||
|
||||
To FLASH an ELF via the command line is a two step process, something like
|
||||
this:
|
||||
|
||||
esptool.py --chip esp32 elf2image --flash_mode dio --flash_size 4MB -o ./nuttx.bin nuttx.elf
|
||||
esptool.py --chip esp32 --port COMx write_flash 0x1000 bootloader.bin 0x4000 partition_table.bin 0x10000 nuttx.bin
|
||||
|
||||
The first step converts an ELF image into an ESP32-compatible binary
|
||||
image format, and the second step flashes it (along with bootloader image and
|
||||
partition table binary.)
|
||||
|
||||
To put the ESP32 into serial flashing mode, it needs to be reset with IO0 held
|
||||
low. On the Core boards this can be accomplished by holding the button marked
|
||||
"Boot" and pressing then releasing the button marked "EN". Actually, esptool.py
|
||||
can enter bootloader mode automatically (via RTS/DTR control lines), but
|
||||
unfortunately a timing interaction between the Windows CP2012 driver and the
|
||||
hardware means this doesn't currently work on Windows.
|
||||
|
||||
Secondary Boot Loader / Partition Table
|
||||
---------------------------------------
|
||||
I need to understand how to use the secondary bootloader. My
|
||||
understanding is that it will configure hardware, read a partition
|
||||
table at address 0x5000, and then load code into memory. I do need to
|
||||
download and build the bootloader?
|
||||
|
||||
Do I need to create a partition table at 0x5000? Should this be part
|
||||
of the NuttX build?
|
||||
|
||||
See https://github.com/espressif/esp-idf/tree/master/components/bootloader
|
||||
and https://github.com/espressif/esp-idf/tree/master/components/partition_table.
|
||||
I suppose some of what I need is in there, but I am not sure what I am
|
||||
looking at right now.
|
||||
|
||||
Running from IRAM
|
||||
-----------------
|
||||
Running from IRAM is a good debug option. You should be able to load the ELF directly via JTAG in this case, and you may not need the bootloader. The one "gotcha" for needing the bootloader is disabling the initial watchdog, there is code in bootloader_start.c that does this.
|
||||
|
||||
It is possible to skip the secondary bootloader and run out of IRAM using
|
||||
only the primary bootloader if your application of small enough (< 128KiB code,
|
||||
<180KiB data), then you can simplify initial bring-up by avoiding second stage
|
||||
bootloader. Your application will be loaded into IRAM using first stage
|
||||
bootloader present in ESP32 ROM. To achieve this, you need two things:
|
||||
|
||||
1. Have a linker script which places all code into IRAM and all data into DRAM
|
||||
1. Have a linker script which places all code into IRAM and all data into
|
||||
IRAM/DRAM
|
||||
|
||||
2. Use "esptool.py" utility found in ESP-IDF to convert application .elf file
|
||||
into binary format which can be loaded by first stage bootloader.
|
||||
2. Use "esptool.py" utility found in ESP-IDF to convert application .elf
|
||||
file into binary format which can be loaded by first stage bootloader.
|
||||
|
||||
The default linker script in ESP-IDF places most code into memory-mapped flash:
|
||||
https://github.com/espressif/esp-idf/blob/master/components/esp32/ld/esp32.common.ld#L178-L186
|
||||
NuttX supports a configuration option, CONFIG_ESP32CORE_RUN_IRAM, that may be
|
||||
selected for execution from IRAM. This option simply selects the correct
|
||||
linker script for IRAM execution.
|
||||
|
||||
You would need to remove this section and move its contents into the end of .iram0.text section:
|
||||
https://github.com/espressif/esp-idf/blob/master/components/esp32/ld/esp32.common.ld#L85
|
||||
|
||||
Same with constant data: move contents of .flash.rodata section:
|
||||
https://github.com/espressif/esp-idf/blob/master/components/esp32/ld/esp32.common.ld#L134-L173
|
||||
|
||||
into the end of .dram0.data section (before _heap_start):
|
||||
https://github.com/espressif/esp-idf/blob/master/components/esp32/ld/esp32.common.ld#L128
|
||||
|
||||
With these modifications, all code and data should be moved into IRAM/DRAM. Next, you would
|
||||
need to link the ELF file and convert it to binary format suitable for flashing into the
|
||||
board. The xommand should to convert ELF file to binary image looks as follows:
|
||||
Again you would need to link the ELF file and convert it to binary format suitable
|
||||
for flashing into the board. The command should to convert ELF file to binary
|
||||
image looks as follows:
|
||||
|
||||
python esp-idf/components/esptool_py/esptool/esptool.py --chip esp32 elf2image --flash_mode "dio" --flash_freq "40m" --flash_size "2MB" -o app.bin app.elf
|
||||
|
||||
@ -554,4 +590,4 @@ Things to Do
|
||||
|
||||
5. See SMP-related issues above
|
||||
|
||||
6. See Debug Issues above
|
||||
6. See OpenOCD for the ESP32 above
|
||||
|
@ -38,10 +38,15 @@ include ${TOPDIR}/tools/Config.mk
|
||||
include ${TOPDIR}/arch/xtensa/src/lx6/Toolchain.defs
|
||||
|
||||
LDSCRIPT1 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_out.ld
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_common.ld
|
||||
LDSCRIPT3 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_rom.ld
|
||||
LDSCRIPT4 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_peripherals.ld
|
||||
|
||||
ifeq ($(CONFIG_ESP32CORE_RUN_IRAM),y)
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_iram.ld
|
||||
else
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_flash.ld
|
||||
endif
|
||||
|
||||
ifeq ($(WINTOOL),y)
|
||||
# Windows-native toolchains
|
||||
DIRLINK = $(TOPDIR)/tools/copydir.sh
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* configs/elf32-core/scripts/esp32_common.ld
|
||||
* configs/elf32-core/scripts/esp32_flash.ld
|
||||
****************************************************************************/
|
||||
|
||||
/* Default entry point: */
|
191
configs/esp32-core/scripts/esp32_iram.ld
Normal file
191
configs/esp32-core/scripts/esp32_iram.ld
Normal file
@ -0,0 +1,191 @@
|
||||
/****************************************************************************
|
||||
* configs/elf32-core/scripts/esp32_iram.ld
|
||||
****************************************************************************/
|
||||
|
||||
/* Default entry point: */
|
||||
|
||||
ENTRY(__start);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Send .iram0 code to iram */
|
||||
|
||||
.iram0.vectors :
|
||||
{
|
||||
/* Vectors go to IRAM */
|
||||
|
||||
_init_start = ABSOLUTE(.);
|
||||
|
||||
/* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */
|
||||
|
||||
. = 0x0;
|
||||
KEEP(*(.window_vectors.text));
|
||||
. = 0x180;
|
||||
KEEP(*(.xtensa_level2_vector.text));
|
||||
. = 0x1c0;
|
||||
KEEP(*(.xtensa_level3_vector.text));
|
||||
. = 0x200;
|
||||
KEEP(*(.xtensa_level4_vector.text));
|
||||
. = 0x240;
|
||||
KEEP(*(.xtensa_level5_vector.text));
|
||||
. = 0x280;
|
||||
KEEP(*(.debug_exception_vector.text));
|
||||
. = 0x2c0;
|
||||
KEEP(*(.nmi_vector.text));
|
||||
. = 0x300;
|
||||
KEEP(*(.kernel_exception_vector.text));
|
||||
. = 0x340;
|
||||
KEEP(*(.user_exception_vector.text));
|
||||
. = 0x3c0;
|
||||
KEEP(*(.double_exception_vector.text));
|
||||
. = 0x400;
|
||||
*(.*_vector.literal)
|
||||
|
||||
. = ALIGN (16);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
_init_end = ABSOLUTE(.);
|
||||
} > iram0_0_seg
|
||||
|
||||
.iram0.text :
|
||||
{
|
||||
/* Code marked as runnning out of IRAM */
|
||||
|
||||
_iram_text_start = ABSOLUTE(.);
|
||||
*(.iram1 .iram1.*)
|
||||
*libphy.a:(.literal .text .literal.* .text.*)
|
||||
*librtc.a:(.literal .text .literal.* .text.*)
|
||||
*libpp.a:(.literal .text .literal.* .text.*)
|
||||
*libhal.a:(.literal .text .literal.* .text.*)
|
||||
_iram_text_end = ABSOLUTE(.);
|
||||
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
|
||||
} > iram0_0_seg
|
||||
|
||||
/* Shared RAM */
|
||||
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
/* .bss initialized on power-up */
|
||||
|
||||
. = ALIGN (8);
|
||||
_sbss = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
*(.dynbss)
|
||||
KEEP(*(.bss))
|
||||
*(.bss.*)
|
||||
*(.share.mem)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
_ebss = ABSOLUTE(.);
|
||||
|
||||
/* Uninitialized .bss */
|
||||
|
||||
*(.noinit)
|
||||
} >dram0_0_seg
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
/* .data initialized on power-up in ROMed configurations. */
|
||||
|
||||
_sdata = ABSOLUTE(.);
|
||||
KEEP(*(.data))
|
||||
KEEP(*(.data.*))
|
||||
KEEP(*(.gnu.linkonce.d.*))
|
||||
KEEP(*(.data1))
|
||||
KEEP(*(.sdata))
|
||||
KEEP(*(.sdata.*))
|
||||
KEEP(*(.gnu.linkonce.s.*))
|
||||
KEEP(*(.sdata2))
|
||||
KEEP(*(.sdata2.*))
|
||||
KEEP(*(.gnu.linkonce.s2.*))
|
||||
KEEP(*(.jcr))
|
||||
*(.dram1 .dram1.*)
|
||||
_edata = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
|
||||
_srodata = ABSOLUTE(.);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
|
||||
*(.xt_except_table)
|
||||
*(.gcc_except_table)
|
||||
*(.gnu.linkonce.e.*)
|
||||
*(.gnu.version_r)
|
||||
*(.eh_frame)
|
||||
|
||||
. = (. + 3) & ~ 3;
|
||||
|
||||
/* C++ constructor and destructor tables, properly ordered: */
|
||||
|
||||
_sinit = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
_einit = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
|
||||
/* C++ exception handlers table: */
|
||||
|
||||
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
|
||||
*(.xt_except_desc)
|
||||
*(.gnu.linkonce.h.*)
|
||||
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
|
||||
*(.xt_except_desc_end)
|
||||
*(.dynamic)
|
||||
*(.gnu.version_d)
|
||||
_erodata = ABSOLUTE(.);
|
||||
/* Literals are also RO data. */
|
||||
_lit4_start = ABSOLUTE(.);
|
||||
*(*.lit4)
|
||||
*(.lit4.*)
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
|
||||
/* Heap starts at the end of .data */
|
||||
|
||||
_sheap = ABSOLUTE(.);
|
||||
} >dram0_0_seg
|
||||
|
||||
.flash.rodata :
|
||||
{
|
||||
} >drom0_0_seg
|
||||
|
||||
.rtc.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rtc.literal .rtc.text)
|
||||
} >rtc_iram_seg
|
||||
|
||||
.rtc.data :
|
||||
{
|
||||
*(.rtc.data)
|
||||
*(.rtc.rodata)
|
||||
} > rtc_slow_seg
|
||||
}
|
@ -38,10 +38,15 @@ include ${TOPDIR}/tools/Config.mk
|
||||
include ${TOPDIR}/arch/xtensa/src/lx6/Toolchain.defs
|
||||
|
||||
LDSCRIPT1 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_out.ld
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_common.ld
|
||||
LDSCRIPT3 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_rom.ld
|
||||
LDSCRIPT4 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_peripherals.ld
|
||||
|
||||
ifeq ($(CONFIG_ESP32CORE_RUN_IRAM),y)
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_iram.ld
|
||||
else
|
||||
LDSCRIPT2 = $(TOPDIR)/configs/$(CONFIG_ARCH_BOARD)/scripts/esp32_flash.ld
|
||||
endif
|
||||
|
||||
ifeq ($(WINTOOL),y)
|
||||
# Windows-native toolchains
|
||||
DIRLINK = $(TOPDIR)/tools/copydir.sh
|
||||
|
Loading…
Reference in New Issue
Block a user