vbenso commented on code in PR #6992:
URL: https://github.com/apache/incubator-nuttx/pull/6992#discussion_r961957160


##########
arch/xtensa/src/esp32/esp32_rmt.c:
##########
@@ -0,0 +1,315 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_rmt.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 <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <arch/board/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+
+#include "xtensa.h"
+
+#include "esp32_gpio.h"
+#include "esp32_rmt.h"
+#include "esp32_irq.h"
+#include "esp32_clockconfig.h"
+
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_gpio_sigmap.h"
+
+#ifdef CONFIG_ESP32_RMT
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* RMT methods */
+
+static void esp32rmt_reset(struct rmt_dev_s *dev);
+
+IRAM_ATTR static int esp32rmt_interrupt(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32rmt_reset
+ *
+ * Description:
+ *   Reset the RMT device.  Called early to initialize the hardware. This
+ *   function is called, before esp32_rmt_setup().
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" RMT driver state structure.
+ *
+ * Returned Value:
+ *  None
+ *
+ ****************************************************************************/
+
+static void esp32rmt_reset(struct rmt_dev_s *dev)
+{
+  irqstate_t flags;
+  int ret;
+  
+  flags = enter_critical_section();
+
+  modifyreg32(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST, 1);
+  modifyreg32(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST, 0);
+  putreg32(0xFFFFFFFF, RMT_INT_CLR_REG); /* Clear any spurious IRQ Flag */
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp32rmt_setup
+ *
+ * Description:
+ *   Configure the RMT. This method is called the first time that the RMT
+ *   device is opened.  This will occur when the port is first opened.
+ *   This setup includes configuring and attaching RMT interrupts.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" RMT driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32rmt_setup(struct rmt_dev_s *dev)
+{
+  irqstate_t flags;
+  int ret = OK;
+
+  flags = enter_critical_section();
+
+  if (dev->cpuint != -ENOMEM)
+    {
+      /* Disable the provided CPU Interrupt to configure it. */
+      up_disable_irq(dev->cpuint);
+    }
+
+  dev->cpu = up_cpu_index();
+  dev->cpuint = esp32_setup_irq(dev->cpu, dev->periph,
+                                2, ESP32_CPUINT_LEVEL);
+  if (dev->cpuint < 0)
+    {
+      /* Failed to allocate a CPU interrupt of this type. */
+  
+      ret = dev->cpuint;
+      leave_critical_section(flags);
+  
+      return ret;
+    }
+  
+  ret = irq_attach(dev->irq, esp32rmt_interrupt, dev);
+  
+  if (ret != OK)
+    {
+      /* Failed to attach IRQ, so CPU interrupt must be freed. */
+  
+      esp32_teardown_irq(dev->cpu, dev->periph, dev->cpuint);
+      dev->cpuint = -ENOMEM;
+      leave_critical_section(flags);
+  
+      return ret;
+    }
+
+  /* Enable the CPU interrupt that is linked to the RMT device. */
+  up_enable_irq(dev->cpuint);
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32rmt_interrupt
+ *
+ * Description:
+ *   RMT TX interrupt handler
+ *
+ * Input Parameters:
+ *   irq - The IRQ number of the interrupt.
+ *   context - The register state save array at the time of the interrupt.
+ *   arg - The pointer to driver structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+IRAM_ATTR static int esp32rmt_interrupt(int irq, void *context, void *arg)
+{
+  struct rmt_dev_s *dev = (struct rmt_dev_s *)arg;
+  uint32_t regval = getreg32(RMT_INT_ST_REG);
+  uint32_t total_pixels;
+  uint32_t current_pixel;
+  uint32_t dst_mem;
+  uint32_t used_words;
+  uint8_t *pixel_ptr;
+  
+  if (regval & RMT_CHn_TX_END_INT_ST(dev->channel))
+    {
+      putreg32(RMT_CHn_TX_END_INT_CLR(dev->channel), RMT_INT_CLR_REG);
+      regval = getreg32(RMT_INT_ENA_REG);
+      regval &= ~(RMT_CHn_TX_END_INT_ENA(dev->channel));
+      putreg32(regval, RMT_INT_ENA_REG);
+      nxsem_post(&dev->tx_sem);
+    }
+  else if (regval & RMT_CHn_TX_THR_EVENT_INT_ST(dev->channel))
+    {
+      putreg32(RMT_CHn_TX_THR_EVENT_INT_CLR(dev->channel), RMT_INT_CLR_REG);
+      total_pixels = dev->data_len;
+      current_pixel = dev->next_pixel_to_load;
+      dst_mem = dev->start_address;
+      if(dev->frame++==1)
+        dst_mem += dev->reload_thresh * 4;
+      
+      if (dev->frame > 1)
+        dev->frame = 0;
+      
+      used_words = 0;
+      pixel_ptr = dev->data_ptr + current_pixel;
+  
+      while (used_words < dev->reload_thresh)
+        {
+          if (current_pixel < total_pixels)
+            {
+              register uint8_t pixel = (*pixel_ptr++);
+              for (register uint32_t i = 0; i < 8; i++)
+                {
+                  if (pixel & 0x80L)
+                    {
+                      putreg32(LOGIC_ONE, dst_mem);
+                    }
+                  else
+                    {
+                      putreg32(LOGIC_ZERO, dst_mem);
+                    }
+                  pixel <<= 1;
+                  dst_mem += 4;
+                }
+              used_words+=8;
+              current_pixel++;
+            }
+          else
+            {
+              regval = getreg32(RMT_INT_ENA_REG);
+              regval |= RMT_CHn_TX_END_INT_ENA(dev->channel);
+              putreg32(regval, RMT_INT_ENA_REG);
+              putreg32(0, dst_mem);
+              break;
+            }
+        }
+      
+      dev->next_pixel_to_load = current_pixel;
+    }

Review Comment:
   The ws2812 is an 1-wire RGB LED that can be daisy chained with many others. 
Each LED receives a train of pulses encoding the 0's or 1's required to encode 
24 bits of RGB color. Once the LED receives its pulses, it will adopt that 
color and only forward the remaining pulses to the next LED.
   Pulses for zeros and ones have an specific timing each, so LOGIC_ZERO and 
LOGIC_ONE will set the RMT to generate the output wave that will encode the 
desired bit in the output GPIO.
   Each channel of ESP32's RMT can hold up to 64 words of data, and we use one 
word to encode each pulse. This is enough for a single LED, however, when we 
have many LEDs connected to the system, there is the need to keep "refueling" 
the RMT's input with more data. 
   The RMT will generate an interrupt once it has transmitted half of the data 
on its internal buffer, so, when this happens, this routine will copy more data 
to its buffer. This process will happen until all the input data is copied to 
RMT's internal buffer. 
   In the last "refueling" interaction, 0 is written to RMT's buffer, and once 
RMT's transmission state machine reaches that point, it will go back to IDLE 
and generate an END interrupt, so that's when the write lock is released and 
the write function finally returns.
   
   Perhaps LOGIC_ONE and LOGIC_ZERO definitions' can be considered application 
specific and could be members of the dev structure. Also the term pixel, 
doesn't help much. I've considered translating the output bytes to the RMT 
encoding format inside the write function and then we would have no need to 
translate the bytes to pulse bits inside the interruption, however, it would 
require a lot of extra memory, since a single bit of input data, becomes a word 
when transmitting.



-- 
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-unsubscr...@nuttx.apache.org

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

Reply via email to