You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by "hartmannathan (via GitHub)" <gi...@apache.org> on 2023/02/07 01:46:19 UTC

[GitHub] [nuttx] hartmannathan commented on a diff in pull request #8446: esp32s3: Add pwm support using LEDC peripheral

hartmannathan commented on code in PR #8446:
URL: https://github.com/apache/nuttx/pull/8446#discussion_r1098091258


##########
boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_ledc.c:
##########
@@ -0,0 +1,134 @@
+/****************************************************************************
+ * boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_ledc.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/board.h>
+#include <nuttx/timers/pwm.h>
+
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "esp32s3_ledc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_pwm_setup
+ *
+ * Description:
+ *   Initialize LEDC PWM and register the PWM device.
+ *
+ ****************************************************************************/
+
+int esp32s3_pwm_setup(void)
+{
+  int ret;
+  struct pwm_lowerhalf_s *pwm;
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM0
+  pwm = esp32s3_ledc_init(0);
+  if (!pwm)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 0 lower half\n");
+      return -ENODEV;
+    }
+
+  /* Register the PWM driver at "/dev/pwm0" */
+
+  ret = pwm_register("/dev/pwm0", pwm);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM1
+  pwm = esp32s3_ledc_init(1);
+  if (!pwm)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 1 lower half\n");
+      return -ENODEV;
+    }
+
+  /* Register the PWM driver at "/dev/pwm1" */
+
+  ret = pwm_register("/dev/pwm1", pwm);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM2
+  pwm = esp32s3_ledc_init(2);
+  if (!pwm)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 2 lower half\n");
+      return -ENODEV;
+    }
+
+  /* Register the PWM driver at "/dev/pwm2" */
+
+  ret = pwm_register("/dev/pwm2", pwm);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM3
+  pwm = esp32s3_ledc_init(3);
+  if (!pwm)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 3 lower half\n");
+      return -ENODEV;
+    }
+
+  /* Register the PWM driver at "/dev/pwm3" */
+
+  ret = pwm_register("/dev/pwm3", pwm);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
+      return ret;
+    }
+#endif
+
+  return OK;
+}

Review Comment:
   In this function, if none of `CONFIG_ESP32S3_LEDC_TIM0`, `CONFIG_ESP32S3_LEDC_TIM1`, `CONFIG_ESP32S3_LEDC_TIM2`, or `CONFIG_ESP32S3_LEDC_TIM3`, then compiler will warn about declared but unused `pwm` and `ret`.



##########
arch/xtensa/src/esp32s3/esp32s3_ledc.c:
##########
@@ -0,0 +1,813 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_ledc.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include "esp32s3_clockconfig.h"
+#include "esp32s3_gpio.h"
+#include "esp32s3_ledc.h"
+
+#include "xtensa.h"
+#include "hardware/esp32s3_ledc.h"
+#include "hardware/esp32s3_system.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* LEDC total timers */
+
+#define LEDC_TIMERS               (4)
+
+/* LEDC total channels */
+
+#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#  define LEDC_CHANNELS           (8)
+#else
+#  define LEDC_CHANNELS           (4)
+#endif
+
+/* LEDC timer0 channels and offset */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM0
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM0_CHANS       CONFIG_ESP32S3_LEDC_TIM0_CHANNELS
+#  else
+#    define LEDC_TIM0_CHANS       (1)
+#  endif
+#    define LEDC_TIM0_CHANS_OFF   (0)
+#endif
+
+/* LEDC timer1 channels and offset */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM1
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM1_CHANS       CONFIG_ESP32S3_LEDC_TIM1_CHANNELS
+#  else
+#    define LEDC_TIM1_CHANS       (1)
+#  endif
+#  define LEDC_TIM1_CHANS_OFF     (LEDC_TIM0_CHANS_OFF + LEDC_TIM0_CHANS)
+#endif
+
+/* LEDC timer2 channels and offset */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM2
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM2_CHANS       CONFIG_ESP32S3_LEDC_TIM2_CHANNELS
+#  else
+#    define LEDC_TIM2_CHANS       (1)
+#  endif
+
+#  define LEDC_TIM2_CHANS_OFF     (LEDC_TIM1_CHANS_OFF + LEDC_TIM1_CHANS)
+#endif
+
+/* LEDC timer3 channels and offset */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM3
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM3_CHANS       CONFIG_ESP32S3_LEDC_TIM3_CHANNELS
+#  else
+#    define LEDC_TIM3_CHANS       (1)
+#  endif
+
+#  define LEDC_TIM3_CHANS_OFF     (LEDC_TIM2_CHANS_OFF + LEDC_TIM2_CHANS)
+#endif
+
+/* LEDC clock resource */
+
+#define LEDC_CLK_RES              (1)         /* APB clock */
+
+/* LEDC timer max reload */
+
+#define LEDC_RELOAD_MAX           (16384)    /* 2^14 */
+
+/* LEDC timer max clock divider parameter */
+
+#define LEDC_CLKDIV_MAX           (262144)    /* 2^18 */
+
+/* LEDC timer registers mapping */
+
+#define LEDC_TIMER_REG(r, n)      ((r) + (n) * (LEDC_TIMER1_CONF_REG - \
+                                                LEDC_TIMER0_CONF_REG))
+
+/* LEDC timer channel registers mapping */
+
+#define setbits(bs, a)            modifyreg32(a, 0, bs)
+#define resetbits(bs, a)          modifyreg32(a, bs, 0)
+
+#define LEDC_CHAN_REG(r, n)       ((r) + (n) * (LEDC_CH1_CONF0_REG - \
+                                                LEDC_CH0_CONF0_REG))
+
+#define SET_TIMER_BITS(t, r, b)   setbits(b, LEDC_TIMER_REG(r, (t)->num));
+#define SET_TIMER_REG(t, r, v)    putreg32(v, LEDC_TIMER_REG(r, (t)->num));
+
+#define SET_CHAN_BITS(c, r, b)    setbits(b, LEDC_CHAN_REG(r, (c)->num));
+#define SET_CHAN_REG(c, r, v)     putreg32(v, LEDC_CHAN_REG(r, (c)->num));
+
+#ifndef MIN
+#  define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* LEDC timer channel configuration */
+
+struct esp32s3_ledc_chan_s
+{
+  const uint8_t num;                    /* Timer channel ID */
+  const uint8_t pin;                    /* Timer channel GPIO pin number */
+  uint16_t duty;                        /* Timer channel current duty */
+};
+
+/* This structure represents the state of one LEDC timer */
+
+struct esp32s3_ledc_s
+{
+  const struct pwm_ops_s *ops;          /* PWM operations */
+
+  const uint8_t num;                    /* Timer ID */
+
+  const uint8_t channels;               /* Timer channels number */
+  struct esp32s3_ledc_chan_s *chans;    /* Timer channels pointer */
+
+  uint32_t frequency;                   /* Timer current frequency */
+  uint32_t reload;                      /* Timer current reload */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int pwm_setup(struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
+static int pwm_start(struct pwm_lowerhalf_s *dev,
+                     const struct pwm_info_s *info);
+static int pwm_stop(struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
+                     unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* LEDC PWM operations */
+
+static const struct pwm_ops_s g_pwmops =
+{
+  .setup       = pwm_setup,
+  .shutdown    = pwm_shutdown,
+  .start       = pwm_start,
+  .stop        = pwm_stop,
+  .ioctl       = pwm_ioctl
+};
+
+/* LEDC channels table */
+
+static struct esp32s3_ledc_chan_s g_ledc_chans[LEDC_CHANNELS] =
+{
+  {
+    .num       = 0,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL0_PIN
+  },
+
+  {
+    .num       = 1,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL1_PIN
+  },
+
+  {
+    .num       = 2,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL2_PIN
+  },
+
+  {
+    .num       = 3,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL3_PIN
+  },
+
+#if LEDC_CHANNELS > 4
+  {
+    .num       = 4,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL4_PIN
+  },
+
+  {
+    .num       = 5,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL5_PIN
+  },
+
+  {
+    .num       = 6,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL6_PIN
+  },
+
+  {
+    .num       = 7,
+    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL7_PIN
+  }
+#endif
+};
+
+/* LEDC timer0 private data */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM0
+static struct esp32s3_ledc_s g_pwm0dev =
+{
+  .ops         = &g_pwmops,
+  .num         = 0,
+  .channels    = LEDC_TIM0_CHANS,
+  .chans       = &g_ledc_chans[LEDC_TIM0_CHANS_OFF]
+};
+#endif /* CONFIG_ESP32S3_LEDC_TIM0 */
+
+/* LEDC timer1 private data */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM1
+static struct esp32s3_ledc_s g_pwm1dev =
+{
+  .ops         = &g_pwmops,
+  .num         = 1,
+  .channels    = LEDC_TIM1_CHANS,
+  .chans       = &g_ledc_chans[LEDC_TIM1_CHANS_OFF]
+};
+#endif /* CONFIG_ESP32S3_LEDC_TIM1 */
+
+/* LEDC timer2 private data */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM2
+static struct esp32s3_ledc_s g_pwm2dev =
+{
+  .ops         = &g_pwmops,
+  .num         = 2,
+  .channels    = LEDC_TIM2_CHANS,
+  .chans       = &g_ledc_chans[LEDC_TIM2_CHANS_OFF]
+};
+#endif /* CONFIG_ESP32S3_LEDC_TIM2 */
+
+/* LEDC timer3 private data */
+
+#ifdef CONFIG_ESP32S3_LEDC_TIM3
+static struct esp32s3_ledc_s g_pwm3dev =
+{
+  .ops         = &g_pwmops,
+  .num         = 3,
+  .channels    = LEDC_TIM3_CHANS,
+  .chans       = &g_ledc_chans[LEDC_TIM3_CHANS_OFF]
+};
+#endif /* CONFIG_ESP32S3_LEDC_TIM3 */
+
+/* Clock reference count */
+
+static uint32_t g_clk_ref;
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ledc_enable_clk
+ *
+ * Description:
+ *   Enable LEDC clock.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void ledc_enable_clk(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (g_clk_ref == 0)
+    {
+      setbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
+      resetbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
+
+      putreg32(LEDC_CLK_RES, LEDC_CONF_REG);
+      putreg32(LEDC_CLK_EN, LEDC_CONF_REG);
+
+      pwminfo("Enable ledc clock\n");
+    }
+
+  g_clk_ref++;
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: ledc_disable_clk
+ *
+ * Description:
+ *   Disable LEDC clock.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void ledc_disable_clk(void)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  g_clk_ref--;
+
+  if (g_clk_ref == 0)
+    {
+      pwminfo("Disable ledc clock\n");
+
+      setbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
+      resetbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: setup_timer
+ *
+ * Description:
+ *   Setup LEDC timer frequency and reload.
+ *
+ * Input Parameters:
+ *   priv - A reference to the LEDC timer state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void setup_timer(struct esp32s3_ledc_s *priv)
+{
+  irqstate_t flags;
+  uint32_t regval;
+  uint32_t reload;
+  uint32_t prescaler;
+  uint32_t shift = 1;
+  uint64_t pwmclk = esp_clk_apb_freq();
+
+  /* Reset timer */
+
+  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
+
+  /* Calculate optimal values for the timer prescaler and for the timer
+   * modulo register.  If' frequency' is the desired frequency, then

Review Comment:
   Very minor:
   
   ```suggestion
      * modulo register.  If 'frequency' is the desired frequency, then
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org