Problem med arduino - begriper inte timingen....
Problem med arduino - begriper inte timingen....
Det är antagligen något gravt fel i mitt huvud, min arduino eller mitt oscilloskop - eventuellt i alla tre.
Efter att ha felsökt, fram och åter, min kod i två dagar utan att bli annat än förvirrad så har jag förenklat i omgångar för att se vad sjutton som händer.
När jag är nere i koden:
...
digitalWrite(outPin, HIGH);
delayMicroseconds(312);
digitalWrite(outPin, LOW);
...
Så får jag en puls som enligt mitt skåp är 427uS lång.
Jag bryter ihop.
(Nej, inga IRQ används)
Efter att ha felsökt, fram och åter, min kod i två dagar utan att bli annat än förvirrad så har jag förenklat i omgångar för att se vad sjutton som händer.
När jag är nere i koden:
...
digitalWrite(outPin, HIGH);
delayMicroseconds(312);
digitalWrite(outPin, LOW);
...
Så får jag en puls som enligt mitt skåp är 427uS lång.
Jag bryter ihop.
(Nej, inga IRQ används)
Re: Problem med arduino - begriper inte timingen....
Funktionsanropen kanske tar X microsekunder.
Re: Problem med arduino - begriper inte timingen....
En första gissning vore ju att det är 427-312 = 115 us overhead
i koden som utför kommandona. Men det låter lite mycket.
Nästa gisning är att processorn körs i en annan hastighet än
vad utvecklingsmiljön tror. Processorn i sig har ju inte en aning
om vilken hastighet den körs i.
Kör utan delayMicroseconds() för att mäta overhead i digitalWrite().
Kör med 2 st delayMicroseconds(156) för att mäta overhead i delayMicroseconds().
i koden som utför kommandona. Men det låter lite mycket.
Nästa gisning är att processorn körs i en annan hastighet än
vad utvecklingsmiljön tror. Processorn i sig har ju inte en aning
om vilken hastighet den körs i.
Kör utan delayMicroseconds() för att mäta overhead i digitalWrite().
Kör med 2 st delayMicroseconds(156) för att mäta overhead i delayMicroseconds().
- MicaelKarlsson
- Inlägg: 4669
- Blev medlem: 18 juni 2004, 09:16:07
- Ort: Aneby
- Kontakt:
Re: Problem med arduino - begriper inte timingen....
Denna sida kan nog skingra dina funderingar: http://billgrundmann.wordpress.com/2009 ... tedigital/
Hoppas jag!
Hoppas jag!

Re: Problem med arduino - begriper inte timingen....
Jo, förrutom att den uppmätta overheaden är 3-4 us, inte över 100 us.
Men visst är det en viss skillnad på 50-55 cykler mot 2 cykler...
Men visst är det en viss skillnad på 50-55 cykler mot 2 cykler...

- Krille Krokodil
- Inlägg: 4062
- Blev medlem: 9 december 2005, 22:33:11
- Ort: Helsingborg
Re: Problem med arduino - begriper inte timingen....
Det står väl i manualen, har jag för mig, att delayMicroseconds är en pseudo-us-delay funktion, dvs den kan användas för att ge delay kortare än 1 ms men där är inga garantier på exakthet. På Aurduino ligger där tex en systemklocka på interrupt som kan gå in mitt i delayloopen...
Vill du ha exakt timing på us så programmera med GCC, där har du kontroll över varje bit, byte och klockcykel.
Vill du ha exakt timing på us så programmera med GCC, där har du kontroll över varje bit, byte och klockcykel.
Re: Problem med arduino - begriper inte timingen....
Tack för svar.
Lärdom: Är det tidskritiskt använd lågnivåspråk.
Att det skulle bli en viss overhead förstod jag men att den var så stor, det var en obehaglig överraskning.
Nu har jag inte forskat så mycket i exakt hur stor overheaden är, mina första stapplande försök (som att lägga två lika stora delay efter varandra) genomskådades uppenbarligen av kompilatorn och slopades.
Jag tycker inte att referensdokumentationen är så tydlig på exekveringstiderna. Det enda jag har sett är en varning på analogRead() men annars inget.
Lärdom: Är det tidskritiskt använd lågnivåspråk.
Att det skulle bli en viss overhead förstod jag men att den var så stor, det var en obehaglig överraskning.
Nu har jag inte forskat så mycket i exakt hur stor overheaden är, mina första stapplande försök (som att lägga två lika stora delay efter varandra) genomskådades uppenbarligen av kompilatorn och slopades.
Jag tycker inte att referensdokumentationen är så tydlig på exekveringstiderna. Det enda jag har sett är en varning på analogRead() men annars inget.
Re: Problem med arduino - begriper inte timingen....
Kontrollera assemblerkoden som genereras, det vore intressant att veta vad det är som händer egentligen.
Re: Problem med arduino - begriper inte timingen....
Gjorde ett litet snabbt test med Arduino IDE 1.0.1:
Källkod:
Genererad assemblerkod:
Har inte hunnit kika så noga men man ser en del overhead på digitalWrite() (2e2: och framåt) samt att timinginterruptet kan stöka till det ..
Källkod:
Kod: Markera allt
#define outPin 13
void setup() {
// put your setup code here, to run once:
pinMode(outPin, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(outPin, HIGH);
delayMicroseconds(312);
digitalWrite(outPin, LOW);
}
Genererad assemblerkod:
Kod: Markera allt
/tmp/build8043867660794877832.tmp/test_ef_.cpp.elf: file format elf32-avr
Disassembly of section .text:
00000000 <__vectors>:
0: 0c 94 5c 00 jmp 0xb8 ; 0xb8 <__ctors_end>
4: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
8: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
10: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
14: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
18: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
1c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
20: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
24: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
28: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
2c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
30: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
34: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
38: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
3c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
40: 0c 94 80 00 jmp 0x100 ; 0x100 <__vector_16>
44: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
48: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
4c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
50: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
54: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
58: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
5c: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
60: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
64: 0c 94 6e 00 jmp 0xdc ; 0xdc <__bad_interrupt>
00000068 <digital_pin_to_timer_PGM>:
68: 00 00 00 07 00 02 01 00 00 03 04 06 00 00 00 00 ................
78: 00 00 00 00 ....
0000007c <digital_pin_to_bit_mask_PGM>:
7c: 01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02 ..... @...... ..
8c: 04 08 10 20 ...
00000090 <digital_pin_to_port_PGM>:
90: 04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03 ................
a0: 03 03 03 03 ....
000000a4 <port_to_output_PGM>:
a4: 00 00 00 00 25 00 28 00 2b 00 ....%.(.+.
000000ae <port_to_mode_PGM>:
ae: 00 00 00 00 24 00 27 00 2a 00 ....$.'.*.
000000b8 <__ctors_end>:
b8: 11 24 eor r1, r1
ba: 1f be out 0x3f, r1 ; 63
bc: cf ef ldi r28, 0xFF ; 255
be: d8 e0 ldi r29, 0x08 ; 8
c0: de bf out 0x3e, r29 ; 62
c2: cd bf out 0x3d, r28 ; 61
000000c4 <__do_clear_bss>:
c4: 11 e0 ldi r17, 0x01 ; 1
c6: a0 e0 ldi r26, 0x00 ; 0
c8: b1 e0 ldi r27, 0x01 ; 1
ca: 01 c0 rjmp .+2 ; 0xce <.do_clear_bss_start>
000000cc <.do_clear_bss_loop>:
cc: 1d 92 st X+, r1
000000ce <.do_clear_bss_start>:
ce: a9 30 cpi r26, 0x09 ; 9
d0: b1 07 cpc r27, r17
d2: e1 f7 brne .-8 ; 0xcc <.do_clear_bss_loop>
d4: 0e 94 a8 01 call 0x350 ; 0x350 <main>
d8: 0c 94 b5 01 jmp 0x36a ; 0x36a <_exit>
000000dc <__bad_interrupt>:
dc: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>
000000e0 <setup>:
e0: 61 e0 ldi r22, 0x01 ; 1
e2: 8d e0 ldi r24, 0x0D ; 13
e4: 0c 94 39 01 jmp 0x272 ; 0x272 <pinMode>
000000e8 <loop>:
e8: 61 e0 ldi r22, 0x01 ; 1
ea: 8d e0 ldi r24, 0x0D ; 13
ec: 0e 94 71 01 call 0x2e2 ; 0x2e2 <digitalWrite>
f0: 88 e3 ldi r24, 0x38 ; 56
f2: 91 e0 ldi r25, 0x01 ; 1
f4: 0e 94 ca 00 call 0x194 ; 0x194 <delayMicroseconds>
f8: 60 e0 ldi r22, 0x00 ; 0
fa: 8d e0 ldi r24, 0x0D ; 13
fc: 0c 94 71 01 jmp 0x2e2 ; 0x2e2 <digitalWrite>
00000100 <__vector_16>:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
100: 1f 92 push r1
102: 0f 92 push r0
104: 0f b6 in r0, 0x3f ; 63
106: 0f 92 push r0
108: 11 24 eor r1, r1
10a: 2f 93 push r18
10c: 3f 93 push r19
10e: 8f 93 push r24
110: 9f 93 push r25
112: af 93 push r26
114: 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;
116: 80 91 00 01 lds r24, 0x0100
11a: 90 91 01 01 lds r25, 0x0101
11e: a0 91 02 01 lds r26, 0x0102
122: b0 91 03 01 lds r27, 0x0103
unsigned char f = timer0_fract;
126: 30 91 08 01 lds r19, 0x0108
m += MILLIS_INC;
f += FRACT_INC;
12a: 23 2f mov r18, r19
12c: 2d 5f subi r18, 0xFD ; 253
if (f >= FRACT_MAX) {
12e: 2d 37 cpi r18, 0x7D ; 125
130: 20 f4 brcc .+8 ; 0x13a <__vector_16+0x3a>
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;
m += MILLIS_INC;
132: 01 96 adiw r24, 0x01 ; 1
134: a1 1d adc r26, r1
136: b1 1d adc r27, r1
138: 05 c0 rjmp .+10 ; 0x144 <__vector_16+0x44>
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
13a: 23 2f mov r18, r19
13c: 2a 57 subi r18, 0x7A ; 122
m += 1;
13e: 02 96 adiw r24, 0x02 ; 2
140: a1 1d adc r26, r1
142: b1 1d adc r27, r1
}
timer0_fract = f;
144: 20 93 08 01 sts 0x0108, r18
timer0_millis = m;
148: 80 93 00 01 sts 0x0100, r24
14c: 90 93 01 01 sts 0x0101, r25
150: a0 93 02 01 sts 0x0102, r26
154: b0 93 03 01 sts 0x0103, r27
timer0_overflow_count++;
158: 80 91 04 01 lds r24, 0x0104
15c: 90 91 05 01 lds r25, 0x0105
160: a0 91 06 01 lds r26, 0x0106
164: b0 91 07 01 lds r27, 0x0107
168: 01 96 adiw r24, 0x01 ; 1
16a: a1 1d adc r26, r1
16c: b1 1d adc r27, r1
16e: 80 93 04 01 sts 0x0104, r24
172: 90 93 05 01 sts 0x0105, r25
176: a0 93 06 01 sts 0x0106, r26
17a: b0 93 07 01 sts 0x0107, r27
}
17e: bf 91 pop r27
180: af 91 pop r26
182: 9f 91 pop r25
184: 8f 91 pop r24
186: 3f 91 pop r19
188: 2f 91 pop r18
18a: 0f 90 pop r0
18c: 0f be out 0x3f, r0 ; 63
18e: 0f 90 pop r0
190: 1f 90 pop r1
192: 18 95 reti
00000194 <delayMicroseconds>:
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
194: 01 97 sbiw r24, 0x01 ; 1
196: 39 f0 breq .+14 ; 0x1a6 <delayMicroseconds+0x12>
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
198: 88 0f add r24, r24
19a: 99 1f adc r25, r25
19c: 88 0f add r24, r24
19e: 99 1f adc r25, r25
// account for the time taken in the preceeding commands.
us -= 2;
1a0: 02 97 sbiw r24, 0x02 ; 2
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
1a2: 01 97 sbiw r24, 0x01 ; 1
1a4: f1 f7 brne .-4 ; 0x1a2 <delayMicroseconds+0xe>
1a6: 08 95 ret
000001a8 <init>:
void init()
{
// this needs to be called before setup() or some functions won't
// work there
sei();
1a8: 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);
1aa: 84 b5 in r24, 0x24 ; 36
1ac: 82 60 ori r24, 0x02 ; 2
1ae: 84 bd out 0x24, r24 ; 36
sbi(TCCR0A, WGM00);
1b0: 84 b5 in r24, 0x24 ; 36
1b2: 81 60 ori r24, 0x01 ; 1
1b4: 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);
1b6: 85 b5 in r24, 0x25 ; 37
1b8: 82 60 ori r24, 0x02 ; 2
1ba: 85 bd out 0x25, r24 ; 37
sbi(TCCR0B, CS00);
1bc: 85 b5 in r24, 0x25 ; 37
1be: 81 60 ori r24, 0x01 ; 1
1c0: 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);
1c2: ee e6 ldi r30, 0x6E ; 110
1c4: f0 e0 ldi r31, 0x00 ; 0
1c6: 80 81 ld r24, Z
1c8: 81 60 ori r24, 0x01 ; 1
1ca: 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;
1cc: e1 e8 ldi r30, 0x81 ; 129
1ce: f0 e0 ldi r31, 0x00 ; 0
1d0: 10 82 st Z, r1
// set timer 1 prescale factor to 64
sbi(TCCR1B, CS11);
1d2: 80 81 ld r24, Z
1d4: 82 60 ori r24, 0x02 ; 2
1d6: 80 83 st Z, r24
#if F_CPU >= 8000000L
sbi(TCCR1B, CS10);
1d8: 80 81 ld r24, Z
1da: 81 60 ori r24, 0x01 ; 1
1dc: 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);
1de: e0 e8 ldi r30, 0x80 ; 128
1e0: f0 e0 ldi r31, 0x00 ; 0
1e2: 80 81 ld r24, Z
1e4: 81 60 ori r24, 0x01 ; 1
1e6: 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);
1e8: e1 eb ldi r30, 0xB1 ; 177
1ea: f0 e0 ldi r31, 0x00 ; 0
1ec: 80 81 ld r24, Z
1ee: 84 60 ori r24, 0x04 ; 4
1f0: 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);
1f2: e0 eb ldi r30, 0xB0 ; 176
1f4: f0 e0 ldi r31, 0x00 ; 0
1f6: 80 81 ld r24, Z
1f8: 81 60 ori r24, 0x01 ; 1
1fa: 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);
1fc: ea e7 ldi r30, 0x7A ; 122
1fe: f0 e0 ldi r31, 0x00 ; 0
200: 80 81 ld r24, Z
202: 84 60 ori r24, 0x04 ; 4
204: 80 83 st Z, r24
sbi(ADCSRA, ADPS1);
206: 80 81 ld r24, Z
208: 82 60 ori r24, 0x02 ; 2
20a: 80 83 st Z, r24
sbi(ADCSRA, ADPS0);
20c: 80 81 ld r24, Z
20e: 81 60 ori r24, 0x01 ; 1
210: 80 83 st Z, r24
// enable a2d conversions
sbi(ADCSRA, ADEN);
212: 80 81 ld r24, Z
214: 80 68 ori r24, 0x80 ; 128
216: 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;
218: 10 92 c1 00 sts 0x00C1, r1
21c: 08 95 ret
0000021e <turnOffPWM>:
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
switch (timer)
21e: 83 30 cpi r24, 0x03 ; 3
220: 69 f0 breq .+26 ; 0x23c <turnOffPWM+0x1e>
222: 28 f4 brcc .+10 ; 0x22e <turnOffPWM+0x10>
224: 81 30 cpi r24, 0x01 ; 1
226: a1 f0 breq .+40 ; 0x250 <turnOffPWM+0x32>
228: 82 30 cpi r24, 0x02 ; 2
22a: 11 f5 brne .+68 ; 0x270 <turnOffPWM+0x52>
22c: 14 c0 rjmp .+40 ; 0x256 <turnOffPWM+0x38>
22e: 86 30 cpi r24, 0x06 ; 6
230: b1 f0 breq .+44 ; 0x25e <turnOffPWM+0x40>
232: 87 30 cpi r24, 0x07 ; 7
234: c1 f0 breq .+48 ; 0x266 <turnOffPWM+0x48>
236: 84 30 cpi r24, 0x04 ; 4
238: d9 f4 brne .+54 ; 0x270 <turnOffPWM+0x52>
23a: 04 c0 rjmp .+8 ; 0x244 <turnOffPWM+0x26>
{
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A: cbi(TCCR1A, COM1A1); break;
23c: 80 91 80 00 lds r24, 0x0080
240: 8f 77 andi r24, 0x7F ; 127
242: 03 c0 rjmp .+6 ; 0x24a <turnOffPWM+0x2c>
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B: cbi(TCCR1A, COM1B1); break;
244: 80 91 80 00 lds r24, 0x0080
248: 8f 7d andi r24, 0xDF ; 223
24a: 80 93 80 00 sts 0x0080, r24
24e: 08 95 ret
#if defined(TCCR2) && defined(COM21)
case TIMER2: cbi(TCCR2, COM21); break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A: cbi(TCCR0A, COM0A1); break;
250: 84 b5 in r24, 0x24 ; 36
252: 8f 77 andi r24, 0x7F ; 127
254: 02 c0 rjmp .+4 ; 0x25a <turnOffPWM+0x3c>
#endif
#if defined(TIMER0B) && defined(COM0B1)
case TIMER0B: cbi(TCCR0A, COM0B1); break;
256: 84 b5 in r24, 0x24 ; 36
258: 8f 7d andi r24, 0xDF ; 223
25a: 84 bd out 0x24, r24 ; 36
25c: 08 95 ret
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A: cbi(TCCR2A, COM2A1); break;
25e: 80 91 b0 00 lds r24, 0x00B0
262: 8f 77 andi r24, 0x7F ; 127
264: 03 c0 rjmp .+6 ; 0x26c <turnOffPWM+0x4e>
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B: cbi(TCCR2A, COM2B1); break;
266: 80 91 b0 00 lds r24, 0x00B0
26a: 8f 7d andi r24, 0xDF ; 223
26c: 80 93 b0 00 sts 0x00B0, r24
270: 08 95 ret
00000272 <pinMode>:
#define ARDUINO_MAIN
#include "wiring_private.h"
#include "pins_arduino.h"
void pinMode(uint8_t pin, uint8_t mode)
{
272: cf 93 push r28
274: df 93 push r29
uint8_t bit = digitalPinToBitMask(pin);
276: 90 e0 ldi r25, 0x00 ; 0
278: fc 01 movw r30, r24
27a: e4 58 subi r30, 0x84 ; 132
27c: ff 4f sbci r31, 0xFF ; 255
27e: 44 91 lpm r20, Z+
uint8_t port = digitalPinToPort(pin);
280: fc 01 movw r30, r24
282: e0 57 subi r30, 0x70 ; 112
284: ff 4f sbci r31, 0xFF ; 255
286: 84 91 lpm r24, Z+
volatile uint8_t *reg, *out;
if (port == NOT_A_PIN) return;
288: 88 23 and r24, r24
28a: 41 f1 breq .+80 ; 0x2dc <pinMode+0x6a>
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
28c: 90 e0 ldi r25, 0x00 ; 0
28e: 88 0f add r24, r24
290: 99 1f adc r25, r25
292: fc 01 movw r30, r24
294: e2 55 subi r30, 0x52 ; 82
296: ff 4f sbci r31, 0xFF ; 255
298: 25 91 lpm r18, Z+
29a: 34 91 lpm r19, Z+
29c: d9 01 movw r26, r18
out = portOutputRegister(port);
29e: 8c 55 subi r24, 0x5C ; 92
2a0: 9f 4f sbci r25, 0xFF ; 255
2a2: fc 01 movw r30, r24
2a4: 85 91 lpm r24, Z+
2a6: 94 91 lpm r25, Z+
2a8: c8 2f mov r28, r24
2aa: d9 2f mov r29, r25
if (mode == INPUT) {
uint8_t oldSREG = SREG;
2ac: 9f b7 in r25, 0x3f ; 63
cli();
2ae: f8 94 cli
*reg &= ~bit;
2b0: 8c 91 ld r24, X
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
out = portOutputRegister(port);
if (mode == INPUT) {
2b2: 61 11 cpse r22, r1
2b4: 06 c0 rjmp .+12 ; 0x2c2 <pinMode+0x50>
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
2b6: 40 95 com r20
2b8: 84 23 and r24, r20
2ba: 8c 93 st X, r24
*out &= ~bit;
2bc: 88 81 ld r24, Y
2be: 84 23 and r24, r20
2c0: 08 c0 rjmp .+16 ; 0x2d2 <pinMode+0x60>
SREG = oldSREG;
} else if (mode == INPUT_PULLUP) {
2c2: 62 30 cpi r22, 0x02 ; 2
2c4: 41 f4 brne .+16 ; 0x2d6 <pinMode+0x64>
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
2c6: 24 2f mov r18, r20
2c8: 20 95 com r18
2ca: 82 23 and r24, r18
2cc: 8c 93 st X, r24
*out |= bit;
2ce: 88 81 ld r24, Y
2d0: 84 2b or r24, r20
2d2: 88 83 st Y, r24
2d4: 02 c0 rjmp .+4 ; 0x2da <pinMode+0x68>
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
2d6: 84 2b or r24, r20
2d8: 8c 93 st X, r24
SREG = oldSREG;
2da: 9f bf out 0x3f, r25 ; 63
}
}
2dc: df 91 pop r29
2de: cf 91 pop r28
2e0: 08 95 ret
000002e2 <digitalWrite>:
#endif
}
}
void digitalWrite(uint8_t pin, uint8_t val)
{
2e2: 0f 93 push r16
2e4: 1f 93 push r17
2e6: cf 93 push r28
2e8: df 93 push r29
2ea: 1f 92 push r1
2ec: cd b7 in r28, 0x3d ; 61
2ee: de b7 in r29, 0x3e ; 62
uint8_t timer = digitalPinToTimer(pin);
2f0: 28 2f mov r18, r24
2f2: 30 e0 ldi r19, 0x00 ; 0
2f4: f9 01 movw r30, r18
2f6: e8 59 subi r30, 0x98 ; 152
2f8: ff 4f sbci r31, 0xFF ; 255
2fa: 84 91 lpm r24, Z+
uint8_t bit = digitalPinToBitMask(pin);
2fc: f9 01 movw r30, r18
2fe: e4 58 subi r30, 0x84 ; 132
300: ff 4f sbci r31, 0xFF ; 255
302: 14 91 lpm r17, Z+
uint8_t port = digitalPinToPort(pin);
304: f9 01 movw r30, r18
306: e0 57 subi r30, 0x70 ; 112
308: ff 4f sbci r31, 0xFF ; 255
30a: 04 91 lpm r16, Z+
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
30c: 00 23 and r16, r16
30e: d1 f0 breq .+52 ; 0x344 <digitalWrite+0x62>
// 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);
310: 88 23 and r24, r24
312: 21 f0 breq .+8 ; 0x31c <digitalWrite+0x3a>
314: 69 83 std Y+1, r22 ; 0x01
316: 0e 94 0f 01 call 0x21e ; 0x21e <turnOffPWM>
31a: 69 81 ldd r22, Y+1 ; 0x01
out = portOutputRegister(port);
31c: e0 2f mov r30, r16
31e: f0 e0 ldi r31, 0x00 ; 0
320: ee 0f add r30, r30
322: ff 1f adc r31, r31
324: ec 55 subi r30, 0x5C ; 92
326: ff 4f sbci r31, 0xFF ; 255
328: 85 91 lpm r24, Z+
32a: 94 91 lpm r25, Z+
32c: dc 01 movw r26, r24
uint8_t oldSREG = SREG;
32e: 9f b7 in r25, 0x3f ; 63
cli();
330: f8 94 cli
if (val == LOW) {
*out &= ~bit;
332: 8c 91 ld r24, X
out = portOutputRegister(port);
uint8_t oldSREG = SREG;
cli();
if (val == LOW) {
334: 61 11 cpse r22, r1
336: 03 c0 rjmp .+6 ; 0x33e <digitalWrite+0x5c>
*out &= ~bit;
338: 10 95 com r17
33a: 81 23 and r24, r17
33c: 01 c0 rjmp .+2 ; 0x340 <digitalWrite+0x5e>
} else {
*out |= bit;
33e: 81 2b or r24, r17
340: 8c 93 st X, r24
}
SREG = oldSREG;
342: 9f bf out 0x3f, r25 ; 63
}
344: 0f 90 pop r0
346: df 91 pop r29
348: cf 91 pop r28
34a: 1f 91 pop r17
34c: 0f 91 pop r16
34e: 08 95 ret
00000350 <main>:
#include <Arduino.h>
int main(void)
{
init();
350: 0e 94 d4 00 call 0x1a8 ; 0x1a8 <init>
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
354: 0e 94 70 00 call 0xe0 ; 0xe0 <setup>
for (;;) {
loop();
if (serialEventRun) serialEventRun();
358: c0 e0 ldi r28, 0x00 ; 0
35a: d0 e0 ldi r29, 0x00 ; 0
#endif
setup();
for (;;) {
loop();
35c: 0e 94 74 00 call 0xe8 ; 0xe8 <loop>
if (serialEventRun) serialEventRun();
360: 20 97 sbiw r28, 0x00 ; 0
362: e1 f3 breq .-8 ; 0x35c <main+0xc>
364: 0e 94 00 00 call 0 ; 0x0 <__vectors>
368: f9 cf rjmp .-14 ; 0x35c <main+0xc>
0000036a <_exit>:
36a: f8 94 cli
0000036c <__stop_program>:
36c: ff cf rjmp .-2 ; 0x36c <__stop_program>
- Krille Krokodil
- Inlägg: 4062
- Blev medlem: 9 december 2005, 22:33:11
- Ort: Helsingborg
Re: Problem med arduino - begriper inte timingen....
Nej, det går bra med C eftersom att den overhead som skapas är konstant och du lätt kan justera delay-loopen eller interrupt-rutinen för det. I AVR-libc finns där delay-funktioner färdiga som du kan använda.laban12 skrev:Lärdom: Är det tidskritiskt använd lågnivåspråk.
Men du behöver börja från en tom AVR utan Arduinos "operativsystem".
Re: Problem med arduino - begriper inte timingen....
Är det inte så att man även kan skriva egna tillägg (I t.ex C eller ASM
eller vad som nu är lämpligt) som sedan läggs in i Arduino miljön.
Där kan man (på eget ansvar) göra vad man vill, som att stänga
av interrupt under tidskritiska delar o.s.v. D.v.s att man behåller
Arduinos ramverk men bygger ut med egna funktioner.
Men visst visar detta enkla exempel både på Aduinos fördelar (man
får mycket gjort med lite kod) och nackdelar (det händer mycket
"under the hood" även med lite kod)...
eller vad som nu är lämpligt) som sedan läggs in i Arduino miljön.
Där kan man (på eget ansvar) göra vad man vill, som att stänga
av interrupt under tidskritiska delar o.s.v. D.v.s att man behåller
Arduinos ramverk men bygger ut med egna funktioner.
Men visst visar detta enkla exempel både på Aduinos fördelar (man
får mycket gjort med lite kod) och nackdelar (det händer mycket
"under the hood" även med lite kod)...

Re: Problem med arduino - begriper inte timingen....
Jag skulle inte säga att det är "lätt" om det inte står i dokumentationen hur många klockcykler en instruktion kräver. (I alla fall inte den dokumentation jag har, arduino.cc)Krille Krokodil skrev:Nej, det går bra med C eftersom att den overhead som skapas är konstant och du lätt kan justera delay-loopen eller interrupt-rutinen för det...
Att det överhuvudtaget finns en funktion delayMicros() som går att justera ner till +- 1uS är ju direkt vilseledande, om funktionen i sig har en overhead som överstiger detta!?
Såvitt jag har förstått så går det, precis som sodjan skriver, att göra vissa snuttar av koden i ren assembler - och det är väl vad man kan kalla för en användbar kompromiss.
Tidigare har jag bara knackat assembler och C är relativt nytt för mig - som jag skrev inledningsvis så kan det ju vara så att problemet ligger hos mig!

Re: Problem med arduino - begriper inte timingen....
Du bör naturligtvis använda de inbyggda hårdvarutimerarna med tillhörande utgångar om det är tidskritiskt, de tuggar på i bakgrunden oavsett vad mjukvaran funderar på (inom rimliga gränser).
Med en 1Mhz klocka så tickar räknarna i just µs upplösning (om du nu vill det).
Med en 1Mhz klocka så tickar räknarna i just µs upplösning (om du nu vill det).
Re: Problem med arduino - begriper inte timingen....
Arduino-miljön är byggd ovanpå AVR Libc vars rutiner går alldeles utmärkt att anropa från en "sketch".Krille Krokodil skrev:Men du behöver börja från en tom AVR utan Arduinos "operativsystem".
arcuino.cc skrev:Arduino sketches are C/C++ based and compiled with the open-source compiler avr-gcc and linked against the open-source AVR Libc.
Re: Problem med arduino - begriper inte timingen....
Naturligtvis får du lov att läsa rätt dokumentation, i ditt fall antagligen Atmels manualer för ATmega328 tillsammans med dokumentationen för platformen (för att hitta exakt klockfrekvens et c.).laban12 skrev:Jag skulle inte säga att det är "lätt" om det inte står i dokumentationen hur många klockcykler en instruktion kräver. (I alla fall inte den dokumentation jag har, arduino.cc)