You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/03/06 17:30:11 UTC
[nuttx] 02/02: samv7: add support for dead time delay to PWM driver
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit f97d93903c6ddd5afc90159b70ba9780c076cbbd
Author: Michal Lenc <mi...@seznam.cz>
AuthorDate: Mon Mar 6 12:43:38 2023 +0100
samv7: add support for dead time delay to PWM driver
This commit adds support for dead time delay to SAMv7 PWM driver. The
dead time can be used to delay an active PWM output at the begining
of the period. This can be used for H bridge control for example.
The values are to be set from the application level. It is required
to allow config option PWM_DEADTIME in order to support dead time delay.
Signed-off-by: Michal Lenc <mi...@seznam.cz>
---
arch/arm/src/samv7/Kconfig | 1 +
arch/arm/src/samv7/sam_pwm.c | 105 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig
index 85019d244c..80bc5fae2b 100644
--- a/arch/arm/src/samv7/Kconfig
+++ b/arch/arm/src/samv7/Kconfig
@@ -314,6 +314,7 @@ config SAMV7_PWM
default n
select ARCH_HAVE_PWM_MULTICHAN
select ARCH_HAVE_PWM_OVERWRITE
+ select ARCH_HAVE_PWM_DEADTIME
config SAMV7_HAVE_SDRAMC
bool
diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c
index b59b545e76..cd08629fe9 100644
--- a/arch/arm/src/samv7/sam_pwm.c
+++ b/arch/arm/src/samv7/sam_pwm.c
@@ -326,6 +326,11 @@ static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel,
static void pwm_set_freq(struct pwm_lowerhalf_s *dev, uint8_t channel,
uint32_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);
+#endif
/****************************************************************************
* Private Functions
@@ -530,6 +535,90 @@ static void pwm_set_comparison(struct pwm_lowerhalf_s *dev)
}
}
+/****************************************************************************
+ * Name: pwm_set_deadtime
+ *
+ * Description:
+ * Set deadtime generator values.
+ *
+ * Input Parameters:
+ * dev - A reference to the lower half PWM driver state structure
+ * channel - Channel to by updated
+ * dead_time_a - dead time value for output A
+ * dead_time_b - dead time value for output B
+ * duty - channel duty cycle
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#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)
+{
+ struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
+ uint16_t period;
+ uint16_t width_1;
+ uint16_t width_2;
+ uint16_t regval;
+
+ /* Get the period value */
+
+ period = pwm_getreg(priv, SAMV7_PWM_CPRDX + (channel * CHANNEL_OFFSET));
+
+ /* 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.
+ *
+ * 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);
+
+ /* It is required width_1 < (CORD - CDTY) and
+ * width_2 < CDTY
+ */
+
+ if (width_1 > (period - regval))
+ {
+ pwmerr("ERROR: Dead Time value DTH has to be < period - duty! " \
+ "Setting DTH to 0\n");
+ width_1 = 0;
+ }
+
+ if (width_2 > regval)
+ {
+ pwmerr("ERROR: Dead Time value DTL has to be < duty! " \
+ "Setting DTL to 0\n");
+ width_2 = 0;
+ }
+
+ /* Update dead time value */
+
+ if (pwm_getreg(priv, SAMV7_PWM_SR) & CHID_SEL(1 << channel))
+ {
+ pwm_putreg(priv, SAMV7_PWM_DTUPDX + (channel * CHANNEL_OFFSET),
+ DTUPD_DTHUPD_SEL(width_1) | DTUPD_DTLUPD_SEL(width_2));
+ }
+ else
+ {
+ pwm_putreg(priv, SAMV7_PWM_DTX + (channel * CHANNEL_OFFSET),
+ DT_DTH_SEL(width_1) | DT_DTL_SEL(width_2));
+ }
+}
+#endif
+
/****************************************************************************
* Name: pwm_setup
*
@@ -581,7 +670,11 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev)
channel = priv->channels[i].channel;
- regval = CMR_CPOL | CMR_DPOLI;
+ regval = CMR_DPOLI;
+#ifdef CONFIG_PWM_DEADTIME
+ regval |= CMR_DTE;
+#endif
+
pwm_putreg(priv, SAMV7_PWM_CMRX + (channel * CHANNEL_OFFSET), regval);
/* Reset duty cycle register */
@@ -713,6 +806,12 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
pwm_set_freq(dev, priv->channels[index - 1].channel,
info->frequency);
+#ifdef CONFIG_PWM_DEADTIME
+ pwm_set_deadtime(dev, priv->channels[index - 1].channel,
+ info->channels[i].dead_time_a,
+ info->channels[i].dead_time_b,
+ info->channels[i].duty);
+#endif
pwm_set_output(dev, priv->channels[index - 1].channel,
info->channels[i].duty);
#ifdef CONFIG_PWM_OVERWRITE
@@ -740,6 +839,10 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
/* 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[index - 1].channel,
+ info->dead_time_a, info->dead_time_b);
+#endif
pwm_set_output(dev, priv->channels[0].channel, info->duty);
#endif