From 32e43fdb02ddb7582866c29dad5e6c87f3315605 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 21 Nov 2010 13:45:22 +0000 Subject: Fixed bug 3114481. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2409 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- demos/ARMCM3-STM32F100-DISCOVERY-GCC/halconf.h | 4 +- demos/ARMCM3-STM32F100-DISCOVERY-GCC/main.c | 113 ++++++++++++++-- demos/ARMCM3-STM32F100-DISCOVERY-GCC/mcuconf.h | 4 +- os/hal/include/pwm.h | 4 +- os/hal/platforms/STM32/pwm_lld.c | 173 ++++++++++++------------- os/hal/platforms/STM32/pwm_lld.h | 7 +- os/hal/src/pwm.c | 13 +- os/hal/templates/pwm_lld.c | 30 ++--- os/hal/templates/pwm_lld.h | 7 +- readme.txt | 4 + 10 files changed, 217 insertions(+), 142 deletions(-) diff --git a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/halconf.h b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/halconf.h index 890f3896b..02a280269 100644 --- a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/halconf.h +++ b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/halconf.h @@ -44,7 +44,7 @@ * @brief Enables the ADC subsystem. */ #if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) -#define HAL_USE_ADC FALSE +#define HAL_USE_ADC TRUE #endif /** @@ -79,7 +79,7 @@ * @brief Enables the PWM subsystem. */ #if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) -#define HAL_USE_PWM FALSE +#define HAL_USE_PWM TRUE #endif /** diff --git a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/main.c b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/main.c index 05f0712e4..aea56bab2 100644 --- a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/main.c +++ b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/main.c @@ -21,21 +21,101 @@ #include "hal.h" #include "test.h" +static void pwmpcb(PWMDriver *pwmp); +static void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n); + +#define ADC_GRP1_NUM_CHANNELS 2 +#define ADC_GRP1_BUF_DEPTH 4 + +/* + * ADC samples buffer. + */ +static adcsample_t samples[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH] = +{ + 2048, 0, + 2048, 0, + 2048, 0, + 2048, 0 +}; + +/* + * ADC conversion group. + * Mode: Linear buffer, 4 samples of 2 channels, SW triggered. + * Channels: IN10, Sensor. + */ +static const ADCConversionGroup adcgrpcfg = { + FALSE, + ADC_GRP1_NUM_CHANNELS, + adccb, + 0, + ADC_CR2_EXTSEL_SWSTART | ADC_CR2_TSVREFE, + 0, + 0, + ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS), + 0, + ADC_SQR3_SQ1_N(ADC_CHANNEL_SENSOR) | ADC_SQR3_SQ0_N(ADC_CHANNEL_IN10) +}; + +/* + * ADC configuration structure, empty for STM32, there is nothing to configure. + */ +static const ADCConfig adccfg = { +}; + +/* + * PWM configuration structure. + */ +static PWMConfig pwmcfg = { + pwmpcb, + { + {PWM_OUTPUT_DISABLED, NULL}, + {PWM_OUTPUT_DISABLED, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL} + }, + PWM_COMPUTE_PSC(STM32_TIMCLK1, 10000), /* 10KHz PWM clock frequency. */ + PWM_COMPUTE_ARR(10000, 1000000000), /* PWM period 1S (in nS). */ + 0 +}; + +/* + * PWM cyclic callback. PWM channels are reprogrammed using a duty cycle + * calculated as average of the last sampling operations. + */ +static void pwmpcb(PWMDriver *pwmp) { + adcsample_t avg_ch1, avg_ch2; + + /* Calculates the average values from the previous ADC sampling + operation.*/ + avg_ch1 = (samples[0] + samples[2] + samples[4] + samples[6]) / 4; + avg_ch2 = (samples[1] + samples[3] + samples[5] + samples[7]) / 4; + chSysLockFromIsr(); + pwmEnableChannelI(pwmp, 2, PWM_FRACTION_TO_WIDTH(pwmp, 4096, avg_ch1)); + pwmEnableChannelI(pwmp, 3, PWM_FRACTION_TO_WIDTH(pwmp, 4096, avg_ch2)); + + /* Starts an asynchronous ADC conversion operation, the conversion + will be executed in parallel to the current PWM cycle and will + terminate before the next PWM cycle.*/ +// adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP1_BUF_DEPTH); + chSysUnlockFromIsr(); +} + /* - * Red LEDs blinker thread, times are in milliseconds. + * ADC end conversion callback. + */ +void adccb(ADCDriver *adcp, adcsample_t *buffer, size_t n) { + + (void)adcp; (void) buffer; (void) n; +} + +/* + * Red and blue LEDs blinker thread, times are in milliseconds. */ static WORKING_AREA(waThread1, 128); static msg_t Thread1(void *arg) { (void)arg; while (TRUE) { - palSetPad(GPIOC, GPIOC_LED4); - chThdSleepMilliseconds(250); - palClearPad(GPIOC, GPIOC_LED4); - chThdSleepMilliseconds(250); - palSetPad(GPIOC, GPIOC_LED3); - chThdSleepMilliseconds(250); - palClearPad(GPIOC, GPIOC_LED3); chThdSleepMilliseconds(250); } return 0; @@ -55,6 +135,23 @@ int main(int argc, char **argv) { */ sdStart(&SD1, NULL); + /* + * Initializes the ADC driver 1. + */ + adcStart(&ADCD1, &adccfg); + + /* + * Initializes the PWM driver 1, re-routes the TIM3 outputs, programs the + * pins as alternate functions and finally enables channels with zero + * initial duty cycle. + * Note, the AFIO access routes the TIM3 output pins on the PC6...PC9 + * where the LEDs are connected. + */ + pwmStart(&PWMD3, &pwmcfg); + AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_0 | AFIO_MAPR_TIM3_REMAP_1; + palSetGroupMode(GPIOC, PAL_PORT_BIT(GPIOC_LED3) | PAL_PORT_BIT(GPIOC_LED4), + PAL_MODE_STM32_ALTERNATE_PUSHPULL); + /* * Creates the blinker thread. */ diff --git a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/mcuconf.h b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/mcuconf.h index d1ad23373..0ff6793f2 100644 --- a/demos/ARMCM3-STM32F100-DISCOVERY-GCC/mcuconf.h +++ b/demos/ARMCM3-STM32F100-DISCOVERY-GCC/mcuconf.h @@ -61,9 +61,9 @@ /* * PWM driver system settings. */ -#define STM32_PWM_USE_TIM1 TRUE +#define STM32_PWM_USE_TIM1 FALSE #define STM32_PWM_USE_TIM2 FALSE -#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM3 TRUE #define STM32_PWM_USE_TIM4 FALSE #define STM32_PWM_PWM1_IRQ_PRIORITY 7 #define STM32_PWM_PWM2_IRQ_PRIORITY 7 diff --git a/os/hal/include/pwm.h b/os/hal/include/pwm.h index 867cc1de6..ff1ba575f 100644 --- a/os/hal/include/pwm.h +++ b/os/hal/include/pwm.h @@ -82,7 +82,7 @@ typedef enum { * @iclass */ #define pwmEnableChannelI(pwmp, channel, width) { \ - pwm_lld_enable_channel(pwmp, channel, width); \ + pwm_lld_set_channel(pwmp, channel, width); \ } /** @@ -97,7 +97,7 @@ typedef enum { * @iclass */ #define pwmDisableChannelI(pwmp, channel) { \ - pwm_lld_disable_channel(pwmp, channel); \ + pwm_lld_set_channel(pwmp, channel, 0); \ } /*===========================================================================*/ diff --git a/os/hal/platforms/STM32/pwm_lld.c b/os/hal/platforms/STM32/pwm_lld.c index 335c0c8bd..f3588123a 100644 --- a/os/hal/platforms/STM32/pwm_lld.c +++ b/os/hal/platforms/STM32/pwm_lld.c @@ -414,115 +414,102 @@ void pwm_lld_stop(PWMDriver *pwmp) { } /** - * @brief Enables a PWM channel. + * @brief Disables, enables or reprograms a PWM channel. * * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) - * @param[in] width PWM pulse width as clock pulses number + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) + * @param[in] width PWM pulse width as clock pulses number, note that + * specifying zero disables the channel and enforces + * the output to the idle state. * * @notapi */ -void pwm_lld_enable_channel(PWMDriver *pwmp, - pwmchannel_t channel, - pwmcnt_t width) { - - /* - * 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. - */ +void pwm_lld_set_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width) { + + if (width == 0) { + /* Channel disable mode.*/ + pwmp->pd_enabled_channels &= ~(1 << channel); 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->SR = ~TIM_SR_CC1IF; - pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[0].pcc_callback == NULL - ? 0 : TIM_DIER_CC1IE; + pwmp->pd_tim->CCR1 = 0; + pwmp->pd_tim->CCMR1 = (pwmp->pd_tim->CCMR1 & 0xFF00) | TIM_CCMR1_OC1M_2; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC1IE; 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->SR = ~TIM_SR_CC2IF; - pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[1].pcc_callback == NULL - ? 0 : TIM_DIER_CC2IE; + pwmp->pd_tim->CCR2 = 0; + pwmp->pd_tim->CCMR1 = (pwmp->pd_tim->CCMR1 & 0x00FF) | TIM_CCMR1_OC2M_2; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC2IE; 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->SR = ~TIM_SR_CC3IF; - pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[2].pcc_callback == NULL - ? 0 : TIM_DIER_CC3IE; + pwmp->pd_tim->CCR3 = 0; + pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0xFF00) | TIM_CCMR2_OC3M_2; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC3IE; 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->SR = ~TIM_SR_CC4IF; - pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[3].pcc_callback == NULL - ? 0 : TIM_DIER_CC4IE; + pwmp->pd_tim->CCR4 = 0; + pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0x00FF) | TIM_CCMR2_OC4M_2; + pwmp->pd_tim->DIER &= ~TIM_DIER_CC4IE; break; } } -} - -/** - * @brief Disables a PWM channel. - * @details The channel is disabled and its output line returned to the - * idle state. - * - * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) - * - * @notapi - */ -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) | TIM_CCMR1_OC1M_2; - pwmp->pd_tim->DIER &= ~TIM_DIER_CC1IE; - break; - case 1: - pwmp->pd_tim->CCR2 = 0; - pwmp->pd_tim->CCMR1 = (pwmp->pd_tim->CCMR1 & 0x00FF) | TIM_CCMR1_OC2M_2; - pwmp->pd_tim->DIER &= ~TIM_DIER_CC2IE; - break; - case 2: - pwmp->pd_tim->CCR3 = 0; - pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0xFF00) | TIM_CCMR2_OC3M_2; - pwmp->pd_tim->DIER &= ~TIM_DIER_CC3IE; - break; - case 3: - pwmp->pd_tim->CCR4 = 0; - pwmp->pd_tim->CCMR2 = (pwmp->pd_tim->CCMR2 & 0x00FF) | TIM_CCMR2_OC4M_2; - pwmp->pd_tim->DIER &= ~TIM_DIER_CC4IE; - break; + else { + /* Channel enable or reprogram mode.*/ + 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->SR = ~TIM_SR_CC1IF; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[0].pcc_callback == NULL + ? 0 : TIM_DIER_CC1IE; + 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->SR = ~TIM_SR_CC2IF; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[1].pcc_callback == NULL + ? 0 : TIM_DIER_CC2IE; + 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->SR = ~TIM_SR_CC3IF; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[2].pcc_callback == NULL + ? 0 : TIM_DIER_CC3IE; + 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->SR = ~TIM_SR_CC4IF; + pwmp->pd_tim->DIER |= pwmp->pd_config->pc_channels[3].pcc_callback == NULL + ? 0 : TIM_DIER_CC4IE; + break; + } + } } } diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h index 194e60b48..4c3b99e4d 100644 --- a/os/hal/platforms/STM32/pwm_lld.h +++ b/os/hal/platforms/STM32/pwm_lld.h @@ -344,10 +344,9 @@ extern "C" { void pwm_lld_init(void); void pwm_lld_start(PWMDriver *pwmp); void pwm_lld_stop(PWMDriver *pwmp); - void pwm_lld_enable_channel(PWMDriver *pwmp, - pwmchannel_t channel, - pwmcnt_t width); - void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel); + void pwm_lld_set_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width); #ifdef __cplusplus } #endif diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c index 79cc73b30..ecf9eba3f 100644 --- a/os/hal/src/pwm.c +++ b/os/hal/src/pwm.c @@ -117,8 +117,9 @@ void pwmStop(PWMDriver *pwmp) { * @details Programs (or reprograms) a PWM channel. * * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) - * @param[in] width PWM pulse width as clock pulses number + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) + * @param[in] width PWM pulse width as clock pulses number, setting the + * width at zero is equivalent to disabling the channel * * @api */ @@ -132,17 +133,17 @@ void pwmEnableChannel(PWMDriver *pwmp, chSysLock(); chDbgAssert(pwmp->pd_state == PWM_READY, "pwmEnableChannel(), #1", "not ready"); - pwm_lld_enable_channel(pwmp, channel, width); + pwm_lld_set_channel(pwmp, channel, width); chSysUnlock(); } /** - * @brief Disables a PWM channel. + * @brief Disables a PWM channel. * @details The channel is disabled and its output line returned to the * idle state. * * @param[in] pwmp pointer to a @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * * @api */ @@ -154,7 +155,7 @@ void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) { chSysLock(); chDbgAssert(pwmp->pd_state == PWM_READY, "pwmDisableChannel(), #1", "not ready"); - pwm_lld_disable_channel(pwmp, channel); + pwm_lld_set_channel(pwmp, channel, 0); chSysUnlock(); } diff --git a/os/hal/templates/pwm_lld.c b/os/hal/templates/pwm_lld.c index 4f9aab29b..5a4838ade 100644 --- a/os/hal/templates/pwm_lld.c +++ b/os/hal/templates/pwm_lld.c @@ -102,31 +102,19 @@ bool_t pwm_lld_is_enabled(PWMDriver *pwmp, pwmchannel_t channel) { } /** - * @brief Enables a PWM channel. + * @brief Disables, enables or reprograms a PWM channel. * - * @param[in] pwmp pointer to the @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) - * @param[in] width PWM pulse width as clock pulses number - * - * @notapi - */ -void pwm_lld_enable_channel(PWMDriver *pwmp, - pwmchannel_t channel, - pwmcnt_t width) { - -} - -/** - * @brief Disables a PWM channel. - * @details The channel is disabled and its output line returned to the - * idle state. - * - * @param[in] pwmp pointer to the @p PWMDriver object - * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1]) + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) + * @param[in] width PWM pulse width as clock pulses number, note that + * specifying zero disables the channel and enforces + * the output to the idle state. * * @notapi */ -void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { +void pwm_lld_set_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width) { } diff --git a/os/hal/templates/pwm_lld.h b/os/hal/templates/pwm_lld.h index 2b8cf294f..3e81959e7 100644 --- a/os/hal/templates/pwm_lld.h +++ b/os/hal/templates/pwm_lld.h @@ -195,10 +195,9 @@ extern "C" { 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_enable_channel(PWMDriver *pwmp, - pwmchannel_t channel, - pwmcnt_t width); - void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel); + void pwm_lld_set_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width); #ifdef __cplusplus } #endif diff --git a/readme.txt b/readme.txt index 2ab8e1160..5dc2b2b6c 100644 --- a/readme.txt +++ b/readme.txt @@ -65,6 +65,8 @@ ***************************************************************************** *** 2.1.4 *** +- FIX: Fixed PWM channels going to ACTIVE state when the pulse width is + set to zero in the STM32 PWM driver (bug 3114481)(backported to 2.0.8). - FIX: Fixed PWM channels return to IDLE state in STM32 PWM driver (bug 3114467)(backported to 2.0.8). - FIX: Fixed wrong initializer macros in STM32 PWM driver (bug 3114319). @@ -81,6 +83,8 @@ - NEW: Added demo for the ST STM8L-Discovery kit. - NEW: Added support for the STM32 Value Line to the HAL. - NEW: Added demo for the ST STM32VL-Discovery kit. +- NEW: Simplified the interface between the PWM high level driver and the + low level driver, now there is a single channels-interacting function. - CHANGE: Improved the STM32 HAL to support multiple sub-families, at compile time now it is possible to test the presence of any single peripheral into the specified STM32 device. -- cgit v1.2.3