Skip to content

Commit 694fdec

Browse files
committed
2 parents 0e9a311 + a9c8fbb commit 694fdec

File tree

5 files changed

+117
-173
lines changed

5 files changed

+117
-173
lines changed

README.rst

+44
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,50 @@ This example demonstrates the library with the single built-in DotStar on the
7878
pixels = adafruit_dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1)
7979
pixels[0] = (10, 0, 0)
8080
81+
82+
This example demonstrates the library with the DotStar Feather Wing and bounces Blinka.
83+
84+
`Feather M4 Express <https://www.adafruit.com/product/3857>`_ and
85+
`DotStar FeatherWing <https://www.adafruit.com/product/3449>`_.
86+
87+
.. code-block:: python
88+
89+
import board
90+
import adafruit_dotstar
91+
import time
92+
93+
94+
import adafruit_dotstar
95+
dotstar = adafruit_dotstar.DotStar(board.D13, board.D11, 72,
96+
pixel_order=adafruit_dotstar.BGR,
97+
brightness=0.3, auto_write=False)
98+
99+
blinka = (
100+
(0, 0x0f0716, 0x504069, 0x482e63, 0, 0),
101+
(0, 0x3d1446, 0x502b74, 0x622f8c, 0, 0),
102+
(0, 0x2e021b, 0x2e021b, 0x2e021b, 0, 0),
103+
(0, 0, 0x2e021b, 0x2e021b, 0, 0),
104+
(0, 0x591755, 0x912892, 0x3f205c, 0x282828, 0x301844),
105+
(0x65206b, 0x932281, 0x6e318f, 0x6d2b7e, 0x7e2686, 0x8c2c8f),
106+
(0x7c2d8c, 0xa21c81, 0x6b308e, 0x74257b, 0x7b2482, 0x742f8d),
107+
(0x23051a, 0x5c0f45, 0x81227b, 0x551a5b, 0x691b5d, 0x4d0c39),
108+
)
109+
offset = 0
110+
direction = 1
111+
while True:
112+
dotstar.fill(0)
113+
for y, row in enumerate(blinka):
114+
for x, value in enumerate(row):
115+
n = x * 12 + (y + offset)
116+
dotstar[n] = row[x]
117+
dotstar.show()
118+
time.sleep(0.1)
119+
offset += direction
120+
if offset > 4 or offset < 0:
121+
direction = -direction
122+
offset += direction
123+
124+
81125
Contributing
82126
============
83127

adafruit_dotstar.py

+65-169
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Copyright (c) 2016 Damien P. George (original Neopixel object)
44
# Copyright (c) 2017 Ladyada
55
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
6+
# Copyright (c) 2019 Roy Hooper
67
#
78
# Permission is hereby granted, free of charge, to any person obtaining a copy
89
# of this software and associated documentation files (the "Software"), to deal
@@ -23,30 +24,33 @@
2324
# THE SOFTWARE.
2425

2526
"""
26-
`adafruit_dotstar` - DotStar strip driver
27-
====================================================
27+
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
28+
=================================================================================
2829
29-
* Author(s): Damien P. George, Limor Fried & Scott Shawcroft
30+
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
3031
"""
3132
import busio
3233
import digitalio
34+
try:
35+
import _pixelbuf
36+
except ImportError:
37+
import adafruit_pypixelbuf as _pixelbuf
3338

3439
__version__ = "0.0.0-auto.0"
3540
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
3641

3742
START_HEADER_SIZE = 4
38-
LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
3943

40-
# Pixel color order constants
41-
RGB = (0, 1, 2)
42-
RBG = (0, 2, 1)
43-
GRB = (1, 0, 2)
44-
GBR = (1, 2, 0)
45-
BRG = (2, 0, 1)
46-
BGR = (2, 1, 0)
44+
RBG = 'PRBG'
45+
RGB = 'PRGB'
46+
GRB = 'PGRB'
47+
GBR = 'PGBR'
48+
BRG = 'PBRG'
49+
BGR = 'PBGR'
50+
BGR = 'PBGR'
4751

4852

49-
class DotStar:
53+
class DotStar(_pixelbuf.PixelBuf):
5054
"""
5155
A sequence of dotstars.
5256
@@ -56,16 +60,14 @@ class DotStar:
5660
:param float brightness: Brightness of the pixels between 0.0 and 1.0
5761
:param bool auto_write: True if the dotstars should immediately change when
5862
set. If False, `show` must be called explicitly.
59-
:param tuple pixel_order: Set the pixel order on the strip - different
60-
strips implement this differently. If you send red, and it looks blue
61-
or green on the strip, modify this! It should be one of the values
62-
above.
63+
:param str pixel_order: Set the pixel order on the strip - different
64+
strips implement this differently. If you send red, and it looks blue
65+
or green on the strip, modify this! It should be one of the values above.
6366
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
6467
using 'soft' SPI). This is only a recommendation; the actual clock
6568
rate may be slightly different depending on what the system hardware
6669
can provide.
6770
68-
6971
Example for Gemma M0:
7072
7173
.. code-block:: python
@@ -105,36 +107,60 @@ def __init__(
105107
self.dpin.direction = digitalio.Direction.OUTPUT
106108
self.cpin.direction = digitalio.Direction.OUTPUT
107109
self.cpin.value = False
108-
self._n = n
110+
self.n = n
111+
109112
# Supply one extra clock cycle for each two pixels in the strip.
110-
self.end_header_size = n // 16
113+
end_header_size = n // 16
111114
if n % 16 != 0:
112-
self.end_header_size += 1
113-
self._buf = bytearray(n * 4 + START_HEADER_SIZE + self.end_header_size)
114-
self.end_header_index = len(self._buf) - self.end_header_size
115+
end_header_size += 1
116+
bufsize = 4 * n + START_HEADER_SIZE + end_header_size
117+
end_header_index = bufsize - end_header_size
115118
self.pixel_order = pixel_order
119+
120+
self._buf = bytearray(bufsize)
121+
self._rawbuf = bytearray(bufsize)
122+
116123
# Four empty bytes to start.
117124
for i in range(START_HEADER_SIZE):
118-
self._buf[i] = 0x00
119-
# Mark the beginnings of each pixel.
120-
for i in range(START_HEADER_SIZE, self.end_header_index, 4):
121-
self._buf[i] = 0xFF
125+
self._rawbuf[i] = 0x00
122126
# 0xff bytes at the end.
123-
for i in range(self.end_header_index, len(self._buf)):
124-
self._buf[i] = 0xFF
125-
self._brightness = 1.0
126-
# Set auto_write to False temporarily so brightness setter does _not_
127-
# call show() while in __init__.
128-
self.auto_write = False
129-
self.brightness = brightness
130-
self.auto_write = auto_write
127+
for i in range(end_header_index, bufsize):
128+
self._rawbuf[i] = 0xff
129+
# Mark the beginnings of each pixel.
130+
for i in range(START_HEADER_SIZE, end_header_index, 4):
131+
self._rawbuf[i] = 0xff
132+
self._buf[:] = self._rawbuf[:]
133+
134+
super(DotStar, self).__init__(n, self._buf, byteorder=pixel_order,
135+
rawbuf=self._rawbuf, offset=START_HEADER_SIZE,
136+
brightness=brightness, auto_write=auto_write)
137+
138+
def show(self):
139+
"""Shows the new colors on the pixels themselves if they haven't already
140+
been autowritten.
141+
142+
The colors may or may not be showing after this method returns because
143+
it may be done asynchronously.
144+
145+
This method is called automatically if auto_write is set to True.
146+
"""
147+
if self._spi:
148+
self._spi.write(self._buf)
149+
else:
150+
self.ds_writebytes()
151+
152+
def _ds_writebytes(self):
153+
for b in self.buf:
154+
for _ in range(8):
155+
self.dpin.value = (b & 0x80)
156+
self.cpin.value = True
157+
self.cpin.value = False
158+
b = b << 1
159+
self.cpin.value = False
131160

132161
def deinit(self):
133162
"""Blank out the DotStars and release the resources."""
134-
self.auto_write = False
135-
for i in range(START_HEADER_SIZE, self.end_header_index):
136-
if i % 4 != 0:
137-
self._buf[i] = 0
163+
self.fill(0)
138164
self.show()
139165
if self._spi:
140166
self._spi.deinit()
@@ -151,136 +177,6 @@ def __exit__(self, exception_type, exception_value, traceback):
151177
def __repr__(self):
152178
return "[" + ", ".join([str(x) for x in self]) + "]"
153179

154-
def _set_item(self, index, value):
155-
"""
156-
value can be one of three things:
157-
a (r,g,b) list/tuple
158-
a (r,g,b, brightness) list/tuple
159-
a single, longer int that contains RGB values, like 0xFFFFFF
160-
brightness, if specified should be a float 0-1
161-
162-
Set a pixel value. You can set per-pixel brightness here, if it's not passed it
163-
will use the max value for pixel brightness value, which is a good default.
164-
165-
Important notes about the per-pixel brightness - it's accomplished by
166-
PWMing the entire output of the LED, and that PWM is at a much
167-
slower clock than the rest of the LEDs. This can cause problems in
168-
Persistence of Vision Applications
169-
"""
170-
171-
offset = index * 4 + START_HEADER_SIZE
172-
rgb = value
173-
if isinstance(value, int):
174-
rgb = (value >> 16, (value >> 8) & 0xFF, value & 0xFF)
175-
176-
if len(rgb) == 4:
177-
brightness = value[3]
178-
# Ignore value[3] below.
179-
else:
180-
brightness = 1
181-
182-
# LED startframe is three "1" bits, followed by 5 brightness bits
183-
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
184-
# vary based on hardware
185-
# same as math.ceil(brightness * 31) & 0b00011111
186-
# Idea from https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions
187-
brightness_byte = 32 - int(32 - brightness * 31) & 0b00011111
188-
self._buf[offset] = brightness_byte | LED_START
189-
self._buf[offset + 1] = rgb[self.pixel_order[0]]
190-
self._buf[offset + 2] = rgb[self.pixel_order[1]]
191-
self._buf[offset + 3] = rgb[self.pixel_order[2]]
192-
193-
def __setitem__(self, index, val):
194-
if isinstance(index, slice):
195-
start, stop, step = index.indices(self._n)
196-
length = stop - start
197-
if step != 0:
198-
# same as math.ceil(length / step)
199-
# Idea from https://fizzbuzzer.com/implement-a-ceil-function/
200-
length = (length + step - 1) // step
201-
if len(val) != length:
202-
raise ValueError("Slice and input sequence size do not match.")
203-
for val_i, in_i in enumerate(range(start, stop, step)):
204-
self._set_item(in_i, val[val_i])
205-
else:
206-
self._set_item(index, val)
207-
208-
if self.auto_write:
209-
self.show()
210-
211-
def __getitem__(self, index):
212-
if isinstance(index, slice):
213-
out = []
214-
for in_i in range(*index.indices(self._n)):
215-
out.append(
216-
tuple(
217-
self._buf[in_i * 4 + (3 - i) + START_HEADER_SIZE]
218-
for i in range(3)
219-
)
220-
)
221-
return out
222-
if index < 0:
223-
index += len(self)
224-
if index >= self._n or index < 0:
225-
raise IndexError
226-
offset = index * 4
227-
return tuple(self._buf[offset + (3 - i) + START_HEADER_SIZE] for i in range(3))
228-
229-
def __len__(self):
230-
return self._n
231-
232-
@property
233-
def brightness(self):
234-
"""Overall brightness of the pixel"""
235-
return self._brightness
236-
237-
@brightness.setter
238-
def brightness(self, brightness):
239-
self._brightness = min(max(brightness, 0.0), 1.0)
240-
if self.auto_write:
241-
self.show()
242-
243180
def fill(self, color):
244181
"""Colors all pixels the given ***color***."""
245-
auto_write = self.auto_write
246-
self.auto_write = False
247-
for i in range(self._n):
248-
self[i] = color
249-
if auto_write:
250-
self.show()
251-
self.auto_write = auto_write
252-
253-
def _ds_writebytes(self, buf):
254-
for b in buf:
255-
for _ in range(8):
256-
self.dpin.value = b & 0x80
257-
self.cpin.value = True
258-
self.cpin.value = False
259-
b = b << 1
260-
261-
def show(self):
262-
"""Shows the new colors on the pixels themselves if they haven't already
263-
been autowritten.
264-
265-
The colors may or may not be showing after this function returns because
266-
it may be done asynchronously."""
267-
# Create a second output buffer if we need to compute brightness
268-
buf = self._buf
269-
if self.brightness < 1.0:
270-
buf = bytearray(self._buf)
271-
# Four empty bytes to start.
272-
for i in range(START_HEADER_SIZE):
273-
buf[i] = 0x00
274-
for i in range(START_HEADER_SIZE, self.end_header_index):
275-
buf[i] = (
276-
self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness)
277-
)
278-
# Four 0xff bytes at the end.
279-
for i in range(self.end_header_index, len(buf)):
280-
buf[i] = 0xFF
281-
282-
if self._spi:
283-
self._spi.write(buf)
284-
else:
285-
self._ds_writebytes(buf)
286-
self.cpin.value = False
182+
_pixelbuf.fill(self, color)

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"sphinx.ext.viewcode",
1717
]
1818

19-
# autodoc_mock_imports = ["digitalio", "busio"]
19+
autodoc_mock_imports = ["pypixelbuf"]
2020

2121
intersphinx_mapping = {
2222
"python": ("https://docs.python.org/3.4", None),

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
Adafruit-Blinka
22
adafruit-circuitpython-busdevice
3+
adafruit-circuitpython-pypixelbuf

setup.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@
2828
# The project's main homepage.
2929
url="https://github.com/adafruit/Adafruit_CircuitPython_DotStar",
3030
# Author details
31-
author="Adafruit Industries",
32-
author_email="[email protected]",
33-
install_requires=["Adafruit-Blinka", "adafruit-circuitpython-busdevice"],
31+
author='Adafruit Industries',
32+
author_email='[email protected]',
33+
34+
install_requires=['Adafruit-Blinka', 'adafruit-circuitpython-busdevice',
35+
'adafruit-circuitpython-pypixelbuf'],
36+
3437
# Choose your license
3538
license="MIT",
3639
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers

0 commit comments

Comments
 (0)