About embedded programming
Most embedded software is built on a multi-layer architecture, where lower layers provide
drivers for a simpler way of using different hardware peripherals. Then those drivers can be
used for implementing drivers for more complex devices or for high-level application related
functions.
The figure below illustrates a software architecture example where an MC33984 high side
switch chip is used for driving some loads, supervising their power and detecting errors while
providing a serial communication interface to the user.
This document is focused on lower software layer interacting with the MCU’s peripherals
directly. In embedded C software there are some restrictions compared to regular C software:
The program must never reach the end of main function. It usually ends up having a
main loop with a state machine or an empty infinite loop.
All the local variables have to be defined at the beginning of a function.
Main function has often the same structure: first it initialises the system clock and mode and
then it initialises and configures each peripheral it uses. On this MCU it also has to disable the
watchdog before doing anything else.
Most of the programming is done by writing and reading peripheral registers so use of masks is
pretty common for accessing specific fields (AND ‘&’ mask for clearing, OR ‘|’ for setting, XOR ‘^’
for toggling).
Due to limited amount of code and data memory, compiler optimisations are quite handy, but
the result might turn into an undefined behaviour if variables that are altered by external
environment are optimised. To avoid this, the keyword ‘volatile’ can be used with these kind of
variables.
MC33984 SMART MOS CONTROLLER
APP. DRIVER
&
MCU DRIVER
LAYER
MCU HW LAYER
(Registers etc.)
x |= mask; /* Bits specified by the mask are set, others unchanged. */
x &= (~mask); /* Bits specified by the mask are cleared, others unchanged. */
x ^= mask; /* Bits specified by the mask are toggled, others unchanged. */