X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Fpwm.c;h=2448f5681f13c5180c3da70a8dd786cf0714c38e;hb=12a865a058c2c3da0e4da685158f3a506ffad876;hp=3946188262263c0f406062adef2fac522a19d77b;hpb=791e167e053bdd9250d34a9a5ccae6ccde4d6679;p=bertos.git diff --git a/bertos/drv/pwm.c b/bertos/drv/pwm.c index 39461882..2448f568 100644 --- a/bertos/drv/pwm.c +++ b/bertos/drv/pwm.c @@ -32,78 +32,216 @@ * * \brief PWM driver (implementation) * - * \version $Id$ * * \author Francesco Sacchi * \author Daniele Basile */ -#include -#include - -#include -#include +#include "cfg/cfg_pwm.h" #include -#include - - -/** - * 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_duty_t)PWM_MAX_DUTY); - - period = pwm_hw_getPeriod(dev); - - real_duty = (uint64_t)(duty * period) >> (uint64_t)PWM_MAX_PERIOD_LOG2; - -// kprintf("real_duty[%d] duty[%d], period[%d]\n", real_duty, duty, period); - pwm_hw_setDutyUnlock(dev, real_duty); -} +#include -/** - * 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); -} +// Define logging setting (for cfg/log.h module). +#define LOG_LEVEL PWM_LOG_LEVEL +#define LOG_VERBOSITY PWM_LOG_FORMAT -/** - * 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) -{ - cpuflags_t flags; - PwmDev dev; - - IRQ_SAVE_DISABLE(flags); - - /* set all pwm to 0 */ - for (dev = 0; dev < PWM_CNT; dev++) - pwm_setDuty(dev, 0); +#include +#include - pwm_hw_init(); +#include - IRQ_RESTORE(flags); -} +#include CPU_HEADER(pwm) +#include +#include +#include + +#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