Skip to content

Commit 150d430

Browse files
author
Martino Facchin
committed
pulseIn: simplify ASM function, remove switch
1 parent f06cb4f commit 150d430

File tree

3 files changed

+44
-150
lines changed

3 files changed

+44
-150
lines changed

hardware/arduino/avr/cores/arduino/wiring_private.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,7 @@ extern "C"{
4343
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
4444
#endif
4545

46-
uint32_t countPulseASM_B(const uint8_t bit, uint8_t state, uint32_t maxloops);
47-
uint32_t countPulseASM_C(const uint8_t bit, uint8_t state, uint32_t maxloops);
48-
uint32_t countPulseASM_D(const uint8_t bit, uint8_t state, uint32_t maxloops);
49-
50-
#if defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)
51-
uint32_t countPulseASM_E(const uint8_t bit, uint8_t state, uint32_t maxloops);
52-
uint32_t countPulseASM_F(const uint8_t bit, uint8_t state, uint32_t maxloops);
53-
uint32_t countPulseASM_G(const uint8_t bit, uint8_t state, uint32_t maxloops);
54-
#endif
46+
uint32_t countPulseASM(uint8_t bit, uint8_t state, uint32_t maxloops, volatile uint8_t* port);
5547

5648
#define EXTERNAL_INT_0 0
5749
#define EXTERNAL_INT_1 1

hardware/arduino/avr/cores/arduino/wiring_pulse.S

Lines changed: 39 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -22,102 +22,47 @@
2222

2323
#include <avr/io.h>
2424

25-
#if 0 // commented version, unusable for macro expansion
25+
.section .text
26+
27+
.global countPulseASM
2628

27-
// bit is r25-24, state is r23-r22, timeout is r21-r18
29+
// bit is r25-24, state is r23-r22, timeout is r21-r18, *port is r17-r16
2830
// these register do not need to be restored
29-
// save r24 and r22 to r16,r17 for further use
31+
// save r24 and r22 to r14,r15 for further use
3032
// r25-r22 are used to store width and must be restored
3133

32-
#define countPulseASM_gen(X) \
33-
countPulseASM_##X: $ \
34-
push r17 ; save r17-r15 $ \
35-
push r16 $ \
36-
push r15 $ \
37-
mov r16, r24 ; set r16 to r24 and r17 to r22 $ \
38-
mov r17, r22 ; r17 is now state $ \
39-
mov r25,r1 ; zero r25-r22 $ \
40-
mov r24,r1 $ \
41-
mov r23,r1 $ \
42-
mov r22,r1 $ \
43-
loop_##X: ; start loop $ \
44-
subi r22, 255 ; increment width $ \
45-
sbci r23, 255 $ \
46-
sbci r24, 255 $ \
47-
sbci r25, 255 $ \
48-
cp r22, r18 ; compare width with timeout $ \
49-
cpc r23, r19 $ \
50-
cpc r24, r20 $ \
51-
cpc r25, r21 $ \
52-
breq return_zero_##X ; if equal, return 0 $ \
53-
in r26, PIN##X - 0x20 ; save port state to unused r26 $ \
54-
eor r26, r17 ; xor with state $ \
55-
and r26, r16 ; and with bit $ \
56-
cpi r26, 0 ; compare with zero $ \
57-
breq loop_##X ; if equal, continue looping $ \
58-
rjmp exit_##X $ \
59-
return_zero_##X: $ \
60-
mov r22,r1 ; return 0 - timeout reached $ \
61-
mov r23,r1 $ \
62-
mov r24,r1 $ \
63-
mov r25,r1 $ \
64-
exit_##X: $ \
65-
pop r17 $ \
66-
pop r16 $ \
67-
pop r15 $ \
68-
ret
69-
70-
#endif
71-
72-
#define countPulseASM_gen(X) .global countPulseASM_##X $\
73-
countPulseASM_##X: $\
74-
push r17 $\
75-
push r16 $\
76-
push r15 $\
77-
mov r16, r24 $\
78-
mov r17, r22 $\
79-
mov r25, r1 $\
80-
mov r24, r1 $\
81-
mov r23, r1 $\
82-
mov r22, r1 $\
83-
loop_##X: $\
84-
subi r22, 255 $\
85-
sbci r23, 255 $\
86-
sbci r24, 255 $\
87-
sbci r25, 255 $\
88-
cp r22, r18 $\
89-
cpc r23, r19 $\
90-
cpc r24, r20 $\
91-
cpc r25, r21 $\
92-
breq return_zero_##X $\
93-
in r26, PIN##X - 0x20 $\
94-
eor r26, r17 $\
95-
and r26, r16 $\
96-
cpi r26, 0 $\
97-
breq loop_##X $\
98-
rjmp exit_##X $\
99-
return_zero_##X: $\
100-
mov r22, r1 $\
101-
mov r23, r1 $\
102-
mov r24, r1 $\
103-
mov r25, r1 $\
104-
exit_##X: $\
105-
pop r17 $\
106-
pop r16 $\
107-
pop r15 $\
34+
countPulseASM:
35+
push r14 ; save r14-r15
36+
push r15
37+
mov r14, r24 ; set r14 to r24 and r15 to r22
38+
mov r15, r22 ; r15 is now state
39+
mov r25,r1 ; zero r25-r22
40+
mov r24,r1
41+
mov r23,r1
42+
mov r22,r1
43+
loop: ; start loop
44+
subi r22, 255 ; increment width
45+
sbci r23, 255
46+
sbci r24, 255
47+
sbci r25, 255
48+
cp r22, r18 ; compare width with timeout
49+
cpc r23, r19
50+
cpc r24, r20
51+
cpc r25, r21
52+
breq return_zero ; if equal, return 0
53+
movw r30, r16 ; save port state to unused r26
54+
ld r26, Z
55+
eor r26, r15 ; xor with state
56+
and r26, r14 ; and with bit
57+
cpi r26, 0
58+
breq loop ; if equal, continue looping
59+
rjmp exit
60+
return_zero:
61+
mov r22,r1 ; return 0 - timeout reached
62+
mov r23,r1
63+
mov r24,r1
64+
mov r25,r1
65+
exit:
66+
pop r14
67+
pop r15
10868
ret
109-
110-
.section .text
111-
112-
countPulseASM_gen(B)
113-
countPulseASM_gen(C)
114-
countPulseASM_gen(D)
115-
116-
117-
#if defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)
118-
119-
countPulseASM_gen(E)
120-
countPulseASM_gen(F)
121-
countPulseASM_gen(G)
122-
123-
#endif

hardware/arduino/avr/cores/arduino/wiring_pulse.c

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,6 @@
2525
#include "wiring_private.h"
2626
#include "pins_arduino.h"
2727

28-
//include PORT as the ones defined in Arduino.h
29-
#define PA 1
30-
#define PB 2
31-
#define PC 3
32-
#define PD 4
33-
#define PE 5
34-
#define PF 6
35-
#define PG 7
36-
#define PH 8
37-
#define PJ 10
38-
#define PK 11
39-
#define PL 12
40-
41-
uint32_t (*countPulseASM)(const uint8_t bit, uint8_t state, uint32_t maxloops);
42-
4328
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
4429
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
4530
* to 3 minutes in length, but must be called at least a few dozen microseconds
@@ -57,38 +42,10 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
5742
uint8_t stateMask = (state ? bit : 0);
5843
unsigned long width = 0; // keep initialization out of time critical area
5944

60-
switch (port) {
61-
case PB:
62-
//portB
63-
countPulseASM = &countPulseASM_B;
64-
break;
65-
case PC:
66-
//portC
67-
countPulseASM = &countPulseASM_C;
68-
break;
69-
case PD:
70-
//portD
71-
countPulseASM = &countPulseASM_D;
72-
break;
73-
#if defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)
74-
case PE:
75-
//portE
76-
countPulseASM = &countPulseASM_E;
77-
case PF:
78-
//portF
79-
countPulseASM = &countPulseASM_F;
80-
case PG:
81-
//portG
82-
countPulseASM = &countPulseASM_G;
83-
#endif
84-
default:
85-
return 0;
86-
}
87-
8845
// convert the timeout from microseconds to a number of times through
89-
// the initial loop; it takes 11 clock cycles per iteration.
46+
// the initial loop; it takes approximately 24 clock cycles per iteration. (compiler dependant)
9047
unsigned long numloops = 0;
91-
unsigned long maxloops = microsecondsToClockCycles(timeout)/15;
48+
unsigned long maxloops = microsecondsToClockCycles(timeout)/24;
9249

9350
// wait for any previous pulse to end
9451
while ((*portInputRegister(port) & bit) == stateMask)
@@ -100,8 +57,8 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
10057
if (numloops++ == maxloops)
10158
return 0;
10259

103-
width = countPulseASM(bit, stateMask, (maxloops - numloops));
104-
return clockCyclesToMicroseconds(width * 15 + 30);
60+
width = countPulseASM(bit, stateMask, (maxloops - numloops), portInputRegister(port));
61+
return clockCyclesToMicroseconds(width * 17 + 32);
10562
}
10663

10764
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH

0 commit comments

Comments
 (0)