AVR assembly

Tanfolyamok, oktatások és kapcsolódó házi feladatok...
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

AVR assembly

Hozzászólás Szerző: holex »

A 60 nap alatt Arduino tanfolyam során (meg sok helyen utána olvasgatva) rájöttem, hogy az Arduino keretrendszer tudása a mikrokontroller lehetőségeihez képest igen csekély (gondolok például a (belső) megszakításokra, stb). Nem tervezitek a jövőben egy erre a tanfolyamra épülő assembly tanfolyam indítását, ami pont az ilyen nyalánkságokat mutatná be?
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Én nem rajongok az assembly-ért, bár ezzel a fórumon nem biztos, hogy osztatlan sikert aratok.

Az indok az, hogy míg a C és a Basic hordozható egyik gépről a másikra, érthető, tömör, addig az assembly nem az.
Ami az AVR assembly-t illeti: szép, érthető, viszont egy kezdő assembly programozót a gcc simán megver.

Lehet beszélni az UINT32-es osztásról, a lebegőpontos aritmetikáról, dinamikus memóriafoglalásról,... amit gcc-ben kiteszteltek, a lehető legtömörebbre összenyomták és megy.

Ha assembly-re van szükségem, azt közvetlenül benyomom a C-be. Ennek viszont a szépséghibája, hogy még sokkal bonyolultabbá és érthetetlenebbé válik a kód, mint előtte.
Ha lehet, akkor inkább a C-re gyúrnék, az assembly "szépségei" helyett.

Csak ízelítőnek, hogy az assembly-t hogyan lehet fokozni:

Kód: Egész kijelölése

  uint8_t var;
  asm volatile (
    "in %[var], %[pin];        \n\t"
    "inc %[var];               \n\t"
    "out %[port], %[var];      \n\t"
      :
      : [c]     "r" (var),
        [pin]   "I" (_SFR_IO_ADDR(PIND)),
        [port]  "I" (_SFR_IO_ADDR(PORTB))
  );
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: AVR assembly

Hozzászólás Szerző: holex »

És szerinted C-ben ki lehet használni teljesen a hardver lehetőségeit? Mint amiket pl. az első hsz-ben említettem: megszakítások jobb használhatósága, stb. Megvannak ehhez C-ben a megfelelő könyvtárak?
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10122
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

Hozzászólás Szerző: Robert »

ASM nincs tervben. (AVR-re ha rákeresel, az _alapok_ megvannak angolul.)

Ami C-ben ill Bascom-ban 10 perces munka, az ASM-ben két-három nap.
Egyetlen miatt jó az ASM: ha időkritikus alkalmazás-rész van, akkor azt ASM betétben írod meg.

Minden kód a végén ASM lesz.
De pl. ASMben egy TCPIP stack, egy SD kártya kezelés nem annyira egyszerű.

De az i2C kezelés Bascom alatt 4 sor.
C-ben azt hiszem 5-6 sor.
ASM alatt ~40-100 körül.
És a kód C ill Bascom alatt kisebb, mint a sima ASMben (mert Te nem tudsz optimalizálni fejben)....


Az összes INT elérhető C ill Bascom alól is...
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Az Arduino 512 byte-os bootloaderét C-ben írták, assemblyvel keverve. Amikor én programozok, akkor C-ben írok mindent, kizárólag a problémás részek kerülnek assembly-be. Emellett mindig generálok assembly forráskódot is és megnézem a végeredményt.

Ha elírtam a for ciklust és uint32_t van uint8_t helyett, akkor azonnal látni fogom hogy a generált kód 4 byte-os regiszterekkel szórakozik 1 helyett. Meglehetősen randa lesz és azonnal szemetszúr.

Elég sok érdekes dolgot meg lehet C-ben csinálni:

Kód: Egész kijelölése

register unsigned char counter asm("r3");
Ebben az esetben megadod, hogy a counter változó az r3 regiszterben legyen definiálva. A compilernek ha megadod, hogy "-ffixed-r3", akkor az r3-at teljesen figyelmen kívül fogja hagyni.

Nálam a rekord egy 29 órajelciklus alatt lefutó interruptot volt. Ez azért elég kemény dolog, a verem helyett regisztereket használtam mentésre.
(Uint16 esetén 2 push 2 pop = 8 órajel. Ha regiszterekbe mentesz, akkor a MOVW 1 (*2) órajel alatt megcsinálja!)

El lehet vinni C-ben is az IC-t a határig, de én csak akkor és ott csinálom, amikor szükség van rá. Egy szimpla LCD kijelző vezérléséhez természetesen nem fogok assembly-vel szórakozni.
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10122
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

Hozzászólás Szerző: Robert »

Nálam a Bascom-AVR regisztrált változata nagyon bejön.
A mcs.lib illetve a mcsebyte.lib belül végig ASM. Azaz a rendszermag ASM rutinjai hozzáférhetőek - kommentezve!
És rengeteg kiegészítő eljárás az LCD-től a Infravevőig mindennek ott a nevesített kódja.
Persze vannak trükkök + optimalizálások is. És a generált HEX/BIN mellett a visszaírt ASM kódból is rengeteget lehet tanulni...
De az inline ASM viszonylag ritkán kellett...
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: AVR assembly

Hozzászólás Szerző: holex »

Rendben, köszönöm a választ, akkor ezek szerint C-ben is teljesen ki tudom használni a hardver lehetőségeit. Ez megnyugtató, mert én sem szívesen assemblyeztem volna, de az Arduino lehetőségei - szerintem - elég gyatrák.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Igen, mindent lehet. Ezt olvasd el.

Ha C-ben assembly-t használsz, akkor nem kerülheted el a beágyazást. Pl. hogy hogyan férsz hozzá C-ben deklarált IO portokhoz, lokális-globális változókhoz, mutatókhoz. Nem az assembly megírása a legnehezebb, hanem az assembly és C közötti adatcsere, ez a legbonyolultabb, de szerencsére csak rövidek az assembly rutinok.
Avatar
Robert
Elektronbűvölő
Hozzászólások: 10122
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

Hozzászólás Szerző: Robert »

A processzor és a nyelv az csak egy eszköz - amivel adott feladatot akarsz/tudsz végrehajtani.

Az Arduino a belépő szint. Hisz' trabanttal sem indulsz gyorsasági versenyen - de valamint a vezetést el kell kezdeni megtanulni...

Az Arduinot olyan lazán leszólod. De csak nézz bele: Jéééé, belül C és a hozzávaló GCC fordító :)
Fogalmazz úgy: sokat kell tanulni, hogy a C nyelven kihasználda teljes hardware-t. majd az első LCD kezelésed, az első sorosportkezelés után lehet hogy visszakívánod az Arduino-t hogy mindent a kezedbe adott... :P
Arduino a kezdetekhez, a hardware megismeréséhez és a gyors eredményekhez nagyon jó. Aki most kezd a LED villogóval ismerkedni, annak a C nyelv - mint kezdet - esélytelen... (regiszterek, fordítókörnyezet, stb.)
Avatar
irak
Biztosítékgyilkos
Hozzászólások: 73
Csatlakozott: 2005. november 2. szerda, 7:00
Tartózkodási hely: Győr

Re: AVR assembly

Hozzászólás Szerző: irak »

Szevasztok!

Ha nincs még gyakorlatod egyik nyelven se, akkor én is bascom-ot javaslom.
Alapban a basic fordítók nem a tömörségről/optimalizációról híresek, de ez igen.
Én is C-ben programozok alapban, épp ezért ismerem a kezdeti nehézségeit (mutatók,precedencia, mellékhatások,stb).
Jó nyelv a C, érdemes megtanulni, már csak azért is, mert ha megérted akkor nem csak avr-en, hanem szinte minden platformon otthon leszel.
Assembler is jó, akkor megérted az eszköz működését teljesen.
De szerintem leghamarabb bascom-avr-el érsz majd el sikert.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Róbert, az Arduino nem C, hanem C++. :)

Ugyanaz megoldható Arduinoval, mint C-vel, csak kissé nagyobb programméretet generál.
Az avr-gcc beállításait az Arduinonak szimplán lemásoltam a saját Makefile-jaimba, mert olyan jól optimalizál. Szórakoztam 1 napot az LCD kijelzővel, nem ment (időzítések). Megnéztem, hogy az Arduino hogyan csinálja, lemásoltam, bár halvány lila gőzöm sem volt, hogy miért küld bizonyos dolgokat 3-szor a kijelzőnek indulásnál, de úgy mégiscsak ment. Kitesztelt könyvtárak, használható, jól működik.

Akkor mire nem jó az Arduino?
- Minthogy C++, így a generált kód jóval nagyobb, mint C-ben. Ez főleg az Attiny és egyéb minichipekre való fordításnál ciki.
- Kicsit körülményes, amikor eltérünk az Atmega328P-től. Amennyivel olcsóbb mondjuk egy tiny chip, kb. háromszor annyival többet szívunk is vele, ergo Arduino környezetben a tiny nem kifizetődő hobbi célra.
- Bizonyos interruptokat tőlem függetlenül kezel. Ez időérzékeny méréseknél probléma. Bizonyos esetekben nem megengedhető, ha egy interrupt 500 órajelet eltüntet.

Szerintem az esetek 95%-ában megoldható Arduino alatt is mindaz, ami C-ben. Én azért nem használok Arduinokat, mert az 550Ft-os Atmega48-as chipekkel szórakozom az 1300 Ft-os Atmega328P helyett, ISP programozóval. Arduino-ból kinyerni a hex fájlt, amit ISP-vel átküldeni az Atmega48-nak igencsak macerás.
Arduino-t kizárólag tesztelésre tartok, a végleges megoldásokra nem használom.

Emellett a C++ nem való szerintem mikrokontrolleres környezetbe. Konstruktor, destruktor, copy konstruktor, operátor túlterhelés,... még a leghalványabb sejtése sincs az embernek arról, hogy egy kifejezés belsejében mi van és ezt a mikrokontroller hogyan eszi meg. A C-t hordozható assembly-nek is hívják, annyira közel van a mikroprocesszor utasításkészletéhez.
Avatar
irak
Biztosítékgyilkos
Hozzászólások: 73
Csatlakozott: 2005. november 2. szerda, 7:00
Tartózkodási hely: Győr

Re: AVR assembly

Hozzászólás Szerző: irak »

Nyilván arduino eszközökhöz készült az egész, nagyobb kontrollerrel.

Amit bemásoltam dckillman-nak,a prell témában, annak a programnak 1K fölött volt a binárisa.
Pedig csak delay van benne ami extra függvény.
Mega8-al szórakozgatok éppen (arduino NG arra épül), annak persze hogy sok.

Sajna a gyári cuccok benne c++-ra épülnek, nagyja feleslegesen.
Például vicces a timer1 class,(TimerOne csomag) amikor fizikailag csak egy timer1 létezik.
A headerben létrehoz egy timer1 nevű extern példányt amit használsz a főprogramodban.:D

Az lcd furmány meg azért kell, mert reset után nem tudni milyen módba volt a kijelző. (4 vagy 8 bit).
Visszavált 8 bitre 2 menetben, utána amire akarod. (ezzel már szenvedtem én is).
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Kód: Egész kijelölése

Amit bemásoltam dckillman-nak,a prell témában, annak a programnak 1K fölött volt a binárisa.
Pedig csak delay van benne ami extra függvény.
Ez így azért durván csúsztatás :)

Szóval leírom, hogy az 1300 byte az micsoda (végignéztem az assembly-t neked):
- 100 byte interrupt vektor tábla
- 100 byte Arduino táblák, melyik arduino pin melyik port fizikailag, melyik PWM hova tartozik,...
- 50 byte avr-gcc libc
- 70 byte loop() függvény
- 30 byte setup() függvény
- 150 byte timer0 overflow interrupt
- 170 byte delay() függvény
- 210 byte belső init() függvény, ahol a timerek / PWM / ADC definiálva van
- 120 byte pinMode() függvény
- 170 byte digitalWrite() függvény
- 170 byte digitalRead() függvény
- 30 byte belső main() függvény,

Ebből a te munkád a loop+setup=100 byte, a maradék 1200 byte az Arduino framework indulásához kellett. Ezt egyszer kell az IC-be bevasalni, utána csak meghívni. A te kódod 100 byte-ra fordult le, ami egyáltalán nem tűnik durvának.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

Hozzászólás Szerző: csabeszq »

Az assembly, ha érdekel itt van (nem tudtam csatolni):

Kód: Egész kijelölése


/tmp/build352395802279720463.tmp/sketch_oct30a.cpp.elf:     file format elf32-avr

Disassembly of section .text:

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

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

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

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

00000086 <digital_pin_to_port_PGM>:
  86:	04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03     ................
  96:	03 03 03 03                                         ....

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

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

000000c2 <__ctors_end>:
  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 <__do_copy_data>:
  ce:	11 e0       	ldi	r17, 0x01	; 1
  d0:	a0 e0       	ldi	r26, 0x00	; 0
  d2:	b1 e0       	ldi	r27, 0x01	; 1
  d4:	e2 e1       	ldi	r30, 0x12	; 18
  d6:	f5 e0       	ldi	r31, 0x05	; 5
  d8:	02 c0       	rjmp	.+4      	; 0xde <.do_copy_data_start>

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

000000de <.do_copy_data_start>:
  de:	a2 30       	cpi	r26, 0x02	; 2
  e0:	b1 07       	cpc	r27, r17
  e2:	d9 f7       	brne	.-10     	; 0xda <.do_copy_data_loop>

000000e4 <__do_clear_bss>:
  e4:	11 e0       	ldi	r17, 0x01	; 1
  e6:	a2 e0       	ldi	r26, 0x02	; 2
  e8:	b1 e0       	ldi	r27, 0x01	; 1
  ea:	01 c0       	rjmp	.+2      	; 0xee <.do_clear_bss_start>

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

000000ee <.do_clear_bss_start>:
  ee:	ae 30       	cpi	r26, 0x0E	; 14
  f0:	b1 07       	cpc	r27, r17
  f2:	e1 f7       	brne	.-8      	; 0xec <.do_clear_bss_loop>
  f4:	0e 94 78 02 	call	0x4f0	; 0x4f0 <main>
  f8:	0c 94 87 02 	jmp	0x50e	; 0x50e <_exit>

000000fc <__bad_interrupt>:
  fc:	0c 94 00 00 	jmp	0	; 0x0 <__heap_end>

00000100 <loop>:
 100:	1f 93       	push	r17
 102:	80 91 00 01 	lds	r24, 0x0100
 106:	0e 94 25 02 	call	0x44a	; 0x44a <digitalRead>
 10a:	18 2f       	mov	r17, r24
 10c:	80 93 03 01 	sts	0x0103, r24
 110:	80 91 04 01 	lds	r24, 0x0104
 114:	88 23       	and	r24, r24
 116:	99 f4       	brne	.+38     	; 0x13e <loop+0x3e>
 118:	11 30       	cpi	r17, 0x01	; 1
 11a:	89 f4       	brne	.+34     	; 0x13e <loop+0x3e>
 11c:	60 91 02 01 	lds	r22, 0x0102
 120:	61 27       	eor	r22, r17
 122:	60 93 02 01 	sts	0x0102, r22
 126:	80 91 01 01 	lds	r24, 0x0101
 12a:	0e 94 d1 01 	call	0x3a2	; 0x3a2 <digitalWrite>
 12e:	64 e6       	ldi	r22, 0x64	; 100
 130:	70 e0       	ldi	r23, 0x00	; 0
 132:	80 e0       	ldi	r24, 0x00	; 0
 134:	90 e0       	ldi	r25, 0x00	; 0
 136:	0e 94 fe 00 	call	0x1fc	; 0x1fc <delay>
 13a:	10 93 04 01 	sts	0x0104, r17
 13e:	80 91 03 01 	lds	r24, 0x0103
 142:	88 23       	and	r24, r24
 144:	11 f4       	brne	.+4      	; 0x14a <loop+0x4a>
 146:	10 92 04 01 	sts	0x0104, r1
 14a:	1f 91       	pop	r17
 14c:	08 95       	ret

0000014e <setup>:
 14e:	80 91 00 01 	lds	r24, 0x0100
 152:	60 e0       	ldi	r22, 0x00	; 0
 154:	0e 94 92 01 	call	0x324	; 0x324 <pinMode>
 158:	80 91 01 01 	lds	r24, 0x0101
 15c:	61 e0       	ldi	r22, 0x01	; 1
 15e:	0e 94 92 01 	call	0x324	; 0x324 <pinMode>
 162:	10 92 02 01 	sts	0x0102, r1
 166:	10 92 04 01 	sts	0x0104, r1
 16a:	08 95       	ret

0000016c <__vector_16>:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
 16c:	1f 92       	push	r1
 16e:	0f 92       	push	r0
 170:	0f b6       	in	r0, 0x3f	; 63
 172:	0f 92       	push	r0
 174:	11 24       	eor	r1, r1
 176:	2f 93       	push	r18
 178:	3f 93       	push	r19
 17a:	8f 93       	push	r24
 17c:	9f 93       	push	r25
 17e:	af 93       	push	r26
 180:	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;
 182:	80 91 09 01 	lds	r24, 0x0109
 186:	90 91 0a 01 	lds	r25, 0x010A
 18a:	a0 91 0b 01 	lds	r26, 0x010B
 18e:	b0 91 0c 01 	lds	r27, 0x010C
	unsigned char f = timer0_fract;
 192:	30 91 0d 01 	lds	r19, 0x010D

	m += MILLIS_INC;
 196:	01 96       	adiw	r24, 0x01	; 1
 198:	a1 1d       	adc	r26, r1
 19a:	b1 1d       	adc	r27, r1
	f += FRACT_INC;
 19c:	23 2f       	mov	r18, r19
 19e:	2d 5f       	subi	r18, 0xFD	; 253
	if (f >= FRACT_MAX) {
 1a0:	2d 37       	cpi	r18, 0x7D	; 125
 1a2:	20 f0       	brcs	.+8      	; 0x1ac <__vector_16+0x40>
		f -= FRACT_MAX;
 1a4:	2d 57       	subi	r18, 0x7D	; 125
		m += 1;
 1a6:	01 96       	adiw	r24, 0x01	; 1
 1a8:	a1 1d       	adc	r26, r1
 1aa:	b1 1d       	adc	r27, r1
	}

	timer0_fract = f;
 1ac:	20 93 0d 01 	sts	0x010D, r18
	timer0_millis = m;
 1b0:	80 93 09 01 	sts	0x0109, r24
 1b4:	90 93 0a 01 	sts	0x010A, r25
 1b8:	a0 93 0b 01 	sts	0x010B, r26
 1bc:	b0 93 0c 01 	sts	0x010C, r27
	timer0_overflow_count++;
 1c0:	80 91 05 01 	lds	r24, 0x0105
 1c4:	90 91 06 01 	lds	r25, 0x0106
 1c8:	a0 91 07 01 	lds	r26, 0x0107
 1cc:	b0 91 08 01 	lds	r27, 0x0108
 1d0:	01 96       	adiw	r24, 0x01	; 1
 1d2:	a1 1d       	adc	r26, r1
 1d4:	b1 1d       	adc	r27, r1
 1d6:	80 93 05 01 	sts	0x0105, r24
 1da:	90 93 06 01 	sts	0x0106, r25
 1de:	a0 93 07 01 	sts	0x0107, r26
 1e2:	b0 93 08 01 	sts	0x0108, r27
}
 1e6:	bf 91       	pop	r27
 1e8:	af 91       	pop	r26
 1ea:	9f 91       	pop	r25
 1ec:	8f 91       	pop	r24
 1ee:	3f 91       	pop	r19
 1f0:	2f 91       	pop	r18
 1f2:	0f 90       	pop	r0
 1f4:	0f be       	out	0x3f, r0	; 63
 1f6:	0f 90       	pop	r0
 1f8:	1f 90       	pop	r1
 1fa:	18 95       	reti

000001fc <delay>:
	
	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

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

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
 200:	7f b7       	in	r23, 0x3f	; 63
	
	cli();
 202:	f8 94       	cli
	m = timer0_overflow_count;
 204:	80 91 05 01 	lds	r24, 0x0105
 208:	90 91 06 01 	lds	r25, 0x0106
 20c:	a0 91 07 01 	lds	r26, 0x0107
 210:	b0 91 08 01 	lds	r27, 0x0108
#if defined(TCNT0)
	t = TCNT0;
 214:	66 b5       	in	r22, 0x26	; 38
	#error TIMER 0 not defined
#endif

  
#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
 216:	a8 9b       	sbis	0x15, 0	; 21
 218:	05 c0       	rjmp	.+10     	; 0x224 <delay+0x28>
 21a:	6f 3f       	cpi	r22, 0xFF	; 255
 21c:	19 f0       	breq	.+6      	; 0x224 <delay+0x28>
		m++;
 21e:	01 96       	adiw	r24, 0x01	; 1
 220:	a1 1d       	adc	r26, r1
 222:	b1 1d       	adc	r27, r1
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif

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

void delay(unsigned long ms)
{
	uint16_t start = (uint16_t)micros();
 226:	ba 2f       	mov	r27, r26
 228:	a9 2f       	mov	r26, r25
 22a:	98 2f       	mov	r25, r24
 22c:	88 27       	eor	r24, r24
 22e:	86 0f       	add	r24, r22
 230:	91 1d       	adc	r25, r1
 232:	a1 1d       	adc	r26, r1
 234:	b1 1d       	adc	r27, r1
 236:	62 e0       	ldi	r22, 0x02	; 2
 238:	88 0f       	add	r24, r24
 23a:	99 1f       	adc	r25, r25
 23c:	aa 1f       	adc	r26, r26
 23e:	bb 1f       	adc	r27, r27
 240:	6a 95       	dec	r22
 242:	d1 f7       	brne	.-12     	; 0x238 <delay+0x3c>
 244:	bc 01       	movw	r22, r24
 246:	2d c0       	rjmp	.+90     	; 0x2a2 <delay+0xa6>
	return m;
}

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
 248:	ff b7       	in	r31, 0x3f	; 63
	
	cli();
 24a:	f8 94       	cli
	m = timer0_overflow_count;
 24c:	80 91 05 01 	lds	r24, 0x0105
 250:	90 91 06 01 	lds	r25, 0x0106
 254:	a0 91 07 01 	lds	r26, 0x0107
 258:	b0 91 08 01 	lds	r27, 0x0108
#if defined(TCNT0)
	t = TCNT0;
 25c:	e6 b5       	in	r30, 0x26	; 38
	#error TIMER 0 not defined
#endif

  
#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
 25e:	a8 9b       	sbis	0x15, 0	; 21
 260:	05 c0       	rjmp	.+10     	; 0x26c <delay+0x70>
 262:	ef 3f       	cpi	r30, 0xFF	; 255
 264:	19 f0       	breq	.+6      	; 0x26c <delay+0x70>
		m++;
 266:	01 96       	adiw	r24, 0x01	; 1
 268:	a1 1d       	adc	r26, r1
 26a:	b1 1d       	adc	r27, r1
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif

	SREG = oldSREG;
 26c:	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) {
 26e:	ba 2f       	mov	r27, r26
 270:	a9 2f       	mov	r26, r25
 272:	98 2f       	mov	r25, r24
 274:	88 27       	eor	r24, r24
 276:	8e 0f       	add	r24, r30
 278:	91 1d       	adc	r25, r1
 27a:	a1 1d       	adc	r26, r1
 27c:	b1 1d       	adc	r27, r1
 27e:	e2 e0       	ldi	r30, 0x02	; 2
 280:	88 0f       	add	r24, r24
 282:	99 1f       	adc	r25, r25
 284:	aa 1f       	adc	r26, r26
 286:	bb 1f       	adc	r27, r27
 288:	ea 95       	dec	r30
 28a:	d1 f7       	brne	.-12     	; 0x280 <delay+0x84>
 28c:	86 1b       	sub	r24, r22
 28e:	97 0b       	sbc	r25, r23
 290:	88 5e       	subi	r24, 0xE8	; 232
 292:	93 40       	sbci	r25, 0x03	; 3
 294:	c8 f2       	brcs	.-78     	; 0x248 <delay+0x4c>
			ms--;
 296:	21 50       	subi	r18, 0x01	; 1
 298:	30 40       	sbci	r19, 0x00	; 0
 29a:	40 40       	sbci	r20, 0x00	; 0
 29c:	50 40       	sbci	r21, 0x00	; 0
			start += 1000;
 29e:	68 51       	subi	r22, 0x18	; 24
 2a0:	7c 4f       	sbci	r23, 0xFC	; 252

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

	while (ms > 0) {
 2a2:	21 15       	cp	r18, r1
 2a4:	31 05       	cpc	r19, r1
 2a6:	41 05       	cpc	r20, r1
 2a8:	51 05       	cpc	r21, r1
 2aa:	71 f6       	brne	.-100    	; 0x248 <delay+0x4c>
		if (((uint16_t)micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}
 2ac:	08 95       	ret

000002ae <init>:

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
 2ae:	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);
 2b0:	84 b5       	in	r24, 0x24	; 36
 2b2:	82 60       	ori	r24, 0x02	; 2
 2b4:	84 bd       	out	0x24, r24	; 36
	sbi(TCCR0A, WGM00);
 2b6:	84 b5       	in	r24, 0x24	; 36
 2b8:	81 60       	ori	r24, 0x01	; 1
 2ba:	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);
 2bc:	85 b5       	in	r24, 0x25	; 37
 2be:	82 60       	ori	r24, 0x02	; 2
 2c0:	85 bd       	out	0x25, r24	; 37
	sbi(TCCR0B, CS00);
 2c2:	85 b5       	in	r24, 0x25	; 37
 2c4:	81 60       	ori	r24, 0x01	; 1
 2c6:	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);
 2c8:	ee e6       	ldi	r30, 0x6E	; 110
 2ca:	f0 e0       	ldi	r31, 0x00	; 0
 2cc:	80 81       	ld	r24, Z
 2ce:	81 60       	ori	r24, 0x01	; 1
 2d0:	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;
 2d2:	e1 e8       	ldi	r30, 0x81	; 129
 2d4:	f0 e0       	ldi	r31, 0x00	; 0
 2d6:	10 82       	st	Z, r1

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
 2d8:	80 81       	ld	r24, Z
 2da:	82 60       	ori	r24, 0x02	; 2
 2dc:	80 83       	st	Z, r24
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
 2de:	80 81       	ld	r24, Z
 2e0:	81 60       	ori	r24, 0x01	; 1
 2e2:	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);
 2e4:	e0 e8       	ldi	r30, 0x80	; 128
 2e6:	f0 e0       	ldi	r31, 0x00	; 0
 2e8:	80 81       	ld	r24, Z
 2ea:	81 60       	ori	r24, 0x01	; 1
 2ec:	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);
 2ee:	e1 eb       	ldi	r30, 0xB1	; 177
 2f0:	f0 e0       	ldi	r31, 0x00	; 0
 2f2:	80 81       	ld	r24, Z
 2f4:	84 60       	ori	r24, 0x04	; 4
 2f6:	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);
 2f8:	e0 eb       	ldi	r30, 0xB0	; 176
 2fa:	f0 e0       	ldi	r31, 0x00	; 0
 2fc:	80 81       	ld	r24, Z
 2fe:	81 60       	ori	r24, 0x01	; 1
 300:	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);
 302:	ea e7       	ldi	r30, 0x7A	; 122
 304:	f0 e0       	ldi	r31, 0x00	; 0
 306:	80 81       	ld	r24, Z
 308:	84 60       	ori	r24, 0x04	; 4
 30a:	80 83       	st	Z, r24
	sbi(ADCSRA, ADPS1);
 30c:	80 81       	ld	r24, Z
 30e:	82 60       	ori	r24, 0x02	; 2
 310:	80 83       	st	Z, r24
	sbi(ADCSRA, ADPS0);
 312:	80 81       	ld	r24, Z
 314:	81 60       	ori	r24, 0x01	; 1
 316:	80 83       	st	Z, r24

	// enable a2d conversions
	sbi(ADCSRA, ADEN);
 318:	80 81       	ld	r24, Z
 31a:	80 68       	ori	r24, 0x80	; 128
 31c:	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;
 31e:	10 92 c1 00 	sts	0x00C1, r1
#endif
}
 322:	08 95       	ret

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

void pinMode(uint8_t pin, uint8_t mode)
{
 324:	cf 93       	push	r28
 326:	df 93       	push	r29
	uint8_t bit = digitalPinToBitMask(pin);
 328:	48 2f       	mov	r20, r24
 32a:	50 e0       	ldi	r21, 0x00	; 0
 32c:	ca 01       	movw	r24, r20
 32e:	86 56       	subi	r24, 0x66	; 102
 330:	9f 4f       	sbci	r25, 0xFF	; 255
 332:	fc 01       	movw	r30, r24
 334:	34 91       	lpm	r19, Z+
	uint8_t port = digitalPinToPort(pin);
 336:	4a 57       	subi	r20, 0x7A	; 122
 338:	5f 4f       	sbci	r21, 0xFF	; 255
 33a:	fa 01       	movw	r30, r20
 33c:	84 91       	lpm	r24, Z+
	volatile uint8_t *reg, *out;

	if (port == NOT_A_PIN) return;
 33e:	88 23       	and	r24, r24
 340:	69 f1       	breq	.+90     	; 0x39c <pinMode+0x78>

	// JWS: can I let the optimizer do this?
	reg = portModeRegister(port);
 342:	90 e0       	ldi	r25, 0x00	; 0
 344:	88 0f       	add	r24, r24
 346:	99 1f       	adc	r25, r25
 348:	fc 01       	movw	r30, r24
 34a:	e8 59       	subi	r30, 0x98	; 152
 34c:	ff 4f       	sbci	r31, 0xFF	; 255
 34e:	a5 91       	lpm	r26, Z+
 350:	b4 91       	lpm	r27, Z+
	out = portOutputRegister(port);
 352:	fc 01       	movw	r30, r24
 354:	ee 58       	subi	r30, 0x8E	; 142
 356:	ff 4f       	sbci	r31, 0xFF	; 255
 358:	c5 91       	lpm	r28, Z+
 35a:	d4 91       	lpm	r29, Z+

	if (mode == INPUT) { 
 35c:	66 23       	and	r22, r22
 35e:	51 f4       	brne	.+20     	; 0x374 <pinMode+0x50>
		uint8_t oldSREG = SREG;
 360:	2f b7       	in	r18, 0x3f	; 63
                cli();
 362:	f8 94       	cli
		*reg &= ~bit;
 364:	8c 91       	ld	r24, X
 366:	93 2f       	mov	r25, r19
 368:	90 95       	com	r25
 36a:	89 23       	and	r24, r25
 36c:	8c 93       	st	X, r24
		*out &= ~bit;
 36e:	88 81       	ld	r24, Y
 370:	89 23       	and	r24, r25
 372:	0b c0       	rjmp	.+22     	; 0x38a <pinMode+0x66>
		SREG = oldSREG;
	} else if (mode == INPUT_PULLUP) {
 374:	62 30       	cpi	r22, 0x02	; 2
 376:	61 f4       	brne	.+24     	; 0x390 <pinMode+0x6c>
		uint8_t oldSREG = SREG;
 378:	2f b7       	in	r18, 0x3f	; 63
                cli();
 37a:	f8 94       	cli
		*reg &= ~bit;
 37c:	8c 91       	ld	r24, X
 37e:	93 2f       	mov	r25, r19
 380:	90 95       	com	r25
 382:	89 23       	and	r24, r25
 384:	8c 93       	st	X, r24
		*out |= bit;
 386:	88 81       	ld	r24, Y
 388:	83 2b       	or	r24, r19
 38a:	88 83       	st	Y, r24
		SREG = oldSREG;
 38c:	2f bf       	out	0x3f, r18	; 63
 38e:	06 c0       	rjmp	.+12     	; 0x39c <pinMode+0x78>
	} else {
		uint8_t oldSREG = SREG;
 390:	9f b7       	in	r25, 0x3f	; 63
                cli();
 392:	f8 94       	cli
		*reg |= bit;
 394:	8c 91       	ld	r24, X
 396:	83 2b       	or	r24, r19
 398:	8c 93       	st	X, r24
		SREG = oldSREG;
 39a:	9f bf       	out	0x3f, r25	; 63
	}
}
 39c:	df 91       	pop	r29
 39e:	cf 91       	pop	r28
 3a0:	08 95       	ret

000003a2 <digitalWrite>:
	}
}

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
 3a2:	48 2f       	mov	r20, r24
 3a4:	50 e0       	ldi	r21, 0x00	; 0
 3a6:	ca 01       	movw	r24, r20
 3a8:	82 55       	subi	r24, 0x52	; 82
 3aa:	9f 4f       	sbci	r25, 0xFF	; 255
 3ac:	fc 01       	movw	r30, r24
 3ae:	24 91       	lpm	r18, Z+
	uint8_t bit = digitalPinToBitMask(pin);
 3b0:	ca 01       	movw	r24, r20
 3b2:	86 56       	subi	r24, 0x66	; 102
 3b4:	9f 4f       	sbci	r25, 0xFF	; 255
 3b6:	fc 01       	movw	r30, r24
 3b8:	94 91       	lpm	r25, Z+
	uint8_t port = digitalPinToPort(pin);
 3ba:	4a 57       	subi	r20, 0x7A	; 122
 3bc:	5f 4f       	sbci	r21, 0xFF	; 255
 3be:	fa 01       	movw	r30, r20
 3c0:	34 91       	lpm	r19, Z+
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;
 3c2:	33 23       	and	r19, r19
 3c4:	09 f4       	brne	.+2      	; 0x3c8 <digitalWrite+0x26>
 3c6:	40 c0       	rjmp	.+128    	; 0x448 <digitalWrite+0xa6>

	// 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);
 3c8:	22 23       	and	r18, r18
 3ca:	51 f1       	breq	.+84     	; 0x420 <digitalWrite+0x7e>
//
//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)
 3cc:	23 30       	cpi	r18, 0x03	; 3
 3ce:	71 f0       	breq	.+28     	; 0x3ec <digitalWrite+0x4a>
 3d0:	24 30       	cpi	r18, 0x04	; 4
 3d2:	28 f4       	brcc	.+10     	; 0x3de <digitalWrite+0x3c>
 3d4:	21 30       	cpi	r18, 0x01	; 1
 3d6:	a1 f0       	breq	.+40     	; 0x400 <digitalWrite+0x5e>
 3d8:	22 30       	cpi	r18, 0x02	; 2
 3da:	11 f5       	brne	.+68     	; 0x420 <digitalWrite+0x7e>
 3dc:	14 c0       	rjmp	.+40     	; 0x406 <digitalWrite+0x64>
 3de:	26 30       	cpi	r18, 0x06	; 6
 3e0:	b1 f0       	breq	.+44     	; 0x40e <digitalWrite+0x6c>
 3e2:	27 30       	cpi	r18, 0x07	; 7
 3e4:	c1 f0       	breq	.+48     	; 0x416 <digitalWrite+0x74>
 3e6:	24 30       	cpi	r18, 0x04	; 4
 3e8:	d9 f4       	brne	.+54     	; 0x420 <digitalWrite+0x7e>
 3ea:	04 c0       	rjmp	.+8      	; 0x3f4 <digitalWrite+0x52>
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
 3ec:	80 91 80 00 	lds	r24, 0x0080
 3f0:	8f 77       	andi	r24, 0x7F	; 127
 3f2:	03 c0       	rjmp	.+6      	; 0x3fa <digitalWrite+0x58>
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 3f4:	80 91 80 00 	lds	r24, 0x0080
 3f8:	8f 7d       	andi	r24, 0xDF	; 223
 3fa:	80 93 80 00 	sts	0x0080, r24
 3fe:	10 c0       	rjmp	.+32     	; 0x420 <digitalWrite+0x7e>
		#if defined(TCCR2) && defined(COM21)
		case  TIMER2:   cbi(TCCR2, COM21);      break;
		#endif
		
		#if defined(TCCR0A) && defined(COM0A1)
		case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
 400:	84 b5       	in	r24, 0x24	; 36
 402:	8f 77       	andi	r24, 0x7F	; 127
 404:	02 c0       	rjmp	.+4      	; 0x40a <digitalWrite+0x68>
		#endif
		
		#if defined(TIMER0B) && defined(COM0B1)
		case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
 406:	84 b5       	in	r24, 0x24	; 36
 408:	8f 7d       	andi	r24, 0xDF	; 223
 40a:	84 bd       	out	0x24, r24	; 36
 40c:	09 c0       	rjmp	.+18     	; 0x420 <digitalWrite+0x7e>
		#endif
		#if defined(TCCR2A) && defined(COM2A1)
		case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
 40e:	80 91 b0 00 	lds	r24, 0x00B0
 412:	8f 77       	andi	r24, 0x7F	; 127
 414:	03 c0       	rjmp	.+6      	; 0x41c <digitalWrite+0x7a>
		#endif
		#if defined(TCCR2A) && defined(COM2B1)
		case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
 416:	80 91 b0 00 	lds	r24, 0x00B0
 41a:	8f 7d       	andi	r24, 0xDF	; 223
 41c:	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);
 420:	e3 2f       	mov	r30, r19
 422:	f0 e0       	ldi	r31, 0x00	; 0
 424:	ee 0f       	add	r30, r30
 426:	ff 1f       	adc	r31, r31
 428:	ee 58       	subi	r30, 0x8E	; 142
 42a:	ff 4f       	sbci	r31, 0xFF	; 255
 42c:	a5 91       	lpm	r26, Z+
 42e:	b4 91       	lpm	r27, Z+

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

	if (val == LOW) {
 434:	66 23       	and	r22, r22
 436:	21 f4       	brne	.+8      	; 0x440 <digitalWrite+0x9e>
		*out &= ~bit;
 438:	8c 91       	ld	r24, X
 43a:	90 95       	com	r25
 43c:	89 23       	and	r24, r25
 43e:	02 c0       	rjmp	.+4      	; 0x444 <digitalWrite+0xa2>
	} else {
		*out |= bit;
 440:	8c 91       	ld	r24, X
 442:	89 2b       	or	r24, r25
 444:	8c 93       	st	X, r24
	}

	SREG = oldSREG;
 446:	2f bf       	out	0x3f, r18	; 63
 448:	08 95       	ret

0000044a <digitalRead>:
}

int digitalRead(uint8_t pin)
{
	uint8_t timer = digitalPinToTimer(pin);
 44a:	68 2f       	mov	r22, r24
 44c:	70 e0       	ldi	r23, 0x00	; 0
 44e:	cb 01       	movw	r24, r22
 450:	82 55       	subi	r24, 0x52	; 82
 452:	9f 4f       	sbci	r25, 0xFF	; 255
 454:	fc 01       	movw	r30, r24
 456:	24 91       	lpm	r18, Z+
	uint8_t bit = digitalPinToBitMask(pin);
 458:	cb 01       	movw	r24, r22
 45a:	86 56       	subi	r24, 0x66	; 102
 45c:	9f 4f       	sbci	r25, 0xFF	; 255
 45e:	fc 01       	movw	r30, r24
 460:	44 91       	lpm	r20, Z+
	uint8_t port = digitalPinToPort(pin);
 462:	6a 57       	subi	r22, 0x7A	; 122
 464:	7f 4f       	sbci	r23, 0xFF	; 255
 466:	fb 01       	movw	r30, r22
 468:	94 91       	lpm	r25, Z+

	if (port == NOT_A_PIN) return LOW;
 46a:	99 23       	and	r25, r25
 46c:	19 f4       	brne	.+6      	; 0x474 <digitalRead+0x2a>
 46e:	20 e0       	ldi	r18, 0x00	; 0
 470:	30 e0       	ldi	r19, 0x00	; 0
 472:	3c c0       	rjmp	.+120    	; 0x4ec <digitalRead+0xa2>

	// If the pin that support PWM output, we need to turn it off
	// before getting a digital reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
 474:	22 23       	and	r18, r18
 476:	51 f1       	breq	.+84     	; 0x4cc <digitalRead+0x82>
//
//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)
 478:	23 30       	cpi	r18, 0x03	; 3
 47a:	71 f0       	breq	.+28     	; 0x498 <digitalRead+0x4e>
 47c:	24 30       	cpi	r18, 0x04	; 4
 47e:	28 f4       	brcc	.+10     	; 0x48a <digitalRead+0x40>
 480:	21 30       	cpi	r18, 0x01	; 1
 482:	a1 f0       	breq	.+40     	; 0x4ac <digitalRead+0x62>
 484:	22 30       	cpi	r18, 0x02	; 2
 486:	11 f5       	brne	.+68     	; 0x4cc <digitalRead+0x82>
 488:	14 c0       	rjmp	.+40     	; 0x4b2 <digitalRead+0x68>
 48a:	26 30       	cpi	r18, 0x06	; 6
 48c:	b1 f0       	breq	.+44     	; 0x4ba <digitalRead+0x70>
 48e:	27 30       	cpi	r18, 0x07	; 7
 490:	c1 f0       	breq	.+48     	; 0x4c2 <digitalRead+0x78>
 492:	24 30       	cpi	r18, 0x04	; 4
 494:	d9 f4       	brne	.+54     	; 0x4cc <digitalRead+0x82>
 496:	04 c0       	rjmp	.+8      	; 0x4a0 <digitalRead+0x56>
	{
		#if defined(TCCR1A) && defined(COM1A1)
		case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
 498:	80 91 80 00 	lds	r24, 0x0080
 49c:	8f 77       	andi	r24, 0x7F	; 127
 49e:	03 c0       	rjmp	.+6      	; 0x4a6 <digitalRead+0x5c>
		#endif
		#if defined(TCCR1A) && defined(COM1B1)
		case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
 4a0:	80 91 80 00 	lds	r24, 0x0080
 4a4:	8f 7d       	andi	r24, 0xDF	; 223
 4a6:	80 93 80 00 	sts	0x0080, r24
 4aa:	10 c0       	rjmp	.+32     	; 0x4cc <digitalRead+0x82>
		#if defined(TCCR2) && defined(COM21)
		case  TIMER2:   cbi(TCCR2, COM21);      break;
		#endif
		
		#if defined(TCCR0A) && defined(COM0A1)
		case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
 4ac:	84 b5       	in	r24, 0x24	; 36
 4ae:	8f 77       	andi	r24, 0x7F	; 127
 4b0:	02 c0       	rjmp	.+4      	; 0x4b6 <digitalRead+0x6c>
		#endif
		
		#if defined(TIMER0B) && defined(COM0B1)
		case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
 4b2:	84 b5       	in	r24, 0x24	; 36
 4b4:	8f 7d       	andi	r24, 0xDF	; 223
 4b6:	84 bd       	out	0x24, r24	; 36
 4b8:	09 c0       	rjmp	.+18     	; 0x4cc <digitalRead+0x82>
		#endif
		#if defined(TCCR2A) && defined(COM2A1)
		case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
 4ba:	80 91 b0 00 	lds	r24, 0x00B0
 4be:	8f 77       	andi	r24, 0x7F	; 127
 4c0:	03 c0       	rjmp	.+6      	; 0x4c8 <digitalRead+0x7e>
		#endif
		#if defined(TCCR2A) && defined(COM2B1)
		case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
 4c2:	80 91 b0 00 	lds	r24, 0x00B0
 4c6:	8f 7d       	andi	r24, 0xDF	; 223
 4c8:	80 93 b0 00 	sts	0x00B0, r24

	// If the pin that support PWM output, we need to turn it off
	// before getting a digital reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	if (*portInputRegister(port) & bit) return HIGH;
 4cc:	89 2f       	mov	r24, r25
 4ce:	90 e0       	ldi	r25, 0x00	; 0
 4d0:	88 0f       	add	r24, r24
 4d2:	99 1f       	adc	r25, r25
 4d4:	84 58       	subi	r24, 0x84	; 132
 4d6:	9f 4f       	sbci	r25, 0xFF	; 255
 4d8:	fc 01       	movw	r30, r24
 4da:	a5 91       	lpm	r26, Z+
 4dc:	b4 91       	lpm	r27, Z+
 4de:	8c 91       	ld	r24, X
 4e0:	20 e0       	ldi	r18, 0x00	; 0
 4e2:	30 e0       	ldi	r19, 0x00	; 0
 4e4:	84 23       	and	r24, r20
 4e6:	11 f0       	breq	.+4      	; 0x4ec <digitalRead+0xa2>
 4e8:	21 e0       	ldi	r18, 0x01	; 1
 4ea:	30 e0       	ldi	r19, 0x00	; 0
	return LOW;
}
 4ec:	c9 01       	movw	r24, r18
 4ee:	08 95       	ret

000004f0 <main>:
#include <Arduino.h>

int main(void)
 4f0:	cf 93       	push	r28
 4f2:	df 93       	push	r29
{
	init();
 4f4:	0e 94 57 01 	call	0x2ae	; 0x2ae <init>

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
 4f8:	0e 94 a7 00 	call	0x14e	; 0x14e <setup>
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
 4fc:	c0 e0       	ldi	r28, 0x00	; 0
 4fe:	d0 e0       	ldi	r29, 0x00	; 0
#endif
	
	setup();
    
	for (;;) {
		loop();
 500:	0e 94 80 00 	call	0x100	; 0x100 <loop>
		if (serialEventRun) serialEventRun();
 504:	20 97       	sbiw	r28, 0x00	; 0
 506:	e1 f3       	breq	.-8      	; 0x500 <main+0x10>
 508:	0e 94 00 00 	call	0	; 0x0 <__heap_end>
 50c:	f9 cf       	rjmp	.-14     	; 0x500 <main+0x10>

0000050e <_exit>:
 50e:	f8 94       	cli

00000510 <__stop_program>:
 510:	ff cf       	rjmp	.-2      	; 0x510 <__stop_program>
holex
Biztosítékgyilkos
Hozzászólások: 70
Csatlakozott: 2013. október 29. kedd, 1:35

Re: AVR assembly

Hozzászólás Szerző: holex »

"Az Arduinot olyan lazán leszólod. De csak nézz bele: Jéééé, belül C és a hozzávaló GCC fordító "

Nem volt célom leszólni az Arduinot, csak a tanfolyamon most vagyok túl a megszakításos anyagon és abban ugye írtad, hogy csak 2 láb használható megszakításra az Arduinoban, holott egyébként a hardverben adottak a lehetőségek arra, hogy az összes láb megszakítást generáljon, és nem értem, hogy akkor ez miért nem került be az Arduinoba. Ha valami olyanra szeretné alkalmazni az ember, ahol mondjuk van 5-6 gomb, meg 1-2 végálláskapcsoló stb (ez nem olyan elvetemült ötlet szerintem), akkor nem tud mást tenni a program, minthogy mindig mindegyiknek ellenőrzi az állapotát, ahelyett, hogy mindegyiket bekötném egy külön lábra, külön megszakítási rutinokat írnék hozzá, ami akkor fut le, ha az adott lábon megváltozott a jelszint.
Válasz küldése