Author Topic: Best way to write modular 'C' code for microcontrollers  (Read 8122 times)

0 Members and 1 Guest are viewing this topic.

Offline ZeroResistanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 585
  • Country: gb
Best way to write modular 'C' code for microcontrollers
« on: November 17, 2016, 02:00:59 pm »
I'm trying to write an interrupt based driver for the PS/2 keyboard using PIC24F.

What I'm trying to understand is what is the best way to modularize this code.

1. This piece of code will use some pins and resources and interrupts of the uC.
2. Where do I define these I mean suppose I want to use a pin of PS2 clock and PS2 data, I see that the standard procedure is to make a '.h' file of the same name like 'ps2keyboard.h' and put these into that file.
3. But what about fixed resources that the module uses like a fixed external interrupt pin like INT0 or INT1 how do I ensure that no one else uses that resource.
4. Then comes interrupts again this would have its own interrupt handler where should the interrupt related code go?
5. Then comes other peripherals like timers, uart, if this module needs to use those resources where would those be defined and how would those be used?

I've just used the PS/2 keyboard as an example here but in general this question applies to the design of modular code and then reuse of that code across other projects.

There may be other points which I have missed and I would like to hear from forum users what would the best way to approach this issue.

TIA
ZR
« Last Edit: November 17, 2016, 03:40:05 pm by ZeroResistance »
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #1 on: November 17, 2016, 02:30:02 pm »
Good question, I've always wondered that myself.  :popcorn:
If you said C++, I would have some kind of answer, but C....  :palm:

2) But then you would have to edit the ps2-file.h when pin assignments change. Now that is not very modular IMO.

I gues you could take this as far as you like. You would probably take it further if you were writing a library, than just an 'app'. Most would assume you know everything that is going on in the app, so no need to make it all generic and modular.
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3461
  • Country: it
Re: Best way to write modular 'C' code for microcontrollers
« Reply #2 on: November 17, 2016, 02:57:03 pm »
Good question, I've always wondered that myself.  :popcorn:
If you said C++, I would have some kind of answer, but C....  :palm:

2) But then you would have to edit the ps2-file.h when pin assignments change. Now that is not very modular IMO.

I gues you could take this as far as you like. You would probably take it further if you were writing a library, than just an 'app'. Most would assume you know everything that is going on in the app, so no need to make it all generic and modular.
nothing that can't be done with defines.
you want static pin assignment because the code gets optimized a lot , at least on lower end micros
your library header could contain something like
Code: [Select]
#ifndef _ALTERNATE_PIN_ASSIGNMENT
  /* Default direction mask */
  /* Default pin assignment */
  #warning "Default Pin Assignment use. Refer to library documentation"
#endif

interrupt are a bit more of my concern too. that means you have to restrain for using specific resources, which sucks and will make things harder for future projects with those libraries. I am doing it because i'm software emulating some peripherals and in that case a dedicated timer and interrupt has been a must
 

Offline ZeroResistanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 585
  • Country: gb
Re: Best way to write modular 'C' code for microcontrollers
« Reply #3 on: November 17, 2016, 03:48:55 pm »
If you said C++, I would have some kind of answer, but C....  :palm:

2) But then you would have to edit the ps2-file.h when pin assignments change. Now that is not very modular IMO.


I don't mind you answering for C++ too however I wonder if the xc16 compiler supports C++.

Yes to edit the ps2-file.h would be not sensible for every new project would there be some way to pass pins into this module, so that from main we can specify pin assignments.
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3461
  • Country: it
Re: Best way to write modular 'C' code for microcontrollers
« Reply #4 on: November 17, 2016, 04:34:54 pm »
yes. read my reply. that's how i do it. not sure if it's the best practice but it's still a better way than some digital write style crap
 
The following users thanked this post: ZeroResistance

Offline bktemp

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: de
Re: Best way to write modular 'C' code for microcontrollers
« Reply #5 on: November 17, 2016, 04:40:10 pm »
Yes to edit the ps2-file.h would be not sensible for every new project would there be some way to pass pins into this module, so that from main we can specify pin assignments.
Assigning pins at run time works fine if the controller supports peripheral pin select. Otherwise I wouldn't do it, because it leads to inefficient code and is rarely necessary. Switching interrupt pins can be done by adding a HAL layer with callback functions that can be assigned during runtime. For small controllers this is useless, because it waste many kbytes of flash and it will also waste a lot of CPU time for small interrupts because of the increased overhead.
If you don't like to edit the ps2 header file, add a ps2_config.h file where you can select the pin configuration. This is often used, because it generates the most optimized code.
 
The following users thanked this post: ZeroResistance

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: Best way to write modular 'C' code for microcontrollers
« Reply #6 on: November 17, 2016, 04:47:21 pm »
Maybe you could use a pre-build script to process a pin defintions file (in a format of your choosing) and generate the actual .h files. This could be called from the makefile so the .h files only get regenerated when you change pin definitions.
 
The following users thanked this post: ZeroResistance

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #7 on: November 17, 2016, 05:27:44 pm »
I tend to write a .c & .h file for each peripheral.  I don't have any clever way to preclude using a pin twice but it hasn't happened yet.  I usually have a file, init.c, that calls all of the initialization functions in the proper sequence.  If I put the interrupt handler in the peripherals code file, I need to expose the function so that I can program the NVIC.  Not a big deal.  If the program is fairly trivial, I might put all of the handlers in the interrupt file.  I guess it depends on how I feel at the moment.

I don't spend a lot of time worrying about porting the code to another device.  If I am writing for an mbed, I'm not thinking about an Arduino or even an STM32F4.  Maybe the high level code will port easily but it's just a given that every detail of the hardware dependent code will change.  No point in worrying about it.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: Best way to write modular 'C' code for microcontrollers
« Reply #8 on: November 17, 2016, 05:31:14 pm »
I usually have a hardware.h which holds all the pin GPIO pin definitions & control macros, system timer frequency, clock frequency. Then each hardware related software module has it's own initialisation & control routines for the peripherals it uses. I'd avoid making too generic layer when it comes to hardware because it is easy to create layers which don't add any real functionality.

When it comes to handling a protocol it is a good idea to split it into a part which handles the physical layer (receiving & transmitting packets) and another part which deals with the higher level protocol part. This should make it easier to port the code.
« Last Edit: November 17, 2016, 05:34:07 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #9 on: November 17, 2016, 05:35:49 pm »
It's easier if you have a bunch of processors in mind. It's hard to guess at what low level code on one type of processor will look like on another processor.

My suggestion would be to write the code for the particular project that you have now. Take pains to make it neat without any bad hacks or things like that. When it's time to port it to some other processor or project, one of your tasks will be to go to this code and at that point get an idea for what the similarities and differences are. You'll be in much better position to write modular code once you have an intimate understanding of what can and can't be modular.

What you don't want to do is spend gobs of time guessing at it and creating a system that is only of limited value when you have to move it. It's better to have a good solid idea of what you're really up against when you're talking about low level code.

Sometimes, and this isn't what you expect to hear from a software engineer, the most practical way forward is to just not worry about it because the complexity and compromises of making something portable outweigh the benefit you gets. Sometimes, it's easier and more reliable to simply rewrite some simple bits of code than it is to maintain a more complicated library. You have to use your judgement here.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #10 on: November 17, 2016, 08:46:56 pm »
Besides the question if you should or should not, the question is how if you do.

Using #defines as an API to a software component/module is very suboptimal IMO.
For a hint on my C++ answer see my signature... 

My philosophy is that you try to create a library of generic and reusable components that are fully (unit) tested and known to be good. That means that you should not have to change a single character to use it in your project. After a while creating a new app is very easy because you have a lot of known good building blocks to pick from.

You harvest generic code from existing projects (like John said in the previous post).

Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #11 on: November 17, 2016, 09:12:03 pm »

Sometimes, and this isn't what you expect to hear from a software engineer, the most practical way forward is to just not worry about it because the complexity and compromises of making something portable outweigh the benefit you gets. Sometimes, it's easier and more reliable to simply rewrite some simple bits of code than it is to maintain a more complicated library. You have to use your judgement here.

The best FORTRAN programs were written after the box of cards was dropped.  It's amazing how much more clear the solution is when you can start fresh with prior experience.
 

Online hans

  • Super Contributor
  • ***
  • Posts: 1640
  • Country: nl
Re: Best way to write modular 'C' code for microcontrollers
« Reply #12 on: November 17, 2016, 11:04:03 pm »
You can get quite far with defines and preproccesors tricks in C, but creating a dependable and testable code base without reaching out to very messy hacks is near to impossible. You will quickly reach to const array's (that need to be optimized away - they should not appear in FLASH) or maybe even worse: macro tables.

However I think that if a truly modular code base is a requirement, switch to C++ and ditch all MCU's that don't support it. It's unfortunate that XC16 does not have a C++ compiler, which I really don't understand from Microchip. AVR has it, MSP430 has it, and I would consider the PIC24 to be more than capable of it.

After all, it's up to the programmer to use the provided language features wisely. Static classes and some templates can be extremely useful, as long as you're aware of what code all stuff translates to. For other chips, this site is quite good fun to get a live view of several GCC compilers: https://godbolt.org/

I also saw this project the other day:
https://github.com/fabio-d/xc16plusplus

But I don't know how up-to-date this is, if it works, or how stable/bugfree it is.
Would like to try it out some day when I got the time.
« Last Edit: November 17, 2016, 11:08:16 pm by hans »
 
The following users thanked this post: ZeroResistance

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #13 on: November 17, 2016, 11:20:29 pm »
FWIW, there's really no reason you can't write object oriented code using C....or assembly, for that matter. It's a pretty common design pattern to use structs with function pointers, bind the function pointers (and maybe even some data pointers to other structures) at runtime depending on the specific hardware, and voila....you've got something resembling objects in function, if not in appearance. Obviously you don't want to recreate some complex C++ style mechanisms using C code, but this is a nice, simple way of burying a lot of the messiness in one place...namely in your startup configuration code.

But to do it sensibly, you still need to have a pretty good idea of what your hardware going to look like or you'll end up either building an abstraction that doesn't go far enough, or building an abstraction that is so complex it dwarfs the simple task of just writing the code from scratch, salvaging what you can from other projects.

It really helps to get a few boards up and running, and to consider those "prototypes" in the sense that you intend to eventually scrap that code and replace it with something more generic. Once you get some experience with a platform, you can usually jump right in and create a usable library from day 1.

When you've done this for a while, you eventually end up with a bunch of usable libraries and ideas that tend to follow you around like a loyal pet. :)
 
The following users thanked this post: ZeroResistance

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: Best way to write modular 'C' code for microcontrollers
« Reply #14 on: November 18, 2016, 12:14:09 am »
Sometimes, and this isn't what you expect to hear from a software engineer, the most practical way forward is to just not worry about it because the complexity and compromises of making something portable outweigh the benefit you gets. Sometimes, it's easier and more reliable to simply rewrite some simple bits of code than it is to maintain a more complicated library. You have to use your judgement here.

I have to agree wholeheartedly with this approach. The difficulty in practice is knowing when to stop over-engineering for something that isn't in the plan, and instead concentrate on what you have planned. If you discover late on in a product design you have picked the wrong processor*, it is likely that you now have a lot more problems on your hands than a software port, for example your project may not now even make financial sense anymore, or there might not be the right skills available. This sort of thing should have been determined at a very early stage and that is what a POC is for.

So yes, make the effort to modularise and layer your code, and use #defines for your hardware, but also remember that often you are resource limited so excessive abstraction is also to be avoided. I too am a bit of a fan of function pointers with structs where appropriate, and having a naming convention for namespace implementation, but none of this should be overbearing, leading to unnecessarily complicated code obfuscating its purpose.

As with all engineering everything is a compromise, made up from several requirements of varying priority. Trying to develop generic interfaces for unknown and unplanned hardware scenarios is hard and excrutiatingly time consuming, and in many cases impossible unless your crystal ball skills are up to scratch.

* By "picking the wrong processor" I'm talking about discovering that you need to change chip family or vendor, not that you might simply need a few more pins or a bit more memory within the the same device family which is usually simple from a software point of view, but it might need a new board spin, so usually nothing more than a minor irritation.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #15 on: November 18, 2016, 01:43:01 am »
Quote
3. But what about fixed resources that the module uses like a fixed external interrupt pin like INT0 or INT1 how do I ensure that no one else uses that resource.
4. Then comes interrupts again this would have its own interrupt handler where should the interrupt related code go?
You can only go so far to utilize or protect resources that are fundamentally un-sharable.
Quote
the most practical way forward is to just not worry about it because the complexity and compromises of making something portable outweigh the benefit you gets
Yeah.  That.  You really don't want to implement a timer hw allocation mechanism that loops through all the timers available on the chip looking for one that isn't assigned to some other function yet, and figuring out how to use that timer with your "modular code" (keeping in mind that a given chip usually contains several different types of timers.
The interrupts are actually a pretty good mechanism for defending resources.  Put your ISRs (usually with fixed names) in your C code, and if anyone else uses the same ISR, you'll get error messages at link time.
I'd have ps2k.c, ps2k-private.h, ps2k-api.h, psk2-config.h  - stuff that you expect to be easily changeable (pin numbers) goes in the last one, and the others shouldn't have to change.
"Not going overboard on portability" isn't the same as ignoring portability entirely, of course.  It'd be better to base your code on a timer callback service rather than a hardware timer, and better to use an interrupt mechanism that allows other pins in the same port to still get interrupts that are directed to other code (on an AVR, there are some pins that generate individually vectored interrupts, and some that only generate interrupts has part of a "pin change" interrupt shared with all the other bits on that port.  It would be reasonable to at least consider both.)

People have mentioned testability.  Testing all cases of a generalized library is "hard."  2nd best is to DOCUMENT those cases you've tested and found working, those you've tested and found NOT working, and those you haven't tested but expect to fall in one side or the other.

Spend a lot of time thinking about the API to the higher-level code.  Chances are that being able to move the ps/2 keyboard to use a different type of interrupts may be less important (portability-wise) than being able to replace the ps/2 keyboard with a USB keyboard, so ... do you really want to use key codes that are specific to PS/2, or do you want something more generic (any codes permitted) or more specific (unified codes for the common keys)?


Quote
5. Then comes other peripherals like timers, uart, if this module needs to use those resources where would those be defined and how would those be used?
A library should touch as few "other peripherals" as possible.  There's not excuse for a PS/2 keyboard library to do anything with a UART.
You CAN use "abstracted" features controlled by the config file.  Fiddling with UART registers would be awful, but using "debug_print(xxx)" is fine...
 
The following users thanked this post: ZeroResistance

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #16 on: November 18, 2016, 07:26:59 am »
So we have two ways for modular design in C:
1) use #defines
2) use structs & ptrs

#defines will work for smaller projects but will be a mess when scaled up. I like to use the modern IDE features that suggest values/operations and defines is not the best for that.

Using structs and ptrs is less optimal than using C++ templates. Usually C++ templates are optimized very well - produces smaller code that uses less RAM. For large ARM processors this might not be an issue, but for small resource-limited MCU that is something you need to look out for.

For interrupts I provide (inline) methods that can be either called from an ISR, but the choice to use an ISR is made at app level, not at module level. If the app decides to make it an ISR it just calls that specific method or a combination of methods provided by modules and others provided by the app itself.

Part II of my C++ answer...
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 
The following users thanked this post: ZeroResistance

Offline ZeroResistanceTopic starter

  • Frequent Contributor
  • **
  • Posts: 585
  • Country: gb
Re: Best way to write modular 'C' code for microcontrollers
« Reply #17 on: November 18, 2016, 08:17:27 am »
So we have two ways for modular design in C:
1) use #defines
2) use structs & ptrs



Interesting!
In the Ps/2 keyboard example or for that matter any other library could you explain a bit of how to use these #defines and structs and pointers?
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #18 on: November 18, 2016, 09:38:52 am »
Use defines to communicate app-variable but module-static data such as which pins to use etc.
Use structs to group module instance data and have a common parameter for all module-related methods.

<module>.h
Code: [Select]
#ifndef MAX_BUFFER_SIZE
#define MAX_BUFFER_SIZE 16
#endif

#ifndef MODULE_SENSE_PIN
#MODULE_SENSE_PIN 0
#endif

typedef fnCallback ...

struct Module
{
  uint16_t SomeModuleVar;
  char[MAX_BUFFER_SIZE] ModuleBuffer;
  fnCallback OnNotify;
};

// stupid example method
void setNotifyCallback(struct Module* this,  fnCallback handler)
{
    this->OnNotify = handler;
}

void Initialize(struct Module* this)
{
    // use masks and shifts as needed
    MCUREG = MODULE_SENSE_PIN;

    this->SomeModuleVar = 1; // set some state
}
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 
The following users thanked this post: JPortici, ZeroResistance

Offline Lukas

  • Frequent Contributor
  • **
  • Posts: 412
  • Country: de
    • carrotIndustries.net
Re: Best way to write modular 'C' code for microcontrollers
« Reply #19 on: November 18, 2016, 01:03:00 pm »
I consider the firmware for my DIY watch to be quite modular: https://github.com/carrotIndustries/pluto-fw/
It clearly helped that the firmware has to be compiled to run on linux as well, so register accesses mangled with application code is a big no-no
Some random hints:
 - Avoid global variables, make as many variables/functions static as possible
 - Use enums. Although enums aren't type safe in C, they still help to communicate the design intent
 - Follow a strict naming convention. Since C doesn't give you anything like namespaces and classes, it's up to you to name things sensible.
 
The following users thanked this post: ZeroResistance

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #20 on: November 18, 2016, 01:36:57 pm »
- Use enums. Although enums aren't type safe in C, they still help to communicate the design intent

You can fix that.

Usage:
Code: [Select]
    BeginEnum(ControlState)
    {
        Normal,     // no other states active
        Hidden,     // control is not displayed
        Disabled,   // control is displayed as read-only
        Focused,    // control is high-lighted
        Selected,   // control is active/selected (entered)
    }
    EndEnum(ControlState)

   ....

    inline bool getIsDisabled() const
    {
        return _state == ControlState::Disabled;
    }
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline Lukas

  • Frequent Contributor
  • **
  • Posts: 412
  • Country: de
    • carrotIndustries.net
Re: Best way to write modular 'C' code for microcontrollers
« Reply #21 on: November 18, 2016, 01:49:46 pm »
- Use enums. Although enums aren't type safe in C, they still help to communicate the design intent

You can fix that.

Usage:

That's C++.
But why bother with that when C++ has type safe enums built in? http://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: Best way to write modular 'C' code for microcontrollers
« Reply #22 on: November 18, 2016, 01:54:34 pm »
Is it? Sorry, I always get them confused.   :-\
The enum class didn't work on the compiler I wrote this for/with...
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Best way to write modular 'C' code for microcontrollers
« Reply #23 on: November 18, 2016, 02:11:23 pm »
It all kind of comes full circle to another thread where we're talking about C and C++. C++ is fantastic and extremely useful if you consider it as an OO extension to C, even for embedded work. It's only bloated and funky if you decide to drag in STL and start using all of strange language features they keep adding to it over the years (though some new features aren't too bad).
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13748
  • Country: gb
    • Mike's Electric Stuff
Re: Best way to write modular 'C' code for microcontrollers
« Reply #24 on: November 18, 2016, 02:24:56 pm »
How likely is it that things will ever need to be changed ?
Does it make sense to spend time making it super-generic and modular if the likelihood of actually needing that is low?
Consider the time spent abstracting and #defining everything that might coneivably change compared with just getting on with it and commenting the things that need changing in the event anything changes.
e.g.
#if productvariant == version1
<the code for that version>
#endif
#if productvariant == version2
<the code for that version>
#endif

etc.

Some things make sense to abstract into a header file - e.g. simple I/Os, 

#define led_out LATBbits.LATB1
#define led_out_tris TRISBbits.TRISB1

But things get more complicated once you start needing to use peripherals and map the peripheral pins.
And even more so once you try to make it generic to use one of <n> peripherals.
You end up with so many abstracted things it becomes hard to debug and follow exactly what's going on. 

And even harder if code density really becomes important e.g. merging pin direction defines over multiple ports into word-wide values. 

It will definitely take you time now to abstract everything as much as possible
It might save some time at some unknown time in the future if you need to change things.
You need to consider what is the best use of your time.

There is no "right" or "wrong" answer, only more or less appropriate for your particular set of circumstances.

 
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf