aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/hal/include/pwm.h26
-rw-r--r--os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c188
-rw-r--r--os/hal/ports/STM32/LLD/TIMv1/pwm_lld.h49
-rw-r--r--os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h3
-rw-r--r--os/hal/ports/STM32/STM32F0xx/stm32_registry.h6
-rw-r--r--os/hal/ports/STM32/STM32F4xx/stm32_registry.h2
-rw-r--r--os/hal/src/pwm.c127
7 files changed, 330 insertions, 71 deletions
diff --git a/os/hal/include/pwm.h b/os/hal/include/pwm.h
index d7176660e..6ecd93717 100644
--- a/os/hal/include/pwm.h
+++ b/os/hal/include/pwm.h
@@ -87,7 +87,7 @@ typedef enum {
typedef struct PWMDriver PWMDriver;
/**
- * @brief PWM notification callback type.
+ * @brief Type of a PWM notification callback.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*/
@@ -187,13 +187,15 @@ typedef void (*pwmcallback_t)(PWMDriver *pwmp);
* or immediately (fallback implementation).
*
* @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...channels-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @iclass
*/
-#define pwmEnableChannelI(pwmp, channel, width) \
- pwm_lld_enable_channel(pwmp, channel, width)
+#define pwmEnableChannelI(pwmp, channel, width) do { \
+ (pwmp)->enabled |= 1 << (channel); \
+ pwm_lld_enable_channel(pwmp, channel, width); \
+} while (0)
/**
* @brief Disables a PWM channel.
@@ -205,24 +207,26 @@ typedef void (*pwmcallback_t)(PWMDriver *pwmp);
* or immediately (fallback implementation).
*
* @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...channels-1)
*
* @iclass
*/
-#define pwmDisableChannelI(pwmp, channel) \
- pwm_lld_disable_channel(pwmp, channel)
+#define pwmDisableChannelI(pwmp, channel) do { \
+ (pwmp)->enabled &= ~(1 << (channel)); \
+ pwm_lld_disable_channel(pwmp, channel); \
+} while (0)
/**
* @brief Returns a PWM channel status.
* @pre The PWM unit must have been activated using @p pwmStart().
*
* @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...channels-1)
*
* @iclass
*/
#define pwmIsChannelEnabledI(pwmp, channel) \
- pwm_lld_is_channel_enabled(pwmp, channel)
+ ((bool)((pwmp)->enabled & (1 << (channel))))
/** @} */
/*===========================================================================*/
@@ -241,6 +245,10 @@ extern "C" {
pwmchannel_t channel,
pwmcnt_t width);
void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel);
+ void pwmEnablePeriodicNotification(PWMDriver *pwmp);
+ void pwmDisablePeriodicNotification(PWMDriver *pwmp);
+ void pwmEnableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel);
+ void pwmDisableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c b/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c
index 07055fba4..2b633c2e2 100644
--- a/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c
+++ b/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c
@@ -114,15 +114,19 @@ static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
sr = pwmp->tim->SR;
sr &= pwmp->tim->DIER & STM32_TIM_DIER_IRQ_MASK;
pwmp->tim->SR = ~sr;
- if ((sr & STM32_TIM_SR_CC1IF) != 0)
+ if (((sr & STM32_TIM_SR_CC1IF) != 0) &&
+ (pwmp->config->channels[0].callback != NULL))
pwmp->config->channels[0].callback(pwmp);
- if ((sr & STM32_TIM_SR_CC2IF) != 0)
+ if (((sr & STM32_TIM_SR_CC2IF) != 0) &&
+ (pwmp->config->channels[1].callback != NULL))
pwmp->config->channels[1].callback(pwmp);
- if ((sr & STM32_TIM_SR_CC3IF) != 0)
+ if (((sr & STM32_TIM_SR_CC3IF) != 0) &&
+ (pwmp->config->channels[2].callback != NULL))
pwmp->config->channels[2].callback(pwmp);
- if ((sr & STM32_TIM_SR_CC4IF) != 0)
+ if (((sr & STM32_TIM_SR_CC4IF) != 0) &&
+ (pwmp->config->channels[3].callback != NULL))
pwmp->config->channels[3].callback(pwmp);
- if ((sr & STM32_TIM_SR_UIF) != 0)
+ if (((sr & STM32_TIM_SR_UIF) != 0) && (pwmp->config->callback != NULL))
pwmp->config->callback(pwmp);
}
#endif /* STM32_PWM_USE_TIM2 || ... || STM32_PWM_USE_TIM5 */
@@ -148,7 +152,8 @@ OSAL_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
OSAL_IRQ_PROLOGUE();
STM32_TIM1->SR = ~STM32_TIM_SR_UIF;
- PWMD1.config->callback(&PWMD1);
+ if (PWMD1.config->callback != NULL)
+ PWMD1.config->callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
@@ -169,15 +174,22 @@ OSAL_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) {
OSAL_IRQ_PROLOGUE();
- sr = STM32_TIM1->SR & STM32_TIM1->DIER & STM32_TIM_DIER_IRQ_MASK;
+ sr = STM32_TIM1->SR & STM32_TIM1->DIER & (STM32_TIM_DIER_CC1IE |
+ STM32_TIM_DIER_CC2IE |
+ STM32_TIM_DIER_CC3IE |
+ STM32_TIM_DIER_CC4IE);
STM32_TIM1->SR = ~sr;
- if ((sr & STM32_TIM_SR_CC1IF) != 0)
+ if (((sr & STM32_TIM_SR_CC1IF) != 0) &&
+ (PWMD1.config->channels[0].callback != NULL))
PWMD1.config->channels[0].callback(&PWMD1);
- if ((sr & STM32_TIM_SR_CC2IF) != 0)
+ if (((sr & STM32_TIM_SR_CC2IF) != 0) &&
+ (PWMD1.config->channels[1].callback != NULL))
PWMD1.config->channels[1].callback(&PWMD1);
- if ((sr & STM32_TIM_SR_CC3IF) != 0)
+ if (((sr & STM32_TIM_SR_CC3IF) != 0) &&
+ (PWMD1.config->channels[2].callback != NULL))
PWMD1.config->channels[2].callback(&PWMD1);
- if ((sr & STM32_TIM_SR_CC4IF) != 0)
+ if (((sr & STM32_TIM_SR_CC4IF) != 0) &&
+ (PWMD1.config->channels[3].callback != NULL))
PWMD1.config->channels[3].callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
@@ -277,7 +289,8 @@ OSAL_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
OSAL_IRQ_PROLOGUE();
STM32_TIM8->SR = ~TIM_SR_UIF;
- PWMD8.config->callback(&PWMD8);
+ if (PWMD8.config->callback != NULL)
+ PWMD8.config->callback(&PWMD8);
OSAL_IRQ_EPILOGUE();
}
@@ -298,15 +311,22 @@ OSAL_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) {
OSAL_IRQ_PROLOGUE();
- sr = STM32_TIM8->SR & STM32_TIM8->DIER & STM32_TIM_DIER_IRQ_MASK;
+ sr = STM32_TIM8->SR & STM32_TIM8->DIER & (STM32_TIM_DIER_CC1IE |
+ STM32_TIM_DIER_CC2IE |
+ STM32_TIM_DIER_CC3IE |
+ STM32_TIM_DIER_CC4IE);
STM32_TIM8->SR = ~sr;
- if ((sr & STM32_TIM_SR_CC1IF) != 0)
+ if (((sr & STM32_TIM_SR_CC1IF) != 0) &&
+ (PWMD8.config->channels[0].callback != NULL))
PWMD8.config->channels[0].callback(&PWMD8);
- if ((sr & STM32_TIM_SR_CC2IF) != 0)
+ if (((sr & STM32_TIM_SR_CC2IF) != 0) &&
+ (PWMD8.config->channels[1].callback != NULL))
PWMD8.config->channels[1].callback(&PWMD8);
- if ((sr & STM32_TIM_SR_CC3IF) != 0)
+ if (((sr & STM32_TIM_SR_CC3IF) != 0) &&
+ (PWMD8.config->channels[2].callback != NULL))
PWMD8.config->channels[2].callback(&PWMD8);
- if ((sr & STM32_TIM_SR_CC4IF) != 0)
+ if (((sr & STM32_TIM_SR_CC4IF) != 0) &&
+ (PWMD8.config->channels[3].callback != NULL))
PWMD8.config->channels[3].callback(&PWMD8);
OSAL_IRQ_EPILOGUE();
@@ -346,42 +366,49 @@ void pwm_lld_init(void) {
#if STM32_PWM_USE_TIM1
/* Driver initialization.*/
pwmObjectInit(&PWMD1);
+ PWMD1.channels = STM32_TIM1_CHANNELS;
PWMD1.tim = STM32_TIM1;
#endif
#if STM32_PWM_USE_TIM2
/* Driver initialization.*/
pwmObjectInit(&PWMD2);
+ PWMD2.channels = STM32_TIM2_CHANNELS;
PWMD2.tim = STM32_TIM2;
#endif
#if STM32_PWM_USE_TIM3
/* Driver initialization.*/
pwmObjectInit(&PWMD3);
+ PWMD3.channels = STM32_TIM3_CHANNELS;
PWMD3.tim = STM32_TIM3;
#endif
#if STM32_PWM_USE_TIM4
/* Driver initialization.*/
pwmObjectInit(&PWMD4);
+ PWMD4.channels = STM32_TIM4_CHANNELS;
PWMD4.tim = STM32_TIM4;
#endif
#if STM32_PWM_USE_TIM5
/* Driver initialization.*/
pwmObjectInit(&PWMD5);
+ PWMD5.channels = STM32_TIM5_CHANNELS;
PWMD5.tim = STM32_TIM5;
#endif
#if STM32_PWM_USE_TIM8
/* Driver initialization.*/
pwmObjectInit(&PWMD8);
+ PWMD8.channels = STM32_TIM8_CHANNELS;
PWMD8.tim = STM32_TIM8;
#endif
#if STM32_PWM_USE_TIM9
/* Driver initialization.*/
pwmObjectInit(&PWMD9);
+ PWMD9.channels = STM32_TIM9_CHANNELS;
PWMD9.tim = STM32_TIM9;
#endif
}
@@ -475,6 +502,10 @@ void pwm_lld_start(PWMDriver *pwmp) {
STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE;
pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE |
STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE;
+#if STM32_TIM_MAX_CHANNELS > 4
+ pwmp->tim->CCMR3 = STM32_TIM_CCMR3_OC5M(6) | STM32_TIM_CCMR3_OC5PE |
+ STM32_TIM_CCMR3_OC6M(6) | STM32_TIM_CCMR3_OC6PE;
+#endif
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
@@ -486,6 +517,12 @@ void pwm_lld_start(PWMDriver *pwmp) {
pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */
pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */
pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */
+#if STM32_TIM_MAX_CHANNELS > 4
+ if (pwmp->channels > 4) {
+ pwmp->tim->CCXR[0] = 0; /* Comparator 5 disabled. */
+ pwmp->tim->CCXR[1] = 0; /* Comparator 6 disabled. */
+ }
+#endif
pwmp->tim->CNT = 0; /* Counter reset to zero. */
}
@@ -571,7 +608,6 @@ void pwm_lld_start(PWMDriver *pwmp) {
pwmp->tim->CCER = ccer;
pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
- pwmp->tim->DIER |= pwmp->config->callback == NULL ? 0 : STM32_TIM_DIER_UIE;
pwmp->tim->SR = 0; /* Clear pending IRQs. */
#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8
#if STM32_PWM_USE_ADVANCED
@@ -655,9 +691,10 @@ void pwm_lld_stop(PWMDriver *pwmp) {
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is active using the specified configuration.
* @note The function has effect at the next cycle start.
+ * @note Channel notification is not enabled.
*
* @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...channels-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @notapi
@@ -666,36 +703,121 @@ void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
- pwmp->tim->CCR[channel] = width; /* New duty cycle. */
- /* If there is a callback defined for the channel then the associated
- interrupt must be enabled.*/
- if (pwmp->config->channels[channel].callback != NULL) {
- uint32_t dier = pwmp->tim->DIER;
- /* If the IRQ is not already enabled care must be taken to clear it,
- it is probably already pending because the timer is running.*/
- if ((dier & (2 << channel)) == 0) {
- pwmp->tim->DIER = dier | (2 << channel);
- pwmp->tim->SR = ~(2 << channel);
- }
- }
+ /* Changing channel duty cycle on the fly.*/
+#if STM32_TIM_MAX_CHANNELS <= 4
+ pwmp->tim->CCR[channel] = width;
+#else
+ if (channel <= 4)
+ pwmp->tim->CCR[channel] = width;
+ else
+ pwmp->tim->CCXR[channel - 4] = width;
+#endif
}
/**
- * @brief Disables a PWM channel.
+ * @brief Disables a PWM channel and its notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is disabled and its output line returned to the
* idle state.
* @note The function has effect at the next cycle start.
*
* @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...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
+#if STM32_TIM_MAX_CHANNELS <= 4
pwmp->tim->CCR[channel] = 0;
pwmp->tim->DIER &= ~(2 << channel);
+#else
+ if (channel <= 4) {
+ pwmp->tim->CCR[channel] = 0;
+ pwmp->tim->DIER &= ~(2 << channel);
+ }
+ else
+ pwmp->tim->CCXR[channel - 4] = 0;
+#endif
+}
+
+/**
+ * @brief Enables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
+ uint32_t dier = pwmp->tim->DIER;
+
+ /* If the IRQ is not already enabled care must be taken to clear it,
+ it is probably already pending because the timer is running.*/
+ if ((dier & STM32_TIM_DIER_UIE) == 0) {
+ pwmp->tim->DIER = dier | STM32_TIM_DIER_UIE;
+ pwmp->tim->SR &= STM32_TIM_SR_UIF;
+ }
+}
+
+/**
+ * @brief Disables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @notapi
+ */
+void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
+
+ pwmp->tim->DIER &= ~STM32_TIM_DIER_UIE;
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+ uint32_t dier = pwmp->tim->DIER;
+
+#if STM32_TIM_MAX_CHANNELS > 4
+ /* Channels 4 and 5 do not support callbacks.*/
+ osalDbgAssert(channel < 4, "callback not supported");
+#endif
+
+ /* If the IRQ is not already enabled care must be taken to clear it,
+ it is probably already pending because the timer is running.*/
+ if ((dier & (2 << channel)) == 0) {
+ pwmp->tim->DIER = dier | (2 << channel);
+ pwmp->tim->SR = ~(2 << channel);
+ }
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel) {
+
+ pwmp->tim->DIER &= ~(2 << channel);
}
#endif /* HAL_USE_PWM */
diff --git a/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.h b/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.h
index ca517651e..5b54847fb 100644
--- a/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.h
+++ b/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.h
@@ -36,9 +36,13 @@
/**
* @brief Number of PWM channels per PWM driver.
*/
-#define PWM_CHANNELS 4
+#define PWM_CHANNELS STM32_TIM_MAX_CHANNELS
/**
+ * @name STM32-specific PWM complementary output mode macros
+ * @{
+ */
+/**
* @brief Complementary output modes mask.
* @note This is an STM32-specific setting.
*/
@@ -67,6 +71,7 @@
* timers TIM1 and TIM8.
*/
#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20
+/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
@@ -283,22 +288,27 @@
/*===========================================================================*/
/**
- * @brief PWM mode type.
+ * @brief Type of a PWM mode.
*/
typedef uint32_t pwmmode_t;
/**
- * @brief PWM channel type.
+ * @brief Type of a PWM channel.
*/
typedef uint8_t pwmchannel_t;
/**
- * @brief PWM counter type.
+ * @brief Type of a channels mask.
+ */
+typedef uint32_t pwmchnmsk_t;
+
+/**
+ * @brief Type of a PWM counter.
*/
typedef uint16_t pwmcnt_t;
/**
- * @brief PWM driver channel configuration structure.
+ * @brief Type of a PWM driver channel configuration structure.
*/
typedef struct {
/**
@@ -315,7 +325,7 @@ typedef struct {
} PWMChannelConfig;
/**
- * @brief PWM driver configuration structure.
+ * @brief Type of a PWM driver configuration structure.
*/
typedef struct {
/**
@@ -377,6 +387,14 @@ struct PWMDriver {
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
+ /**
+ * @brief Mask of the enabled channels.
+ */
+ pwmchnmsk_t enabled;
+ /**
+ * @brief Number of channels in this instance.
+ */
+ pwmchannel_t channels;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
@@ -414,19 +432,6 @@ struct PWMDriver {
#define pwm_lld_change_period(pwmp, period) \
((pwmp)->tim->ARR = (uint16_t)((period) - 1))
-/**
- * @brief Returns a PWM channel status.
- * @pre The PWM unit must have been activated using @p pwmStart().
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
- *
- * @notapi
- */
-#define pwm_lld_is_channel_enabled(pwmp, channel) \
- (((pwmp)->tim->CCR[channel] != 0) || \
- (((pwmp)->tim->DIER & (2 << channel)) != 0))
-
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -469,6 +474,12 @@ extern "C" {
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
+ void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
+ void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
+ void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
+ pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h b/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h
index 1e0c9ecbb..9770846c6 100644
--- a/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h
+++ b/os/hal/ports/STM32/LLD/TIMv1/stm32_tim.h
@@ -431,8 +431,7 @@ typedef struct {
volatile uint32_t DMAR;
volatile uint32_t OR;
volatile uint32_t CCMR3;
- volatile uint32_t CCR5;
- volatile uint32_t CCR6;
+ volatile uint32_t CCXR[2];
} stm32_tim_t;
/*===========================================================================*/
diff --git a/os/hal/ports/STM32/STM32F0xx/stm32_registry.h b/os/hal/ports/STM32/STM32F0xx/stm32_registry.h
index f6d183a8d..a00ff3960 100644
--- a/os/hal/ports/STM32/STM32F0xx/stm32_registry.h
+++ b/os/hal/ports/STM32/STM32F0xx/stm32_registry.h
@@ -106,6 +106,8 @@
#define STM32_HAS_SPI6 FALSE
/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 4
+
#define STM32_HAS_TIM1 TRUE
#define STM32_TIM1_IS_32BITS FALSE
#define STM32_TIM1_CHANNELS 4
@@ -236,6 +238,8 @@
#define STM32_HAS_SPI6 FALSE
/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 4
+
#define STM32_HAS_TIM1 TRUE
#define STM32_TIM1_IS_32BITS FALSE
#define STM32_TIM1_CHANNELS 4
@@ -363,6 +367,8 @@
#define STM32_HAS_SPI6 FALSE
/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 4
+
#define STM32_HAS_TIM1 TRUE
#define STM32_TIM1_IS_32BITS FALSE
#define STM32_TIM1_CHANNELS 4
diff --git a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
index 8f2d9c442..50a082b33 100644
--- a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
+++ b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
@@ -193,6 +193,8 @@
#endif /* !(defined(STM32F427_437xx) || defined(STM32F429_439xx)) */
/* TIM attributes.*/
+#define STM32_TIM_MAX_CHANNELS 4
+
#define STM32_HAS_TIM1 TRUE
#define STM32_TIM1_IS_32BITS FALSE
#define STM32_TIM1_CHANNELS 4
diff --git a/os/hal/src/pwm.c b/os/hal/src/pwm.c
index c10fda3ce..eb35e434e 100644
--- a/os/hal/src/pwm.c
+++ b/os/hal/src/pwm.c
@@ -73,6 +73,8 @@ void pwmObjectInit(PWMDriver *pwmp) {
pwmp->state = PWM_STOP;
pwmp->config = NULL;
+ pwmp->enabled = 0;
+ pwmp->channels = 0;
#if defined(PWM_DRIVER_EXT_INIT_HOOK)
PWM_DRIVER_EXT_INIT_HOOK(pwmp);
#endif
@@ -117,7 +119,8 @@ void pwmStop(PWMDriver *pwmp) {
osalDbgAssert((pwmp->state == PWM_STOP) || (pwmp->state == PWM_READY),
"invalid state");
pwm_lld_stop(pwmp);
- pwmp->state = PWM_STOP;
+ pwmp->enabled = 0;
+ pwmp->state = PWM_STOP;
osalSysUnlock();
}
@@ -155,7 +158,7 @@ void pwmChangePeriod(PWMDriver *pwmp, pwmcnt_t period) {
* or immediately (fallback implementation).
*
* @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...channels-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @api
@@ -164,16 +167,19 @@ void pwmEnableChannel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
- osalDbgCheck((pwmp != NULL) && (channel < PWM_CHANNELS));
+ osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
osalSysLock();
+
osalDbgAssert(pwmp->state == PWM_READY, "not ready");
- pwm_lld_enable_channel(pwmp, channel, width);
+
+ pwmEnableChannelI(pwmp, channel, width);
+
osalSysUnlock();
}
/**
- * @brief Disables a PWM channel.
+ * @brief Disables a PWM channel and its notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is disabled and its output line returned to the
* idle state.
@@ -182,17 +188,122 @@ void pwmEnableChannel(PWMDriver *pwmp,
* or immediately (fallback implementation).
*
* @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...channels-1)
*
* @api
*/
void pwmDisableChannel(PWMDriver *pwmp, pwmchannel_t channel) {
- osalDbgCheck((pwmp != NULL) && (channel < PWM_CHANNELS));
+ osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(pwmp->state == PWM_READY, "not ready");
+
+ pwmDisableChannelI(pwmp, channel);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @api
+ */
+void pwmEnablePeriodicNotification(PWMDriver *pwmp) {
+
+ osalDbgCheck(pwmp != NULL);
+
+ osalSysLock();
+
+ osalDbgAssert(pwmp->state == PWM_READY, "not ready");
+ osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback");
+
+ pwm_lld_enable_periodic_notification(pwmp);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables the periodic activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ *
+ * @api
+ */
+void pwmDisablePeriodicNotification(PWMDriver *pwmp) {
+
+ osalDbgCheck(pwmp != NULL);
+
+ osalSysLock();
+
+ osalDbgAssert(pwmp->state == PWM_READY, "not ready");
+ osalDbgAssert(pwmp->config->callback != NULL, "undefined periodic callback");
+
+ pwm_lld_disable_periodic_notification(pwmp);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @api
+ */
+void pwmEnableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) {
+
+ osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(pwmp->state == PWM_READY, "not ready");
+ osalDbgAssert((pwmp->enabled & (1 << channel)) != 0,
+ "channel not enabled");
+ osalDbgAssert(pwmp->config->channels[channel].callback != NULL,
+ "undefined channel callback");
+
+ pwm_lld_enable_channel_notification(pwmp, channel);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @pre The channel must have been activated using @p pwmEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
+ * @param[in] channel PWM channel identifier (0...channels-1)
+ *
+ * @api
+ */
+void pwmDisableChannelNotification(PWMDriver *pwmp, pwmchannel_t channel) {
+
+ osalDbgCheck((pwmp != NULL) && (channel < pwmp->channels));
osalSysLock();
+
osalDbgAssert(pwmp->state == PWM_READY, "not ready");
- pwm_lld_disable_channel(pwmp, channel);
+ osalDbgAssert((pwmp->enabled & (1 << channel)) != 0,
+ "channel not enabled");
+ osalDbgAssert(pwmp->config->channels[channel].callback != NULL,
+ "undefined channel callback");
+
+ pwm_lld_disable_channel_notification(pwmp, channel);
+
osalSysUnlock();
}