From a8863f265d188eb769257788beba012f672c909d Mon Sep 17 00:00:00 2001 From: gdisirio Date: Thu, 17 Dec 2009 15:40:32 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1426 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/pwm.h | 2 - os/hal/platforms/STM32/pwm_lld.c | 169 ++++++++++++++++++++++++++++----------- os/hal/platforms/STM32/pwm_lld.h | 51 +++++------- os/hal/src/pwm.c | 31 +------ 4 files changed, 146 insertions(+), 107 deletions(-) (limited to 'os/hal') diff --git a/os/hal/include/pwm.h b/os/hal/include/pwm.h index 55e890ea4..b48f067c9 100644 --- a/os/hal/include/pwm.h +++ b/os/hal/include/pwm.h @@ -62,8 +62,6 @@ extern "C" { void pwmObjectInit(PWMDriver *pwmp); void pwmStart(PWMDriver *pwmp, const PWMConfig *config); void pwmStop(PWMDriver *pwmp); - void pwmSetupChannel(PWMDriver *pwmp, pwmchannel_t channel, - const PWMChannelConfig *pccp); void pwmEnableChannel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width); diff --git a/os/hal/platforms/STM32/pwm_lld.c b/os/hal/platforms/STM32/pwm_lld.c index 3c9092ad5..b1e4f7bc3 100644 --- a/os/hal/platforms/STM32/pwm_lld.c +++ b/os/hal/platforms/STM32/pwm_lld.c @@ -55,6 +55,10 @@ void stop_channels(PWMDriver *pwmp) { pwmp->pd_enabled_channels = 0; /* All channels disabled. */ pwmp->pd_tim->CCER = 0; /* Outputs disabled. */ + pwmp->pd_tim->CCR1 = 0; /* Comparator 1 disabled. */ + pwmp->pd_tim->CCR2 = 0; /* Comparator 2 disabled. */ + pwmp->pd_tim->CCR3 = 0; /* Comparator 3 disabled. */ + pwmp->pd_tim->CCR4 = 0; /* Comparator 4 disabled. */ pwmp->pd_tim->CCMR1 = 0; /* Channels 1 and 2 frozen. */ pwmp->pd_tim->CCMR2 = 0; /* Channels 3 and 4 frozen. */ } @@ -93,13 +97,14 @@ CH_IRQ_HANDLER(VectorAC) { 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(); + PWMD1.pd_config->pc_channels[0].pcc_callback(); if ((sr & TIM_SR_CC2IF) != 0) - PWMD1.pd_channel_configs[1]->pcc_callback(); + PWMD1.pd_config->pc_channels[1].pcc_callback(); if ((sr & TIM_SR_CC3IF) != 0) - PWMD1.pd_channel_configs[2]->pcc_callback(); + PWMD1.pd_config->pc_channels[2].pcc_callback(); if ((sr & TIM_SR_CC4IF) != 0) - PWMD1.pd_channel_configs[3]->pcc_callback(); + PWMD1.pd_config->pc_channels[3].pcc_callback(); + CH_IRQ_EPILOGUE(); } #endif /* USE_STM32_PWM1 */ @@ -132,6 +137,7 @@ void pwm_lld_init(void) { * @param[in] pwmp pointer to a @p PWMDriver object */ void pwm_lld_start(PWMDriver *pwmp) { + uint16_t ccer; if (pwmp->pd_state == PWM_STOP) { /* Clock activation.*/ @@ -147,18 +153,27 @@ void pwm_lld_start(PWMDriver *pwmp) { 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. */ + pwmp->pd_tim->CR1 = 0; /* Timer stopped. */ + pwmp->pd_tim->SMCR = 0; /* Slave mode disabled. */ + pwmp->pd_tim->CR2 = pwmp->pd_config->pc_cr2; + pwmp->pd_tim->PSC = pwmp->pd_config->pc_psc; + pwmp->pd_tim->CNT = 0; + pwmp->pd_tim->ARR = pwmp->pd_config->pc_arr; + ccer = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E; + if (pwmp->pd_config->pc_channels[0].pcc_mode == PWM_ACTIVE_LOW) + ccer |= TIM_CCER_CC1P; + if (pwmp->pd_config->pc_channels[1].pcc_mode == PWM_ACTIVE_LOW) + ccer |= TIM_CCER_CC2P; + if (pwmp->pd_config->pc_channels[2].pcc_mode == PWM_ACTIVE_LOW) + ccer |= TIM_CCER_CC3P; + if (pwmp->pd_config->pc_channels[3].pcc_mode == PWM_ACTIVE_LOW) + ccer |= TIM_CCER_CC4P; + pwmp->pd_tim->CCER = ccer; + pwmp->pd_tim->EGR = TIM_EGR_UG; /* Update event. */ + pwmp->pd_tim->SR = 0; /* Clear pending IRQs. */ + pwmp->pd_tim->DIER = pwmp->pd_config->pc_callback == NULL ? 0 : TIM_DIER_UIE; + pwmp->pd_tim->CR1 = TIM_CR1_ARPE | TIM_CR1_URS | + TIM_CR1_CEN; /* Timer configured and started.*/ } /** @@ -167,9 +182,12 @@ void pwm_lld_start(PWMDriver *pwmp) { * @param[in] pwmp pointer to a @p PWMDriver object */ void pwm_lld_stop(PWMDriver *pwmp) { - /* If in ready state then disables the PWM clock.*/ if (pwmp->pd_state == PWM_READY) { + stop_channels(pwmp); + pwmp->pd_tim->CR1 = 0; + pwmp->pd_tim->DIER = 0; + #if USE_STM32_PWM1 if (&PWMD1 == pwmp) { NVICDisableVector(TIM1_UP_IRQn); @@ -178,35 +196,6 @@ void pwm_lld_stop(PWMDriver *pwmp) { } #endif } - - stop_channels(pwmp); - pwmp->pd_tim->CR1 = 0; - pwmp->pd_tim->DIER = 0; -} - -/** - * @brief Determines whatever the PWM channel is already enabled. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier - * - * @return The PWM channel status. - * @retval FALSE the channel is not enabled. - * @retval TRUE the channel is enabled. - */ -bool_t pwm_lld_is_enabled(PWMDriver *pwmp, pwmchannel_t channel) { - - return (pwmp->pd_enabled_channels & (1 << channel)) != 0; -} - -/** - * @brief Setups a PWM channel. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier - */ -void pwm_lld_setup_channel(PWMDriver *pwmp, pwmchannel_t channel) { - } /** @@ -220,7 +209,67 @@ void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width) { - pwmp->pd_enabled_channels |= (1 << channel); + /* + * Changes the pulse width. + */ + switch (channel) { + case 0: + pwmp->pd_tim->CCR1 = width; + break; + case 1: + pwmp->pd_tim->CCR2 = width; + break; + case 2: + pwmp->pd_tim->CCR3 = width; + break; + case 3: + pwmp->pd_tim->CCR4 = width; + break; + } + if ((pwmp->pd_enabled_channels & (1 << channel)) == 0) { + /* + * The channel is not enabled yet. + */ + pwmp->pd_enabled_channels |= (1 << channel); + /* + * Setup the comparator, the channel is configured as PWM mode 1 with + * preload enabled. + */ + switch (channel) { + case 0: + pwmp->pd_tim->CCMR1 = (pwmp->pd_tim->CCMR1 & 0xFF00) | + TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | + TIM_CCMR1_OC1PE; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[0].pcc_callback == NULL + ? 0 : TIM_DIER_CC1IE; + pwmp->pd_tim->SR = ~TIM_SR_CC1IF; + break; + case 1: + pwmp->pd_tim->CCMR1 = (pwmp->pd_tim->CCMR1 & 0x00FF) | + TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | + TIM_CCMR1_OC2PE; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[1].pcc_callback == NULL + ? 0 : TIM_DIER_CC2IE; + pwmp->pd_tim->SR = ~TIM_SR_CC2IF; + break; + case 2: + pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0xFF00) | + TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | + TIM_CCMR2_OC3PE; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[2].pcc_callback == NULL + ? 0 : TIM_DIER_CC3IE; + pwmp->pd_tim->SR = ~TIM_SR_CC3IF; + break; + case 3: + pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0x00FF) | + TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 | + TIM_CCMR2_OC4PE; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[3].pcc_callback == NULL + ? 0 : TIM_DIER_CC4IE; + pwmp->pd_tim->SR = ~TIM_SR_CC4IF; + break; + } + } } /** @@ -234,6 +283,32 @@ void pwm_lld_enable_channel(PWMDriver *pwmp, void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { pwmp->pd_enabled_channels &= ~(1 << channel); + switch (channel) { + case 0: + pwmp->pd_tim->CCR1 = 0; + pwmp->pd_tim->CCMR1 = pwmp->pd_tim->CCMR1 & 0xFF00; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC1IE; + pwmp->pd_tim->SR = ~TIM_SR_CC1IF; + break; + case 1: + pwmp->pd_tim->CCR2 = 0; + pwmp->pd_tim->CCMR1 = pwmp->pd_tim->CCMR1 & 0x00FF; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC2IE; + pwmp->pd_tim->SR = ~TIM_SR_CC2IF; + break; + case 2: + pwmp->pd_tim->CCR3 = 0; + pwmp->pd_tim->CCMR2 = pwmp->pd_tim->CCMR2 & 0xFF00; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC3IE; + pwmp->pd_tim->SR = ~TIM_SR_CC3IF; + break; + case 3: + pwmp->pd_tim->CCR4 = 0; + pwmp->pd_tim->CCMR2 = pwmp->pd_tim->CCMR2 & 0x00FF; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC4IE; + pwmp->pd_tim->SR = ~TIM_SR_CC4IF; + break; + } } #endif /* CH_HAL_USE_PWM */ diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h index a48a93619..d44c1fdbf 100644 --- a/os/hal/platforms/STM32/pwm_lld.h +++ b/os/hal/platforms/STM32/pwm_lld.h @@ -73,6 +73,24 @@ typedef uint8_t pwmchannel_t; */ typedef uint16_t pwmcnt_t; +/** + * @brief PWM driver channel configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Channel active logic level. + */ + pwmmode_t pcc_mode; + /** + * @brief Channel callback pointer. + * @details This callback is invoked on the channel compare event. If set to + * @p NULL then the callback is disabled. + */ + pwmcallback_t pcc_callback; + /* End of the mandatory fields.*/ +} PWMChannelConfig; + /** * @brief PWM driver configuration structure. * @note It could be empty on some architectures. @@ -84,6 +102,10 @@ typedef struct { * @p NULL then the callback is disabled. */ pwmcallback_t pc_callback; + /** + * @brief Channels configurations. + */ + PWMChannelConfig pc_channels[PWM_CHANNELS]; /* End of the mandatory fields.*/ /** * @brief TIM PSC (pre-scaler) register initialization data. @@ -93,11 +115,6 @@ typedef struct { * @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. @@ -105,24 +122,6 @@ typedef struct { uint16_t pc_cr2; } PWMConfig; -/** - * @brief PWM driver channel configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief Channel idle logic level. - */ - pwmmode_t pcc_mode; - /** - * @brief Channel callback pointer. - * @details This callback is invoked on the channel compare event. If set to - * @p NULL then the callback is disabled. - */ - pwmcallback_t pcc_callback; - /* End of the mandatory fields.*/ -} PWMChannelConfig; - /** * @brief Structure representing a PWM driver. */ @@ -135,10 +134,6 @@ typedef struct { * @brief Current driver configuration data. */ const PWMConfig *pd_config; - /** - * @brief Current channel configurations. - */ - const PWMChannelConfig *pd_channel_configs[PWM_CHANNELS]; /* End of the mandatory fields.*/ /** * @brief Bit mask of the enabled channels. @@ -165,8 +160,6 @@ extern "C" { void pwm_lld_init(void); void pwm_lld_start(PWMDriver *pwmp); void pwm_lld_stop(PWMDriver *pwmp); - bool_t pwm_lld_is_enabled(PWMDriver *pwmp, pwmchannel_t channel); - void pwm_lld_setup_channel(PWMDriver *pwmp, pwmchannel_t channel); void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width); diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c index ad3c15728..f6164ea35 100644 --- a/os/hal/src/pwm.c +++ b/os/hal/src/pwm.c @@ -86,31 +86,6 @@ void pwmStop(PWMDriver *pwmp) { chSysUnlock(); } -/** - * @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 - * @param[in] pccp pointer to a @p PWMChannelConfig object - */ -void pwmSetupChannel(PWMDriver *pwmp, pwmchannel_t channel, - const PWMChannelConfig *pccp) { - - chDbgCheck((pwmp != NULL) && (channel < PWM_CHANNELS) && (pccp != NULL), - "pwmSetupChannel"); - - chSysLock(); - chDbgAssert((pwmp->pd_state == PWM_READY) && - !pwm_lld_is_enabled(pwmp, channel), - "pwmSetupChannel(), #1", "invalid state"); - pwmp->pd_channel_configs[channel] = pccp; - pwm_lld_setup_channel(pwmp, channel); - chSysUnlock(); -} - /** * @brief Enables a PWM channel. * @@ -126,8 +101,7 @@ void pwmEnableChannel(PWMDriver *pwmp, "pwmEnableChannel"); chSysLock(); - chDbgAssert((pwmp->pd_state == PWM_READY) && - (pwmp->pd_channel_configs[channel] != NULL), + chDbgAssert(pwmp->pd_state == PWM_READY, "pwmEnableChannel(), #1", "invalid state"); pwm_lld_enable_channel(pwmp, channel, width); chSysUnlock(); @@ -147,8 +121,7 @@ void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) { "pwmEnableChannel"); chSysLock(); - chDbgAssert((pwmp->pd_state == PWM_READY) && - (pwmp->pd_channel_configs[channel] != NULL), + chDbgAssert(pwmp->pd_state == PWM_READY, "pwmDisableChannel(), #1", "invalid state"); pwm_lld_disable_channel(pwmp, channel); chSysUnlock(); -- cgit v1.2.3