summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/stm32/stm32_pwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_pwm.c')
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_pwm.c617
1 files changed, 548 insertions, 69 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_pwm.c b/nuttx/arch/arm/src/stm32/stm32_pwm.c
index 8646bfcd7..141b7bb43 100644
--- a/nuttx/arch/arm/src/stm32/stm32_pwm.c
+++ b/nuttx/arch/arm/src/stm32/stm32_pwm.c
@@ -42,9 +42,11 @@
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
+#include <errno.h>
#include <debug.h>
#include <nuttx/pwm.h>
+#include <arch/board/board.h>
#include "up_internal.h"
#include "up_arch.h"
@@ -59,8 +61,7 @@
#if defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM2_PWM) || \
defined(CONFIG_STM32_TIM3_PWM) || defined(CONFIG_STM32_TIM4_PWM) || \
- defined(CONFIG_STM32_TIM5_PWM) || defined(CONFIG_STM32_TIM6_PWM) || \
- defined(CONFIG_STM32_TIM7_PWM) || defined(CONFIG_STM32_TIM8_PWM) || \
+ defined(CONFIG_STM32_TIM5_PWM) || defined(CONFIG_STM32_TIM8_PWM) || \
defined(CONFIG_STM32_TIM9_PWM) || defined(CONFIG_STM32_TIM10_PWM) || \
defined(CONFIG_STM32_TIM11_PWM) || defined(CONFIG_STM32_TIM12_PWM) || \
defined(CONFIG_STM32_TIM13_PWM) || defined(CONFIG_STM32_TIM14_PWM)
@@ -68,6 +69,19 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_DEBUG_PWM
+# define pwmdbg dbg
+# define pwmvdbg vdbg
+# define pwmlldbg lldbg
+# define pwmllvdbg llvdbg
+#else
+# define pwmdbg(x...)
+# define pwmvdbg(x...)
+# define pwmlldbg(x...)
+# define pwmllvdbg(x...)
+#endif
/****************************************************************************
* Private Types
@@ -76,12 +90,26 @@
struct stm32_pwmtimer_s
{
- uint32_t base; /* The base address of the timer */
+ FAR const struct pwm_ops_s *ops; /* PWM operations */
+ uint8_t timid; /* Timer ID {1,...,14} */
+ uint8_t channel; /* Timer output channel: {1,..4} */
+ uint8_t unused2;
+ uint8_t unused3;
+ uint32_t base; /* The base address of the timer */
+ uint32_t pincfg; /* Output pin configuration */
+ uint32_t pclk; /* The frequency of the peripheral clock
+ * that drives the timer module. */
};
/****************************************************************************
* Static Function Prototypes
****************************************************************************/
+/* Register access */
+
+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);
+
+/* PWM driver methods */
static int pwm_setup(FAR struct pwm_lowerhalf_s *dev);
static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
@@ -97,125 +125,155 @@ static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg
static const struct pwm_ops_s g_pwmops =
{
- .setup = pwm_setup(FAR struct pwm_lowerhalf_s *dev);
- .shutdown = pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
- .start = pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info);
- .stop = pwm_stop(FAR struct pwm_lowerhalf_s *dev);
- .pulsecount = pwm_pulsecount(FAR struct pwm_lowerhalf_s *dev, FAR pwm_count_t *count);
- .ioctl = pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg);
+ .setup = pwm_setup,
+ .shutdown = pwm_shutdown,
+ .start = pwm_start,
+ .stop = pwm_stop,
+ .pulsecount = pwm_pulsecount,
+ .ioctl = pwm_ioctl,
};
-/* The following represent the state of each possible PWM driver */
-
#ifdef CONFIG_STM32_TIM1_PWM
static struct stm32_pwmtimer_s g_pwm1dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM1_BASE;
+ .ops = &g_pwmops,
+ .timid = 1,
+ .channel = CONFIG_STM32_TIM1_CHANNEL,
+ .base = STM32_TIM1_BASE,
+ .pincfg = PWM_TIM1_PINCFG,
+ .pclk = STM32_PCLK2_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM2_PWM
static struct stm32_pwmtimer_s g_pwm2dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM2_BASE;
+ .ops = &g_pwmops,
+ .timid = 2,
+ .channel = CONFIG_STM32_TIM2_CHANNEL,
+ .base = STM32_TIM2_BASE,
+ .pincfg = PWM_TIM2_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM3_PWM
static struct stm32_pwmtimer_s g_pwm3dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM3_BASE;
+ .ops = &g_pwmops,
+ .timid = 3,
+ .channel = CONFIG_STM32_TIM3_CHANNEL,
+ .base = STM32_TIM3_BASE,
+ .pincfg = PWM_TIM3_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM4_PWM
static struct stm32_pwmtimer_s g_pwm4dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM4_BASE;
+ .ops = &g_pwmops,
+ .timid = 4,
+ .channel = CONFIG_STM32_TIM4_CHANNEL,
+ .base = STM32_TIM4_BASE,
+ .pincfg = PWM_TIM4_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM5_PWM
static struct stm32_pwmtimer_s g_pwm5dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM5_BASE;
-};
-#endif
-
-#ifdef CONFIG_STM32_TIM6_PWM
-static struct stm32_pwmtimer_s g_pwm6dev =
-{
- .ops = *g_pwmops;
- .base = STM32_TIM6_BASE;
-};
-#endif
-
-#ifdef CONFIG_STM32_TIM7_PWM
-static struct stm32_pwmtimer_s g_pwm7dev =
-{
- .ops = *g_pwmops;
- .base = STM32_TIM7_BASE;
+ .ops = &g_pwmops,
+ .timid = 5,
+ .channel = CONFIG_STM32_TIM5_CHANNEL,
+ .base = STM32_TIM5_BASE,
+ .pincfg = PWM_TIM5_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM8_PWM
static struct stm32_pwmtimer_s g_pwm8dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM8_BASE;
+ .ops = &g_pwmops,
+ .timid = 8,
+ .channel = CONFIG_STM32_TIM8_CHANNEL,
+ .base = STM32_TIM8_BASE,
+ .pincfg = PWM_TIM8_PINCFG,
+ .pclk = STM32_PCLK2_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM9_PWM
static struct stm32_pwmtimer_s g_pwm9dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM9_BASE;
+ .ops = &g_pwmops,
+ .timid = 9,
+ .channel = CONFIG_STM32_TIM9_CHANNEL,
+ .base = STM32_TIM9_BASE,
+ .pincfg = PWM_TIM9_PINCFG,
+ .pclk = STM32_PCLK2_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM10_PWM
static struct stm32_pwmtimer_s g_pwm10dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM10_BASE;
+ .ops = &g_pwmops,
+ .timid = 10,
+ .channel = CONFIG_STM32_TIM10_CHANNEL,
+ .base = STM32_TIM10_BASE,
+ .pincfg = PWM_TIM10_PINCFG,
+ .pclk = STM32_PCLK2_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM11_PWM
static struct stm32_pwmtimer_s g_pwm11dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM11_BASE;
+ .ops = &g_pwmops,
+ .timid = 11,
+ .channel = CONFIG_STM32_TIM11_CHANNEL,
+ .base = STM32_TIM11_BASE,
+ .pincfg = PWM_TIM11_PINCFG,
+ .pclk = STM32_PCLK2_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM12_PWM
static struct stm32_pwmtimer_s g_pwm12dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM12_BASE;
+ .ops = &g_pwmops,
+ .timid = 12,
+ .channel = CONFIG_STM32_TIM12_CHANNEL,
+ .base = STM32_TIM12_BASE,
+ .pincfg = PWM_TIM12_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM13_PWM
static struct stm32_pwmtimer_s g_pwm13dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM13_BASE;
+ .ops = &g_pwmops,
+ .timid = 13,
+ .channel = CONFIG_STM32_TIM13_CHANNEL,
+ .base = STM32_TIM13_BASE,
+ .pincfg = PWM_TIM13_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
#ifdef CONFIG_STM32_TIM14_PWM
static struct stm32_pwmtimer_s g_pwm14dev =
{
- .ops = *g_pwmops;
- .base = STM32_TIM14_BASE;
+ .ops = &g_pwmops,
+ .timid = 14,
+ .channel = CONFIG_STM32_TIM14_CHANNEL,
+ .base = STM32_TIM14_BASE,
+ .pincfg = PWM_TIM14_PINCFG,
+ .pclk = STM32_PCLK1_FREQUENCY,
};
#endif
@@ -224,6 +282,46 @@ static struct stm32_pwmtimer_s g_pwm14dev =
****************************************************************************/
/****************************************************************************
+ * Name: pwm_getreg
+ *
+ * Description:
+ * Read the value of an ADC timer register.
+ *
+ * Input Parameters:
+ * priv - A reference to the ADC block status
+ * offset - The offset to the register to read
+ *
+ * Returned Value:
+ * The current contents of the specified register
+ *
+ ****************************************************************************/
+
+static uint16_t pwm_getreg(struct stm32_pwmtimer_s *priv, int offset)
+{
+ return getreg16(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: pwm_putreg
+ *
+ * Description:
+ * Read the value of an ADC timer register.
+ *
+ * Input Parameters:
+ * priv - A reference to the ADC block status
+ * offset - The offset to the register to read
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void pwm_putreg(struct stm32_pwmtimer_s *priv, int offset, uint16_t value)
+{
+ putreg16(value, priv->base + offset);
+}
+
+/****************************************************************************
* Name: pwm_setup
*
* Description:
@@ -237,12 +335,20 @@ static struct stm32_pwmtimer_s g_pwm14dev =
* Returned Value:
* Zero on success; a negated errno value on failure
*
+ * Assumptions:
+ * AHB1 or 2 clocking for the GPIOs and timer has already been configured
+ * by the RCC logic at power up.
+ *
****************************************************************************/
static int pwm_setup(FAR struct pwm_lowerhalf_s *dev)
{
-#warning "Missing logic"
- return -ENOSYS;
+ FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev;
+
+ /* Configure the PWM output pin, but do not start the timer yet */
+
+ stm32_configgpio(priv->pincfg);
+ return OK;
}
/****************************************************************************
@@ -263,8 +369,27 @@ static int pwm_setup(FAR struct pwm_lowerhalf_s *dev)
static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
{
-#warning "Missing logic"
- return -ENOSYS;
+ FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev;
+ uint32_t pincfg;
+
+ /* Make sure that the output has been stopped */
+
+ pwm_stop(dev);
+
+ /* Then put the GPIO pin back to the default state */
+
+ pincfg = priv->pincfg & (GPIO_PORT_MASK|GPIO_PIN_MASK);
+
+#if defined(CONFIG_STM32_STM32F10XX)
+ pincfg |= (GPIO_INPUT|GPIO_CNF_INFLOAT|GPIO_MODE_INPUT);
+#elif defined(CONFIG_STM32_STM32F40XX)
+ pincfg |= (GPIO_INPUT|GPIO_FLOAT);
+#else
+# error "Unrecognized STM32 chip"
+#endif
+
+ stm32_configgpio(pincfg);
+ return OK;
}
/****************************************************************************
@@ -284,8 +409,281 @@ static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info)
{
-#warning "Missing logic"
- return -ENOSYS;
+ FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev;
+
+ /* Calculated values */
+
+ uint32_t prescaler;
+ uint32_t timclk;
+ uint32_t reload;
+ uint32_t ccr;
+
+ /* Register contents */
+
+ uint16_t cr1;
+ uint16_t ccer;
+ uint16_t cr2;
+ uint16_t ccmr1;
+ uint16_t ccmr2;
+
+ /* New timer regiser bit settings */
+
+ uint16_t ccenable;
+ uint16_t ocmode1;
+ uint16_t ocmode2;
+
+ /* Caculate optimal values for the timer prescaler and for the timer reload
+ * register. If' frequency' is the desired frequency, then
+ *
+ * reload = timclk / frequency
+ * timclk = pclk / presc
+ *
+ * Or,
+ *
+ * reload = pclk / presc / frequency
+ *
+ * There are many solutions to this this, but the best solution will be the
+ * one that has the largest reload value and the smallest prescaler value.
+ * That is the solution that should give us the most accuracy in the timer
+ * control. Subject to:
+ *
+ * 0 <= presc <= 65536
+ * 1 <= reload <= 65535
+ *
+ * So presc = pclk / 65535 / frequency would be optimal.
+ *
+ * Example:
+ *
+ * pclk = 42 MHz
+ * frequency = 100 Hz
+ *
+ * prescaler = 42,000,000 / 65,535 / 100
+ * = 6.4 (or 7 -- taking the ceiling always)
+ * timclk = 42,000,000 / 7
+ * = 6,000,000
+ * reload = 7,000,000 / 100
+ * = 60,000
+ */
+
+ prescaler = (priv->pclk / info->frequency + 65534) / 65535;
+ if (prescaler < 1)
+ {
+ prescaler = 1;
+ }
+ else if (prescaler > 65536)
+ {
+ prescaler = 65536;
+ }
+
+ timclk = priv->pclk / prescaler;
+
+ reload = timclk / info->frequency;
+ if (reload < 1)
+ {
+ reload = 1;
+ }
+ else if (reload > 65535)
+ {
+ 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);
+
+ /* Set up the timer CR1 register:
+ *
+ * 1-8 CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN
+ * 2-5 CKD[1:0] ARPE CMS DIR OPM URS UDIS CEN
+ * 6-7 ARPE OPM URS UDIS CEN
+ * 9-14 CKD[1:0] ARPE URS UDIS CEN
+ */
+
+ cr1 = pwm_getreg(priv, STM32_GTIM_CR1_OFFSET);
+
+ /* Disable the timer until we get it configured */
+
+ cr1 &= ~GTIM_CR1_CEN;
+
+ /* Set the counter mode for the advanced timers (1,8) and most general
+ * purpose timers (2-5, but not 9-14):
+ */
+
+#if defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM2_PWM) || \
+ defined(CONFIG_STM32_TIM3_PWM) || defined(CONFIG_STM32_TIM4_PWM) || \
+ defined(CONFIG_STM32_TIM5_PWM) || defined(CONFIG_STM32_TIM8_PWM)
+
+ if ((priv->timid >= 1 && priv->timid <= 5) || priv->timid == 8)
+ {
+ /* Select the Counter Mode == count up:
+ *
+ * ATIM_CR1_EDGE: The counter counts up or down depending on the
+ * direction bit(DIR).
+ * ATIM_CR1_DIR: 0: count up, 1: count down
+ */
+
+ cr1 &= ~(ATIM_CR1_DIR | ATIM_CR1_CMS_MASK);
+ cr1 |= ATIM_CR1_EDGE;
+ }
+#endif
+
+ /* Set the clock division to zero for all (but the basic timers, but there
+ * should be no basic timers in this context
+ */
+
+ cr1 &= ~GTIM_CR1_CKD_MASK;
+ pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, cr1);
+
+ /* Set the reload and prescaler values */
+
+ pwm_putreg(priv, STM32_GTIM_ARR_OFFSET, reload);
+ pwm_putreg(priv, STM32_GTIM_PSC_OFFSET, prescaler - 1);
+
+ /* Clear the advanced timers repitition counter in all but the advanced timers */
+
+#if defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM8_PWM)
+ if (priv->timid == 1 || priv->timid == 8)
+ {
+ pwm_putreg(priv, STM32_ATIM_RCR_OFFSET, 0);
+ }
+#endif
+
+ /* Generate an update event to reload the prescaler (all timers) */
+
+ 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;
+ ocmode2 = 0;
+ switch (priv->channel)
+ {
+ case 1: /* PWM Mode configuration: Channel 1 */
+ {
+ ccenable = ATIM_CCER_CC1E;
+ ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) |
+ (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) |
+ ATIM_CCMR1_OC1PE;
+ }
+ break;
+
+ case 2: /* PWM Mode configuration: Channel 2 */
+ {
+ ccenable = ATIM_CCER_CC2E;
+ ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) |
+ (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) |
+ ATIM_CCMR1_OC2PE;
+ }
+ break;
+
+ case 3: /* PWM Mode configuration: Channel3 */
+ {
+ ccenable = ATIM_CCER_CC3E;
+ ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) |
+ (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) |
+ ATIM_CCMR2_OC3PE;
+ }
+ break;
+
+ case 4: /* PWM1 Mode configuration: Channel4 */
+ {
+ ccenable = ATIM_CCER_CC4E;
+ ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) |
+ (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) |
+ ATIM_CCMR2_OC4PE;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable the Channel by resetting the CCxE Bit in the CCER register */
+
+ ccer = pwm_getreg(priv, STM32_GTIM_CCER_OFFSET);
+ ccer &= ~ccenable;
+ pwm_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer);
+
+ /* Fetch the CR2, CCMR1, and CCMR2 register (already have cr1 and ccer) */
+
+ cr2 = pwm_getreg(priv, STM32_GTIM_CR2_OFFSET);
+ ccmr1 = pwm_getreg(priv, STM32_GTIM_CCMR1_OFFSET);
+ ccmr2 = pwm_getreg(priv, STM32_GTIM_CCMR1_OFFSET);
+
+ /* Reset the Output Compare Mode Bits and set the select output compare mode */
+
+ ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE |
+ ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE);
+ ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE |
+ ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE);
+ ccmr1 |= ocmode1;
+ ccmr2 |= ocmode2;
+
+ /* Reset the output polarity level of all channels (selects high polarity)*/
+
+ ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | ATIM_CCER_CC3P | ATIM_CCER_CC4P);
+
+ /* Enable the output state of the selected channel (only) */
+
+ ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | ATIM_CCER_CC3E | ATIM_CCER_CC4E);
+ ccer |= ccenable;
+
+ /* Some special setup for advanced timers */
+
+#if defined(CONFIG_STM32_TIM1_PWM) || defined(CONFIG_STM32_TIM8_PWM)
+ if (priv->timid == 1 || priv->timid == 8)
+ {
+ /* Reset output N polarity level, output N state, output compre state,
+ * output compare N idle state.
+ */
+
+#ifdef CONFIG_STM32_STM32F40XX
+ ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP |
+ ATIM_CCER_CC3NE | ATIM_CCER_CC3NP | ATIM_CCER_CC4NP);
+#else
+ ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP |
+ ATIM_CCER_CC3NE | ATIM_CCER_CC3NP);
+#endif
+
+ /* Reset the output compare and output compare N IDLE State */
+
+ cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | ATIM_CR2_OIS2 | ATIM_CR2_OIS2N |
+ ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | ATIM_CR2_OIS4);
+ }
+#ifdef CONFIG_STM32_STM32F40XX
+ else
+#endif
+#endif
+#ifdef CONFIG_STM32_STM32F40XX
+ {
+ ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP | GTIM_CCER_CC4NP);
+ }
+#endif
+
+ /* Save the modified register values */
+
+ 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_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);
+
+ /* And, finally, enable the timer */
+
+ cr1 |= GTIM_CR1_CEN;
+ pwm_putreg(priv, STM32_GTIM_CR1_OFFSET, ccmr2);
+ return OK;
}
/****************************************************************************
@@ -304,8 +702,99 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_
static int pwm_stop(FAR struct pwm_lowerhalf_s *dev)
{
-#warning "Missing logic"
- return -ENOSYS;
+ FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev;
+
+ uint32_t resetbit;
+ uint32_t regaddr;
+ uint32_t regval;
+
+ switch (priv->timid)
+ {
+#ifdef CONFIG_STM32_TIM1_PWM
+ case 1:
+ regaddr = STM32_RCC_APB2RSTR;
+ resetbit = RCC_APB2RSTR_TIM1RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM2_PWM
+ case 2:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM2RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM3_PWM
+ case 3:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM3RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM4_PWM
+ case 4:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM4RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM5_PWM
+ case 5:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM5RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM8_PWM
+ case 8:
+ regaddr = STM32_RCC_APB2RSTR;
+ resetbit = RCC_APB2RSTR_TIM8RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM9_PWM
+ case 9:
+ regaddr = STM32_RCC_APB2RSTR;
+ resetbit = RCC_APB2RSTR_TIM9RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM10_PWM
+ case 10:
+ regaddr = STM32_RCC_APB2RSTR;
+ resetbit = RCC_APB2RSTR_TIM10RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM11_PWM
+ case 11:
+ regaddr = STM32_RCC_APB2RSTR;
+ resetbit = RCC_APB2RSTR_TIM11RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM12_PWM
+ case 12:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM12RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM13_PWM
+ case 13:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM13RST;
+ break;
+#endif
+#ifdef CONFIG_STM32_TIM14_PWM
+ case 14:
+ regaddr = STM32_RCC_APB1RSTR;
+ resetbit = RCC_APB1RSTR_TIM14RST;
+ break;
+#endif
+ }
+
+ /* Reset the timer - stopping the output and putting the timer back
+ * into a state where pwm_start() can be called.
+ */
+
+ regval = getreg32(regaddr);
+ regval |= resetbit;
+ putreg32(regval, regaddr);
+
+ regval &= ~resetbit;
+ putreg32(regval, regaddr);
+ return OK;
}
/****************************************************************************
@@ -404,16 +893,6 @@ FAR struct pwm_lowerhalf_s *stm32_pwminitialize(int timer)
lower = &g_pwm5dev;
break;
#endif
-#ifdef CONFIG_STM32_TIM6_PWM
- case 6:
- lower = &g_pwm6dev;
- break;
-#endif
-#ifdef CONFIG_STM32_TIM7_PWM
- case 7:
- lower = &g_pwm7dev;
- break;
-#endif
#ifdef CONFIG_STM32_TIM8_PWM
case 8:
lower = &g_pwm8dev;