Page 1 of 1
Class methods as ISR (IRAM allocation)
Posted: Thu Aug 31, 2023 7:51 am
by doglike
Hi,
I want to use a class method as ISR and want to allocate it in IRAM.
How to do it correctly?
Will this example code work ?
Thanks in advance.
Code: Select all
class PIN_t
{
void isr_func (void);
} pin;
void IRAM_ATTR PIN_t::isr_func (void)
{
// do stuff
}
Re: Class methods as ISR (IRAM allocation)
Posted: Thu Aug 31, 2023 10:33 am
by MicroController
Seems to work, at least on RISC-V gcc 12.2.
To be sure, after building, you can check the /build/*.map file. Find your member function's name and check that its section is some ".iram.???".
Note that
virtual methods won't usually work as IRAM-only because classes' vtables will end up in flash anyway.
Also note that a member function cannot be an ISR handler directly. You'll need some trampoline function (can be a static member function) to call the member function on an object instance, like
Code: Select all
void IRAM_ATTR pin_t_isr_handler(void* user_ctx) {
((PIN_t*)user_ctx)->isr_func();
}
Re: Class methods as ISR (IRAM allocation)
Posted: Thu Sep 07, 2023 7:36 am
by doglike
Hi,
thanks for your feedback.
I tried it with this code:
Code: Select all
class PIN_t
{
public:
void IRAM_ATTR set_mode(void);
}
void IRAM_ATTR PIN_t::set_mode(void)
{
// do stuff
}
PIN_t pin_instance;
Then I checked the map file in build directory:
- method set_mode is
not appearing in map file at all.
- when searching for "pin_instance", this is the only entry:
Code: Select all
0x0000000000000000 0x1 /home/user/eclipse-workspace/class_test/build/main/libmain.a(main.o)
.bss.pin_instance
0x0000000000000000 0x1 /home/user/eclipse-workspace/class_test/build/main/libmain.a(main.o)
.bss.SensDiag
0x0000000000000000 0x8 /home/user/eclipse-workspace/class_test/build/main/libmain.a(main.o)
Any other ideas ?
Re: Class methods as ISR (IRAM allocation)
Posted: Thu Sep 07, 2023 12:30 pm
by MicroController
Do you 'use' the function in your code? If not, the compiler or linker may remove the function and its symbol completely. If you have the above mentioned trampoline function for ISR calling PIN_t::isr_func, the member function may also be inlined into the trampoline, so you may want to check if the trampoline is in IRAM. The trampoline should actually be registered as an ISR, otherwise the compiler or linker may again inline or remove it and transitively all functions called only from the trampoline.
__attribute__((used)) affects the compiler but doesn't make it into the linker, so a q&d way to force inclusion of the (non-inlined) function for examination could be
Code: Select all
void (PIN_t::*volatile dummy_PIN_t_isr_fptr)(void) = &PIN_t::isr_func;
Re: Class methods as ISR (IRAM allocation)
Posted: Thu Sep 07, 2023 2:26 pm
by doglike
MicroController wrote: ↑Thu Sep 07, 2023 12:30 pm
Do you 'use' the function in your code?
Yes, I am calling pin_instance.set_mode() it in a freertos task.
I didn't checked your "trampoline" workaround yet.
First I want to see, whether it is allocated in IRAM.
Re: Class methods as ISR (IRAM allocation)
Posted: Thu Sep 07, 2023 3:12 pm
by MicroController
The "volatile pointer" approach will certainly work. You can also try __attribute__((noinline)) to prevent inlining of the function at the call site.
Re: Class methods as ISR (IRAM allocation)
Posted: Fri Sep 08, 2023 7:46 am
by doglike
MicroController wrote: ↑Thu Sep 07, 2023 3:12 pm
You can also try __attribute__((noinline)) to prevent inlining of the function at the call site.
That worked, many thanks
Code: Select all
.iram1.1605 0x00000000400836dc 0xe /home/user/eclipse-workspace/class_test/build/main/libmain.a(main.o)
0x11 (size before relaxing)
0x00000000400836dc _ZN5PIN_t8set_modeEhh
In meanwhile I am wondering:
Sometimes I want some code to be in IRAM, so that it could be executed as fast as possible (not necessarily as ISR - also normal functions).
So when compiler is inlining the class-method or function, than this already is speed optimized - isn't it - because it is no more a function call ?
Re: Class methods as ISR (IRAM allocation)
Posted: Fri Sep 08, 2023 9:06 am
by MicroController
When a function gets inlined, its code is "copied" into the calling function. If the calling function is not ATTR_IRAM neither is any code inlined into it.
This usually isn't much of an issue since the caller isn't in IRAM anyway; but the caller's code may get bigger by the inlining, so more code may need to be fetched from flash.
Gcc decides if a function call gets inlined based, among other factors like optimization flags, on the size of the called function. Tiny/trivial ("one-line") functions have a higher likelihood of being inlined than bigger ones. Gcc's underlying performance cost calculation doesn't take into account IRAM or the (worst-case) cost of fetching code from flash; it kind-of does when optimizing for code size (-Os). You can leave the decision to gcc, especially as the result will automatically adapt to future code changes. If you don't want that, you can use __attribute__((noinline)).
Note though that the ESPs have an in-RAM cache for the flash memory. Code which runs frequently, or in a tight loop, will run directly from the cache at the same speed it would from IRAM. That said, actual performance benefits of IRAM functions may be minute to non-existing in many cases. The main reason to use IRAM code is for the code to be able to run when the cache is unavailable, specifically during writes (OTA, NVS,...) to the flash.