diff --git a/os/hal/include/icu.h b/os/hal/include/icu.h index 9d7a06220..f9df3cd6a 100644 --- a/os/hal/include/icu.h +++ b/os/hal/include/icu.h @@ -187,6 +187,7 @@ typedef void (*icucallback_t)(ICUDriver *icup); /** * @brief Common ISR code, ICU period event. + * @note A period event brings the driver into the @p ICU_ACTIVE state. * * @param[in] icup pointer to the @p ICUDriver object * @@ -201,6 +202,8 @@ typedef void (*icucallback_t)(ICUDriver *icup); /** * @brief Common ISR code, ICU timer overflow event. + * @note An overflow always brings the driver back to the @p ICU_WAITING + * state. * * @param[in] icup pointer to the @p ICUDriver object * @@ -208,6 +211,7 @@ typedef void (*icucallback_t)(ICUDriver *icup); */ #define _icu_isr_invoke_overflow_cb(icup) do { \ (icup)->config->overflow_cb(icup); \ + (icup)->state = ICU_WAITING; \ } while (0) /** @} */ @@ -223,7 +227,7 @@ extern "C" { void icuStart(ICUDriver *icup, const ICUConfig *config); void icuStop(ICUDriver *icup); void icuStartCapture(ICUDriver *icup); - void icuWaitCapture(ICUDriver *icup); + bool icuWaitCapture(ICUDriver *icup); void icuStopCapture(ICUDriver *icup); void icuEnableNotifications(ICUDriver *icup); void icuDisableNotifications(ICUDriver *icup); diff --git a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c index d5604515e..04fec43cd 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c +++ b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c @@ -102,7 +102,9 @@ ICUDriver ICUD9; /* Driver local functions. */ /*===========================================================================*/ -static void icu_lld_wait_edge(ICUDriver *icup) { +static bool icu_lld_wait_edge(ICUDriver *icup) { + uint32_t sr; + bool result; /* Polled mode so re-enabling the interrupts while the operation is performed.*/ @@ -111,23 +113,29 @@ static void icu_lld_wait_edge(ICUDriver *icup) { /* Polling the right bit depending on the input channel.*/ if (icup->config->channel == ICU_CHANNEL_1) { /* Waiting for an edge.*/ - while ((icup->tim->SR & STM32_TIM_SR_CC1IF) == 0) + while (((sr = icup->tim->SR) & + (STM32_TIM_SR_CC1IF | STM32_TIM_SR_UIF)) == 0) ; - - /* Resetting capture flag.*/ - icup->tim->SR &= ~STM32_TIM_SR_CC1IF; } else { /* Waiting for an edge.*/ - while ((icup->tim->SR & STM32_TIM_SR_CC2IF) == 0) + while (((sr = icup->tim->SR) & + (STM32_TIM_SR_CC2IF | STM32_TIM_SR_UIF)) == 0) ; - - /* Resetting capture flag.*/ - icup->tim->SR &= ~STM32_TIM_SR_CC2IF; } + /* Edge or overflow?*/ + result = (sr & STM32_TIM_SR_UIF) != 0 ? true : false; + /* Done, disabling interrupts again.*/ chSysLock(); + + /* Resetting all flags.*/ + icup->tim->SR &= ~(STM32_TIM_SR_CC1IF | + STM32_TIM_SR_CC2IF | + STM32_TIM_SR_UIF); + + return result; } /** @@ -648,18 +656,22 @@ void icu_lld_start_capture(ICUDriver *icup) { * @note In order to use this function notifications must be disabled. * * @param[in] icup pointer to the @p ICUDriver object + * @return The capture status. + * @retval false if the capture is successful. + * @retval true if a timer overflow occurred. * * @notapi */ -void icu_lld_wait_capture(ICUDriver *icup) { +bool icu_lld_wait_capture(ICUDriver *icup) { /* If the driver is still in the ICU_WAITING state then we need to wait for the first activation edge.*/ if (icup->state == ICU_WAITING) - icu_lld_wait_edge(icup); + if (icu_lld_wait_edge(icup)) + return true; /* This edge marks the availability of a capture result.*/ - icu_lld_wait_edge(icup); + return icu_lld_wait_edge(icup); } /** diff --git a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.h b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.h index 5b8b71d9f..c20d1bc7c 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.h +++ b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.h @@ -413,7 +413,7 @@ extern "C" { void icu_lld_start(ICUDriver *icup); void icu_lld_stop(ICUDriver *icup); void icu_lld_start_capture(ICUDriver *icup); - void icu_lld_wait_capture(ICUDriver *icup); + bool icu_lld_wait_capture(ICUDriver *icup); void icu_lld_stop_capture(ICUDriver *icup); void icu_lld_enable_notifications(ICUDriver *icup); void icu_lld_disable_notifications(ICUDriver *icup); diff --git a/os/hal/src/icu.c b/os/hal/src/icu.c index 9f7a6b6c6..481b8a6c6 100644 --- a/os/hal/src/icu.c +++ b/os/hal/src/icu.c @@ -136,15 +136,20 @@ void icuStartCapture(ICUDriver *icup) { * @brief Waits for a completed capture. * @note The operation could be performed in polled mode depending on. * @note In order to use this function notifications must be disabled. - * @pre The driver must be in @p ICU_WAITING or @p ICU_ACTIVE modes. + * @pre The driver must be in @p ICU_WAITING or @p ICU_ACTIVE states. * @post After the capture is available the driver is in @p ICU_ACTIVE - * mode. + * state. If a capture fails then the driver is in @p ICU_WAITING + * state. * * @param[in] icup pointer to the @p ICUDriver object + * @return The capture status. + * @retval false if the capture is successful. + * @retval true if a timer overflow occurred. * * @api */ -void icuWaitCapture(ICUDriver *icup) { +bool icuWaitCapture(ICUDriver *icup) { + bool result; osalDbgCheck(icup != NULL); @@ -153,9 +158,11 @@ void icuWaitCapture(ICUDriver *icup) { "invalid state"); osalDbgAssert(icuAreNotificationsEnabledX(icup) == false, "notifications enabled"); - icu_lld_wait_capture(icup); - icup->state = ICU_ACTIVE; + result = icu_lld_wait_capture(icup); + icup->state = result ? ICU_WAITING : ICU_ACTIVE; osalSysUnlock(); + + return result; } /**