From 494cd0f0953d131bb31dcda508abfbd4eaef9899 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Wed, 16 Dec 2009 15:48:50 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1425 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/pwm_lld.c | 79 +++++++++++++++++++++++++++++++++++++++- os/hal/platforms/STM32/pwm_lld.h | 22 +++++++++++ os/hal/src/pwm.c | 9 ++++- 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/os/hal/platforms/STM32/pwm_lld.c b/os/hal/platforms/STM32/pwm_lld.c index d816aa47a..3c9092ad5 100644 --- a/os/hal/platforms/STM32/pwm_lld.c +++ b/os/hal/platforms/STM32/pwm_lld.c @@ -46,10 +46,64 @@ PWMDriver PWMD1; /* Low Level Driver local functions. */ /*===========================================================================*/ +/** + * @brief Stops all channels. + * + * @param[in] pwmp pointer to a @p PWMDriver object + */ +void stop_channels(PWMDriver *pwmp) { + + pwmp->pd_enabled_channels = 0; /* All channels disabled. */ + pwmp->pd_tim->CCER = 0; /* Outputs disabled. */ + pwmp->pd_tim->CCMR1 = 0; /* Channels 1 and 2 frozen. */ + pwmp->pd_tim->CCMR2 = 0; /* Channels 3 and 4 frozen. */ +} + /*===========================================================================*/ /* Low Level Driver interrupt handlers. */ /*===========================================================================*/ +#if USE_STM32_PWM1 +/** + * @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. + */ +CH_IRQ_HANDLER(VectorA4) { + + CH_IRQ_PROLOGUE(); + + PWMD1.pd_config->pc_callback(); + + 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. + */ +CH_IRQ_HANDLER(VectorAC) { + uint16_t sr; + + CH_IRQ_PROLOGUE(); + + sr = TIM1->SR; + TIM1->SR &= ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF); + if ((sr & TIM_SR_CC1IF) != 0) + PWMD1.pd_channel_configs[0]->pcc_callback(); + if ((sr & TIM_SR_CC2IF) != 0) + PWMD1.pd_channel_configs[1]->pcc_callback(); + if ((sr & TIM_SR_CC3IF) != 0) + PWMD1.pd_channel_configs[2]->pcc_callback(); + if ((sr & TIM_SR_CC4IF) != 0) + PWMD1.pd_channel_configs[3]->pcc_callback(); + CH_IRQ_EPILOGUE(); +} +#endif /* USE_STM32_PWM1 */ + /*===========================================================================*/ /* Low Level Driver exported functions. */ /*===========================================================================*/ @@ -66,6 +120,8 @@ void pwm_lld_init(void) { /* Driver initialization.*/ pwmObjectInit(&PWMD1); + PWMD1.pd_enabled_channels = 0; + PWMD1.pd_tim = TIM1; #endif } @@ -81,12 +137,28 @@ void pwm_lld_start(PWMDriver *pwmp) { /* Clock activation.*/ #if USE_STM32_PWM1 if (&PWMD1 == pwmp) { + NVICEnableVector(TIM1_UP_IRQn, STM32_PWM1_IRQ_PRIORITY); NVICEnableVector(TIM1_CC_IRQn, STM32_PWM1_IRQ_PRIORITY); RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; } #endif } - /* Configuration.*/ + /* Reset channels.*/ + stop_channels(pwmp); + + /* Configuration or reconfiguration.*/ + pwmp->pd_tim->CR1 = pwmp->pd_config->pc_cr1; + pwmp->pd_tim->CR2 = pwmp->pd_config->pc_cr2; + pwmp->pd_tim->PSC = pwmp->pd_config->pc_psc; + pwmp->pd_tim->ARR = pwmp->pd_config->pc_arr; + pwmp->pd_tim->CNT = 0; + pwmp->pd_tim->EGR = TIM_EGR_UG; /* Update event. */ + pwmp->pd_tim->SR = 0; /* Clear pending IRQs. */ + if (pwmp->pd_config->pc_callback == NULL) + pwmp->pd_tim->DIER = 0; /* No IRQs. */ + else + pwmp->pd_tim->DIER = TIM_DIER_UIE; /* IRQ on update event. */ + pwmp->pd_tim->CR1 |= TIM_CR1_CEN; /* Starts the timer. */ } /** @@ -100,11 +172,16 @@ void pwm_lld_stop(PWMDriver *pwmp) { if (pwmp->pd_state == PWM_READY) { #if USE_STM32_PWM1 if (&PWMD1 == pwmp) { + NVICDisableVector(TIM1_UP_IRQn); NVICDisableVector(TIM1_CC_IRQn); RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN; } #endif } + + stop_channels(pwmp); + pwmp->pd_tim->CR1 = 0; + pwmp->pd_tim->DIER = 0; } /** diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h index 879012451..a48a93619 100644 --- a/os/hal/platforms/STM32/pwm_lld.h +++ b/os/hal/platforms/STM32/pwm_lld.h @@ -85,6 +85,24 @@ typedef struct { */ pwmcallback_t pc_callback; /* End of the mandatory fields.*/ + /** + * @brief TIM PSC (pre-scaler) register initialization data. + */ + uint16_t pc_psc; + /** + * @brief TIM ARR (auto-reload) register initialization data. + */ + uint16_t pc_arr; + /** + * @brief TIM CR1 register initialization data. + * @note The value of this field should normally be equal to zero. + */ + uint16_t pc_cr1; + /** + * @brief TIM CR2 register initialization data. + * @note The value of this field should normally be equal to zero. + */ + uint16_t pc_cr2; } PWMConfig; /** @@ -126,6 +144,10 @@ typedef struct { * @brief Bit mask of the enabled channels. */ uint32_t pd_enabled_channels; + /** + * @brief Pointer to the TIMx registers block. + */ + TIM_TypeDef *pd_tim; } PWMDriver; /*===========================================================================*/ diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c index ddae89d45..ad3c15728 100644 --- a/os/hal/src/pwm.c +++ b/os/hal/src/pwm.c @@ -88,6 +88,9 @@ void pwmStop(PWMDriver *pwmp) { /** * @brief Setups a PWM channel. + * @details Associates a configuration to a PWM channel, this operation is + * required before a channel can be enabled using + * @p pwmEnableChannel(). * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier @@ -123,7 +126,8 @@ void pwmEnableChannel(PWMDriver *pwmp, "pwmEnableChannel"); chSysLock(); - chDbgAssert(pwmp->pd_state == PWM_READY, + chDbgAssert((pwmp->pd_state == PWM_READY) && + (pwmp->pd_channel_configs[channel] != NULL), "pwmEnableChannel(), #1", "invalid state"); pwm_lld_enable_channel(pwmp, channel, width); chSysUnlock(); @@ -143,7 +147,8 @@ void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) { "pwmEnableChannel"); chSysLock(); - chDbgAssert(pwmp->pd_state == PWM_READY, + chDbgAssert((pwmp->pd_state == PWM_READY) && + (pwmp->pd_channel_configs[channel] != NULL), "pwmDisableChannel(), #1", "invalid state"); pwm_lld_disable_channel(pwmp, channel); chSysUnlock(); -- cgit v1.2.3