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ásSzerző: holex » 2013. október 29. kedd, 1:40

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 8:06

É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ásSzerző: holex » 2013. október 29. kedd, 8:25

É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: 9793
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

HozzászólásSzerző: Robert » 2013. október 29. kedd, 10:52

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 11:00

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: 9793
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

HozzászólásSzerző: Robert » 2013. október 29. kedd, 11:57

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ásSzerző: holex » 2013. október 29. kedd, 12:01

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 12:35

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: 9793
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: AVR assembly

HozzászólásSzerző: Robert » 2013. október 29. kedd, 14:42

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
Kapcsolat:

Re: AVR assembly

HozzászólásSzerző: irak » 2013. október 29. kedd, 16:36

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 16:48

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
Kapcsolat:

Re: AVR assembly

HozzászólásSzerző: irak » 2013. október 29. kedd, 18:37

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 23:44

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: 662
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: AVR assembly

HozzászólásSzerző: csabeszq » 2013. október 29. kedd, 23:52

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ásSzerző: holex » 2013. október 30. szerda, 11:56

"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.


Vissza: “Oktatás”

Ki van itt

Jelenlévő fórumozók: Bing [Bot] valamint 1 vendég