From 051dd3958373c27c9ffeb06da004dca0023003b6 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Mon, 1 Sep 2014 08:27:52 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7224 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/dox/icu.dox | 111 +++++++++++++++++++++++++++++++++ os/hal/dox/pwm.dox | 69 ++++++++++++++++++++ os/hal/include/icu.h | 6 +- os/hal/ports/STM32/LLD/TIMv1/icu_lld.c | 56 +++++++++++------ os/hal/src/icu.c | 6 +- 5 files changed, 218 insertions(+), 30 deletions(-) create mode 100644 os/hal/dox/icu.dox create mode 100644 os/hal/dox/pwm.dox (limited to 'os') diff --git a/os/hal/dox/icu.dox b/os/hal/dox/icu.dox new file mode 100644 index 000000000..520f320b8 --- /dev/null +++ b/os/hal/dox/icu.dox @@ -0,0 +1,111 @@ +/* + ChibiOS/HAL - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013,2014 Giovanni Di Sirio. + + This file is part of ChibiOS/HAL + + ChibiOS/HAL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @defgroup ICU ICU Driver + * @brief Generic ICU Driver. + * @details This module implements a generic ICU (Input Capture Unit) driver. + * The purpose of the driver is to measure period and duty cycle of + * an input digital signal (PWM input). + * @pre In order to use the ICU driver the @p HAL_USE_ICU option + * must be enabled in @p halconf.h. + * + * @section icu_1 Driver State Machine + * The driver implements a state machine internally, not all the driver + * functionalities can be used in any moment, any transition not explicitly + * shown in the following diagram has to be considered an error and shall + * be captured by an assertion (if enabled). + * @if LATEX_PDF + * @dot + digraph example { + size="5, 7"; + rankdir="LR"; + + node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; + edge [fontname=Sans, fontsize=8]; + + stop [label="ICU_STOP\nLow Power"]; + uninit [label="ICU_UNINIT", style="bold"]; + ready [label="ICU_READY\nClock Enabled"]; + waiting [label="ICU_WAITING"]; + active [label="ICU_ACTIVE"]; + + uninit -> stop [label=" icuInit()", constraint=false]; + stop -> stop [label="\nicuStop()"]; + stop -> ready [label="\nicuStart()"]; + ready -> stop [label="\nicuStop()"]; + ready -> ready [label="\nicuStart()\nicuStopCapture()"]; + ready -> waiting [label="\nicuStartCapture()"]; + waiting -> active [label="\nFirst Activation Edge\nicuWaitCapture()"]; + waiting -> ready [label="\nicuStopCapture()"]; + active -> ready [label="\nicuStopCapture()"]; + active -> active [label="\nActivation Edge\n>period_cb<"]; + active -> active [label="\nDe-activation Edge\n>width_cb<"]; + } + * @enddot + * @else + * @dot + digraph example { + rankdir="LR"; + + node [shape=circle, fontname=Sans, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; + edge [fontname=Sans, fontsize=8]; + + stop [label="ICU_STOP\nLow Power"]; + uninit [label="ICU_UNINIT", style="bold"]; + ready [label="ICU_READY\nClock Enabled"]; + waiting [label="ICU_WAITING"]; + active [label="ICU_ACTIVE"]; + + uninit -> stop [label=" icuInit()", constraint=false]; + stop -> stop [label="\nicuStop()"]; + stop -> ready [label="\nicuStart()"]; + ready -> stop [label="\nicuStop()"]; + ready -> ready [label="\nicuStart()\nicuStopCapture()"]; + ready -> waiting [label="\nicuStartCapture()"]; + waiting -> active [label="\nFirst Activation Edge\nicuWaitCapture()"]; + waiting -> ready [label="\nicuStopCapture()"]; + active -> ready [label="\nicuStopCapture()"]; + active -> active [label="\nActivation Edge\n>period_cb<"]; + active -> active [label="\nDe-activation Edge\n>width_cb<"]; + } + * @enddot + * @endif + * + * @section icu_2 ICU Operations. + * This driver abstracts a generic Input Capture Unit composed of: + * - A clock prescaler. + * - A main up counter. + * - Two capture registers triggered by the rising and falling edges on + * the sampled input. + * . + * The ICU unit can be programmed to synchronize on the rising or falling + * edge of the sample input: + * - ICU_INPUT_ACTIVE_HIGH, a rising edge is the start signal. + * - ICU_INPUT_ACTIVE_LOW, a falling edge is the start signal. + * . + * Callbacks are optionally invoked when: + * - On the PWM de-activation edge. + * - On the PWM activation edge, measurements for the previous cycle are + * available from this callback and can be retrieved using + * @p icuGetPeriodX() and @p icuGetWidthX(). + * . + * @ingroup IO + */ diff --git a/os/hal/dox/pwm.dox b/os/hal/dox/pwm.dox new file mode 100644 index 000000000..719cdc656 --- /dev/null +++ b/os/hal/dox/pwm.dox @@ -0,0 +1,69 @@ +/* + ChibiOS/HAL - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013,2014 Giovanni Di Sirio. + + This file is part of ChibiOS/HAL + + ChibiOS/HAL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @defgroup PWM PWM Driver + * @brief Generic PWM Driver. + * @details This module implements a generic PWM (Pulse Width Modulation) + * driver. + * @pre In order to use the PWM driver the @p HAL_USE_PWM option + * must be enabled in @p halconf.h. + * + * @section pwm_1 Driver State Machine + * The driver implements a state machine internally, not all the driver + * functionalities can be used in any moment, any transition not explicitly + * shown in the following diagram has to be considered an error and shall + * be captured by an assertion (if enabled). + * @dot + digraph example { + rankdir="LR"; + node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; + edge [fontname=Helvetica, fontsize=8]; + uninit [label="PWM_UNINIT", style="bold"]; + stop [label="PWM_STOP\nLow Power"]; + ready [label="PWM_READY\nClock Enabled"]; + uninit -> stop [label="pwmInit()"]; + stop -> stop [label="pwmStop()"]; + stop -> ready [label="pwmStart()"]; + ready -> stop [label="pwmStop()"]; + ready -> ready [label="pwmEnableChannel()\npwmDisableChannel()"]; + } + * @enddot + * + * @section pwm_2 PWM Operations. + * This driver abstracts a generic PWM timer composed of: + * - A clock prescaler. + * - A main up counter. + * - A comparator register that resets the main counter to zero when the limit + * is reached. An optional callback can be generated when this happens. + * - An array of @p PWM_CHANNELS PWM channels, each channel has an output, + * a comparator and is able to invoke an optional callback when a comparator + * match with the main counter happens. + * . + * A PWM channel output can be in two different states: + * - IDLE, when the channel is disabled or after a match occurred. + * - ACTIVE, when the channel is enabled and a match didn't occur yet + * in the current PWM cycle. + * . + * Note that the two states can be associated to both logical zero or one in + * the @p PWMChannelConfig structure. + * + * @ingroup IO + */ diff --git a/os/hal/include/icu.h b/os/hal/include/icu.h index 007226616..f07d4a76e 100644 --- a/os/hal/include/icu.h +++ b/os/hal/include/icu.h @@ -93,11 +93,7 @@ typedef void (*icucallback_t)(ICUDriver *icup); } while (0) /** - * @brief Waits for the next cycle activation edge. - * @details The function waits for the next PWM input activation front then - * brings the driver in the @p ICU_ACTIVE state. - * @note If notifications are enabled then the transition to the - * @p ICU_ACTIVE state is done automatically on the first edge. + * @brief Waits for a completed capture. * * @param[in] icup pointer to the @p ICUDriver object * diff --git a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c index d8bc2e84c..c11736884 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c +++ b/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c @@ -102,6 +102,34 @@ ICUDriver ICUD9; /* Driver local functions. */ /*===========================================================================*/ +static void icu_lld_wait_edge(ICUDriver *icup) { + + /* Polled mode so re-enabling the interrupts while the operation is + performed.*/ + chSysUnlock(); + + /* 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) + ; + + /* Resetting capture flag.*/ + icup->tim->SR &= ~STM32_TIM_SR_CC1IF; + } + else { + /* Waiting for an edge.*/ + while ((icup->tim->SR & STM32_TIM_SR_CC2IF) == 0) + ; + + /* Resetting capture flag.*/ + icup->tim->SR &= ~STM32_TIM_SR_CC2IF; + } + + /* Done, disabling interrupts again.*/ + chSysLock(); +} + /** * @brief Shared IRQ handler. * @@ -615,12 +643,9 @@ void icu_lld_start_capture(ICUDriver *icup) { } /** - * @brief Waits for the next cycle activation edge. - * @details The function waits for the next PWM input activation front then - * brings the driver in the @p ICU_ACTIVE state. - * @note If notifications are enabled then the transition to the - * @p ICU_ACTIVE state is done automatically on the first edge. + * @brief Waits for a completed capture. * @note The wait is performed in polled mode. + * @note The function cannot work if notifications are enabled. * * @param[in] icup pointer to the @p ICUDriver object * @@ -628,22 +653,13 @@ void icu_lld_start_capture(ICUDriver *icup) { */ void icu_lld_wait_capture(ICUDriver *icup) { - if (icup->config->channel == ICU_CHANNEL_1) { - /* Resetting capture flag.*/ - icup->tim->SR &= ~STM32_TIM_SR_CC1IF; - - /* Waiting for an edge.*/ - while ((icup->tim->SR & STM32_TIM_SR_CC1IF) == 0) - ; - } - else { - /* Resetting capture flag.*/ - icup->tim->SR &= ~STM32_TIM_SR_CC2IF; + /* 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); - /* Waiting for an edge.*/ - while ((icup->tim->SR & STM32_TIM_SR_CC2IF) == 0) - ; - } + /* This edge marks the availability of a capture result.*/ + icu_lld_wait_edge(icup); } /** diff --git a/os/hal/src/icu.c b/os/hal/src/icu.c index 298e1cb28..92f8a2f1e 100644 --- a/os/hal/src/icu.c +++ b/os/hal/src/icu.c @@ -133,11 +133,7 @@ void icuStartCapture(ICUDriver *icup) { } /** - * @brief Waits for the next cycle activation edge. - * @details The function waits for the next PWM input activation front then - * brings the driver in the @p ICU_ACTIVE state. - * @note If notifications are enabled then the transition to the - * @p ICU_ACTIVE state is done automatically on the first edge. + * @brief Waits for a completed capture. * * @param[in] icup pointer to the @p ICUDriver object * -- cgit v1.2.3