diff options
author | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2011-03-28 15:32:56 +0000 |
---|---|---|
committer | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2011-03-28 15:32:56 +0000 |
commit | ff676aee33d4061e9d8186a15ad72c78fa1466a0 (patch) | |
tree | 46f1c511db8f2bccf4d9e12dcafe59726b038811 /os/hal/platforms/STM32 | |
parent | 6e6c6944fb7f82c837c34d6ab3be6bb3ba1a97f3 (diff) | |
download | ChibiOS-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/platforms/STM32')
-rw-r--r-- | os/hal/platforms/STM32/icu_lld.c | 221 | ||||
-rw-r--r-- | os/hal/platforms/STM32/icu_lld.h | 230 |
2 files changed, 451 insertions, 0 deletions
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_ */
+
+/** @} */
|