Hi,
I am working on getting Rust working with the ESP32, using your LLVM fork: https://github.com/espressif/llvm-xtensa, it is going very well so farhttps://github.com/MabezDev/rust-xtensa.
I now need to a basic run time for the xtensa cores but I am finding it quite difficult to find documentation on the startup of the processors and contents of vector table etc.
Could you point me in the right direction to some docs or code examples if you have them?
Thanks,
Scott
Rust ESP32 - Xtensa startup
Re: Rust ESP32 - Xtensa startup
Awesome, very interesting!
There is a high level overview of the ESP-IDF application startup flow (from ROM code to app) here:
https://docs.espressif.com/projects/esp ... artup-flow
Aside from this, the ESP-IDF source code for the bootloader and app startup is probably the best place to see all the details:
https://github.com/espressif/esp-idf/tr ... oject/main
https://github.com/espressif/esp-idf/tr ... er_support
https://github.com/espressif/esp-idf/bl ... pu_start.c
Some of these things (like the MMU which maps the flash contents into the address space) are also documented in the ESP32 Technical Reference Manual..
Given some of the complex nature of ESP32 compared to many simpler microcontrollers, I'd suggest maybe starting by trying to build an application as a Rust static library and then link it into an existing ESP-IDF project - so it will use the ESP-IDF software bootloader, and then call the ESP-IDF app startup code in cpu_start.c which then calls into the Rust code after the basics are running. There are at least two entry points you could use: app_main() (the C function which most C IDF apps use) runs in a FreeRTOS task already, so FreeRTOS is already running. If you want something lower level, start_cpu0() and start_cpu1() are weak linked functions in IDF which do the RTOS startup after the initial hardware configuration is done - so you could override these with functions that call into Rust immediately.
Once that works, it's a solid base to iterate on. As a second stage, you could expand the Rust part to take over all of the app startup so the ELF for the "app" is written entirely in Rust, but still using the ESP-IDF software bootloader.
And as a third stage if you wanted you could take the ESP-IDF software bootloader out of the equation, and either build a bootloader in Rust or run the app directly from the ROM bootloader.
Alternatively to everything I wrote above, if you want to start from the other end with very simple Rust code (ie running out of IRAM only, no flash cache, etc) running in place of the software bootloader - this is simpler but it leaves you with some constraints (mostly, no flash cache mappings yet so you're limited to the code which fits in IRAM). So it's a longer journey before you have a lot of functionality on the Rust side. The software bootloader entry point is basically a C function - you have a stack already, etc - because the ROM code does some setup and loads the software bootloader from flash into IRAM for you. The software bootloader uses the same CPU exception vectors as the ROM (ie stubs, basically) so there isn't an example of those in the bootloader project, but you can copy the IDF exception vectors as referenced from the startup code in IDF (vectors here, linker script that lays them out at correct offsets is here, moving the vector base pointer is done like this.) You could also take a look at the Zephyr or NuttX projects who have roughly that same level of functionality at the moment (ie run from IRAM only, but basics are in place).
If you have specific questions, feel free to ask.
There is a high level overview of the ESP-IDF application startup flow (from ROM code to app) here:
https://docs.espressif.com/projects/esp ... artup-flow
Aside from this, the ESP-IDF source code for the bootloader and app startup is probably the best place to see all the details:
https://github.com/espressif/esp-idf/tr ... oject/main
https://github.com/espressif/esp-idf/tr ... er_support
https://github.com/espressif/esp-idf/bl ... pu_start.c
Some of these things (like the MMU which maps the flash contents into the address space) are also documented in the ESP32 Technical Reference Manual..
Given some of the complex nature of ESP32 compared to many simpler microcontrollers, I'd suggest maybe starting by trying to build an application as a Rust static library and then link it into an existing ESP-IDF project - so it will use the ESP-IDF software bootloader, and then call the ESP-IDF app startup code in cpu_start.c which then calls into the Rust code after the basics are running. There are at least two entry points you could use: app_main() (the C function which most C IDF apps use) runs in a FreeRTOS task already, so FreeRTOS is already running. If you want something lower level, start_cpu0() and start_cpu1() are weak linked functions in IDF which do the RTOS startup after the initial hardware configuration is done - so you could override these with functions that call into Rust immediately.
Once that works, it's a solid base to iterate on. As a second stage, you could expand the Rust part to take over all of the app startup so the ELF for the "app" is written entirely in Rust, but still using the ESP-IDF software bootloader.
And as a third stage if you wanted you could take the ESP-IDF software bootloader out of the equation, and either build a bootloader in Rust or run the app directly from the ROM bootloader.
Alternatively to everything I wrote above, if you want to start from the other end with very simple Rust code (ie running out of IRAM only, no flash cache, etc) running in place of the software bootloader - this is simpler but it leaves you with some constraints (mostly, no flash cache mappings yet so you're limited to the code which fits in IRAM). So it's a longer journey before you have a lot of functionality on the Rust side. The software bootloader entry point is basically a C function - you have a stack already, etc - because the ROM code does some setup and loads the software bootloader from flash into IRAM for you. The software bootloader uses the same CPU exception vectors as the ROM (ie stubs, basically) so there isn't an example of those in the bootloader project, but you can copy the IDF exception vectors as referenced from the startup code in IDF (vectors here, linker script that lays them out at correct offsets is here, moving the vector base pointer is done like this.) You could also take a look at the Zephyr or NuttX projects who have roughly that same level of functionality at the moment (ie run from IRAM only, but basics are in place).
If you have specific questions, feel free to ask.
Re: Rust ESP32 - Xtensa startup
Wow! Thanks for the detailed response this should be plenty to get me started.
I think using the idf bootloader as a makeshift runtime for Rust is a great idea, and something that can easily swapped out later if we wanted it to be written in pure Rust.
Is the LX6 processor on the esp32 customized in anyway? The cadence datasheets I did find seemed to indicate it was very configurable.
I think using the idf bootloader as a makeshift runtime for Rust is a great idea, and something that can easily swapped out later if we wanted it to be written in pure Rust.
Is the LX6 processor on the esp32 customized in anyway? The cadence datasheets I did find seemed to indicate it was very configurable.
-
- Posts: 9764
- Joined: Thu Nov 26, 2015 4:08 am
Re: Rust ESP32 - Xtensa startup
It can be configurable, and the configuration we use should be specified in a bunch of defines somewhere. (Don't know where in the LLVM tree, but in esp-idf it's here: https://github.com/espressif/esp-idf/tr ... nsa/config). It can also be extendable with custom instructions, but the Xtensa in the ESP32 (and ESP8266) does not have any.
Re: Rust ESP32 - Xtensa startup
Hey guys, it's been a while but I have been making progress over the summer.
I've written a small blog post, in which I get an ESP32 to blink the onboard LED, in pure Rust!
Here's the link: https://mabez.dev/blog/posts/esp32-rust/
There are still a few things missing i.e the vector table is non existant at the moment, and the board boot loops unless started with a debugger (I'm guessing theres a watchdog I need to disable?) but it's a start.
I've written a small blog post, in which I get an ESP32 to blink the onboard LED, in pure Rust!
Here's the link: https://mabez.dev/blog/posts/esp32-rust/
There are still a few things missing i.e the vector table is non existant at the moment, and the board boot loops unless started with a debugger (I'm guessing theres a watchdog I need to disable?) but it's a start.
Who is online
Users browsing this forum: No registered users and 115 guests