Moving from STM32? Read the 10 Step MCU Porting Guide

Share:

Having to move from STM32 and redesign your PCB due to the chip shortage?  For ease of development, read our porting guide which takes you through the process to help you keep your projects on track.

Julian Skidmore Senior Firmware Engineer, ByteSnap Design

Many developers and manufacturers, are continuing to deal with the repercussions of the worldwide chip shortage due to the COVID pandemic.

One solution to keep electronics product design moving is to port an application to a different hardware platform or microcontroller (MCU).

In this guide, we take you through how we ported an application from an ST Microelectronics STM32 to GigaDevice’s GD32 – both the principles and practicalities.

The 10 Step Mega MCU Porting Guide for Moving from STM32 – Content:

1. Factorise your Firmware

2. Apply the Principle of Locality

3. Abstract Peripheral Interfaces

4. Minimise Peripheral Usage

5. Minimise MCU Constraints

6. Don’t Wait – Emulate!

7. Design for Component Substitution

8. Design for Bring-Up

9. Open the Tools

10. Unify the Build

11. Things Will Get Better

12. Support for your STM32 and other redesign projects

1. Factorise Your Firmware

As a general principle of embedded firmware design, code should be as factorised as possible.

Repeated code means a repeated porting effort wherever the code uses actual registers or peripherals.

With the example used in this guide, the entire firmware is also Object-oriented.

2. Apply the Principle of Locality

The fewer dependencies there are between modules of code in your firmware, the easier it will be to port, because you have fewer side-effects to consider when porting each component.

This implies that IO pin setups should be placed in the modules of code for which they apply, not in a file that defines all the IO pin setups.

A similar principle applies to interrupt functionality – it should be local to the firmware that actually uses it wherever possible.

3. Abstract Peripheral Interfaces

It’s hugely advantageous to make the interfaces to peripherals consistent and abstracted for the application’s needs, but not exceeding the application’s needs.

That’s because the more functionality that’s abstracted, the more effort has to be placed in writing new drivers for the Peripherals.

If it makes sense, one should use standard interfaces, such as CMSIS, if they exist for both of the new and old platform.

Now this may well be the case if you’re porting from an ARM processor that supports CMSIS, to another that does, but if this isn’t the case (e.g., porting from a SiLabs EFM32 to PIC32), then a better route will be to provide your own peripheral interfaces (because otherwise you’d end up porting significant chunks of CMSIS to the new platform too and that would be quite an undertaking in itself).

Part of the problem with peripheral abstraction is that different MCUs can do this in different ways.

For example, the STM32 supports alternative functionality on GPIOs by having a mapping per GPIO pin.

This means there are a significant number of registers supporting multiple GPIOs and it’s easy to specify this when setting up a GPIO pin.

However, the GD32 supports alternative functionality by having a mapping per functional block, to map to one of a set of GPIOs. In our system this is faked as a GPIO mapping parameter (i.e., supplying a given value applies the same peripheral mapping regardless of what GPIO it’s provided for).

It also means you need to abstract interrupt vectors. Different MCUs not only have different names for interrupt vectors, but share them differently.

Thus, on one MCU you may find that there’s only one main interrupt (and a lower priority interrupt which could also service anything); on another you might find that the first timer interrupt is mapped to one vector while the rest are mapped to a shared vector; yet your new MCU has a unique vector per timer interrupt.

Or, your old MCU’s I2c interrupt vector handles all interrupt sources; while the other has a separate vector for errors.

4. Apply the Principle of Locality

The fewer dependencies there are between modules of code in your firmware, the easier it will be to port, because you have fewer side-effects to consider when porting each component.

This implies that IO pin setups should be placed in the modules of code for which they apply, not in a file that defines all the IO pin setups.

A similar principle applies to interrupt functionality – it should be local to the firmware that actually uses it wherever possible.

4 Minimise Peripheral Usage

It’s tempting as a firmware developer to use all the possible hardware features that are available, such as DMA or Events or the peripheral mode that accomplishes as much of the functionality as possible, in order to reduce the application development effort.

But from a porting viewpoint, this is counter-productive, because peripherals on different MCUs often have quite different detailed functionality, which means that either the code would have to be re-written or the missing functionality must be simulated.

It’s better, therefore, as a whole to write firmware to use only the minimum functionality you can get away with and support additional functionality with additional software layers. This also means using interrupts in place of DMA if that can work, or even avoiding interrupts if requirements can be met by other means.

With our project; all we needed was input and output GPIOs with pull-ups and pull-downs; interrupt-based serial transfer (we needed to simulate the automatic DE pin provided on the STM32); ADC sampling on request and PWM outputs for timers. This is because we were porting to another ARM architecture, we were able to use the Systick timer as a general timer.

5 Minimise MCU Constraints

All MCUs have constraints, ranging from the type of CPU core to the physical locations of peripherals on the chip; to the capabilities of the peripherals.

It is better, therefore to anticipate having to work with the lowest common denominator: a less powerful MCU (e.g., a Cortex M0 instead of an M3); and less flexible IO than one would prefer.

For example, it may be necessary to share compare channels in a single timer on the new target, whereas on the old target it was possible to use unique timers.

6 Don’t Wait – Emulate!

Supply constraints may mean a continual hardware redesign and a perpetual moving target with uncertain delivery times.

You can reduce pressure on hardware engineers, by taking hardware abstraction another step and emulating the application on generic desktop hardware.

It’s the norm for smartphone development and may give additional advantages, such as:

  • faster debugging turnaround
  • more sophisticated debugging facilities
  • more comprehensive test harnesses
  • and the opportunity to run the system at different, emulated speeds.

A good design will enable you to develop and test perhaps 90% or more of the system, before the real hardware arrives.

 

7 Design for Component Substitution

It’s not just the processor that might need to be substituted, but also external components, for ones that may have various degrees of compatibility, or different characteristics to the original design.

For example, we migrated from a design that expected a single accelerometer to one where we needed to support up to 7 different types of accelerometers with different register sets and features; at two different locations.

Therefore, it’s not just a case of being able to abstract a target peripheral, but also porting the firmware to make alternatives easy to substitute.

In our case, our firmware was written in C++, so it was relatively easy to define suitable interfaces to multiple device sub-types.

8 Design for Bring-Up

In our project we had some test harness firmware for every piece of functionality from the lowest level, to just below the application.

For our first STM32 to GD32 project, we split the conversion process into a number of stages:

  1. We first ran Blinky on the new target hardware. This meant that we’d largely got the linker script and start-up code right and integrated it with our IDE (in this case Embedded Eclipse).
  2. Then, we ported our basic Serial Debug to the new target hardware. So, now it would be possible to see the output from all our test harnesses. Around this point we needed to make sure that
  3. The entire firmware was then copied to the new project and stubbed out all the direct hardware references.
  4. Next, we ported each low-level driver from the bottom up, and tested it against its test harness.
  5. Finally, we ported the application. Since the application, along with the higher-level functionality was almost entirely free of hardware specifics this was relatively simple.

9 Open the Tools

Although there may sometimes be reasons not to, in general, the more open the set of tools used to develop the firmware, the easier it will be to port it.

That’s because there are few or no licensing issues with porting the software to an open IDE (which lowers the risk); it’s much easier to gain access to enough internals to help make the port easier and finally there’s usually plenty of help.

In our case, we moved from a more customised embedded Eclipse based IDE to a less customised one and we moved from ST-LINK/2 based debugging to OpenCD debugging.

Both of these changes were relatively painless, and more importantly – free.

10 Unify the Build

Unifying the build is critical to being able to maintain the project, since it’s likely you’ll have units out in the field that use the previous hardware, alongside the new hardware and firmware and you’ll have to maintain both.

The easiest way to do this is to make sure there’s only one project to maintain.

We did this by putting platform-specific code in a source code folder called PlatformTargetPlatFormName, in our case PlatformGD32 and PlatformSTM32.

We supported multiple platforms by creating a configuration for each platform. Although Embedded Eclipse seemed to want to share the same MCU across different configurations, it’s possible to edit the underlying .xml files to define unique characteristics including different compilers (e.g., Cortex M0 vs Cortex M4).

The way this was done was to create a separate project for the other platform and then analysing the differences and reproducing them on the combined project.

In addition, for each configuration we have project level defines that specify each project; so that if needed, any part of the source code can detect which configuration it belongs to.

And of course, it’s possible to make each configuration use different source trees.

11. Things Will Get Better

Component and supply chain shortages have been hugely challenging for businesses and innovators since the covid-19 pandemic and look set to continue for at least another year.

However, there is an upside.

Embedded hardware and software practices will improve as a consequence of all the turmoil, as we’re forced to adapt.

In one sense, the above principles are extrapolations of good software design, given additional constraints and good software design can be carried into future development for free.

The upshot will be an industry better-equipped for future shocks and more capable of exploiting available hardware choices in leaner periods.

12. Ease of development – support for your STM32 and other redesign projects

In this guide, we’ve given you a straightforward, walkthrough of what is generally a very complex part of electronics product development.

ByteSnap can help with the porting process if you’ve not got the in-house resources or are short on skillsets. 

Whether you’re migrating from PIC to ARM, or looking for a microcontroller replacement design service, we are trusted, safe pair of hands, who can accelerate your redesign.

If you want to improve your design, we can support you with that too – by refreshing and optimising it, thereby giving your design longevity and ability to build it long term.

We’ve been trusted by businesses around the world on hundreds of porting and redesign projects to deliver them robustly and quickly.

Let ByteSnap help you accelerate electronics design projects to market

To get started on your redesign, just click the contact button below and let us know your project requirements.

Share:

Related Posts