Problem med arduino - begriper inte timingen....

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
laban12
Inlägg: 1199
Blev medlem: 17 april 2008, 16:01:56
Ort: Stockholm

Problem med arduino - begriper inte timingen....

Inlägg av laban12 »

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)
Larsson90
Inlägg: 646
Blev medlem: 24 december 2008, 21:43:25
Ort: Göteborg

Re: Problem med arduino - begriper inte timingen....

Inlägg av Larsson90 »

Funktionsanropen kanske tar X microsekunder.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med arduino - begriper inte timingen....

Inlägg av sodjan »

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().
Användarvisningsbild
MicaelKarlsson
Inlägg: 4669
Blev medlem: 18 juni 2004, 09:16:07
Ort: Aneby
Kontakt:

Re: Problem med arduino - begriper inte timingen....

Inlägg av MicaelKarlsson »

Denna sida kan nog skingra dina funderingar: http://billgrundmann.wordpress.com/2009 ... tedigital/

Hoppas jag! :)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med arduino - begriper inte timingen....

Inlägg av sodjan »

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... :-)
Användarvisningsbild
Krille Krokodil
Inlägg: 4062
Blev medlem: 9 december 2005, 22:33:11
Ort: Helsingborg

Re: Problem med arduino - begriper inte timingen....

Inlägg av Krille Krokodil »

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.
laban12
Inlägg: 1199
Blev medlem: 17 april 2008, 16:01:56
Ort: Stockholm

Re: Problem med arduino - begriper inte timingen....

Inlägg av laban12 »

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.
Användarvisningsbild
calmar
Inlägg: 540
Blev medlem: 23 november 2005, 13:14:41
Ort: Göteborg
Kontakt:

Re: Problem med arduino - begriper inte timingen....

Inlägg av calmar »

Kontrollera assemblerkoden som genereras, det vore intressant att veta vad det är som händer egentligen.
Användarvisningsbild
calmar
Inlägg: 540
Blev medlem: 23 november 2005, 13:14:41
Ort: Göteborg
Kontakt:

Re: Problem med arduino - begriper inte timingen....

Inlägg av calmar »

Gjorde ett litet snabbt test med Arduino IDE 1.0.1:

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>
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 ..
Användarvisningsbild
Krille Krokodil
Inlägg: 4062
Blev medlem: 9 december 2005, 22:33:11
Ort: Helsingborg

Re: Problem med arduino - begriper inte timingen....

Inlägg av Krille Krokodil »

laban12 skrev:Lärdom: Är det tidskritiskt använd lågnivåspråk.
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.

Men du behöver börja från en tom AVR utan Arduinos "operativsystem".
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem med arduino - begriper inte timingen....

Inlägg av sodjan »

Ä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)... :-)
laban12
Inlägg: 1199
Blev medlem: 17 april 2008, 16:01:56
Ort: Stockholm

Re: Problem med arduino - begriper inte timingen....

Inlägg av laban12 »

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

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! ;)
Gimbal
Inlägg: 8683
Blev medlem: 20 april 2005, 15:43:53

Re: Problem med arduino - begriper inte timingen....

Inlägg av Gimbal »

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).
sm5tfx
Inlägg: 114
Blev medlem: 20 juli 2011, 14:28:41
Ort: Gnällbältet

Re: Problem med arduino - begriper inte timingen....

Inlägg av sm5tfx »

Krille Krokodil skrev:Men du behöver börja från en tom AVR utan Arduinos "operativsystem".
Arduino-miljön är byggd ovanpå AVR Libc vars rutiner går alldeles utmärkt att anropa från en "sketch".
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.
sm5tfx
Inlägg: 114
Blev medlem: 20 juli 2011, 14:28:41
Ort: Gnällbältet

Re: Problem med arduino - begriper inte timingen....

Inlägg av sm5tfx »

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)
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.).
Skriv svar