Please visit the homepage for location and information on open hours


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Arduino Bloat! (A comparison of the Blink program)
02-18-2016, 08:22 PM,
#1
Arduino Bloat! (A comparison of the Blink program)
So, I've been working with Arduino lately, learning the environment, and trying to learn more about the bare-metal underneath.

I've installed the AVR plugin into Eclipse (another programming IDE) and I wrote the obligatory "Hello World" program for micro-controllers...the LED "Blink" program.

After compiling and looking at the HEX, I was amazed at the size difference between writing code for the AVR itself, and writing code in the Arduino IDE.

Don't get me wrong, I really like the Arduino ecosystem...and I think Arduino is a GREAT learning environment. However, I wanted to illustrate how much overhead the Arduino IDE puts into its code.

Here are the programs...

Arduino: (Everybody should know this one!)
   

And the straight "coded for AVR":
   

As you can see, it's the same program. Turn port PB5 (called "13" in Arduino land) on, wait 100 milliseconds, turn it off, wait 900 milliseconds. Lather, Rinse, Repeat.

Eclipse Compiled the program and it weighed in at 176 bytes (0.5% full) with 0 bytes of data memory used.

Arduino compiled the same program and it came in at: 1,070 bytes! (3% full) with 9 bytes of data memory used!

Here is the HEX file comparison: (if you're a visual person like me)

AVR:
Code:
:100000000C9434000C943E000C943E000C943E0082
:100010000C943E000C943E000C943E000C943E0068
:100020000C943E000C943E000C943E000C943E0058
:100030000C943E000C943E000C943E000C943E0048
:100040000C943E000C943E000C943E000C943E0038
:100050000C943E000C943E000C943E000C943E0028
:100060000C943E000C943E0011241FBECFEFD8E04C
:10007000DEBFCDBF0E9440000C9456000C940000DF
:10008000259A2D9A2FE78AE196E0215080409040F2
:10009000E1F700C000002D982FE78EEE96E3215087
:1000A00080409040E1F700C00000EBCFF894FFCF14
:00000001FF

Arduino:
Code:
:100000000C945C000C946E000C946E000C946E00CA
:100010000C946E000C946E000C946E000C946E00A8
:100020000C946E000C946E000C946E000C946E0098
:100030000C946E000C946E000C946E000C946E0088
:100040000C9488000C946E000C946E000C946E005E
:100050000C946E000C946E000C946E000C946E0068
:100060000C946E000C946E00000000080002010069
:100070000003040700000000000000000102040863
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A0000303030300000000250028002B000000CC
:1000B0000000240027002A0011241FBECFEFD8E043
:1000C000DEBFCDBF21E0A0E0B1E001C01D92A930AC
:1000D000B207E1F70E94EB010C9415020C940000AA
:1000E00061E08DE00C947B0161E08DE00E94B40141
:1000F00064E670E080E090E00E94EF0060E08DE058
:100100000E94B40164E873E080E090E00C94EF009A
:100110001F920F920FB60F9211242F933F938F933C
:100120009F93AF93BF938091010190910201A091A1
:100130000301B09104013091000126E6230F2D3711
:1001400028F029EE230F0196A11DB11D2093000177
:100150008093010190930201A0930301B0930401E5
:100160008091050190910601A0910701B0910801CD
:100170000196A11DB11D8093050190930601A093E6
:100180000701B0930801BF91AF919F918F913F916B
:100190002F910F900FBE0F901F9018959FB7F89456
:1001A000409105015091060160910701709108018D
:1001B00086B5A89B06C08F3F21F04F5F5F4F6F4F02
:1001C0007F4F9FBF2227342F452F562F280F311DD9
:1001D000411D511DA3E0B0E00E94FB010895CF92A4
:1001E000DF92EF92FF92CF93DF936B017C010E942D
:1001F000CE00EB01C114D104E104F10489F00E94A6
:10020000FA010E94CE006C1B7D0B683E734090F398
:1002100081E0C81AD108E108F108C851DC4FEACFE3
:10022000DF91CF91FF90EF90DF90CF900895789479
:1002300084B5826084BD84B5816084BD85B58260EB
:1002400085BD85B5816085BDEEE6F0E08081816089
:100250008083E1E8F0E01082808182608083808189
:1002600081608083E0E8F0E0808181608083E1EB61
:10027000F0E0808184608083E0EBF0E08081816049
:100280008083EAE7F0E080818460808380818260FF
:1002900080838081816080838081806880831092E8
:1002A000C1000895833081F028F4813099F08230C4
:1002B000A1F008958730A9F08830B9F08430D1F4E6
:1002C000809180008F7D03C0809180008F77809324
:1002D0008000089584B58F7702C084B58F7D84BD7A
:1002E00008958091B0008F7703C08091B0008F7D1A
:1002F0008093B0000895CF93DF9390E0FC01E45821
:10030000FF4F2491FC01E057FF4F8491882349F16E
:1003100090E0880F991FFC01E255FF4FA591B49121
:100320008C559F4FFC01C591D4919FB7611108C0B6
:10033000F8948C91209582238C93888182230AC023
:10034000623051F4F8948C91322F309583238C9342
:100350008881822B888304C0F8948C91822B8C93A3
:100360009FBFDF91CF9108950F931F93CF93DF939A
:100370001F92CDB7DEB7282F30E0F901E859FF4FC3
:100380008491F901E458FF4F1491F901E057FF4FB0
:1003900004910023C9F0882321F069830E9452014F
:1003A0006981E02FF0E0EE0FFF1FEC55FF4FA591A4
:1003B000B4919FB7F8948C91611103C0109581237B
:1003C00001C0812B8C939FBF0F90DF91CF911F9124
:1003D0000F91089508950E9417010E94EA010E945A
:1003E0007000C0E0D0E00E9474002097E1F30E940A
:1003F0000000F9CF08950E940602A59F900DB49FBA
:10040000900DA49F800D911D11240895A29FB0010D
:10041000B39FC001A39F700D811D1124911DB29F38
:0E042000700D811D1124911D0895F894FFCFD9
:00000001FF

I then went on to dump the code back into Assembly, as I'm trying to learn how to read Assembly (I don't have a desire to program in it, just read it!) Here are the dumps...

Avr:
Code:
BlinkyLight.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:    0c 94 34 00     jmp    0x68    ; 0x68 <__ctors_end>
   4:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
   8:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
   c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  10:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  14:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  18:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  1c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  20:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  24:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  28:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  2c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  30:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  34:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  38:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  3c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  40:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  44:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  48:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  4c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  50:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  54:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  58:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  5c:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  60:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>
  64:    0c 94 3e 00     jmp    0x7c    ; 0x7c <__bad_interrupt>

00000068 <__ctors_end>:
  68:    11 24           eor    r1, r1
  6a:    1f be           out    0x3f, r1    ; 63
  6c:    cf ef           ldi    r28, 0xFF    ; 255
  6e:    d8 e0           ldi    r29, 0x08    ; 8
  70:    de bf           out    0x3e, r29    ; 62
  72:    cd bf           out    0x3d, r28    ; 61
  74:    0e 94 40 00     call    0x80    ; 0x80 <main>
  78:    0c 94 56 00     jmp    0xac    ; 0xac <_exit>

0000007c <__bad_interrupt>:
  7c:    0c 94 00 00     jmp    0    ; 0x0 <__vectors>

00000080 <main>:
  80:    25 9a           sbi    0x04, 5    ; 4
  82:    2d 9a           sbi    0x05, 5    ; 5
  84:    2f e7           ldi    r18, 0x7F    ; 127
  86:    8a e1           ldi    r24, 0x1A    ; 26
  88:    96 e0           ldi    r25, 0x06    ; 6
  8a:    21 50           subi    r18, 0x01    ; 1
  8c:    80 40           sbci    r24, 0x00    ; 0
  8e:    90 40           sbci    r25, 0x00    ; 0
  90:    e1 f7           brne    .-8          ; 0x8a <main+0xa>
  92:    00 c0           rjmp    .+0          ; 0x94 <main+0x14>
  94:    00 00           nop
  96:    2d 98           cbi    0x05, 5    ; 5
  98:    2f e7           ldi    r18, 0x7F    ; 127
  9a:    8e ee           ldi    r24, 0xEE    ; 238
  9c:    96 e3           ldi    r25, 0x36    ; 54
  9e:    21 50           subi    r18, 0x01    ; 1
  a0:    80 40           sbci    r24, 0x00    ; 0
  a2:    90 40           sbci    r25, 0x00    ; 0
  a4:    e1 f7           brne    .-8          ; 0x9e <main+0x1e>
  a6:    00 c0           rjmp    .+0          ; 0xa8 <main+0x28>
  a8:    00 00           nop
  aa:    eb cf           rjmp    .-42         ; 0x82 <main+0x2>

000000ac <_exit>:
  ac:    f8 94           cli

000000ae <__stop_program>:
  ae:    ff cf           rjmp    .-2          ; 0xae <__stop_program>

And Arduino:
Code:
Blink.ino.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:    0c 94 5c 00     jmp    0xb8    ; 0xb8 <__ctors_end>
   4:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
   8:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
   c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  10:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  14:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  18:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  1c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  20:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  24:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  28:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  2c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  30:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  34:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  38:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  3c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  40:    0c 94 88 00     jmp    0x110    ; 0x110 <__vector_16>
  44:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  48:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  4c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  50:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  54:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  58:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  5c:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  60:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>
  64:    0c 94 6e 00     jmp    0xdc    ; 0xdc <__bad_interrupt>

00000068 <__trampolines_end>:
  68:    00 00           nop
  6a:    00 08           sbc    r0, r0
  6c:    00 02           muls    r16, r16
  6e:    01 00           .word    0x0001    ; ????
  70:    00 03           mulsu    r16, r16
  72:    04 07           cpc    r16, r20
    ...

0000007c <digital_pin_to_bit_mask_PGM>:
  7c:    01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02     ..... @...... ..
  8c:    04 08 10 20                                         ...

00000090 <digital_pin_to_port_PGM>:
  90:    04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03     ................
  a0:    03 03 03 03                                         ....

000000a4 <port_to_output_PGM>:
  a4:    00 00 00 00 25 00 28 00 2b 00                       ....%.(.+.

000000ae <port_to_mode_PGM>:
  ae:    00 00 00 00 24 00 27 00 2a 00                       ....$.'.*.

000000b8 <__ctors_end>:
  b8:    11 24           eor    r1, r1
  ba:    1f be           out    0x3f, r1    ; 63
  bc:    cf ef           ldi    r28, 0xFF    ; 255
  be:    d8 e0           ldi    r29, 0x08    ; 8
  c0:    de bf           out    0x3e, r29    ; 62
  c2:    cd bf           out    0x3d, r28    ; 61

000000c4 <__do_clear_bss>:
  c4:    21 e0           ldi    r18, 0x01    ; 1
  c6:    a0 e0           ldi    r26, 0x00    ; 0
  c8:    b1 e0           ldi    r27, 0x01    ; 1
  ca:    01 c0           rjmp    .+2          ; 0xce <.do_clear_bss_start>

000000cc <.do_clear_bss_loop>:
  cc:    1d 92           st    X+, r1

000000ce <.do_clear_bss_start>:
  ce:    a9 30           cpi    r26, 0x09    ; 9
  d0:    b2 07           cpc    r27, r18
  d2:    e1 f7           brne    .-8          ; 0xcc <.do_clear_bss_loop>
  d4:    0e 94 eb 01     call    0x3d6    ; 0x3d6 <main>
  d8:    0c 94 15 02     jmp    0x42a    ; 0x42a <_exit>

000000dc <__bad_interrupt>:
  dc:    0c 94 00 00     jmp    0    ; 0x0 <__vectors>

000000e0 <setup>:


// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
  e0:    61 e0           ldi    r22, 0x01    ; 1
  e2:    8d e0           ldi    r24, 0x0D    ; 13
  e4:    0c 94 7b 01     jmp    0x2f6    ; 0x2f6 <pinMode>

000000e8 <loop>:
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  e8:    61 e0           ldi    r22, 0x01    ; 1
  ea:    8d e0           ldi    r24, 0x0D    ; 13
  ec:    0e 94 b4 01     call    0x368    ; 0x368 <digitalWrite>
  delay(100);              // wait for a second
  f0:    64 e6           ldi    r22, 0x64    ; 100
  f2:    70 e0           ldi    r23, 0x00    ; 0
  f4:    80 e0           ldi    r24, 0x00    ; 0
  f6:    90 e0           ldi    r25, 0x00    ; 0
  f8:    0e 94 ef 00     call    0x1de    ; 0x1de <delay>
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  fc:    60 e0           ldi    r22, 0x00    ; 0
  fe:    8d e0           ldi    r24, 0x0D    ; 13
100:    0e 94 b4 01     call    0x368    ; 0x368 <digitalWrite>
  delay(900);              // wait for a second
104:    64 e8           ldi    r22, 0x84    ; 132
106:    73 e0           ldi    r23, 0x03    ; 3
108:    80 e0           ldi    r24, 0x00    ; 0
10a:    90 e0           ldi    r25, 0x00    ; 0
10c:    0c 94 ef 00     jmp    0x1de    ; 0x1de <delay>

00000110 <__vector_16>:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
110:    1f 92           push    r1
112:    0f 92           push    r0
114:    0f b6           in    r0, 0x3f    ; 63
116:    0f 92           push    r0
118:    11 24           eor    r1, r1
11a:    2f 93           push    r18
11c:    3f 93           push    r19
11e:    8f 93           push    r24
120:    9f 93           push    r25
122:    af 93           push    r26
124:    bf 93           push    r27
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
126:    80 91 01 01     lds    r24, 0x0101
12a:    90 91 02 01     lds    r25, 0x0102
12e:    a0 91 03 01     lds    r26, 0x0103
132:    b0 91 04 01     lds    r27, 0x0104
    unsigned char f = timer0_fract;
136:    30 91 00 01     lds    r19, 0x0100

    m += MILLIS_INC;
    f += FRACT_INC;
13a:    26 e6           ldi    r18, 0x66    ; 102
13c:    23 0f           add    r18, r19
    if (f >= FRACT_MAX) {
13e:    2d 37           cpi    r18, 0x7D    ; 125
140:    28 f0           brcs    .+10         ; 0x14c <__vector_16+0x3c>
        f -= FRACT_MAX;
142:    29 ee           ldi    r18, 0xE9    ; 233
144:    23 0f           add    r18, r19
        m += 1;
146:    01 96           adiw    r24, 0x01    ; 1
148:    a1 1d           adc    r26, r1
14a:    b1 1d           adc    r27, r1
    }

    timer0_fract = f;
14c:    20 93 00 01     sts    0x0100, r18
    timer0_millis = m;
150:    80 93 01 01     sts    0x0101, r24
154:    90 93 02 01     sts    0x0102, r25
158:    a0 93 03 01     sts    0x0103, r26
15c:    b0 93 04 01     sts    0x0104, r27
    timer0_overflow_count++;
160:    80 91 05 01     lds    r24, 0x0105
164:    90 91 06 01     lds    r25, 0x0106
168:    a0 91 07 01     lds    r26, 0x0107
16c:    b0 91 08 01     lds    r27, 0x0108
170:    01 96           adiw    r24, 0x01    ; 1
172:    a1 1d           adc    r26, r1
174:    b1 1d           adc    r27, r1
176:    80 93 05 01     sts    0x0105, r24
17a:    90 93 06 01     sts    0x0106, r25
17e:    a0 93 07 01     sts    0x0107, r26
182:    b0 93 08 01     sts    0x0108, r27
}
186:    bf 91           pop    r27
188:    af 91           pop    r26
18a:    9f 91           pop    r25
18c:    8f 91           pop    r24
18e:    3f 91           pop    r19
190:    2f 91           pop    r18
192:    0f 90           pop    r0
194:    0f be           out    0x3f, r0    ; 63
196:    0f 90           pop    r0
198:    1f 90           pop    r1
19a:    18 95           reti

0000019c <micros>:
    return m;
}

unsigned long micros() {
    unsigned long m;
    uint8_t oldSREG = SREG, t;
19c:    9f b7           in    r25, 0x3f    ; 63
    
    cli();
19e:    f8 94           cli
    m = timer0_overflow_count;
1a0:    40 91 05 01     lds    r20, 0x0105
1a4:    50 91 06 01     lds    r21, 0x0106
1a8:    60 91 07 01     lds    r22, 0x0107
1ac:    70 91 08 01     lds    r23, 0x0108
#if defined(TCNT0)
    t = TCNT0;
1b0:    86 b5           in    r24, 0x26    ; 38
#else
    #error TIMER 0 not defined
#endif

#ifdef TIFR0
    if ((TIFR0 & _BV(TOV0)) && (t < 255))
1b2:    a8 9b           sbis    0x15, 0    ; 21
1b4:    06 c0           rjmp    .+12         ; 0x1c2 <micros+0x26>
1b6:    8f 3f           cpi    r24, 0xFF    ; 255
1b8:    21 f0           breq    .+8          ; 0x1c2 <micros+0x26>
        m++;
1ba:    4f 5f           subi    r20, 0xFF    ; 255
1bc:    5f 4f           sbci    r21, 0xFF    ; 255
1be:    6f 4f           sbci    r22, 0xFF    ; 255
1c0:    7f 4f           sbci    r23, 0xFF    ; 255
#else
    if ((TIFR & _BV(TOV0)) && (t < 255))
        m++;
#endif

    SREG = oldSREG;
1c2:    9f bf           out    0x3f, r25    ; 63
    
    return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
1c4:    22 27           eor    r18, r18
1c6:    34 2f           mov    r19, r20
1c8:    45 2f           mov    r20, r21
1ca:    56 2f           mov    r21, r22
1cc:    28 0f           add    r18, r24
1ce:    31 1d           adc    r19, r1
1d0:    41 1d           adc    r20, r1
1d2:    51 1d           adc    r21, r1
1d4:    a3 e0           ldi    r26, 0x03    ; 3
1d6:    b0 e0           ldi    r27, 0x00    ; 0
1d8:    0e 94 fb 01     call    0x3f6    ; 0x3f6 <__muluhisi3>
}
1dc:    08 95           ret

000001de <delay>:

void delay(unsigned long ms)
{
1de:    cf 92           push    r12
1e0:    df 92           push    r13
1e2:    ef 92           push    r14
1e4:    ff 92           push    r15
1e6:    cf 93           push    r28
1e8:    df 93           push    r29
1ea:    6b 01           movw    r12, r22
1ec:    7c 01           movw    r14, r24
    uint16_t start = (uint16_t)micros();
1ee:    0e 94 ce 00     call    0x19c    ; 0x19c <micros>
1f2:    eb 01           movw    r28, r22

    while (ms > 0) {
1f4:    c1 14           cp    r12, r1
1f6:    d1 04           cpc    r13, r1
1f8:    e1 04           cpc    r14, r1
1fa:    f1 04           cpc    r15, r1
1fc:    89 f0           breq    .+34         ; 0x220 <delay+0x42>
        yield();
1fe:    0e 94 fa 01     call    0x3f4    ; 0x3f4 <yield>
        if (((uint16_t)micros() - start) >= 1000) {
202:    0e 94 ce 00     call    0x19c    ; 0x19c <micros>
206:    6c 1b           sub    r22, r28
208:    7d 0b           sbc    r23, r29
20a:    68 3e           cpi    r22, 0xE8    ; 232
20c:    73 40           sbci    r23, 0x03    ; 3
20e:    90 f3           brcs    .-28         ; 0x1f4 <delay+0x16>
            ms--;
210:    81 e0           ldi    r24, 0x01    ; 1
212:    c8 1a           sub    r12, r24
214:    d1 08           sbc    r13, r1
216:    e1 08           sbc    r14, r1
218:    f1 08           sbc    r15, r1
            start += 1000;
21a:    c8 51           subi    r28, 0x18    ; 24
21c:    dc 4f           sbci    r29, 0xFC    ; 252
21e:    ea cf           rjmp    .-44         ; 0x1f4 <delay+0x16>
        }
    }
}
220:    df 91           pop    r29
222:    cf 91           pop    r28
224:    ff 90           pop    r15
226:    ef 90           pop    r14
228:    df 90           pop    r13
22a:    cf 90           pop    r12
22c:    08 95           ret

0000022e <init>:

void init()
{
    // this needs to be called before setup() or some functions won't
    // work there
    sei();
22e:    78 94           sei
    
    // on the ATmega168, timer 0 is also used for fast hardware pwm
    // (using phase-correct PWM would mean that timer 0 overflowed half as often
    // resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
    sbi(TCCR0A, WGM01);
230:    84 b5           in    r24, 0x24    ; 36
232:    82 60           ori    r24, 0x02    ; 2
234:    84 bd           out    0x24, r24    ; 36
    sbi(TCCR0A, WGM00);
236:    84 b5           in    r24, 0x24    ; 36
238:    81 60           ori    r24, 0x01    ; 1
23a:    84 bd           out    0x24, r24    ; 36
    // this combination is for the standard atmega8
    sbi(TCCR0, CS01);
    sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
    // this combination is for the standard 168/328/1280/2560
    sbi(TCCR0B, CS01);
23c:    85 b5           in    r24, 0x25    ; 37
23e:    82 60           ori    r24, 0x02    ; 2
240:    85 bd           out    0x25, r24    ; 37
    sbi(TCCR0B, CS00);
242:    85 b5           in    r24, 0x25    ; 37
244:    81 60           ori    r24, 0x01    ; 1
246:    85 bd           out    0x25, r24    ; 37

    // enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
    sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
    sbi(TIMSK0, TOIE0);
248:    ee e6           ldi    r30, 0x6E    ; 110
24a:    f0 e0           ldi    r31, 0x00    ; 0
24c:    80 81           ld    r24, Z
24e:    81 60           ori    r24, 0x01    ; 1
250:    80 83           st    Z, r24
    // this is better for motors as it ensures an even waveform
    // note, however, that fast pwm mode can achieve a frequency of up
    // 8 MHz (with a 16 MHz clock) at 50% duty cycle

#if defined(TCCR1B) && defined(CS11) && defined(CS10)
    TCCR1B = 0;
252:    e1 e8           ldi    r30, 0x81    ; 129
254:    f0 e0           ldi    r31, 0x00    ; 0
256:    10 82           st    Z, r1

    // set timer 1 prescale factor to 64
    sbi(TCCR1B, CS11);
258:    80 81           ld    r24, Z
25a:    82 60           ori    r24, 0x02    ; 2
25c:    80 83           st    Z, r24
#if F_CPU >= 8000000L
    sbi(TCCR1B, CS10);
25e:    80 81           ld    r24, Z
260:    81 60           ori    r24, 0x01    ; 1
262:    80 83           st    Z, r24
    sbi(TCCR1, CS10);
#endif
#endif
    // put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
    sbi(TCCR1A, WGM10);
264:    e0 e8           ldi    r30, 0x80    ; 128
266:    f0 e0           ldi    r31, 0x00    ; 0
268:    80 81           ld    r24, Z
26a:    81 60           ori    r24, 0x01    ; 1
26c:    80 83           st    Z, r24

    // set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
    sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
    sbi(TCCR2B, CS22);
26e:    e1 eb           ldi    r30, 0xB1    ; 177
270:    f0 e0           ldi    r31, 0x00    ; 0
272:    80 81           ld    r24, Z
274:    84 60           ori    r24, 0x04    ; 4
276:    80 83           st    Z, r24

    // configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
    sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
    sbi(TCCR2A, WGM20);
278:    e0 eb           ldi    r30, 0xB0    ; 176
27a:    f0 e0           ldi    r31, 0x00    ; 0
27c:    80 81           ld    r24, Z
27e:    81 60           ori    r24, 0x01    ; 1
280:    80 83           st    Z, r24
#endif

#if defined(ADCSRA)
    // set a2d prescaler so we are inside the desired 50-200 KHz range.
    #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
        sbi(ADCSRA, ADPS2);
282:    ea e7           ldi    r30, 0x7A    ; 122
284:    f0 e0           ldi    r31, 0x00    ; 0
286:    80 81           ld    r24, Z
288:    84 60           ori    r24, 0x04    ; 4
28a:    80 83           st    Z, r24
        sbi(ADCSRA, ADPS1);
28c:    80 81           ld    r24, Z
28e:    82 60           ori    r24, 0x02    ; 2
290:    80 83           st    Z, r24
        sbi(ADCSRA, ADPS0);
292:    80 81           ld    r24, Z
294:    81 60           ori    r24, 0x01    ; 1
296:    80 83           st    Z, r24
        cbi(ADCSRA, ADPS2);
        cbi(ADCSRA, ADPS1);
        sbi(ADCSRA, ADPS0);
    #endif
    // enable a2d conversions
    sbi(ADCSRA, ADEN);
298:    80 81           ld    r24, Z
29a:    80 68           ori    r24, 0x80    ; 128
29c:    80 83           st    Z, r24
    // here so they can be used as normal digital i/o; they will be
    // reconnected in Serial.begin()
#if defined(UCSRB)
    UCSRB = 0;
#elif defined(UCSR0B)
    UCSR0B = 0;
29e:    10 92 c1 00     sts    0x00C1, r1
2a2:    08 95           ret

000002a4 <turnOffPWM>:
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
    switch (timer)
2a4:    83 30           cpi    r24, 0x03    ; 3
2a6:    81 f0           breq    .+32         ; 0x2c8 <turnOffPWM+0x24>
2a8:    28 f4           brcc    .+10         ; 0x2b4 <turnOffPWM+0x10>
2aa:    81 30           cpi    r24, 0x01    ; 1
2ac:    99 f0           breq    .+38         ; 0x2d4 <turnOffPWM+0x30>
2ae:    82 30           cpi    r24, 0x02    ; 2
2b0:    a1 f0           breq    .+40         ; 0x2da <turnOffPWM+0x36>
2b2:    08 95           ret
2b4:    87 30           cpi    r24, 0x07    ; 7
2b6:    a9 f0           breq    .+42         ; 0x2e2 <turnOffPWM+0x3e>
2b8:    88 30           cpi    r24, 0x08    ; 8
2ba:    b9 f0           breq    .+46         ; 0x2ea <turnOffPWM+0x46>
2bc:    84 30           cpi    r24, 0x04    ; 4
2be:    d1 f4           brne    .+52         ; 0x2f4 <turnOffPWM+0x50>
    {
        #if defined(TCCR1A) && defined(COM1A1)
        case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
        #endif
        #if defined(TCCR1A) && defined(COM1B1)
        case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
2c0:    80 91 80 00     lds    r24, 0x0080
2c4:    8f 7d           andi    r24, 0xDF    ; 223
2c6:    03 c0           rjmp    .+6          ; 0x2ce <turnOffPWM+0x2a>
static void turnOffPWM(uint8_t timer)
{
    switch (timer)
    {
        #if defined(TCCR1A) && defined(COM1A1)
        case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
2c8:    80 91 80 00     lds    r24, 0x0080
2cc:    8f 77           andi    r24, 0x7F    ; 127
        #endif
        #if defined(TCCR1A) && defined(COM1B1)
        case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
2ce:    80 93 80 00     sts    0x0080, r24
2d2:    08 95           ret
        #if defined(TCCR2) && defined(COM21)
        case  TIMER2:   cbi(TCCR2, COM21);      break;
        #endif
        
        #if defined(TCCR0A) && defined(COM0A1)
        case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
2d4:    84 b5           in    r24, 0x24    ; 36
2d6:    8f 77           andi    r24, 0x7F    ; 127
2d8:    02 c0           rjmp    .+4          ; 0x2de <turnOffPWM+0x3a>
        #endif
        
        #if defined(TCCR0A) && defined(COM0B1)
        case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
2da:    84 b5           in    r24, 0x24    ; 36
2dc:    8f 7d           andi    r24, 0xDF    ; 223
2de:    84 bd           out    0x24, r24    ; 36
2e0:    08 95           ret
        #endif
        #if defined(TCCR2A) && defined(COM2A1)
        case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
2e2:    80 91 b0 00     lds    r24, 0x00B0
2e6:    8f 77           andi    r24, 0x7F    ; 127
2e8:    03 c0           rjmp    .+6          ; 0x2f0 <turnOffPWM+0x4c>
        #endif
        #if defined(TCCR2A) && defined(COM2B1)
        case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
2ea:    80 91 b0 00     lds    r24, 0x00B0
2ee:    8f 7d           andi    r24, 0xDF    ; 223
2f0:    80 93 b0 00     sts    0x00B0, r24
2f4:    08 95           ret

000002f6 <pinMode>:
#define ARDUINO_MAIN
#include "wiring_private.h"
#include "pins_arduino.h"

void pinMode(uint8_t pin, uint8_t mode)
{
2f6:    cf 93           push    r28
2f8:    df 93           push    r29
    uint8_t bit = digitalPinToBitMask(pin);
2fa:    90 e0           ldi    r25, 0x00    ; 0
2fc:    fc 01           movw    r30, r24
2fe:    e4 58           subi    r30, 0x84    ; 132
300:    ff 4f           sbci    r31, 0xFF    ; 255
302:    24 91           lpm    r18, Z
    uint8_t port = digitalPinToPort(pin);
304:    fc 01           movw    r30, r24
306:    e0 57           subi    r30, 0x70    ; 112
308:    ff 4f           sbci    r31, 0xFF    ; 255
30a:    84 91           lpm    r24, Z
    volatile uint8_t *reg, *out;

    if (port == NOT_A_PIN) return;
30c:    88 23           and    r24, r24
30e:    49 f1           breq    .+82         ; 0x362 <pinMode+0x6c>

    // JWS: can I let the optimizer do this?
    reg = portModeRegister(port);
310:    90 e0           ldi    r25, 0x00    ; 0
312:    88 0f           add    r24, r24
314:    99 1f           adc    r25, r25
316:    fc 01           movw    r30, r24
318:    e2 55           subi    r30, 0x52    ; 82
31a:    ff 4f           sbci    r31, 0xFF    ; 255
31c:    a5 91           lpm    r26, Z+
31e:    b4 91           lpm    r27, Z
    out = portOutputRegister(port);
320:    8c 55           subi    r24, 0x5C    ; 92
322:    9f 4f           sbci    r25, 0xFF    ; 255
324:    fc 01           movw    r30, r24
326:    c5 91           lpm    r28, Z+
328:    d4 91           lpm    r29, Z

    if (mode == INPUT) {
        uint8_t oldSREG = SREG;
32a:    9f b7           in    r25, 0x3f    ; 63

    // JWS: can I let the optimizer do this?
    reg = portModeRegister(port);
    out = portOutputRegister(port);

    if (mode == INPUT) {
32c:    61 11           cpse    r22, r1
32e:    08 c0           rjmp    .+16         ; 0x340 <pinMode+0x4a>
        uint8_t oldSREG = SREG;
                cli();
330:    f8 94           cli
        *reg &= ~bit;
332:    8c 91           ld    r24, X
334:    20 95           com    r18
336:    82 23           and    r24, r18
338:    8c 93           st    X, r24
        *out &= ~bit;
33a:    88 81           ld    r24, Y
33c:    82 23           and    r24, r18
33e:    0a c0           rjmp    .+20         ; 0x354 <pinMode+0x5e>
        SREG = oldSREG;
    } else if (mode == INPUT_PULLUP) {
340:    62 30           cpi    r22, 0x02    ; 2
342:    51 f4           brne    .+20         ; 0x358 <pinMode+0x62>
        uint8_t oldSREG = SREG;
                cli();
344:    f8 94           cli
        *reg &= ~bit;
346:    8c 91           ld    r24, X
348:    32 2f           mov    r19, r18
34a:    30 95           com    r19
34c:    83 23           and    r24, r19
34e:    8c 93           st    X, r24
        *out |= bit;
350:    88 81           ld    r24, Y
352:    82 2b           or    r24, r18
354:    88 83           st    Y, r24
356:    04 c0           rjmp    .+8          ; 0x360 <pinMode+0x6a>
        SREG = oldSREG;
    } else {
        uint8_t oldSREG = SREG;
                cli();
358:    f8 94           cli
        *reg |= bit;
35a:    8c 91           ld    r24, X
35c:    82 2b           or    r24, r18
35e:    8c 93           st    X, r24
        SREG = oldSREG;
360:    9f bf           out    0x3f, r25    ; 63
    }
}
362:    df 91           pop    r29
364:    cf 91           pop    r28
366:    08 95           ret

00000368 <digitalWrite>:
        #endif
    }
}

void digitalWrite(uint8_t pin, uint8_t val)
{
368:    0f 93           push    r16
36a:    1f 93           push    r17
36c:    cf 93           push    r28
36e:    df 93           push    r29
370:    1f 92           push    r1
372:    cd b7           in    r28, 0x3d    ; 61
374:    de b7           in    r29, 0x3e    ; 62
    uint8_t timer = digitalPinToTimer(pin);
376:    28 2f           mov    r18, r24
378:    30 e0           ldi    r19, 0x00    ; 0
37a:    f9 01           movw    r30, r18
37c:    e8 59           subi    r30, 0x98    ; 152
37e:    ff 4f           sbci    r31, 0xFF    ; 255
380:    84 91           lpm    r24, Z
    uint8_t bit = digitalPinToBitMask(pin);
382:    f9 01           movw    r30, r18
384:    e4 58           subi    r30, 0x84    ; 132
386:    ff 4f           sbci    r31, 0xFF    ; 255
388:    14 91           lpm    r17, Z
    uint8_t port = digitalPinToPort(pin);
38a:    f9 01           movw    r30, r18
38c:    e0 57           subi    r30, 0x70    ; 112
38e:    ff 4f           sbci    r31, 0xFF    ; 255
390:    04 91           lpm    r16, Z
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;
392:    00 23           and    r16, r16
394:    c9 f0           breq    .+50         ; 0x3c8 <digitalWrite+0x60>

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);
396:    88 23           and    r24, r24
398:    21 f0           breq    .+8          ; 0x3a2 <digitalWrite+0x3a>
39a:    69 83           std    Y+1, r22    ; 0x01
39c:    0e 94 52 01     call    0x2a4    ; 0x2a4 <turnOffPWM>
3a0:    69 81           ldd    r22, Y+1    ; 0x01

    out = portOutputRegister(port);
3a2:    e0 2f           mov    r30, r16
3a4:    f0 e0           ldi    r31, 0x00    ; 0
3a6:    ee 0f           add    r30, r30
3a8:    ff 1f           adc    r31, r31
3aa:    ec 55           subi    r30, 0x5C    ; 92
3ac:    ff 4f           sbci    r31, 0xFF    ; 255
3ae:    a5 91           lpm    r26, Z+
3b0:    b4 91           lpm    r27, Z

    uint8_t oldSREG = SREG;
3b2:    9f b7           in    r25, 0x3f    ; 63
    cli();
3b4:    f8 94           cli

    if (val == LOW) {
        *out &= ~bit;
3b6:    8c 91           ld    r24, X
    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
3b8:    61 11           cpse    r22, r1
3ba:    03 c0           rjmp    .+6          ; 0x3c2 <digitalWrite+0x5a>
        *out &= ~bit;
3bc:    10 95           com    r17
3be:    81 23           and    r24, r17
3c0:    01 c0           rjmp    .+2          ; 0x3c4 <digitalWrite+0x5c>
    } else {
        *out |= bit;
3c2:    81 2b           or    r24, r17
3c4:    8c 93           st    X, r24
    }

    SREG = oldSREG;
3c6:    9f bf           out    0x3f, r25    ; 63
}
3c8:    0f 90           pop    r0
3ca:    df 91           pop    r29
3cc:    cf 91           pop    r28
3ce:    1f 91           pop    r17
3d0:    0f 91           pop    r16
3d2:    08 95           ret

000003d4 <initVariant>:
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }
3d4:    08 95           ret

000003d6 <main>:
void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
    init();
3d6:    0e 94 17 01     call    0x22e    ; 0x22e <init>

    initVariant();
3da:    0e 94 ea 01     call    0x3d4    ; 0x3d4 <initVariant>

#if defined(USBCON)
    USBDevice.attach();
#endif
    
    setup();
3de:    0e 94 70 00     call    0xe0    ; 0xe0 <setup>
    
    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
3e2:    c0 e0           ldi    r28, 0x00    ; 0
3e4:    d0 e0           ldi    r29, 0x00    ; 0
#endif
    
    setup();
    
    for (;;) {
        loop();
3e6:    0e 94 74 00     call    0xe8    ; 0xe8 <loop>
        if (serialEventRun) serialEventRun();
3ea:    20 97           sbiw    r28, 0x00    ; 0
3ec:    e1 f3           breq    .-8          ; 0x3e6 <main+0x10>
3ee:    0e 94 00 00     call    0    ; 0x0 <__vectors>
3f2:    f9 cf           rjmp    .-14         ; 0x3e6 <main+0x10>

000003f4 <yield>:
* libraries or sketches that supports cooperative threads.
*
* Its defined as a weak symbol and it can be redefined to implement a
* real cooperative scheduler.
*/
static void __empty() {
3f4:    08 95           ret

000003f6 <__muluhisi3>:
3f6:    0e 94 06 02     call    0x40c    ; 0x40c <__umulhisi3>
3fa:    a5 9f           mul    r26, r21
3fc:    90 0d           add    r25, r0
3fe:    b4 9f           mul    r27, r20
400:    90 0d           add    r25, r0
402:    a4 9f           mul    r26, r20
404:    80 0d           add    r24, r0
406:    91 1d           adc    r25, r1
408:    11 24           eor    r1, r1
40a:    08 95           ret

0000040c <__umulhisi3>:
40c:    a2 9f           mul    r26, r18
40e:    b0 01           movw    r22, r0
410:    b3 9f           mul    r27, r19
412:    c0 01           movw    r24, r0
414:    a3 9f           mul    r26, r19
416:    70 0d           add    r23, r0
418:    81 1d           adc    r24, r1
41a:    11 24           eor    r1, r1
41c:    91 1d           adc    r25, r1
41e:    b2 9f           mul    r27, r18
420:    70 0d           add    r23, r0
422:    81 1d           adc    r24, r1
424:    11 24           eor    r1, r1
426:    91 1d           adc    r25, r1
428:    08 95           ret

0000042a <_exit>:
42a:    f8 94           cli

0000042c <__stop_program>:
42c:    ff cf           rjmp    .-2          ; 0x42c <__stop_program>

I've taken some time and figured out the AVR assembly. I may post a quick write-up walking us through the code...I don't think I'll take the time to figure out all the Arduino code!

The Assembly is very elegant, and fun to figure out.

I just wanted to show a little bit of what happens "under the hood".

Brendan
Reply
02-19-2016, 11:17 AM,
#2
RE: Arduino Bloat! (A comparison of the Blink program)
The cost of abstraction and simplification. Also a good reminder that when you're playing with hardware it's good to get on the hardware's level. I'd bet you could trim another 20 bytes off the AVR-C bytecode by writing in pure AVR-ASM.
Reply
03-23-2016, 12:13 PM,
#3
RE: Arduino Bloat! (A comparison of the Blink program)
Can you do another comparison with the MBed libraries? I'd be interested in how the other frameworks add up.
Reply
03-27-2016, 09:18 PM,
#4
RE: Arduino Bloat! (A comparison of the Blink program)
(03-23-2016, 12:13 PM)fossum Wrote: Can you do another comparison with the MBed libraries? I'd be interested in how the other frameworks add up.

I don't know anything about MBed, but I'll look into it! Smile
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)