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. */ @@ -191,6 +191,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. */ @@ -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. */ diff --git a/readme.txt b/readme.txt index cbdf1be41..d7374f312 100644 --- a/readme.txt +++ b/readme.txt @@ -103,6 +103,8 @@ multiple timers used at same time. - NEW: Added board files and demo for Olimex LPC-P1343 (contributed by Johnny Halfmoon). +- NEW: Added handling of input 2 to the STM32 ICU driver (contributed by + Fabio). *** 2.3.5 *** - FIX: Fixed RTC compile problem on STM32F103 (bug 3468445). diff --git a/testhal/STM32F1xx/PWM-ICU/main.c b/testhal/STM32F1xx/PWM-ICU/main.c index 8ae149304..ab9cd8be2 100644 --- a/testhal/STM32F1xx/PWM-ICU/main.c +++ b/testhal/STM32F1xx/PWM-ICU/main.c @@ -53,19 +53,20 @@ icucnt_t last_width, last_period; static void icuwidthcb(ICUDriver *icup) { - last_width = icuGetWidthI(icup); + last_width = icuGetWidth(icup); } static void icuperiodcb(ICUDriver *icup) { - last_period = icuGetPeriodI(icup); + last_period = icuGetPeriod(icup); } static ICUConfig icucfg = { ICU_INPUT_ACTIVE_HIGH, 10000, /* 10KHz ICU clock frequency. */ icuwidthcb, - icuperiodcb + icuperiodcb, + ICU_CHANNEL_1 }; /* diff --git a/todo.txt b/todo.txt index 6a866d69a..fa1a32ba5 100644 --- a/todo.txt +++ b/todo.txt @@ -16,8 +16,10 @@ Within 2.5.x: * Handling of Virtual Timer callbacks out of critical zone. * Add normal API (not iclass) variants of the VT functions. * MMC_SPI driver speedup. -- Add the RTC service inside the kernel and port, remove from HAL. -- Add option to use the RTC counter instead of the systick counter into the +- MAC driver for STM32F107, STM32F2xx, STM32F4xx. +- USB driver model revision. +- STM32 OTG USB cell support for CL, F2, F4 devices. +- Add option to use another counter instead of the systick counter into the trace buffer. - Add a chSysIntegrityCheck() API to the kernel. - Add guard pages as extra stack checking mechanism. Guard pages should be @@ -28,15 +30,13 @@ Within 2.5.x: - Runtime errors manager in HAL. - Critical errors manager in HAL (to replace or complement assertions). - Streaming DAC/I2S driver model and STM32 implementation. -- USB driver model revision. -- MAC driver for STM32F107, STM32F2xx, STM32F4xx. -- STM32 OTG USB cell support for CL, F2, F4 devices. - Add ADC3 support to the STM32 ADC driver. - Update C++ wrapper. - FatFs 0.9x integration. - Nios II support. - LPC17xx support. - NUC120 support. +? Add the RTC service inside the kernel and port, remove from HAL. Within 2.x.x - Software I2C implementation using a GPT instance for timings.