Optimize Later in Embedded Software Development
One of the common pitfalls in embedded software development is optimizing too early. This applies to all software but is more prevalent in embedded software development due to relatively tighter processing constraints causing an engineer to feel like they need to optimize immediately. A much more maintainable result can be achieved by writing code for readability first and only optimizing after the bottlenecks have been identified. There are many cases where the cycles saved by a premature optimization do not outweigh the loss of maintainability and higher chance for bugs down the line.
Polling vs Interrupts in Embedded Software Development
Input processing within embedded software development can generally be divided into two categories, polling, and interrupts. Polling is the process of repeatedly checking an input pin within the main control loop and therefore provides more consistency. Interrupts will interrupt your code flow whenever the level on an input pin changes which allows the microcontroller to catch brief pin changes and respond as fast as possible. The choice between the two should be considered for each input individually. Using a simple button as an example, consider two cases: one with software debouncing and one with hardware debouncing. Software debouncing would generally be better with a polled input as the flow of your program would not constantly be interrupted by every bounce of the button input. With a hardware debounced button though using an interrupt would allow you to react potentially much faster.
Portability in Embedded Software Development
A good thing to keep in mind during embedded software development is portability. Consider a prototype developed on a Raspberry Pi that will be ported to a microcontroller in the future. These two systems will have different ways to toggle GPIO (General Purpose Input/Output) pins, read the ADC (Analog to Digital Converter), configure a PWM (Pulse Width Modulation) output, setup timers, etc. Keeping these chip-specific tasks nicely contained can speed up the transition to a new chip down the road. Instead of scouring the code for these pieces, one would just need to rewrite the functions doing the specific tasks allowing the heart of the program to remain identical.
Debugging in Embedded Software Development
Debugging issues in any piece of software can be challenging, but embedded software development can add even more hurdles. A PC application is much more virtualized than the bare-metal programming of a microcontroller. Real-time inputs cannot be paused and even if you are able to set breakpoints many of the hardware modules within the chip, like timers, will drift as they cannot all be stopped in perfect unison. Simulators are useful but can take time to set up and do not always fully support all the features of a microcontroller. An alternative to breakpoints and stepping through code is to send real-time debug info out of something like a UART/Serial/RS-232 interface. If the delay imposed by writing to UART is too large another option could be to log data to internal RAM (memory) and print that out after the relevant event. Either way removes any weirdness that debuggers could inject.