2

I am now teaching my friend how to program AVR microcontrollers. We've written this small program, which sends simple morse-like code.

The problem is that, after compilling it both with AVR-GCC and WinAVR the a.out file is almost 30KB and the hex file is 11KB, so that it doesn't fit the attiny2313 flash.

WinAVR CMD: avr-gcc -mmcu=attiny2313 -Os -g main.c

Avr-objcopy: avr-objcopy -O ihex a.out a.hex

Here is the code:

#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>

void light_led(int ms)
{
 PORTD |= (1 << 4);
 _delay_ms(ms);
 PORTD &= ~(1 << 4);
 _delay_ms(1000);
}

void send_char(int c)
{
 int i;
 for(i = 1; i < 8+1; i++)
 {
  if(c & i) light_led(1000);
  else light_led(500); 
 }
}

int main(void)
{
 DDRD |= (1 << 4);
 //char text[] = {'t', 'e', 's', 't'};
 int i;
 for(i = 0; i < 1; i++) send_char(100);//text[i]);
 return 0;
}
jblew
  • 506
  • 3
  • 9
  • Try strip option. See [here](http://manned.org/avr-strip) for more info. – Dayal rai Sep 30 '13 at 11:52
  • The way to make the hex smaller if all else fails: omit the libraries, and implement the functions by hand, trimming their (often too flexible for the purpose) extra features. This way, the unused stuff is left out... Sure, the code will be ugly. – ppeterka Sep 30 '13 at 11:53
  • 1
    The ATtiny2313 has 2 KB of program flash, but since that's in binary the exact size of the hex file is not directly comparable. It takes a lot more than one byte to express a single byte of program flash data in the hex file. That said, take @Dayalrai's advice and make sure the binary is stripped and optimized for size. – unwind Sep 30 '13 at 12:00

1 Answers1

6

The size of the hex file is misleading. It takes 43 bytes to represent 16, so your executable is actually only 4 K.

That said, passing the parameter to the _delay_ms() function really blows up the code. I tried this instead, always calling the delay function with a constant, and the executable was less than 190 bytes.

#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>

void light_led(int longer)
{
 PORTD |= (1 << 4);
 if(longer) _delay_ms(1000);
 else  _delay_ms(500);
 PORTD &= ~(1 << 4);
 _delay_ms(1000);
}

void send_char(int c)
{
 int i;
 for(i = 1; i < 8+1; i++)
 {
  if(c & i) light_led(1);
  else light_led(0); 
 }
}

int main(void)
{
 DDRD |= (1 << 4);
 //char text[] = {'t', 'e', 's', 't'};
 int i;
 for(i = 0; i < 1; i++) send_char(100);//text[i]);
 return 0;
}
UncleO
  • 8,299
  • 21
  • 29
  • 2
    To expand on that answer, from the AVR libc [manual](http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html) "In order for these functions to work as intended, compiler optimizations must be enabled, and the delay time must be an expression that is a known constant at compile-time. If these requirements are not met, the resulting delay will be much longer (and basically unpredictable), and applications [..] will experience severe code bloat by the floating-point library routines linked into the application" which is essentially what you were seeing in your code. – TRON Oct 01 '13 at 03:27
  • I thought inlining light_led would solve it, but it turns out I get a compile time error with avr-gcc 4.7.2 and avr-libc 1.8.0; it's from a test added to avoid this type of gotcha. – Yann Vernier Oct 02 '13 at 13:08