diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 29be88cbc4..f10315941d 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -387,10 +387,18 @@ config SAMV7_ADC bool "12-bit ADC Controller (ADC)" default n +config SAMV7_AFEC_SWTRIG + bool + default n + config SAMV7_AFEC_TIOATRIG bool default n +config SAMV7_AFEC_PWMTRIG + bool + default n + menuconfig SAMV7_AFEC0 bool "Analog Front End 0 (AFEC0)" default n @@ -437,8 +445,15 @@ config SAMV7_AFEC0_TIOATRIG ---help--- Use output of Timer/Counter as a trigger. +config SAMV7_AFEC0_PWMTRIG + bool "PWM trigger" + select SAMV7_AFEC_PWMTRIG + ---help--- + Use output of PWM as a trigger. + config SAMV7_AFEC0_SWTRIG bool "Software trigger" + select SAMV7_AFEC_SWTRIG ---help--- Use software trigger. @@ -462,6 +477,17 @@ config SAMV7_AFEC0_TIOACHAN endif #SAMV7_AFEC0_TIOATRIG +if SAMV7_AFEC0_PWMTRIG + +config SAMV7_AFEC0_PWMEVENT + int "PWM Event Line" + default 0 + range 0 1 + ---help--- + PWM event line used for AFEC triggering. Can be either 0 or 1. + +endif # SAMV7_AFEC0_PWM_TRIG + endif # SAMV7_AFEC0 menuconfig SAMV7_AFEC1 @@ -510,8 +536,15 @@ config SAMV7_AFEC1_TIOATRIG ---help--- Use output of Timer/Counter as a trigger. +config SAMV7_AFEC1_PWMTRIG + bool "PWM trigger" + select SAMV7_AFEC_PWMTRIG + ---help--- + Use output of PWM as a trigger. + config SAMV7_AFEC1_SWTRIG bool "Software trigger" + select SAMV7_AFEC_SWTRIG ---help--- Use software trigger. @@ -535,6 +568,17 @@ config SAMV7_AFEC1_TIOACHAN endif #SAMV7_AFEC1_TIOATRIG +if SAMV7_AFEC1_PWMTRIG + +config SAMV7_AFEC1_PWMEVENT + int "PWM Event Line" + default 0 + range 0 1 + ---help--- + PWM event line used for AFEC triggering. Can be either 0 or 1. + +endif # SAMV7_AFEC1_PWM_TRIG + endif # SAMV7_AFEC1 config SAMV7_MCAN0 @@ -656,6 +700,94 @@ config SAMV7_PWM0_CH3_COMP endif +menu "PWM Comparison units" + +config SAMV7_PWM0_TRIG0 + int "PWM0 Comparison Unit 0 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG1 + int "PWM0 Comparison Unit 1 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG2 + int "PWM0 Comparison Unit 2 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG3 + int "PWM0 Comparison Unit 3 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG4 + int "PWM0 Comparison Unit 4 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG5 + int "PWM0 Comparison Unit 5 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG6 + int "PWM0 Comparison Unit 6 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM0_TRIG7 + int "PWM0 Comparison Unit 7 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM + +endmenu + +config SAMV7_PWM0_EVENT0 + bool "Generate trigger on Event Line 0" + default n + ---help--- + PWM allows trigger generation on event lines. This can be + used for ADC conversion triggering for example. It is + necessary to set a comparison unit in order to generate an + event. + +config SAMV7_PWM0_EVENT1 + bool "Generate trigger on Event Line 1" + default n + ---help--- + PWM allows trigger generation on event lines. This can be + used for ADC conversion triggering for example. It is + necessary to set a comparison unit in order to generate an + event. + endif menuconfig SAMV7_PWM1 @@ -715,6 +847,92 @@ config SAMV7_PWM1_CH3_COMP endif +menu "PWM Comparison units" + +config SAMV7_PWM1_TRIG0 + int "PWM1 Comparison Unit 0 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG1 + int "PWM1 Comparison Unit 1 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG2 + int "PWM1 Comparison Unit 2 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG3 + int "PWM1 Comparison Unit 3 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG4 + int "PWM1 Comparison Unit 4 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG5 + int "PWM1 Comparison Unit 5 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG6 + int "PWM1 Comparison Unit 6 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +config SAMV7_PWM1_TRIG7 + int "PWM1 Comparison Unit 7 value" + range 0 100 + default 0 + ---help--- + Timer value on which the comparison unit generates + an event. Value is in percentages. + +endmenu + +config SAMV7_PWM1_EVENT0 + bool "Generate trigger on Event Line 0" + default n + ---help--- + PWM allows trigger generation on event lines. This can be + used for ADC conversion triggering for example. It is + necessary to set a comparison unit in order to generate an + event. + +config SAMV7_PWM1_EVENT1 + bool "Generate trigger on Event Line 1" + default n + ---help--- + PWM allows trigger generation on event lines. This can be + used for ADC conversion triggering for example. It is + necessary to set a comparison unit in order to generate an + event. + endif config SAMV7_QSPI diff --git a/arch/arm/src/samv7/sam_afec.c b/arch/arm/src/samv7/sam_afec.c index a12845b2f1..74e3f6ae88 100644 --- a/arch/arm/src/samv7/sam_afec.c +++ b/arch/arm/src/samv7/sam_afec.c @@ -94,6 +94,7 @@ struct samv7_dev_s uint8_t resolution; /* ADC resolution (SAMV7_AFECn_RES) */ uint8_t trigger; /* ADC trigger (software, timer...) */ uint8_t timer_channel; /* Timer channel to trigger ADC */ + uint8_t event_line; /* PWM event line to trigger ADC */ uint32_t frequency; /* Frequency of the timer */ int irq; /* ADC IRQ number */ int pid; /* ADC PID number */ @@ -177,12 +178,15 @@ static struct samv7_dev_s g_adcpriv0 = .intf = 0, .initialized = 0, .resolution = CONFIG_SAMV7_AFEC0_RES, -#ifdef CONFIG_SAMV7_AFEC0_SWTRIG - .trigger = 0, -#else +#if defined (CONFIG_SAMV7_AFEC0_PWMTRIG) + .trigger = 2, + .event_line = CONFIG_SAMV7_AFEC0_PWMEVENT, +#elif defined (CONFIG_SAMV7_AFEC0_TIOATRIG) .trigger = 1, .timer_channel = CONFIG_SAMV7_AFEC0_TIOACHAN, .frequency = CONFIG_SAMV7_AFEC0_TIOAFREQ, +#else + .trigger = 0, #endif .base = SAM_AFEC0_BASE, }; @@ -217,12 +221,15 @@ static struct samv7_dev_s g_adcpriv1 = .intf = 1, .initialized = 0, .resolution = CONFIG_SAMV7_AFEC1_RES, -#ifdef CONFIG_SAMV7_AFEC1_SWTRIG - .trigger = 0, -#else +#if defined (CONFIG_SAMV7_AFEC1_PWMTRIG) + .trigger = 2, + .event_line = CONFIG_SAMV7_AFEC0_PWMEVENT, +#elif defined (CONFIG_SAMV7_AFEC1_TIOATRIG) .trigger = 1, .timer_channel = CONFIG_SAMV7_AFEC1_TIOACHAN, .frequency = CONFIG_SAMV7_AFEC1_TIOAFREQ, +#else + .trigger = 0, #endif .base = SAM_AFEC1_BASE, }; @@ -624,7 +631,9 @@ static int sam_afec_trigger(struct samv7_dev_s *priv) regval &= ~AFEC_MR_TRGSEL_MASK; afec_putreg(priv, SAM_AFEC_MR_OFFSET, regval); } -#elif CONFIG_SAMV7_AFEC_TIOATRIG + +#endif +#ifdef CONFIG_SAMV7_AFEC_TIOATRIG if (priv->trigger == 1) { ainfo("Setup timer/counter trigger\n"); @@ -655,6 +664,31 @@ static int sam_afec_trigger(struct samv7_dev_s *priv) afec_putreg(priv, SAM_AFEC_MR_OFFSET, regval); } + +#endif +#ifdef CONFIG_SAMV7_AFEC_PWMTRIG + if (priv->trigger == 2) + { + regval = afec_getreg(priv, SAM_AFEC_MR_OFFSET); + regval &= ~AFEC_MR_TRGSEL_MASK; + + if (priv->event_line == 1) + { + /* PWM Event Line 1 is used for AFEC triggering */ + + regval |= AFEC_MR_TRGSEL_PWM1; + } + else + { + /* PWM Event Line 0 is used for AFEC triggering */ + + regval |= AFEC_MR_TRGSEL_PWM0; + } + + regval |= AFEC_MR_TRGEN; + + afec_putreg(priv, SAM_AFEC_MR_OFFSET, regval); + } #endif return ret; diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c index c041f36d93..67c3c5f369 100644 --- a/arch/arm/src/samv7/sam_pwm.c +++ b/arch/arm/src/samv7/sam_pwm.c @@ -59,8 +59,10 @@ #endif #define CHANNEL_OFFSET 0x20 +#define COMP_OFFSET 0x10 #define CLK_FREQ BOARD_MCK_FREQUENCY #define PWM_RES 65535 +#define COMP_UNITS_NUM 8 /**************************************************************************** * Pre-processor Definitions @@ -77,10 +79,18 @@ struct sam_pwm_channel_s gpio_pinset_t pin_l; /* PWM L output pin */ }; +struct sam_pwm_comparison_s +{ + int comp_vals[COMP_UNITS_NUM]; + int event0; + int event1; +}; + 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; uint8_t channels_num; /* Number of channels */ uintptr_t base; /* Base address of peripheral register */ }; @@ -158,10 +168,32 @@ static struct sam_pwm_channel_s g_pwm0_channels[] = #endif }; +static struct sam_pwm_comparison_s g_pwm0_comparison = +{ + .comp_vals = + { + CONFIG_SAMV7_PWM0_TRIG0, CONFIG_SAMV7_PWM0_TRIG1, + CONFIG_SAMV7_PWM0_TRIG2, CONFIG_SAMV7_PWM0_TRIG3, + CONFIG_SAMV7_PWM0_TRIG4, CONFIG_SAMV7_PWM0_TRIG5, + CONFIG_SAMV7_PWM0_TRIG6, CONFIG_SAMV7_PWM0_TRIG7 + }, +#ifdef CONFIG_SAMV7_PWM0_EVENT0 + .event0 = 1, +#else + .event0 = 0, +#endif +#ifdef CONFIG_SAMV7_PWM0_EVENT1 + .event1 = 1, +#else + .event1 = 0, +#endif +}; + static struct sam_pwm_s g_pwm0 = { .ops = &g_pwmops, .channels = g_pwm0_channels, + .comparison = &g_pwm0_comparison, .channels_num = PWM0_NCHANNELS, .base = SAM_PWM0_BASE, }; @@ -217,10 +249,32 @@ static struct sam_pwm_channel_s g_pwm1_channels[] = #endif }; /* CONFIG_SAMV7_PWM1 */ +static struct sam_pwm_comparison_s g_pwm1_comparison = +{ + .comp_vals = + { + CONFIG_SAMV7_PWM1_TRIG0, CONFIG_SAMV7_PWM1_TRIG1, + CONFIG_SAMV7_PWM1_TRIG2, CONFIG_SAMV7_PWM1_TRIG3, + CONFIG_SAMV7_PWM1_TRIG4, CONFIG_SAMV7_PWM1_TRIG5, + CONFIG_SAMV7_PWM1_TRIG6, CONFIG_SAMV7_PWM1_TRIG7 + }, +#ifdef CONFIG_SAMV7_PWM0_EVENT0 + .event0 = 1, +#else + .event0 = 0, +#endif +#ifdef CONFIG_SAMV7_PWM0_EVENT1 + .event1 = 1, +#else + .event1 = 0, +#endif +}; + static struct sam_pwm_s g_pwm1 = { .ops = &g_pwmops, .channels = g_pwm1_channels, + .comparison = &g_pwm1_comparison, .channels_num = PWM1_NCHANNELS, .base = SAM_PWM1_BASE, }; @@ -241,6 +295,7 @@ static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel, ub16_t duty); 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); /**************************************************************************** * Private Functions @@ -370,6 +425,81 @@ static void pwm_set_output(struct pwm_lowerhalf_s *dev, uint8_t channel, pwm_putreg(priv, SAMV7_PWM_ENA, regval); } +/**************************************************************************** + * Name: pwm_set_comparison + * + * Description: + * Set comparison units. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void pwm_set_comparison(struct pwm_lowerhalf_s *dev) +{ + struct sam_pwm_s *priv = (struct sam_pwm_s *)dev; + uint16_t period; + uint16_t width; + uint16_t comp_value; + uint8_t comp_en; + int i; + + /* Get the period value */ + + period = pwm_getreg(priv, SAMV7_PWM_CPRDX); + + /* Compute PWM width (count value to set PWM low) */ + + comp_en = 0; + + for (i = 0; i < COMP_UNITS_NUM; i++) + { + if (priv->comparison->comp_vals[i] == 0) + { + continue; + } + + comp_value = b16divi(uitoub16(priv->comparison->comp_vals[i]), 100); + + width = b16toi(comp_value * period + b16HALF); + + /* Generate event line */ + + if (pwm_getreg(priv, SAMV7_PWM_CMPMX + COMP_OFFSET * i) & CMPM_CEN) + { + /* Use update register if comparision unit is used */ + + pwm_putreg(priv, SAMV7_PWM_CMPVUPDX + COMP_OFFSET * i, width); + pwm_putreg(priv, SAMV7_PWM_CMPMUPDX + COMP_OFFSET * i, CMPM_CEN); + } + else + { + pwm_putreg(priv, SAMV7_PWM_CMPVX + COMP_OFFSET * i, width); + pwm_putreg(priv, SAMV7_PWM_CMPMX + COMP_OFFSET * i, CMPM_CEN); + } + + comp_en += 1 << i; + } + + if (priv->comparison->event0) + { + /* Enable output on Event Line 0 */ + + pwm_putreg(priv, SAMV7_PWM_ELMR1, comp_en); + } + + if (priv->comparison->event1) + { + /* Enable output on Event Line 1 */ + + pwm_putreg(priv, SAMV7_PWM_ELMR2, comp_en); + } +} + /**************************************************************************** * Name: pwm_setup * @@ -552,6 +682,8 @@ static int pwm_start(struct pwm_lowerhalf_s *dev, pwm_set_output(dev, priv->channels[0].channel, info->duty); #endif + pwm_set_comparison(dev); + return OK; }