Skip to content

Commit

Permalink
NeoPixel: Add invertedDIN option to use single transistor driver.
Browse files Browse the repository at this point in the history
* Patch allows using single transistor (i.e. IRLML6344) to drive WS2812B.
* Transistor is required for MCU 3.3V signals to drive 5V WS2812B.
* Inverted DIN and bistream hi-to-lo only is compensated by timings.
* Please verify on your hardware.

How compensation timings were calculated:
```
    STREAM: 11001010
       BUS: 110 110 100 100 110 100 110 100
       LET: A B A B CD  CD  A B CD  A B CD
INV STREAM: 00110101
   INV BUS: 001 001 011 011 001 011 001 011
   INV LET: D C D C BA  BA  D C BA  D C BA
```

Signed-off-by: Tomasz 'CeDeROM' CEDRO <tomek@cedro.info>
  • Loading branch information
cederom committed Nov 27, 2021
1 parent 97a7cc2 commit 12ec6b1
Showing 1 changed file with 33 additions and 8 deletions.
41 changes: 33 additions & 8 deletions drivers/neopixel/neopixel.py
@@ -1,26 +1,50 @@
# NeoPixel driver for MicroPython
# MIT license; Copyright (c) 2016 Damien P. George, 2021 Jim Mussared
#
# (C) 2021 CeDeROM Tomasz CEDRO.
# Note: Inverted DIN using single transistor (i.e. IRLML6344) is experimental!
# Below analysis of inverted DIN timings is presented. Works on WS2812B.
# STREAM: 11001010
# BUS: 110 110 100 100 110 100 110 100
# LET: A B A B CD CD A B CD A B CD
# INV STREAM: 00110101
# INV BUS: 001 001 011 011 001 011 001 011
# INV LET: D C D C BA BA D C BA D C BA


from machine import bitstream

_BITSTREAM_TYPE_HIGH_LOW = const(0)
_TIMING_WS2818_800 = (400, 850, 800, 450)
_TIMING_WS2818_400 = (800, 1700, 1600, 900)
_TIMING_WS2818_800_INV = (850, 400, 450, 800)
_TIMING_WS2812_400_INV = (1700, 800, 900, 1600)

class NeoPixel:
# G R B W
ORDER = (1, 0, 2, 3)

def __init__(self, pin, n, bpp=3, timing=1):
def __init__(self, pin, n, bpp=3, timing=1, invertedDIN=False):
self.pin = pin
self.n = n
self.bpp = bpp
self.buf = bytearray(n * bpp)
self.invertedDIN = invertedDIN
self.pin.init(pin.OUT)
# Timing arg can either be 1 for 800kHz or 0 for 400kHz,
# or a user-specified timing ns tuple (high_0, low_0, high_1, low_1).
self.timing = (
((400, 850, 800, 450) if timing else (800, 1700, 1600, 900))
if isinstance(timing, int)
else timing
)
if self.invertedDIN:
self.timing = (
(_TIMING_WS2818_800_INV if timing else _TIMING_WS2818_400_INV)
if isinstance(timing, int)
else timing
)
else:
self.timing = (
(_TIMING_WS2818_800 if timing else _TIMING_WS2818_400)
if isinstance(timing, int)
else timing
)

def __len__(self):
return self.n
Expand All @@ -46,5 +70,6 @@ def fill(self, v):
j += bpp

def write(self):
# BITSTREAM_TYPE_HIGH_LOW = 0
bitstream(self.pin, 0, self.timing, self.buf)
if self.invertedDIN: pin.value(1)
bitstream(self.pin, _BITSTREAM_TYPE_HIGH_LOW, self.timing, self.buf)
if self.invertedDIN: pin.value(1)

0 comments on commit 12ec6b1

Please sign in to comment.