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 49ce1c5df7 samv7: add support for ADC conversion triggering with PWM
49ce1c5df7 is described below

commit 49ce1c5df733d3bcf92312ca8f8f96aeafea53ee
Author: Michal Lenc <michall...@seznam.cz>
AuthorDate: Fri Feb 24 16:33:42 2023 +0100

    samv7: add support for ADC conversion triggering with PWM
    
    This commit enhances ADC and PWM drivers with option to trigger ADC
    conversion with events generated by PWM comparison units.
    
    The generation of PWM events is handled by comparison units set up from
    Kconfig option SAMV7_PWMx_TRIGn. ADC triggering from PWM can be selected
    by AFECn_PWMTRIG option.
    
    Signed-off-by: Michal Lenc <michall...@seznam.cz>
---
 arch/arm/src/samv7/Kconfig    | 218 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/src/samv7/sam_afec.c |  48 ++++++++--
 arch/arm/src/samv7/sam_pwm.c  | 132 +++++++++++++++++++++++++
 3 files changed, 391 insertions(+), 7 deletions(-)

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;
 }
 

Reply via email to