Firmware architecture, "compile time requests", RTOS

Hi everyone. I’ve heard a lot about klipper and I was interested in how the klipper FW worked, so I looked through it.

I am roughly interested in doing some refactoring changes in a fork, as a
skill-builder project.

Up front, I was curious about something:
Is there a specific reason that you put it together with the “compile time
requests” architecture, using the named sections?

It seems like the same could be done with judicious use of kconfig flags and
macros, then a common “chassis” that launches/terminates any of the given
components, and the whole CTR mechanism could be removed.

Beyond that:
I’m also interested in doing an RTOS port, to refactor away from the
super-loop design. Again - is there already a known “dealbreaker” for that
design that made the devs not build it that way?

Most likely pitfalls here are going to be with the “Linux Process” and “Host Simulator” targets, and maybe keeping clean cross-platform support, but those aside, it seems like a project worth doing.

The goal of the CTR system was to facilitate encapsulation between the different components in the micro-controller software. If there was one central code location that knew of every module (and every module parameter) then that central code location would likely become very complex and need to be modified frequently. The goal was to keep the various code modules separate - for example, all the stepper logic in stepper.c and all the pwm logic in gpiocmds.c .

It was also desirable to store a compressed “data dictionary” in the flash of the micro-controller. The data dictionary stores pin names (eg, PA1) and supported commands. Many of the micro-controllers have limited flash space, so it was a goal to conserve it. The CTR system facilitates generating that data dictionary at compile time.

I’m not sure what you mean by “super-loop design”. If you are referring to the DECL_TASK system, where a module’s tasks are periodically invoked from a loop, then the goal was also to facilitate encapsulation between modules. If a central code location had to know about every module and when to invoke it, then that central location would likely become very complex and require frequent changes.

-Kevin

Interesting.

For the CTR:
I can see the implicit advantage of having all the “tasks” and such detected just by declaration and auto-launched.
And the issue of “commands” is common - you’d either need a central table of them all, with exported defs and strings, or you need a runtime “install” system to add them to a list.
Same for a single repository of strings.
I just have not seen many projects do it this way - not clear that it’s any less complex.

For concurrency:
Yes, that is what I mean by “super loop” - polling a set of tasks functions and irq_poll in a loop. RTOS design totally frees you from that and solves this issue from the README:

These functions should avoid long pauses, delays, or do work that lasts a
significant time. (Long delays in these “task” functions result in
scheduling jitter for other “tasks” - delays over 100us may become
noticeable, delays over 500us may result in command retransmissions,
delays over 100ms may result in watchdog reboots.)

RTOS would let you define and launch separate tasks, set priorities between them, and avoid this potential timing clash, by construction.
Also frees you from having to implement e.g. sched.c and your own allocator, although that is already done.
It seems like this a worthwhile refactor - I’ll work on it.

I don’t think the CTR is incompatible with such a refactor, necessarily.
Although the generated portion would change substantially.

Any advancements on the RTOS side? Having developed one, way back when, it would seem like a good fit for this kind of use case

As is common for me, my ambitions exceed my effort.
Everything is a forever project.

No progress yet.
Well, a little:
I have a cmake build for existing klipper firmware, and the FreeRTOS kernel, for the big STM32H5 micro.

From there, it would “just” be rewriting the ~10 tasks as RTOS tasks, adapting how they do their yielding/blocking.

Then figuring out something for the build system.
The existing macro + objdump system could be extended to wrap task creation or task function declaration, or something like that.

Yes, I think it is the “right” thing for this project. I expect there’s some wins for performance and latency.
Could also likely solve some small issues, like USB having issues on some platforms.

Which RTOS did you develop? Toy one or commercial?
FreeRTOS would be the goto, although ThreadX is now FOSS under Eclipse (thanks MSFT), and they have a very professional ecosystem.

Story of my life. But how else do you learn new things?
Definitely keeps things interesting, never ending supply of things to work on.

The RTOS I worked on was a commercial one, used in a few project, writte all in assembly. Very basic, with schduling/context switching/interrupt handling/timers and p/v operations, but no real memory management for example. But very small and fast. And forgotten by now, I believe. For fun I used it as basis to build a pre-emptive multitasking MS-DOS :slight_smile: . I have not worked with these things for years, but it does seem like something like that would be a good fit for klipper

Of course, but what about Klipper development goals for 2024? Who does the coding? It takes a “little” time :wink:

Sigh, ok … I should commit (to myself) to produce a prototype over the summer.

It should really only be a few weekends of work to get in place, maybe a few more to debug and refine, RFQ, get it running on the BTT STM32H5 board, etc.

no stress :smile:

I just tried to measure an oil flow with my measuring system at work today. 4-20mA, so far and boring. Never worked with that sensor before. The analog output voltage of the sensor was as expected. My AD converter could not read the signal. Some thinking…
I got it right in the end. My expected time frame was different.

I’m older than half a century. I’ll never learn how to estimate the needed time to finish a project :zipper_mouth_face: My bosses expect that, …

Hofstadter’s Law: It always takes longer than you expect, even when you take into account Hofstadter’s Law.

On a side note about estimating time on projects, I had that discussion with my boss during a meeting one time.

I realized I was giving estimates based on “If I worked on this project right now, with no distractions and interruptions it would take me X amount of time.”

I didn’t even realize I was doing that honestly, I’d add in a buffer naturally, but the buffer time wasn’t sufficient enough to take into account that other things are ALWAYS going to pull me off task. So I had to learn to re-estimate based on real world expectations of “unforseen factors”.