C compilers are getting more and more advanced, but there is always a trade off made between speed and code size. Compiled code can be faster or smaller but not both. So you have to choose which part is more important speed or code size.
The Increase of microcontroller code efficiency can be done in many ways. Don’t trust compiler optimization features, as they might not bee as effective as you expect. It is better to grab some profiler and inspect what parts of your code takes the most time and size.
It is better to follow some techniques that may reduce code execution time and increase microcontroller code efficiency:
Use keyword inline to any function you want. This makes compiler not to call a function, but to copy the function code in to desired place. This technique is effective when inline function is called frequently and it contains a few code lines. In other hand bigger functions can fill you code size limit very fast.
Table lookups are implemented by using switch statement. Be smart using switch statement. Put most likely sentences firsts and last likely sentences last. This may reduce execution time.
If there much work to do within switch cases might be it is better to replace switch sentence with table of pointers to functions.
Assembly is always the best optimized code (well not for all programmers). You can make code efficient as you need. But sometimes C or C++ compilers produce better code than average programmer. So decide is this worth your time to mess up with assembly. But using inline assembly can significantly increase microcontroller code efficiency.
Use register values
Register keyword can be used when declaring variables. This makes compiler to assign variable to a genera purpose register besides a stack. Use this keyword to most frequently used variables.
Consider global variables
In computer software development it is strictly recommended to use local variables to make code more universal and readable. But in embedded systems it is more efficient to use global variables as this eliminates the need to push parameter to stack before function call popup. You increase speed of you code but loose modularity.
Polling vs. Interrupt
In embedded systems interrupt routines are used frequently. So sometimes might be to use polling routines to communicate the hardware. In some cases interrupts my cause latencies. Using polling also leads to less modularity.
Don’t use float point arithmetic
Floating point arithmetic is a killer of microcontroller code efficiency unless your design includes FPU. Otherwise compiler uses software subroutines to simulate floating point arithmetics. There are many techniques which let you avoid using floating point operations like byte shift instead divide and so on.