From 75c85b80ff7b2e4ce68e231c3e49b41dd73f90ef Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 20 Dec 2011 17:31:06 +0000 Subject: PWM driver works git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4205 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/chip/stm32_tim.h | 2 - nuttx/arch/arm/src/stm32/stm32_pwm.c | 141 ++++++++++++++++++--- nuttx/configs/stm3240g-eval/include/board.h | 8 +- .../configs/stm3240g-eval/src/stm3240g-internal.h | 8 +- nuttx/configs/stm3240g-eval/src/up_pwm.c | 38 ++++-- 5 files changed, 158 insertions(+), 39 deletions(-) diff --git a/nuttx/arch/arm/src/stm32/chip/stm32_tim.h b/nuttx/arch/arm/src/stm32/chip/stm32_tim.h index 6af2e515c..4ecd79b84 100644 --- a/nuttx/arch/arm/src/stm32/chip/stm32_tim.h +++ b/nuttx/arch/arm/src/stm32/chip/stm32_tim.h @@ -97,13 +97,11 @@ #define STM32_ATIM_PSC_OFFSET 0x0028 /* Prescaler (16-bit) */ #define STM32_ATIM_ARR_OFFSET 0x002c /* Auto-reload register (16-bit) */ #define STM32_ATIM_RCR_OFFSET 0x0030 /* Repetition counter register (16-bit) */ - #define STM32_ATIM_CCR1_OFFSET 0x0034 /* Capture/compare register 1 (16-bit) */ #define STM32_ATIM_CCR2_OFFSET 0x0038 /* Capture/compare register 2 (16-bit) */ #define STM32_ATIM_CCR3_OFFSET 0x003c /* Capture/compare register 3 (16-bit) */ #define STM32_ATIM_CCR4_OFFSET 0x0040 /* Capture/compare register 4 (16-bit) */ #define STM32_ATIM_BDTR_OFFSET 0x0044 /* Break and dead-time register (16-bit) */ - #define STM32_ATIM_DCR_OFFSET 0x0048 /* DMA control register (16-bit) */ #define STM32_ATIM_DMAR_OFFSET 0x004c /* DMA address for burst mode (16-bit) */ diff --git a/nuttx/arch/arm/src/stm32/stm32_pwm.c b/nuttx/arch/arm/src/stm32/stm32_pwm.c index 420537ebb..379ec2ba4 100644 --- a/nuttx/arch/arm/src/stm32/stm32_pwm.c +++ b/nuttx/arch/arm/src/stm32/stm32_pwm.c @@ -110,6 +110,12 @@ struct stm32_pwmtimer_s static uint16_t pwm_getreg(struct stm32_pwmtimer_s *priv, int offset); static void pwm_putreg(struct stm32_pwmtimer_s *priv, int offset, uint16_t value); +#if defined(CONFIG_DEBUG_PWM) && defined(CONFIG_DEBUG_VERBOSE) +static void pwm_dumpregs(struct stm32_pwmtimer_s *priv, FAR const char *msg); +#else +# define pwm_dumpregs(priv,msg) +#endif + /* PWM driver methods */ static int pwm_setup(FAR struct pwm_lowerhalf_s *dev); @@ -284,10 +290,10 @@ static struct stm32_pwmtimer_s g_pwm14dev = * Name: pwm_getreg * * Description: - * Read the value of an ADC timer register. + * Read the value of an PWM timer register. * * Input Parameters: - * priv - A reference to the ADC block status + * priv - A reference to the PWM block status * offset - The offset to the register to read * * Returned Value: @@ -304,10 +310,10 @@ static uint16_t pwm_getreg(struct stm32_pwmtimer_s *priv, int offset) * Name: pwm_putreg * * Description: - * Read the value of an ADC timer register. + * Read the value of an PWM timer register. * * Input Parameters: - * priv - A reference to the ADC block status + * priv - A reference to the PWM block status * offset - The offset to the register to read * * Returned Value: @@ -320,6 +326,63 @@ static void pwm_putreg(struct stm32_pwmtimer_s *priv, int offset, uint16_t value putreg16(value, priv->base + offset); } +/**************************************************************************** + * Name: pwm_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input parameters: + * priv - A reference to the PWM block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_PWM) && defined(CONFIG_DEBUG_VERBOSE) +static void pwm_dumpregs(struct stm32_pwmtimer_s *priv, FAR const char *msg) +{ + pwmvdbg("%s:\n", msg); + pwmvdbg(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + pwm_getreg(priv, STM32_GTIM_CR1_OFFSET), + pwm_getreg(priv, STM32_GTIM_CR2_OFFSET), + pwm_getreg(priv, STM32_GTIM_SMCR_OFFSET), + pwm_getreg(priv, STM32_GTIM_DIER_OFFSET)); + pwmvdbg(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n", + pwm_getreg(priv, STM32_GTIM_SR_OFFSET), + pwm_getreg(priv, STM32_GTIM_EGR_OFFSET), + pwm_getreg(priv, STM32_GTIM_CCMR1_OFFSET), + pwm_getreg(priv, STM32_GTIM_CCMR2_OFFSET)); + pwmvdbg(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", + pwm_getreg(priv, STM32_GTIM_CCER_OFFSET), + pwm_getreg(priv, STM32_GTIM_CNT_OFFSET), + pwm_getreg(priv, STM32_GTIM_PSC_OFFSET), + pwm_getreg(priv, STM32_GTIM_ARR_OFFSET)); + pwmvdbg(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", + pwm_getreg(priv, STM32_GTIM_CCR1_OFFSET), + pwm_getreg(priv, STM32_GTIM_CCR2_OFFSET), + pwm_getreg(priv, STM32_GTIM_CCR3_OFFSET), + pwm_getreg(priv, STM32_GTIM_CCR4_OFFSET)); +#if defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM8_PWM) + if (priv->timid == 1 || priv->timid == 8) + { + pwmvdbg(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + pwm_getreg(priv, STM32_ATIM_RCR_OFFSET), + pwm_getreg(priv, STM32_ATIM_BDTR_OFFSET), + pwm_getreg(priv, STM32_ATIM_DCR_OFFSET), + pwm_getreg(priv, STM32_ATIM_DMAR_OFFSET)); + } + else +#endif + { + pwmvdbg(" DCR: %04x DMAR: %04x\n", + pwm_getreg(priv, STM32_GTIM_DCR_OFFSET), + pwm_getreg(priv, STM32_GTIM_DMAR_OFFSET)); + } +} +#endif + /**************************************************************************** * Name: pwm_setup * @@ -345,6 +408,7 @@ static int pwm_setup(FAR struct pwm_lowerhalf_s *dev) FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev; pwmvdbg("TIM%d pincfg: %08x\n", priv->timid, priv->pincfg); + pwm_dumpregs(priv, "Initially"); /* Configure the PWM output pin, but do not start the timer yet */ @@ -496,8 +560,15 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_ reload = 65535; } - pwmvdbg("TIM%d PCLK: %d frequency: %d TIMCLK: %d prescaler: %d reload: %d\n", - priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload); + /* Duty cycle: + * + * duty cycle = ccr / reload (fractional value) + */ + + ccr = b16toi(info->duty * reload + b16HALF); + + pwmvdbg("TIM%d PCLK: %d frequency: %d TIMCLK: %d prescaler: %d reload: %d ccr: %d\n", + priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload, ccr); /* Set up the timer CR1 register: * @@ -544,8 +615,8 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_ /* Set the reload and prescaler values */ - pwm_putreg(priv, STM32_GTIM_ARR_OFFSET, reload); - pwm_putreg(priv, STM32_GTIM_PSC_OFFSET, prescaler - 1); + pwm_putreg(priv, STM32_GTIM_ARR_OFFSET, (uint16_t)reload); + pwm_putreg(priv, STM32_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1)); /* Clear the advanced timers repitition counter in all but the advanced timers */ @@ -560,13 +631,6 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_ pwm_putreg(priv, STM32_GTIM_EGR_OFFSET, ATIM_EGR_UG); - /* Duty cycle: - * - * duty cycle = ccr / reload (fractional value) - */ - - ccr = b16toi(info->duty * reload + b16HALF); - /* Handle channel specific setup */ ocmode1 = 0; @@ -575,37 +639,73 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_ { case 1: /* PWM Mode configuration: Channel 1 */ { + /* Select the CCER enable bit for this channel */ + ccenable = ATIM_CCER_CC1E; + + /* Set the CCRMR1 mode values (leave CCRMR2 zero) */ + ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) | (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) | ATIM_CCMR1_OC1PE; + + /* Set the duty cycle by writing to the CCR register for this channel */ + + pwm_putreg(priv, STM32_GTIM_CCR1_OFFSET, (uint16_t)ccr); } break; case 2: /* PWM Mode configuration: Channel 2 */ { + /* Select the CCER enable bit for this channel */ + ccenable = ATIM_CCER_CC2E; + + /* Set the CCRMR1 mode values (leave CCRMR2 zero) */ + ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) | (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) | ATIM_CCMR1_OC2PE; + + /* Set the duty cycle by writing to the CCR register for this channel */ + + pwm_putreg(priv, STM32_GTIM_CCR2_OFFSET, (uint16_t)ccr); } break; case 3: /* PWM Mode configuration: Channel3 */ { + /* Select the CCER enable bit for this channel */ + ccenable = ATIM_CCER_CC3E; + + /* Set the CCRMR2 mode values (leave CCRMR1 zero) */ + ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) | (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) | ATIM_CCMR2_OC3PE; + + /* Set the duty cycle by writing to the CCR register for this channel */ + + pwm_putreg(priv, STM32_GTIM_CCR3_OFFSET, (uint16_t)ccr); } break; case 4: /* PWM1 Mode configuration: Channel4 */ { + /* Select the CCER enable bit for this channel */ + ccenable = ATIM_CCER_CC4E; + + /* Set the CCRMR2 mode values (leave CCRMR1 zero) */ + ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) | (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) | ATIM_CCMR2_OC4PE; + + /* Set the duty cycle by writing to the CCR register for this channel */ + + pwm_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)ccr); } break; @@ -680,23 +780,21 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_ pwm_putreg(priv, STM32_GTIM_CR2_OFFSET, cr2); pwm_putreg(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); - pwm_putreg(priv, STM32_GTIM_CCMR1_OFFSET, ccmr2); + pwm_putreg(priv, STM32_GTIM_CCMR2_OFFSET, ccmr2); pwm_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer); /* Set the ARR Preload Bit */ cr1 = pwm_getreg(priv, STM32_GTIM_CR1_OFFSET); cr1 |= GTIM_CR1_ARPE; - pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, ccmr2); + pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, cr1); /* And, finally, enable the timer */ cr1 |= GTIM_CR1_CEN; - pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, ccmr2); - - pwmvdbg("CR1: %04x CR2:%04x CCER: %08x CCMR1: %08x CCMR2: %08x\n", - cr1, cr2, ccer, ccmr1, ccmr2); + pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, cr1); + pwm_dumpregs(priv, "After starting"); return OK; } @@ -812,6 +910,7 @@ static int pwm_stop(FAR struct pwm_lowerhalf_s *dev) putreg32(regval, regaddr); pwmvdbg("regaddr: %08x resetbit: %08x\n", regaddr, resetbit); + pwm_dumpregs(priv, "After stop"); return OK; } diff --git a/nuttx/configs/stm3240g-eval/include/board.h b/nuttx/configs/stm3240g-eval/include/board.h index 9ae54a4d0..4002f918a 100755 --- a/nuttx/configs/stm3240g-eval/include/board.h +++ b/nuttx/configs/stm3240g-eval/include/board.h @@ -269,9 +269,13 @@ * a pulse train using TIM4 CH2. This pin is used by FSMC is connect to CN5 just for this * purpose: * - * PD13 FSMC_A18 / MC_TIM4_CH2 pin 33 (EnB) + * PD13 FSMC_A18 / MC_TIM4_CH2 pin 33 (EnB) * - * FSMC must be disabled in this case! + * FSMC must be disabled in this case! PD13 is available at: + * + * Daughterboard Extension Connector, CN3, pin 32 - available + * TFT LCD Connector, CN19, pin 17 -- not available without removing the LCD. + * Motor Control Connector CN15, pin 33 -- no available unless to connect SB14. */ #define GPIO_TIM4_CH2 GPIO_TIM4_CH2_2 diff --git a/nuttx/configs/stm3240g-eval/src/stm3240g-internal.h b/nuttx/configs/stm3240g-eval/src/stm3240g-internal.h index 415831191..0ccdaf40a 100644 --- a/nuttx/configs/stm3240g-eval/src/stm3240g-internal.h +++ b/nuttx/configs/stm3240g-eval/src/stm3240g-internal.h @@ -90,9 +90,13 @@ * a pulse train using TIM4 CH2. This pin is used by FSMC is connect to CN5 just for this * purpose: * - * PD13 FSMC_A18 / MC_TIM4_CH2 pin 33 (EnB) + * PD13 FSMC_A18 / MC_TIM4_CH2 pin 33 (EnB) * - * FSMC must be disabled in this case! + * FSMC must be disabled in this case! PD13 is available at: + * + * Daughterboard Extension Connector, CN3, pin 32 - available + * TFT LCD Connector, CN19, pin 17 -- not available without removing the LCD. + * Motor Control Connector CN15, pin 33 -- no available unless to connect SB14. */ #define STM3240G_EVAL_PWMTIMER 4 diff --git a/nuttx/configs/stm3240g-eval/src/up_pwm.c b/nuttx/configs/stm3240g-eval/src/up_pwm.c index 503e26073..d0701b2b2 100644 --- a/nuttx/configs/stm3240g-eval/src/up_pwm.c +++ b/nuttx/configs/stm3240g-eval/src/up_pwm.c @@ -40,6 +40,7 @@ #include +#include #include #include @@ -102,27 +103,40 @@ * ************************************************************************************/ -void pwm_devinit(void) +int pwm_devinit(void) { + static bool initialized = false; struct pwm_lowerhalf_s *pwm; int ret; - /* Call stm32_pwminitialize() to get an instance of the PWM interface */ + /* Have we already initialized? */ - pwm = stm32_pwminitialize(STM3240G_EVAL_PWMTIMER); - if (!pwm) + if (!initialized) { - dbg("Failed to get the STM32 PWM lower half\n"); - return; - } + /* Call stm32_pwminitialize() to get an instance of the PWM interface */ - /* Register the PWM driver at "/dev/pwm0" */ + pwm = stm32_pwminitialize(STM3240G_EVAL_PWMTIMER); + if (!pwm) + { + dbg("Failed to get the STM32 PWM lower half\n"); + return -ENODEV; + } - ret = pwm_register("/dev/pwm0", pwm); - if (ret < 0) - { - adbg("pwm_register failed: %d\n", ret); + /* Register the PWM driver at "/dev/pwm0" */ + + ret = pwm_register("/dev/pwm0", pwm); + if (ret < 0) + { + adbg("pwm_register failed: %d\n", ret); + return ret; + } + + /* Now we are initialized */ + + initialized = true; } + + return OK; } #endif /* HAVE_PWM */ -- cgit v1.2.3