2019-06-05 02:03 PM
I have a project that involves a STM32F7 controlling a stepper motor through GPIO. I have now been tasked with redesigning it with a ST L6470, a motor control IC which has a SPI interface. I would like have a shared codebase so that a simple #define could be used at compile time to choose between GPIO or SPI code depending on the board used. Examples of polymorphism in C such as the linux device driver code and GObject are difficult to understand and perhaps not a good example for microcontroller code.
The solution must be C11 compatible and compiled in IAR EWARM.
2019-06-05 02:16 PM
Keep It Simple is the best of methodologies for embedded C.
Another is to make it Somebody Else's Problem (hire a contractor, let him sweat instead of you).
-- pa
2019-06-05 04:29 PM
OOD sounds like a bit of overkill for a motor controller.
2019-06-05 08:53 PM
OOD is needed only if You have multiple motor instances in one project. In C it can be implemented by defining a structure for object and passing a pointer to it in API functions. If it's only one motor instance in a project, then make one .h file with API definition (set of functions) and multiple .c files for different API implementations. To switch between .c files with a #define, put #ifdef/#endif pair on top/bottom of .c files so that unneeded files are effectively empty.
2019-06-06 08:03 AM
Unclear what you want to do and where OO makes things more modular.
More details are needed.
Are the higher level source code the same and plumbing below either to GPIO or SPI?
2019-06-06 09:14 AM
OOP in C is doable, but for small projects, not likely worth the complexity. However, you can gain many of the advantages of OOP through well structured code, using opaque data types, and using C’s built-in techniques for separating private/public interfaces. Don’t worry about inheritance, use composition instead. Those steps alone keep C plain and simple for none-OOP readers, but give OOP-experienced folks a lot of the “structure�? they like to see.
As for polymorphism, there are fancy ways, but in your case, I’m inclined to think #ifdef is suitable. I use it a lot for the same purpose you’re looking at (building with various optional hardware drivers).
I have a master mProject.h file which declares project level constants. That file #includes mLocal.h which is specifically for the purpose of triggering versions of builds.
(I prefix our code with a “namespace�? of “m�? so I can easily identify “ours�? vs. “theirs.�?)
Two techniques come to mind:
In mProject.h, before mLocal.h is included, you have
// Define a build options to choose from, and a build variable
#define mMOTOR_CTLR_GPIO (1U)
#define mMOTOR_CTLR_SPI (2U)
#define mBUILD_WITH_MTR_CTLR_TYPE mMOTOR_CTLR_GPIO // this is the default build
In mLocal.h you have
// Affirm or override the mProject build variable in your own personalized mLocal file
#undef mBUILD_WITH_MTR_CTLR_TYPE
#define mBUILD_WITH_MTR_CTLR_TYPE mMOTOR_CTLR_SPI // this overrides mProject.h
Next, in your application code files, where you might have
#include “mCtlr_motorGpio.h�?
You would now have
// The file to include is determined based on your build option variable
#if (mBUILD_WITH_MTR_CTLR_TYPE == mMOTOR_CTLR_SPI)
#include “mCtlr_motorSpi.h�?
#else
#include “mCtlr_motorGpio.h�?
#endif
Obviously you could skip mLocal.h and use just mProject.h. However, the advantages of mLocal.h are
2019-06-06 09:53 AM
Think it just needs to use structures passed as pointers, and not use a shed load of global variables.
2019-06-06 11:01 AM
Yes that's how I do my real-time (audio) designs. A proper OOD design would add too much non-determism to the timing which I imagine would be bad for a motor
2019-06-07 08:15 AM
This is a tempting solution for the short term, but multiple motors is a possibility in the future.
2019-06-07 08:20 AM
Right, I don't need a complete OO solution. I am thinking just a shared structure with pointers to the to functions that each codebase would have such as:
initialize
start motion
stop motion
is moving