Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    Controlling NeoPixel LED

    Scheduled Pinned Locked Moved SiPy
    ledspilibrary
    9 Posts 3 Posters 1.4k Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B Offline
      brossingo
      last edited by

      Hello,
      I am new with Pycom and working on a project which requires the use of a Sipy board. I have to blink LEDs connected to VCC, GND and Pin 22 through three wires. I do not know if these are WS2812 LEDs but thought of using the corresponding library (https://github.com/JanBednarik/micropython-ws2812/blob/master/ws2812.py). That or the Adafruit_Blinka librabry. However, both libraries seem to be working only for Wipy or Lopy board and also with the use of a SPI connection (which I am not using, but I could if easier). That is why I would like to know if it is possible to control those LEDs with Sipy and without using SPI ?
      I can provide you with further information if you need. Thank you all for your help

      robert-hhR J 4 Replies Last reply Reply Quote 0
      • robert-hhR Offline
        robert-hh @brossingo
        last edited by

        @brossingo You can use all Pycom devices with a generic peripheral like WS2812 LED's. The only thing you have to care about is whtjher a certain Pin is used by board internal peripherals. P22 on the SiPy can be used for the LEDs. The WS2812 needs 5v for operation, so you have to connect it to Vin. The data input may work with 3.3V levels. if not, you will need a level shifter or reduve the supply voltage of the WS2812 to about 4V. A simple 1N4001 Diode between Vin of the SiPy and Vcc of the WD2812 would do that reduction.
        The example you linked if for a Pyboard device. When used with a SiPy, it requires chages in the sections, where the SPI object is instantiated. You may also look at https://github.com/nickovs/ws2812-SPI/blob/master/neoSPI.py, which is also for a different MicroPython dialect, but more close to the PyCom PySpeak.

        B 1 Reply Last reply Reply Quote 0
        • B Offline
          brossingo
          last edited by

          This post is deleted!
          1 Reply Last reply Reply Quote 0
          • B Offline
            brossingo @robert-hh
            last edited by robert-hh

            @robert-hh Thanks for answering. As I said, I did not want to use a SPI connection. My 2 LEDs only share 3 wires. I wanted to use this neopixel module :

            import neopixel_write
            from neopixel_write import neopixel_write
            
            class NeoPixel:
                def __init__(self, pin, n):
                    self.pin = pin
                    self.n = n
                    self.buf = bytearray(n * 3)
                    self.pin.init(pin.OUT)
            
                def __setitem__(self, index, val):
                    r, g, b = val
                    self.buf[index * 3] = g
                    self.buf[index * 3 + 1] = r
                    self.buf[index * 3 + 2] = b
            
                def __getitem__(self, index):
                    i = index * 3
                    return self.buf[i + 1], self.buf[i], self.buf[i + 2]
            
                def fill(self, color):
                    r, g, b = color
                    for i in range(len(self.buf) / 3):
                        self.buf[i * 3] = g
                        self.buf[i * 3 + 1] = r
                        self.buf[i * 3 + 2] = b
            
                def write(self):
                    neopixel_write(self.pin, self.buf, True)
            
            
            

            It seems really appropriate, but can't find a proper definition of the neopixel_write function which is really useful. I only have this for now (https://github.com/adafruit/Adafruit_Blinka/blob/master/src/neopixel_write.py) (i ignored everything above the definition of the function itstelf). The thing is, when I run it, I got this error message : NameError: name ':_neopixel' is not defined.

            robert-hhR 2 Replies Last reply Reply Quote 0
            • robert-hhR Offline
              robert-hh @brossingo
              last edited by robert-hh

              @brossingo You cannot find the neopixel_write() method on a pycom device, because that is specific to the esp module of micropython.org's firmware. I will try tonight to use the SPI lib you cited in your post.
              See also this post: https://forum.pycom.io/topic/2196/rgb/2
              There have been examples with pycom device to use the RMT module. If you search in the forum for WS2812 or neopixel, you'll find that. But the code there addresses the controller directly, and since then a more comfortable support for using the RMT has been implemented.

              1 Reply Last reply Reply Quote 0
              • J Offline
                jcaron @brossingo
                last edited by

                @brossingo is using WS2812 LEDs a requirement? There are alternatives that use a standard SPI interface instead of the timing-sensitive interface of the WS2812.

                1 Reply Last reply Reply Quote 0
                • robert-hhR Offline
                  robert-hh @brossingo
                  last edited by

                  @brossingo Using this module https://raw.githubusercontent.com/Gadgetoid/wipy-WS2812/master/ws2812alt.py with a few test lines I could get it working with SPI, but not well. Only certain brightness values can be used.

                  from ws2812 import WS2812
                  chain = WS2812(ledNumber=4)
                  data = [
                      (127, 0, 0),    # red
                      (0, 127, 0),    # green
                      (0, 0, 127),    # blue
                      (127, 127, 127),   # white
                  ]
                  chain.show(data)
                  

                  Vcc of neopixel to Vin,
                  GND to GND
                  Data to P11
                  So I'll give RMT a chance.

                  1 Reply Last reply Reply Quote 0
                  • robert-hhR Offline
                    robert-hh @brossingo
                    last edited by robert-hh

                    @brossingo Now I drew the skeleton of a module which uses RMT to send the data using a single GPIO port. It is not overly effective in matters of RAM usage, but it works well and has reliable timing. I tested that with a 24 NeoPixel device.
                    Connection:
                    WS2812 -> xxPy
                    Vcc -> Vin (5v)
                    GND -> GND
                    Data -> GPIO (here: P11)

                    from machine import RMT
                    from time import sleep
                    
                    def send_rmt(data, rmt):
                        no_pixel = len(data)
                        bits = bytearray(no_pixel * 24 * 2 + 2)
                        duration =  bytearray(no_pixel * 24 * 2 + 2)
                        bits[0] = 0
                        duration[0] = 255
                        bits[0] = 1
                        duration[1] = 255 # reset 51 µs
                        index = 2
                        for pixel in data:
                            for byte in pixel:
                                mask = 0x80
                                while mask:
                                    bits[index] = 1
                                    bits[index+1] = 0
                                    if byte & mask:
                                        duration[index] = 8
                                        duration[index+1] = 4
                                    else:
                                        duration[index] = 5
                                        duration[index+1] = 9
                                    index += 2
                                    mask >>= 1
                        rmt.pulses_send(tuple(duration), tuple(bits))
                    
                    data = [
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                        (127, 0, 0),    # green
                        (0, 127, 0),    # red
                        (0, 0, 127),    # blue
                        (127, 127, 127),   # white
                    ]
                    
                    blank = 24 * [(0,0,0)]
                    rmt = RMT(channel=3, gpio="P11", tx_idle_level=0)
                    
                    while True:
                        send_rmt(data, rmt)
                        sleep(1)
                        send_rmt(blank, rmt)
                        sleep(1)
                    
                    1 Reply Last reply Reply Quote 0
                    • robert-hhR Offline
                      robert-hh @brossingo
                      last edited by

                      @brossingo I simplified the neopixel demo code using RMT a little bit. Also, I made a similar short function using SPI. It works to some extend (better than the other SPI driver), but the problem is the unpredictable timing of SPI. It had gaps between the words it sends, which the disturbs the communication.
                      Here is the RMT variant

                      from machine import RMT
                      from time import sleep
                      
                      def send_rmt(data, rmt):
                          from time import sleep_us
                          no_pixel = len(data)
                          bits = bytearray(no_pixel * 24 * 2)
                          duration =  bytearray(no_pixel * 24 * 2)
                          index = 0
                          for pixel in data:
                              for byte in pixel:
                                  mask = 0x80
                                  while mask:
                                      bits[index] = 1
                                      bits[index+1] = 0
                                      if byte & mask:
                                          duration[index] = 8
                                          duration[index+1] = 4
                                      else:
                                          duration[index] = 4
                                          duration[index+1] = 8
                                      index += 2
                                      mask >>= 1
                          sleep_us(60) # wait for the reset time
                          rmt.pulses_send(tuple(duration), tuple(bits))
                          sleep_us(60) # wait for the reset time
                      
                      data = 6 * [
                          (127, 0, 0),    # green
                          (0, 127, 0),    # red
                          (0, 0, 127),    # blue
                          ]
                      
                      blank = 24 * [(0,0,0)]
                      
                      rmt = RMT(channel=3, gpio="P11", tx_idle_level=0)
                      
                      while True:
                          send_rmt(data, rmt)
                          sleep(1)
                          send_rmt(blank, rmt)
                          sleep(1)
                      

                      And here is the SPI variant:

                      from machine import SPI, disable_irq, enable_irq
                      from time import sleep, sleep_us
                      
                      def send_spi(data, spi):
                          no_pixel = len(data)
                          buffer = bytearray(no_pixel * 3 * 4)
                          index = 0
                          for pixel in data:
                              for byte in pixel:
                                  bits = 0
                                  mask = 0x80
                                  while mask:
                                      bits <<= 4
                                      if byte & mask:
                                          bits |= 0x0e
                                      else:
                                          bits |= 0x08
                                      mask >>= 1
                                  buffer[index] = (bits >> 24) & 0xff
                                  buffer[index + 1] = (bits >> 16) & 0xff
                                  buffer[index + 2] = (bits >> 8) & 0xff
                                  buffer[index + 3] = bits & 0xff
                                  index += 4
                          sleep_us(60) # ensure initial reset
                          state = disable_irq()
                          spi.write(buffer)
                          enable_irq(state)
                      
                      data = 6 * [
                          (85, 0, 0),    # green
                          (0, 85, 0),    # red
                          (0, 0, 85),    # blue
                          (85, 85, 85),   # white
                          ]
                      
                      blank = 24 * [(0,0,0)]
                      spi = SPI(SPI.MASTER, baudrate=3200000, polarity = 0, firstbit = SPI.MSB, bits=32)
                      
                      while True:
                          send_spi(data, spi)
                          sleep(1)
                          send_spi(blank, spi)
                          sleep(1)
                      
                      1 Reply Last reply Reply Quote 0

                      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                      With your input, this post could be even better 💗

                      Register Login
                      • 1 / 1
                      • First post
                        Last post

                      Pycom on Twitter

                      Pycom