Update preset.
[bertos.git] / bertos / drv / pwm.c
index cb5a45fb0e7293b7f5c292ff2fad620dc9f09a3b..2448f5681f13c5180c3da70a8dd786cf0714c38e 100644 (file)
@@ -32,7 +32,6 @@
  *
  * \brief PWM driver (implementation)
  *
- * \version $Id$
  *
  * \author Francesco Sacchi <batt@develer.com>
  * \author Daniele Basile <asterix@develer.com>
@@ -41,6 +40,7 @@
 #include "cfg/cfg_pwm.h"
 
 #include <cfg/macros.h>
+#include <cfg/module.h>
 
 // Define logging setting (for cfg/log.h module).
 #define LOG_LEVEL         PWM_LOG_LEVEL
 #include <cpu/types.h>
 #include <cpu/irq.h>
 
-
-/**
- * Set duty of pwm channel \p dev.
- */
-void pwm_setDuty(PwmDev dev, pwm_duty_t duty)
-{
-       pwm_period_t period = 0;
-       pwm_duty_t real_duty = 0;
-
-       duty = MIN(duty, PWM_MAX_DUTY);
-
-       period = pwm_hw_getPeriod(dev);
-
-       real_duty = (uint64_t)(duty * period) >> (uint64_t)PWM_MAX_PERIOD_LOG2;
-
-       LOG_INFO("real_duty[%d] duty[%d], period[%d]", real_duty, duty, period);
-       pwm_hw_setDutyUnlock(dev, real_duty);
-}
-
-/**
- * Set frequency of pwm channel \p dev at \p freq in Hz.
- */
-void pwm_setFrequency(PwmDev dev, pwm_freq_t freq)
-{
-       pwm_hw_setFrequency(dev, freq);
-}
-
-/**
- * Set duty of pwm channel \p dev.
- */
-void pwm_enable(PwmDev dev, bool state)
-{
-       if (state)
-               pwm_hw_enable(dev);
-       else
-               pwm_hw_disable(dev);
-}
-
-/**
- * Initialize PWM hw.
- */
-void pwm_init(void)
-{
-       cpu_flags_t flags;
-       PwmDev dev;
-
-       IRQ_SAVE_DISABLE(flags);
-
-       pwm_hw_init();
-
-       /* set all pwm to 0 */
-       for (dev = 0; dev < PWM_CNT; dev++)
-               pwm_setDuty(dev, 0);
-
-       IRQ_RESTORE(flags);
-}
-
-
+#include <string.h>
+
+#if CFG_PWM_ENABLE_OLD_API
+
+       /**
+        * Set duty of PWM channel \p dev.
+        * The current output frequency will be maintained.
+        * \param dev PWM channel.
+        * \param duty the new duty cycle.
+        */
+       void pwm_setDuty(PwmDev dev, pwm_duty_t duty)
+       {
+               pwm_period_t period = 0;
+               pwm_duty_t real_duty = 0;
+
+               duty = MIN(duty, PWM_MAX_DUTY);
+
+               period = pwm_hw_getPeriod(dev);
+
+               real_duty = (uint64_t)(duty * period) >> (uint64_t)PWM_MAX_PERIOD_LOG2;
+
+               LOG_INFO("real_duty[%d] duty[%d], period[%d]\n", real_duty, duty, period);
+               pwm_hw_setDutyUnlock(dev, real_duty);
+       }
+
+       /**
+        * Set frequency of PWM channel \p dev at \p freq.
+        * \param dev PWM channel.
+        * \param freq new frequency, in Hz.
+        * \warning This function has to be called with PWM disabled, otherwise
+        *          the output value will be undefined.
+        *          The current duty cycle value will be lost, after calling this
+        *          function the duty cycle have to be set again.
+        */
+       void pwm_setFrequency(PwmDev dev, pwm_freq_t freq)
+       {
+               pwm_hw_setFrequency(dev, freq);
+       }
+
+       /**
+        * Enable/Disable PWM channel \p dev.
+        * \param dev PWM channel.
+        * \param state if true the PWM on \p dev is activated, if false is disabled.
+        */
+       void pwm_enable(PwmDev dev, bool state)
+       {
+               if (state)
+                       pwm_hw_enable(dev);
+               else
+                       pwm_hw_disable(dev);
+       }
+
+       MOD_DEFINE(pwm);
+
+       /**
+        * Initialize the PWM driver.
+        * \warning all available PWM channels are initialized.
+        */
+       void pwm_init(void)
+       {
+               cpu_flags_t flags;
+               PwmDev dev;
+
+               IRQ_SAVE_DISABLE(flags);
+
+               pwm_hw_init();
+
+               /* set all pwm to 0 */
+               for (dev = 0; dev < PWM_CNT; dev++)
+                       pwm_setDuty(dev, 0);
+
+               IRQ_RESTORE(flags);
+               MOD_INIT(pwm);
+       }
+#endif
+
+#if !CFG_PWM_ENABLE_OLD_API || defined(__doxygen__)
+
+       INLINE void setRealDuty(Pwm *ctx, pwm_duty_t duty)
+       {
+               if (ctx->pol == PWM_POL_LOW_PULSE)
+                       duty = PWM_MAX_DUTY - duty;
+
+               pwm_hwreg_t period = pwm_hw_getPeriod(ctx);
+               pwm_hwreg_t hw_duty;
+
+               switch (duty)
+               {
+               case 0:
+                       hw_duty = 0;
+                       break;
+               case PWM_MAX_DUTY:
+                       hw_duty = period;
+                       break;
+               default:
+                       hw_duty = (uint64_t)(duty * period) >> (uint64_t)PWM_MAX_PERIOD_LOG2;
+               }
+
+               pwm_hw_setDuty(ctx, hw_duty);
+       }
+
+       /**
+        * Set the duty cycle of the PWM channel linked to \p ctx.
+        * The modification will be applied to the channel immediatly.
+        * The current frequency of the channel will be maintained.
+        * \param ctx PWM channel context.
+        * \param duty the new duty cycle value.
+        * \see pwm_duty_t
+        */
+       void pwm_setDuty(Pwm *ctx, pwm_duty_t duty)
+       {
+               ctx->duty = duty;
+
+               if (ctx->enabled)
+                       setRealDuty(ctx, duty);
+       }
+
+       /**
+        * Set PWM frequency of channel linked to \p ctx.
+        * The modification will be applied to the channel immediatly.
+        * The duty cycle of the channel will be maintained.
+        * \param ctx PWM channel context.
+        * \param freq the new frequency of the signal, in Hz.
+        * \note Depending on the hardware implementation, this function may
+        *       generate a glitch in the output signal upon frequency changing.
+        */
+       void pwm_setFrequency(Pwm *ctx, pwm_freq_t freq)
+       {
+               pwm_hw_setFrequency(ctx, freq);
+               pwm_enable(ctx, ctx->enabled);
+       }
+
+       /**
+        * Set PWM polarity of pwm channel linked to \p ctx.
+        * The modification will be applied to the channel immediatly.
+        * \param ctx PWM channel context.
+        * \param pol the new polarity of the signal.
+        *
+        * \note if a channel is disabled, changing its polarity will change the
+        *       current steady output level.
+        * \see pwm_enable
+        * \see PwmPolarity
+        */
+       void pwm_setPolarity(Pwm *ctx, PwmPolarity pol)
+       {
+               ctx->pol = pol;
+               pwm_enable(ctx, ctx->enabled);
+       }
+
+       /**
+        * Enable/Disable the pwm channel linked to \p ctx.
+        * The modification will be applied to the channel immediatly.
+        * \param ctx PWM channel context.
+        * \param enable if true the channel will be enabled, if false will be disabled.
+        *
+        * \note When a PWM channel is disabled, the output level will be the same
+        *       as if the duty would be set to 0%.
+        *       So, if current polarity is positive, a disabled channel will be
+        *       low, if polarity is negative will be high.
+        * \see pwm_setPolarity
+        */
+       void pwm_enable(Pwm *ctx, bool enable)
+       {
+               ctx->enabled = enable;
+
+               if (enable)
+                       setRealDuty(ctx, ctx->duty);
+               else
+                       setRealDuty(ctx, 0);
+       }
+
+       /**
+        * Initialize PWM driver.
+        * \param ctx pointer to a PWM context structure, used for holding PWM
+        *            driver related information.
+        * \param channel the channel you want to initialize.
+        * \note The channel will be initialized disabled and with High polarity.
+        */
+       void pwm_init(Pwm *ctx, unsigned channel)
+       {
+               memset(ctx, 0, sizeof(*ctx));
+               ctx->ch = channel;
+
+               pwm_hw_init(ctx, channel);
+       }
+
+#endif