diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 76d111f11ef3d..77a7637ed4025 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -181,19 +181,22 @@ Miscellaneous functions varies by hardware (so use substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds to the network MAC address. -.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000, /) +.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000, wait_opposite=false, /) Time a pulse on the given *pin*, and return the duration of the pulse in microseconds. The *pulse_level* argument should be 0 to time a low pulse or 1 to time a high pulse. - If the current input value of the pin is different to *pulse_level*, - the function first (*) waits until the pin input becomes equal to *pulse_level*, - then (**) times the duration that the pin is equal to *pulse_level*. + If *wait_opposite* is true, if the pin is initially equal to *pulse_level* then first + waits until the pin input becomes different from *pulse_level* (***). + Then if the current input value of the pin is different to *pulse_level*, + the function first (**) waits until the pin input becomes equal to *pulse_level*, + then (*) times the duration that the pin is equal to *pulse_level*. If the pin is already equal to *pulse_level* then timing starts straight away. + The function returns -3 if there was timeout waiting for condition marked (***) above. The function will return -2 if there was timeout waiting for condition marked - (*) above, and -1 if there was timeout during the main measurement, marked (**) + (**) above, and -1 if there was timeout during the main measurement, marked (*) above. The timeout is the same for both cases and given by *timeout_us* (which is in microseconds). diff --git a/drivers/dht/dht.c b/drivers/dht/dht.c index e6b71542dabc9..47d114fed784e 100644 --- a/drivers/dht/dht.c +++ b/drivers/dht/dht.c @@ -71,8 +71,9 @@ static mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) { } } + #define WAIT_OPPOSITE false // time pulse, should be 80us - ticks = machine_time_pulse_us(pin, 1, 150); + ticks = machine_time_pulse_us(pin, 1, 150, WAIT_OPPOSITE); if ((mp_int_t)ticks < 0) { goto timeout; } @@ -80,7 +81,7 @@ static mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) { // time 40 pulses for data (either 26us or 70us) uint8_t *buf = bufinfo.buf; for (int i = 0; i < 40; ++i) { - ticks = machine_time_pulse_us(pin, 1, 100); + ticks = machine_time_pulse_us(pin, 1, 100, WAIT_OPPOSITE); if ((mp_int_t)ticks < 0) { goto timeout; } diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c index 85dba86d9b5ad..60edc3ce9e4c4 100644 --- a/extmod/machine_pulse.c +++ b/extmod/machine_pulse.c @@ -30,8 +30,14 @@ #if MICROPY_PY_MACHINE_PULSE -MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { +MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us, bool wait_opposite) { mp_uint_t start = mp_hal_ticks_us(); + while (wait_opposite && (mp_hal_pin_read(pin) == pulse_level)) { + if ((uint64_t)(mp_hal_ticks_us() - start) >= (uint64_t)timeout_us) { + return (mp_uint_t)-3; + } + } + start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) != pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { return (mp_uint_t)-2; @@ -56,10 +62,14 @@ static mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { if (n_args > 2) { timeout_us = mp_obj_get_int(args[2]); } - mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); - // May return -1 or -2 in case of timeout + bool wait_opposite = false; + if (n_args > 3) { + wait_opposite = mp_obj_is_true(args[3]); + } + mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us, wait_opposite); + // May return -1 or -2 or -3 in case of timeout return mp_obj_new_int(us); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 4, machine_time_pulse_us_); #endif diff --git a/extmod/modmachine.h b/extmod/modmachine.h index 7c16ed302ee2f..c3a1e61da4d4d 100644 --- a/extmod/modmachine.h +++ b/extmod/modmachine.h @@ -244,7 +244,7 @@ uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align); NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args); void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len); -mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us, bool wait_opposite); MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 23ccf8cebfb0d..b994bf813382e 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -329,7 +329,7 @@ MP_DEFINE_CONST_OBJ_TYPE( ); // Custom version of this function that feeds system WDT if necessary -mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us, bool wait_opposite) { int nchanges = 2; uint32_t start = system_get_time(); // in microseconds for (;;) { diff --git a/tests/extmod_hardware/machine_pwm.py b/tests/extmod_hardware/machine_pwm.py index e27da32548659..4010dbeccaca0 100644 --- a/tests/extmod_hardware/machine_pwm.py +++ b/tests/extmod_hardware/machine_pwm.py @@ -72,14 +72,11 @@ def _test_freq_duty(self, pulse_in, pwm, freq, duty_u16): expected_us = (expected_low_us, expected_high_us) timeout = 2 * expected_total_us - # Wait for output to settle. - time_pulse_us(pulse_in, 0, timeout) - time_pulse_us(pulse_in, 1, timeout) - if duty_u16 == 0 or duty_u16 == 65535: # Expect a constant output level. no_pulse = ( - time_pulse_us(pulse_in, 0, timeout) < 0 and time_pulse_us(pulse_in, 1, timeout) < 0 + time_pulse_us(pulse_in, 0, timeout, True) < 0 + and time_pulse_us(pulse_in, 1, timeout, True) < 0 ) self.assertTrue(no_pulse) if expected_high_us == 0: @@ -93,9 +90,8 @@ def _test_freq_duty(self, pulse_in, pwm, freq, duty_u16): n_averaging = 10 for level in (0, 1): t = 0 - time_pulse_us(pulse_in, level, timeout) for _ in range(n_averaging): - t += time_pulse_us(pulse_in, level, timeout) + t += time_pulse_us(pulse_in, level, timeout, True) t //= n_averaging expected = expected_us[level] print(" level={} timing_er={}".format(level, abs(t - expected)), end="")