mspgcc: A port of the GNU tools to the Texas Instruments MSP430 microcontrollers | ||
---|---|---|
<<< Previous | Next >>> |
As well as the usual things a good programmer will do, there are some issues specific to mspgcc which you should be aware of.
If you are sure your main routine will never exit, you can use the "-mendup-at=main" flag when compiling. This will save 6 bytes of ROM.
Avoid passing long argument lists to functions. Avoid returning long values from functions. The most efficient function types to use are void, int, or pointer.
Avoid initializing global variables within a small function. Instead, assign a value during variable definition.
Avoid converting chars to another type. char variables can be located anywhere in RAM, while word variables can only be at even addresses. Because of this, the following code:
const char *a = "1234"; int k; k = *((int *)((char *a) + 3)); |
Use int instead of char or unsigned char if you want a small integer within a function. The code produced will be more efficient, and in most cases storage isn't actually wasted.
Inspect assembler code (-S compiler flag). The compiler cannot eliminate dead code in some cases. Do not write dead code :)
Do not declare your own SFRs. They are all declared in include files in the right way to achieve maximum code performance.
Try to minimise the use of addition and subtraction with floating point numbers. These are slow operations.
Use shift instead of multiplication by constants which are 2^N (actually, the compiler may do this for you when optimization is switched on).
Use unsigned int for indices - the compiler will snip _lots_ of code.
Use 'switch/case' constructs rather than a chain of 'if/else' constructs.
Use logical or ('|') rather than '+' for bitmasks.
When defining bit fields, try to use signed integers. This produces more compact code that bit fields of unsigned integers.
Use 'alloca' instead of 'malloc' for locals. In embedded applications trying to avoid any dynamic memory allocation is usually even better ;).
C++ recomendations aside :-), it can be more efficient to use:
#define SMTS 1234567890l |
const long smts = 1234567890l; |
Delay loops are very sophisticated routines.:-) Developers often do something like:
int i = 1234; while (i--); |
int i; for (i = 0; i < 1234; i++); |
Regardless of these optimisation issues, this type of delay loop is poor programming style - you have no idea how long or short a delay it might produce (although there is an obvious minimum bound!). It would be better, and more reliable to define something like:
static void __inline__ brief_pause(register unsigned int n) { __asm__ __volatile__ ( "1: \n" " dec %[n] \n" " jne 1b \n" : [n] "+r"(n)); } |
Use the volatile attribute for variables which may be changed or inspected by more than one processing thread (e.g. the main code and an interrupt routine). If you are used to less efficient compilers, you may be used to writing code like:
int i; interrupt (TIMERA0_VECTOR) irq_routine(void) { i = 42; } void func(void) { i = 0; while (i == 0); } |
To tell the compiler that it must look at the actual memory location of "i" each time it checks or manipulates "i", the "volatile" attribute should be added the definition of "i".
Avoid using the "volatile" attribute, unless it is actually necessary. Because it forces the compiler to generate additional code to load, store and test a variable's memory location under all circumstances, it significantly reduces the effectiveness of the compiler's optimiser. The temptation to make lots of global definitions "volatile", just to err on the safe side, comes at a price.
Try to avoid doing tricky things in your code, unless you are really confident you understand their consequences. :-)
<<< Previous | Home | Next >>> |
Library calls | Hardware tools |