aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-28 15:32:56 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-28 15:32:56 +0000
commitff676aee33d4061e9d8186a15ad72c78fa1466a0 (patch)
tree46f1c511db8f2bccf4d9e12dcafe59726b038811 /os/hal
parent6e6c6944fb7f82c837c34d6ab3be6bb3ba1a97f3 (diff)
downloadChibiOS-ff676aee33d4061e9d8186a15ad72c78fa1466a0.tar.gz
ChibiOS-ff676aee33d4061e9d8186a15ad72c78fa1466a0.tar.bz2
ChibiOS-ff676aee33d4061e9d8186a15ad72c78fa1466a0.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2848 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/dox/adc.dox4
-rw-r--r--os/hal/dox/can.dox4
-rw-r--r--os/hal/dox/gpt.dox7
-rw-r--r--os/hal/dox/hal.dox21
-rw-r--r--os/hal/dox/i2c.dox5
-rw-r--r--os/hal/dox/icu.dox115
-rw-r--r--os/hal/dox/pwm.dox3
-rw-r--r--os/hal/dox/spi.dox6
-rw-r--r--os/hal/dox/uart.dox4
-rw-r--r--os/hal/dox/usb.dox4
-rw-r--r--os/hal/include/icu.h131
-rw-r--r--os/hal/platforms/STM32/icu_lld.c221
-rw-r--r--os/hal/platforms/STM32/icu_lld.h230
-rw-r--r--os/hal/src/icu.c151
-rw-r--r--os/hal/templates/icu_lld.c145
-rw-r--r--os/hal/templates/icu_lld.h136
16 files changed, 1160 insertions, 27 deletions
diff --git a/os/hal/dox/adc.dox b/os/hal/dox/adc.dox
index f5b83532d..0d6770f64 100644
--- a/os/hal/dox/adc.dox
+++ b/os/hal/dox/adc.dox
@@ -21,8 +21,8 @@
/**
* @defgroup ADC ADC Driver
* @brief Generic ADC Driver.
- * @details This module implements a generic ADC driver supporting a
- * variety of buffer and conversion modes.
+ * @details This module implements a generic ADC (Analog to Digital Converter)
+ * driver supporting a variety of buffer and conversion modes.
* @pre In order to use the ADC driver the @p HAL_USE_ADC option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/dox/can.dox b/os/hal/dox/can.dox
index f32630442..1a0c81c0d 100644
--- a/os/hal/dox/can.dox
+++ b/os/hal/dox/can.dox
@@ -21,8 +21,8 @@
/**
* @defgroup CAN CAN Driver
* @brief Generic CAN Driver.
- * @details This module implements a generic CAN driver allowing the exchange
- * of information at frame level.
+ * @details This module implements a generic CAN (Controller Area Network)
+ * driver allowing the exchange of information at frame level.
* @pre In order to use the CAN driver the @p HAL_USE_CAN option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/dox/gpt.dox b/os/hal/dox/gpt.dox
index 203f7a647..d51ad6af3 100644
--- a/os/hal/dox/gpt.dox
+++ b/os/hal/dox/gpt.dox
@@ -21,9 +21,10 @@
/**
* @defgroup GPT GPT Driver
* @brief Generic GPT Driver.
- * @details This module implements a generic timer driver. The timer can be
- * programmed in order to trigger callbacks after a specified time
- * period or continuously with a specified interval.
+ * @details This module implements a generic GPT (General Purpose Timer)
+ * driver. The timer can be programmed in order to trigger callbacks
+ * after a specified time period or continuously with a specified
+ * interval.
* @pre In order to use the GPT driver the @p HAL_USE_GPT option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/dox/hal.dox b/os/hal/dox/hal.dox
index d08f10bcd..15b4401fb 100644
--- a/os/hal/dox/hal.dox
+++ b/os/hal/dox/hal.dox
@@ -20,16 +20,17 @@
/**
* @defgroup HAL HAL Driver
- * @brief Hardware Abstraction Layer.
- * @details The HAL driver performs the system initialization and includes
- * the platform support code shared by the other drivers. This driver does
- * contain any API function except for a general initialization function
- * @p halInit() that must be invoked before any HAL service can be used,
- * usually the HAL initialization should be performed immediately before the
- * kernel initialization.<br>
- * Some HAL driver implementations also offer a custom early clock
- * setum function that can be invoked before the C runtime initialization
- * in order to accellerate the startup time.
+ * @brief Hardware Abstraction Layer.
+ * @details The HAL (Hardware Abstraction Layer) driver performs the system
+ * initialization and includes the platform support code shared by
+ * the other drivers. This driver does contain any API function
+ * except for a general initialization function @p halInit() that
+ * must be invoked before any HAL service can be used, usually the
+ * HAL initialization should be performed immediately before the
+ * kernel initialization.<br>
+ * Some HAL driver implementations also offer a custom early clock
+ * setup function that can be invoked before the C runtime
+ * initialization in order to accelerate the startup time.
*
* @ingroup IO
*/
diff --git a/os/hal/dox/i2c.dox b/os/hal/dox/i2c.dox
index 391fbb62e..1ffd2da47 100644
--- a/os/hal/dox/i2c.dox
+++ b/os/hal/dox/i2c.dox
@@ -20,8 +20,9 @@
/**
* @defgroup I2C I2C Driver
- * @brief Generic I2C Driver.
- * @details This module implements a generic I2C driver.
+ * @brief Generic I2C Driver.
+ * @details This module implements a generic I2C (Inter-Integrated Circuit)
+ * driver.
* @pre In order to use the I2C driver the @p HAL_USE_I2C option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/dox/icu.dox b/os/hal/dox/icu.dox
new file mode 100644
index 000000000..c90dc237d
--- /dev/null
+++ b/os/hal/dox/icu.dox
@@ -0,0 +1,115 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @defgroup ICU ICU Driver
+ * @brief Generic ICU Driver.
+ * @details This module implements a generic ICU (Input Capture Unit) driver.
+ * @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"];
+ idle [label="ICU_IDLE"];
+
+ uninit -> stop [label=" icuInit()", constraint=false];
+ stop -> stop [label="\nicuStop()"];
+ stop -> ready [label="\nicuStart()"];
+ ready -> stop [label="\nicuStop()"];
+ ready -> ready [label="\nicuStart()\nicuDisable()"];
+ ready -> waiting [label="\nicuEnable()"];
+ waiting -> active [label="\nStart Front"];
+ waiting -> ready [label="\nicuDisable()"];
+ active -> idle [label="\nStop Front\n>width_cb<"];
+ active -> ready [label="\nicuDisable()\nicuDisableI()"];
+ idle -> active [label="\nStart Front\n>period_cb<"];
+ idle -> ready [label="\nicuDisable()\nicuDisableI()"];
+ }
+ * @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"];
+ idle [label="ICU_IDLE"];
+
+ uninit -> stop [label=" icuInit()", constraint=false];
+ stop -> stop [label="\nicuStop()"];
+ stop -> ready [label="\nicuStart()"];
+ ready -> stop [label="\nicuStop()"];
+ ready -> ready [label="\nicuStart()\nicuDisable()"];
+ ready -> waiting [label="\nicuEnable()"];
+ waiting -> active [label="\nStart Front"];
+ waiting -> ready [label="\nicuDisable()"];
+ active -> idle [label="\nStop Front\n>width_cb<"];
+ active -> ready [label="\nicuDisable()\nicuDisableI()"];
+ idle -> active [label="\nStart Front\n>period_cb<"];
+ idle -> ready [label="\nicuDisable()\nicuDisableI()"];
+ }
+ * @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:
+ * - <b>ICU_INPUT_ACTIVE_HIGH</b>, a rising edge is the start signal.
+ * - <b>ICU_INPUT_ACTIVE_LOW</b>, a falling edge is the start signal.
+ * .
+ * After the activation the ICU unit can be in one of the following
+ * states at any time:
+ * - <b>ICU_WAITING</b>, waiting the first start signal.
+ * - <b>ICU_ACTIVE</b>, after a start signal.
+ * - <b>ICU_IDLE</b>, after a stop signal.
+ * .
+ * Callbacks are invoked when start or stop signals occur.
+ *
+ * @ingroup IO
+ */
diff --git a/os/hal/dox/pwm.dox b/os/hal/dox/pwm.dox
index 3f2bdfd71..fbf61ca9f 100644
--- a/os/hal/dox/pwm.dox
+++ b/os/hal/dox/pwm.dox
@@ -21,7 +21,8 @@
/**
* @defgroup PWM PWM Driver
* @brief Generic PWM Driver.
- * @details This module implements a 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.
*
diff --git a/os/hal/dox/spi.dox b/os/hal/dox/spi.dox
index cd462b8ae..047ff646e 100644
--- a/os/hal/dox/spi.dox
+++ b/os/hal/dox/spi.dox
@@ -21,9 +21,9 @@
/**
* @defgroup SPI SPI Driver
* @brief Generic SPI Driver.
- * @details This module implements a generic SPI driver allowing bidirectional
- * and monodirectional transfers, complex atomic transactions are
- * supported as well.
+ * @details This module implements a generic SPI (Serial Peripheral Interface)
+ * driver allowing bidirectional and monodirectional transfers,
+ * complex atomic transactions are supported as well.
* @pre In order to use the SPI driver the @p HAL_USE_SPI option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/dox/uart.dox b/os/hal/dox/uart.dox
index fe7a31534..7fea38dcb 100644
--- a/os/hal/dox/uart.dox
+++ b/os/hal/dox/uart.dox
@@ -21,8 +21,8 @@
/**
* @defgroup UART UART Driver
* @brief Generic UART Driver.
- * @details This driver abstracts a generic UART peripheral, the API is
- * designed to be:
+ * @details This driver abstracts a generic UART (Universal Asynchronous
+ * Receiver Transmitter) peripheral, the API is designed to be:
* - Unbuffered and copy-less, transfers are always directly performed
* from/to the application-level buffers without extra copy
* operations.
diff --git a/os/hal/dox/usb.dox b/os/hal/dox/usb.dox
index ebf2042a0..62b3aaf12 100644
--- a/os/hal/dox/usb.dox
+++ b/os/hal/dox/usb.dox
@@ -21,8 +21,8 @@
/**
* @defgroup USB USB Driver
* @brief Generic USB Driver.
- * @details This module implements a generic USB driver supporting device-mode
- * operations.
+ * @details This module implements a generic USB (Universal Serial Bus) driver
+ * supporting device-mode operations.
* @pre In order to use the USB driver the @p HAL_USE_USB option
* must be enabled in @p halconf.h.
*
diff --git a/os/hal/include/icu.h b/os/hal/include/icu.h
new file mode 100644
index 000000000..1f4e58ece
--- /dev/null
+++ b/os/hal/include/icu.h
@@ -0,0 +1,131 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file icu.h
+ * @brief ICU Driver macros and structures.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#ifndef _ICU_H_
+#define _ICU_H_
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Driver state machine possible states.
+ */
+typedef enum {
+ ICU_UNINIT = 0, /**< Not initialized. */
+ ICU_STOP = 1, /**< Stopped. */
+ ICU_READY = 2, /**< Ready. */
+ ICU_WAITING = 3, /**< Waiting first edge. */
+ ICU_ACTIVE = 4, /**< Active cycle phase. */
+ ICU_IDLE = 5, /**< Idle cycle phase. */
+} icustate_t;
+
+#include "icu_lld.h"
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @iclass
+ */
+void icuEnableI(icup) icu_lld_enable(icup)
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @iclass
+ */
+void icuDisableI(ICUDriver *icup) icu_lld_disable(icup)
+
+/**
+ * @brief Returns the width of the latest pulse.
+ * @details The pulse width is defined as number of ticks between the start
+ * edge and the stop edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @iclass
+ */
+#define icuGetWidthI(icup) icu_lld_get_width(icup)
+
+/**
+ * @brief Returns the width of the latest cycle.
+ * @details The cycle width is defined as number of ticks between a start
+ * edge and the next start edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @iclass
+ */
+#define icuGetPeriodI(icup) icu_lld_get_period(icup)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void icuInit(void);
+ void icuObjectInit(ICUDriver *icup);
+ void icuStart(ICUDriver *icup, const ICUConfig *config);
+ void icuStop(ICUDriver *icup);
+ void icuEnableI(ICUDriver *icup);
+ void icuDisableI(ICUDriver *icup);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ICU */
+
+#endif /* _ICU_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/icu_lld.c b/os/hal/platforms/STM32/icu_lld.c
new file mode 100644
index 000000000..6877b2d72
--- /dev/null
+++ b/os/hal/platforms/STM32/icu_lld.c
@@ -0,0 +1,221 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/icu_lld.c
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU1 driver identifier.
+ * @note The driver ICUD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__)
+ICUDriver ICUD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1
+/**
+ * @brief TIM1 update interrupt handler.
+ * @note It is assumed that this interrupt is only activated if the callback
+ * pointer is not equal to @p NULL in order to not perform an extra
+ * check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM1_UP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ TIM1->SR = ~TIM_SR_UIF;
+ ICUD1.config->callback(&ICUD1);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief TIM1 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM1_CC_IRQHandler) {
+ uint16_t sr;
+
+ CH_IRQ_PROLOGUE();
+
+ sr = TIM1->SR & TIM1->DIER;
+ TIM1->SR = ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF);
+ if ((sr & TIM_SR_CC1IF) != 0)
+ ICUD1.config->channels[0].callback(&ICUD1);
+ if ((sr & TIM_SR_CC2IF) != 0)
+ ICUD1.config->channels[1].callback(&ICUD1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM1 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ICU driver initialization.
+ *
+ * @notapi
+ */
+void icu_lld_init(void) {
+
+#if STM32_ICU_USE_TIM1
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD1);
+ ICUD1.tim = TIM1;
+#endif
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_start(ICUDriver *icup) {
+
+ if (icup->state == ICU_STOP) {
+ /* Clock activation and timer reset.*/
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+ RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
+ RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
+ RCC->APB2RSTR = 0;
+ NVICEnableVector(TIM1_UP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
+ NVICEnableVector(TIM1_CC_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
+ }
+#endif
+ }
+
+ /* Timer configuration, PWM input mode.*/
+ icup->tim->CR1 = 0; /* Initially stopped. */
+ icup->tim->CR2 = 0;
+ icup->tim->ARR = 0xFFFF;
+ icup->tim->PSC = icup->config->psc; /* Prescaler value. */
+ icup->tim->DIER = 0;
+ /* CCMR1_CC1S = 01 = CH1 Input on TI1.
+ CCMR1_CC2S = 10 = CH2 Input on TI2.*/
+ icup->tim->CCMR1 = TIM_CCMR1_CC1S_0 |
+ TIM_CCMR1_CC2S_1;
+ /* SMCR_TS = 101, input is TI1FP1.
+ SMCR_SMS = 100, reset on rising edge.*/
+ icup->tim->SMCR = TIM_SMCR_TS_2 | TIM_SMCR_TS_0 |
+ TIM_SMCR_SMS_2.
+ /* The CCER settings depend on the selected trigger mode.
+ ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
+ ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
+ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
+ icup->tim->CCER = TIM_CCER_CC1E |
+ TIM_CCER_CC2E | TIM_CCER_CC2P;
+ else
+ icup->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P
+ TIM_CCER_CC2E;
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_stop(ICUDriver *icup) {
+
+ if (icup->state == ICU_READY) {
+ /* Clock deactivation.*/
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->DIER = 0; /* All IRQs disabled. */
+
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+ NVICDisableVector(TIM1_UP_IRQn);
+ RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_enable(ICUDriver *icup) {
+
+ icup->tim->SR = 0; /* Clear pending IRQs (if any). */
+ icup->tim->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
+ icup->tim->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
+}
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_disable(ICUDriver *icup) {
+
+ icup->tim->CR1 = 0; /* Initially stopped. */
+ icup->tim->SR = 0; /* Clear pending IRQs (if any). */
+ icup->tim->DIER = 0; /* Interrupts disabled. */
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/icu_lld.h b/os/hal/platforms/STM32/icu_lld.h
new file mode 100644
index 000000000..78efa9765
--- /dev/null
+++ b/os/hal/platforms/STM32/icu_lld.h
@@ -0,0 +1,230 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/icu_lld.h
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#ifndef _ICU_LLD_H_
+#define _ICU_LLD_H_
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief ICUD1 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM1 TRUE
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if !STM32_ICU_USE_TIM1 && !STM32_ICU_USE_TIM2 && \
+ !STM32_ICU_USE_TIM3 && !STM32_ICU_USE_TIM4 && \
+ !STM32_ICU_USE_TIM5
+#error "ICU driver activated but no TIM peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU driver mode.
+ */
+typedef enum {
+ ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
+ ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
+} icumode_t;
+
+/**
+ * @brief ICU counter type.
+ */
+typedef uint16_t icucnt_t;
+
+/**
+ * @brief Type of a structure representing an ICU driver.
+ */
+typedef struct ICUDriver ICUDriver;
+
+/**
+ * @brief ICU notification callback type.
+ *
+ * @param[in] icup pointer to a @p ICUDriver object
+ */
+typedef void (*icucallback_t)(ICUDriver *icup);
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Driver mode.
+ */
+ icumode_t mode;
+ /**
+ * @brief Callback for pulse width measurement.
+ */
+ icucallback_t width_cb;
+ /**
+ * @brief Callback for cycle period measurement.
+ */
+ icucallback_t period_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief TIM PSC (pre-scaler) register initialization data.
+ */
+ uint16_t psc;
+} ICUConfig;
+
+/**
+ * @brief Structure representing an ICU driver.
+ */
+struct ICUDriver {
+ /**
+ * @brief Driver state.
+ */
+ icustate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const ICUConfig *config;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ TIM_TypeDef *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+
+/**
+ * @brief Returns the width of the latest pulse.
+ * @details The pulse width is defined as number of ticks between the start
+ * edge and the stop edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_width(icup) ((icup)->tim->CCR2)
+
+/**
+ * @brief Returns the width of the latest cycle.
+ * @details The cycle width is defined as number of ticks between a start
+ * edge and the next start edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_period(icup) ((icup)->tim->CCR1)
+
+/**
+ * @brief ICU clock prescaler initialization utility.
+ * @note The real clock value is rounded to the lower valid value, please
+ * make sure that the source clock frequency is a multiple of the
+ * requested ICU clock frequency.
+ * @note The calculated value must fit into an unsigned 16 bits integer.
+ *
+ * @param[in] clksrc clock source frequency, depending on the target timer
+ * cell it can be one of:
+ * - STM32_TIMCLK1
+ * - STM32_TIMCLK2
+ * .
+ * Please refer to the STM32 HAL driver documentation
+ * and/or the STM32 Reference Manual for the right clock
+ * source.
+ * @param[in] icuclk ICU clock frequency in cycles
+ * @return The value to be stored in the @p psc field of the
+ * @p ICUConfig structure.
+ */
+#define ICU_COMPUTE_PSC(clksrc, icuclk) \
+ ((uint16_t)(((clksrc) / (icuclk)) - 1))
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void icu_lld_init(void);
+ void icu_lld_start(ICUDriver *icup);
+ void icu_lld_stop(ICUDriver *icup);
+ void icu_lld_enable(ICUDriver *icup);
+ void icu_lld_disable(ICUDriver *icup);
+ icucnt_t icu_lld_get_width(ICUDriver *icup);
+ icucnt_t icu_lld_get_period(ICUDriver *icup);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ICU */
+
+#endif /* _ICU_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/src/icu.c b/os/hal/src/icu.c
new file mode 100644
index 000000000..3be67448e
--- /dev/null
+++ b/os/hal/src/icu.c
@@ -0,0 +1,151 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file icu.c
+ * @brief ICU Driver code.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void icuInit(void) {
+
+ icu_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p ICUDriver structure.
+ *
+ * @param[out] icup pointer to the @p ICUDriver object
+ *
+ * @init
+ */
+void icuObjectInit(ICUDriver *icup) {
+
+ icup->state = ICU_STOP;
+ icup->config = NULL;
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @param[in] config pointer to the @p ICUConfig object
+ *
+ * @api
+ */
+void icuStart(ICUDriver *icup, const ICUConfig *config) {
+
+ chDbgCheck((icup != NULL) && (config != NULL), "icuStart");
+
+ chSysLock();
+ chDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY),
+ "icuStart(), #1", "invalid state");
+ icup->config = config;
+ icu_lld_start(icup);
+ icup->state = ICU_READY;
+ chSysUnlock();
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuStop(ICUDriver *icup) {
+
+ chDbgCheck(icup != NULL, "icuStop");
+
+ chSysLock();
+ chDbgAssert((icup->state == ICU_STOP) || (icup->state == ICU_READY),
+ "icuStop(), #1", "invalid state");
+ icu_lld_stop(icup);
+ icup->state = ICU_STOP;
+ chSysUnlock();
+}
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuEnable(ICUDriver *icup) {
+
+ chSysLock();
+ chDbgAssert(icup->state == ICU_READY, "icuEnable(), #1", "invalid state");
+ icu_lld_enable(icup);
+ icup->state = ICU_WAITING;
+ chSysUnlock();
+}
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @api
+ */
+void icuDisable(ICUDriver *icup) {
+
+ chSysLock();
+ chDbgAssert((icup->state == ICU_READY) || (icup->state == ICU_WAITING) ||
+ (icup->state == ICU_ACTIVE) || (icup->state == ICU_IDLE),
+ "icuDisable(), #1", "invalid state");
+ icu_lld_disable(icup);
+ icup->state = ICU_READY;
+ chSysUnlock();
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/os/hal/templates/icu_lld.c b/os/hal/templates/icu_lld.c
new file mode 100644
index 000000000..3611c1baa
--- /dev/null
+++ b/os/hal/templates/icu_lld.c
@@ -0,0 +1,145 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file templates/icu_lld.c
+ * @brief ICU Driver subsystem low level driver source template.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ICU driver initialization.
+ *
+ * @notapi
+ */
+void icu_lld_init(void) {
+
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_start(ICUDriver *icup) {
+
+ if (icup->state == ICU_STOP) {
+ /* Clock activation.*/
+ }
+ /* Configuration.*/
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_stop(ICUDriver *icup) {
+
+ if (icup->state == ICU_READY) {
+ /* Clock deactivation.*/
+
+ }
+}
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_enable(ICUDriver *icup) {
+
+}
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_disable(ICUDriver *icup) {
+
+}
+
+/**
+ * @brief Returns the width of the latest pulse.
+ * @details The pulse width is defined as number of ticks between the start
+ * edge and the stop edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+icucnt_t icu_lld_get_width(icup) {
+
+}
+
+/**
+ * @brief Returns the width of the latest cycle.
+ * @details The cycle width is defined as number of ticks between a start
+ * edge and the next start edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+icucnt_t icu_lld_get_period(icup) {
+
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/os/hal/templates/icu_lld.h b/os/hal/templates/icu_lld.h
new file mode 100644
index 000000000..b0debb2b9
--- /dev/null
+++ b/os/hal/templates/icu_lld.h
@@ -0,0 +1,136 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file templates/icu_lld.h
+ * @brief ICU Driver subsystem low level driver header template.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#ifndef _ICU_LLD_H_
+#define _ICU_LLD_H_
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU driver mode.
+ */
+typedef enum {
+ ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
+ ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
+} icumode_t;
+
+/**
+ * @brief ICU counter type.
+ */
+typedef uint16_t icucnt_t;
+
+/**
+ * @brief Type of a structure representing an ICU driver.
+ */
+typedef struct ICUDriver ICUDriver;
+
+/**
+ * @brief ICU notification callback type.
+ *
+ * @param[in] icup pointer to a @p ICUDriver object
+ */
+typedef void (*icucallback_t)(ICUDriver *icup);
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Driver mode.
+ */
+ icumode_t mode;
+ /**
+ * @brief Callback for pulse width measurement.
+ */
+ icucallback_t width_cb;
+ /**
+ * @brief Callback for cycle period measurement.
+ */
+ icucallback_t period_cb;
+ /* End of the mandatory fields.*/
+} ICUConfig;
+
+/**
+ * @brief Structure representing an ICU driver.
+ */
+struct ICUDriver {
+ /**
+ * @brief Driver state.
+ */
+ icustate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const ICUConfig *config;
+ /* End of the mandatory fields.*/
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void icu_lld_init(void);
+ void icu_lld_start(ICUDriver *icup);
+ void icu_lld_stop(ICUDriver *icup);
+ void icu_lld_enable(ICUDriver *icup);
+ void icu_lld_disable(ICUDriver *icup);
+ icucnt_t icu_lld_get_width(ICUDriver *icup);
+ icucnt_t icu_lld_get_period(ICUDriver *icup);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ICU */
+
+#endif /* _ICU_LLD_H_ */
+
+/** @} */