------------------------------------------------------------------------ << "Abusing" AVR-GCC for Use with RAM-less AVR ATtiny Parts >> ------------------------------------------------------------------------ I've been using "avr-gcc" to program the Atmel ATmega15L microcontroller for some time. I love the part, especially its size, features, power consumption, and price! I've used "avr-gcc" for quite a number of ATtiny15L projects, including a tiny RS232 serial port programmer for AVR in-circuit programming (fits in DB9 connector "hood" and is self-powered by RS232 voltages), a couple of different DC motor controllers, a air-flow sensor, a touch sensitive light with dimmer, and an analog data logger. This use of "avr-gcc" not for everyone! You need to have a good understanding of what kind of C statements generate what kind of AVR assembly code. If you are a "hard core" embedded programmer like me, that part comes naturally. I use avr-gcc version 2.95.2 for ATtiny15L programming, but it is very likely that avr-gcc version 3 will work as well with a little bit of work on the "depreciated" header files. I use the default AVR processor (i.e., AT80S8515), but provide my own I/O header definitions for the ATtiny15L. You *must* use C-compiler optimization (such as -Os) to get AVR code that does not reference any SRAM. I really like the ATtiny15L, and am willing to "jump through a few hoops" in order to make "avr-gcc" work. If you give avr-gcc's excellent code generator a chance, it will generate AVR machine code that is as good or better than hand-generated assembly language, with no need for SRAM. Here are a few of the required "tricks"... (1) Limit the call tree depth to 2 or 3 (e.g., main -> subroutine -> subroutine), depending up whether you will be using interrupts. The ATtiny15L has a "hardware" call/return stack of limited depth. (2) Limit the complexity of your subroutines as to not overflow the available "scratch" registers. I found that this is pretty easy to control, once you have a little bit of experience. (3) Assign any required global variables to registers as in the following example: register unsigned short v asm("r2"); You can expect a "warning" from the compiler because of this. Beware, every "seperately compiled" "leaf" modules needs to be informed of this "reserved" register", not just the "main" program. (4) Use a Perl script to check the generated AVR machine code for "illegal instructions", namely those that reference SRAM (e.g., push/pop/sts/lds) or use instructions missing from the ATtiny15 instruction set (e.g., adiw/sbiw). My "makefiles" add the following rule... .c.o: $(CC) $(CFLAGS) -c -g -Wa,-almshd=$*.lst -o $*.o $*.c perl chkinstr.pl $*.lst || ( rm $*.o && exit 1 ) ...which runs the assembler's "mixed listing" through a Perl script (chkinstr.pl) which will abort the compile process if "bad stuff" is detected. The Perl script prints out an error message showing the offending AVR assembly code along with the C-code line number and statement that caused the problem. (5) Use "static inline" routines and in-line assembly macros as required to limit call depth (and register usage). I tend to code up both "in-line" and "normal" version of many routines. The in-line version I typically name with a leading "_". The "normal" versions simple reference the "in-line" macro with a wrapper. Both end up doing exactly the same thing. (6) Use my BYTE() in-line assembly macro to avoid C code which generates "illegal" ATtiny AVR instructions like "sbiw". (This could be fixed with a patch to avr-gcc, but I'm too lazy to figure out how.) #define BYTE(ch) ({ \ uint8_t t; \ asm volatile ( \ "ldi %0, %1" \ : "=d" (t) \ : "M" ((uint8_t)(ch)) \ ); \ t; \ }) For example, instead of using constructs like... while (n--) for (i = 0; i < 10; ++i) ...use instead... while (n -= BYTE(1)) for (i = 0; i < 10; i += BYTE(1)) (7) If you discover any more "tips", please let me know. ------------------------------------------------------------------------ Bruce D. Lightner (lightner@lightner.net) ------------------------------------------------------------------------