From 61059ae472f03c43613bb05c3789636aa5061e2f Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 11 Jan 2012 18:44:12 +0000 Subject: Fix the STM32 PWM driver pulse count logic git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4298 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/stm32_pwm.c | 68 +++++++++++++++++++++++++++++------- nuttx/drivers/pwm.c | 5 ++- 2 files changed, 60 insertions(+), 13 deletions(-) (limited to 'nuttx') diff --git a/nuttx/arch/arm/src/stm32/stm32_pwm.c b/nuttx/arch/arm/src/stm32/stm32_pwm.c index dea64c7d9..c9b97db28 100644 --- a/nuttx/arch/arm/src/stm32/stm32_pwm.c +++ b/nuttx/arch/arm/src/stm32/stm32_pwm.c @@ -145,8 +145,7 @@ struct stm32_pwmtimer_s uint8_t timtype; /* See the TIMTYPE_* definitions */ #ifdef CONFIG_PWM_PULSECOUNT uint8_t irq; /* Timer update IRQ */ -#else - uint8_t unused; + bool endseq; /* True: Next interrupt is the end */ #endif uint32_t base; /* The base address of the timer */ uint32_t pincfg; /* Output pin configuration */ @@ -552,9 +551,18 @@ static int pwm_timer(FAR struct stm32_pwmtimer_s *priv, DEBUGASSERT(priv != NULL && info != NULL); +#ifdef CONFIG_PWM_PULSECOUNT + pwmvdbg("TIM%d channel: %d frequency: %d duty: %08x count: %d\n", + priv->timid, priv->channel, info->frequency, + info->duty, info->count); + DEBUGASSERT(info->frequency > 0 && info->duty > 0 && + info->duty < uitoub16(100) && info->count < PWM_MAX_COUNT); +#else pwmvdbg("TIM%d channel: %d frequency: %d duty: %08x\n", priv->timid, priv->channel, info->frequency, info->duty); - DEBUGASSERT(info->frequency > 0 && info->duty > 0 && info->duty < uitoub16(100)); + DEBUGASSERT(info->frequency > 0 && info->duty > 0 && + info->duty < uitoub16(100)); +#endif /* Disable all interrupts and DMA requests, clear all pending status */ @@ -884,9 +892,11 @@ static int pwm_timer(FAR struct stm32_pwmtimer_s *priv, #ifdef CONFIG_PWM_PULSECOUNT if (info->count > 0) { - /* Enable the update interrupt. */ + /* Clear all pending interrupts and enable the update interrupt. */ + pwm_putreg(priv, STM32_GTIM_SR_OFFSET, 0); pwm_putreg(priv, STM32_GTIM_DIER_OFFSET, ATIM_DIER_UIE); + priv->endseq = false; /* Enable the timer */ @@ -927,19 +937,49 @@ static int pwm_timer(FAR struct stm32_pwmtimer_s *priv, #if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM8_PWM)) static int pwm_interrupt(struct stm32_pwmtimer_s *priv) { + uint16_t regval; + /* Verify that this is an update interrupt. Nothing else is expected. */ - pwmllvdbg("Update interrupt: %04x\n", pwm_getreg(priv, STM32_GTIM_SR_OFFSET)); - DEBUGASSERT((pwm_getreg(priv, STM32_GTIM_SR_OFFSET) & ATIM_SR_UIF) != 0); + regval = pwm_getreg(priv, STM32_ATIM_SR_OFFSET); + DEBUGASSERT((regval & ATIM_SR_UIF) != 0); - /* Disable further interrupts and stop the timer */ + /* Clear the UIF interrupt bit */ - (void)pwm_stop((FAR struct pwm_lowerhalf_s *)priv); + pwm_putreg(priv, STM32_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF); - /* Then perform the callback into the upper half driver */ + /* Now all of the time critical stuff is done so we can do some debug output */ + + pwmllvdbg("Update interrupt SR: %04x RCR: %d endseq: %d\n", + regval, pwm_getreg(priv, STM32_ATIM_RCR_OFFSET), priv->endseq); + + /* Ignore the first update interrupt. That apparently happens when the + * timer first starts so we always get one immediately. The second is + * one that is controlled by RCR. + */ + + if (!priv->endseq) + { + /* The next interrupt will be the one we care about. */ + + priv->endseq = true; + } + else + { + /* OK.. This is the real thing. Disable further interrupts and stop + * the timer + */ + + (void)pwm_stop((FAR struct pwm_lowerhalf_s *)priv); + + /* Then perform the callback into the upper half driver */ + + pwm_expired(priv->handle); + + priv->handle = NULL; + priv->endseq = false; + } - pwm_expired(priv->handle); - priv->handle = NULL; return OK; } #endif @@ -1002,7 +1042,7 @@ static int pwm_setup(FAR struct pwm_lowerhalf_s *dev) /* Configure the PWM output pin, but do not start the timer yet */ stm32_configgpio(priv->pincfg); - pwm_dumpgpio(priv->pincfg, "PWM setup"); // REMOVE ME + pwm_dumpgpio(priv->pincfg, "PWM setup"); return OK; } @@ -1096,6 +1136,10 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, } } + /* Save the handle */ + + priv->handle = handle; + /* Start the time */ return pwm_timer(priv, info); diff --git a/nuttx/drivers/pwm.c b/nuttx/drivers/pwm.c index 6a613f3b5..adfe0e2e8 100644 --- a/nuttx/drivers/pwm.c +++ b/nuttx/drivers/pwm.c @@ -322,7 +322,7 @@ static int pwm_start(FAR struct pwm_upperhalf_s *upper, unsigned int oflags) * We do these things before starting the PWM to avoid race conditions. */ - upper->waiting = (upper->info.count > 0) && ((oflags & O_NONBLOCK) != 0); + upper->waiting = (upper->info.count > 0) && ((oflags & O_NONBLOCK) == 0); upper->started = true; /* Invoke the bottom half method to start the pulse train */ @@ -354,6 +354,7 @@ static int pwm_start(FAR struct pwm_upperhalf_s *upper, unsigned int oflags) { /* Looks like we won't be waiting after all */ + pwmvdbg("start failed: %d\n", ret); upper->started = false; upper->waiting = false; } @@ -649,6 +650,8 @@ void pwm_expired(FAR void *handle) { FAR struct pwm_upperhalf_s *upper = (FAR struct pwm_upperhalf_s *)handle; + pwmllvdbg("started: %d waiting: %d\n", upper->started, upper->waiting); + /* Make sure that the PWM is started */ if (upper->started) -- cgit v1.2.3