AVR assembly
AVR assembly
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?
Re: AVR assembly
É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:
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))
);
Re: AVR assembly
É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?
Re: AVR assembly
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...
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...
Re: AVR assembly
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:
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.
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");
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.
Re: AVR assembly
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...
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...
Re: AVR assembly
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.
Re: AVR assembly
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.
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.
Re: AVR assembly
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...
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.)
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...
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.)
Re: AVR assembly
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.
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.
Re: AVR assembly
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.
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.
Re: AVR assembly
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.
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).
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.
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).
Re: AVR assembly
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.
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.
Re: AVR assembly
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>
Re: AVR assembly
"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.
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.