2
\$\begingroup\$

I got 2 totally different microcontrollers (one is 16-bit MSP and another 32-bit nordic). They are supposed to do the same task and I thought that maybe it would be posible to write one program in C language and then use different compilers while programming them. I got some common xxx.h files with different source implementations for each device so part of the code would look exactly the same. The difference is when it comes to writing internal registers and that part of code has to be various for each device so I tought about introducing some macro that would point which microcontroller I want to compile code for. Then I would be able to use #ifdef directive inside source files to carry conditional compilation. I have no experience with such programming so I need some tips, is it good idea or is it better to write one program for each microcontroller ?

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

The trick is to define an interface that gives you access to the I/O pins (or other peripherals and functionality that you need, and maybe a delay functions). Declare this interface in a .h file. Now write your application in one or more .c files that use this .h file. Write two .c files, one for each platfom, that implement the interface for that particular platform. When you build for one platform, compile and link with the correct implementation .c file.

A possible .h file:

bool pin_read( unsigned char pin );
void pin_write( unsigned char pin, bool value );
void configure_pin_as_input(  unsigned char pin );
void configure_pin_as_output(  unsigned char pin );
void delay_us( unsigned int t );

This approach does not require any preprocessor trickery, but its does impose a function call overhead on each access to a platform-specific function. If this is not acceptable, you could implement both interfaces as macro's in the .h file (using #ifdefs to select between them).

Another trick is to stick with the .h/.c approach, but to compile all application code with the implementation.c included, and rely on the optimizer to eliminate the function call overhead. This requires two different 'main' files, one for the 16-bit target

// main.c for MSP430
#include "interface.h"
#include "msp430-interface.c"
#include "application.c"

and one for the other target

// main.c for Cortex-M0
#include "interface.h"
#include "CortexM0-interface.c"
#include "application.c"

Personally I prefer C++ to tackle such problems, and I essentialy use the last approach, which is quite normal for C++ template-based programming (templates must be in the .h file). (See this article and this video for my approach)

\$\endgroup\$
2
  • \$\begingroup\$ Generally this is a good answer, but please never #include .c files. There should never be a reason to do so, if your IDE and linker are somewhat sane. Furthermore, this adds tight coupling between main and the hardware, which is bad. You should only need to swap out the msp430-interface.c in the project for the cortex M0 one, and it should all link fine, given that those two C files #include the generic interface file and use the same function names. Main should only #include the same generic one. Make sure to use header guards in every single h file ever written. \$\endgroup\$
    – Lundin
    Feb 19, 2015 at 7:52
  • \$\begingroup\$ I agree that including code (other than C++ templates) is the least desirable option, and in such a case those files should not be called .c to state their use explicitly. In that case the main.c is not a classical main, that role has been taken over by the included application, and the main.c has the role of a configuration file. Not the most common or approach, still OK in some situations. The coupling between the 'main code' (in one of the included files) and the harfdware is the same as in the normal interface-in-.h-files approach. \$\endgroup\$ Feb 19, 2015 at 7:59
4
\$\begingroup\$

Well, I imagine the program you are doing has the same functionality in both micro-controllers.

Firstly, you would write the generic parts of the code, the ones that are not dependent on the architecture. When you write or retrieve data from a specific device from the micro-controller or even access particular registers of the processor, you would call a function.

In the .c file which implements this function, you would then do the #ifdef with a variable defining the architecture to select between the function for micro-controller X and the one for Y.

Maybe you will have to standardize the interface of communication between the generic code and the specific function to be able to support the particularities of both MCUs.

Remember that it would be efficient for a program which has a lot of common parts and just a little bit specific to the architecture.

Another advantage concerns the implementation of new MCUs. If you have to introduce a third architecture to your project, you would just write a couple of new functions, instead of re-writing all of your code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.