samv7: add support for PWM fault protection

This commit adds configurable fault protection to SAMv7 PWM driver.
The fault input can be used from peripherals as ADC or GPIO inputs.
Inputs from GPIO have configurable polarity (high or low). The PWM output
is automatically set to zero if fault input is active and restored
if fault input is not actived.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2023-02-27 16:27:44 +01:00 committed by Xiang Xiao
parent 16ea80e53b
commit 93097be705
3 changed files with 354 additions and 6 deletions

View File

@ -770,6 +770,75 @@ config SAMV7_PWM
endmenu
menu "PWM Fault inputs"
config SAMV7_PWM0_PA9
bool "External fault input from PA9"
default n
if SAMV7_PWM1_PA9
config SAMV7_PWM1_PA9_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM0_PD8
bool "External fault input from PD8"
default n
if SAMV7_PWM1_PD8
config SAMV7_PWM1_PD8_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM0_PD9
bool "External fault input from PD9"
default n
if SAMV7_PWM1_PD9
config SAMV7_PWM1_PD9_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM0_PMC
bool "External fault input from PMC"
default n
config SAMV7_PWM0_AFEC0
bool "External fault input from AFEC0"
default n
config SAMV7_PWM0_AFEC1
bool "External fault input from AFEC1"
default n
config SAMV7_PWM0_ACC
bool "External fault input from ACC"
default n
config SAMV7_PWM0_TIM0
bool "External fault input from Timer 0"
default n
endmenu
config SAMV7_PWM0_EVENT0
bool "Generate trigger on Event Line 0"
default n
@ -915,6 +984,76 @@ config SAMV7_PWM1_TRIG7
endmenu
menu "PWM Fault inputs"
config SAMV7_PWM1_PA21
bool "External fault input from PA21"
default n
if SAMV7_PWM1_PA21
config SAMV7_PWM1_PA21_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM1_PA26
bool "External fault input from PA26"
default n
if SAMV7_PWM1_PA26
config SAMV7_PWM1_PA26_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM1_PA28
bool "External fault input from PA28"
default n
if SAMV7_PWM1_PA28
config SAMV7_PWM1_PA28_POL
bool "Inverted polarity"
default n
---help---
Fault input is by default active on high level. This config
inverts the logic and makes fault active on low level.
endif
config SAMV7_PWM1_PMC
bool "External fault input from PMC"
default n
config SAMV7_PWM1_AFEC0
bool "External fault input from AFEC0"
default n
config SAMV7_PWM1_AFEC1
bool "External fault input from AFEC1"
default n
config SAMV7_PWM1_ACC
bool "External fault input from ACC"
default n
config SAMV7_PWM1_TIM0
bool "External fault input from Timer 0"
default n
endmenu
config SAMV7_PWM1_EVENT0
bool "Generate trigger on Event Line 0"
default n

View File

@ -60,6 +60,7 @@
#define CHANNEL_OFFSET 0x20
#define COMP_OFFSET 0x10
#define FAULT_SEL_OFFSET 0x8
#define CLK_FREQ BOARD_MCK_FREQUENCY
#define PWM_RES 65535
#define COMP_UNITS_NUM 8
@ -86,11 +87,21 @@ struct sam_pwm_comparison_s
int event1;
};
struct sam_pwm_fault_s
{
uint8_t source; /* Source of fault input */
uint8_t polarity;
gpio_pinset_t gpio_0; /* GPIO 1 fault input */
gpio_pinset_t gpio_1; /* GPIO 2 fault input */
gpio_pinset_t gpio_2; /* GPIO 3 fault input */
};
struct sam_pwm_s
{
const struct pwm_ops_s *ops; /* PWM operations */
const struct sam_pwm_channel_s *channels;
const struct sam_pwm_comparison_s *comparison;
const struct sam_pwm_fault_s *fault;
uint8_t channels_num; /* Number of channels */
uintptr_t base; /* Base address of peripheral register */
};
@ -189,11 +200,21 @@ static struct sam_pwm_comparison_s g_pwm0_comparison =
#endif
};
static struct sam_pwm_fault_s g_pwm0_fault =
{
.source = PWM0_FAULTS,
.polarity = PWM0_POL,
.gpio_0 = GPIO_PWMC0_FI0,
.gpio_1 = GPIO_PWMC0_FI1,
.gpio_2 = GPIO_PWMC0_FI2,
};
static struct sam_pwm_s g_pwm0 =
{
.ops = &g_pwmops,
.channels = g_pwm0_channels,
.comparison = &g_pwm0_comparison,
.fault = &g_pwm0_fault,
.channels_num = PWM0_NCHANNELS,
.base = SAM_PWM0_BASE,
};
@ -270,17 +291,26 @@ static struct sam_pwm_comparison_s g_pwm1_comparison =
#endif
};
static struct sam_pwm_fault_s g_pwm1_fault =
{
.source = PWM1_FAULTS,
.polarity = PWM1_POL,
.gpio_0 = GPIO_PWMC1_FI0,
.gpio_1 = GPIO_PWMC1_FI1,
.gpio_2 = GPIO_PWMC1_FI2,
};
static struct sam_pwm_s g_pwm1 =
{
.ops = &g_pwmops,
.channels = g_pwm1_channels,
.comparison = &g_pwm1_comparison,
.fault = &g_pwm1_fault,
.channels_num = PWM1_NCHANNELS,
.base = SAM_PWM1_BASE,
};
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@ -566,13 +596,45 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev)
pwm_putreg(priv, SAMV7_PWM_DTX + (channel * CHANNEL_OFFSET), 0);
/* Fault protection registers */
/* Enable fault protection if configured. The protection has to
* be enabled for every configured channel separately.
*/
pwm_putreg(priv, SAMV7_PWM_FPV1, 0);
pwm_putreg(priv, SAMV7_PWM_FPV2, 0);
pwm_putreg(priv, SAMV7_PWM_FPE, 0);
regval = pwm_getreg(priv, SAMV7_PWM_FPE);
regval |= priv->fault->source << (FAULT_SEL_OFFSET * channel);
pwm_putreg(priv, SAMV7_PWM_FPE, regval);
}
/* Configure fault GPIOs if used */
if (priv->fault->source & 1)
{
sam_configgpio(priv->fault->gpio_0);
}
if (priv->fault->source & (1 << 1))
{
sam_configgpio(priv->fault->gpio_1);
}
if (priv->fault->source & (1 << 2))
{
sam_configgpio(priv->fault->gpio_2);
}
/* Set fault polarity. This has to be 1 for peripheral fault
* generation (from ADC for example), GPIO generated fault
* is set via configuration options.
*/
regval = FMR_FPOL_SEL(priv->fault->polarity);
pwm_putreg(priv, SAMV7_PWM_FMR, regval);
/* Force both outputs to 0 if fault occurs */
pwm_putreg(priv, SAMV7_PWM_FPV1, 0);
pwm_putreg(priv, SAMV7_PWM_FPV2, 0);
return OK;
}
@ -653,7 +715,6 @@ static int pwm_start(struct pwm_lowerhalf_s *dev,
info->frequency);
pwm_set_output(dev, priv->channels[index - 1].channel,
info->channels[i].duty);
#ifdef CONFIG_PWM_OVERWRITE
if (info->channels[i].ch_outp_ovrwr)
{

View File

@ -88,6 +88,154 @@
#define PWM1_NCHANNELS (PWM1_CH0 + PWM1_CH1 + PWM1_CH2 + PWM1_CH3)
/* Fault protection */
#ifdef CONFIG_SAMV7_PWM0_PA9
#define PWM0_PA9 1
#ifdef CONFIG_SAMV7_PWM0_PA9_POL
#define PWM0_PA9_POL 0
#else
#define PWM0_PA9_POL 1
#endif
#else
#define PWM0_PA9 0
#define PWM0_PA9_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM0_PD8
#define PWM0_PD8 (1 << 1)
#ifdef CONFIG_SAMV7_PWM0_PD8_POL
#define PWM0_PD8_POL 0
#else
#define PWM0_PD8_POL (1 << 1)
#endif
#else
#define PWM0_PD8 0
#define PWM0_PD8_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM0_PD9
#define PWM0_PD9 (1 << 2)
#ifdef CONFIG_SAMV7_PWM0_PD9_POL
#define PWM0_PD9_POL 0
#else
#define PWM0_PD9_POL (1 << 2)
#endif
#else
#define PWM0_PD9 0
#define PWM0_PD9_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM0_PMC
#define PWM0_PMC (1 << 3)
#else
#define PWM0_PMC 0
#endif
#ifdef CONFIG_SAMV7_PWM0_AFEC0
#define PWM0_AFEC0 (1 << 4)
#else
#define PWM0_AFEC0 0
#endif
#ifdef CONFIG_SAMV7_PWM0_AFEC1
#define PWM0_AFEC1 (1 << 5)
#else
#define PWM0_AFEC1 0
#endif
#ifdef CONFIG_SAMV7_PWM0_ACC
#define PWM0_ACC (1 << 6)
#else
#define PWM0_ACC 0
#endif
#ifdef CONFIG_SAMV7_PWM0_TIM0
#define PWM0_TIM0 (1 << 7)
#else
#define PWM0_TIM0 0
#endif
#define PWM0_FAULTS (PWM0_PA9 + PWM0_PD8 + PWM0_PD9 + PWM0_PMC + \
PWM0_AFEC0 + PWM0_AFEC1 + PWM0_ACC + PWM0_TIM0)
#define PWM0_POL (PWM0_PA9_POL + PWM0_PD8_POL + PWM0_PD9_POL + \
PWM0_PMC + PWM0_AFEC0 + PWM0_AFEC1 + PWM0_ACC + \
PWM0_TIM0)
#ifdef CONFIG_SAMV7_PWM1_PA21
#define PWM1_PA21 1
#ifdef CONFIG_SAMV7_PWM1_PA21_POL
#define PWM1_PA21_POL 0
#else
#define PWM1_PA21_POL 1
#endif
#else
#define PWM1_PA21 0
#define PWM1_PA21_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM1_PA26
#define PWM1_PA26 (1 << 1)
#ifdef CONFIG_SAMV7_PWM1_PA26_POL
#define PWM1_PA26_POL 0
#else
#define PWM1_PA26_POL (1 << 1)
#endif
#else
#define PWM1_PA26 0
#define PWM1_PA26_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM1_PA28
#define PWM1_PA28 (1 << 2)
#ifdef CONFIG_SAMV7_PWM1_PA28_POL
#define PWM1_PA28_POL 0
#else
#define PWM1_PA28_POL (1 << 2)
#endif
#else
#define PWM1_PA28 0
#define PWM1_PA28_POL 0
#endif
#ifdef CONFIG_SAMV7_PWM1_PMC
#define PWM1_PMC (1 << 3)
#else
#define PWM1_PMC 0
#endif
#ifdef CONFIG_SAMV7_PWM1_AFEC0
#define PWM1_AFEC0 (1 << 4)
#else
#define PWM1_AFEC0 0
#endif
#ifdef CONFIG_SAMV7_PWM1_AFEC1
#define PWM1_AFEC1 (1 << 5)
#else
#define PWM1_AFEC1 0
#endif
#ifdef CONFIG_SAMV7_PWM1_ACC
#define PWM1_ACC (1 << 6)
#else
#define PWM1_ACC 0
#endif
#ifdef CONFIG_SAMV7_PWM1_TIM0
#define PWM1_TIM0 (1 << 7)
#else
#define PWM1_TIM0 0
#endif
#define PWM1_FAULTS (PWM1_PA21 + PWM1_PA26 + PWM1_PA28 + PWM1_PMC + \
PWM1_AFEC0 + PWM1_AFEC1 + PWM1_ACC + PWM1_TIM0)
#define PWM1_POL (PWM1_PA21_POL + PWM1_PA26_POL + PWM1_PA28_POL + \
PWM1_PMC + PWM1_AFEC0 + PWM1_AFEC1 + PWM1_ACC + \
PWM1_TIM0)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/