Internet stock ticker (64×8 matrix)
A finance ticker on the big 8-in-1 MAX7219 bar: the ESP32 fetches quotes from the sandbox internet’s mock exchange — prices tick on a deterministic walk every 5 seconds — and scrolls symbol, price, and change across 64×8 LEDs over bit-banged SPI. The scroll re-fetches at every wrap, so watch the numbers move; the serial monitor prints each refresh.

How it works
Eight cascaded MAX7219 blocks make a 64×8 LED bar, driven exactly like real hardware: the ESP32 bit-bangs SPI words (register in the high byte, row data in the low byte) through all eight chips per load pulse. The script joins Wi-Fi, fetches JSON quotes from the sandbox internet's mock exchange at api.stocks.test, and formats them into one long ticker string — symbol, price, and signed change for four tickers. A 64×8 framebuffer scrolls the message one column per frame; when the scroll wraps, the script re-fetches. The mock prices walk deterministically, stepping every 5 seconds of virtual time, so successive laps show the market moving while staying fully reproducible.
What's on the bench
- Battery
- ESP32-C3
- LED Matrix 64×8 (8-in-1)
How it's wired
- Battery · pos→ESP32-C3 · vin
- Battery · neg→ESP32-C3 · gnd
- ESP32-C3 · 3v3→LED Matrix 64×8 (8-in-1) · vcc
- ESP32-C3 · gnd2→LED Matrix 64×8 (8-in-1) · gnd
- ESP32-C3 · g4→LED Matrix 64×8 (8-in-1) · din
- ESP32-C3 · g3→LED Matrix 64×8 (8-in-1) · cs
- ESP32-C3 · g6→LED Matrix 64×8 (8-in-1) · clk
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
from machine import Pin, SoftSPI import framebuf, time, network, socket, json spi = SoftSPI(baudrate=1000000, sck=Pin(6), mosi=Pin(4), miso=Pin(5)) cs = Pin(3, Pin.OUT, value=1) NUM = 8 # eight cascaded MAX7219 blocks: 64x8 buf = bytearray(NUM * 8) fb = framebuf.FrameBuffer(buf, NUM * 8, 8, framebuf.MONO_HLSB) def all8(a, d): cs(0); spi.write(bytes([a, d]) * NUM); cs(1) for a, d in ((0x0f, 0), (0x0b, 7), (0x09, 0), (0x0a, 3), (0x0c, 1)): all8(a, d) def show(): for y in range(8): cs(0) for m in range(NUM): spi.write(bytes([y + 1, buf[y * NUM + m]])) cs(1) w = network.WLAN(network.STA_IF) w.active(True) w.connect('BreadboardNet') fb.text('WiFi...', 0, 0); show() while not w.isconnected(): time.sleep_ms(100) def quotes(): addr = socket.getaddrinfo('api.stocks.test', 80)[0][-1] s = socket.socket() s.connect(addr) s.send(b'GET /stocks HTTP/1.0\r\nHost: api.stocks.test\r\n\r\n') r = b'' while True: c = s.recv(256) if not c: break r += c s.close() q = json.loads(r.split(b'\r\n\r\n', 1)[1])['quotes'] out = '' for it in q: out += '%s %s %s%s ' % (it['symbol'], it['price'], '+' if it['change'] >= 0 else '-', abs(it['change'])) return out msg = quotes() print('ticker:', msg) x = NUM * 8 while True: fb.fill(0) fb.text(msg, x, 0) show() x -= 1 if x < -len(msg) * 8: x = NUM * 8 msg = quotes() print('ticker:', msg) time.sleep_ms(60)
Try this
- Let the ticker complete a lap — the re-fetch at the wrap picks up new prices; compare the change figures.
- Open the serial monitor: every refresh prints the full quote line.
- Slow the scroll (raise sleep_ms) or change the message format in the Code tab and run it again.
- Open the 📡 Sniffer to watch each re-fetch as a real DNS + TCP exchange.



