From 9e690340e9bb3d52251fdbb63278840d67c826e2 Mon Sep 17 00:00:00 2001 From: Ryan Kast Date: Mon, 20 Jul 2020 14:54:45 -0400 Subject: [PATCH] first take on adding a timeout parameter to the pulseIn function --- hal/inc/gpio_hal.h | 1 + hal/src/gcc/gpio_hal.cpp | 5 +++ hal/src/nRF52840/gpio_hal.cpp | 60 +++++++++++++++++++++++++++++++++++ hal/src/stm32f2xx/gpio_hal.c | 44 +++++++++++++++++++++++++ wiring/inc/spark_wiring.h | 1 + 5 files changed, 111 insertions(+) diff --git a/hal/inc/gpio_hal.h b/hal/inc/gpio_hal.h index a4ba6192ed..39f4f99540 100644 --- a/hal/inc/gpio_hal.h +++ b/hal/inc/gpio_hal.h @@ -61,6 +61,7 @@ PinMode HAL_Get_Pin_Mode(pin_t pin); void HAL_GPIO_Write(pin_t pin, uint8_t value); int32_t HAL_GPIO_Read(pin_t pin); uint32_t HAL_Pulse_In(pin_t pin, uint16_t value); +uint32_t HAL_Pulse_In(pin_t pin, uint16_t value, unsigned long timeout); #ifdef __cplusplus } diff --git a/hal/src/gcc/gpio_hal.cpp b/hal/src/gcc/gpio_hal.cpp index b1efea683f..a37f4491d6 100644 --- a/hal/src/gcc/gpio_hal.cpp +++ b/hal/src/gcc/gpio_hal.cpp @@ -217,3 +217,8 @@ uint32_t HAL_Pulse_In(pin_t pin, uint16_t value) return 0; } + +uint32_t HAL_Pulse_In(pin_t pin, uint16_t value, unsigned long timeout) +{ + return 0; +} diff --git a/hal/src/nRF52840/gpio_hal.cpp b/hal/src/nRF52840/gpio_hal.cpp index 5c01b84cca..6078e359cf 100644 --- a/hal/src/nRF52840/gpio_hal.cpp +++ b/hal/src/nRF52840/gpio_hal.cpp @@ -344,3 +344,63 @@ uint32_t HAL_Pulse_In(pin_t pin, uint16_t value) { } #endif } + +/* +* @brief blocking call to measure a high or low pulse +* @returns uint32_t pulse width in microseconds up to a specified number of microseconds timeout, +* returns 0 on specified microsecond timeout error, or invalid pin. +*/ +uint32_t HAL_Pulse_In(pin_t pin, uint16_t value, unsigned long timeout) { + #define FAST_READ(pin) ((reg->IN >> pin) & 1UL) + + if (!is_valid_pin(pin)) { + return 0; + } + + Hal_Pin_Info* PIN_MAP = HAL_Pin_Map(); + +#if HAL_PLATFORM_IO_EXTENSION && MODULE_FUNCTION != MOD_FUNC_BOOTLOADER + if (PIN_MAP[pin].type == HAL_PIN_TYPE_MCU) { +#endif + uint32_t nrf_pin = NRF_GPIO_PIN_MAP(PIN_MAP[pin].gpio_port, PIN_MAP[pin].gpio_pin); + NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&nrf_pin); + + volatile uint32_t timeout_start = SYSTEM_TICK_COUNTER; + volatile unsigned long timeoutTicks = 192UL*timeout; // total systems ticks to wait before timeout + + /* If already on the value we want to measure, wait for the next one. + * Time out after specified microseconds so we don't block the background tasks + */ + // while (nrf_gpio_pin_read(gpio_pin_map) == value) + while (FAST_READ(nrf_pin) == value) { + if (SYSTEM_TICK_COUNTER - timeout_start > timeoutTicks) { + return 0; + } + } + + /* Wait until the start of the pulse. + * Time out after specified microseconds so we don't block the background tasks + */ + while (FAST_READ(nrf_pin) != value) { + if (SYSTEM_TICK_COUNTER - timeout_start > timeoutTicks) { + return 0; + } + } + + /* Wait until this value changes, this will be our elapsed pulse width. + * Time out after specified microseconds so we don't block the background tasks + */ + volatile uint32_t pulse_start = SYSTEM_TICK_COUNTER; + while (FAST_READ(nrf_pin) == value) { + if (SYSTEM_TICK_COUNTER - timeout_start > timeoutTicks) { + return 0; + } + } + + return (SYSTEM_TICK_COUNTER - pulse_start) / SYSTEM_US_TICKS; +#if HAL_PLATFORM_IO_EXTENSION && MODULE_FUNCTION != MOD_FUNC_BOOTLOADER + } else { + return 0; + } +#endif +} \ No newline at end of file diff --git a/hal/src/stm32f2xx/gpio_hal.c b/hal/src/stm32f2xx/gpio_hal.c index 1003bbd2e8..ab8334172b 100644 --- a/hal/src/stm32f2xx/gpio_hal.c +++ b/hal/src/stm32f2xx/gpio_hal.c @@ -325,3 +325,47 @@ uint32_t HAL_Pulse_In(pin_t pin, uint16_t value) return (SYSTEM_TICK_COUNTER - pulseStart)/SYSTEM_US_TICKS; } + +/* + * @brief blocking call to measure a high or low pulse + * @returns uint32_t pulse width in microseconds up to a specified number of microseconds timeout, + * returns 0 on specified microsecond timeout error, or invalid pin. + */ +uint32_t HAL_Pulse_In(pin_t pin, uint16_t value, unsigned long timeout) +{ + Hal_Pin_Info* SOLO_PIN_MAP = HAL_Pin_Map(); + #define pinReadFast(_pin) ((SOLO_PIN_MAP[_pin].gpio_peripheral->IDR & SOLO_PIN_MAP[_pin].gpio_pin) == 0 ? 0 : 1) + + volatile uint32_t timeoutStart = SYSTEM_TICK_COUNTER; + volatile unsigned long timeoutTicks = 360UL*timeout; // total systems ticks to wait before timeout + + /* If already on the value we want to measure, wait for the next one. + * Time out after specified microseconds so we don't block the background tasks + */ + while (pinReadFast(pin) == value) { + if (SYSTEM_TICK_COUNTER - timeoutStart > timeoutTicks) { + return 0; + } + } + + /* Wait until the start of the pulse. + * Time out after specified microseconds so we don't block the background tasks + */ + while (pinReadFast(pin) != value) { + if (SYSTEM_TICK_COUNTER - timeoutStart > timeoutTicks) { + return 0; + } + } + + /* Wait until this value changes, this will be our elapsed pulse width. + * Time out after specified microseconds so we don't block the background tasks + */ + volatile uint32_t pulseStart = SYSTEM_TICK_COUNTER; + while (pinReadFast(pin) == value) { + if (SYSTEM_TICK_COUNTER - timeoutStart > timeoutTicks) { + return 0; + } + } + + return (SYSTEM_TICK_COUNTER - pulseStart)/SYSTEM_US_TICKS; +} diff --git a/wiring/inc/spark_wiring.h b/wiring/inc/spark_wiring.h index 1d5c982053..aeccb507e0 100644 --- a/wiring/inc/spark_wiring.h +++ b/wiring/inc/spark_wiring.h @@ -81,6 +81,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void serialReadLine(Stream *serialObj, char *dst, int max_len, system_tick_t timeout); uint32_t pulseIn(pin_t pin, uint16_t value); +uint32_t pulseIn(pin_t pin, uint16_t value, unsigned long timeout); #ifdef __cplusplus }