aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2012-02-18 16:46:21 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2012-02-18 16:46:21 +0000
commit39fa1818ffe52d04832d5f5d25ae01fb7b6d514f (patch)
treeafbbb3a0cd9fe8f776c7b061a274acbc850f41a4 /os/hal
parent995e1f732e43a5b85e5961e9791977b0cada7c50 (diff)
downloadChibiOS-39fa1818ffe52d04832d5f5d25ae01fb7b6d514f.tar.gz
ChibiOS-39fa1818ffe52d04832d5f5d25ae01fb7b6d514f.tar.bz2
ChibiOS-39fa1818ffe52d04832d5f5d25ae01fb7b6d514f.zip
Improvements to the STM32 ICU driver.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3955 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/include/icu.h12
-rw-r--r--os/hal/platforms/STM32/icu_lld.c101
-rw-r--r--os/hal/platforms/STM32/icu_lld.h27
3 files changed, 108 insertions, 32 deletions
diff --git a/os/hal/include/icu.h b/os/hal/include/icu.h
index d01c18749..99cfc4e3c 100644
--- a/os/hal/include/icu.h
+++ b/os/hal/include/icu.h
@@ -103,25 +103,29 @@ typedef void (*icucallback_t)(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.
+ * @note This function is meant to be invoked from the width capture
+ * callback only.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
- * @iclass
+ * @special
*/
-#define icuGetWidthI(icup) icu_lld_get_width(icup)
+#define icuGetWidth(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.
+ * @note This function is meant to be invoked from the width capture
+ * callback only.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
- * @iclass
+ * @special
*/
-#define icuGetPeriodI(icup) icu_lld_get_period(icup)
+#define icuGetPeriod(icup) icu_lld_get_period(icup)
/** @} */
/**
diff --git a/os/hal/platforms/STM32/icu_lld.c b/os/hal/platforms/STM32/icu_lld.c
index 3d362a3be..2c641280f 100644
--- a/os/hal/platforms/STM32/icu_lld.c
+++ b/os/hal/platforms/STM32/icu_lld.c
@@ -101,10 +101,17 @@ static void icu_lld_serve_interrupt(ICUDriver *icup) {
sr = icup->tim->SR & icup->tim->DIER;
icup->tim->SR = 0;
- if ((sr & TIM_SR_CC1IF) != 0)
- _icu_isr_invoke_period_cb(icup);
- if ((sr & TIM_SR_CC2IF) != 0)
- _icu_isr_invoke_width_cb(icup);
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ if ((sr & TIM_SR_CC1IF) != 0)
+ _icu_isr_invoke_period_cb(icup);
+ if ((sr & TIM_SR_CC2IF) != 0)
+ _icu_isr_invoke_width_cb(icup);
+ } else {
+ if ((sr & TIM_SR_CC1IF) != 0)
+ _icu_isr_invoke_width_cb(icup);
+ if ((sr & TIM_SR_CC2IF) != 0)
+ _icu_isr_invoke_period_cb(icup);
+ }
}
/*===========================================================================*/
@@ -283,6 +290,10 @@ void icu_lld_init(void) {
void icu_lld_start(ICUDriver *icup) {
uint32_t psc;
+ chDbgAssert((icup->config->channel == ICU_CHANNEL_1) ||
+ (icup->config->channel == ICU_CHANNEL_2),
+ "icu_lld_start(), #1", "invalid input");
+
if (icup->state == ICU_STOP) {
/* Clock activation and timer reset.*/
#if STM32_ICU_USE_TIM1
@@ -359,23 +370,56 @@ void icu_lld_start(ICUDriver *icup) {
icup->tim->PSC = (uint16_t)psc;
icup->tim->ARR = 0xFFFF;
- /* CCMR1_CC1S = 01 = CH1 Input on TI1.
- CCMR1_CC2S = 10 = CH2 Input on TI1.*/
- 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;
+ chDbgAssert((icup->config->channel != ICU_CHANNEL_1) &&
+ (icup->config->channel != ICU_CHANNEL_2),
+ "icu_lld_start(), #2", "invalid channel");
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ /* Selected input 1.
+ CCMR1_CC1S = 01 = CH1 Input on TI1.
+ CCMR1_CC2S = 10 = CH2 Input on TI1.*/
+ 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;
+ /* Direct pointers to the capture registers in order to make reading
+ data faster from within callbacks.*/
+ icup->wccrp = &icup->tim->CCR[1];
+ icup->pccrp = &icup->tim->CCR[0];
+ } else {
+ /* Selected input 2.
+ CCMR1_CC1S = 10 = CH1 Input on TI2.
+ CCMR1_CC2S = 01 = CH2 Input on TI2.*/
+ icup->tim->CCMR1 = TIM_CCMR1_CC1S_1 |
+ TIM_CCMR1_CC2S_0;
+ /* SMCR_TS = 110, input is TI2FP2.
+ SMCR_SMS = 100, reset on rising edge.*/
+ icup->tim->SMCR = TIM_SMCR_TS_2 | TIM_SMCR_TS_1 |
+ 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_CC1P |
+ TIM_CCER_CC2E;
+ else
+ icup->tim->CCER = TIM_CCER_CC1E |
+ TIM_CCER_CC2E | TIM_CCER_CC2P;
+ /* Direct pointers to the capture registers in order to make reading
+ data faster from within callbacks.*/
+ icup->wccrp = &icup->tim->CCR[0];
+ icup->pccrp = &icup->tim->CCR[1];
+ }
}
/**
@@ -442,10 +486,17 @@ void icu_lld_stop(ICUDriver *icup) {
void icu_lld_enable(ICUDriver *icup) {
icup->tim->SR = 0; /* Clear pending IRQs (if any). */
- if (icup->config->period_cb != NULL)
- icup->tim->DIER |= TIM_DIER_CC1IE;
- if (icup->config->width_cb != NULL)
- icup->tim->DIER |= TIM_DIER_CC2IE;
+ if (icup->config->channel == ICU_CHANNEL_1) {
+ if (icup->config->period_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC1IE;
+ if (icup->config->width_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC2IE;
+ } else {
+ if (icup->config->width_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC1IE;
+ if (icup->config->period_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC2IE;
+ }
icup->tim->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
}
diff --git a/os/hal/platforms/STM32/icu_lld.h b/os/hal/platforms/STM32/icu_lld.h
index 5f53884cd..642de2a64 100644
--- a/os/hal/platforms/STM32/icu_lld.h
+++ b/os/hal/platforms/STM32/icu_lld.h
@@ -179,7 +179,7 @@
/*===========================================================================*/
/**
- * @brief ICU driver mode.
+ * @brief ICU driver mode.
*/
typedef enum {
ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
@@ -192,6 +192,14 @@ typedef enum {
typedef uint32_t icufreq_t;
/**
+ * @brief ICU channel.
+ */
+typedef enum {
+ ICU_CHANNEL_1 = 0, /**< Use TIMxCH1. */
+ ICU_CHANNEL_2 = 1, /**< Use TIMxCH2. */
+} icuchannel_t;
+
+/**
* @brief ICU counter type.
*/
typedef uint16_t icucnt_t;
@@ -220,6 +228,11 @@ typedef struct {
*/
icucallback_t period_cb;
/* End of the mandatory fields.*/
+ /**
+ * @brief Timer input channel to be used.
+ * @note Only inputs TIMx 1 and 2 are supported.
+ */
+ icuchannel_t channel;
} ICUConfig;
/**
@@ -246,6 +259,14 @@ struct ICUDriver {
* @brief Pointer to the TIMx registers block.
*/
stm32_tim_t *tim;
+ /**
+ * @bried CCR register used for width capture.
+ */
+ volatile uint32_t *wccrp;
+ /**
+ * @bried CCR register used for period capture.
+ */
+ volatile uint32_t *pccrp;
};
/*===========================================================================*/
@@ -262,7 +283,7 @@ struct ICUDriver {
*
* @notapi
*/
-#define icu_lld_get_width(icup) ((icup)->tim->CCR[1] + 1)
+#define icu_lld_get_width(icup) (*((icup)->wccrp) + 1)
/**
* @brief Returns the width of the latest cycle.
@@ -274,7 +295,7 @@ struct ICUDriver {
*
* @notapi
*/
-#define icu_lld_get_period(icup) ((icup)->tim->CCR[0] + 1)
+#define icu_lld_get_period(icup) (*((icup)->pccrp) + 1)
/*===========================================================================*/
/* External declarations. */