From 76da43a7978ef841407e57f679a6d1293a33d76a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 16 Dec 2025 20:14:05 +0100 Subject: [PATCH 01/27] added experimental spi transport --- src/main.cpp | 6 +- src/main.h | 2 + src/transports/spi_transport.cpp | 167 ++++++++++++++++++++++++++++++- src/transports/spi_transport.h | 42 ++++++++ src/transports/transport.h | 2 + 5 files changed, 212 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4649c40..ce61abc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -949,7 +949,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { bool headerCompleted = false; while (pos < len || - (headerCompleted && command != 5 && command != 22 && command != 23 && + (headerCompleted && command != 4 && command != 5 && command != 22 && command != 23 && command != 27 && command != 28 && command != 29 && command != 40 && command != 41 && command != 42 && command != 43 && command != 44 && command != 45 && command != 46 && command != 47 && command != 48)) { @@ -2331,6 +2331,8 @@ void loop() { #ifdef DMDREADER void loop1() { + transport->SetupEnablePin(); + if (transport->isLoopback()) { uint8_t *buffer = dmdreader_loopback_render(); if (buffer != nullptr) { @@ -2340,7 +2342,7 @@ void loop1() { tight_loop_contents(); } } else { - // @todo SPI + // SPI uses interrupts. delay(100); } } diff --git a/src/main.h b/src/main.h index 333333c..8575141 100644 --- a/src/main.h +++ b/src/main.h @@ -94,6 +94,8 @@ extern const uint8_t CtrlChars[6]; extern const uint8_t rgbOrder[]; extern uint16_t shortId; extern uint8_t wifiPower; +class Clock; +extern Clock lastDataReceivedClock; extern uint8_t usbPackageSizeMultiplier; extern uint8_t rgbMode; extern uint8_t rgbModeLoaded; diff --git a/src/transports/spi_transport.cpp b/src/transports/spi_transport.cpp index 8c14a7b..8cb2140 100644 --- a/src/transports/spi_transport.cpp +++ b/src/transports/spi_transport.cpp @@ -3,6 +3,13 @@ #include "main.h" #ifdef DMDREADER #include + +#include "pico/zedmd_spi_input.pio.h" +#include "utility/clock.h" +#endif + +#ifdef DMDREADER +SpiTransport* SpiTransport::s_instance = nullptr; #endif SpiTransport::SpiTransport() : Transport() { m_type = SPI; } @@ -10,14 +17,21 @@ SpiTransport::SpiTransport() : Transport() { m_type = SPI; } SpiTransport::~SpiTransport() { deinit(); } bool SpiTransport::init() { - #ifdef DMDREADER - dmdreader_init(pio1); +#ifdef DMDREADER + dmdreader_init(m_pio); - // @todo Check if SPI is established, otherwise use loopback - dmdreader_loopback_init(buffers[0], buffers[1], Color::GREEN); + // Start in loopback mode until the host enables SPI via GPIO 13. + dmdreader_loopback_init(buffers[0], buffers[1], Color::ORANGE); m_loopback = true; - #endif + pinMode(kEnablePin, INPUT_PULLDOWN); + pinMode(kClockPin, INPUT); + pinMode(kDataPin, INPUT); + + initPio(); + m_dmaChannel = dma_claim_unused_channel(true); + s_instance = this; +#endif m_active = true; transportActive = true; @@ -28,6 +42,15 @@ bool SpiTransport::init() { bool SpiTransport::deinit() { if (m_active) { m_active = false; +#ifdef DMDREADER + if (m_irqInitialized) { + gpio_set_irq_enabled(kEnablePin, + GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false); + m_irqInitialized = false; + s_instance = nullptr; + } + disableSpiStateMachine(); +#endif // TODO ? clean exit ? // delay(500); // vTaskDelete(m_task); @@ -35,3 +58,137 @@ bool SpiTransport::deinit() { return true; } + +#ifdef DMDREADER + +void SpiTransport::initPio() { + m_stateMachine = pio_claim_unused_sm(m_pio, true); + m_programOffset = pio_add_program(m_pio, &zedmd_spi_input_program); + + pio_gpio_init(m_pio, kClockPin); + pio_gpio_init(m_pio, kDataPin); + pio_sm_set_consecutive_pindirs(m_pio, m_stateMachine, kClockPin, 1, false); + pio_sm_set_consecutive_pindirs(m_pio, m_stateMachine, kDataPin, 1, false); + + pio_sm_config config = + zedmd_spi_input_program_get_default_config(m_programOffset); + sm_config_set_in_pins(&config, kDataPin); + sm_config_set_jmp_pin(&config, kClockPin); + sm_config_set_in_shift(&config, false, true, 8); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); + + pio_sm_init(m_pio, m_stateMachine, m_programOffset, &config); + pio_sm_set_enabled(m_pio, m_stateMachine, false); +} + +void SpiTransport::enableSpiStateMachine() { + if (m_spiEnabled) return; + + pio_sm_set_enabled(m_pio, m_stateMachine, false); + pio_sm_clear_fifos(m_pio, m_stateMachine); + pio_sm_restart(m_pio, m_stateMachine); + pio_sm_set_enabled(m_pio, m_stateMachine, true); + m_spiEnabled = true; +} + +void SpiTransport::disableSpiStateMachine() { + if (!m_spiEnabled || m_stateMachine < 0) return; + pio_sm_set_enabled(m_pio, m_stateMachine, false); + m_spiEnabled = false; +} + +void SpiTransport::flushRxBuffer() { + if (m_rxBufferPos == 0) return; + transportActive = true; + HandleData(m_rxBuffer, m_rxBufferPos); + m_rxBufferPos = 0; +} + +void SpiTransport::startDma() { + if (m_dmaChannel < 0 || m_stateMachine < 0) return; + m_rxBufferPos = 0; + dma_channel_config cfg = dma_channel_get_default_config(m_dmaChannel); + channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8); + channel_config_set_read_increment(&cfg, false); + channel_config_set_write_increment(&cfg, true); + channel_config_set_dreq(&cfg, pio_get_dreq(m_pio, m_stateMachine, false)); + + dma_channel_configure(m_dmaChannel, &cfg, m_rxBuffer, + &m_pio->rxf[m_stateMachine], kRxBufferSize, true); + m_dmaRunning = true; +} + +void SpiTransport::stopDmaAndFlush() { + if (m_dmaChannel < 0) return; + + uint32_t remaining = dma_channel_hw_addr(m_dmaChannel)->transfer_count; + dma_channel_abort(m_dmaChannel); + m_dmaRunning = false; + + // Bytes already written by DMA + m_rxBufferPos = kRxBufferSize - remaining; + if (m_rxBufferPos > kRxBufferSize) m_rxBufferPos = 0; + + // Drain any residual FIFO bytes that arrived after the DMA stop. + while (!pio_sm_is_rx_fifo_empty(m_pio, m_stateMachine) && + m_rxBufferPos < kRxBufferSize) { + const uint32_t raw = pio_sm_get(m_pio, m_stateMachine); + m_rxBuffer[m_rxBufferPos++] = raw & 0xff; + } + + flushRxBuffer(); +} + +void SpiTransport::switchToSpiMode() { + if (!m_loopback) return; + m_loopback = false; + m_transferActive = false; + m_rxBufferPos = 0; + payloadMissing = 0; + headerBytesReceived = 0; + numCtrlCharsFound = 0; + transportActive = false; + enableSpiStateMachine(); +} + +void SpiTransport::onEnableRise() { + if (m_loopback) { + switchToSpiMode(); + return; + } + if (m_transferActive) { + stopDmaAndFlush(); + m_transferActive = false; + } +} + +void SpiTransport::onEnableFall() { + if (m_loopback) return; + if (!m_transferActive) { + m_transferActive = true; + enableSpiStateMachine(); + startDma(); + } +} + +void SpiTransport::gpio_irq_handler(uint gpio, uint32_t events) { + if (!s_instance || gpio != kEnablePin) return; + if (events & GPIO_IRQ_EDGE_RISE) { + s_instance->onEnableRise(); + } + if (events & GPIO_IRQ_EDGE_FALL) { + s_instance->onEnableFall(); + } +} + +void SpiTransport::SetupEnablePin() { + // Initialize GPIO IRQ from core1 (loop1) so callbacks run on core1. + if (!m_irqInitialized) { + gpio_set_irq_enabled_with_callback( + kEnablePin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, + &SpiTransport::gpio_irq_handler); + m_irqInitialized = true; + } +} + +#endif diff --git a/src/transports/spi_transport.h b/src/transports/spi_transport.h index f73805e..0f36c02 100644 --- a/src/transports/spi_transport.h +++ b/src/transports/spi_transport.h @@ -4,6 +4,12 @@ #ifdef PICO_BUILD #include "pico/zedmd_pico.h" #endif +#ifdef DMDREADER +#include "hardware/dma.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" +#endif +#include "main.h" #include "transport.h" class SpiTransport final : public Transport { @@ -15,6 +21,42 @@ class SpiTransport final : public Transport { bool init() override; bool deinit() override; + +#ifdef DMDREADER + void SetupEnablePin(); +#endif + + private: +#ifdef DMDREADER + void initPio(); + void enableSpiStateMachine(); + void disableSpiStateMachine(); + void flushRxBuffer(); + void startDma(); + void stopDmaAndFlush(); + void switchToSpiMode(); + void onEnableRise(); + void onEnableFall(); + static void gpio_irq_handler(uint gpio, uint32_t events); + + static constexpr uint8_t kEnablePin = 13; + static constexpr uint8_t kClockPin = 14; + static constexpr uint8_t kDataPin = 15; + static constexpr size_t kRxBufferSize = BUFFER_SIZE; + + static SpiTransport* s_instance; + + PIO m_pio = pio1; + int m_stateMachine = -1; + int m_programOffset = -1; + int m_dmaChannel = -1; + bool m_spiEnabled = false; + bool m_transferActive = false; + bool m_dmaRunning = false; + bool m_irqInitialized = false; + uint8_t m_rxBuffer[kRxBufferSize]; + size_t m_rxBufferPos = 0; +#endif }; #endif // ZEDMD_SPI_TRANSPORT_H diff --git a/src/transports/transport.h b/src/transports/transport.h index c45dece..4aa37be 100644 --- a/src/transports/transport.h +++ b/src/transports/transport.h @@ -54,6 +54,8 @@ class Transport { bool isLoopback() const { return m_loopback; } + void SetupEnablePin() {} + protected: uint8_t m_type = USB; bool m_active = false; From c9efdd89a2353623c91e83f65422ee661208e60e Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 16 Dec 2025 20:28:39 +0100 Subject: [PATCH 02/27] send dmdreader signals --- src/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ce61abc..73a52be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2332,7 +2332,7 @@ void loop() { #ifdef DMDREADER void loop1() { transport->SetupEnablePin(); - + if (transport->isLoopback()) { uint8_t *buffer = dmdreader_loopback_render(); if (buffer != nullptr) { @@ -2345,5 +2345,8 @@ void loop1() { // SPI uses interrupts. delay(100); } + elseif (!dmdreader_spi_send()) { + tight_loop_contents(); + } } #endif From 629eaa3666e81b35777ef75241f55f7143e69080 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 16 Dec 2025 20:56:12 +0100 Subject: [PATCH 03/27] added pio --- src/main.cpp | 5 +---- src/pico/zedmd_spi_input.pio | 10 ++++++++++ src/transports/spi_transport.cpp | 1 - 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 src/pico/zedmd_spi_input.pio diff --git a/src/main.cpp b/src/main.cpp index 73a52be..fdb905e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2341,11 +2341,8 @@ void loop1() { } else { tight_loop_contents(); } - } else { - // SPI uses interrupts. - delay(100); } - elseif (!dmdreader_spi_send()) { + else if (!dmdreader_spi_send()) { tight_loop_contents(); } } diff --git a/src/pico/zedmd_spi_input.pio b/src/pico/zedmd_spi_input.pio new file mode 100644 index 0000000..9e228d9 --- /dev/null +++ b/src/pico/zedmd_spi_input.pio @@ -0,0 +1,10 @@ +.program zedmd_spi_input + +; Simple clocked input PIO program for ZeDMD SPI transport. +; Samples data on GPIO 15 using GPIO 14 as the external clock. + +.wrap_target +wait 1 gpio 14 ; wait for clock high +in pins, 1 ; sample GPIO 15 (IN pin base) +wait 0 gpio 14 ; wait for clock low +.wrap diff --git a/src/transports/spi_transport.cpp b/src/transports/spi_transport.cpp index 8cb2140..0ab93d3 100644 --- a/src/transports/spi_transport.cpp +++ b/src/transports/spi_transport.cpp @@ -73,7 +73,6 @@ void SpiTransport::initPio() { pio_sm_config config = zedmd_spi_input_program_get_default_config(m_programOffset); sm_config_set_in_pins(&config, kDataPin); - sm_config_set_jmp_pin(&config, kClockPin); sm_config_set_in_shift(&config, false, true, 8); sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); From 98e8a060de4046bf17f9376a5428ae444908eb7a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 18 Dec 2025 00:07:42 +0100 Subject: [PATCH 04/27] added color menu --- src/main.cpp | 110 +++++++++++++++++++++++++++---- src/transports/spi_transport.cpp | 16 ++--- src/transports/spi_transport.h | 6 +- src/transports/transport.h | 4 +- 4 files changed, 115 insertions(+), 21 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fdb905e..a3deb45 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -137,6 +137,32 @@ uint8_t panelDriver = 0; uint8_t panelI2sspeed = 8; uint8_t panelLatchBlanking = 2; uint8_t panelMinRefreshRate = 60; +#ifdef DMDREADER +uint8_t loopbackColor = (uint8_t)Color::ORANGE; + +const char *ColorString(uint8_t color) { + switch ((Color)color) { + case Color::ORANGE: + return "orange"; + case Color::RED: + return "red "; + case Color::YELLOW: + return "yellow"; + case Color::GREEN: + return "green "; + case Color::BLUE: + return "blue "; + case Color::VIOLET: + return "violet"; + case Color::PINK: + return "pink "; + case Color::WHITE: + return "white "; + default: + return nullptr; + } +} +#endif // We needed to change these from RGB to RC (Red Color), BC, GC to prevent // conflicting with the TFT_SPI Library. @@ -507,6 +533,28 @@ void LoadScale() { f.close(); } +#ifdef DMDREADER +void SaveColor() { + File f = LittleFS.open("/color.val", "w"); + f.write(loopbackColor); + f.close(); +} + +void LoadColor() { + File f = LittleFS.open("/color.val", "r"); + if (!f) { + SaveColor(); + return; + } + loopbackColor = f.read(); + if (ColorString(loopbackColor) == nullptr) { + loopbackColor = (uint8_t)Color::ORANGE; + SaveColor(); + } + f.close(); +} +#endif + #ifdef SPEAKER_LIGHTS void SaveSpeakerLightsSettings() { File f = LittleFS.open("/speaker_lights_left_num.val", "w"); @@ -929,13 +977,21 @@ void RefreshSetupScreen() { DisplayNumber(usbPackageSizeMultiplier * 32, 4, 7 * (TOTAL_WIDTH / 128) + (16 * 4), (TOTAL_HEIGHT / 2) + 4, 255, 191, 0); - } - if (transport->isWifi()) { + } else if (transport->isWifi()) { display->DisplayText("UDP Delay:", 7 * (TOTAL_WIDTH / 128), (TOTAL_HEIGHT / 2) + 4, 128, 128, 128); DisplayNumber(transport->getDelay(), 1, 7 * (TOTAL_WIDTH / 128) + 10 * 4, (TOTAL_HEIGHT / 2) + 4, 255, 191, 0); } +#ifdef DMDREADER + else if (transport->isSpi()) { + display->DisplayText("Color:", 7 * (TOTAL_WIDTH / 128), + (TOTAL_HEIGHT / 2) + 4, 128, 128, 128); + display->DisplayText(ColorString(loopbackColor), + 7 * (TOTAL_WIDTH / 128) + (6 * 4), + (TOTAL_HEIGHT / 2) + 4, 255, 191, 0); + } +#endif #ifdef ZEDMD_HD_HALF display->DisplayText("Y-Offset", TOTAL_WIDTH - (7 * (TOTAL_WIDTH / 128)) - 32, (TOTAL_HEIGHT / 2) - 10, 128, 128, 128); @@ -949,10 +1005,11 @@ uint8_t HandleData(uint8_t *pData, size_t len) { bool headerCompleted = false; while (pos < len || - (headerCompleted && command != 4 && command != 5 && command != 22 && command != 23 && - command != 27 && command != 28 && command != 29 && command != 40 && - command != 41 && command != 42 && command != 43 && command != 44 && - command != 45 && command != 46 && command != 47 && command != 48)) { + (headerCompleted && command != 4 && command != 5 && command != 22 && + command != 23 && command != 27 && command != 28 && command != 29 && + command != 40 && command != 41 && command != 42 && command != 43 && + command != 44 && command != 45 && command != 46 && command != 47 && + command != 48)) { headerCompleted = false; if (numCtrlCharsFound < N_CTRL_CHARS) { // Detect 5 consecutive start bits @@ -1728,7 +1785,9 @@ void setup() { LoadSettingsMenu(); LoadTransport(); -#ifndef DMDREADER +#ifdef DMDREADER + LoadColor(); +#else LoadUsbPackageSizeMultiplier(); #endif #if defined(DISPLAY_LED_MATRIX) || defined(DISPLAY_PICO_LED_MATRIX) @@ -1872,7 +1931,7 @@ void setup() { if (transport->isUsb()) { if (position == 4) position = forward ? 5 : 3; } else if (transport->isSpi()) { - if (position == 3 || position == 4) position = forward ? 5 : 2; + if (position == 3) position = forward ? 4 : 2; } else { if (position == 3) position = forward ? 4 : 2; } @@ -1896,12 +1955,21 @@ void setup() { (TOTAL_HEIGHT / 2) + 4, 255, 191, 0); break; } +#ifdef DMDREADER + case 4: { // Color + RefreshSetupScreen(); + display->DisplayText("Color:", 7 * (TOTAL_WIDTH / 128), + TOTAL_HEIGHT / 2 + 4, 255, 191, 0); + break; + } +#else case 4: { // UDP Delay RefreshSetupScreen(); display->DisplayText("UDP Delay:", 7 * (TOTAL_WIDTH / 128), TOTAL_HEIGHT / 2 + 4, 255, 191, 0); break; } +#endif case 5: { // Transport RefreshSetupScreen(); display->DisplayText(transport->getTypeString(), @@ -1968,6 +2036,23 @@ void setup() { SaveUsbPackageSizeMultiplier(); break; } +#ifdef DMDREADER + case 4: { // Color + if (up && ++loopbackColor > ((uint8_t)Color::WHITE)) + loopbackColor = ((uint8_t)Color::ORANGE); + else if (down && + --loopbackColor > + ((uint8_t)Color::WHITE)) // underflow will result in + // 255, set it to WHITE + loopbackColor = ((uint8_t)Color::WHITE); + + display->DisplayText(ColorString(loopbackColor), + 7 * (TOTAL_WIDTH / 128) + (6 * 4), + TOTAL_HEIGHT / 2 + 4, 255, 191, 0); + SaveColor(); + break; + } +#else case 4: { // UDP Delay uint8_t delay = transport->getDelay(); if (up && ++delay > 9) @@ -1982,6 +2067,7 @@ void setup() { transport->saveDelay(); break; } +#endif case 5: { // Transport #ifdef ZEDMD_NO_NETWORKING const uint8_t type = transport->getType() == Transport::USB @@ -2074,6 +2160,9 @@ void setup() { } } +#ifdef DMDREADER + transport->SetColor(loopbackColor); +#endif transport->init(); #ifdef SPEAKER_LIGHTS @@ -2331,7 +2420,7 @@ void loop() { #ifdef DMDREADER void loop1() { - transport->SetupEnablePin(); + //transport->SetupEnablePin(); if (transport->isLoopback()) { uint8_t *buffer = dmdreader_loopback_render(); @@ -2341,8 +2430,7 @@ void loop1() { } else { tight_loop_contents(); } - } - else if (!dmdreader_spi_send()) { + } else if (!dmdreader_spi_send()) { tight_loop_contents(); } } diff --git a/src/transports/spi_transport.cpp b/src/transports/spi_transport.cpp index 0ab93d3..6f0a95d 100644 --- a/src/transports/spi_transport.cpp +++ b/src/transports/spi_transport.cpp @@ -2,8 +2,6 @@ #include "main.h" #ifdef DMDREADER -#include - #include "pico/zedmd_spi_input.pio.h" #include "utility/clock.h" #endif @@ -21,7 +19,7 @@ bool SpiTransport::init() { dmdreader_init(m_pio); // Start in loopback mode until the host enables SPI via GPIO 13. - dmdreader_loopback_init(buffers[0], buffers[1], Color::ORANGE); + dmdreader_loopback_init(buffers[0], buffers[1], m_color); m_loopback = true; pinMode(kEnablePin, INPUT_PULLDOWN); @@ -44,8 +42,8 @@ bool SpiTransport::deinit() { m_active = false; #ifdef DMDREADER if (m_irqInitialized) { - gpio_set_irq_enabled(kEnablePin, - GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false); + gpio_set_irq_enabled(kEnablePin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, + false); m_irqInitialized = false; s_instance = nullptr; } @@ -183,11 +181,13 @@ void SpiTransport::gpio_irq_handler(uint gpio, uint32_t events) { void SpiTransport::SetupEnablePin() { // Initialize GPIO IRQ from core1 (loop1) so callbacks run on core1. if (!m_irqInitialized) { - gpio_set_irq_enabled_with_callback( - kEnablePin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, - &SpiTransport::gpio_irq_handler); + gpio_set_irq_enabled_with_callback(kEnablePin, + GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, + true, &SpiTransport::gpio_irq_handler); m_irqInitialized = true; } } +void SpiTransport::SetColor(uint8_t color) { m_color = (Color)color; } + #endif diff --git a/src/transports/spi_transport.h b/src/transports/spi_transport.h index 0f36c02..f20a27f 100644 --- a/src/transports/spi_transport.h +++ b/src/transports/spi_transport.h @@ -5,6 +5,8 @@ #include "pico/zedmd_pico.h" #endif #ifdef DMDREADER +#include + #include "hardware/dma.h" #include "hardware/gpio.h" #include "hardware/pio.h" @@ -23,7 +25,8 @@ class SpiTransport final : public Transport { bool deinit() override; #ifdef DMDREADER - void SetupEnablePin(); + void SetupEnablePin() override; + void SetColor(uint8_t color) override; #endif private: @@ -56,6 +59,7 @@ class SpiTransport final : public Transport { bool m_irqInitialized = false; uint8_t m_rxBuffer[kRxBufferSize]; size_t m_rxBufferPos = 0; + Color m_color = Color::ORANGE; #endif }; diff --git a/src/transports/transport.h b/src/transports/transport.h index 4aa37be..676f500 100644 --- a/src/transports/transport.h +++ b/src/transports/transport.h @@ -54,7 +54,9 @@ class Transport { bool isLoopback() const { return m_loopback; } - void SetupEnablePin() {} + virtual void SetupEnablePin() {} + + virtual void SetColor(uint8_t color) {} protected: uint8_t m_type = USB; From 0142f4118b59eb5f4b07d99bf7d869559e521b6e Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 18 Dec 2025 14:47:13 +0100 Subject: [PATCH 05/27] reduced the load of the irq handler --- src/main.cpp | 35 +++++++++++++++------ src/transports/spi_transport.cpp | 53 ++++++++++++++++---------------- src/transports/spi_transport.h | 10 +++--- src/transports/transport.h | 4 --- 4 files changed, 57 insertions(+), 45 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a3deb45..4c59858 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -138,6 +138,7 @@ uint8_t panelI2sspeed = 8; uint8_t panelLatchBlanking = 2; uint8_t panelMinRefreshRate = 60; #ifdef DMDREADER +bool core_0_initialized = false; uint8_t loopbackColor = (uint8_t)Color::ORANGE; const char *ColorString(uint8_t color) { @@ -2161,7 +2162,7 @@ void setup() { } #ifdef DMDREADER - transport->SetColor(loopbackColor); + static_cast(transport)->SetColor((Color)loopbackColor); #endif transport->init(); @@ -2188,6 +2189,10 @@ void setup() { speakerLightsRight->start(); } #endif + +#ifdef DMDREADER + core_0_initialized = true; +#endif } void loop() { @@ -2419,19 +2424,29 @@ void loop() { } #ifdef DMDREADER + +void setup1() { + while (!core_0_initialized) { + tight_loop_contents(); + } + + static_cast(transport)->SetupEnablePin(); +} + void loop1() { - //transport->SetupEnablePin(); + if (transport) { + static_cast(transport)->ProcessEnablePinEvents(); - if (transport->isLoopback()) { - uint8_t *buffer = dmdreader_loopback_render(); - if (buffer != nullptr) { - memcpy(renderBuffer[currentRenderBuffer], buffer, TOTAL_BYTES); - Render(); + if (transport->isLoopback()) { + uint8_t *buffer = dmdreader_loopback_render(); + if (buffer != nullptr) { + memcpy(renderBuffer[currentRenderBuffer], buffer, TOTAL_BYTES); + Render(); + } } else { - tight_loop_contents(); + dmdreader_spi_send(); } - } else if (!dmdreader_spi_send()) { - tight_loop_contents(); } + tight_loop_contents(); } #endif diff --git a/src/transports/spi_transport.cpp b/src/transports/spi_transport.cpp index 6f0a95d..1f529df 100644 --- a/src/transports/spi_transport.cpp +++ b/src/transports/spi_transport.cpp @@ -40,15 +40,6 @@ bool SpiTransport::init() { bool SpiTransport::deinit() { if (m_active) { m_active = false; -#ifdef DMDREADER - if (m_irqInitialized) { - gpio_set_irq_enabled(kEnablePin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, - false); - m_irqInitialized = false; - s_instance = nullptr; - } - disableSpiStateMachine(); -#endif // TODO ? clean exit ? // delay(500); // vTaskDelete(m_task); @@ -145,15 +136,11 @@ void SpiTransport::switchToSpiMode() { headerBytesReceived = 0; numCtrlCharsFound = 0; transportActive = false; - enableSpiStateMachine(); } void SpiTransport::onEnableRise() { - if (m_loopback) { - switchToSpiMode(); - return; - } - if (m_transferActive) { + if (m_loopback) switchToSpiMode(); + else if (m_transferActive) { stopDmaAndFlush(); m_transferActive = false; } @@ -161,33 +148,47 @@ void SpiTransport::onEnableRise() { void SpiTransport::onEnableFall() { if (m_loopback) return; - if (!m_transferActive) { - m_transferActive = true; + else if (!m_transferActive) { enableSpiStateMachine(); startDma(); + m_transferActive = true; + } +} + +void SpiTransport::ProcessEnablePinEvents() { + if (m_enableRisePending) { + m_enableRisePending = false; + onEnableRise(); + } + + if (m_enableFallPending) { + m_enableFallPending = false; + onEnableFall(); } } void SpiTransport::gpio_irq_handler(uint gpio, uint32_t events) { if (!s_instance || gpio != kEnablePin) return; if (events & GPIO_IRQ_EDGE_RISE) { - s_instance->onEnableRise(); + s_instance->m_enableRisePending = true; } if (events & GPIO_IRQ_EDGE_FALL) { - s_instance->onEnableFall(); + s_instance->m_enableFallPending = true; } } void SpiTransport::SetupEnablePin() { + m_enableRisePending = false; + m_enableFallPending = false; + // Initialize GPIO IRQ from core1 (loop1) so callbacks run on core1. - if (!m_irqInitialized) { - gpio_set_irq_enabled_with_callback(kEnablePin, - GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, - true, &SpiTransport::gpio_irq_handler); - m_irqInitialized = true; - } + gpio_acknowledge_irq(kEnablePin, + GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL); // clear stale + gpio_set_irq_enabled_with_callback(kEnablePin, + GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, + true, &SpiTransport::gpio_irq_handler); } -void SpiTransport::SetColor(uint8_t color) { m_color = (Color)color; } +void SpiTransport::SetColor(Color color) { m_color = color; } #endif diff --git a/src/transports/spi_transport.h b/src/transports/spi_transport.h index f20a27f..f48bc2d 100644 --- a/src/transports/spi_transport.h +++ b/src/transports/spi_transport.h @@ -25,12 +25,11 @@ class SpiTransport final : public Transport { bool deinit() override; #ifdef DMDREADER - void SetupEnablePin() override; - void SetColor(uint8_t color) override; -#endif + void SetupEnablePin(); + void SetColor(Color color); + void ProcessEnablePinEvents(); private: -#ifdef DMDREADER void initPio(); void enableSpiStateMachine(); void disableSpiStateMachine(); @@ -56,10 +55,11 @@ class SpiTransport final : public Transport { bool m_spiEnabled = false; bool m_transferActive = false; bool m_dmaRunning = false; - bool m_irqInitialized = false; uint8_t m_rxBuffer[kRxBufferSize]; size_t m_rxBufferPos = 0; Color m_color = Color::ORANGE; + volatile bool m_enableRisePending = false; + volatile bool m_enableFallPending = false; #endif }; diff --git a/src/transports/transport.h b/src/transports/transport.h index 676f500..c45dece 100644 --- a/src/transports/transport.h +++ b/src/transports/transport.h @@ -54,10 +54,6 @@ class Transport { bool isLoopback() const { return m_loopback; } - virtual void SetupEnablePin() {} - - virtual void SetColor(uint8_t color) {} - protected: uint8_t m_type = USB; bool m_active = false; From 585b8f9646a3bf8d4d8546fd85e5c0889cd39cdb Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 18 Dec 2025 17:53:32 +0100 Subject: [PATCH 06/27] improved double buffering --- platformio.ini | 2 +- src/displays/LedMatrix.cpp | 10 ------- src/displays/PicoLedMatrix.cpp | 16 ---------- src/main.cpp | 54 +++++++++++++++++++++++++++------- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/platformio.ini b/platformio.ini index c395ba2..76b0a41 100644 --- a/platformio.ini +++ b/platformio.ini @@ -195,7 +195,7 @@ board_build.filesystem_size = 3.5m lib_deps = thomasfredericks/Bounce2 https://github.com/PPUC/pimoroni-pico#0002c1d20a8a6c79c6a4125fe34f12815b0e2f2c - https://github.com/PPUC/dmdreader#a1b4c4debeca31488c0c6db42588f7df3f701d17 + https://github.com/PPUC/dmdreader#3d8b050d33fdc25276ed70700f30ac5c2f3c1ada lib_ignore = WiFi AsyncUDP diff --git a/src/displays/LedMatrix.cpp b/src/displays/LedMatrix.cpp index 5b5bbcf..a578f1f 100644 --- a/src/displays/LedMatrix.cpp +++ b/src/displays/LedMatrix.cpp @@ -57,8 +57,6 @@ void LedMatrix::DisplayText(const char *text, uint16_t x, uint16_t y, uint8_t r, } } } - - Render(); } void IRAM_ATTR LedMatrix::FillZoneRaw(uint8_t idx, uint8_t *pBuffer) { @@ -73,8 +71,6 @@ void IRAM_ATTR LedMatrix::FillZoneRaw(uint8_t idx, uint8_t *pBuffer) { pBuffer[pos + 1], pBuffer[pos + 2]); } } - - Render(); } void IRAM_ATTR LedMatrix::FillZoneRaw565(uint8_t idx, uint8_t *pBuffer) { @@ -88,8 +84,6 @@ void IRAM_ATTR LedMatrix::FillZoneRaw565(uint8_t idx, uint8_t *pBuffer) { (((uint16_t)pBuffer[pos + 1]) << 8) + pBuffer[pos]); } } - - Render(); } void IRAM_ATTR LedMatrix::ClearZone(uint8_t idx) { @@ -101,8 +95,6 @@ void IRAM_ATTR LedMatrix::ClearZone(uint8_t idx) { DrawPixel(x + zoneXOffset, y + zoneYOffset, 0, 0, 0); } } - - Render(); } void IRAM_ATTR LedMatrix::FillPanelRaw(uint8_t *pBuffer) { @@ -115,8 +107,6 @@ void IRAM_ATTR LedMatrix::FillPanelRaw(uint8_t *pBuffer) { DrawPixel(x, y, pBuffer[pos], pBuffer[pos + 1], pBuffer[pos + 2]); } } - - Render(); } void LedMatrix::Render() {} diff --git a/src/displays/PicoLedMatrix.cpp b/src/displays/PicoLedMatrix.cpp index 2bd0a8f..320f10e 100644 --- a/src/displays/PicoLedMatrix.cpp +++ b/src/displays/PicoLedMatrix.cpp @@ -2,7 +2,6 @@ #include "PicoLedMatrix.h" -#include #include #include "pico/zedmd_pico.h" @@ -48,21 +47,6 @@ static uint16_t lut_table[256] = { 1023}; PicoLedMatrix::PicoLedMatrix() { - // tested working on a lot of different devices - vreg_set_voltage(VREG_VOLTAGE_1_15); - busy_wait_at_least_cycles((SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US * - static_cast(XOSC_HZ)) / - 1000000); - set_sys_clock_khz(266000, false); - -#if 0 - // serial needs to be inited after oc - Serial1.setTX(16); - Serial1.setRX(17); - Serial1.begin(); - Serial1.println("PicoLedMatrix"); -#endif - // rgb565 > rgb888 "fast" pixel conversion init_rgb_tables(); diff --git a/src/main.cpp b/src/main.cpp index 4c59858..bcce653 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -153,8 +153,8 @@ const char *ColorString(uint8_t color) { return "green "; case Color::BLUE: return "blue "; - case Color::VIOLET: - return "violet"; + case Color::PURPLE: + return "purple"; case Color::PINK: return "pink "; case Color::WHITE: @@ -202,12 +202,14 @@ void DoRestart(int sec) { } display->ClearScreen(); display->DisplayText("Restarting ...", 0, 0, 255, 0, 0); + display->Render(); #ifndef DMDREADER vTaskDelay(pdMS_TO_TICKS(sec * 1000)); #else delay(1000); #endif display->ClearScreen(); + display->Render(); delay(20); #ifdef PICO_BUILD @@ -661,15 +663,19 @@ void LoadSpeakerLightsSettings() { void LedTester(void) { display->FillScreen(255, 0, 0); + display->Render(); delay(LED_CHECK_DELAY); display->FillScreen(0, 255, 0); + display->Render(); delay(LED_CHECK_DELAY); display->FillScreen(0, 0, 255); + display->Render(); delay(LED_CHECK_DELAY); display->ClearScreen(); + display->Render(); } void AcquireNextBuffer() { @@ -720,7 +726,6 @@ uint16_t frames = 0; char fpsStr[3]; void FpsUpdate() { - // if (debug) { frames++; if (fpsClock.getElapsedTime().asMilliseconds() >= 200) { @@ -731,7 +736,7 @@ void FpsUpdate() { display->DisplayText(fpsStr, TOTAL_WIDTH - 7, TOTAL_HEIGHT - 5, 255, 0, 0, false, false); - //} + display->Render(); } #endif @@ -739,7 +744,7 @@ uint8_t GetPixelBrightness(uint8_t r, uint8_t g, uint8_t b) { return (r * 77 + g * 150 + b * 29) >> 8; // Optimized luminance calculation } -void Render() { +void Render(bool renderAll = true) { if (NUM_RENDER_BUFFERS == 1) { display->FillPanelRaw(renderBuffer[currentRenderBuffer]); } else if (currentRenderBuffer != lastRenderBuffer) { @@ -797,7 +802,7 @@ void Render() { } } - display->Render(); + if (renderAll) display->Render(); #ifdef SPEAKER_LIGHTS if (FX_MODE_AMBILIGHT == speakerLightsLeftMode) { @@ -859,7 +864,7 @@ void ClearScreen() { } } -void DisplayLogo(void) { +void DisplayLogo() { File f; if (TOTAL_HEIGHT == 64) { @@ -893,7 +898,7 @@ void DisplayLogo(void) { #endif f.close(); - Render(); + Render(false); DisplayVersion(true); throbberColors[0] = 0; @@ -1050,6 +1055,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { 0, 0); DisplayNumber(payloadSize, 5, 0, 19, 255, 0, 0); DisplayNumber(BUFFER_SIZE, 5, 0, 25, 255, 0, 0); + display->Render(); while (1); } headerBytesReceived = 0; @@ -1066,6 +1072,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { (TOTAL_HEIGHT / 2) - 4, 128, 128, 128); DisplayNumber(payloadSize, 2, 7 * (TOTAL_WIDTH / 128) + (8 * 4), (TOTAL_HEIGHT / 2) - 4, 255, 191, 0); + display->Render(); } bool rgb888ZoneStream = false; @@ -1306,6 +1313,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { Serial.flush(); } display->DisplayText("Saving settings ...", 0, 0, 255, 0, 0); + display->Render(); SaveLum(); SaveDebug(); SaveTransport(); @@ -1322,6 +1330,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { SaveYOffset(); #endif display->DisplayText("Saving settings ... done", 0, 0, 255, 0, 0); + display->Render(); headerBytesReceived = 0; numCtrlCharsFound = 0; if (transport->isWifiAndActive()) break; @@ -1634,6 +1643,7 @@ uint8_t HandleData(uint8_t *pData, size_t len) { display->DisplayText("KEEP ALIVE RECEIVED", 7 * (TOTAL_WIDTH / 128), (TOTAL_HEIGHT / 2) - 10, 128, 128, 128); + display->Render(); } lastDataReceivedClock.restart(); headerBytesReceived = 0; @@ -1737,6 +1747,15 @@ void setup() { #ifndef PICO_BUILD esp_log_level_set("*", ESP_LOG_NONE); #else + /* + // tested working on a lot of different devices + vreg_set_voltage(VREG_VOLTAGE_1_15); + busy_wait_at_least_cycles((SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US * + static_cast(XOSC_HZ)) / + 1000000); + set_sys_clock_khz(266000, false); + */ + // overclock to achieve higher SPI transfer speed set_sys_clock_khz(SYS_CLK_MHZ * 1000, true); #endif @@ -1823,6 +1842,7 @@ void setup() { if (!fileSystemOK) { display->DisplayText("Error reading file system!", 0, 0, 255, 0, 0); display->DisplayText("Try to flash the firmware again.", 0, 6, 255, 0, 0); + display->Render(); while (true); } @@ -1839,9 +1859,11 @@ void setup() { DisplayNumber(esp_reset_reason(), 2, 16 * 4, 18, 255, 0, 0); if (debug) { display->DisplayText("Reboot in 30 seconds ...", 0, 24, 255, 0, 0); + display->Render(); for (uint8_t i = 29; i > 0; i--) { delay(1000); DisplayNumber(i, 2, 40, 24, 255, 0, 0); + display->Render(); } Restart(); } @@ -1853,9 +1875,11 @@ void setup() { display->DisplayText("Check your power supply and", 0, 6, 255, 0, 0); display->DisplayText("hardware.", 0, 12, 255, 0, 0); display->DisplayText("Reboot in 30 seconds ...", 0, 24, 255, 0, 0); + display->Render(); for (uint8_t i = 29; i > 0; i--) { delay(1000); DisplayNumber(i, 2, 40, 24, 255, 0, 0); + display->Render(); } Restart(); break; @@ -1874,6 +1898,7 @@ void setup() { #endif if (nullptr == renderBuffer[i]) { display->DisplayText("out of memory", 0, 0, 255, 0, 0); + display->Render(); while (1); } memset(renderBuffer[i], 0, TOTAL_BYTES); @@ -1915,6 +1940,7 @@ void setup() { #endif uint8_t position = 1; + bool firstMenuRendering = true; while (1) { forwardButton->update(); const bool forward = forwardButton->pressed(); @@ -1923,7 +1949,8 @@ void setup() { backwardButton->update(); backward = backwardButton->pressed(); #endif - if (forward || backward) { + bool buttonPressed = forward || backward; + if (buttonPressed) { if (forward && ++position > MENU_ITEMS_COUNT) position = 1; else if (backward && --position < 1) @@ -2008,6 +2035,7 @@ void setup() { downButton->update(); down = downButton->pressed(); #endif + buttonPressed = buttonPressed || up || down; if (up || down) { switch (position) { case 1: { // Exit @@ -2130,7 +2158,10 @@ void setup() { #endif } } - + if (buttonPressed || firstMenuRendering) { + firstMenuRendering = false; + display->Render(); + } delay(1); } } @@ -2146,6 +2177,7 @@ void setup() { DisplayLogo(); DisplayId(); + display->Render(); // Create synchronization primitives for (uint8_t i = 0; i < NUM_BUFFERS; i++) { @@ -2157,6 +2189,7 @@ void setup() { #endif if (nullptr == buffers[i]) { display->DisplayText("out of memory", 0, 0, 255, 0, 0); + display->Render(); while (1); } } @@ -2328,6 +2361,7 @@ void loop() { display->DisplayText("miniz error: ", 0, 0, 255, 0, 0); DisplayNumber(minizStatus, 3, 13 * 4, 0, 255, 0, 0); display->DisplayText("free heap: ", 0, 6, 255, 0, 0); + display->Render(); #ifdef PICO_BUILD DisplayNumber(rp2040.getFreeHeap(), 8, 11 * 4, 6, 255, 0, 0); #else From e550ae1f29c710ad8ee30e9f03f3850c12f6dd39 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 18 Dec 2025 21:18:52 +0100 Subject: [PATCH 07/27] switched to different lib --- platformio.ini | 24 +++++-------- src/displays/PicoLedMatrix.cpp | 61 +++++++++++----------------------- src/displays/PicoLedMatrix.h | 19 ++++++----- 3 files changed, 38 insertions(+), 66 deletions(-) diff --git a/platformio.ini b/platformio.ini index 76b0a41..10613e4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/pimoroni-pico#0002c1d20a8a6c79c6a4125fe34f12815b0e2f2c + https://github.com/PPUC/hub75#88aa0f394a695c05259bbfa1f18c5522409fc841 lib_ignore = SPI WiFi @@ -194,7 +194,7 @@ board_build.filesystem = littlefs board_build.filesystem_size = 3.5m lib_deps = thomasfredericks/Bounce2 - https://github.com/PPUC/pimoroni-pico#0002c1d20a8a6c79c6a4125fe34f12815b0e2f2c + https://github.com/PPUC/hub75#88aa0f394a695c05259bbfa1f18c5522409fc841 https://github.com/PPUC/dmdreader#3d8b050d33fdc25276ed70700f30ac5c2f3c1ada lib_ignore = WiFi @@ -215,18 +215,10 @@ build_flags = -DRP2350 ; needed for dmdreader -DPICO_RP2350 -DPICO_RP2350A=0 ; Not RP2350A means RP2350B - -DHUB75_R0=30 - -DHUB75_G0=31 - -DHUB75_B0=32 - -DHUB75_R1=33 - -DHUB75_G1=34 - -DHUB75_B1=35 - -DHUB75_A=36 - -DHUB75_B=37 - -DHUB75_C=38 - -DHUB75_D=39 - -DHUB75_E=40 - -DHUB75_CLK=41 - -DHUB75_LAT=42 - -DHUB75_OE=43 + -DDATA_BASE_PIN=30 + -DROWSEL_BASE_PIN=36 + -DCLK_PIN=41 + -DSTROBE_PIN=42 + -DOEN_PIN=43 + -DHUB75_MULTIPLEX_2_ROWS=1 build_unflags = -Og diff --git a/src/displays/PicoLedMatrix.cpp b/src/displays/PicoLedMatrix.cpp index 320f10e..70bcd7f 100644 --- a/src/displays/PicoLedMatrix.cpp +++ b/src/displays/PicoLedMatrix.cpp @@ -2,15 +2,8 @@ #include "PicoLedMatrix.h" -#include - #include "pico/zedmd_pico.h" -static pimoroni::Hub75 *s_hub75; - -// interrupt callback required function -static void __isr dma_complete() { s_hub75->dma_complete(); } - static uint8_t r5_to_8[32]; static uint8_t g6_to_8[64]; static uint8_t b5_to_8[32]; @@ -26,61 +19,45 @@ static void init_rgb_tables() { } } -static uint16_t lut_table[256] = { - 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23, 24, 26, 27, - 29, 30, 32, 33, 35, 36, 38, 39, 41, 43, 44, 46, 48, 50, 51, - 53, 55, 57, 59, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, - 82, 84, 87, 89, 91, 93, 95, 98, 100, 102, 104, 107, 109, 112, 114, - 116, 119, 121, 124, 126, 129, 131, 134, 136, 139, 142, 144, 147, 150, 152, - 155, 158, 161, 163, 166, 169, 172, 175, 178, 181, 184, 187, 190, 193, 196, - 199, 202, 205, 208, 211, 214, 218, 221, 224, 227, 231, 234, 237, 241, 244, - 248, 251, 254, 258, 262, 265, 269, 272, 276, 280, 283, 287, 291, 295, 298, - 302, 306, 310, 314, 318, 322, 326, 330, 334, 338, 342, 346, 350, 354, 359, - 363, 367, 372, 376, 380, 385, 389, 394, 398, 403, 407, 412, 416, 421, 426, - 431, 435, 440, 445, 450, 455, 460, 465, 470, 475, 480, 485, 490, 495, 500, - 506, 511, 516, 522, 527, 532, 538, 543, 549, 555, 560, 566, 572, 577, 583, - 589, 595, 601, 607, 613, 619, 625, 631, 637, 643, 649, 656, 662, 668, 675, - 681, 688, 694, 701, 708, 714, 721, 728, 735, 741, 748, 755, 762, 769, 776, - 784, 791, 798, 805, 813, 820, 828, 835, 843, 850, 858, 866, 874, 881, 889, - 897, 905, 913, 921, 929, 938, 946, 954, 963, 971, 980, 988, 997, 1005, 1014, - 1023}; - PicoLedMatrix::PicoLedMatrix() { // rgb565 > rgb888 "fast" pixel conversion init_rgb_tables(); - s_hub75 = new pimoroni::Hub75( - TOTAL_WIDTH, PANEL_HEIGHT, nullptr, pimoroni::PANEL_FM6126A, false, - static_cast(color_order[rgbMode]), - lut_table); - s_hub75->start(dma_complete); + create_hub75_driver(TOTAL_WIDTH, PANEL_HEIGHT, PanelType::PANEL_FM6126A, + false); + start_hub75_driver(); } -PicoLedMatrix::~PicoLedMatrix() { - s_hub75->stop(dma_complete); - delete s_hub75; -} +PicoLedMatrix::~PicoLedMatrix() {} void IRAM_ATTR PicoLedMatrix::DrawPixel(const uint16_t x, const uint16_t y, const uint8_t r, const uint8_t g, const uint8_t b) { - s_hub75->set_pixel(x, y + yOffset, r, g, b); + uint16_t pos = ((y + yOffset) * TOTAL_WIDTH + x) * 3; + drawBuffer[pos] = b; + drawBuffer[++pos] = g; + drawBuffer[++pos] = r; } void IRAM_ATTR PicoLedMatrix::DrawPixel(const uint16_t x, const uint16_t y, const uint16_t color) { - s_hub75->set_pixel(x, y + yOffset, r5_to_8[(color >> 11) & 0x1F], - g6_to_8[(color >> 5) & 0x3F], b5_to_8[color & 0x1F]); + uint16_t pos = ((y + yOffset) * TOTAL_WIDTH + x) * 3; + drawBuffer[pos] = r5_to_8[(color >> 11) & 0x1F]; + drawBuffer[++pos] = g6_to_8[(color >> 5) & 0x3F]; + drawBuffer[++pos] = b5_to_8[color & 0x1F]; } -void PicoLedMatrix::ClearScreen() { s_hub75->clear(); } +void PicoLedMatrix::ClearScreen() { memset(drawBuffer, 0, sizeof(drawBuffer)); } void PicoLedMatrix::SetBrightness(const uint8_t level) { // TODO: verify this (compare with an "esp board") ? const auto b = static_cast(static_cast(level) * 1.5f); - s_hub75->brightness = b; + setBasisBrightness(b); +} + +void PicoLedMatrix::Render() { + // double buffering is handled inside the hub75 driver + update_bgr(drawBuffer); } -void PicoLedMatrix::Render() { s_hub75->render(); } #endif // PICO_BUILD diff --git a/src/displays/PicoLedMatrix.h b/src/displays/PicoLedMatrix.h index afbc5a9..9a6c68f 100644 --- a/src/displays/PicoLedMatrix.h +++ b/src/displays/PicoLedMatrix.h @@ -2,7 +2,7 @@ #define PICO_LED_MATRIX_H #include "LedMatrix.h" -#include "hub75.hpp" +#include class PicoLedMatrix final : public LedMatrix { public: @@ -18,13 +18,16 @@ class PicoLedMatrix final : public LedMatrix { void Render() override; private: - uint8_t color_order[6] = { - static_cast(pimoroni::Hub75::COLOR_ORDER::RGB), - static_cast(pimoroni::Hub75::COLOR_ORDER::BRG), - static_cast(pimoroni::Hub75::COLOR_ORDER::GBR), - static_cast(pimoroni::Hub75::COLOR_ORDER::RBG), - static_cast(pimoroni::Hub75::COLOR_ORDER::GRB), - static_cast(pimoroni::Hub75::COLOR_ORDER::BGR)}; + /* + uint8_t color_order[6] = { + static_cast(pimoroni::Hub75::COLOR_ORDER::RGB), + static_cast(pimoroni::Hub75::COLOR_ORDER::BRG), + static_cast(pimoroni::Hub75::COLOR_ORDER::GBR), + static_cast(pimoroni::Hub75::COLOR_ORDER::RBG), + static_cast(pimoroni::Hub75::COLOR_ORDER::GRB), + static_cast(pimoroni::Hub75::COLOR_ORDER::BGR)}; + */ + uint8_t drawBuffer[TOTAL_WIDTH * PANEL_HEIGHT * 3]; }; #endif // PICO_LED_MATRIX_H From cfe1c034a33d10c2ba0c3cc8ad3c9dcb7951369b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 18 Dec 2025 22:15:44 +0100 Subject: [PATCH 08/27] fixed pico --- platformio.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platformio.ini b/platformio.ini index 10613e4..26c8a4d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -169,6 +169,7 @@ extends = pico board = pico build_flags = ${pico.build_flags} -DZEDMD_HD=1 + -DHUB75_MULTIPLEX_2_ROWS=1 [env:pico2_128x32] extends = pico @@ -176,6 +177,7 @@ board = rpipico2 board_build.filesystem_size = 3.5m build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM + -DHUB75_MULTIPLEX_2_ROWS=1 [env:pico2_256x64] extends = pico @@ -184,6 +186,7 @@ board_build.filesystem_size = 3.5m build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM -DZEDMD_HD=1 + -DHUB75_MULTIPLEX_2_ROWS=1 [env:ppucdmd_128x32] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 From f9188bb9e474d2bbae3020fefedea360b62d5e99 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 27 Dec 2025 20:53:07 +0100 Subject: [PATCH 09/27] removed duplicate function --- src/main.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5f90393..3eaf490 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2549,20 +2549,4 @@ void loop1() { static_cast(transport)->SetupEnablePin(); } -void loop1() { - if (transport) { - static_cast(transport)->ProcessEnablePinEvents(); - - if (transport->isLoopback()) { - uint8_t *buffer = dmdreader_loopback_render(); - if (buffer != nullptr) { - memcpy(renderBuffer[currentRenderBuffer], buffer, TOTAL_BYTES); - Render(); - } - } else { - dmdreader_spi_send(); - } - } - tight_loop_contents(); -} #endif From a367c03b6c826a67439555525862ca99e06b1914 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 27 Dec 2025 20:55:26 +0100 Subject: [PATCH 10/27] removed function --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3eaf490..e0ed16d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2545,8 +2545,6 @@ void loop1() { } else { delay(1); } - - static_cast(transport)->SetupEnablePin(); } #endif From b33a55803b3d7f065d04dbe1953daddf3494a928 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 17:03:16 +0100 Subject: [PATCH 11/27] fixed compile issues --- platformio.ini | 2 +- src/displays/PicoLedMatrix.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index f97c62c..cb47d93 100644 --- a/platformio.ini +++ b/platformio.ini @@ -239,8 +239,8 @@ board_build.filesystem = littlefs board_build.filesystem_size = 1.5m lib_deps = thomasfredericks/Bounce2 - https://github.com/PPUC/hub75#e18a897de981bf59803f2218a3a7fb8f0a631245 https://github.com/PPUC/dmdreader#c627fbe48d67f094e4a59ecbea8bc4319e97a6d0 + https://github.com/PPUC/hub75#0e629f9fff855f026b2cd1def187f3cbca4069c0 lib_ignore = WiFi AsyncUDP diff --git a/src/displays/PicoLedMatrix.cpp b/src/displays/PicoLedMatrix.cpp index 6f51647..a2f412a 100644 --- a/src/displays/PicoLedMatrix.cpp +++ b/src/displays/PicoLedMatrix.cpp @@ -23,8 +23,7 @@ PicoLedMatrix::PicoLedMatrix() { // rgb565 > rgb888 "fast" pixel conversion init_rgb_tables(); - create_hub75_driver(TOTAL_WIDTH, PANEL_HEIGHT, PanelType::PANEL_RUL6024, - false); + create_hub75_driver(TOTAL_WIDTH, PANEL_HEIGHT, PANEL_RUL6024, false); start_hub75_driver(); } From ff373b7422094e2c509bb88479368c4baa4481d5 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 17:26:00 +0100 Subject: [PATCH 12/27] fixed build --- platformio.ini | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/platformio.ini b/platformio.ini index cb47d93..c24ec2b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/hub75#88aa0f394a695c05259bbfa1f18c5522409fc841 + https://github.com/PPUC/hub75#0e629f9fff855f026b2cd1def187f3cbca4069c0 lib_ignore = SPI WiFi @@ -214,22 +214,27 @@ board = rpipico2 build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM -DZEDMD_HD=1 + -DZEDMD_NO_NETWORKING=1 + -DNO_PICO_GRAPHICS=1 + -DDISPLAY_LED_MATRIX=1 + -DMINIZ_NO_STDIO=1 + -DMINIZ_NO_TIME=1 + -DMINIZ_NO_DEFLATE_APIS=1 + -DMINIZ_NO_ARCHIVE_APIS=1 + -DMINIZ_NO_ZLIB_COMPATIBLE_NAMES=1 + -Wl,-Map,${BUILD_DIR}/firmware.map + -Os + -DRP2350 ; needed for dmdreader -DPICO_RP2350 -DPICO_RP2350A=0 ; Not RP2350A means RP2350B - -DHUB75_R0=30 - -DHUB75_G0=31 - -DHUB75_B0=32 - -DHUB75_R1=33 - -DHUB75_G1=34 - -DHUB75_B1=35 - -DHUB75_A=36 - -DHUB75_B=37 - -DHUB75_C=38 - -DHUB75_D=39 - -DHUB75_E=40 - -DHUB75_CLK=41 - -DHUB75_LAT=42 - -DHUB75_OE=43 + -DDATA_BASE_PIN=30 + -DROWSEL_BASE_PIN=36 + -DCLK_PIN=41 + -DSTROBE_PIN=42 + -DOEN_PIN=43 + -DHUB75_CLK2=44 + -DHUB75_LAT2=45 + -DHUB75_OE2=46 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 @@ -265,7 +270,6 @@ build_flags = -DCLK_PIN=41 -DSTROBE_PIN=42 -DOEN_PIN=43 - -DHUB75_MULTIPLEX_2_ROWS=1 build_unflags = -Og [env:ppucdmd_128x32] From a87b6f077421ee6296393ed6ce8c0d48ad295c05 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 18:05:27 +0100 Subject: [PATCH 13/27] HUB75_MULTIPLEX_4_ROWS --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index c24ec2b..2322f64 100644 --- a/platformio.ini +++ b/platformio.ini @@ -235,6 +235,7 @@ build_flags = ${pico.build_flags} -DHUB75_CLK2=44 -DHUB75_LAT2=45 -DHUB75_OE2=46 + -DHUB75_MULTIPLEX_4_ROWS=1 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 From f8585a7e20a02fc2a443fc5222949ff1d5547e20 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 18:16:54 +0100 Subject: [PATCH 14/27] changed setting --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2322f64..35e294a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -213,7 +213,7 @@ extends = pico board = rpipico2 build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM - -DZEDMD_HD=1 + -DZEDMD_HD_HALF=1 -DZEDMD_NO_NETWORKING=1 -DNO_PICO_GRAPHICS=1 -DDISPLAY_LED_MATRIX=1 @@ -235,7 +235,7 @@ build_flags = ${pico.build_flags} -DHUB75_CLK2=44 -DHUB75_LAT2=45 -DHUB75_OE2=46 - -DHUB75_MULTIPLEX_4_ROWS=1 + -DHUB75_MULTIPLEX_2_ROWS=1 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 From 6a690aa8f6d210fbfa07e5113377a5090500bdca Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 18:26:57 +0100 Subject: [PATCH 15/27] HUB75_P3_1415_16S_64X64_S31 --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 35e294a..8c7cb6b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -213,7 +213,7 @@ extends = pico board = rpipico2 build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM - -DZEDMD_HD_HALF=1 + -DZEDMD_HD=1 -DZEDMD_NO_NETWORKING=1 -DNO_PICO_GRAPHICS=1 -DDISPLAY_LED_MATRIX=1 @@ -235,7 +235,7 @@ build_flags = ${pico.build_flags} -DHUB75_CLK2=44 -DHUB75_LAT2=45 -DHUB75_OE2=46 - -DHUB75_MULTIPLEX_2_ROWS=1 + -DHUB75_P3_1415_16S_64X64_S31=1 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 From c17f27cc2205aae86809d9fc8b0618b5e8561f83 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 20:47:35 +0100 Subject: [PATCH 16/27] HUB75_P10_3535_16X32_4S --- platformio.ini | 4 ++-- src/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 8c7cb6b..02b95fa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -213,7 +213,7 @@ extends = pico board = rpipico2 build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM - -DZEDMD_HD=1 + -DZEDMD_HD_HALF=1 -DZEDMD_NO_NETWORKING=1 -DNO_PICO_GRAPHICS=1 -DDISPLAY_LED_MATRIX=1 @@ -235,7 +235,7 @@ build_flags = ${pico.build_flags} -DHUB75_CLK2=44 -DHUB75_LAT2=45 -DHUB75_OE2=46 - -DHUB75_P3_1415_16S_64X64_S31=1 + -DHUB75_P10_3535_16X32_4S=1 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 diff --git a/src/main.cpp b/src/main.cpp index a259973..aad100a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -575,7 +575,7 @@ void LoadUsbPackageSizeMultiplier() { #ifdef ZEDMD_HD_HALF void SaveYOffset() { File f = LittleFS.open("/y_offset.val", "w"); - f.write(yOffset); + f.write(static_cast(yOffset)); f.close(); } @@ -585,7 +585,7 @@ void LoadYOffset() { SaveYOffset(); return; } - yOffset = f.read(); + yOffset = static_cast(f.read()); f.close(); } #endif From 878a3a52155d279a63bac7762c9147610e6e610a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 20:57:18 +0100 Subject: [PATCH 17/27] new test --- platformio.ini | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 02b95fa..392297c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -183,7 +183,13 @@ extends = pico board = rpipico2 build_flags = ${pico.build_flags} -DBOARD_HAS_PSRAM - -DZEDMD_HD=1 + -DZEDMD_HD_HALF=1 + -DPICO_RP2350 + -DDATA_BASE_PIN=0 + -DROWSEL_BASE_PIN=6 + -DCLK_PIN=11 + -DSTROBE_PIN=12 + -DOEN_PIN=13 -DHUB75_MULTIPLEX_2_ROWS=1 [env:pico2_128x32_ppucdmd] From 1b7b6a6683f746cd6d39e6cc4c950397851e5129 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 21:04:24 +0100 Subject: [PATCH 18/27] HUB75_P3_1415_16S_64X64_S31 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 392297c..89e85d5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -190,7 +190,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_MULTIPLEX_2_ROWS=1 + -DHUB75_P3_1415_16S_64X64_S31=1 [env:pico2_128x32_ppucdmd] extends = pico From de03b116a50f4cf6791fe72229ec9283dff1c69f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 21:10:20 +0100 Subject: [PATCH 19/27] HUB75_P10_3535_16X32_4S --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 89e85d5..ecfb3e1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -190,7 +190,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_P3_1415_16S_64X64_S31=1 + -DHUB75_P10_3535_16X32_4S=1 [env:pico2_128x32_ppucdmd] extends = pico From bcad99d618ac9fdb2008e4fe65bb519b48fccab9 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 23:04:00 +0100 Subject: [PATCH 20/27] ROWSEL_N_PINS 5 --- platformio.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index ecfb3e1..d0bb3a2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -187,10 +187,11 @@ build_flags = ${pico.build_flags} -DPICO_RP2350 -DDATA_BASE_PIN=0 -DROWSEL_BASE_PIN=6 + -DROWSEL_N_PINS 5 -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_P10_3535_16X32_4S=1 + -DHUB75_MULTIPLEX_2_ROWS=1 [env:pico2_128x32_ppucdmd] extends = pico From c1a2c229f253e01f4b95dab9c5faee5bf4d840f0 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 25 Jan 2026 23:27:18 +0100 Subject: [PATCH 21/27] fixed builds --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d0bb3a2..833303e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -187,7 +187,7 @@ build_flags = ${pico.build_flags} -DPICO_RP2350 -DDATA_BASE_PIN=0 -DROWSEL_BASE_PIN=6 - -DROWSEL_N_PINS 5 + -DROWSEL_N_PINS=5 -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 From 85d90c99821487e5d7fb00eb4dbcc26f4b9a0688 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 26 Jan 2026 12:14:33 +0100 Subject: [PATCH 22/27] next test --- platformio.ini | 6 +++--- src/displays/PicoLedMatrix.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 833303e..093ebf1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/hub75#0e629f9fff855f026b2cd1def187f3cbca4069c0 + https://github.com/PPUC/hub75#e75ce7f3d9e24efde57586bf194a1e96b79a5fe2 lib_ignore = SPI WiFi @@ -191,7 +191,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_MULTIPLEX_2_ROWS=1 + -DHUB75_LINEDECODER_SM5368=1 [env:pico2_128x32_ppucdmd] extends = pico @@ -253,7 +253,7 @@ board_build.filesystem_size = 1.5m lib_deps = thomasfredericks/Bounce2 https://github.com/PPUC/dmdreader#c627fbe48d67f094e4a59ecbea8bc4319e97a6d0 - https://github.com/PPUC/hub75#0e629f9fff855f026b2cd1def187f3cbca4069c0 + https://github.com/PPUC/hub75#e75ce7f3d9e24efde57586bf194a1e96b79a5fe2 lib_ignore = WiFi AsyncUDP diff --git a/src/displays/PicoLedMatrix.cpp b/src/displays/PicoLedMatrix.cpp index a2f412a..b379d71 100644 --- a/src/displays/PicoLedMatrix.cpp +++ b/src/displays/PicoLedMatrix.cpp @@ -23,7 +23,7 @@ PicoLedMatrix::PicoLedMatrix() { // rgb565 > rgb888 "fast" pixel conversion init_rgb_tables(); - create_hub75_driver(TOTAL_WIDTH, PANEL_HEIGHT, PANEL_RUL6024, false); + create_hub75_driver(TOTAL_WIDTH, PANEL_HEIGHT, PANEL_DP3246, false); start_hub75_driver(); } From 235ca613bd4c5a22b818c0471e2c07079535ef1a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 26 Jan 2026 18:15:53 +0100 Subject: [PATCH 23/27] test --- platformio.ini | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 093ebf1..ec389f4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/hub75#e75ce7f3d9e24efde57586bf194a1e96b79a5fe2 + https://github.com/PPUC/hub75#c76e6a83320c53cd04f69c29335b92274469435e lib_ignore = SPI WiFi @@ -239,10 +239,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=41 -DSTROBE_PIN=42 -DOEN_PIN=43 - -DHUB75_CLK2=44 - -DHUB75_LAT2=45 - -DHUB75_OE2=46 - -DHUB75_P10_3535_16X32_4S=1 + -DHUB75_LINEDECODER_SM5368 [ppucdmd] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 @@ -253,7 +250,7 @@ board_build.filesystem_size = 1.5m lib_deps = thomasfredericks/Bounce2 https://github.com/PPUC/dmdreader#c627fbe48d67f094e4a59ecbea8bc4319e97a6d0 - https://github.com/PPUC/hub75#e75ce7f3d9e24efde57586bf194a1e96b79a5fe2 + https://github.com/PPUC/hub75#c76e6a83320c53cd04f69c29335b92274469435e lib_ignore = WiFi AsyncUDP From b592c541a37ecd95a79eb1471467a67332224149 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 26 Jan 2026 18:56:41 +0100 Subject: [PATCH 24/27] test --- platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index ec389f4..15c7ece 100644 --- a/platformio.ini +++ b/platformio.ini @@ -191,7 +191,6 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_LINEDECODER_SM5368=1 [env:pico2_128x32_ppucdmd] extends = pico From 2c7c7ad84d23ab8dc4d519b8bd5e2cb826471f55 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 26 Jan 2026 20:35:01 +0100 Subject: [PATCH 25/27] 1/16 --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 15c7ece..0d3bdb5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -191,6 +191,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 + -DHUB75_P3_1415_16S_64X64_S31=1 [env:pico2_128x32_ppucdmd] extends = pico From 0b4b9825524aa281d7a40baf190cefcedf1c5cd5 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 26 Jan 2026 23:20:00 +0100 Subject: [PATCH 26/27] inverted clock --- platformio.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0d3bdb5..182c4fe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/hub75#c76e6a83320c53cd04f69c29335b92274469435e + https://github.com/PPUC/hub75#60aab342dede78f92a252f6f9251936998b9b549 lib_ignore = SPI WiFi @@ -191,7 +191,6 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 - -DHUB75_P3_1415_16S_64X64_S31=1 [env:pico2_128x32_ppucdmd] extends = pico @@ -250,7 +249,7 @@ board_build.filesystem_size = 1.5m lib_deps = thomasfredericks/Bounce2 https://github.com/PPUC/dmdreader#c627fbe48d67f094e4a59ecbea8bc4319e97a6d0 - https://github.com/PPUC/hub75#c76e6a83320c53cd04f69c29335b92274469435e + https://github.com/PPUC/hub75#60aab342dede78f92a252f6f9251936998b9b549 lib_ignore = WiFi AsyncUDP From 34d02296e2763f71e412525f012f1f202f90caf7 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 27 Jan 2026 00:08:03 +0100 Subject: [PATCH 27/27] LATCH_BLANKING --- platformio.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 182c4fe..65b7986 100644 --- a/platformio.ini +++ b/platformio.ini @@ -135,7 +135,7 @@ board_build.arduino.earlephilhower.usb_pid = 0x1001 lib_deps = thomasfredericks/Bounce2 https://github.com/Cpasjuste/Adafruit_TinyUSB_Arduino#zedmd - https://github.com/PPUC/hub75#60aab342dede78f92a252f6f9251936998b9b549 + https://github.com/PPUC/hub75#012944057476da4e4e976db7ed3b5fbc0bb4f2d2 lib_ignore = SPI WiFi @@ -191,6 +191,7 @@ build_flags = ${pico.build_flags} -DCLK_PIN=11 -DSTROBE_PIN=12 -DOEN_PIN=13 + -DLATCH_BLANKING=4 [env:pico2_128x32_ppucdmd] extends = pico @@ -249,7 +250,7 @@ board_build.filesystem_size = 1.5m lib_deps = thomasfredericks/Bounce2 https://github.com/PPUC/dmdreader#c627fbe48d67f094e4a59ecbea8bc4319e97a6d0 - https://github.com/PPUC/hub75#60aab342dede78f92a252f6f9251936998b9b549 + https://github.com/PPUC/hub75#012944057476da4e4e976db7ed3b5fbc0bb4f2d2 lib_ignore = WiFi AsyncUDP