Updated UM boards

This commit is contained in:
Seon Rozenblum 2020-09-23 05:20:10 +10:00
parent 2bb44f6c4d
commit a2a0aa058f
23 changed files with 2663 additions and 15 deletions

View File

@ -0,0 +1,198 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Damien P. George (original Neopixel object)
# Copyright (c) 2017 Ladyada
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
# Copyright (c) 2019 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
=================================================================================
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
"""
# pylint: disable=ungrouped-imports
import sys
import busio
import digitalio
if sys.implementation.version[0] < 5:
import adafruit_pypixelbuf as _pixelbuf
else:
try:
import _pixelbuf
except ImportError:
import adafruit_pypixelbuf as _pixelbuf
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
START_HEADER_SIZE = 4
# Pixel color order constants
RBG = "PRBG"
"""Red Blue Green"""
RGB = "PRGB"
"""Red Green Blue"""
GRB = "PGRB"
"""Green Red Blue"""
GBR = "PGBR"
"""Green Blue Red"""
BRG = "PBRG"
"""Blue Red Green"""
BGR = "PBGR"
"""Blue Green Red"""
class DotStar(_pixelbuf.PixelBuf):
"""
A sequence of dotstars.
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
:param ~microcontroller.Pin data: The pin to output dotstar data on.
:param int n: The number of dotstars in the chain
:param float brightness: Brightness of the pixels between 0.0 and 1.0
:param bool auto_write: True if the dotstars should immediately change when
set. If False, `show` must be called explicitly.
:param str pixel_order: Set the pixel order on the strip - different
strips implement this differently. If you send red, and it looks blue
or green on the strip, modify this! It should be one of the values above.
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
using 'soft' SPI). This is only a recommendation; the actual clock
rate may be slightly different depending on what the system hardware
can provide.
Example for Gemma M0:
.. code-block:: python
import adafruit_dotstar
import time
from board import *
RED = 0x100000
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
pixels[0] = RED
time.sleep(2)
.. py:method:: DotStar.show()
Shows the new colors on the dotstars themselves if they haven't already
been autowritten.
The colors may or may not be showing after this function returns because
it may be done asynchronously.
.. py:method:: DotStar.fill(color)
Colors all dotstars the given ***color***.
.. py:attribute:: brightness
Overall brightness of all dotstars (0 to 1.0)
"""
def __init__(
self,
clock,
data,
n,
*,
brightness=1.0,
auto_write=True,
pixel_order=BGR,
baudrate=4000000
):
self._spi = None
try:
self._spi = busio.SPI(clock, MOSI=data)
while not self._spi.try_lock():
pass
self._spi.configure(baudrate=baudrate)
except (NotImplementedError, ValueError):
self.dpin = digitalio.DigitalInOut(data)
self.cpin = digitalio.DigitalInOut(clock)
self.dpin.direction = digitalio.Direction.OUTPUT
self.cpin.direction = digitalio.Direction.OUTPUT
self.cpin.value = False
# Supply one extra clock cycle for each two pixels in the strip.
trailer_size = n // 16
if n % 16 != 0:
trailer_size += 1
# Four empty bytes for the header.
header = bytearray(START_HEADER_SIZE)
# 0xff bytes for the trailer.
trailer = bytearray(b"\xff") * trailer_size
super().__init__(
n,
byteorder=pixel_order,
brightness=brightness,
auto_write=auto_write,
header=header,
trailer=trailer,
)
def deinit(self):
"""Blank out the DotStars and release the resources."""
self.fill(0)
self.show()
if self._spi:
self._spi.deinit()
else:
self.dpin.deinit()
self.cpin.deinit()
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
self.deinit()
def __repr__(self):
return "[" + ", ".join([str(x) for x in self]) + "]"
@property
def n(self):
"""
The number of dotstars in the chain (read-only)
"""
return len(self)
def _transmit(self, buffer):
if self._spi:
self._spi.write(buffer)
else:
self._ds_writebytes(buffer)
def _ds_writebytes(self, buffer):
for b in buffer:
for _ in range(8):
self.dpin.value = b & 0x80
self.cpin.value = True
self.cpin.value = False
b = b << 1
self.cpin.value = False

View File

@ -0,0 +1,374 @@
# The MIT License (MIT)
#
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
# Copyright (c) 2019-2020 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
=================================================================
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
in neopixel.py and adafruit_dotstar.py.
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
"""
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
DOTSTAR_LED_BRIGHTNESS = 0b00011111
class PixelBuf: # pylint: disable=too-many-instance-attributes
"""
A sequence of RGB/RGBW pixels.
This is the pure python implementation of CircuitPython's _pixelbuf.
:param ~int n: Number of pixels
:param ~str byteorder: Byte order string constant (also sets bpp)
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
:param ~bool auto_write: Whether to automatically write pixels (Default False)
:param bytes header: Sequence of bytes to always send before pixel values.
:param bytes trailer: Sequence of bytes to always send after pixel values.
"""
def __init__( # pylint: disable=too-many-locals,too-many-arguments
self,
n,
byteorder="BGR",
brightness=1.0,
auto_write=False,
header=None,
trailer=None,
):
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
self.auto_write = False
effective_bpp = 4 if dotstar_mode else bpp
_bytes = effective_bpp * n
buf = bytearray(_bytes)
offset = 0
if header is not None:
if not isinstance(header, bytearray):
raise TypeError("header must be a bytearray")
buf = header + buf
offset = len(header)
if trailer is not None:
if not isinstance(trailer, bytearray):
raise TypeError("trailer must be a bytearray")
buf += trailer
self._pixels = n
self._bytes = _bytes
self._byteorder = byteorder_tuple
self._byteorder_string = byteorder
self._has_white = has_white
self._bpp = bpp
self._pre_brightness_buffer = None
self._post_brightness_buffer = buf
self._offset = offset
self._dotstar_mode = dotstar_mode
self._pixel_step = effective_bpp
if dotstar_mode:
self._byteorder_tuple = (
byteorder_tuple[0] + 1,
byteorder_tuple[1] + 1,
byteorder_tuple[2] + 1,
0,
)
# Initialize the buffer with the dotstar start bytes.
for i in range(self._offset, self._bytes + self._offset, 4):
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
self._brightness = 1.0
self.brightness = brightness
self.auto_write = auto_write
@staticmethod
def parse_byteorder(byteorder):
"""
Parse a Byteorder string for validity and determine bpp, byte order, and
dostar brightness bits.
Byteorder strings may contain the following characters:
R - Red
G - Green
B - Blue
W - White
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
:param: ~str bpp: bpp string.
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
"""
bpp = len(byteorder)
dotstar_mode = False
has_white = False
if byteorder.strip("RGBWP") != "":
raise ValueError("Invalid Byteorder string")
try:
r = byteorder.index("R")
g = byteorder.index("G")
b = byteorder.index("B")
except ValueError:
raise ValueError("Invalid Byteorder string")
if "W" in byteorder:
w = byteorder.index("W")
byteorder = (r, g, b, w)
has_white = True
elif "P" in byteorder:
lum = byteorder.index("P")
byteorder = (r, g, b, lum)
dotstar_mode = True
else:
byteorder = (r, g, b)
return bpp, byteorder, has_white, dotstar_mode
@property
def bpp(self):
"""
The number of bytes per pixel in the buffer (read-only).
"""
return self._bpp
@property
def brightness(self):
"""
Float value between 0 and 1. Output brightness.
When brightness is less than 1.0, a second buffer will be used to store the color values
before they are adjusted for brightness.
"""
return self._brightness
@brightness.setter
def brightness(self, value):
value = min(max(value, 0.0), 1.0)
change = value - self._brightness
if -0.001 < change < 0.001:
return
self._brightness = value
if self._pre_brightness_buffer is None:
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
# Adjust brightness of existing pixels
offset_check = self._offset % self._pixel_step
for i in range(self._offset, self._bytes + self._offset):
# Don't adjust per-pixel luminance bytes in dotstar mode
if self._dotstar_mode and (i % 4 != offset_check):
continue
self._post_brightness_buffer[i] = int(
self._pre_brightness_buffer[i] * self._brightness
)
if self.auto_write:
self.show()
@property
def byteorder(self):
"""
ByteOrder string for the buffer (read-only)
"""
return self._byteorder_string
def __len__(self):
"""
Number of pixels.
"""
return self._pixels
def show(self):
"""
Call the associated write function to display the pixels
"""
return self._transmit(self._post_brightness_buffer)
def fill(self, color):
"""
Fills the given pixelbuf with the given color.
:param pixelbuf: A pixel object.
:param color: Color to set.
"""
r, g, b, w = self._parse_color(color)
for i in range(self._pixels):
self._set_item(i, r, g, b, w)
if self.auto_write:
self.show()
def _parse_color(self, value):
r = 0
g = 0
b = 0
w = 0
if isinstance(value, int):
r = value >> 16
g = (value >> 8) & 0xFF
b = value & 0xFF
w = 0
if self._dotstar_mode:
w = 1.0
else:
if len(value) < 3 or len(value) > 4:
raise ValueError(
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
)
if len(value) == self._bpp:
if self._bpp == 3:
r, g, b = value
else:
r, g, b, w = value
elif len(value) == 3:
r, g, b = value
if self._dotstar_mode:
w = 1.0
if self._bpp == 4:
if self._dotstar_mode:
# LED startframe is three "1" bits, followed by 5 brightness bits
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
# vary based on hardware
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
elif (
self._has_white
and (isinstance(value, int) or len(value) == 3)
and r == g
and g == b
):
# If all components are the same and we have a white pixel then use it
# instead of the individual components when all 4 values aren't explicitly given.
w = r
r = 0
g = 0
b = 0
return (r, g, b, w)
def _set_item(
self, index, r, g, b, w
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
offset = self._offset + (index * self._bpp)
if self._pre_brightness_buffer is not None:
if self._bpp == 4:
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
if self._bpp == 4:
# Only apply brightness if w is actually white (aka not DotStar.)
if not self._dotstar_mode:
w = int(w * self._brightness)
self._post_brightness_buffer[offset + self._byteorder[3]] = w
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
r * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
g * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
b * self._brightness
)
def __setitem__(self, index, val):
if isinstance(index, slice):
start, stop, step = index.indices(self._pixels)
for val_i, in_i in enumerate(range(start, stop, step)):
r, g, b, w = self._parse_color(val[val_i])
self._set_item(in_i, r, g, b, w)
else:
r, g, b, w = self._parse_color(val)
self._set_item(index, r, g, b, w)
if self.auto_write:
self.show()
def _getitem(self, index):
start = self._offset + (index * self._bpp)
buffer = (
self._pre_brightness_buffer
if self._pre_brightness_buffer is not None
else self._post_brightness_buffer
)
value = [
buffer[start + self._byteorder[0]],
buffer[start + self._byteorder[1]],
buffer[start + self._byteorder[2]],
]
if self._has_white:
value.append(buffer[start + self._byteorder[3]])
elif self._dotstar_mode:
value.append(
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
)
return value
def __getitem__(self, index):
if isinstance(index, slice):
out = []
for in_i in range(
*index.indices(len(self._post_brightness_buffer) // self._bpp)
):
out.append(self._getitem(in_i))
return out
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
return self._getitem(index)
def _transmit(self, buffer):
raise NotImplementedError("Must be subclassed")
def wheel(pos):
"""
Helper to create a colorwheel.
:param pos: int 0-255 of color value to return
:return: tuple of RGB values
"""
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return 0, 0, 0
if pos < 85:
return 255 - pos * 3, pos * 3, 0
if pos < 170:
pos -= 85
return 0, 255 - pos * 3, pos * 3
pos -= 170
return pos * 3, 0, 255 - pos * 3

View File

@ -0,0 +1,311 @@
# The MIT License (MIT)
#
# Copyright (c) 2019 ladyada for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_requests`
================================================================================
A requests-like library for web interfacing
* Author(s): ladyada, Paul Sokolovsky
Implementation Notes
--------------------
Adapted from https://github.com/micropython/micropython-lib/tree/master/urequests
micropython-lib consists of multiple modules from different sources and
authors. Each module comes under its own licensing terms. Short name of
a license can be found in a file within a module directory (usually
metadata.txt or setup.py). Complete text of each license used is provided
at https://github.com/micropython/micropython-lib/blob/master/LICENSE
author='Paul Sokolovsky'
license='MIT'
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
import gc
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Requests.git"
_the_interface = None # pylint: disable=invalid-name
_the_sock = None # pylint: disable=invalid-name
def set_socket(sock, iface=None):
"""Helper to set the global socket and optionally set the global network interface.
:param sock: socket object.
:param iface: internet interface object
"""
global _the_sock # pylint: disable=invalid-name, global-statement
_the_sock = sock
if iface:
global _the_interface # pylint: disable=invalid-name, global-statement
_the_interface = iface
_the_sock.set_interface(iface)
class Response:
"""The response from a request, contains all the headers/content"""
encoding = None
def __init__(self, sock):
self.socket = sock
self.encoding = "utf-8"
self._cached = None
self.status_code = None
self.reason = None
self._read_so_far = 0
self.headers = {}
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
def close(self):
"""Close, delete and collect the response data"""
if self.socket:
self.socket.close()
del self.socket
del self._cached
gc.collect()
@property
def content(self):
"""The HTTP content direct from the socket, as bytes"""
# print(self.headers)
try:
content_length = int(self.headers["content-length"])
except KeyError:
content_length = 0
# print("Content length:", content_length)
if self._cached is None:
try:
self._cached = self.socket.recv(content_length)
finally:
self.socket.close()
self.socket = None
# print("Buffer length:", len(self._cached))
return self._cached
@property
def text(self):
"""The HTTP content, encoded into a string according to the HTTP
header encoding"""
return str(self.content, self.encoding)
def json(self):
"""The HTTP content, parsed into a json dictionary"""
# pylint: disable=import-outside-toplevel
try:
import json as json_module
except ImportError:
import ujson as json_module
return json_module.loads(self.content)
def iter_content(self, chunk_size=1, decode_unicode=False):
"""An iterator that will stream data by only reading 'chunk_size'
bytes and yielding them, when we can't buffer the whole datastream"""
if decode_unicode:
raise NotImplementedError("Unicode not supported")
while True:
chunk = self.socket.recv(chunk_size)
if chunk:
yield chunk
else:
return
# pylint: disable=too-many-branches, too-many-statements, unused-argument, too-many-arguments, too-many-locals
def request(method, url, data=None, json=None, headers=None, stream=False, timeout=1):
"""Perform an HTTP request to the given url which we will parse to determine
whether to use SSL ('https://') or not. We can also send some provided 'data'
or a json dictionary which we will stringify. 'headers' is optional HTTP headers
sent along. 'stream' will determine if we buffer everything, or whether to only
read only when requested
"""
global _the_interface # pylint: disable=global-statement, invalid-name
global _the_sock # pylint: disable=global-statement, invalid-name
if not headers:
headers = {}
try:
proto, dummy, host, path = url.split("/", 3)
# replace spaces in path
path = path.replace(" ", "%20")
except ValueError:
proto, dummy, host = url.split("/", 2)
path = ""
if proto == "http:":
port = 80
elif proto == "https:":
port = 443
else:
raise ValueError("Unsupported protocol: " + proto)
if ":" in host:
host, port = host.split(":", 1)
port = int(port)
addr_info = _the_sock.getaddrinfo(host, port, 0, _the_sock.SOCK_STREAM)[0]
sock = _the_sock.socket(addr_info[0], addr_info[1], addr_info[2])
resp = Response(sock) # our response
sock.settimeout(timeout) # socket read timeout
try:
if proto == "https:":
conntype = _the_interface.TLS_MODE
sock.connect(
(host, port), conntype
) # for SSL we need to know the host name
else:
conntype = _the_interface.TCP_MODE
sock.connect(addr_info[-1], conntype)
sock.send(
b"%s /%s HTTP/1.0\r\n" % (bytes(method, "utf-8"), bytes(path, "utf-8"))
)
if "Host" not in headers:
sock.send(b"Host: %s\r\n" % bytes(host, "utf-8"))
if "User-Agent" not in headers:
sock.send(b"User-Agent: Adafruit CircuitPython\r\n")
# Iterate over keys to avoid tuple alloc
for k in headers:
sock.send(k.encode())
sock.send(b": ")
sock.send(headers[k].encode())
sock.send(b"\r\n")
if json is not None:
assert data is None
# pylint: disable=import-outside-toplevel
try:
import json as json_module
except ImportError:
import ujson as json_module
# pylint: enable=import-outside-toplevel
data = json_module.dumps(json)
sock.send(b"Content-Type: application/json\r\n")
if data:
if isinstance(data, dict):
sock.send(b"Content-Type: application/x-www-form-urlencoded\r\n")
_post_data = ""
for k in data:
_post_data = "{}&{}={}".format(_post_data, k, data[k])
data = _post_data[1:]
sock.send(b"Content-Length: %d\r\n" % len(data))
sock.send(b"\r\n")
if data:
if isinstance(data, bytearray):
sock.send(bytes(data))
else:
sock.send(bytes(data, "utf-8"))
line = sock.readline()
# print(line)
line = line.split(None, 2)
status = int(line[1])
reason = ""
if len(line) > 2:
reason = line[2].rstrip()
resp.headers = parse_headers(sock)
if resp.headers.get("transfer-encoding"):
if "chunked" in resp.headers.get("transfer-encoding"):
raise ValueError("Unsupported " + resp.headers.get("transfer-encoding"))
elif resp.headers.get("location") and not 200 <= status <= 299:
raise NotImplementedError("Redirects not yet supported")
except:
sock.close()
raise
resp.status_code = status
resp.reason = reason
return resp
def parse_headers(sock):
"""
Parses the header portion of an HTTP request/response from the socket.
Expects first line of HTTP request/response to have been read already
return: header dictionary
rtype: Dict
"""
headers = {}
while True:
line = sock.readline()
if not line or line == b"\r\n":
break
# print("**line: ", line)
splits = line.split(b": ", 1)
title = splits[0]
content = ""
if len(splits) > 1:
content = splits[1]
if title and content:
title = str(title.lower(), "utf-8")
content = str(content, "utf-8")
headers[title] = content
return headers
def head(url, **kw):
"""Send HTTP HEAD request"""
return request("HEAD", url, **kw)
def get(url, **kw):
"""Send HTTP GET request"""
return request("GET", url, **kw)
def post(url, **kw):
"""Send HTTP POST request"""
return request("POST", url, **kw)
def put(url, **kw):
"""Send HTTP PUT request"""
return request("PUT", url, **kw)
def patch(url, **kw):
"""Send HTTP PATCH request"""
return request("PATCH", url, **kw)
def delete(url, **kw):
"""Send HTTP DELETE request"""
return request("DELETE", url, **kw)

View File

@ -0,0 +1,47 @@
# FeatherS2 Helper Library
# 2020 Seon Rozenblum, Unexpected Maker
#
# Project home:
# https://feathers2.io
#
# Import required libraries
import time
import board
from digitalio import DigitalInOut, Direction, Pull
# Helper functions
def enable_LDO2(state):
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
# Grab a reference to the LDO2 IO (21 in this case)
ldo2 = DigitalInOut(board.LDO2)
ldo2.direction = Direction.OUTPUT
# Set the LDO2 power pin on / off
ldo2.value = state
# A small delay to let the IO change state
time.sleep(0.035)
# Dotstar rainbow colour wheel
def dotstar_color_wheel(wheel_pos):
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
wheel_pos = wheel_pos % 255
if wheel_pos < 85:
return 255 - wheel_pos * 3, 0, wheel_pos * 3
elif wheel_pos < 170:
wheel_pos -= 85
return 0, wheel_pos * 3, 255 - wheel_pos * 3
else:
wheel_pos -= 170
return wheel_pos * 3, 255 - wheel_pos * 3, 0
# Disable LDO2 by default
enable_LDO2(False)

View File

@ -35,6 +35,5 @@
#define AUTORESET_DELAY_MS 500
// Doesn't work with this on.
// #define MICROPY_HW_APA102_MOSI (&pin_GPIO44)
// #define MICROPY_HW_APA102_SCK (&pin_GPIO45)
#define MICROPY_HW_APA102_MOSI (&pin_GPIO40)
#define MICROPY_HW_APA102_SCK (&pin_GPIO45)

View File

@ -16,3 +16,7 @@ CIRCUITPY_ESP_FLASH_FREQ=40m
CIRCUITPY_ESP_FLASH_SIZE=16MB
CIRCUITPY_BITBANG_APA102 = 1
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar

View File

@ -1,55 +1,103 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO14) },
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO14) },
{ MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
// Moving to 9 and 8
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO38) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO33) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO44) }, // MTDO
{ MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_A10), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) },
{ MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO33) },
{ MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
{ MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO38) },
{ MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO11) },
// { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
// { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_AMB), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },

View File

@ -0,0 +1,198 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Damien P. George (original Neopixel object)
# Copyright (c) 2017 Ladyada
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
# Copyright (c) 2019 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
=================================================================================
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
"""
# pylint: disable=ungrouped-imports
import sys
import busio
import digitalio
if sys.implementation.version[0] < 5:
import adafruit_pypixelbuf as _pixelbuf
else:
try:
import _pixelbuf
except ImportError:
import adafruit_pypixelbuf as _pixelbuf
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
START_HEADER_SIZE = 4
# Pixel color order constants
RBG = "PRBG"
"""Red Blue Green"""
RGB = "PRGB"
"""Red Green Blue"""
GRB = "PGRB"
"""Green Red Blue"""
GBR = "PGBR"
"""Green Blue Red"""
BRG = "PBRG"
"""Blue Red Green"""
BGR = "PBGR"
"""Blue Green Red"""
class DotStar(_pixelbuf.PixelBuf):
"""
A sequence of dotstars.
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
:param ~microcontroller.Pin data: The pin to output dotstar data on.
:param int n: The number of dotstars in the chain
:param float brightness: Brightness of the pixels between 0.0 and 1.0
:param bool auto_write: True if the dotstars should immediately change when
set. If False, `show` must be called explicitly.
:param str pixel_order: Set the pixel order on the strip - different
strips implement this differently. If you send red, and it looks blue
or green on the strip, modify this! It should be one of the values above.
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
using 'soft' SPI). This is only a recommendation; the actual clock
rate may be slightly different depending on what the system hardware
can provide.
Example for Gemma M0:
.. code-block:: python
import adafruit_dotstar
import time
from board import *
RED = 0x100000
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
pixels[0] = RED
time.sleep(2)
.. py:method:: DotStar.show()
Shows the new colors on the dotstars themselves if they haven't already
been autowritten.
The colors may or may not be showing after this function returns because
it may be done asynchronously.
.. py:method:: DotStar.fill(color)
Colors all dotstars the given ***color***.
.. py:attribute:: brightness
Overall brightness of all dotstars (0 to 1.0)
"""
def __init__(
self,
clock,
data,
n,
*,
brightness=1.0,
auto_write=True,
pixel_order=BGR,
baudrate=4000000
):
self._spi = None
try:
self._spi = busio.SPI(clock, MOSI=data)
while not self._spi.try_lock():
pass
self._spi.configure(baudrate=baudrate)
except (NotImplementedError, ValueError):
self.dpin = digitalio.DigitalInOut(data)
self.cpin = digitalio.DigitalInOut(clock)
self.dpin.direction = digitalio.Direction.OUTPUT
self.cpin.direction = digitalio.Direction.OUTPUT
self.cpin.value = False
# Supply one extra clock cycle for each two pixels in the strip.
trailer_size = n // 16
if n % 16 != 0:
trailer_size += 1
# Four empty bytes for the header.
header = bytearray(START_HEADER_SIZE)
# 0xff bytes for the trailer.
trailer = bytearray(b"\xff") * trailer_size
super().__init__(
n,
byteorder=pixel_order,
brightness=brightness,
auto_write=auto_write,
header=header,
trailer=trailer,
)
def deinit(self):
"""Blank out the DotStars and release the resources."""
self.fill(0)
self.show()
if self._spi:
self._spi.deinit()
else:
self.dpin.deinit()
self.cpin.deinit()
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
self.deinit()
def __repr__(self):
return "[" + ", ".join([str(x) for x in self]) + "]"
@property
def n(self):
"""
The number of dotstars in the chain (read-only)
"""
return len(self)
def _transmit(self, buffer):
if self._spi:
self._spi.write(buffer)
else:
self._ds_writebytes(buffer)
def _ds_writebytes(self, buffer):
for b in buffer:
for _ in range(8):
self.dpin.value = b & 0x80
self.cpin.value = True
self.cpin.value = False
b = b << 1
self.cpin.value = False

View File

@ -0,0 +1,374 @@
# The MIT License (MIT)
#
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
# Copyright (c) 2019-2020 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
=================================================================
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
in neopixel.py and adafruit_dotstar.py.
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
"""
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
DOTSTAR_LED_BRIGHTNESS = 0b00011111
class PixelBuf: # pylint: disable=too-many-instance-attributes
"""
A sequence of RGB/RGBW pixels.
This is the pure python implementation of CircuitPython's _pixelbuf.
:param ~int n: Number of pixels
:param ~str byteorder: Byte order string constant (also sets bpp)
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
:param ~bool auto_write: Whether to automatically write pixels (Default False)
:param bytes header: Sequence of bytes to always send before pixel values.
:param bytes trailer: Sequence of bytes to always send after pixel values.
"""
def __init__( # pylint: disable=too-many-locals,too-many-arguments
self,
n,
byteorder="BGR",
brightness=1.0,
auto_write=False,
header=None,
trailer=None,
):
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
self.auto_write = False
effective_bpp = 4 if dotstar_mode else bpp
_bytes = effective_bpp * n
buf = bytearray(_bytes)
offset = 0
if header is not None:
if not isinstance(header, bytearray):
raise TypeError("header must be a bytearray")
buf = header + buf
offset = len(header)
if trailer is not None:
if not isinstance(trailer, bytearray):
raise TypeError("trailer must be a bytearray")
buf += trailer
self._pixels = n
self._bytes = _bytes
self._byteorder = byteorder_tuple
self._byteorder_string = byteorder
self._has_white = has_white
self._bpp = bpp
self._pre_brightness_buffer = None
self._post_brightness_buffer = buf
self._offset = offset
self._dotstar_mode = dotstar_mode
self._pixel_step = effective_bpp
if dotstar_mode:
self._byteorder_tuple = (
byteorder_tuple[0] + 1,
byteorder_tuple[1] + 1,
byteorder_tuple[2] + 1,
0,
)
# Initialize the buffer with the dotstar start bytes.
for i in range(self._offset, self._bytes + self._offset, 4):
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
self._brightness = 1.0
self.brightness = brightness
self.auto_write = auto_write
@staticmethod
def parse_byteorder(byteorder):
"""
Parse a Byteorder string for validity and determine bpp, byte order, and
dostar brightness bits.
Byteorder strings may contain the following characters:
R - Red
G - Green
B - Blue
W - White
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
:param: ~str bpp: bpp string.
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
"""
bpp = len(byteorder)
dotstar_mode = False
has_white = False
if byteorder.strip("RGBWP") != "":
raise ValueError("Invalid Byteorder string")
try:
r = byteorder.index("R")
g = byteorder.index("G")
b = byteorder.index("B")
except ValueError:
raise ValueError("Invalid Byteorder string")
if "W" in byteorder:
w = byteorder.index("W")
byteorder = (r, g, b, w)
has_white = True
elif "P" in byteorder:
lum = byteorder.index("P")
byteorder = (r, g, b, lum)
dotstar_mode = True
else:
byteorder = (r, g, b)
return bpp, byteorder, has_white, dotstar_mode
@property
def bpp(self):
"""
The number of bytes per pixel in the buffer (read-only).
"""
return self._bpp
@property
def brightness(self):
"""
Float value between 0 and 1. Output brightness.
When brightness is less than 1.0, a second buffer will be used to store the color values
before they are adjusted for brightness.
"""
return self._brightness
@brightness.setter
def brightness(self, value):
value = min(max(value, 0.0), 1.0)
change = value - self._brightness
if -0.001 < change < 0.001:
return
self._brightness = value
if self._pre_brightness_buffer is None:
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
# Adjust brightness of existing pixels
offset_check = self._offset % self._pixel_step
for i in range(self._offset, self._bytes + self._offset):
# Don't adjust per-pixel luminance bytes in dotstar mode
if self._dotstar_mode and (i % 4 != offset_check):
continue
self._post_brightness_buffer[i] = int(
self._pre_brightness_buffer[i] * self._brightness
)
if self.auto_write:
self.show()
@property
def byteorder(self):
"""
ByteOrder string for the buffer (read-only)
"""
return self._byteorder_string
def __len__(self):
"""
Number of pixels.
"""
return self._pixels
def show(self):
"""
Call the associated write function to display the pixels
"""
return self._transmit(self._post_brightness_buffer)
def fill(self, color):
"""
Fills the given pixelbuf with the given color.
:param pixelbuf: A pixel object.
:param color: Color to set.
"""
r, g, b, w = self._parse_color(color)
for i in range(self._pixels):
self._set_item(i, r, g, b, w)
if self.auto_write:
self.show()
def _parse_color(self, value):
r = 0
g = 0
b = 0
w = 0
if isinstance(value, int):
r = value >> 16
g = (value >> 8) & 0xFF
b = value & 0xFF
w = 0
if self._dotstar_mode:
w = 1.0
else:
if len(value) < 3 or len(value) > 4:
raise ValueError(
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
)
if len(value) == self._bpp:
if self._bpp == 3:
r, g, b = value
else:
r, g, b, w = value
elif len(value) == 3:
r, g, b = value
if self._dotstar_mode:
w = 1.0
if self._bpp == 4:
if self._dotstar_mode:
# LED startframe is three "1" bits, followed by 5 brightness bits
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
# vary based on hardware
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
elif (
self._has_white
and (isinstance(value, int) or len(value) == 3)
and r == g
and g == b
):
# If all components are the same and we have a white pixel then use it
# instead of the individual components when all 4 values aren't explicitly given.
w = r
r = 0
g = 0
b = 0
return (r, g, b, w)
def _set_item(
self, index, r, g, b, w
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
offset = self._offset + (index * self._bpp)
if self._pre_brightness_buffer is not None:
if self._bpp == 4:
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
if self._bpp == 4:
# Only apply brightness if w is actually white (aka not DotStar.)
if not self._dotstar_mode:
w = int(w * self._brightness)
self._post_brightness_buffer[offset + self._byteorder[3]] = w
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
r * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
g * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
b * self._brightness
)
def __setitem__(self, index, val):
if isinstance(index, slice):
start, stop, step = index.indices(self._pixels)
for val_i, in_i in enumerate(range(start, stop, step)):
r, g, b, w = self._parse_color(val[val_i])
self._set_item(in_i, r, g, b, w)
else:
r, g, b, w = self._parse_color(val)
self._set_item(index, r, g, b, w)
if self.auto_write:
self.show()
def _getitem(self, index):
start = self._offset + (index * self._bpp)
buffer = (
self._pre_brightness_buffer
if self._pre_brightness_buffer is not None
else self._post_brightness_buffer
)
value = [
buffer[start + self._byteorder[0]],
buffer[start + self._byteorder[1]],
buffer[start + self._byteorder[2]],
]
if self._has_white:
value.append(buffer[start + self._byteorder[3]])
elif self._dotstar_mode:
value.append(
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
)
return value
def __getitem__(self, index):
if isinstance(index, slice):
out = []
for in_i in range(
*index.indices(len(self._post_brightness_buffer) // self._bpp)
):
out.append(self._getitem(in_i))
return out
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
return self._getitem(index)
def _transmit(self, buffer):
raise NotImplementedError("Must be subclassed")
def wheel(pos):
"""
Helper to create a colorwheel.
:param pos: int 0-255 of color value to return
:return: tuple of RGB values
"""
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return 0, 0, 0
if pos < 85:
return 255 - pos * 3, pos * 3, 0
if pos < 170:
pos -= 85
return 0, 255 - pos * 3, pos * 3
pos -= 170
return pos * 3, 0, 255 - pos * 3

View File

@ -0,0 +1,56 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "boards/board.h"
#include "mpconfigboard.h"
#include "shared-bindings/microcontroller/Pin.h"
void board_init(void) {
// USB
common_hal_never_reset_pin(&pin_GPIO19);
common_hal_never_reset_pin(&pin_GPIO20);
// Debug UART
common_hal_never_reset_pin(&pin_GPIO43);
common_hal_never_reset_pin(&pin_GPIO44);
// SPI Flash and RAM
common_hal_never_reset_pin(&pin_GPIO26);
common_hal_never_reset_pin(&pin_GPIO27);
common_hal_never_reset_pin(&pin_GPIO28);
common_hal_never_reset_pin(&pin_GPIO29);
common_hal_never_reset_pin(&pin_GPIO30);
common_hal_never_reset_pin(&pin_GPIO31);
common_hal_never_reset_pin(&pin_GPIO32);
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}

View File

@ -0,0 +1,47 @@
# FeatherS2 Helper Library
# 2020 Seon Rozenblum, Unexpected Maker
#
# Project home:
# https://feathers2.io
#
# Import required libraries
import time
import board
from digitalio import DigitalInOut, Direction, Pull
# Helper functions
def enable_LDO2(state):
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
# Grab a reference to the LDO2 IO (21 in this case)
ldo2 = DigitalInOut(board.LDO2)
ldo2.direction = Direction.OUTPUT
# Set the LDO2 power pin on / off
ldo2.value = state
# A small delay to let the IO change state
time.sleep(0.035)
# Dotstar rainbow colour wheel
def dotstar_color_wheel(wheel_pos):
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
wheel_pos = wheel_pos % 255
if wheel_pos < 85:
return 255 - wheel_pos * 3, 0, wheel_pos * 3
elif wheel_pos < 170:
wheel_pos -= 85
return 0, wheel_pos * 3, 255 - wheel_pos * 3
else:
wheel_pos -= 170
return wheel_pos * 3, 255 - wheel_pos * 3, 0
# Disable LDO2 by default
enable_LDO2(False)

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
//Micropython setup
#define MICROPY_HW_BOARD_NAME "FeatherS2"
#define MICROPY_HW_MCU_NAME "ESP32S2"
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
#define BOARD_USER_SAFE_MODE_ACTION "pressing boot button at start up.\n"
#define AUTORESET_DELAY_MS 500
// Doesn't work with this on.
// #define MICROPY_HW_APA102_MOSI (&pin_GPIO44)
// #define MICROPY_HW_APA102_SCK (&pin_GPIO45)

View File

@ -0,0 +1,21 @@
USB_VID = 0x239A
USB_PID = 0x80AC
USB_PRODUCT = "FeatherS2"
USB_MANUFACTURER = "UnexpectedMaker"
USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
# The default queue depth of 16 overflows on release builds,
# so increase it to 32.
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
CIRCUITPY_ESP_FLASH_MODE=qio
CIRCUITPY_ESP_FLASH_FREQ=40m
CIRCUITPY_ESP_FLASH_SIZE=16MB
CIRCUITPY_BITBANG_APA102 = 1
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar

View File

@ -0,0 +1,56 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
// Moving to 9 and 8
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO38) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO33) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_AMB), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

View File

@ -0,0 +1,35 @@
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
# CONFIG_SPIRAM_TYPE_AUTO is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
CONFIG_SPIRAM_SIZE=8388608
#
# PSRAM clock and cs IO for ESP32S2
#
CONFIG_DEFAULT_PSRAM_CLK_IO=30
CONFIG_DEFAULT_PSRAM_CS_IO=26
# end of PSRAM clock and cs IO for ESP32S2
CONFIG_SPIRAM_SPIWP_SD3_PIN=28
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
# CONFIG_SPIRAM_USE_AHB_DBUS3 is not set
# CONFIG_SPIRAM_SPEED_80M is not set
CONFIG_SPIRAM_SPEED_40M=y
# CONFIG_SPIRAM_SPEED_26M is not set
# CONFIG_SPIRAM_SPEED_20M is not set
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
CONFIG_SPIRAM_USE_MEMMAP=y
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
# CONFIG_SPIRAM_USE_MALLOC is not set
CONFIG_SPIRAM_MEMTEST=y
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config

View File

@ -0,0 +1,198 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Damien P. George (original Neopixel object)
# Copyright (c) 2017 Ladyada
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
# Copyright (c) 2019 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
=================================================================================
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
"""
# pylint: disable=ungrouped-imports
import sys
import busio
import digitalio
if sys.implementation.version[0] < 5:
import adafruit_pypixelbuf as _pixelbuf
else:
try:
import _pixelbuf
except ImportError:
import adafruit_pypixelbuf as _pixelbuf
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
START_HEADER_SIZE = 4
# Pixel color order constants
RBG = "PRBG"
"""Red Blue Green"""
RGB = "PRGB"
"""Red Green Blue"""
GRB = "PGRB"
"""Green Red Blue"""
GBR = "PGBR"
"""Green Blue Red"""
BRG = "PBRG"
"""Blue Red Green"""
BGR = "PBGR"
"""Blue Green Red"""
class DotStar(_pixelbuf.PixelBuf):
"""
A sequence of dotstars.
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
:param ~microcontroller.Pin data: The pin to output dotstar data on.
:param int n: The number of dotstars in the chain
:param float brightness: Brightness of the pixels between 0.0 and 1.0
:param bool auto_write: True if the dotstars should immediately change when
set. If False, `show` must be called explicitly.
:param str pixel_order: Set the pixel order on the strip - different
strips implement this differently. If you send red, and it looks blue
or green on the strip, modify this! It should be one of the values above.
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
using 'soft' SPI). This is only a recommendation; the actual clock
rate may be slightly different depending on what the system hardware
can provide.
Example for Gemma M0:
.. code-block:: python
import adafruit_dotstar
import time
from board import *
RED = 0x100000
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
pixels[0] = RED
time.sleep(2)
.. py:method:: DotStar.show()
Shows the new colors on the dotstars themselves if they haven't already
been autowritten.
The colors may or may not be showing after this function returns because
it may be done asynchronously.
.. py:method:: DotStar.fill(color)
Colors all dotstars the given ***color***.
.. py:attribute:: brightness
Overall brightness of all dotstars (0 to 1.0)
"""
def __init__(
self,
clock,
data,
n,
*,
brightness=1.0,
auto_write=True,
pixel_order=BGR,
baudrate=4000000
):
self._spi = None
try:
self._spi = busio.SPI(clock, MOSI=data)
while not self._spi.try_lock():
pass
self._spi.configure(baudrate=baudrate)
except (NotImplementedError, ValueError):
self.dpin = digitalio.DigitalInOut(data)
self.cpin = digitalio.DigitalInOut(clock)
self.dpin.direction = digitalio.Direction.OUTPUT
self.cpin.direction = digitalio.Direction.OUTPUT
self.cpin.value = False
# Supply one extra clock cycle for each two pixels in the strip.
trailer_size = n // 16
if n % 16 != 0:
trailer_size += 1
# Four empty bytes for the header.
header = bytearray(START_HEADER_SIZE)
# 0xff bytes for the trailer.
trailer = bytearray(b"\xff") * trailer_size
super().__init__(
n,
byteorder=pixel_order,
brightness=brightness,
auto_write=auto_write,
header=header,
trailer=trailer,
)
def deinit(self):
"""Blank out the DotStars and release the resources."""
self.fill(0)
self.show()
if self._spi:
self._spi.deinit()
else:
self.dpin.deinit()
self.cpin.deinit()
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
self.deinit()
def __repr__(self):
return "[" + ", ".join([str(x) for x in self]) + "]"
@property
def n(self):
"""
The number of dotstars in the chain (read-only)
"""
return len(self)
def _transmit(self, buffer):
if self._spi:
self._spi.write(buffer)
else:
self._ds_writebytes(buffer)
def _ds_writebytes(self, buffer):
for b in buffer:
for _ in range(8):
self.dpin.value = b & 0x80
self.cpin.value = True
self.cpin.value = False
b = b << 1
self.cpin.value = False

View File

@ -0,0 +1,374 @@
# The MIT License (MIT)
#
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
# Copyright (c) 2019-2020 Roy Hooper
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
=================================================================
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
in neopixel.py and adafruit_dotstar.py.
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
"""
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
DOTSTAR_LED_BRIGHTNESS = 0b00011111
class PixelBuf: # pylint: disable=too-many-instance-attributes
"""
A sequence of RGB/RGBW pixels.
This is the pure python implementation of CircuitPython's _pixelbuf.
:param ~int n: Number of pixels
:param ~str byteorder: Byte order string constant (also sets bpp)
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
:param ~bool auto_write: Whether to automatically write pixels (Default False)
:param bytes header: Sequence of bytes to always send before pixel values.
:param bytes trailer: Sequence of bytes to always send after pixel values.
"""
def __init__( # pylint: disable=too-many-locals,too-many-arguments
self,
n,
byteorder="BGR",
brightness=1.0,
auto_write=False,
header=None,
trailer=None,
):
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
self.auto_write = False
effective_bpp = 4 if dotstar_mode else bpp
_bytes = effective_bpp * n
buf = bytearray(_bytes)
offset = 0
if header is not None:
if not isinstance(header, bytearray):
raise TypeError("header must be a bytearray")
buf = header + buf
offset = len(header)
if trailer is not None:
if not isinstance(trailer, bytearray):
raise TypeError("trailer must be a bytearray")
buf += trailer
self._pixels = n
self._bytes = _bytes
self._byteorder = byteorder_tuple
self._byteorder_string = byteorder
self._has_white = has_white
self._bpp = bpp
self._pre_brightness_buffer = None
self._post_brightness_buffer = buf
self._offset = offset
self._dotstar_mode = dotstar_mode
self._pixel_step = effective_bpp
if dotstar_mode:
self._byteorder_tuple = (
byteorder_tuple[0] + 1,
byteorder_tuple[1] + 1,
byteorder_tuple[2] + 1,
0,
)
# Initialize the buffer with the dotstar start bytes.
for i in range(self._offset, self._bytes + self._offset, 4):
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
self._brightness = 1.0
self.brightness = brightness
self.auto_write = auto_write
@staticmethod
def parse_byteorder(byteorder):
"""
Parse a Byteorder string for validity and determine bpp, byte order, and
dostar brightness bits.
Byteorder strings may contain the following characters:
R - Red
G - Green
B - Blue
W - White
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
:param: ~str bpp: bpp string.
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
"""
bpp = len(byteorder)
dotstar_mode = False
has_white = False
if byteorder.strip("RGBWP") != "":
raise ValueError("Invalid Byteorder string")
try:
r = byteorder.index("R")
g = byteorder.index("G")
b = byteorder.index("B")
except ValueError:
raise ValueError("Invalid Byteorder string")
if "W" in byteorder:
w = byteorder.index("W")
byteorder = (r, g, b, w)
has_white = True
elif "P" in byteorder:
lum = byteorder.index("P")
byteorder = (r, g, b, lum)
dotstar_mode = True
else:
byteorder = (r, g, b)
return bpp, byteorder, has_white, dotstar_mode
@property
def bpp(self):
"""
The number of bytes per pixel in the buffer (read-only).
"""
return self._bpp
@property
def brightness(self):
"""
Float value between 0 and 1. Output brightness.
When brightness is less than 1.0, a second buffer will be used to store the color values
before they are adjusted for brightness.
"""
return self._brightness
@brightness.setter
def brightness(self, value):
value = min(max(value, 0.0), 1.0)
change = value - self._brightness
if -0.001 < change < 0.001:
return
self._brightness = value
if self._pre_brightness_buffer is None:
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
# Adjust brightness of existing pixels
offset_check = self._offset % self._pixel_step
for i in range(self._offset, self._bytes + self._offset):
# Don't adjust per-pixel luminance bytes in dotstar mode
if self._dotstar_mode and (i % 4 != offset_check):
continue
self._post_brightness_buffer[i] = int(
self._pre_brightness_buffer[i] * self._brightness
)
if self.auto_write:
self.show()
@property
def byteorder(self):
"""
ByteOrder string for the buffer (read-only)
"""
return self._byteorder_string
def __len__(self):
"""
Number of pixels.
"""
return self._pixels
def show(self):
"""
Call the associated write function to display the pixels
"""
return self._transmit(self._post_brightness_buffer)
def fill(self, color):
"""
Fills the given pixelbuf with the given color.
:param pixelbuf: A pixel object.
:param color: Color to set.
"""
r, g, b, w = self._parse_color(color)
for i in range(self._pixels):
self._set_item(i, r, g, b, w)
if self.auto_write:
self.show()
def _parse_color(self, value):
r = 0
g = 0
b = 0
w = 0
if isinstance(value, int):
r = value >> 16
g = (value >> 8) & 0xFF
b = value & 0xFF
w = 0
if self._dotstar_mode:
w = 1.0
else:
if len(value) < 3 or len(value) > 4:
raise ValueError(
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
)
if len(value) == self._bpp:
if self._bpp == 3:
r, g, b = value
else:
r, g, b, w = value
elif len(value) == 3:
r, g, b = value
if self._dotstar_mode:
w = 1.0
if self._bpp == 4:
if self._dotstar_mode:
# LED startframe is three "1" bits, followed by 5 brightness bits
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
# vary based on hardware
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
elif (
self._has_white
and (isinstance(value, int) or len(value) == 3)
and r == g
and g == b
):
# If all components are the same and we have a white pixel then use it
# instead of the individual components when all 4 values aren't explicitly given.
w = r
r = 0
g = 0
b = 0
return (r, g, b, w)
def _set_item(
self, index, r, g, b, w
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
offset = self._offset + (index * self._bpp)
if self._pre_brightness_buffer is not None:
if self._bpp == 4:
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
if self._bpp == 4:
# Only apply brightness if w is actually white (aka not DotStar.)
if not self._dotstar_mode:
w = int(w * self._brightness)
self._post_brightness_buffer[offset + self._byteorder[3]] = w
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
r * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
g * self._brightness
)
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
b * self._brightness
)
def __setitem__(self, index, val):
if isinstance(index, slice):
start, stop, step = index.indices(self._pixels)
for val_i, in_i in enumerate(range(start, stop, step)):
r, g, b, w = self._parse_color(val[val_i])
self._set_item(in_i, r, g, b, w)
else:
r, g, b, w = self._parse_color(val)
self._set_item(index, r, g, b, w)
if self.auto_write:
self.show()
def _getitem(self, index):
start = self._offset + (index * self._bpp)
buffer = (
self._pre_brightness_buffer
if self._pre_brightness_buffer is not None
else self._post_brightness_buffer
)
value = [
buffer[start + self._byteorder[0]],
buffer[start + self._byteorder[1]],
buffer[start + self._byteorder[2]],
]
if self._has_white:
value.append(buffer[start + self._byteorder[3]])
elif self._dotstar_mode:
value.append(
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
)
return value
def __getitem__(self, index):
if isinstance(index, slice):
out = []
for in_i in range(
*index.indices(len(self._post_brightness_buffer) // self._bpp)
):
out.append(self._getitem(in_i))
return out
if index < 0:
index += len(self)
if index >= self._pixels or index < 0:
raise IndexError
return self._getitem(index)
def _transmit(self, buffer):
raise NotImplementedError("Must be subclassed")
def wheel(pos):
"""
Helper to create a colorwheel.
:param pos: int 0-255 of color value to return
:return: tuple of RGB values
"""
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return 0, 0, 0
if pos < 85:
return 255 - pos * 3, pos * 3, 0
if pos < 170:
pos -= 85
return 0, 255 - pos * 3, pos * 3
pos -= 170
return pos * 3, 0, 255 - pos * 3

View File

@ -0,0 +1,56 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "boards/board.h"
#include "mpconfigboard.h"
#include "shared-bindings/microcontroller/Pin.h"
void board_init(void) {
// USB
common_hal_never_reset_pin(&pin_GPIO19);
common_hal_never_reset_pin(&pin_GPIO20);
// Debug UART
common_hal_never_reset_pin(&pin_GPIO43);
common_hal_never_reset_pin(&pin_GPIO44);
// SPI Flash and RAM
common_hal_never_reset_pin(&pin_GPIO26);
common_hal_never_reset_pin(&pin_GPIO27);
common_hal_never_reset_pin(&pin_GPIO28);
common_hal_never_reset_pin(&pin_GPIO29);
common_hal_never_reset_pin(&pin_GPIO30);
common_hal_never_reset_pin(&pin_GPIO31);
common_hal_never_reset_pin(&pin_GPIO32);
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
//Micropython setup
#define MICROPY_HW_BOARD_NAME "ProS2"
#define MICROPY_HW_MCU_NAME "ESP32S2"
#define AUTORESET_DELAY_MS 500
#define MICROPY_HW_APA102_MOSI (&pin_GPIO40)
#define MICROPY_HW_APA102_SCK (&pin_GPIO45)

View File

@ -0,0 +1,21 @@
USB_VID = 0x239A
USB_PID = 0x80AA
USB_PRODUCT = "ProS2"
USB_MANUFACTURER = "UnexpectedMaker"
USB_DEVICES = "CDC,MSC,HID"
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
# The default queue depth of 16 overflows on release builds,
# so increase it to 32.
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
CIRCUITPY_ESP_FLASH_MODE=qio
CIRCUITPY_ESP_FLASH_FREQ=40m
CIRCUITPY_ESP_FLASH_SIZE=16MB
CIRCUITPY_BITBANG_APA102 = 1
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar

View File

@ -0,0 +1,58 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO14) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

View File

@ -0,0 +1,63 @@
# Pros2 Helper Library
# 2020 Seon Rozenblum, Unexpected Maker
#
# Project home:
# https://pros2.io
#
# Import required libraries
import time
import board
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn
# Helper functions
def enable_LDO2(state):
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
# Grab a reference to the LDO2 IO (21 in this case)
ldo2 = DigitalInOut(board.LDO2)
ldo2.direction = Direction.OUTPUT
# Set the LDO2 power pin on / off
ldo2.value = state
# A small delay to let the IO change state
time.sleep(0.035)
# Dotstar rainbow colour wheel
def dotstar_color_wheel(wheel_pos):
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
wheel_pos = wheel_pos % 255
if wheel_pos < 85:
return 255 - wheel_pos * 3, 0, wheel_pos * 3
elif wheel_pos < 170:
wheel_pos -= 85
return 0, wheel_pos * 3, 255 - wheel_pos * 3
else:
wheel_pos -= 170
return wheel_pos * 3, 255 - wheel_pos * 3, 0
# Get a *rough* estimate of the current battery voltage
# If the battery is not present, the charge IC will still report it's trying to charge at X voltage
# so it will still show a voltage.
def get_battery_voltage():
"""
Returns the current battery voltage. If no battery is connected, returns 3.7V
This is an approximation only, but useful to detect of the charge state of the battery is getting low.
"""
adc = AnalogIn(board.VBAT_SENSE)
measured_vbat = adc.value # Read the value
measured_vbat /= 4095 # divide by 4095 as we are using the default ADC voltage range of 0-1V
measured_vbat *= 3.7 # Multiply by 3.7V, our reference voltage
return measured_vbat
# Disable LDO2 by default
enable_LDO2(False)

View File

@ -0,0 +1,35 @@
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
# CONFIG_SPIRAM_TYPE_AUTO is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
CONFIG_SPIRAM_SIZE=8388608
#
# PSRAM clock and cs IO for ESP32S2
#
CONFIG_DEFAULT_PSRAM_CLK_IO=30
CONFIG_DEFAULT_PSRAM_CS_IO=26
# end of PSRAM clock and cs IO for ESP32S2
CONFIG_SPIRAM_SPIWP_SD3_PIN=28
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
# CONFIG_SPIRAM_USE_AHB_DBUS3 is not set
# CONFIG_SPIRAM_SPEED_80M is not set
CONFIG_SPIRAM_SPEED_40M=y
# CONFIG_SPIRAM_SPEED_26M is not set
# CONFIG_SPIRAM_SPEED_20M is not set
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
CONFIG_SPIRAM_USE_MEMMAP=y
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
# CONFIG_SPIRAM_USE_MALLOC is not set
CONFIG_SPIRAM_MEMTEST=y
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config