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
The following commit(s) were added to refs/heads/master by this push:
new 297b3b0209 arch/arm/src/samv7/sam_pwm.c: option to make channels
synchronous
297b3b0209 is described below
commit 297b3b0209b1f6cc0f35ec0f95380d4747b18292
Author: Pressl, Štěpán <[email protected]>
AuthorDate: Fri Apr 26 13:10:16 2024 +0200
arch/arm/src/samv7/sam_pwm.c: option to make channels synchronous
Make channels synchronous (i.e. share the same timebase) with the help
of SAMV7_PWMx_CHy_SYNC defines. All the channels share the same
timebase of channel 0, so this channel must be defined too.
Signed-off-by: Stepan Pressl <[email protected]>
---
arch/arm/src/samv7/Kconfig | 54 +++++++++++++++++++
arch/arm/src/samv7/sam_pwm.c | 126 +++++++++++++++++++++++++++++++++++++++++--
2 files changed, 175 insertions(+), 5 deletions(-)
diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig
index d3602c5f44..562685e8c3 100644
--- a/arch/arm/src/samv7/Kconfig
+++ b/arch/arm/src/samv7/Kconfig
@@ -669,6 +669,18 @@ menuconfig SAMV7_PWM0
if SAMV7_PWM0
+config SAMV7_PWM0_SYNC
+ bool "PWM0 synchronous channels"
+ depends on PWM_MULTICHAN
+ default n
+ ---help---
+ This option makes the synchronization between channels possible.
+ This means every synchronized channel has the same clock, the
+ same period and the same alignment. If any channel is defined
+ as synchronous, channel 0 is defined as synchronous too because
+ channel 0's counter is used by other synchronous channels.
+ This option automatically defines channel 0 as synchronous.
+
config SAMV7_PWM0_CH0
bool "PWM0 Channel 0"
default n
@@ -701,6 +713,11 @@ config SAMV7_PWM0_CH1_COMP
depends on !SAMV7_PWM0_CH1_LONLY
default n
+config SAMV7_PWM0_CH1_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM0_SYNC
+ default n
+
endif
config SAMV7_PWM0_CH2
@@ -718,6 +735,11 @@ config SAMV7_PWM0_CH2_COMP
depends on !SAMV7_PWM0_CH2_LONLY
default n
+config SAMV7_PWM0_CH2_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM0_SYNC
+ default n
+
endif
config SAMV7_PWM0_CH3
@@ -735,6 +757,11 @@ config SAMV7_PWM0_CH3_COMP
depends on !SAMV7_PWM0_CH3_LONLY
default n
+config SAMV7_PWM0_CH3_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM0_SYNC
+ default n
+
endif
menu "PWM Comparison units"
@@ -905,6 +932,18 @@ menuconfig SAMV7_PWM1
if SAMV7_PWM1
+config SAMV7_PWM1_SYNC
+ bool "PWM1 synchronous channels"
+ depends on PWM_MULTICHAN
+ default n
+ ---help---
+ This option makes the synchronization between channels possible.
+ This means every synchronized channel has the same clock, the
+ same period and the same alignment. If any channel is defined
+ as synchronous, channel 0 is defined as synchronous too because
+ channel 0's counter is used by other synchronous channels.
+ This option automatically defines channel 0 as synchronous.
+
config SAMV7_PWM1_CH0
bool "PWM1 Channel 0"
default n
@@ -937,6 +976,11 @@ config SAMV7_PWM1_CH1_COMP
depends on !SAMV7_PWM1_CH1_LONLY
default n
+config SAMV7_PWM1_CH1_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM1_SYNC
+ default n
+
endif
config SAMV7_PWM1_CH2
@@ -954,6 +998,11 @@ config SAMV7_PWM1_CH2_COMP
depends on !SAMV7_PWM1_CH2_LONLY
default n
+config SAMV7_PWM1_CH2_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM1_SYNC
+ default n
+
endif
config SAMV7_PWM1_CH3
@@ -971,6 +1020,11 @@ config SAMV7_PWM1_CH3_COMP
depends on !SAMV7_PWM1_CH3_LONLY
default n
+config SAMV7_PWM1_CH3_SYNC
+ bool "Synchronous channel"
+ depends on SAMV7_PWM1_SYNC
+ default n
+
endif
menu "PWM Comparison units"
diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c
index 58ce8ce16b..e743a83e2a 100644
--- a/arch/arm/src/samv7/sam_pwm.c
+++ b/arch/arm/src/samv7/sam_pwm.c
@@ -65,6 +65,13 @@
#define PWM_RES 65535
#define COMP_UNITS_NUM 8
+/* Sync offset flags defines */
+
+#define CH0_SYNC_FLAG (1 << 0)
+#define CH1_SYNC_FLAG (1 << 1)
+#define CH2_SYNC_FLAG (1 << 2)
+#define CH3_SYNC_FLAG (1 << 3)
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -104,6 +111,7 @@ struct sam_pwm_s
const struct sam_pwm_fault_s *fault;
uint8_t channels_num; /* Number of channels */
uintptr_t base; /* Base address of peripheral register */
+ uint8_t sync; /* Flags of synchronized channels */
};
/* PWM driver methods */
@@ -229,6 +237,38 @@ static struct sam_pwm_fault_s g_pwm0_fault =
.gpio_2 = GPIO_PWMC0_FI2,
};
+/* Define sync flags */
+
+#ifdef CONFIG_SAMV7_PWM0_SYNC
+ #define PWM0_CH0_SYNC_FLAG CH0_SYNC_FLAG
+
+ #ifdef CONFIG_SAMV7_PWM0_CH1_SYNC
+ #define PWM0_CH1_SYNC_FLAG CH1_SYNC_FLAG
+ #else
+ #define PWM0_CH1_SYNC_FLAG 0
+ #endif
+
+ #ifdef CONFIG_SAMV7_PWM0_CH2_SYNC
+ #define PWM0_CH2_SYNC_FLAG CH2_SYNC_FLAG
+ #else
+ #define PWM0_CH2_SYNC_FLAG 0
+ #endif
+
+ #ifdef CONFIG_SAMV7_PWM0_CH3_SYNC
+ #define PWM0_CH3_SYNC_FLAG CH3_SYNC_FLAG
+ #else
+ #define PWM0_CH3_SYNC_FLAG 0
+ #endif
+#else
+ #define PWM0_CH0_SYNC_FLAG 0
+ #define PWM0_CH1_SYNC_FLAG 0
+ #define PWM0_CH2_SYNC_FLAG 0
+ #define PWM0_CH3_SYNC_FLAG 0
+#endif
+
+#define PWM0_SYNC_FLAGS (PWM0_CH0_SYNC_FLAG | PWM0_CH1_SYNC_FLAG | \
+ PWM0_CH2_SYNC_FLAG | PWM0_CH3_SYNC_FLAG)
+
static struct sam_pwm_s g_pwm0 =
{
.ops = &g_pwmops,
@@ -237,6 +277,7 @@ static struct sam_pwm_s g_pwm0 =
.fault = &g_pwm0_fault,
.channels_num = PWM0_NCHANNELS,
.base = SAM_PWM0_BASE,
+ .sync = PWM0_SYNC_FLAGS,
};
#endif /* CONFIG_SAMV7_PWM0 */
@@ -340,6 +381,38 @@ static struct sam_pwm_fault_s g_pwm1_fault =
.gpio_2 = GPIO_PWMC1_FI2,
};
+/* Define sync flags */
+
+#ifdef CONFIG_SAMV7_PWM1_SYNC
+ #define PWM1_CH0_SYNC_FLAG CH0_SYNC_FLAG
+
+ #ifdef CONFIG_SAMV7_PWM1_CH1_SYNC
+ #define PWM1_CH1_SYNC_FLAG CH1_SYNC_FLAG
+ #else
+ #define PWM1_CH1_SYNC_FLAG 0
+ #endif
+
+ #ifdef CONFIG_SAMV7_PWM1_CH2_SYNC
+ #define PWM1_CH2_SYNC_FLAG CH2_SYNC_FLAG
+ #else
+ #define PWM1_CH2_SYNC_FLAG 0
+ #endif
+
+ #ifdef CONFIG_SAMV7_PWM1_CH3_SYNC
+ #define PWM1_CH3_SYNC_FLAG CH3_SYNC_FLAG
+ #else
+ #define PWM1_CH3_SYNC_FLAG 0
+ #endif
+#else
+ #define PWM1_CH0_SYNC_FLAG 0
+ #define PWM1_CH1_SYNC_FLAG 0
+ #define PWM1_CH2_SYNC_FLAG 0
+ #define PWM1_CH3_SYNC_FLAG 0
+#endif
+
+#define PWM1_SYNC_FLAGS (PWM1_CH0_SYNC_FLAG | PWM1_CH1_SYNC_FLAG | \
+ PWM1_CH2_SYNC_FLAG | PWM1_CH3_SYNC_FLAG)
+
static struct sam_pwm_s g_pwm1 =
{
.ops = &g_pwmops,
@@ -348,6 +421,7 @@ static struct sam_pwm_s g_pwm1 =
.fault = &g_pwm1_fault,
.channels_num = PWM1_NCHANNELS,
.base = SAM_PWM1_BASE,
+ .sync = PWM1_SYNC_FLAGS,
};
#endif
@@ -496,10 +570,14 @@ static void pwm_set_output(struct pwm_lowerhalf_s *dev,
uint8_t channel,
width);
}
- /* Enable the channel */
-
regval = CHID_SEL(1 << channel);
- pwm_putreg(priv, SAMV7_PWM_ENA, regval);
+
+ /* The enabling of a channel should be only done on unsynced channels */
+
+ if (!(priv->sync & regval))
+ {
+ pwm_putreg(priv, SAMV7_PWM_ENA, regval);
+ }
}
/****************************************************************************
@@ -684,6 +762,13 @@ static void pwm_set_polarity(struct pwm_lowerhalf_s *dev,
uint8_t channel,
struct sam_pwm_s *priv = (struct sam_pwm_s *)dev;
uint16_t regval;
+ /* Can't change polarity, if the channel is enabled! */
+
+ if (pwm_getreg(priv, SAMV7_PWM_SR) & CHID_SEL(1 << channel))
+ {
+ return;
+ }
+
regval = pwm_getreg(priv, SAMV7_PWM_CMRX + (channel * CHANNEL_OFFSET));
regval &= ~CMR_CPOL;
regval &= ~CMR_DPOLI;
@@ -810,6 +895,14 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev)
pwm_putreg(priv, SAMV7_PWM_FPV1, 0);
pwm_putreg(priv, SAMV7_PWM_FPV2, 0);
+ /* Enable synchronous channels. The flags in priv->sync
+ * correspond to the lowest bits in PWM_SCM.
+ * UPDM[1:0] is set to zero (manual update of deadtime, duty).
+ */
+
+ regval = (uint32_t)priv->sync;
+ pwm_putreg(priv, SAMV7_PWM_SCM, regval);
+
return OK;
}
@@ -864,9 +957,7 @@ 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_OVERWRITE
uint32_t regval;
-#endif
#ifdef CONFIG_PWM_MULTICHAN
for (int i = 0; i < PWM_NCHANNELS; i++)
@@ -920,6 +1011,25 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
#endif
}
}
+
+ /* Perform the update of synchronized PWM channels */
+
+ if (priv->sync)
+ {
+ regval = SCUC_UPDULOCK;
+
+ /* Enable the Channel 0 if synchronous channels are used.
+ * Channel 0's counter is used by all synchronous channels and
+ * enabling CH0 results in enabling all synchronous channels.
+ *
+ * Enable the CH0 here after all setting all channel parameters,
+ * because setting polarity configurations requires disabled
+ * channels.
+ */
+
+ 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 */
@@ -969,6 +1079,12 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev)
pwm_putreg(priv, SAMV7_PWM_DIS, regval);
}
+ /* Just to be sure, disable all sync channels too */
+
+ regval = pwm_getreg(priv, SAMV7_PWM_SCM);
+ 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);