Home > On-Demand Archives > Microtalks >
Developing and Maintaining Application-Independent Driver and Hardware Abstraction Layers for Embedded C
Prabo Semasinghe - Watch Now - EOC 2025 - Duration: 22:47

Creating reusable, easily maintainable, and scalable firmware with a modular architecture greatly benefits development teams. When similar hardware is replicated in multiple projects, the temptation to copy and paste code across projects is strong! However, is this the most effective approach to code reuse? How do you manage bug fixes and improvements for code that is duplicated in various projects?
This session will explore how to generalize and decouple the driver layer and hardware interfacing layer into independently manageable firmware components. Topics covered will include:
- The benefits of developing separate, manageable Driver and Hardware Abstraction Layers (HAL).
- Strategies for writing and managing generalized code:
- Using submodules for code management and reuse.
- Linking generalized driver and hardware abstraction layers with applications via a specific manager module.
- Handling product-specific functionalities using function pointers.
The session will provide examples to illustrate these concepts and demonstrate their application in practice.
Thank you very much. Im glad you enjoyed the talk.
How do you manage shipping multiple projects from one code base? Meaning that you ship product A after a costly qualification process then you make changes to support a very similar product B. Now the code base used to make product A has changes that have not been qualified and it is cost prohibitive to do so. Do you branch the code base for each project release?
Hi Steve,
Thank you for your question. I can see that I did not explicitly mention which modules are managed separately and which modules are managed within the product specific code base. In this specific example, temp_sensor module is the product independent part and the idea is to manage that in a separate git repository (let's say tempSensorHAL). tempSensorHAL is product independent. You can import this repo to both A and B repos as a submodule. Each project (A and B) will have separate manager modules to handle the product specific portion. Bug fixes and improvements for tempSensorHAL can be done in one place and you do not have to worry about changing it separately for each project. Hope this answers your questions. Please let me know if you have more questions or need any further clarifications.
Thanks for the talk. If anyone wants to dig deeper into using function pointers for hardware abstraction, I'd encourage them to look at Zephyr RTOS. Drivers in Zephyr are done using an api structure containing functions pointers. Each implementation of a driver then has its own implementation of the function pointers. There's been quite a few Zephyr talks these last few years are EOC so I'd encourage people to look at those ;)
Hey Nathan,
Thank you very much. Yes I agree, EOC is a great platform for anyone who wants to check that out. Thanks for bringing it up.
I liked your talk, I use similar design in my modules, and I agree in many of your arguments.
But I have one question
Your example is basically dependency injection which can be used to break some dependencies. but I miss the argument as to why You chose to have a parallel manager module, meaning that the main module now has to take care of both, and know about the hidden dependency between them to call them in the right order.
In contrast to if you added temperature sensor as a service or BSP module, that would then use Your HAL temperature sensor module, lets name them tsensBsp and tsensHal, for this example.
tsensBsp.c
void tsensBsp_init( void )
{
tsensHal_init( PIN_22 );
}
tsensHal.c
static int spiEnPin = -1;
void tsensHal_init( int pinNmbr )
{
spiEnPin = pinNmbr;
// ......
}
Then main does not need to care about a hidden dependency between senModule and senmoduleManager. It will simply call tsensBSP_init();
This same pattern can be used with callback pointers as you use, if there is more than the pin-number that varies.
NB: I would not chose those names in the real code, they are for clarity in this example
Hi Otzen, Thank you very much for your question. It is a great question and very insightful.
The manager module Im talking about in the presentation does have the similar functionality as a BSP module, i.e., taking care of the board specific depndancies. Of course temp_sensor_init() can be called inside of the temp_sensor_manager_init() function, so the main routine does not have to worry about that dependency and just call temp_sensor_manager_init().
I'm really happy to know that you are using similar design in your work too.
I enjoyed this talk and plan on rewatching it. Please consider presenting a workshop next year, because I think it would be fun. Thanks!
Thank you very much. I'm glad you enjoyed the talk and yes, it is a great idea to do a workshop, I will definitely consider that in the future.
I hope you enjoyed the talk. If you have questions/comments please keep them posted!
Thank you for a nice presentation. I always enjoy seeing different ways that designers use to decouple hardware dependencies in a project.