Basic support for driving a display with rpi_ws281x
NOTE: weatherscene.py is known to NOT work under Python 3.x due to
an incompatibility with MicroPython's handling of strings and bytes.
This can be easily resolved although I opted to not do this, to preserve
compabilitity with the original code.
To use this on a Raspberry Pi, try:
sudo apt install -y python-pip python-requests
sudo pip install rpi_ws281x
Then connect the display's data line to the Raspberry Pi's GPIO 18 (PCM CLK)
(see https://pinout.xyz/)
References:
- https://github.com/noahwilliamsson/lamatrix/issues/1
- https://github.com/rpi-ws281x/rpi-ws281x-python (userspace WS281x driver)
- https://github.com/jgarff/rpi_ws281x (wiring docs)
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
This is a project to drive a 32x8 or 16x16 LED matrix based on the popular WS2812 RGB LEDs using a microcontroller running [MicroPython](https://micropython.org). There is experimental support for allowing a more powerful host computer (e.g. a Raspberry Pi Zero W) to remotely control a microcontroller without WiFi (e.g. a Teensy 3.x) and the display connected to it over USB serial. Low FPS video of a standalone Pycom LoPy 1 development board cycling through the scenes:
|
This is a project to drive a 32x8 or 16x16 LED matrix based on the popular WS2812 RGB LEDs using a microcontroller running [MicroPython](https://micropython.org). There is experimental support for allowing a more powerful host computer (e.g. a Raspberry Pi Zero W) to remotely control a microcontroller without WiFi (e.g. a Teensy 3.x) and the display connected to it over USB serial. Low FPS video of a standalone Pycom LoPy 1 development board cycling through the scenes:
|
||||||
|
|
||||||

|
TODO: implement
|
||||||
|
|
||||||
Static picture with clock scene. For some reason the colors aren't captured as vidvid as they are in real life.
|
Static picture with clock scene. For some reason the colors aren't captured as vidvid as they are in real life.
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ Features:
|
|||||||
|
|
||||||
Primary development has been made on [Pycom](https://www.pycom.io)'s development boards, including the (obsolete) LoPy 1 and the newer WiPy 3. There is also an Arduino [sketch](ArduinoSer2FastLED/ArduinoSer2FastLED.ino) for Teensy 3.1/3.2 boards that implements a custom serial protocol that is spoken by the host software ([main.py](main.py) and [arduinoserialhal.py](arduinoserialhal.py)) that allows the LED matrix to be remotely controlled.
|
Primary development has been made on [Pycom](https://www.pycom.io)'s development boards, including the (obsolete) LoPy 1 and the newer WiPy 3. There is also an Arduino [sketch](ArduinoSer2FastLED/ArduinoSer2FastLED.ino) for Teensy 3.1/3.2 boards that implements a custom serial protocol that is spoken by the host software ([main.py](main.py) and [arduinoserialhal.py](arduinoserialhal.py)) that allows the LED matrix to be remotely controlled.
|
||||||
|
|
||||||
|
**Update 2021**: If you want to use this with a Raspberry Pi instead of an MCU running MicroPython, see the issue [Using Raspberry PI directly to 8 x 32 not working?](https://github.com/noahwilliamsson/lamatrix/issues/1).
|
||||||
|
|
||||||
## Building and deploying the MCU
|
## Building and deploying the MCU
|
||||||
|
|
||||||
|
|||||||
12
main.py
12
main.py
@@ -36,12 +36,18 @@ if hasattr(sys,'implementation') and sys.implementation.name == 'micropython':
|
|||||||
tmp = None
|
tmp = None
|
||||||
del uname
|
del uname
|
||||||
else:
|
else:
|
||||||
# Emulate https://docs.pycom.io/firmwareapi/micropython/utime.html
|
|
||||||
time.ticks_ms = lambda: int(time.time() * 1000)
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
from arduinoserialhal import ArduinoSerialHAL as HAL
|
# Kludge to allow this project to be used with a Raspberry Pi instead of
|
||||||
|
# an MCU: see https://github.com/noahwilliamsson/lamatrix/issues/1
|
||||||
|
try:
|
||||||
|
# If the rpi_ws281x Python module is available, then use that...
|
||||||
|
from raspberrypihal import RaspberryPiHAL as HAL
|
||||||
|
except:
|
||||||
|
# ...else assume that there's an MCU (driving the display) connected
|
||||||
|
# to a serial port
|
||||||
|
from arduinoserialhal import ArduinoSerialHAL as HAL
|
||||||
|
|
||||||
gc.collect()
|
gc.collect()
|
||||||
from renderloop import RenderLoop
|
from renderloop import RenderLoop
|
||||||
|
|||||||
58
raspberrypihal.py
Normal file
58
raspberrypihal.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# HAL for Raspberry Pi with https://github.com/rpi-ws281x/rpi-ws281x-python
|
||||||
|
# See https://github.com/jgarff/rpi_ws281x for more details on this library.
|
||||||
|
#
|
||||||
|
# The below code assumes the LED strip is connected to GPIO 18 (PCM CLK)
|
||||||
|
# (see https://pinout.xyz) and that you've installed the rpi_ws281x library.
|
||||||
|
#
|
||||||
|
# For Python 2.x:
|
||||||
|
#
|
||||||
|
# sudo apt install -y python-pip; sudo pip install rpi_ws281x
|
||||||
|
#
|
||||||
|
# For Python 3.x:
|
||||||
|
#
|
||||||
|
# sudo apt install -y python3-pip; sudo pip3 install rpi_ws281x
|
||||||
|
#
|
||||||
|
#
|
||||||
|
from rpi_ws281x import PixelStrip, Color
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
|
||||||
|
# LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
|
||||||
|
|
||||||
|
class RaspberryPiHAL:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.num_pixels = config['LedMatrix']['columns'] * config['LedMatrix']['stride']
|
||||||
|
self.strip = PixelStrip(self.num_pixels, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
|
||||||
|
self.strip.begin()
|
||||||
|
def init_display(self, num_pixels=64):
|
||||||
|
self.clear_display()
|
||||||
|
def clear_display(self):
|
||||||
|
c = Color(0, 0, 0)
|
||||||
|
for i in range(self.num_pixels):
|
||||||
|
self.strip.setPixelColor(i, c)
|
||||||
|
self.strip.show()
|
||||||
|
def update_display(self, num_modified_pixels):
|
||||||
|
if not num_modified_pixels:
|
||||||
|
return
|
||||||
|
self.strip.show()
|
||||||
|
def put_pixel(self, addr, r, g, b):
|
||||||
|
self.strip.setPixelColor(addr % self.num_pixels, Color(r, g, b))
|
||||||
|
def reset(self):
|
||||||
|
self.clear_display()
|
||||||
|
def process_input(self):
|
||||||
|
#TODO: implement
|
||||||
|
return 0
|
||||||
|
def set_rtc(self, t):
|
||||||
|
#Not relevant
|
||||||
|
pass
|
||||||
|
def set_auto_time(self, enable=True):
|
||||||
|
#Not relevant
|
||||||
|
pass
|
||||||
|
def suspend_host(self, restart_timeout_seconds):
|
||||||
|
#Not relevant
|
||||||
|
pass
|
||||||
Reference in New Issue
Block a user