diff --git a/os/hal/include/ext.h b/os/hal/include/ext.h index 56e683019..37a7dcd15 100644 --- a/os/hal/include/ext.h +++ b/os/hal/include/ext.h @@ -36,7 +36,7 @@ /*===========================================================================*/ /** - * @name EXT channels modes + * @name EXT channel modes * @{ */ #define EXT_CH_MODE_EDGES_MASK 3 /**< @brief Mask of edges field. */ @@ -104,6 +104,27 @@ typedef struct EXTDriver EXTDriver; * @iclass */ #define extChannelDisableI(extp, channel) ext_lld_channel_disable(extp, channel) + +/** + * @brief Changes the operation mode of a channel. + * @note This function attempts to write over the current configuration + * structure that must have been not declared constant. This + * violates the @p const qualifier in @p extStart() but it is + * intentional. This function cannot be used if the configuration + * structure is declared @p const. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be changed + * @param[in] extcp new configuration for the channel + * + * @api + */ +#define extSetChannelMode(extp, channel, extcp) { \ + chSysLock(); \ + extSetChannelModeI(extp, channel, extcp); \ + chSysUnlock(); \ +} + /** @} */ /*===========================================================================*/ @@ -119,6 +140,9 @@ extern "C" { void extStop(EXTDriver *extp); void extChannelEnable(EXTDriver *extp, expchannel_t channel); void extChannelDisable(EXTDriver *extp, expchannel_t channel); + void extSetChannelModeI(EXTDriver *extp, + expchannel_t channel, + const EXTChannelConfig *extcp); #ifdef __cplusplus } #endif diff --git a/os/hal/platforms/STM32/ext_lld.c b/os/hal/platforms/STM32/ext_lld.c index 569262e75..4a3cd3c2e 100644 --- a/os/hal/platforms/STM32/ext_lld.c +++ b/os/hal/platforms/STM32/ext_lld.c @@ -430,7 +430,6 @@ void ext_lld_init(void) { */ void ext_lld_start(EXTDriver *extp) { unsigned i; - uint32_t imr, emr, rtsr, ftsr; if (extp->state == EXT_STOP) { /* Clock activation.*/ @@ -489,37 +488,12 @@ void ext_lld_start(EXTDriver *extp) { CORTEX_PRIORITY_MASK(STM32_EXT_EXTI18_IRQ_PRIORITY)); #endif } - /* Configuration.*/ - imr = emr = rtsr = ftsr = 0; - for (i = 0; i < EXT_MAX_CHANNELS; i++) { - if (extp->config->channels[i].mode & EXT_CH_MODE_AUTOSTART) { - if (extp->config->channels[i].cb != NULL) - imr |= (1 << i); - else - emr |= (1 << i); - if (extp->config->channels[i].mode & EXT_CH_MODE_RISING_EDGE) - rtsr |= (1 << i); - if (extp->config->channels[i].mode & EXT_CH_MODE_FALLING_EDGE) - ftsr |= (1 << i); - } - } -#if defined(STM32L1XX_MD) || defined(STM32F2XX) || defined(STM32F4XX) - SYSCFG->EXTICR[0] = extp->config->exti[0]; - SYSCFG->EXTICR[1] = extp->config->exti[1]; - SYSCFG->EXTICR[2] = extp->config->exti[2]; - SYSCFG->EXTICR[3] = extp->config->exti[3]; -#else /* STM32F1XX */ - AFIO->EXTICR[0] = extp->config->exti[0]; - AFIO->EXTICR[1] = extp->config->exti[1]; - AFIO->EXTICR[2] = extp->config->exti[2]; - AFIO->EXTICR[3] = extp->config->exti[3]; -#endif /* STM32F1XX */ - EXTI->SWIER = 0; - EXTI->RTSR = rtsr; - EXTI->FTSR = ftsr; - EXTI->PR = EXT_CHANNELS_MASK; - EXTI->EMR = emr; - EXTI->IMR = imr; + /* Configuration of automatic channels.*/ + for (i = 0; i < EXT_MAX_CHANNELS; i++) + if (extp->config->channels[i].mode & EXT_CH_MODE_AUTOSTART) + ext_lld_channel_enable(extp, i); + else + ext_lld_channel_disable(extp, i); } /** @@ -581,14 +555,40 @@ void ext_lld_stop(EXTDriver *extp) { */ void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) { - if (extp->config->channels[channel].cb != NULL) - EXTI->IMR |= (1 << channel); - else - EXTI->EMR |= (1 << channel); + /* Programming edge registers.*/ if (extp->config->channels[channel].mode & EXT_CH_MODE_RISING_EDGE) EXTI->RTSR |= (1 << channel); + else + EXTI->RTSR &= ~(1 << channel); if (extp->config->channels[channel].mode & EXT_CH_MODE_FALLING_EDGE) EXTI->FTSR |= (1 << channel); + else + EXTI->FTSR &= ~(1 << channel); + + /* Programming interrupt and event registers.*/ + if (extp->config->channels[channel].cb != NULL) { + EXTI->IMR |= (1 << channel); + EXTI->EMR &= ~(1 << channel); + } + else { + EXTI->EMR |= (1 << channel); + EXTI->IMR &= ~(1 << channel); + } + + /* Setting the associated GPIO for external channels.*/ + if (channel < 16) { + uint32_t n = channel & 3; + uint32_t mask = 0xF << (channel >> 2); + uint32_t port = ((extp->config->channels[channel].mode & + EXT_MODE_GPIO_MASK) >> + EXT_MODE_GPIO_OFF) << (channel >> 2); + +#if defined(STM32L1XX_MD) || defined(STM32F2XX) || defined(STM32F4XX) + SYSCFG->EXTICR[n] = (SYSCFG->EXTICR[n] & mask) | port; +#else /* STM32F1XX */ + AFIO->EXTICR[n] = (AFIO->EXTICR[n] & mask) | port; +#endif /* STM32F1XX */ + } } /** @@ -605,9 +605,7 @@ void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) { EXTI->IMR &= ~(1 << channel); EXTI->EMR &= ~(1 << channel); - EXTI->RTSR &= ~(1 << channel); - EXTI->FTSR &= ~(1 << channel); - EXTI->PR = (1 << channel); + EXTI->PR = (1 << channel); } #endif /* HAL_USE_EXT */ diff --git a/os/hal/platforms/STM32/ext_lld.h b/os/hal/platforms/STM32/ext_lld.h index 6ef14427b..60a77fc41 100644 --- a/os/hal/platforms/STM32/ext_lld.h +++ b/os/hal/platforms/STM32/ext_lld.h @@ -46,31 +46,20 @@ #define EXT_CHANNELS_MASK ((1 << EXT_MAX_CHANNELS) - 1) /** - * @name EXTI configuration helpers + * @name STM32-specific EXT channel modes * @{ */ -/** - * @brief EXTI-GPIO association macro. - * @details Helper macro to associate a GPIO to each of the Mx EXTI inputs. - */ -#define EXT_MODE_EXTI(m0, m1, m2, m3, m4, m5, m6, m7, \ - m8, m9, m10, m11, m12, m13, m14, m15) \ - { \ - ((m0) << 0) | ((m1) << 4) | ((m2) << 8) | ((m3) << 12), \ - ((m4) << 0) | ((m5) << 4) | ((m6) << 8) | ((m7) << 12), \ - ((m8) << 0) | ((m9) << 4) | ((m10) << 8) | ((m11) << 12), \ - ((m12) << 0) | ((m13) << 4) | ((m14) << 8) | ((m15) << 12) \ - } - -#define EXT_MODE_GPIOA 0 /**< @brief GPIOA identifier. */ -#define EXT_MODE_GPIOB 1 /**< @brief GPIOB identifier. */ -#define EXT_MODE_GPIOC 2 /**< @brief GPIOC identifier. */ -#define EXT_MODE_GPIOD 3 /**< @brief GPIOD identifier. */ -#define EXT_MODE_GPIOE 4 /**< @brief GPIOE identifier. */ -#define EXT_MODE_GPIOF 5 /**< @brief GPIOF identifier. */ -#define EXT_MODE_GPIOG 6 /**< @brief GPIOG identifier. */ -#define EXT_MODE_GPIOH 7 /**< @brief GPIOH identifier. */ -#define EXT_MODE_GPIOI 8 /**< @brief GPIOI identifier. */ +#define EXT_MODE_GPIO_MASK 0xF0 /**< @bried Port field mask. */ +#define EXT_MODE_GPIO_OFF 4 /**< @bried Port field offset. */ +#define EXT_MODE_GPIOA 0x00 /**< @brief GPIOA identifier. */ +#define EXT_MODE_GPIOB 0x10 /**< @brief GPIOB identifier. */ +#define EXT_MODE_GPIOC 0x20 /**< @brief GPIOC identifier. */ +#define EXT_MODE_GPIOD 0x30 /**< @brief GPIOD identifier. */ +#define EXT_MODE_GPIOE 0x40 /**< @brief GPIOE identifier. */ +#define EXT_MODE_GPIOF 0x50 /**< @brief GPIOF identifier. */ +#define EXT_MODE_GPIOG 0x60 /**< @brief GPIOG identifier. */ +#define EXT_MODE_GPIOH 0x70 /**< @brief GPIOH identifier. */ +#define EXT_MODE_GPIOI 0x80 /**< @brief GPIOI identifier. */ /** @} */ /*===========================================================================*/ @@ -228,10 +217,6 @@ typedef struct { */ EXTChannelConfig channels[EXT_MAX_CHANNELS]; /* End of the mandatory fields.*/ - /** - * @brief Initialization values for EXTICRx registers. - */ - uint16_t exti[4]; } EXTConfig; /** diff --git a/os/hal/src/ext.c b/os/hal/src/ext.c index e89962dea..bd175d483 100644 --- a/os/hal/src/ext.c +++ b/os/hal/src/ext.c @@ -120,6 +120,7 @@ void extStop(EXTDriver *extp) { /** * @brief Enables an EXT channel. + * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. * * @param[in] extp pointer to the @p EXTDriver object * @param[in] channel channel to be enabled @@ -128,13 +129,13 @@ void extStop(EXTDriver *extp) { */ void extChannelEnable(EXTDriver *extp, expchannel_t channel) { - chDbgCheck((extp != NULL) && - (channel < EXT_MAX_CHANNELS) && - (extp->config->channels[channel].mode != EXT_CH_MODE_DISABLED), + chDbgCheck((extp != NULL) && (channel < EXT_MAX_CHANNELS), "extChannelEnable"); chSysLock(); - chDbgAssert(extp->state == EXT_ACTIVE, + chDbgAssert((extp->state == EXT_ACTIVE) && + ((extp->config->channels[channel].mode & + EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), "extChannelEnable(), #1", "invalid state"); extChannelEnableI(extp, channel); chSysUnlock(); @@ -142,6 +143,7 @@ void extChannelEnable(EXTDriver *extp, expchannel_t channel) { /** * @brief Disables an EXT channel. + * @pre The channel must not be in @p EXT_CH_MODE_DISABLED mode. * * @param[in] extp pointer to the @p EXTDriver object * @param[in] channel channel to be disabled @@ -150,18 +152,59 @@ void extChannelEnable(EXTDriver *extp, expchannel_t channel) { */ void extChannelDisable(EXTDriver *extp, expchannel_t channel) { - chDbgCheck((extp != NULL) && - (channel < EXT_MAX_CHANNELS) && - (extp->config->channels[channel].mode != EXT_CH_MODE_DISABLED), + chDbgCheck((extp != NULL) && (channel < EXT_MAX_CHANNELS), "extChannelDisable"); chSysLock(); - chDbgAssert(extp->state == EXT_ACTIVE, + chDbgAssert((extp->state == EXT_ACTIVE) && + ((extp->config->channels[channel].mode & + EXT_CH_MODE_EDGES_MASK) != EXT_CH_MODE_DISABLED), "extChannelDisable(), #1", "invalid state"); extChannelDisableI(extp, channel); chSysUnlock(); } +/** + * @brief Changes the operation mode of a channel. + * @note This function attempts to write over the current configuration + * structure that must have been not declared constant. This + * violates the @p const qualifier in @p extStart() but it is + * intentional. + * @note This function cannot be used if the configuration structure is + * declared @p const. + * @note The effect of this function on constant configuration structures + * is not defined. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be changed + * @param[in] extcp new configuration for the channel + * + * @iclass + */ +void extSetChannelModeI(EXTDriver *extp, + expchannel_t channel, + const EXTChannelConfig *extcp) { + EXTChannelConfig *oldcp; + + chDbgCheck((extp != NULL) && (channel < EXT_MAX_CHANNELS) && + (extcp != NULL), "extSetChannelModeI"); + + /* Note that here the access is enforced as non-const, known access + violation.*/ + oldcp = (EXTChannelConfig *)&extp->config->channels[channel]; + + chSysLock(); + + chDbgAssert(extp->state == EXT_ACTIVE, + "extSetChannelModeI(), #1", "invalid state"); + + /* Overwiting the old channels configuration then the channel is reconfigured + by the low level driver.*/ + *oldcp = *extcp; + ext_lld_channel_enable(extp, channel); + chSysUnlock(); +} + #endif /* HAL_USE_EXT */ /** @} */ diff --git a/readme.txt b/readme.txt index cbe7d6e81..23b72f607 100644 --- a/readme.txt +++ b/readme.txt @@ -113,6 +113,9 @@ 3484947)(backported to 2.4.1). - FIX: Fixed various minor documentation errors (bug 3484942)(backported to 2.4.1). +- NEW: EXT driver improved, now it is possible to reprogram channels at + runtime without necessarily specifying a new configuration. + TODO: Update AT91SAM7 EXT driver. - NEW: Integrated FatFS 0.9, now the FatFS integration files are centralized under ./os/various/fatfs_bindings and shared among all demos. The FatFS file ffconf.h is now application-specific like all the other configuration diff --git a/testhal/STM32F1xx/EXT/main.c b/testhal/STM32F1xx/EXT/main.c index e9e2e9090..0c71217ae 100644 --- a/testhal/STM32F1xx/EXT/main.c +++ b/testhal/STM32F1xx/EXT/main.c @@ -51,39 +51,23 @@ static void extcb2(EXTDriver *extp, expchannel_t channel) { static const EXTConfig extcfg = { { - {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART, extcb1}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, extcb2}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - }, - EXT_MODE_EXTI(EXT_MODE_GPIOA, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - EXT_MODE_GPIOC, - 0, - 0, - 0) + {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOC, extcb2}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL} + } }; /* diff --git a/testhal/STM32F4xx/EXT/main.c b/testhal/STM32F4xx/EXT/main.c index e79618715..2a6d7901c 100644 --- a/testhal/STM32F4xx/EXT/main.c +++ b/testhal/STM32F4xx/EXT/main.c @@ -46,33 +46,30 @@ static void extcb1(EXTDriver *extp, expchannel_t channel) { static const EXTConfig extcfg = { { - {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART, extcb1}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL} - }, - EXT_MODE_EXTI(EXT_MODE_GPIOA, /* Button.*/ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0) + {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL} + } }; /* diff --git a/testhal/STM32L1xx/EXT/main.c b/testhal/STM32L1xx/EXT/main.c index 84d57e682..88721db86 100644 --- a/testhal/STM32L1xx/EXT/main.c +++ b/testhal/STM32L1xx/EXT/main.c @@ -44,33 +44,30 @@ static void extcb1(EXTDriver *extp, expchannel_t channel) { static const EXTConfig extcfg = { { - {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART, extcb1}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL} - }, - EXT_MODE_EXTI(EXT_MODE_GPIOA, /* Button.*/ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0) + {EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL}, + {EXT_CH_MODE_DISABLED, NULL} + } }; /*