-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do I put RMT Encoder in IRAM? #280
Comments
I looked at this for I2S. The answer I came to is it's not terribly easy to do today. The main problem I ran into was determining the size of a function at runtime. LLVM does emit this into the debug symbols. For example, this Rust code: pub fn add_it(a: i32, b: i32) -> i32 {
a.wrapping_add(b)
} Becomes this RISCV32 assembly (demangled): .globl _add_it
.type _add_it, @function
_add_it:
add a0, a0, a1
ret
.Lfunc_end0:
.size _add_it, .Lfunc_end0-_add_it Note the Ideally, we'd get another symbol that does end up in the resulting object, like: .globl _add_it_size
_add_it_size:
.dc.l .Lfunc_end0-_add_it
.size _add_it_size, 4 This requires hooking into LLVM somehow, though. Would likely require a patch to LLVM since this intermediate assembly is never actually emitted in the normal workflow, just the MIR. Barring this, the main alternative I can think of is to define an external symbol that gets resolved later, scrape this out of the debug info using |
So the CONFIG_RMT_ISR_IRAM_SAFE config option will handle the C side of putting the required methods in IRAM, so we then just have to worry about the rust side when we detect this option. This isn't trivial at all tbh, it's quite difficult to ensure that all the code/subroutine calls inside a function are all in IRAM too. In my experience its dependent on a number of things, including optimization levels as to whether the functions actually end up in IRAM. |
Interesting... it looks like if you can get the function into a section whose name is in the form If I'm reading this correctly,
Actually putting a function into IRAM is done by decorating it with #define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
#define _COUNTER_STRINGIFY(COUNTER) #COUNTER I can't find the magic that does the copying, though. Maybe it's in the ROM? @MabezDev, do you know where this magic happens? (grep didn't turn up anything other than linker scripts for me.) Both C and Rust have the issue of calling from IRAM into non-IRAM; C is just a bit more predictable in its code generation here. The C code does take care not to accept callback parameters it can't verify as being IRAM-safe, e.g. in |
The copying code will be buried deep in the startup code for esp-idf, but provided we also put our Rust functions there, i.e by using |
Great research both of you. I will experiment a bit with this. Do you know how to verify what functions are placed in IRAM for a given compiled firmware/app? |
Yes, you can use |
Adding on to this, as a note for myself and future spelunkers: process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
typedef struct {
uint32_t load_addr; /*!< Address of segment */
uint32_t data_len; /*!< Length of data */
} esp_image_segment_header_t; This calls The segment headers are created by the flash utility (e.g. espflash's I'm a bit surprised with the amount of code around memory mapping into the flash. It handles virtual to physical address translation cases, which I didn't think were a thing on any ESP32 chips; I thought addresses were directly mapped, and the flash accessible by the SPI bus (with cache possibly mediating accesses). If you're using ESP32-C3/-C6 direct boot (no second-stage bootloader, just ROM into your app code) or have a custom second-stage bootloader, you're responsible for doing all of this yourself. |
In the official documentation for RMT, it is highly recommended to put the encoding function into IRAM:
But I don't understand how to do this. Neither the
esp_idf_hal::rmt
module docs, nor anything inesp_idf_sys
or the Rust on ESP Book mentions IRAM at all.How can I move arbitrary Rust functions to IRAM? And will this be possible with the iterator approach that
TxRmtDriver
is taking?The text was updated successfully, but these errors were encountered: