2011年8月18日 星期四

Porting from IAR to AVR-GCC (WinAVR)...

A few tips on porting code from IAR to AVR-GCC (WinAVR)...

1)REGISTER/MEMORY LOCATIONS have aliases in the IAR .h file, sometimes have unidentical entries in the avr-gcc files (Often, avr-gcc are the correct ones wrt the datasheet). Such entries must be edited in the source code to match avr-gcc names.

Also, .h files are not called explicitly when using WinAVR, you just use a general call, and the makefile generator takes care of calling the proper .h file.

Example:
IAR: #include
GCC: #include

2) INTERRUPT SERVICES
are handled using #pragma directives in IAR.
Example(IAR):
#pragma vector=TIMER0_OVF_vect
__interrupt void MotorPWMBottom(){
// blabla  
}
Interrupt Service Routines have been greatly simplified in recent WinAVR releases, using the ISR() wrapper.

Example(GCC):
ISR(PCINT1_vect){
//code
}
All vectors are defined in the parts' respective avr-gcc header file, so they will be included using the general
#include NB!
You MUST also
 #include   in the compilation. It will compile without this, but the behaviour will not be correct.

3) INTRINSIC FUNCTIONS
Examples: __enable_interrupts(), __disable_interrupts(), and __watchdog_reset(); are intrinsic functions that have counterparts with other names in avr-gcc.

All these are actual AVR instructions, so they can be called using C-syntax like: asm("SEI"); etc....

These are usually defined as macros for avr-gcc, but they're not co-located in one single file covering _all_ intrinsic functions, rather in the particular .h file pertaining to their function.

Example: sei() and cli() are defined in
Example of how to define:
#define wdt_reset() __asm__ __volatile__ ("wdr")
You can can now call wdt_reset() from your C source, effectively executing a wdr instruction.

4) LOCKING REGISTERS
The IAR compiler lock general registers, from r15 and down, by using compiler options and this keyword syntax:
__regvar __no_init volatile unsigned int filteredTimeSinceCommutation @14;

This line locks r14 for use only when explicitly referenced in your code thorugh the var name "filteredTimeSinceCommutation". This means that the compiler cannot dispose of it at its own will.

There is a way to do this in avr-gcc also: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_regbind

NB! Doing this is not recommended as it removes this register from the purview of the compiler, which may make code generation worse. Use at your own risk.

5) FLASH VARIABLES
IAR has non-standard keywords to define data to be put in Flash. GCC uses "attributes" with their own, non-standard syntax. The reason why both syntaxes are non-standard, is because the C language was not designed for Harvard architecture devices, such as the AVR. So for example, one would have to create macros to define a common way to do this. Like so:

#if defined(__ICCAVR__) // IAR C Compiler
#define FLASH_DECLARE(x) __flash x
#endif
#if defined(__GNUC__) // GNU Compiler
#define FLASH_DECLARE(x) x __attribute__((__progmem__))
#endif

To-the-point:

IAR syntax: __flash int myData[] = ....
GCC syntax: int myData[] PROGMEM = ...  OR  int myData[] __attribute__((progmem)) = ...

NB! To read back flash data, use pgm_read_*() functions, defined in (avr/pgmspace.h).

 All progmem/flash handling macros are defined there.

The STK504 LCD driver has been ported to avr-gcc and can be used as an example (Look for "FLASH_DECL").

 6) NON-RETURNING main() FUNCTIONS: C_TASK
In IAR, simply declare the main() like this:
__C_task void main(void) {
//...
}
With gcc, use a prototype first, that declares it's a non-return function:
void main(void) __attribute__((noreturn));  
Void main(void) {
//...
}

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。