Separate platform specific code from general logic code for embedded peripheral drivers

Viewed 78

I am trying to write a peripheral driver for one chip I am using on STM32. To make the driver general for all chips I will possibly use in the future, I am trying to separate the platform-specific code and the code dedicated for the chip. I am wondering is there a discipline that I can follow?

Currently, I am thinking about 2 possibilities:

  1. Use weak functions to separate. The chip driver will rely on several weak functions, and the user provides functions to override the weak functions.

  2. Use an initialization structure, which contains several function pointers that point to the hardware-specific functions. And the driver will use these functions provided during the initialization process.

But I cannot foresee what are the pros and cons.

2 Answers

To develop a cross-platform driver/library you should mix several principles of the software architecture design.

One is modularity and layers in your driver/library, normally there is one base layer (pair of .h and .c file) that should satisfy all the base and logic of the driver. The secon layer is a specific platform later that should include the basic functions to interact with the microcontroller for example de specific SPI interface functions. If you want to make a driver or library for all the stm32 family you can condense this in only one layer because of the standar names of HAL interface functions across all the stm32 family.

Regarding your point 2 this is the standard way to create a library. The struct allow you to create different "pseudo-objects/handlers" in c, this is useful for example when you need to create several different instances/handlers to interface to. For example if you develop a library for motor driver and you are developing a rc-car you will need to control 4 diferente drivers and will need 4 handlers.

Of the approaches you listed I think that 2. is the more popular choice. The setup for 2 is pretty easy and doesn't rely on any compiler specific weak pointer directives. It also makes it easy to re-use code on several slightly different platforms by setting the right pointers. There is a slight performance hit to 2. vs 1. because you need to do an extra pointer dereference for every function call. This usually won't matter, but it could in some scenarios.

Another common approach is to have a header file that has a separate implementation file per platform. To compile for the platform you just pick the right file / files. This is similar to the weak function approach but without actual weak pointers. For example your project setup could be:

main.h
main.c
platform.h
platform.stm32.c
platform.tms570.c
Related