diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index f10315941de..85019d244cb 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -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 diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c index 67c3c5f3696..b59b545e769 100644 --- a/arch/arm/src/samv7/sam_pwm.c +++ b/arch/arm/src/samv7/sam_pwm.c @@ -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) { diff --git a/arch/arm/src/samv7/sam_pwm.h b/arch/arm/src/samv7/sam_pwm.h index b21bd6c3e87..a1f1e70f83d 100644 --- a/arch/arm/src/samv7/sam_pwm.h +++ b/arch/arm/src/samv7/sam_pwm.h @@ -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 ****************************************************************************/