Arduino: просмотр размера кода и ассемблерного листинга программы

Добавлено 19 июня 2016 в 01:00

При разработке программ для плат Arduino иногда может возникнуть необходимость оценки, возможно ли выполнить оптимизацию кода, и определения места, где эта оптимизация необходима. Для этого необходимо получить ассемблерный листинг программы, а также определить, какой размер flash-памяти занимает какая-либо часть вашего кода.

Для этих целей воспользуемся двумя инструментами из набора AVR toolchain: avr-nm и avr-objdump. Оба этих инструмента поставляются вместе с Arduino IDE.

Поиск .elf файла

Итак, предположим, что вы написали скетч для Arduino и хотите оптимизировать его размер.

После компиляции скетча, первое, что необходимо сделать, это найти скомпилированный бинарный файл. Самый простой способ сделать это – включить показ подробного вывода процесса компиляции и посмотреть путь к .elf файлу в конце лога.

настройка вывода компиляции
Настройка вывода процесса компиляции
лог компиляции
Путь к .elf файлу

В зависимости от версии Arduino IDE файл может называться либо Blink.ino.elf, либо Blink.cpp.elf, либо Blink.elf.

Просмотр размера кода с помощью avr-nm

При оптимизации размера программы важно определить место, где эта оптимизация необходима. Используя avr-nm, вы сможете определить размер каждой функции.

Откройте командную строку и введите:

set PATH=%PATH%;C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\
avr-nm --size-sort -Crtd Blink.ino.elf

После чего в консоль будет выведен размер всех функций и данных:

00000148 T __vector_16
00000118 T init
00000114 T pinMode
00000108 T digitalWrite
00000082 t turnOffPWM
00000080 T delay
00000070 T micros
00000040 T loop
00000030 T main
00000020 T digital_pin_to_timer_PGM
00000020 T digital_pin_to_port_PGM
00000020 T digital_pin_to_bit_mask_PGM
00000016 T __do_clear_bss
00000010 T port_to_output_PGM
00000010 T port_to_mode_PGM
00000008 T setup
00000004 B timer0_overflow_count
00000004 B timer0_millis
00000002 W yield
00000002 W initVariant
00000002 t __empty

Первый столбец – это размер объекта, на который ссылается символ. Второй столбец – тип, где 't' (в верхнем или нижнем регистре) означает «текст» (код или данные PROGMEM), 'd' означает «инициализированные данные» (сохраненные во flash-памяти и скопированные в RAM при запуске), а 'b' означает «неинициализированные данные» (также известные, как «BSS», не занимают flash-память, только RAM). Регистр буквы показывает, является ли символ локальным (нижний регистр) или глобальным (верхний регистр). И последний столбец – имя символа. В данном примере вы можете увидеть, что самой большой функцией здесь является __vector_16 (обработчик прерывания по переполнению таймера 0), она занимает 148 байт во flash-памяти.

В этом примере мы передали avr-nm следующие опции:

  • --size-sort, очевидно, сортирует символы по размеру. Она также показывает в первом столбце размер символа, вместо его адреса;
  • -C означает декодирование символов C++. Например, вместо отображения “_ZN14HardwareSerial5beginEm”, она покажет “HardwareSerial::begin(unsigned long)”;
  • -r означает «обратный порядок сортировки». Она выводит самые большие функции вверху;
  • -td означает отображение размеров в десятичном формате, вместо шестнадцатеричного.

Просмотр ассемблерного листинга программы с помощью avr-objdump

Когда avr-nm становится недостаточно, у вас не остается выбора, кроме как использовать самое мощное оружие: дизассемблер. С помощью avr-objdump вы можете извлечь ассемблерный код из .elf файла.

Наберите в командной строке:

set PATH=%PATH%;C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\
avr-objdump -S "путь_к_elf_файлу" > "путь_к_новому_файлу_листинга"

Например:

avr-objdump -S Blink.ino.elf > list.txt

Опция -S означает вывод исходного кода вместе с дизассемблированным.

В результате получили следующее:


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 f1 01 	call	0x3e2	; 0x3e2 <main>
  d8:	0c 94 01 02 	jmp	0x402	; 0x402 <_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 81 01 	jmp	0x302	; 0x302 <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 ba 01 	call	0x374	; 0x374 <digitalWrite>
  delay(1000);              // wait for a second
  f0:	68 ee       	ldi	r22, 0xE8	; 232
  f2:	73 e0       	ldi	r23, 0x03	; 3
  f4:	80 e0       	ldi	r24, 0x00	; 0
  f6:	90 e0       	ldi	r25, 0x00	; 0
  f8:	0e 94 f5 00 	call	0x1ea	; 0x1ea <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 ba 01 	call	0x374	; 0x374 <digitalWrite>
  delay(1000);              // wait for a second
 104:	68 ee       	ldi	r22, 0xE8	; 232
 106:	73 e0       	ldi	r23, 0x03	; 3
 108:	80 e0       	ldi	r24, 0x00	; 0
 10a:	90 e0       	ldi	r25, 0x00	; 0
 10c:	0c 94 f5 00 	jmp	0x1ea	; 0x1ea <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:	23 e0       	ldi	r18, 0x03	; 3
 13c:	23 0f       	add	r18, r19
	if (f >= FRACT_MAX) {
 13e:	2d 37       	cpi	r18, 0x7D	; 125
 140:	20 f4       	brcc	.+8      	; 0x14a <__vector_16+0x3a>
	// 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;
	unsigned char f = timer0_fract;

	m += MILLIS_INC;
 142:	01 96       	adiw	r24, 0x01	; 1
 144:	a1 1d       	adc	r26, r1
 146:	b1 1d       	adc	r27, r1
 148:	05 c0       	rjmp	.+10     	; 0x154 <__vector_16+0x44>
	f += FRACT_INC;
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
 14a:	26 e8       	ldi	r18, 0x86	; 134
 14c:	23 0f       	add	r18, r19
		m += 1;
 14e:	02 96       	adiw	r24, 0x02	; 2
 150:	a1 1d       	adc	r26, r1
 152:	b1 1d       	adc	r27, r1
	}

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

000001a4 <micros>:
	return m;
}

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
 1a4:	3f b7       	in	r19, 0x3f	; 63
	
	cli();
 1a6:	f8 94       	cli
	m = timer0_overflow_count;
 1a8:	80 91 05 01 	lds	r24, 0x0105
 1ac:	90 91 06 01 	lds	r25, 0x0106
 1b0:	a0 91 07 01 	lds	r26, 0x0107
 1b4:	b0 91 08 01 	lds	r27, 0x0108
#if defined(TCNT0)
	t = TCNT0;
 1b8:	26 b5       	in	r18, 0x26	; 38
#else
	#error TIMER 0 not defined
#endif

#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
 1ba:	a8 9b       	sbis	0x15, 0	; 21
 1bc:	05 c0       	rjmp	.+10     	; 0x1c8 <micros+0x24>
 1be:	2f 3f       	cpi	r18, 0xFF	; 255
 1c0:	19 f0       	breq	.+6      	; 0x1c8 <micros+0x24>
		m++;
 1c2:	01 96       	adiw	r24, 0x01	; 1
 1c4:	a1 1d       	adc	r26, r1
 1c6:	b1 1d       	adc	r27, r1
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif

	SREG = oldSREG;
 1c8:	3f bf       	out	0x3f, r19	; 63
	
	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
 1ca:	66 27       	eor	r22, r22
 1cc:	78 2f       	mov	r23, r24
 1ce:	89 2f       	mov	r24, r25
 1d0:	9a 2f       	mov	r25, r26
 1d2:	62 0f       	add	r22, r18
 1d4:	71 1d       	adc	r23, r1
 1d6:	81 1d       	adc	r24, r1
 1d8:	91 1d       	adc	r25, r1
 1da:	42 e0       	ldi	r20, 0x02	; 2
 1dc:	66 0f       	add	r22, r22
 1de:	77 1f       	adc	r23, r23
 1e0:	88 1f       	adc	r24, r24
 1e2:	99 1f       	adc	r25, r25
 1e4:	4a 95       	dec	r20
 1e6:	d1 f7       	brne	.-12     	; 0x1dc <micros+0x38>
}
 1e8:	08 95       	ret

000001ea <delay>:

void delay(unsigned long ms)
{
 1ea:	cf 92       	push	r12
 1ec:	df 92       	push	r13
 1ee:	ef 92       	push	r14
 1f0:	ff 92       	push	r15
 1f2:	cf 93       	push	r28
 1f4:	df 93       	push	r29
 1f6:	6b 01       	movw	r12, r22
 1f8:	7c 01       	movw	r14, r24
	uint16_t start = (uint16_t)micros();
 1fa:	0e 94 d2 00 	call	0x1a4	; 0x1a4 <micros>
 1fe:	eb 01       	movw	r28, r22

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

0000023a <init>:

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
 23a:	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);
 23c:	84 b5       	in	r24, 0x24	; 36
 23e:	82 60       	ori	r24, 0x02	; 2
 240:	84 bd       	out	0x24, r24	; 36
	sbi(TCCR0A, WGM00);
 242:	84 b5       	in	r24, 0x24	; 36
 244:	81 60       	ori	r24, 0x01	; 1
 246:	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);
 248:	85 b5       	in	r24, 0x25	; 37
 24a:	82 60       	ori	r24, 0x02	; 2
 24c:	85 bd       	out	0x25, r24	; 37
	sbi(TCCR0B, CS00);
 24e:	85 b5       	in	r24, 0x25	; 37
 250:	81 60       	ori	r24, 0x01	; 1
 252:	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);
 254:	ee e6       	ldi	r30, 0x6E	; 110
 256:	f0 e0       	ldi	r31, 0x00	; 0
 258:	80 81       	ld	r24, Z
 25a:	81 60       	ori	r24, 0x01	; 1
 25c:	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;
 25e:	e1 e8       	ldi	r30, 0x81	; 129
 260:	f0 e0       	ldi	r31, 0x00	; 0
 262:	10 82       	st	Z, r1

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
 264:	80 81       	ld	r24, Z
 266:	82 60       	ori	r24, 0x02	; 2
 268:	80 83       	st	Z, r24
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
 26a:	80 81       	ld	r24, Z
 26c:	81 60       	ori	r24, 0x01	; 1
 26e:	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);
 270:	e0 e8       	ldi	r30, 0x80	; 128
 272:	f0 e0       	ldi	r31, 0x00	; 0
 274:	80 81       	ld	r24, Z
 276:	81 60       	ori	r24, 0x01	; 1
 278:	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);
 27a:	e1 eb       	ldi	r30, 0xB1	; 177
 27c:	f0 e0       	ldi	r31, 0x00	; 0
 27e:	80 81       	ld	r24, Z
 280:	84 60       	ori	r24, 0x04	; 4
 282:	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);
 284:	e0 eb       	ldi	r30, 0xB0	; 176
 286:	f0 e0       	ldi	r31, 0x00	; 0
 288:	80 81       	ld	r24, Z
 28a:	81 60       	ori	r24, 0x01	; 1
 28c:	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);
 28e:	ea e7       	ldi	r30, 0x7A	; 122
 290:	f0 e0       	ldi	r31, 0x00	; 0
 292:	80 81       	ld	r24, Z
 294:	84 60       	ori	r24, 0x04	; 4
 296:	80 83       	st	Z, r24
		sbi(ADCSRA, ADPS1);
 298:	80 81       	ld	r24, Z
 29a:	82 60       	ori	r24, 0x02	; 2
 29c:	80 83       	st	Z, r24
		sbi(ADCSRA, ADPS0);
 29e:	80 81       	ld	r24, Z
 2a0:	81 60       	ori	r24, 0x01	; 1
 2a2:	80 83       	st	Z, r24
		cbi(ADCSRA, ADPS2);
		cbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#endif
	// enable a2d conversions
	sbi(ADCSRA, ADEN);
 2a4:	80 81       	ld	r24, Z
 2a6:	80 68       	ori	r24, 0x80	; 128
 2a8:	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;
 2aa:	10 92 c1 00 	sts	0x00C1, r1
 2ae:	08 95       	ret

000002b0 <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)
 2b0:	83 30       	cpi	r24, 0x03	; 3
 2b2:	81 f0       	breq	.+32     	; 0x2d4 <turnOffPWM+0x24>
 2b4:	28 f4       	brcc	.+10     	; 0x2c0 <turnOffPWM+0x10>
 2b6:	81 30       	cpi	r24, 0x01	; 1
 2b8:	99 f0       	breq	.+38     	; 0x2e0 <turnOffPWM+0x30>
 2ba:	82 30       	cpi	r24, 0x02	; 2
 2bc:	a1 f0       	breq	.+40     	; 0x2e6 <turnOffPWM+0x36>
 2be:	08 95       	ret
 2c0:	87 30       	cpi	r24, 0x07	; 7
 2c2:	a9 f0       	breq	.+42     	; 0x2ee <turnOffPWM+0x3e>
 2c4:	88 30       	cpi	r24, 0x08	; 8
 2c6:	b9 f0       	breq	.+46     	; 0x2f6 <turnOffPWM+0x46>
 2c8:	84 30       	cpi	r24, 0x04	; 4
 2ca:	d1 f4       	brne	.+52     	; 0x300 <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;
 2cc:	80 91 80 00 	lds	r24, 0x0080
 2d0:	8f 7d       	andi	r24, 0xDF	; 223
 2d2:	03 c0       	rjmp	.+6      	; 0x2da <turnOffPWM+0x2a>
static void turnOffPWM(uint8_t timer)
{
	switch (timer)
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
 2d4:	80 91 80 00 	lds	r24, 0x0080
 2d8:	8f 77       	andi	r24, 0x7F	; 127
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 2da:	80 93 80 00 	sts	0x0080, r24
 2de:	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;
 2e0:	84 b5       	in	r24, 0x24	; 36
 2e2:	8f 77       	andi	r24, 0x7F	; 127
 2e4:	02 c0       	rjmp	.+4      	; 0x2ea <turnOffPWM+0x3a>
		#endif
		
		#if defined(TCCR0A) && defined(COM0B1)
		case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
 2e6:	84 b5       	in	r24, 0x24	; 36
 2e8:	8f 7d       	andi	r24, 0xDF	; 223
 2ea:	84 bd       	out	0x24, r24	; 36
 2ec:	08 95       	ret
		#endif
		#if defined(TCCR2A) && defined(COM2A1)
		case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
 2ee:	80 91 b0 00 	lds	r24, 0x00B0
 2f2:	8f 77       	andi	r24, 0x7F	; 127
 2f4:	03 c0       	rjmp	.+6      	; 0x2fc <turnOffPWM+0x4c>
		#endif
		#if defined(TCCR2A) && defined(COM2B1)
		case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
 2f6:	80 91 b0 00 	lds	r24, 0x00B0
 2fa:	8f 7d       	andi	r24, 0xDF	; 223
 2fc:	80 93 b0 00 	sts	0x00B0, r24
 300:	08 95       	ret

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

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

	if (port == NOT_A_PIN) return;
 318:	88 23       	and	r24, r24
 31a:	49 f1       	breq	.+82     	; 0x36e <pinMode+0x6c>

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

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

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

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

00000374 <digitalWrite>:
		#endif
	}
}

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

	if (port == NOT_A_PIN) return;
 39e:	00 23       	and	r16, r16
 3a0:	c9 f0       	breq	.+50     	; 0x3d4 <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);
 3a2:	88 23       	and	r24, r24
 3a4:	21 f0       	breq	.+8      	; 0x3ae <digitalWrite+0x3a>
 3a6:	69 83       	std	Y+1, r22	; 0x01
 3a8:	0e 94 58 01 	call	0x2b0	; 0x2b0 <turnOffPWM>
 3ac:	69 81       	ldd	r22, Y+1	; 0x01

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

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

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

	uint8_t oldSREG = SREG;
	cli();

	if (val == LOW) {
 3c4:	61 11       	cpse	r22, r1
 3c6:	03 c0       	rjmp	.+6      	; 0x3ce <digitalWrite+0x5a>
		*out &= ~bit;
 3c8:	10 95       	com	r17
 3ca:	81 23       	and	r24, r17
 3cc:	01 c0       	rjmp	.+2      	; 0x3d0 <digitalWrite+0x5c>
	} else {
		*out |= bit;
 3ce:	81 2b       	or	r24, r17
 3d0:	8c 93       	st	X, r24
	}

	SREG = oldSREG;
 3d2:	9f bf       	out	0x3f, r25	; 63
}
 3d4:	0f 90       	pop	r0
 3d6:	df 91       	pop	r29
 3d8:	cf 91       	pop	r28
 3da:	1f 91       	pop	r17
 3dc:	0f 91       	pop	r16
 3de:	08 95       	ret

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

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

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

int main(void)
{
	init();
 3e2:	0e 94 1d 01 	call	0x23a	; 0x23a <init>

	initVariant();
 3e6:	0e 94 f0 01 	call	0x3e0	; 0x3e0 <initVariant>

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

00000400 <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() {
 400:	08 95       	ret

00000402 <_exit>:
 402:	f8 94       	cli

00000404 <__stop_program>:
 404:	ff cf       	rjmp	.-2      	; 0x404 <__stop_program>

Вот и всё! Надеюсь, статья оказалась полезной. Оставляйте комментарии!

Теги

ArduinoАссемблерДизассемблерОтладка

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.