so I would just like to hear what others are doing ?
Most firms have their own coding styles and they are generally good. Here is what I do:
1) be good in C: coding a mcu isn't that different from coding a PC - just that writing to certain memory locations have particular, device-specific meanings (to control the peripherals). So you want to be proficient in C, particularly when it comes to modular programming;
2) limit your hardware access: because of 1), you want your code to be as little "embedded" as possible. That means that you want to shield your application away from the actual hardware. Any access to hardware should be done consistently and as much "single-point-of-entry' as possible. You should use the same routines to read a spi module, or send something over uart, or set a pin to output mode, for example. You shouldn't see hardware specific notations in your user code.
3) minimize writing new code: whenever you write a piece of code, think about ways of writing that code so that it can be used later by other programs, on the same mcu or different mcus. This will allow you to build up your own library and greatly speeds up code development.
Take the frequency meter code I wrote recently on a PIC. It contains a few routines:
1) configuration fuse settings: that's a file over 120KB now that sets the fuse settings for the various PICs I use. By including that in my project, I know that I will have a reasonably good starting point to work with and should I decide to change the fuse settings, the file has its own documentation and I can do so easily. Each time I work on a new PIC, I add the default fuse setting to that file and I don't have to look at the datasheet next time;
2) a gpio routine: that manages all my pin-oriented operations - setting a pin, clearing a pin, setting a pin to input or output, etc.
3) a software delay routine: standardized, frequency-conscious delays that will get me rough timing;
4) tmr0/1/2 routines: that initialize tmr0, sets up its isr, and allows a user to install his/her own handle.
5) a led display routine: that at each invocation, updates the led display.
In my application, I simply use the gpio routines to reset the pins, use the tmr0 routines to set tmr0 to trigger periodically and in the tmr0 isr, it runs the led display routine; I used th tmr1 routines to count external pulses; and tmr2 routines to gate tmr1.
The whole main() was done in 15 minutes and the whole thing was up and running in no time. and you could not see a reference to the actual hardware. So if I were to decide to port the code to AVR, or STM32F3, I can simply hook up the same routines there and hit the compile button.
Code portability is really about writing to a logic machine, improving code reliability, and speeding up development time.
Over the years, I have accumulated over 1000 such files for various functions on many mcus. That collection of routines and constant accumulation of those routines allow me to put something out much faster, and with higher reliability than I would otherwise.