From f2a2b931f828508fcfaf188756954c384155042d Mon Sep 17 00:00:00 2001 From: radex Date: Fri, 24 May 2024 18:01:23 +0200 Subject: [PATCH] pio poc --- firmware/src/leds.cpp | 76 ++++++++++++++++++++++++++++++++--------- firmware/src/leds.pio | 8 +++++ firmware/src/leds.pio.h | 42 +++++++++++++++++++++++ 3 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 firmware/src/leds.pio create mode 100644 firmware/src/leds.pio.h diff --git a/firmware/src/leds.cpp b/firmware/src/leds.cpp index c96aa0d..da10f19 100644 --- a/firmware/src/leds.cpp +++ b/firmware/src/leds.cpp @@ -2,11 +2,21 @@ #include "hardware/gpio.h" #include "mbed_wait_api.h" #include "pico/multicore.h" +#include "hardware/pio.h" #include "leds.h" +#include "leds.pio.h" +PIO pusher_pio = pio0; +uint pusher_sm = 255; // invalid + +// NOTE: RCLK, SRCLK capture on *rising* edge inline void pulsePin(uint8_t pin) { gpio_put(pin, HIGH); + // there are glitches without this (maybe just due to breadboard...) + _NOP(); + _NOP(); + _NOP(); gpio_put(pin, LOW); } @@ -37,6 +47,7 @@ void leds_init() { // set up col pins pinMode(COL_SER, OUTPUT); pinMode(COL_OE, OUTPUT); + outputEnable(ROW_OE, false); pinMode(COL_RCLK, OUTPUT); pinMode(COL_SRCLK, OUTPUT); pinMode(COL_SRCLR, OUTPUT); @@ -44,6 +55,7 @@ void leds_init() { // set up row pins pinMode(ROW_SER, OUTPUT); pinMode(ROW_OE, OUTPUT); + outputEnable(ROW_OE, false); pinMode(ROW_RCLK, OUTPUT); pinMode(ROW_SRCLK, OUTPUT); pinMode(ROW_SRCLR, OUTPUT); @@ -70,10 +82,10 @@ void main2() { } } +void leds_initPusher(); + void leds_initRenderer() { - // launch core1 - // NOTE: For some reason, without delay, core1 doesn't start? - // delay(500); + leds_initPusher(); multicore_reset_core1(); multicore_launch_core1(main2); } @@ -94,10 +106,12 @@ void leds_render() { // we want to keep the matrix on during update (except during latch). At low brightness phases, // we want it off to actually be dim bool brightPhase = brightnessPhase >= 2; - // digitalWrite(ROW_OE, !brightPhase); + digitalWrite(ROW_OE, !brightPhase); // next row - pulsePin(ROW_SRCLK); + gpio_put(ROW_SRCLK, HIGH); + busy_wait_us_32(1); + gpio_put(ROW_SRCLK, LOW); // only one row digitalWrite(ROW_SER, LOW); @@ -111,29 +125,26 @@ void leds_render() { pulsePin(ROW_SRCLK); } - // clear columns - clearShiftReg(COL_SRCLK, COL_SRCLR); - // set row data + size_t rowOffset = y * COL_COUNT; for (int x = 0; x < COL_COUNT; x++) { // get value // NOTE: values are loaded right-left - uint8_t pxValue = framebuffer[y * ROW_COUNT + x]; - // apply brightness - bool gotLight = (pxValue >> (4 + brightnessPhase)) & 1; - // set value (note: inverted logic) - gpio_put(COL_SER, !gotLight); - // push value - pulsePin(COL_SRCLK); + uint8_t pxValue = framebuffer[rowOffset + x]; // we use 7/8 stages on shift registers + 1 is unused int moduleX = x % 20; if (moduleX == 0) { - pulsePin(COL_SRCLK); + pio_sm_put_blocking(pusher_pio, pusher_sm, 0); } if (moduleX == 6 || moduleX == 13 || moduleX == 19) { - pulsePin(COL_SRCLK); + pio_sm_put_blocking(pusher_pio, pusher_sm, 0); } + + // apply brightness + bool gotLight = (pxValue >> (4 + brightnessPhase)) & 1; + // push value + pio_sm_put_blocking(pusher_pio, pusher_sm, gotLight); } // disable columns before latch @@ -152,3 +163,34 @@ void leds_render() { // next brightness phase brightnessPhase = (brightnessPhase + 1) % 4; } + +void leds_initPusher() { + PIO pio = pusher_pio; + uint sm = pio_claim_unused_sm(pio, true); + pusher_sm = sm; + + uint offset = pio_add_program(pio, &leds_px_pusher_program); + + uint dataPin = COL_SER; + uint latchPin = COL_SRCLK; + + pio_sm_config config = leds_px_pusher_program_get_default_config(offset); + sm_config_set_clkdiv_int_frac(&config, 1, 0); + + // Set OUT (data) pin, connect to pad, set as output + sm_config_set_out_pins(&config, dataPin, 1); + pio_gpio_init(pio, dataPin); + pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, true); + + // data is inverted + gpio_set_outover(dataPin, GPIO_OVERRIDE_INVERT); + + // Set SET (latch) pin, connect to pad, set as output + sm_config_set_sideset_pins(&config, latchPin); + pio_gpio_init(pio, latchPin); + pio_sm_set_consecutive_pindirs(pio, sm, latchPin, 1, true); + + // Load our configuration, and jump to the start of the program + pio_sm_init(pio, sm, offset, &config); + pio_sm_set_enabled(pio, sm, true); +} diff --git a/firmware/src/leds.pio b/firmware/src/leds.pio new file mode 100644 index 0000000..19b512d --- /dev/null +++ b/firmware/src/leds.pio @@ -0,0 +1,8 @@ +.program leds_px_pusher +.side_set 1 opt +.wrap_target +public entry_point: + pull side 0 + out pins, 1 + nop side 1 [1] +.wrap diff --git a/firmware/src/leds.pio.h b/firmware/src/leds.pio.h new file mode 100644 index 0000000..16c94d4 --- /dev/null +++ b/firmware/src/leds.pio.h @@ -0,0 +1,42 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// -------------- // +// leds_px_pusher // +// -------------- // + +#define leds_px_pusher_wrap_target 0 +#define leds_px_pusher_wrap 2 + +#define leds_px_pusher_offset_entry_point 0u + +static const uint16_t leds_px_pusher_program_instructions[] = { + // .wrap_target + 0x90a0, // 0: pull block side 0 + 0x6001, // 1: out pins, 1 + 0xb942, // 2: nop side 1 [1] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program leds_px_pusher_program = { + .instructions = leds_px_pusher_program_instructions, + .length = 3, + .origin = -1, +}; + +static inline pio_sm_config leds_px_pusher_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + leds_px_pusher_wrap_target, offset + leds_px_pusher_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} +#endif +