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 <pressste@fel.cvut.cz>
This commit is contained in:
Pressl, Štěpán 2024-04-26 13:10:16 +02:00 committed by Xiang Xiao
parent b049b490b8
commit 297b3b0209
2 changed files with 175 additions and 5 deletions

View File

@ -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"

View File

@ -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);