Skip to content

Commit

Permalink
pwm refactor
Browse files Browse the repository at this point in the history
Signed-off-by: Michal Lenc <michallenc@seznam.cz>
  • Loading branch information
michallenc committed Sep 26, 2024
1 parent d9b95c5 commit 8224f0e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 88 deletions.
56 changes: 13 additions & 43 deletions arch/arm/src/samv7/sam_pwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@

#ifdef CONFIG_SAMV7_PWM

#ifdef CONFIG_PWM_NCHANNELS
# define PWM_NCHANNELS CONFIG_PWM_NCHANNELS
#else
# define PWM_NCHANNELS 1
#endif

#define CHANNEL_OFFSET 0x20
#define COMP_OFFSET 0x10
#define FAULT_SEL_OFFSET 0x8
Expand Down Expand Up @@ -436,14 +430,14 @@ static uint32_t pwm_getreg(struct sam_pwm_s *priv, uint32_t offset);
/* Helper functions */

static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel,
ub16_t duty);
pwm_duty_t duty);
static void pwm_set_freq(struct pwm_lowerhalf_s *dev, uint8_t channel,
uint32_t frequency);
pwm_freq_t frequency);
static void pwm_set_comparison(struct pwm_lowerhalf_s *dev);
#ifdef CONFIG_PWM_DEADTIME
static void pwm_set_deadtime(struct pwm_lowerhalf_s *dev, uint8_t channel,
ub16_t dead_time_a, ub16_t dead_time_b,
ub16_t duty);
pwm_duty_t dead_time_a, pwm_duty_t dead_time_b,
pwm_duty_t duty);
#endif
static void pwm_set_polarity(struct pwm_lowerhalf_s *dev, uint8_t channel,
uint8_t cpol, uint8_t dcpol);
Expand Down Expand Up @@ -481,7 +475,7 @@ static uint32_t pwm_getreg(struct sam_pwm_s *priv, uint32_t offset)
****************************************************************************/

static void pwm_set_freq(struct pwm_lowerhalf_s *dev, uint8_t channel,
uint32_t frequency)
pwm_freq_t frequency)
{
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
uint32_t regval;
Expand Down Expand Up @@ -542,7 +536,7 @@ static void pwm_set_freq(struct pwm_lowerhalf_s *dev, uint8_t channel,
****************************************************************************/

static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel,
ub16_t duty)
pwm_duty_t duty)
{
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
uint16_t period;
Expand All @@ -555,7 +549,7 @@ static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel,

/* Compute PWM width (count value to set PWM low) */

width = b16toi(duty * period + b16HALF);
width = b16toi(b16divi(ftob16(duty), 100) * period + b16HALF);

/* Update duty cycle */

Expand Down Expand Up @@ -675,8 +669,8 @@ static void pwm_set_comparison(struct pwm_lowerhalf_s *dev)

#ifdef CONFIG_PWM_DEADTIME
static void pwm_set_deadtime(struct pwm_lowerhalf_s *dev, uint8_t channel,
ub16_t dead_time_a, ub16_t dead_time_b,
ub16_t duty)
pwm_duty_t dead_time_a, pwm_duty_t dead_time_b,
pwm_duty_t duty)
{
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
uint16_t period;
Expand All @@ -691,20 +685,14 @@ static void pwm_set_deadtime(struct pwm_lowerhalf_s *dev, uint8_t channel,
/* Compute channel's duty cycle value. Dead time counter has only 12 bits
* and not 16 as duty cycle or period counter. Therefore a 12 bits recount
* is necessary to set the dead time value corresponding to selected
* frequency. This expects the dead time value selected in the application
* is moved left by 12 and devided by 100. For example:
* dead_time_a = (selected_dead_time_duty << 12) / 100
* This aproach is the same as with duty cycle setup in the application
* but with 12 bits.
* frequency.
*
* Also note that it might not be possible to get correct delay on lower
* frequencies since dead time register has only 12 bits.
*/

width_1 = (dead_time_a * period) >> 12;
width_2 = (dead_time_b * period) >> 12;

regval = b16toi(duty * period + b16HALF);
width_1 = (((b16_t)(dead_time_a * 4096.0f) / 100) * period) >> 12;
width_2 = (((b16_t)(dead_time_b * 4096.0f) / 100) * period) >> 12;

/* It is required width_1 < (CORD - CDTY) and
* width_2 < CDTY
Expand Down Expand Up @@ -957,7 +945,6 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
const struct pwm_info_s *info)
{
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
#ifdef CONFIG_PWM_MULTICHAN
uint32_t regval;

for (int i = 0; i < PWM_NCHANNELS; i++)
Expand All @@ -978,7 +965,7 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
/* Set the frequency and enable PWM output for each channel */

pwm_set_freq(dev, priv->channels[index - 1].channel,
info->frequency);
info->channels[i].frequency);
#ifdef CONFIG_PWM_DEADTIME
pwm_set_deadtime(dev, priv->channels[index - 1].channel,
info->channels[i].dead_time_a,
Expand Down Expand Up @@ -1030,18 +1017,6 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
pwm_putreg(priv, SAMV7_PWM_ENA, CHID_SEL(1));
pwm_putreg(priv, SAMV7_PWM_SCUC, regval);
}
#else
/* Set the frequency and enable PWM output just for first channel */

pwm_set_freq(dev, priv->channels[0].channel, info->frequency);
#ifdef CONFIG_PWM_DEADTIME
pwm_set_deadtime(dev, priv->channels[0].channel,
info->dead_time_a, info->dead_time_b);
#endif
pwm_set_polarity(dev, priv->channels[0].channel,
info->cpol, info->dcpol);
pwm_set_output(dev, priv->channels[0].channel, info->duty);
#endif

pwm_set_comparison(dev);

Expand Down Expand Up @@ -1072,7 +1047,6 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev)
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
uint32_t regval;

#ifdef CONFIG_PWM_MULTICHAN
for (int i = 0; i < priv->channels_num; i++)
{
regval = CHID_SEL(1 << priv->channels[i].channel);
Expand All @@ -1085,10 +1059,6 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev)
regval &= ~(CHID_SEL(1 << 0) | CHID_SEL(1 << 1) |
CHID_SEL(1 << 2) | CHID_SEL(1 << 3));
pwm_putreg(priv, SAMV7_PWM_SCM, regval);
#else
regval = CHID_SEL(1 << priv->channels[0].channel);
pwm_putreg(priv, SAMV7_PWM_DIS, regval);
#endif /* CONFIG_PWM_MULTICHAN */

return OK;
}
Expand Down
15 changes: 4 additions & 11 deletions drivers/timers/pwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,14 @@ static const struct file_operations g_pwmops =
static void pwm_dump(FAR const char *msg, FAR const struct pwm_info_s *info,
bool started)
{
#ifdef CONFIG_PWM_MULTICHAN
int i;
#endif

pwminfo("%s: frequency: %" PRId32 "\n", msg, info->frequency);

#ifdef CONFIG_PWM_MULTICHAN
for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
for (i = 0; i < PWM_NCHANNELS; i++)
{
pwminfo(" channel: %d duty: %08" PRIx32 "\n",
info->channels[i].channel, info->channels[i].duty);
pwminfo(" channel: %d frequency: %" PWM_FREQ_PRI " duty:"
" %" PWM_FREQ_PRI "\n", info->channels[i].channel,
info->channels[i].frequency, info->channels[i].duty);
}
#else
pwminfo(" duty: %08" PRIx32 "\n", info->duty);
#endif

#ifdef CONFIG_PWM_PULSECOUNT
pwminfo(" count: %" PRIx32 "\n", info->count);
Expand Down
64 changes: 30 additions & 34 deletions include/nuttx/timers/pwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,61 +138,57 @@
#define PWM_DCPOL_LOW 1 /* Logical zero */
#define PWM_DCPOL_HIGH 2 /* Logical one */

/* PWM number of configured channels ****************************************/

#ifdef CONFIG_PWM_MULTICHAN
#define PWM_NCHANNELS CONFIG_PWM_NCHANNELS
#else
#define PWM_NCHANNELS 1
#endif

/* PWM frequency and duty types *********************************************/

#ifdef CONFIG_HAVE_FLOAT
typedef float pwm_freq_t;
typedef float pwm_duty_t;
#define PWM_FREQ_PRI "f"
#define PWM_DUTY_PRI "f"
#else
typedef uint32_t pwm_freq_t;
typedef uint8_t pwm_duty_t;
#define PWM_FREQ_PRI PRIx32
#define PWM_DUTY_PRI PRIx8
#endif

/****************************************************************************
* Public Types
****************************************************************************/

/* If the PWM peripheral supports multiple output channels, then this
* structure describes the output state on one channel.
*/
/* This structure describes the characteristics of one channel */

#ifdef CONFIG_PWM_MULTICHAN
struct pwm_chan_s
{
ub16_t duty;
pwm_freq_t frequency;
pwm_duty_t duty;
#ifdef CONFIG_PWM_OVERWRITE
bool ch_outp_ovrwr;
bool ch_outp_ovrwr_val;
#endif
#ifdef CONFIG_PWM_DEADTIME
ub16_t dead_time_a;
ub16_t dead_time_b;
pwm_duty_t dead_time_a;
pwm_duty_t dead_time_b;
#endif
uint8_t cpol;
uint8_t dcpol;
int8_t channel;
};
#endif

/* This structure describes the characteristics of the pulsed output */
/* This structure describes the PWM device */

struct pwm_info_s
{
uint32_t frequency; /* Frequency of the pulse train */

#ifdef CONFIG_PWM_MULTICHAN
/* Per-channel output state */

struct pwm_chan_s channels[CONFIG_PWM_NCHANNELS];

#else
ub16_t duty; /* Duty of the pulse train, "1"-to-"0" duration.
* Maximum: 65535/65536 (0x0000ffff)
* Minimum: 1/65536 (0x00000001) */
#ifdef CONFIG_PWM_DEADTIME
ub16_t dead_time_a; /* Dead time value for main output */
ub16_t dead_time_b; /* Dead time value for complementary output */
#endif
# ifdef CONFIG_PWM_PULSECOUNT
uint32_t count; /* The number of pulse to generate. 0 means to
* generate an indefinite number of pulses */
# endif
uint8_t cpol; /* Channel polarity */
uint8_t dcpol; /* Disabled channel polarity */
#endif /* CONFIG_PWM_MULTICHAN */

FAR void *arg; /* User provided argument to be used in the
* lower half */
struct pwm_chan_s channels[PWM_NCHANNELS];
FAR void *arg;
};

/* This structure is a set a callback functions used to call from the upper-
Expand Down

0 comments on commit 8224f0e

Please sign in to comment.