Create MCU Independent Embedded Code

One of the struggles in the embedded world is writing software that is reusable in other projects with different microcontrollers. The reason to that is every microprocessor has its own I/O and hardware structures. Good news! you can still write fully portable MCU software with the Porty framework 🙂

What is Porty?

Porty is prepared as a template for a C/C++ project and it provides common interfaces for basic functionalities like GPIO such that editing the files of that framework is enough to port your project to any microcontroller.

What does it offer?

The goal of Porty is to make the application and middleware layers unaware of the MCU hardware. With other words, Porty plays a role as a proxy between the hardware and the application.

As basic example, you can use mPinWrite(...) macro to change the value of an I/O without touching any registers or use only the CLOCK_MHz  definition in your timing calculations without worrying about the crystal frequency.

Project files

The given software is an example project for STM32F100 Discovery board and it is supposed to work with other STM32 series without any modification.

To get the benefit of Porty, you must include porty.h  file from all of your source files and It takes care of other necessary includes for the system to work.

You can also add your own header to porty.h  includes section and stop worrying about their scopes since porty.h  is included from every file. Other than that porty.h  file has the definitions for CLOCK  and basic delay macros. You can safely rely on the CLOCK_xHz  values to build your timing.

The most important part is the hardware-abstraction macros that are defined in platform.h  file. This file is fully microcontroller-dependant and must be edited when porting to other platforms. It is the place where MCU headers are included.

General-purpose section implements macros for the most essential functions like Interrupt and Watchdog.

Here you can see the interrupt enable/disable macros. Once this file is prepared, you can use mIntEnable()  and mIntDisable()  macros in your application code. mIsEnabled()  macro returns the status of the interrupt which can be used before disabling to re-enable afterwards or not. Example usage is shown below. (Note that for ARM Cortex-M there is no smarter way of doing this)

Pin macros part is the other important part. Here you can control the input/output pins easily.

Although the macros seem like re-declaration, there are 2 types of macros here.

The ones with trailing underscore are the real macros that you need to modify for your platform, and the ones without underscore are to enable the usage of PORT,PIN style pin definitions (that are defined in board.h  file). Here mPinWrite(LED_Green, 1)  expands PORT,PIN into 2 parameters and calls mPinWrite_(GPIOC, 9, 1)  with 3 parameters.

Board definitions file board.h  also includes Interrupt priority settings and other MCU-related stuff.

All the global settings goes into settings.h  file.

Finally the only C file, board.c  has board-related initializer function Board_Init() . You must call this in the beginning of your main.c  and put all hardware related initialization code in this function.

Blinky example

Now its time to demonstrate Porty with the most basic LED blinking example.

This example only blinks the green LED on the STM32VLDISCOVERY board at 1Hz with the not-so-precise delay_ms(...) function. Of course a more precise delay is expected and it is yet to come in another post.

Download

Full project with example application Porty-0.1.0. GitHub repository for STM32F10x port is here.

Compilation

The attached project is compatible with GNU Arm Embedded Toolchain (gcc-arm-none-eabi) and to compile the project you can use GNU MCU Eclipse or your favourite environment. Refer to this tutorial page for compilation environment setup instructions.

Conclusion

This is not a fully implemented project but more a starting point for embedded developers who want to write high quality code. For sure, there is a trade-off between portability and performance. Unfortunately, most of the functionalities like ADC are not possible to make portable while preserving their top performance. I have UART, ADC, EXTI, PWM etc drivers that are designed for Porty but they are not the best when compared to non-portable drivers. This is why Porty is kept basic and simple for the time being.

Good porting day ?