How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby ESP_Sprite » Sun Apr 21, 2024 2:28 pm

Code: Select all

void __attribute__((constructor)) int_CPUticker64_init() {
Making a function a constructor calls it as soon as the program starts up, even before main() is called. You then *also* call the function in main.

djixon
Posts: 113
Joined: Sun Oct 01, 2023 7:48 pm

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby djixon » Sun Apr 21, 2024 3:58 pm

Here is final fully working component that makes CCOUNT 64 bits with zero imacts at rest of code.
I implemented all I talked in the very first post of this thread and even more. Results are amazing. Single NOP instruction is measured as single clock difference!!!! It means ZERO ERROR!!!! I also implemented AutoCalibrationRoutine so code should be independent on platform!!!! Function which anulate itself is fully written in assembly as I promised. I implemented two functions for precise measurement Start() and Stop(). That was necessary to allow that auto callibration independent of architecture. Because, once you get clock (i.e. before your code) and second time (i.e. after your code) you still have to do subtraction of those two values. However if you want to anulate that too it means you have to make correction in that offset in assembler function. But such correction then anulate itself because you call the same assembler function for both Start() and Stop() so that difference of subtraction is always presented, because you shifted (in time) both begining of measurement and end of measurement together. To solve that problem, I made C wrapper functions and involve one variable which do that anulation once AutoCalibration function is called.

I am impressed by the accuracy. Zero error on ESP32-WROOM-32E.

Also there is standard function GetTicker64() which, now, you can use to fetch 64bit ticker value with properly handled wrapping. In attachment is also simple example project which include that component. It is commented on all necessary places and in that, demo shows how to use the provided functions. It logs ticks spent for single NOP instruction and also print 64bit value (in hexadecimal) of that, now 64 bits ticker.

Thank you all guys, and especially @ESP-Sprite who shared that ancient code for proper allocation of custom interrupts under RTOS.

As I promised, that I will do the rest of job in assembly, so here it is. The fully functional component which I wanna share with all of you.

Cheers


https://uploadnow.io/f/9KSQ24l

MicroController
Posts: 1705
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby MicroController » Sun Apr 21, 2024 9:27 pm

IIRC, each core has its own CCOUNT register; and the two are not in sync. So be mindful of the core you call GetTicker64() from.

djixon
Posts: 113
Joined: Sun Oct 01, 2023 7:48 pm

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby djixon » Mon Apr 22, 2024 8:21 am

Thank you MicroController. Thats new for me. I thougt both are in sync.

So, that would be probably best fixed if each core has its own "private" memory location for upper part and each core has its own Start/Stop/GetTicker64 so user can chose freely which core to use.

I left some tests overnight and looking the log now. There are some glitches. Since ESP-IDF forbids allocation of NMI interrupts, so glitches are expected. If the GetTicker64 is called at close to wrap-arround while some other task disabled interrupts (or some esp part in rom or higher priority interrupt is executed) that ISR routine of that timer is delayed (and increment of upper part doesnt occur immediatelly) which forms glitches in time. Thats why I insisted on NMI interrupt. But it seems that it only can be done if esspressif decide to implement it as non-maskable or with higher priority.

EDIT:

I found fast way to reproduce those glitches. Just include unistd.h header in main and measure ROM function usleep(1000000) it shows amount of tick ot 1s of that function in ROM .... after 1 minute or so glitch happens. At first I thougth it is about wrong math in asm so I removed all math corrections and also change logic to: read hi, read CCOUNT, read hi again, if those two hi(s) differ then read CCOUNT again, so that way it doesn't depend on timing of esync and rsr instructions ..... but gliches didnt dissapear, then I printed those Start and Stop variables and it shows that ISR of that timer sometimes delay increasing that upper part which means it has to be NMI otherwise those delays can not be removed.

djixon
Posts: 113
Joined: Sun Oct 01, 2023 7:48 pm

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby djixon » Tue Apr 23, 2024 2:44 pm

@ESP_home: Its a pity that NMI interrupts are forbiden by IDF, anyway, I reduced priority as @ESP_Sprite suggested to level 5
@ESP_Sprite: I had call from app-main() to that "constructor" function because it wasn't called otherwise! Until I realized that gcc when finds that any function declared in some .c file isn't used (like in case when from main_app you perform just direct call to assembler function) then, for some unknown reason to me, it doesnt compile code of that constructor function and there is no call at all. Thats why I had to force that call from app_main in that old version. In this latest version I fixed that by making wrapper function in .c which calls assembler function and from main_app I call that wrapper. In that case gcc do proper compilation and that constructor function IS CALLED before main_app. Is it a bug or some kind of compiler optimization when it simply ignore whole .c file if no function is called?
@MicroControler: Now, both assembler functions are aware of CORE_ID which executes them and each core has its own memory address for upper part of its CCOUNT. No more glitches. And now even that difference in CORE clocks (probably due to slightly different power time) is visible.

Added features in this version v1.0:

1. GetClock64() is now aware of coreID which calls it. So if called by CORE0 it will get clock64 from CORE0. The same apply to CORE1
2. User can allocate for example interrupt on single (doesnt matter which) or both cores. Core which is not utilized will not have its own 64 bit counter but only 32bit (its upper part will always be 0 (if memory is initialized))
3. Even if some task runs at let's say CORE0, measurement can be performed on CORE1. Now, StartSnapshot(uint8_t core_id) internaly perform checking if it is called from the same core then it just calls GetTicker64() to take a snapshot, otherwise it perform new task creation forcing that core_id passed to that function, also it then take cares when Stop is called to do snapshot on the same core where start was called etc.
4. Changed algorithm for anulation to be completely architecture independent (it doees not depends on ticks spent in function)
5. Added example where usleep(1000000) is measured, and printed start, stop and difference ticks with upper parts of CCOUNT for both cores

CPU_ticker_v1.0.zip
Here it is:
https://uploadnow.io/f/dTSZ55Y

Again, thank you all for helping this handy tool is done.

MicroController
Posts: 1705
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby MicroController » Tue Apr 23, 2024 3:04 pm

djixon wrote:
Tue Apr 23, 2024 2:44 pm
otherwise it perform new task creation forcing that core_id passed to that function, also it then take cares when Stop is called to do snapshot on the same core where start was called etc.
One more hint: https://docs.espressif.com/projects/esp ... m/ipc.html ;-)

djixon
Posts: 113
Joined: Sun Oct 01, 2023 7:48 pm

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby djixon » Tue Apr 23, 2024 3:29 pm

@MicroControler: It is not violated in any sense. Because User's task does what it does on cores (what ever).
Measurement on specific core doesn't affect that. For example if user tasks run on both cores, he just decide about Snapshot ie. at core1 (which is nothing else than call of GetTicker64() function on that core by utilizing new task if caller of that Snapshot function doesn't match to cpu_id he want to use for measurement. So new task is created forcing that core just for measurement and not for execution of user code.
Now, each core has its own private loaction in ram for its upper part of its own CCOUNT and glitches are not possible anymore.

Allocation of TIMER interrupt, if performed ie. just on CORE0, simply will trigger that ISR when wrap-arround happens at CORE0 only. Wrapp arround at CORE1 will never trigger that interrupt if it is not also allocated on CORE1. In that example (in last version) try to comment allocation of interrupt at core1 so interrupt is only allocated for CORE0. And run example. You will see that upper part of CORE1 stays at 0 all the time because it doesn't have allocated that TIMER interrupt and that ISR is not triggered at all.

Assembler functions do not "comunicate" in between cores. There is special register PRID which exists in each core. 13th bit of that register is hardcoded constant which is 0 in CORE0 and 1 in CORE1. So both functions by testing that bit "know" which core executes it.

MicroController
Posts: 1705
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby MicroController » Tue Apr 23, 2024 3:32 pm

Ok. What I meant was that using the IPC would be more efficient than creating your own task(s) just to execute a few instructions on the other core...

djixon
Posts: 113
Joined: Sun Oct 01, 2023 7:48 pm

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby djixon » Tue Apr 23, 2024 3:43 pm

I tried experimenting with allocation of software interrupts with an idea to make Snap interrupt to use it and then make calls of those GetTicker64() function right from that ISR already on proper core but I didn't find proper way to do that.

For example:

1. At that allocation part, adding two more software interrupts lets call them "snap" on both cores
2. writting an asm ISR which will just call GetTicker64() end returning its value now at desired core because snap ISR is already "at right" core
3. replacing current xTaskCreatePinnedToCore() by TriggerSnapSoftwareInterrupt(core id) with intention to trigger that snap ISR on specific core

But I didn't find any example how to trriger a software interrupt and to fetch that value from it.

MicroController
Posts: 1705
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: How properly, under RTOS, to set up the highest priority non-maskable interrupt vector?

Postby MicroController » Tue Apr 23, 2024 3:59 pm

djixon wrote:
Tue Apr 23, 2024 3:43 pm
but I didn't find proper way to do that.
Maybe my browser is broken, but when I click that link I posted, a page comes up which documents how you can make code run on another core using the IDF-provided API.

Who is online

Users browsing this forum: Bing [Bot] and 79 guests