Skip to content

Instantly share code, notes, and snippets.

@idriszmy
Created December 6, 2021 03:16
Display text on dot matrix (MAX7219) using Maker Pi Pico and CircuitPython.
"""
Display text on dot matrix (MAX7219) using Maker Pi Pico and CircuitPython
Items:
- Maker Pi Pico
https://my.cytron.io/p-maker-pi-pico
- ESP8266 ESP-01 WiFi Serial Transceiver Module
https://my.cytron.io/p-esp-01-wifi-serial-transceiver-module-esp8266
- 4 In 1 MAX7219 Dot Matrix Display Module
https://my.cytron.io/p-4-in-1-max7219-dot-matrix-display-module
- USB Micro B Cable
https://my.cytron.io/p-usb-micro-b-cable
Libraries required from bundle (https://circuitpython.org/libraries):
- adafruit_espatcontrol
- adafruit_max7219
- adafruit_framebuf.mpy
- adafruit_requests.mpy
References:
- https://github.com/robertgallup/circuitpython-multimatrix
- https://learn.adafruit.com/quickstart-rp2040-pico-with-wifi-and-circuitpython/internet-connect
- https://github.com/CytronTechnologies/MAKER-PI-PICO/tree/main/Example%20Code/CircuitPython/IoT
Last update: 6 Dec 2021
"""
import time
import busio
import digitalio
from board import *
from multimatrix import MultiMatrix
import adafruit_requests as requests
import adafruit_espatcontrol.adafruit_espatcontrol_socket as socket
from adafruit_espatcontrol import adafruit_espatcontrol
import json
# Get wifi details and more from a secrets.py file
try:
from secrets import secrets
except ImportError:
print("All secret keys are kept in secrets.py, please add them there!")
raise
URL = "http://api.coindesk.com/v1/bpi/currentprice/USD.json"
led = digitalio.DigitalInOut(LED)
led.direction = digitalio.Direction.OUTPUT
# Initialize UART connection to the ESP8266 WiFi Module.
RX = GP17
TX = GP16
uart = busio.UART(TX, RX, receiver_buffer_size=2048) # Use large buffer as we're not using hardware flow control.
esp = adafruit_espatcontrol.ESP_ATcontrol(uart, 115200, debug=False)
requests.set_socket(socket, esp)
print("Resetting ESP module")
esp.soft_reset()
WIDTH = const(32)
HEIGHT = const(8)
mosi = GP7
clk = GP6
cs = digitalio.DigitalInOut(GP5)
spi = busio.SPI(clk, MOSI=mosi)
display = MultiMatrix (spi, cs, WIDTH, HEIGHT, orientation=1)
def scroll_text(s):
# scroll a string across the display
for pixel_position in range(WIDTH, -(8*6)-1, -1):
display.fill(0)
display.text(s, pixel_position, 0)
display.show()
time.sleep(0.05)
def clear_display():
display.fill(0)
display.show()
clear_display()
while True:
try:
# Make sure WiFi is connected.
while not esp.is_connected:
print("Connecting...")
esp.connect(secrets)
led.value = True
response = requests.get(URL)
print(response.json())
btc_float = response.json()['bpi']['USD']['rate_float']
btc_int = int(btc_float)
print("\nBTC rate: {}\n".format(btc_int))
clear_display()
time.sleep(1)
scroll_text("BTC/USD:{}".format(btc_int))
led.value = False
time.sleep(60)
except (ValueError, RuntimeError, adafruit_espatcontrol.OKError) as e:
print("Failed, retrying\n", e)
from adafruit_max7219 import max7219
import math
class MultiMatrix(max7219.MAX7219):
"""
Driver for LED matrices based on the MAX7219 chip.
Supports multi-matrix displays.
Automatically calculates number of 8x8 modules based on grid size
:param object spi: an spi busio or spi bitbangio object
:param ~digitalio.DigitalInOut cs: digital in/out to use as chip select signal
:param int width: pixel width of grid (default=8)
:param int height: pixel height of grid (default=8)
"""
# Register definitions
_DECODEMODE = const(0b1001) # 9
_SCANLIMIT = const(0b1011) # 11
_SHUTDOWN = const(0b1100) # 12
_DISPLAYTEST = const(0b1111) # 15
_DIGIT0 = const(0b0001) # 1
_INTENSITY = const(0b1010) # 10
def __init__(self, spi, cs, width=8, height=8, orientation=0):
# Number of 8x8 LED displays required is calculated as width/8 * height/8
# ceil() is used to round both up to next whole matrix
self._num_displays = math.ceil(width/8) * math.ceil(height/8)
# Display matrix orientation
self._orienation = orientation
super().__init__(width, height, spi, cs)
def init_display(self):
"""
Initializes displays
"""
# Initialize important registers
for cmd, data in (
(_SHUTDOWN, 0),
(_DISPLAYTEST, 0),
(_SCANLIMIT, 7),
(_DECODEMODE, 0),
(_SHUTDOWN, 1),
):
self.write_cmd(cmd, [data] * self._num_displays)
def brightness(self, value):
"""
Sets the brightness of all displays.
:param int value: 0->15 dimmest to brightest
"""
self.write_cmd(_INTENSITY, [value&0xFF] * self._num_displays)
def write_cmd(self, cmd, values):
"""
Writes a list of values using the same register command
before each value
:param int cmd: a single command (e.g. register number)
:param list values: a list of values.
"""
# Command list of alternating cmd and value pairs
# cmd_list = [[cmd, v] for v in values]
cmd_list = []
for v in values: cmd_list += [cmd, v]
# Set CS low and write the command list to the devices
self._chip_select.value = 0
with self._spi_device as spi:
spi.write(bytearray(cmd_list))
def text(self, strg, xpos, ypos, color=1):
"""
Write text into frame buffer for LED matrix
:param int xpos: x position
:param int ypos: y position
:param string strg: string to place in buffr
:param color: Odd number sets the text, clears otherwise
"""
self.framebuf.text(strg, xpos, ypos, color & 0x01)
def clear_all(self, color=0):
"""
Clears display. Default is clear to 0.
:param int color: even is clear to LED off, odd is LED on
"""
self.fill(color & 0X01)
def show(self):
"""
Updates all displays from the frame buffer
"""
# Each matrix takes 8 bytes (one per row). So, the same rows on
# different matrices are 8 bytes apart in the frame buffer. But,
# the rows must be output in reverse matrix order, i.e. data for
# the last matrix in the chain is output first (just like a shift
# register), then the next closest one, and so on.
v = 0
values = bytearray(self._num_displays)
for y in range(8):
if self._orienation == 1:
d = self._num_displays
for display in range(self._num_displays):
d -= 1
for x in range(8):
v = (v >> 1) | ((self._buffer[(d * 8) + x] << y) & 0b10000000)
values[display] = v
else:
d = self._num_displays
for display in range(self._num_displays):
d -= 1
values[display] = self._buffer[y + (d * 8)]
self.write_cmd(_DIGIT0 + y, values)
# Secret Keys.
secrets = {
"ssid" : "my_wifi_ssid",
"password" : "my_wifi_password",
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment