Smallest Blink Program

Here is my entry into the “smallest blink program contest” compiled in the arduino IDE. Can you determine how it works?

//program only for atmega168 based arduino with supplied bootloader
typedef void (*func_type)(uint8_t);
func_type flash_led = (func_type) 0x1d17;

int main(void) {
  for(;;)
    flash_led(0xff);
}

The arduino IDE reports 184 bytes. The relevant part of the program compiles to the following loop of 14 bytes:

<main>:
  a6:	e0 91 00 01 	lds	r30, 0x0100
  aa:	f0 91 01 01 	lds	r31, 0x0101
  ae:	8f ef       	ldi	r24, 0xFF	; 255
  b0:	09 95       	icall
  b2:	f9 cf       	rjmp	<main>	;.-14

Obviously, the standard startup and arduino code add about 150 bytes. I’ve compiled the same code inside ATMEL Studio using a slimmed down gcrt1.s start file, eliminating the IVT and reduced the entire hex file to 32 total bytes.

Does it have to do with this post by Udo Klein?

Anyway, I'm not a machine code expert, but that looks like it will blink rather quickly.
Have you tried uploading it?

Using the bootloader code to do your dirty work is cheating; you might as well program a completely empty sketch and let it loop through the empty memory until it hits the bootloader again. (although... good luck getting just the sketch area to be "empty." The bootloader doesn't erase it, and upload typically skips 'empty' memory.)

You're correct, remnants of old programs could very well be scattered throughout the flash and probably prevent the program from falling through to the bootloader.

FWIW, avrdude -e option will cleanse the chip.

Using the bootloader code to do your dirty work is cheating

I disagree; it's making maximum use of the existing facilities.

It reminds me of a programming challenge when I was a student.
The challenge was to calculate and print the value of e in as few bytes of code as possible, on an IBM-360 compatible mainframe.
The immediate fails were written in high-level languages like FORTRAN or Algol.
The better ones were written in assembler, but because of the I/O libraries to get the result out, the executables ran to several kilobytes.

The winner was about 30 or 40 bytes of pure assembler; it simply calculated e from the series in one of the floating-point registers, and then did a divide-by-zero.
This caused a core dump, and the core dump print-out included the FP registers.

The winner had the prize confiscated as soon as it was awarded, for wasting paper - a full core-dump ran to about a box of 132 column paper.
The challenge was never run again, to the best of my knowledge.

FWIW, avrdude -e option will cleanse the chip.

Not via the bootloader(s); the bootloaders ignore the "erase chip" command.

AWOL:
The winner was about 30 or 40 bytes of pure assembler; it simply calculated e from the series in one of the floating-point registers, and then did a divide-by-zero.
This caused a core dump, and the core dump print-out included the FP registers.

Divide by zero! Very clever, but very wasteful of paper as you said.

178 bytes.

That doesn't rely on any tricks like falling through to the boot loader.

140 bytes using the new compiler (1.5.7).

Adding a delay only took it up to 164 bytes:

#include <avr/cpufunc.h>

struct Nop{ Nop(){ _NOP(); } };

int main(){
  DDRB = bit(5); 

  while( true ){
    unsigned char cnt = 0;
    while( cnt++ < 100 ) Nop n[ 16000 ];
    PINB = bit(5);
  }
}

@Nick - I think you do yourself a disservice.

If you re-code like this:

int main ()
{
  DDRB = 0x20; // pin 12 & 13
  while (true)
    PINB = 0x20; // pin 12 & 13
}

Then you still get your 178 bytes. However, if you then do your TWO LEDs like this:

int main ()
{
  DDRB = 0x30;
  while (true)
    PINB = 0x30;
}

Then you STILL get 178 bytes. Therefore using your argument you get a LED blinking in ZERO bytes.

(Incidentally - I'm not sure your code would actually work because you're setting bit 5 of the DDR and then clearing it again when you set bit 4).

I ran your program and it appears to me that the LED is always on and doesn't blink. :wink:

Removing the global variable takes it to 142 bytes using the newest ide (1.6.0). :stuck_out_tongue:

//program only for atmega168 based arduino with supplied bootloader

int main(void) {
  for(;;)
    asm volatile(
      "ldi r24,0xff \n\t"
      "ldi r30,0x17 \n\t"
      "ldi r31,0x1d \n\t"
      "icall \n\t"
    );
}

JimEli:
Removing the global variable takes it to 142 bytes using the newest ide (1.6.0). :stuck_out_tongue:

Nicks version without ASM is only 140 bytes.

Got me confused there, you must be using 1.0.6 rather than 1.6.0, as the download page is only up to 1.5.8.

JimEli:
I ran your program and it appears to me that the LED is always on and doesn't blink. :wink:

I did say that it blinked very rapidly indeed.

Because it did not have a delay it blinked thousands of times a second and you would not notice it.

yaafm:
(Incidentally - I'm not sure your code would actually work because you're setting bit 5 of the DDR and then clearing it again when you set bit 4).

Huh?

yaafm:
Then you STILL get 178 bytes. Therefore using your argument you get a LED blinking in ZERO bytes.

Well, using that argument you could blink seven LEDs in zero bytes providing are you already blinking an 8th.

LOL - it’s not MY argument it’s YOURS. On your web site you say:

Eight bytes difference. So really, you can blink an LED in 8 bytes. That is the bottom line.

I was just pointing out (and doing it tongue in cheek BTW) that if YOU want to use that argument you could go the whole nine yards and blink a SECOND LED for ZERO extra bytes if you re-write your code as I suggested.

Which brings me to…

Why the Huh?

2.6MHz, in fact.

Interestingly, the built-in led appears never on, an external one appears always on.

nick pin 13.jpg

yaafm:
Why the Huh?

I would hazard a guess that Nick is Huh-ing at your assertion that it doesn't work, whereas my scope trace in previous code clearly shows that it is working. Just a guess though....

JimboZA:
I would hazard a guess that Nick is Huh-ing at your assertion that it doesn't work, whereas my scope trace in previous code clearly shows that it is working. Just a guess though....

I expect you're correct. However you're statement...

JimboZA:
Interestingly, the built-in led appears never on, an external one appears always on.

is exactly right and exactly confirms my assertion that Nick's code doesn't work as presented.

The built in LED on pin 13 appears never on because he's set it as an output (correctly) but then immediately RESET it to an input with his line that sets pin 12 as an output. (It's not just the one's that are important, the zero's have an effect too). He should have either OR'ed them OR as I said in my earlier post done both bits at the same time by writing 0x30 to the DDR.

To be clear - with Nick's code pin 12 will blink but pin 13 will not.