Home > On-Demand Archives > Talks >
Designing Portable Firmware: Key Principles and Patterns
Alexey Karelin - Watch Now - EOC 2025 - Duration: 31:07

Portable firmware is more than just migrating code across hardware platforms. It involves organizing firmware in a modular, scalable, and reusable way while adhering to better design principles.
This talk begins with a personal story of challenges and setbacks, shedding light on common pitfalls and ineffective approaches. It then explores the principles and patterns essential for creating portable firmware for embedded systems, illustrated with simple examples in C.
Attendees will learn how to develop adaptable firmware capable of running on different microcontrollers and hardware configurations with minimal changes to the application code.
Thanks for the feedback!
Great presentation. I was wondering until the very last bit if you were to mention Zephyr.
For anyone wanting to see large scale implementation of this function pointer to control and data structure abstraction, I'd encourage you to look at Zephyr as this is the core principle behind Zephyr drivers and modules. The BSP_ macros are then replaced by devicetree and its macros.
Thanks for the feedback.
This talk is to some extent inspired by Zephyr driver model, so not to mention it would have been incorrect. But apart from that, my idea was to bring Why this is done in that way, and in a simplified way How this works under the hood.
Congratulations! As you mentioned in your conclusion, the initial design is more complex and naturally requires more time to complete. However, the benefits make it worthwhile. I usually use a design pattern called Factory—the idea is similar.
Thanks for the feedback!
I'd love to hear how you've applied this pattern in your firmware.
From my experience, several design patterns - like Factory or Strategy - can be used for these purposes, even in C. They can also complement the approach shown in this example providing even more flexibility.
vDuring most of the presentation, I was wondering why do he use all those pointers.. Thinking of your example at the start, this does not make sense, why push all this variation to runtime?
In the very end you mention hot-pluging devices, for those this could make sense. Only other example i can think of where this makes sense is if you have different types on same board, i.e. a bord where Vcc is measured using the onboard ADC, and Vsupply is measured using a SPI connected ADC, and you want to reuse the interface.
I have designed from more or less the same principle for many years, but I just define the .h file as the interface, and .c as the implementation. When HW changes i only need to change the implementation (the .c file). So when building for board v.1 i use "adc.h" and "ver1/adc.c", when I build for board v2 I use "adc.h" and "ver2/adc.c", and no changes to the upper layers is needed.
So unless we talk runtime variation in the driver version, what is the reason for using your setup? Please explain I want to understand this.
Great question - and yes, static linkage with selective source inclusion is definitely a valid choice, it has the advantage of direct function calls without any overhead. I initially considered to put more examples, but the presentation started to look overcomplicated, so I focused on this example only. The idea was to demonstrate how a highly flexible and portable implementation can look like in C.
Thanks for pointing it out!
Excellent presentation!
Thank you for the feedback!
Great presentation and examples to illustrate the use of function pointers in C to define and implement interfaces to provide flexibility and polymorphic behaviour without having to resort to C++.