Assembler and C for while loops.

I have the following code working. It measures the time between pulses from my signal generator.

I have got the input signal up to 50 Khz.

The shortest time I can measure is 247 clock cycles.

I presume that the while loop is the overhead.

Can I use another C routine or assembler instead to make it faster ?

const int RPM = 2;
unsigned int Tmr = 0;

void setup() {
  pinMode(RPM, INPUT);           // initialize the LED pin as an input:
  Serial.begin(57600);           // initialize serial communications:
                                 //set up timer 1 control registers here
  TCCR1A = 0x00;                 //select Normal Mode,freerunning counter
  TCCR1B = 0X01;                 //normal, prescaler equals clock. 
}

void loop() {
   while(digitalRead(RPM) != LOW){}           // Wait for falling edge  
   while(digitalRead(RPM) != HIGH){}          // Wait for rising edge 
   TCNT1 = 0;                                 // Reset timer
   while(digitalRead(RPM) != LOW){}           // Wait for falling edge  
   while(digitalRead(RPM) != HIGH){}          // Wait for Rising edge  
   Tmr =  TCNT1;   
   Serial.println(Tmr);        
   delay(1000);     
}

digitalRead is slow.
Have a look around the forum for fastdigitalRead.

Or have a look here: Arduino Playground - PortManipulation

or digitalWriteFast:
http://code.google.com/p/digitalwritefast/

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267553811/0

or digitalWriteFast

S/he's not doing any writes. :-?

Either pulsein() or an interrupt would work better than polling.

pulseIn polls, doesn't it?

The bit manipulation is the easy oart in c, the difficult bit is the while.

I was wanting to use the BRNE assembler statement. BRanch if Not Equal.

BRNE takes only one instruction to execute.

Any suggestions ?

Thanks Wallace

What does the while currently compile into?

What does the while currently compile into?

I'm not sure but is no faster than 247 clock cycles.

   while(digitalRead(RPM) != LOW){}           // Wait for falling edge  
   while(digitalRead(RPM) != HIGH){}          // Wait for Rising edge  
   Tmr =  TCNT1;

I'm not sure but is no faster than 247 clock cycles

Rarely have I come across a microprocessor that took more than 2 cycles to execute a simple relative branch.
247 cycles is the rate glaciers move at.
Why aren't you looking at the generated code?

Why aren't you looking at the generated code?

I'm new to the this, what do you mean, the Hex?

Is this syntax correct

   while(PORTD|0xFB != 0xFB);

Pin 2 on PortD is 00000X00 X being off or on
If I or this with 11111011,

PORTD|0xFB != 0xFB

This will loop until X=0

Thanks Wallace

As others have said, it's not the loop, it's the implementation of digitalRead(). Here's the actual loop, as reported by "avr-objdump" (search the forums for this for further info on how to use this.)

void loop() {
   while(digitalRead(RPM) != LOW){}           // Wait for falling edge  
 118:      82 e0             ldi      r24, 0x02      ; 2
 11a:      0e 94 ab 01       call      0x356      ; 0x356 <digitalRead>
 11e:      89 2b             or      r24, r25
 120:      d9 f7             brne      .-10           ; 0x118 <loop>
   while(digitalRead(RPM) != HIGH){}          // Wait for rising edge
 122:      82 e0             ldi      r24, 0x02      ; 2
 124:      0e 94 ab 01       call      0x356      ; 0x356 <digitalRead>
 128:      01 97             sbiw      r24, 0x01      ; 1
 12a:      d9 f7             brne      .-10           ; 0x122 <loop+0xa>
   TCNT1 = 0;                                 // Reset timer
 12c:      10 92 85 00       sts      0x0085, r1
 130:      10 92 84 00       sts      0x0084, r1
   while(digitalRead(RPM) != LOW){}           // Wait for falling edge  
 134:      82 e0             ldi      r24, 0x02      ; 2
 136:      0e 94 ab 01       call      0x356      ; 0x356 <digitalRead>
 13a:      89 2b             or      r24, r25
 13c:      d9 f7             brne      .-10           ; 0x134 <loop+0x1c>
   while(digitalRead(RPM) != HIGH){}          // Wait for Rising edge  
 13e:      82 e0             ldi      r24, 0x02      ; 2
 140:      0e 94 ab 01       call      0x356      ; 0x356 <digitalRead>
 144:      01 97             sbiw      r24, 0x01      ; 1
 146:      d9 f7             brne      .-10           ; 0x13e <loop+0x26>
   Tmr =  TCNT1;  
 148:      60 91 84 00       lds      r22, 0x0084
 14c:      70 91 85 00       lds      r23, 0x0085
 150:      70 93 13 01       sts      0x0113, r23
 154:      60 93 12 01       sts      0x0112, r22
   Serial.println(Tmr);        
 158:      81 ea             ldi      r24, 0xA1      ; 161
 15a:      91 e0             ldi      r25, 0x01      ; 1
 15c:      4a e0             ldi      r20, 0x0A      ; 10
 15e:      50 e0             ldi      r21, 0x00      ; 0
 160:      0e 94 13 05       call      0xa26      ; 0xa26 <_ZN5Print7printlnEji>
   delay(1000);    
 164:      68 ee             ldi      r22, 0xE8      ; 232
 166:      73 e0             ldi      r23, 0x03      ; 3
 168:      80 e0             ldi      r24, 0x00      ; 0
 16a:      90 e0             ldi      r25, 0x00      ; 0
 16c:      0e 94 13 01       call      0x226      ; 0x226 <delay>
} 
 170:      08 95             ret

Thanks, I got the dump working but now I'll need a day or two to get my hear around this.

This however does not seem to work.

Input 2 on Arduino Board.

   while(PORTD|0xFB != 0xFB);

Thanks Wallace

This however does not seem to work.

The line of code waits for bit 2 of port D to be low. Is that what you intended?

That's what I intended. It's been a while since I last coded and I deleted the {} after the while because I could not remember what they did. TskTsk.

I still have a problem however.

//const int RPM = 2;
const int ledPin =  13;      // the number of the LED pin
unsigned int Tmr = 0;

void setup() {
  pinMode(ledPin, OUTPUT);      
  Serial.begin(57600);           // initialize serial communications:
                                 //set up timer 1 control registers here
  TCCR1A = 0x00;                 //select Normal Mode,freerunning counter
  TCCR1B = 0X01;                 //normal, prescaler equals clock. 
  DDRD = 0x00;                      // set PB to Inputs}
}
void loop() {
   digitalWrite(ledPin, 1);                      // shows where the program stops. 
   while(PORTD|0xFB != 0xFB){};           // Wait for falling edge on bit 2 PORTD
   digitalWrite(ledPin, 0);     
   while(PORTD&0x04 != 0x04){};           // Wait for rising edge on bit 2 PORTD
   TCNT1 = 0;                                    // Reset timer
   while(PORTD|0xFB != 0xFB){};           // Wait for falling edge  
   while(PORTD&0x04 != 0x04){};           // Wait for rising edge  
   Tmr =  TCNT1;   
   Serial.println(Tmr);        
   delay(1000);     
}
   while(PORTD|0xFB != 0xFB);

that seems a weird way to do things. What's wrong with

while ((PORTD & 4) != 0)

or

while ((PORTD & (1<<PD2)) != 0)

Positive bitmasks are so much easier to read. And you get used to (1<<bitnum)...

Always use extra parentheses for boolean operations. Order of operations gets confusing...

Today I found out that I need to know more than just c. I also need to understand the .h files. This is a bit new to me coming from a Delphi and Basic background.

I found a file c:\Arduino\hardware\tools\avr\lib\avr5\iom328p.h and now things like

while ((PORTD & (1<<PD2)) != 0)

are starting to make sense.

OK When do I use, or what is the difference between ?

while ((PORTD & 4) != 0)

or

while ((PORTD & 0X04) != 0)

or

while ((PORTD & (1<<PD2)) != 0) // I see this code can be made portable to other devices.

Thanks Wallace