Skip to content

Commit 014bfde

Browse files
committed
Improve PulseIn().
Replace digitalRead() by direct access to the register. This allow to have a finer resolution: Correct timeout management. Next improvement is to provide one without micros() in order to be able to use it in no interrupt context. Signed-off-by: Frederic.Pillon <[email protected]>
1 parent 25583f5 commit 014bfde

File tree

2 files changed

+22
-26
lines changed

2 files changed

+22
-26
lines changed

Diff for: cores/arduino/wiring_pulse.cpp

+20-23
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,37 @@
2424
* before the start of the pulse.
2525
*
2626
* ATTENTION:
27-
* This function performs better with short pulses in noInterrupt() context
27+
* This function relies on micros() so cannot be used in noInterrupt() context
2828
*/
29-
3029
uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
3130
{
31+
// Cache the port and bit of the pin in order to speed up the
32+
// pulse width measuring loop and achieve finer resolution.
33+
// Calling digitalRead() instead yields much coarser resolution.
34+
uint32_t bit = digitalPinToBitMask(pin);
35+
__IO uint32_t *portIn = portInputRegister(digitalPinToPort(pin));
36+
uint32_t stateMask = (state ? bit : 0);
3237
uint32_t startMicros = micros();
33-
uint32_t start_level = (uint32_t)digitalRead(pin);
34-
uint32_t current_level = start_level;
3538

36-
while(current_level == start_level) {
37-
if (micros() - startMicros > timeout) {
39+
// wait for any previous pulse to end
40+
while ((*portIn & bit) == stateMask) {
41+
if (micros() - startMicros > timeout)
3842
return 0;
39-
}
40-
current_level = (uint32_t)digitalRead(pin);
4143
}
4244

43-
while(current_level != state) {
44-
if (micros() - startMicros > timeout) {
45+
// wait for the pulse to start
46+
while ((*portIn & bit) != stateMask) {
47+
if (micros() - startMicros > timeout)
4548
return 0;
46-
}
47-
current_level = (uint32_t)digitalRead(pin);
4849
}
4950

50-
//lets start measuring the pulse time now
51-
startMicros = micros();
52-
53-
while(current_level == state) {
54-
if (micros() - startMicros > timeout) {
51+
uint32_t start = micros();
52+
// wait for the pulse to stop
53+
while ((*portIn & bit) == stateMask) {
54+
if (micros() - startMicros > timeout)
5555
return 0;
56-
}
57-
current_level = (uint32_t)digitalRead(pin);
5856
}
59-
60-
return (micros() - startMicros);
57+
return (micros() - start);
6158
}
6259

6360
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
@@ -66,9 +63,9 @@ uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout )
6663
* before the start of the pulse.
6764
*
6865
* ATTENTION:
69-
* this function relies on micros() so cannot be used in noInterrupt() context
66+
* This function relies on micros() so cannot be used in noInterrupt() context
7067
*/
71-
uint32_t pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
68+
uint32_t pulseInLong(uint32_t pin, uint32_t state, uint32_t timeout)
7269
{
7370
return pulseIn(pin, state, timeout);
7471
}

Diff for: cores/arduino/wiring_pulse.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@
2020
#define _WIRING_PULSE_
2121

2222
#ifdef __cplusplus
23-
unsigned long countPulseASM(const volatile uint32_t *port, uint32_t bit, uint32_t stateMask, unsigned long maxloops);
2423
/*
2524
* \brief Measures the length (in microseconds) of a pulse on the pin; state is HIGH
2625
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
2726
* to 3 minutes in length, but must be called at least a few dozen microseconds
2827
* before the start of the pulse.
2928
*/
30-
extern uint32_t pulseIn( uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout = 1000000L ) ;
31-
extern uint32_t pulseInLong( uint8_t pin, uint8_t state, unsigned long timeout = 1000000L ) ;
29+
extern uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t timeout = 1000000L ) ;
30+
extern uint32_t pulseInLong( uint32_t pin, uint32_t state, uint32_t timeout = 1000000L ) ;
3231
#endif
3332

3433
#endif /* _WIRING_PULSE_ */

0 commit comments

Comments
 (0)