Tips and Tricks (15)

Previous Tip & Trick

Disassembling code!

What for? Well, once you fight for speed and code efficiency, you may have to get into the ultimate human readable code: assembler.

In the latest Arduino revisions, getting to here is surprisingly not so trivial. The given explanations will work for PC running XP.

First of all, make the hidden files visible. Open “My computer”, under “Tools” select “File options…”, check “Display”, activate the “Display hidden files and directories” radio button. The hidden files and directories will not appear in a shaded manner in the browser.

Then you have to tell Arduino IDE that you decided to change the place where the bits and pieces required to build the .hex files have be recorded. By default, they are recorded @

C:\Documents and Settings\[user_name]\Local Settings\Temp

Close all running Arduino IDEs! Find and open the preference.txt file which is located @

C:\Documents and Settings\[user_name]\Application Data\Arduino

Warning: do not modify the preference.txt file from C:\Program Files\arduino-1.0\lib. This file contains the default settings.

Append the following line:

build.path=[destination_directory]

As an organized man, this is the way I managed it:

build.path=C:\Documents and Settings\[User]\Mes documents\Arduino\Tools\Diassemble\Build

Save and close the preference.txt file, open an existing sketch and compile it (no need to upload). the .o, .a, .eep, .elf, .hex files are now available (and visible)in the specified destination directory.

Now, let’s write a very simple script which will launch avr-objdump.exe and diassemble the .elf file

Open a new text file and name it at your convenience (e.g. diassemble.bat). Enter the following text:

C:\PROGRA~1\arduino-1.0\hardware\tools\avr\bin\avr-objdump.exe -S C:\DOCUME~1\[user_name]\MESDOC~1\Arduino\Tools\Diassemble\Build*.elf > C:\DOCUME~1\[user_name]\MESDOC~1\Arduino\Tools\Diassemble\Build\diassembled_code.s
pause

Note: avr-objdump.exe expects DOS arguments so that short names must be used. Use the dir /x option in a DOS session in order to get these names.

Points of attention:
– All your builds will now be recorded in the specified directory
– The files will leave as long as your Arduino session is open and shall be removed when closing it
– The use of *.elf in the script allows a moderate degree of automation. In this way, you do not have to update the script for all projects.

Here comes the basic blink.ino sketch…

C:\DOCUME~1\[User_name]\MESDOC~1\Arduino\Tools\Diassemble\Build\Blink.cpp.elf:     file format elf32-avr

Disassembly of section .text:

00000000 :
	timer0_millis = m;
	timer0_overflow_count++;
}

unsigned long millis()
{
   0:	0c 94 61 00 	jmp	0xc2	; 0xc2 

	SREG = oldSREG;
}

int digitalRead(uint8_t pin)
{
   4:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
   8:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
   c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  10:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  14:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  18:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  1c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  20:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  24:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  28:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  2c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  30:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  34:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  38:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  3c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  40:	0c 94 9a 00 	jmp	0x134	; 0x134 
  44:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  48:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  4c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  50:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  54:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  58:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  5c:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  60:	0c 94 7e 00 	jmp	0xfc	; 0xfc 
  64:	0c 94 7e 00 	jmp	0xfc	; 0xfc 

00000068 :
  68:	00 00 00 00 24 00 27 00 2a 00                       ....$.'.*.

00000072 :
  72:	00 00 00 00 25 00 28 00 2b 00                       ....%.(.+.

0000007c :
  7c:	00 00 00 00 23 00 26 00 29 00                       ....#.&.).

00000086 :
  86:	04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03     ................
  96:	03 03 03 03                                         ....

0000009a :
  9a:	01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02     ..... @...... ..
  aa:	04 08 10 20                                         ... 

000000ae :
  ae:	00 00 00 07 00 02 01 00 00 03 04 06 00 00 00 00     ................
  be:	00 00 00 00                                         ....

000000c2 :
  c2:	11 24       	eor	r1, r1
  c4:	1f be       	out	0x3f, r1	; 63
  c6:	cf ef       	ldi	r28, 0xFF	; 255
  c8:	d8 e0       	ldi	r29, 0x08	; 8
  ca:	de bf       	out	0x3e, r29	; 62
  cc:	cd bf       	out	0x3d, r28	; 61

000000ce :
  ce:	11 e0       	ldi	r17, 0x01	; 1
  d0:	a0 e0       	ldi	r26, 0x00	; 0
  d2:	b1 e0       	ldi	r27, 0x01	; 1
  d4:	e2 e0       	ldi	r30, 0x02	; 2
  d6:	f4 e0       	ldi	r31, 0x04	; 4
  d8:	02 c0       	rjmp	.+4      	; 0xde 

000000da :
  da:	05 90       	lpm	r0, Z+
  dc:	0d 92       	st	X+, r0

000000de :
  de:	a0 30       	cpi	r26, 0x00	; 0
  e0:	b1 07       	cpc	r27, r17
  e2:	d9 f7       	brne	.-10     	; 0xda 

000000e4 :
  e4:	11 e0       	ldi	r17, 0x01	; 1
  e6:	a0 e0       	ldi	r26, 0x00	; 0
  e8:	b1 e0       	ldi	r27, 0x01	; 1
  ea:	01 c0       	rjmp	.+2      	; 0xee 

000000ec :
  ec:	1d 92       	st	X+, r1

000000ee :
  ee:	a9 30       	cpi	r26, 0x09	; 9
  f0:	b1 07       	cpc	r27, r17
  f2:	e1 f7       	brne	.-8      	; 0xec 
  f4:	0e 94 f0 01 	call	0x3e0	; 0x3e0 
  f8:	0c 94 ff 01 	jmp	0x3fe	; 0x3fe 

000000fc :
  fc:	0c 94 00 00 	jmp	0	; 0x0 

00000100 :
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(13, OUTPUT);     
}

void loop() {
  digitalWrite(13, HIGH);   // set the LED on
 100:	8d e0       	ldi	r24, 0x0D	; 13
 102:	61 e0       	ldi	r22, 0x01	; 1
 104:	0e 94 9c 01 	call	0x338	; 0x338 
  delay(1000);              // wait for a second
 108:	68 ee       	ldi	r22, 0xE8	; 232
 10a:	73 e0       	ldi	r23, 0x03	; 3
 10c:	80 e0       	ldi	r24, 0x00	; 0
 10e:	90 e0       	ldi	r25, 0x00	; 0
 110:	0e 94 e2 00 	call	0x1c4	; 0x1c4 
  digitalWrite(13, LOW);    // set the LED off
 114:	8d e0       	ldi	r24, 0x0D	; 13
 116:	60 e0       	ldi	r22, 0x00	; 0
 118:	0e 94 9c 01 	call	0x338	; 0x338 
  delay(1000);              // wait for a second
 11c:	68 ee       	ldi	r22, 0xE8	; 232
 11e:	73 e0       	ldi	r23, 0x03	; 3
 120:	80 e0       	ldi	r24, 0x00	; 0
 122:	90 e0       	ldi	r25, 0x00	; 0
 124:	0e 94 e2 00 	call	0x1c4	; 0x1c4 
}
 128:	08 95       	ret

0000012a :
void setup();
void loop();
void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(13, OUTPUT);     
 12a:	8d e0       	ldi	r24, 0x0D	; 13
 12c:	61 e0       	ldi	r22, 0x01	; 1
 12e:	0e 94 76 01 	call	0x2ec	; 0x2ec 
}
 132:	08 95       	ret

00000134 :
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
 134:	1f 92       	push	r1
 136:	0f 92       	push	r0
 138:	0f b6       	in	r0, 0x3f	; 63
 13a:	0f 92       	push	r0
 13c:	11 24       	eor	r1, r1
 13e:	2f 93       	push	r18
 140:	3f 93       	push	r19
 142:	8f 93       	push	r24
 144:	9f 93       	push	r25
 146:	af 93       	push	r26
 148:	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;
 14a:	80 91 04 01 	lds	r24, 0x0104
 14e:	90 91 05 01 	lds	r25, 0x0105
 152:	a0 91 06 01 	lds	r26, 0x0106
 156:	b0 91 07 01 	lds	r27, 0x0107
	unsigned char f = timer0_fract;
 15a:	30 91 08 01 	lds	r19, 0x0108

	m += MILLIS_INC;
 15e:	01 96       	adiw	r24, 0x01	; 1
 160:	a1 1d       	adc	r26, r1
 162:	b1 1d       	adc	r27, r1
	f += FRACT_INC;
 164:	23 2f       	mov	r18, r19
 166:	2d 5f       	subi	r18, 0xFD	; 253
	if (f >= FRACT_MAX) {
 168:	2d 37       	cpi	r18, 0x7D	; 125
 16a:	20 f0       	brcs	.+8      	; 0x174 
		f -= FRACT_MAX;
 16c:	2d 57       	subi	r18, 0x7D	; 125
		m += 1;
 16e:	01 96       	adiw	r24, 0x01	; 1
 170:	a1 1d       	adc	r26, r1
 172:	b1 1d       	adc	r27, r1
	}

	timer0_fract = f;
 174:	20 93 08 01 	sts	0x0108, r18
	timer0_millis = m;
 178:	80 93 04 01 	sts	0x0104, r24
 17c:	90 93 05 01 	sts	0x0105, r25
 180:	a0 93 06 01 	sts	0x0106, r26
 184:	b0 93 07 01 	sts	0x0107, r27
	timer0_overflow_count++;
 188:	80 91 00 01 	lds	r24, 0x0100
 18c:	90 91 01 01 	lds	r25, 0x0101
 190:	a0 91 02 01 	lds	r26, 0x0102
 194:	b0 91 03 01 	lds	r27, 0x0103
 198:	01 96       	adiw	r24, 0x01	; 1
 19a:	a1 1d       	adc	r26, r1
 19c:	b1 1d       	adc	r27, r1
 19e:	80 93 00 01 	sts	0x0100, r24
 1a2:	90 93 01 01 	sts	0x0101, r25
 1a6:	a0 93 02 01 	sts	0x0102, r26
 1aa:	b0 93 03 01 	sts	0x0103, r27
}
 1ae:	bf 91       	pop	r27
 1b0:	af 91       	pop	r26
 1b2:	9f 91       	pop	r25
 1b4:	8f 91       	pop	r24
 1b6:	3f 91       	pop	r19
 1b8:	2f 91       	pop	r18
 1ba:	0f 90       	pop	r0
 1bc:	0f be       	out	0x3f, r0	; 63
 1be:	0f 90       	pop	r0
 1c0:	1f 90       	pop	r1
 1c2:	18 95       	reti

000001c4 :

	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

void delay(unsigned long ms)
{
 1c4:	9b 01       	movw	r18, r22
 1c6:	ac 01       	movw	r20, r24
	return m;
}

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
 1c8:	7f b7       	in	r23, 0x3f	; 63

	cli();
 1ca:	f8 94       	cli
	m = timer0_overflow_count;
 1cc:	80 91 00 01 	lds	r24, 0x0100
 1d0:	90 91 01 01 	lds	r25, 0x0101
 1d4:	a0 91 02 01 	lds	r26, 0x0102
 1d8:	b0 91 03 01 	lds	r27, 0x0103
#if defined(TCNT0)
	t = TCNT0;
 1dc:	66 b5       	in	r22, 0x26	; 38
	#error TIMER 0 not defined
#endif

#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
 1de:	a8 9b       	sbis	0x15, 0	; 21
 1e0:	05 c0       	rjmp	.+10     	; 0x1ec 
 1e2:	6f 3f       	cpi	r22, 0xFF	; 255
 1e4:	19 f0       	breq	.+6      	; 0x1ec 
		m++;
 1e6:	01 96       	adiw	r24, 0x01	; 1
 1e8:	a1 1d       	adc	r26, r1
 1ea:	b1 1d       	adc	r27, r1
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif

	SREG = oldSREG;
 1ec:	7f bf       	out	0x3f, r23	; 63
	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();
 1ee:	ba 2f       	mov	r27, r26
 1f0:	a9 2f       	mov	r26, r25
 1f2:	98 2f       	mov	r25, r24
 1f4:	88 27       	eor	r24, r24
 1f6:	86 0f       	add	r24, r22
 1f8:	91 1d       	adc	r25, r1
 1fa:	a1 1d       	adc	r26, r1
 1fc:	b1 1d       	adc	r27, r1
 1fe:	62 e0       	ldi	r22, 0x02	; 2
 200:	88 0f       	add	r24, r24
 202:	99 1f       	adc	r25, r25
 204:	aa 1f       	adc	r26, r26
 206:	bb 1f       	adc	r27, r27
 208:	6a 95       	dec	r22
 20a:	d1 f7       	brne	.-12     	; 0x200 
 20c:	bc 01       	movw	r22, r24
 20e:	2d c0       	rjmp	.+90     	; 0x26a 
	return m;
}

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
 210:	ff b7       	in	r31, 0x3f	; 63

	cli();
 212:	f8 94       	cli
	m = timer0_overflow_count;
 214:	80 91 00 01 	lds	r24, 0x0100
 218:	90 91 01 01 	lds	r25, 0x0101
 21c:	a0 91 02 01 	lds	r26, 0x0102
 220:	b0 91 03 01 	lds	r27, 0x0103
#if defined(TCNT0)
	t = TCNT0;
 224:	e6 b5       	in	r30, 0x26	; 38
	#error TIMER 0 not defined
#endif

#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
 226:	a8 9b       	sbis	0x15, 0	; 21
 228:	05 c0       	rjmp	.+10     	; 0x234 
 22a:	ef 3f       	cpi	r30, 0xFF	; 255
 22c:	19 f0       	breq	.+6      	; 0x234 
		m++;
 22e:	01 96       	adiw	r24, 0x01	; 1
 230:	a1 1d       	adc	r26, r1
 232:	b1 1d       	adc	r27, r1
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif

	SREG = oldSREG;
 234:	ff bf       	out	0x3f, r31	; 63
void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();

	while (ms > 0) {
		if (((uint16_t)micros() - start) >= 1000) {
 236:	ba 2f       	mov	r27, r26
 238:	a9 2f       	mov	r26, r25
 23a:	98 2f       	mov	r25, r24
 23c:	88 27       	eor	r24, r24
 23e:	8e 0f       	add	r24, r30
 240:	91 1d       	adc	r25, r1
 242:	a1 1d       	adc	r26, r1
 244:	b1 1d       	adc	r27, r1
 246:	e2 e0       	ldi	r30, 0x02	; 2
 248:	88 0f       	add	r24, r24
 24a:	99 1f       	adc	r25, r25
 24c:	aa 1f       	adc	r26, r26
 24e:	bb 1f       	adc	r27, r27
 250:	ea 95       	dec	r30
 252:	d1 f7       	brne	.-12     	; 0x248 
 254:	86 1b       	sub	r24, r22
 256:	97 0b       	sbc	r25, r23
 258:	88 5e       	subi	r24, 0xE8	; 232
 25a:	93 40       	sbci	r25, 0x03	; 3
 25c:	c8 f2       	brcs	.-78     	; 0x210 
			ms--;
 25e:	21 50       	subi	r18, 0x01	; 1
 260:	30 40       	sbci	r19, 0x00	; 0
 262:	40 40       	sbci	r20, 0x00	; 0
 264:	50 40       	sbci	r21, 0x00	; 0
			start += 1000;
 266:	68 51       	subi	r22, 0x18	; 24
 268:	7c 4f       	sbci	r23, 0xFC	; 252

void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();

	while (ms > 0) {
 26a:	21 15       	cp	r18, r1
 26c:	31 05       	cpc	r19, r1
 26e:	41 05       	cpc	r20, r1
 270:	51 05       	cpc	r21, r1
 272:	71 f6       	brne	.-100    	; 0x210 
		if (((uint16_t)micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}
 274:	08 95       	ret

00000276 :

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
 276:	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);
 278:	84 b5       	in	r24, 0x24	; 36
 27a:	82 60       	ori	r24, 0x02	; 2
 27c:	84 bd       	out	0x24, r24	; 36
	sbi(TCCR0A, WGM00);
 27e:	84 b5       	in	r24, 0x24	; 36
 280:	81 60       	ori	r24, 0x01	; 1
 282:	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);
 284:	85 b5       	in	r24, 0x25	; 37
 286:	82 60       	ori	r24, 0x02	; 2
 288:	85 bd       	out	0x25, r24	; 37
	sbi(TCCR0B, CS00);
 28a:	85 b5       	in	r24, 0x25	; 37
 28c:	81 60       	ori	r24, 0x01	; 1
 28e:	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);
 290:	ee e6       	ldi	r30, 0x6E	; 110
 292:	f0 e0       	ldi	r31, 0x00	; 0
 294:	80 81       	ld	r24, Z
 296:	81 60       	ori	r24, 0x01	; 1
 298:	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;
 29a:	e1 e8       	ldi	r30, 0x81	; 129
 29c:	f0 e0       	ldi	r31, 0x00	; 0
 29e:	10 82       	st	Z, r1

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
 2a0:	80 81       	ld	r24, Z
 2a2:	82 60       	ori	r24, 0x02	; 2
 2a4:	80 83       	st	Z, r24
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
 2a6:	80 81       	ld	r24, Z
 2a8:	81 60       	ori	r24, 0x01	; 1
 2aa:	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);
 2ac:	e0 e8       	ldi	r30, 0x80	; 128
 2ae:	f0 e0       	ldi	r31, 0x00	; 0
 2b0:	80 81       	ld	r24, Z
 2b2:	81 60       	ori	r24, 0x01	; 1
 2b4:	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);
 2b6:	e1 eb       	ldi	r30, 0xB1	; 177
 2b8:	f0 e0       	ldi	r31, 0x00	; 0
 2ba:	80 81       	ld	r24, Z
 2bc:	84 60       	ori	r24, 0x04	; 4
 2be:	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);
 2c0:	e0 eb       	ldi	r30, 0xB0	; 176
 2c2:	f0 e0       	ldi	r31, 0x00	; 0
 2c4:	80 81       	ld	r24, Z
 2c6:	81 60       	ori	r24, 0x01	; 1
 2c8:	80 83       	st	Z, r24
#if defined(ADCSRA)
	// set a2d prescale factor to 128
	// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
	// XXX: this will not work properly for other clock speeds, and
	// this code should use F_CPU to determine the prescale factor.
	sbi(ADCSRA, ADPS2);
 2ca:	ea e7       	ldi	r30, 0x7A	; 122
 2cc:	f0 e0       	ldi	r31, 0x00	; 0
 2ce:	80 81       	ld	r24, Z
 2d0:	84 60       	ori	r24, 0x04	; 4
 2d2:	80 83       	st	Z, r24
	sbi(ADCSRA, ADPS1);
 2d4:	80 81       	ld	r24, Z
 2d6:	82 60       	ori	r24, 0x02	; 2
 2d8:	80 83       	st	Z, r24
	sbi(ADCSRA, ADPS0);
 2da:	80 81       	ld	r24, Z
 2dc:	81 60       	ori	r24, 0x01	; 1
 2de:	80 83       	st	Z, r24

	// enable a2d conversions
	sbi(ADCSRA, ADEN);
 2e0:	80 81       	ld	r24, Z
 2e2:	80 68       	ori	r24, 0x80	; 128
 2e4:	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;
 2e6:	10 92 c1 00 	sts	0x00C1, r1
#endif
}
 2ea:	08 95       	ret

000002ec :
#include "wiring_private.h"
#include "pins_arduino.h"

void pinMode(uint8_t pin, uint8_t mode)
{
	uint8_t bit = digitalPinToBitMask(pin);
 2ec:	48 2f       	mov	r20, r24
 2ee:	50 e0       	ldi	r21, 0x00	; 0
 2f0:	ca 01       	movw	r24, r20
 2f2:	86 56       	subi	r24, 0x66	; 102
 2f4:	9f 4f       	sbci	r25, 0xFF	; 255
 2f6:	fc 01       	movw	r30, r24
 2f8:	24 91       	lpm	r18, Z+
	uint8_t port = digitalPinToPort(pin);
 2fa:	4a 57       	subi	r20, 0x7A	; 122
 2fc:	5f 4f       	sbci	r21, 0xFF	; 255
 2fe:	fa 01       	movw	r30, r20
 300:	84 91       	lpm	r24, Z+
	volatile uint8_t *reg;

	if (port == NOT_A_PIN) return;
 302:	88 23       	and	r24, r24
 304:	c1 f0       	breq	.+48     	; 0x336 

	// JWS: can I let the optimizer do this?
	reg = portModeRegister(port);
 306:	e8 2f       	mov	r30, r24
 308:	f0 e0       	ldi	r31, 0x00	; 0
 30a:	ee 0f       	add	r30, r30
 30c:	ff 1f       	adc	r31, r31
 30e:	e8 59       	subi	r30, 0x98	; 152
 310:	ff 4f       	sbci	r31, 0xFF	; 255
 312:	a5 91       	lpm	r26, Z+
 314:	b4 91       	lpm	r27, Z+

	if (mode == INPUT) { 
 316:	66 23       	and	r22, r22
 318:	41 f4       	brne	.+16     	; 0x32a 
		uint8_t oldSREG = SREG;
 31a:	9f b7       	in	r25, 0x3f	; 63
                cli();
 31c:	f8 94       	cli
		*reg &= ~bit;
 31e:	8c 91       	ld	r24, X
 320:	20 95       	com	r18
 322:	82 23       	and	r24, r18
 324:	8c 93       	st	X, r24
		SREG = oldSREG;
 326:	9f bf       	out	0x3f, r25	; 63
 328:	08 95       	ret
	} else {
		uint8_t oldSREG = SREG;
 32a:	9f b7       	in	r25, 0x3f	; 63
                cli();
 32c:	f8 94       	cli
		*reg |= bit;
 32e:	8c 91       	ld	r24, X
 330:	82 2b       	or	r24, r18
 332:	8c 93       	st	X, r24
		SREG = oldSREG;
 334:	9f bf       	out	0x3f, r25	; 63
 336:	08 95       	ret

00000338 :
	}
}

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
 338:	48 2f       	mov	r20, r24
 33a:	50 e0       	ldi	r21, 0x00	; 0
 33c:	ca 01       	movw	r24, r20
 33e:	82 55       	subi	r24, 0x52	; 82
 340:	9f 4f       	sbci	r25, 0xFF	; 255
 342:	fc 01       	movw	r30, r24
 344:	24 91       	lpm	r18, Z+
	uint8_t bit = digitalPinToBitMask(pin);
 346:	ca 01       	movw	r24, r20
 348:	86 56       	subi	r24, 0x66	; 102
 34a:	9f 4f       	sbci	r25, 0xFF	; 255
 34c:	fc 01       	movw	r30, r24
 34e:	94 91       	lpm	r25, Z+
	uint8_t port = digitalPinToPort(pin);
 350:	4a 57       	subi	r20, 0x7A	; 122
 352:	5f 4f       	sbci	r21, 0xFF	; 255
 354:	fa 01       	movw	r30, r20
 356:	34 91       	lpm	r19, Z+
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;
 358:	33 23       	and	r19, r19
 35a:	09 f4       	brne	.+2      	; 0x35e 
 35c:	40 c0       	rjmp	.+128    	; 0x3de 

	// 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);
 35e:	22 23       	and	r18, r18
 360:	51 f1       	breq	.+84     	; 0x3b6 
//
//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)
 362:	23 30       	cpi	r18, 0x03	; 3
 364:	71 f0       	breq	.+28     	; 0x382 
 366:	24 30       	cpi	r18, 0x04	; 4
 368:	28 f4       	brcc	.+10     	; 0x374 
 36a:	21 30       	cpi	r18, 0x01	; 1
 36c:	a1 f0       	breq	.+40     	; 0x396 
 36e:	22 30       	cpi	r18, 0x02	; 2
 370:	11 f5       	brne	.+68     	; 0x3b6 
 372:	14 c0       	rjmp	.+40     	; 0x39c 
 374:	26 30       	cpi	r18, 0x06	; 6
 376:	b1 f0       	breq	.+44     	; 0x3a4 
 378:	27 30       	cpi	r18, 0x07	; 7
 37a:	c1 f0       	breq	.+48     	; 0x3ac 
 37c:	24 30       	cpi	r18, 0x04	; 4
 37e:	d9 f4       	brne	.+54     	; 0x3b6 
 380:	04 c0       	rjmp	.+8      	; 0x38a 
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
 382:	80 91 80 00 	lds	r24, 0x0080
 386:	8f 77       	andi	r24, 0x7F	; 127
 388:	03 c0       	rjmp	.+6      	; 0x390 
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 38a:	80 91 80 00 	lds	r24, 0x0080
 38e:	8f 7d       	andi	r24, 0xDF	; 223
 390:	80 93 80 00 	sts	0x0080, r24
 394:	10 c0       	rjmp	.+32     	; 0x3b6 
		#if defined(TCCR2) && defined(COM21)
		case  TIMER2:   cbi(TCCR2, COM21);      break;
		#endif

		#if defined(TCCR0A) && defined(COM0A1)
		case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
 396:	84 b5       	in	r24, 0x24	; 36
 398:	8f 77       	andi	r24, 0x7F	; 127
 39a:	02 c0       	rjmp	.+4      	; 0x3a0 
		#endif

		#if defined(TIMER0B) && defined(COM0B1)
		case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
 39c:	84 b5       	in	r24, 0x24	; 36
 39e:	8f 7d       	andi	r24, 0xDF	; 223
 3a0:	84 bd       	out	0x24, r24	; 36
 3a2:	09 c0       	rjmp	.+18     	; 0x3b6 
		#endif
		#if defined(TCCR2A) && defined(COM2A1)
		case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
 3a4:	80 91 b0 00 	lds	r24, 0x00B0
 3a8:	8f 77       	andi	r24, 0x7F	; 127
 3aa:	03 c0       	rjmp	.+6      	; 0x3b2 
		#endif
		#if defined(TCCR2A) && defined(COM2B1)
		case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
 3ac:	80 91 b0 00 	lds	r24, 0x00B0
 3b0:	8f 7d       	andi	r24, 0xDF	; 223
 3b2:	80 93 b0 00 	sts	0x00B0, r24

	// 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);

	out = portOutputRegister(port);
 3b6:	e3 2f       	mov	r30, r19
 3b8:	f0 e0       	ldi	r31, 0x00	; 0
 3ba:	ee 0f       	add	r30, r30
 3bc:	ff 1f       	adc	r31, r31
 3be:	ee 58       	subi	r30, 0x8E	; 142
 3c0:	ff 4f       	sbci	r31, 0xFF	; 255
 3c2:	a5 91       	lpm	r26, Z+
 3c4:	b4 91       	lpm	r27, Z+

	uint8_t oldSREG = SREG;
 3c6:	2f b7       	in	r18, 0x3f	; 63
	cli();
 3c8:	f8 94       	cli

	if (val == LOW) {
 3ca:	66 23       	and	r22, r22
 3cc:	21 f4       	brne	.+8      	; 0x3d6 
		*out &= ~bit;
 3ce:	8c 91       	ld	r24, X
 3d0:	90 95       	com	r25
 3d2:	89 23       	and	r24, r25
 3d4:	02 c0       	rjmp	.+4      	; 0x3da 
	} else {
		*out |= bit;
 3d6:	8c 91       	ld	r24, X
 3d8:	89 2b       	or	r24, r25
 3da:	8c 93       	st	X, r24
	}

	SREG = oldSREG;
 3dc:	2f bf       	out	0x3f, r18	; 63
 3de:	08 95       	ret

000003e0 :
#include 

int main(void)
 3e0:	cf 93       	push	r28
 3e2:	df 93       	push	r29
{
	init();
 3e4:	0e 94 3b 01 	call	0x276	; 0x276 

#if defined(USBCON)
	USB.attach();
#endif

	setup();
 3e8:	0e 94 95 00 	call	0x12a	; 0x12a 

	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
 3ec:	c0 e0       	ldi	r28, 0x00	; 0
 3ee:	d0 e0       	ldi	r29, 0x00	; 0
#endif

	setup();

	for (;;) {
		loop();
 3f0:	0e 94 80 00 	call	0x100	; 0x100 
		if (serialEventRun) serialEventRun();
 3f4:	20 97       	sbiw	r28, 0x00	; 0
 3f6:	e1 f3       	breq	.-8      	; 0x3f0 
 3f8:	0e 94 00 00 	call	0	; 0x0 
 3fc:	f9 cf       	rjmp	.-14     	; 0x3f0 

000003fe :
 3fe:	f8 94       	cli

00000400 :
 400:	ff cf       	rjmp	.-2      	; 0x400

Related links
Inside Arduino – The Build Process

HTH

Next Tip and Trick

 

 

2 Comments

  1. Alejandro Vargas says:

    For linux users:

    The configuration to edit is at ~/.arduino/preferences.txt

    avr-objdump is at /usr/share/arduino/hardware/tools/avr/bin/avr-objdump

Leave a Reply

You must be logged in to post a comment.