diff options
author | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2009-12-16 15:48:50 +0000 |
---|---|---|
committer | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2009-12-16 15:48:50 +0000 |
commit | 494cd0f0953d131bb31dcda508abfbd4eaef9899 (patch) | |
tree | f6b799556a1b75cd6de792edf3ebe9cabef8fb7d /os/hal | |
parent | ba37ee4f4b32aa3dc67b80ce09cbda7c5a449f4f (diff) | |
download | ChibiOS-494cd0f0953d131bb31dcda508abfbd4eaef9899.tar.gz ChibiOS-494cd0f0953d131bb31dcda508abfbd4eaef9899.tar.bz2 ChibiOS-494cd0f0953d131bb31dcda508abfbd4eaef9899.zip |
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1425 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/platforms/STM32/pwm_lld.c | 79 | ||||
-rw-r--r-- | os/hal/platforms/STM32/pwm_lld.h | 22 | ||||
-rw-r--r-- | 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();
|