You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2020/09/15 22:04:40 UTC

[GitHub] [incubator-nuttx] davids5 commented on a change in pull request #1797: LED: Support for WS2812 LED controller (aka Adafruit NeoPixel)

davids5 commented on a change in pull request #1797:
URL: https://github.com/apache/incubator-nuttx/pull/1797#discussion_r489011256



##########
File path: drivers/leds/ws2812.c
##########
@@ -0,0 +1,475 @@
+/****************************************************************************
+ * drivers/sensors/ws2812.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 <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/leds/ws2812.h>
+
+#ifdef CONFIG_WS2812
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_WS2812_FREQUENCY
+#  define CONFIG_WS2812_FREQUENCY  8000000
+#endif
+
+/* These are the tuning parameters to meeting timeing requirements */
+
+#if CONFIG_WS2812_FREQUENCY == 4000000
+#  define WS2812_RST_CYCLES 30          /* 60us (>50us)*/
+#  define WS2812_ZERO_BYTE  0b01000000  /* 250 ns (200ns - 500ns) */
+#  define WS2812_ONE_BYTE   0b01110000  /* 750 ns (550ns - 850ns) */
+#elif CONFIG_WS2812_FREQUENCY == 8000000
+#  define WS2812_RST_CYCLES 60          /* 60us (>50us)*/
+#  define WS2812_ZERO_BYTE  0b01100000  /* 250 ns (200ns - 500ns) */
+#  define WS2812_ONE_BYTE   0b01111100  /* 750 ns (550ns - 850ns) */
+#else
+#  error "Unsupported SPI Frequency"
+#endif
+
+#define WS2812_BYTES_PER_LED  8 * 3
+#define WS2812_RW_PIXEL_SIZE  4
+
+/* Transmit buffer looks like:
+ * [<----reset bytes---->|<-RGBn->...<-RGB0->|<----reset bytes---->]
+ *
+ * It is important that this is shipped as close to one chunk as possible
+ * in order to meet timeing requirements and to keep MOSI from going high
+ * between transactions.  Some chips will leave MOSI at the state of the
+ * MSB of the last byte for this reason it is recommended to shift the
+ * bytes that represents the zero and one so that the MSB is 1. The reset
+ * clocks will pad the shortend low at the end.
+ */
+
+#define TXBUFF_SIZE(n) (WS2812_RST_CYCLES * 2 + n * WS2812_BYTES_PER_LED)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct ws2812_dev_s
+{
+  FAR struct spi_dev_s *spi;  /* SPI interface */
+  uint16_t nleds;             /* Number of addressable LEDs */
+  uint8_t *tx_buf;            /* Buffer for write transaction and state */
+  sem_t exclsem;              /* Assures exclusive access to the driver */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void ws2812_configspi(FAR struct spi_dev_s *spi);
+static void ws2812_pack(FAR uint8_t *buf, uint32_t rgb);
+
+/* Character driver methods */
+
+static int     ws2812_open(FAR struct file *filep);
+static int     ws2812_close(FAR struct file *filep);
+static ssize_t ws2812_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen);
+static ssize_t ws2812_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen);
+static off_t   ws2812_seek(FAR struct file *filep, off_t offset, int whence);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_ws2812fops =
+{
+  ws2812_open,    /* open */
+  ws2812_close,   /* close */
+  ws2812_read,    /* read */
+  ws2812_write,   /* write */
+  ws2812_seek,    /* seek */
+  NULL,           /* ioctl */
+  NULL,           /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  NULL            /* unlink */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ws2812_configspi
+ *
+ * Description:
+ *   Set the SPI bus configuration
+ *
+ ****************************************************************************/
+
+static inline void ws2812_configspi(FAR struct spi_dev_s *spi)
+{
+  /* Configure SPI for the WS2812 */
+
+  SPI_SETMODE(spi, SPIDEV_MODE3);
+  SPI_SETBITS(spi, 8);
+  SPI_HWFEATURES(spi, 0);
+  SPI_SETFREQUENCY(spi, CONFIG_WS2812_FREQUENCY);
+}
+
+/****************************************************************************
+ * Name: ws2812_pack
+ *
+ * Description:
+ *   This writes the expanded SPI transaction to the transaction buffer
+ *   for a given 24bit RGB value.
+ *
+ * Input Parameters:
+ *   buf - The location in the transmit buffer to write.
+ *   rgb - A 24bit RGB color 8bit red, 8-bit green, 8-bit blue
+ *
+ ****************************************************************************/
+
+static void ws2812_pack(FAR uint8_t *buf, uint32_t rgb)
+{
+  uint8_t bit_idx;
+  uint8_t byte_idx;
+  uint8_t offset = 0;
+  uint8_t color;
+  uint32_t grb;
+
+  grb = (rgb & 0x00ff00) << 8;
+  grb |= (rgb & 0xff0000) >> 8;
+  grb |= rgb & 0x0000ff;
+
+  for (byte_idx = 0; byte_idx < 3; byte_idx++)
+    {
+      color = (uint8_t)(grb >> (8 * (2 - byte_idx)));
+      for (bit_idx = 0; bit_idx < 8; bit_idx++)
+        {
+          if (color & (1 << (7 - bit_idx)))
+            {
+              buf[offset] = WS2812_ONE_BYTE;
+            }
+          else
+            {
+              buf[offset] = WS2812_ZERO_BYTE;
+            }
+
+          offset++;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: ws2812_open
+ *
+ * Description:
+ *   This function is called whenever the WS2812 device is opened.
+ *
+ ****************************************************************************/
+
+static int ws2812_open(FAR struct file *filep)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ws2812_close
+ *
+ * Description:
+ *   This routine is called when the WS2812 device is closed.
+ *
+ ****************************************************************************/
+
+static int ws2812_close(FAR struct file *filep)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ws2812_read
+ ****************************************************************************/
+
+static ssize_t ws2812_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen)
+{
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: ws2812_write
+ *
+ * Description:
+ *   This routine is called when writing to the WS2812 device. Data buffer
+ *   should be an array of 32bit values holding 24bits of color information
+ *   in host byte ordering 0x**rrggbb.
+ *
+ ****************************************************************************/
+
+static ssize_t ws2812_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct ws2812_dev_s *priv = inode->i_private;
+  FAR uint8_t *tx_pixel;
+  FAR uint32_t *pixel_buf = (FAR uint32_t *)buffer;
+  size_t cur_led;
+  size_t start_led;
+  size_t end_led;
+  size_t written = 0;
+
+  if (buffer == NULL)
+    {
+      lederr("ERROR: Buffer is null\n");
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  /* We need at least one display, so 1 byte */
+
+  if (buflen < 1)
+    {
+      lederr("ERROR: You need to control at least 1 LED!\n");
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  if ((buflen % WS2812_RW_PIXEL_SIZE) != 0)
+    {
+      lederr("ERROR: LED values must be 24bit packed in 32bit\n");
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  nxsem_wait(&priv->exclsem);
+
+  start_led = filep->f_pos / WS2812_RW_PIXEL_SIZE;
+  tx_pixel = priv->tx_buf + WS2812_RST_CYCLES + \
+             start_led * WS2812_BYTES_PER_LED;
+
+  end_led = start_led + (buflen / WS2812_RW_PIXEL_SIZE) - 1;
+  ledinfo("Start: %d End: %d\n", start_led, end_led);
+
+  if (end_led  > (priv->nleds -1))
+    {
+      end_led = priv->nleds - 1;
+    }
+
+  for (cur_led = start_led; cur_led <= end_led; cur_led++)
+    {
+      ws2812_pack(tx_pixel, *pixel_buf & 0xffffff);
+      pixel_buf++;
+      tx_pixel += WS2812_BYTES_PER_LED;
+      written += WS2812_RW_PIXEL_SIZE;
+    }
+

Review comment:
       Do you need to lock the SPI bus and then call ws2812_configspi here?




----------------------------------------------------------------
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.

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