From 3880a5813758cbc058e7cd5d6d5a671a655f2b61 Mon Sep 17 00:00:00 2001 From: radex Date: Mon, 27 May 2024 13:35:38 +0200 Subject: [PATCH] Revert "optimize: use PWM interrupt based delays for precision and pipelining" This reverts commit 9f9d089e08edde53dbfe99617f444c4302a76aad. --- firmware/src/leds.cpp | 82 +++++++++-------------------------------- firmware/src/leds.pio | 4 +- firmware/src/leds.pio.h | 11 +++--- 3 files changed, 24 insertions(+), 73 deletions(-) diff --git a/firmware/src/leds.cpp b/firmware/src/leds.cpp index d4f701e..7b5c23b 100644 --- a/firmware/src/leds.cpp +++ b/firmware/src/leds.cpp @@ -3,7 +3,6 @@ #include "mbed_wait_api.h" #include "pico/multicore.h" #include "hardware/pio.h" -#include "hardware/irq.h" #include "leds.h" #include "leds.pio.h" @@ -11,9 +10,6 @@ PIO pusher_pio = pio0; uint pusher_sm = 255; // invalid -#define PWM_SLICE 0 -volatile bool delayFinished = true; - // NOTE: RCLK, SRCLK capture on *rising* edge inline void pulsePin(uint8_t pin) { gpio_put(pin, HIGH); @@ -36,8 +32,7 @@ inline void outputEnable(uint8_t pin, bool enable) { // we have COLOR_BITS-bit color depth, so 2^COLOR_BITS levels of brightness // we go from phase 0 to phase (COLOR_BITS-1) uint8_t brightnessPhase = 0; -// in nanoseconds -uint16_t brightnessPhaseDelays[COLOR_BITS] = {500, 1500, 3000, 20000, 60000}; +uint8_t brightnessPhaseDelays[COLOR_BITS] = {0, 1, 6, 20, 60}; // NOTE: Alignment required to allow 4-byte reads uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0}; @@ -82,24 +77,22 @@ void leds_disable() { outputEnable(ROW_OE, false); } -void leds_initPusher(); -void leds_init_pwm(); - void main2() { - leds_initPusher(); - leds_init_pwm(); + // where we're going, we don't need no interrupts + noInterrupts(); while (true) { leds_render(); } } +void leds_initPusher(); + void leds_initRenderer() { + leds_initPusher(); multicore_reset_core1(); multicore_launch_core1(main2); } -void leds_start_delay(); - void leds_render() { if (!ledBufferReady) { outputEnable(ROW_OE, false); @@ -107,14 +100,9 @@ void leds_render() { } // brightness phase + bool brightPhase = brightnessPhase >= 3; auto buffer = ledBuffer[brightnessPhase + 3]; - // configure delays - pwm_set_clkdiv_int_frac(PWM_SLICE, 1, 0); - // 8ns per cycle at 125MHz - auto delayTicks = brightnessPhaseDelays[brightnessPhase] / 8; - pwm_set_wrap(PWM_SLICE, delayTicks); - // hide output outputEnable(ROW_OE, false); @@ -127,6 +115,11 @@ void leds_render() { int bufferOffset = 0; for (int yModule = 0; yModule < ROW_MODULES; yModule++) { for (int moduleY = 0; moduleY < 20; moduleY++) { + // brigthness - pushing data takes time, so to maximize brightness (at high brightness phases) + // we want to keep the matrix on during update (except during latch). At low brightness phases, + // we want it off to actually be dim + outputEnable(ROW_OE, brightPhase); + // next row pulsePin(ROW_SRCLK); // only one row @@ -153,33 +146,22 @@ void leds_render() { pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues); } - // wait until previous row's delay is done - while (!delayFinished) { - tight_loop_contents(); - } - - // allow pusher to latch data - pusher_pio->irq_force = 1 << 0; - // wait until pushing and RCLK latch are done - while (!pio_interrupt_get(pusher_pio, 1)) { + while (!pio_interrupt_get(pusher_pio, 0)) { tight_loop_contents(); } - pio_interrupt_clear(pusher_pio, 1); + pio_interrupt_clear(pusher_pio, pusher_sm); - // enable output for specified time - leds_start_delay(); + // show for a certain period + outputEnable(ROW_OE, true); + busy_wait_us_32(brightnessPhaseDelays[brightnessPhase]); + outputEnable(ROW_OE, false); // next row bufferOffset += COL_MODULES; } } - // wait until last row's delay is done - while (!delayFinished) { - tight_loop_contents(); - } - // next brightness phase brightnessPhase = (brightnessPhase + 1) % COLOR_BITS; } @@ -222,31 +204,3 @@ void leds_initPusher() { pio_sm_init(pio, sm, offset, &config); pio_sm_set_enabled(pio, sm, true); } - -void leds_start_delay() { - // enable output, start PWM counter - delayFinished = false; - outputEnable(ROW_OE, true); - pwm_set_enabled(PWM_SLICE, true); -} - -void leds_pwm_interrupt_handler() { - // disable output - outputEnable(ROW_OE, false); - // stop PWM counter - pwm_set_enabled(PWM_SLICE, false); - // acknowledge interrupt - pwm_clear_irq(PWM_SLICE); - delayFinished = true; -} - -// We will use PWM to control OE signal with a precise delay -// Note that we only use PWM for timing, it doesn't actually drive the OE GPIO -// (timers are microsecond-resolution, and we need better than this) -void leds_init_pwm() { - irq_set_exclusive_handler(PWM_IRQ_WRAP, leds_pwm_interrupt_handler); - irq_set_enabled(PWM_IRQ_WRAP, true); - - pwm_clear_irq(PWM_SLICE); - pwm_set_irq_enabled(PWM_SLICE, true); -} diff --git a/firmware/src/leds.pio b/firmware/src/leds.pio index bf56d8e..b3c4b5e 100644 --- a/firmware/src/leds.pio +++ b/firmware/src/leds.pio @@ -22,10 +22,8 @@ end: jmp x-- end_of_row .wrap end_of_row: - ; wait for permission to latch onto output - wait 1 irq 0 ; indicate to main processor that row was processed - irq set 1 + irq set 0 ; clock RCLK (latch onto register output stage) set pins, 1 [3] set pins, 0 diff --git a/firmware/src/leds.pio.h b/firmware/src/leds.pio.h index 6abf1d3..c5eb55d 100644 --- a/firmware/src/leds.pio.h +++ b/firmware/src/leds.pio.h @@ -25,17 +25,16 @@ static const uint16_t leds_px_pusher_program_instructions[] = { 0x7028, // 3: out x, 8 side 0 0x0045, // 4: jmp x--, 5 // .wrap - 0x20c0, // 5: wait 1 irq, 0 - 0xc001, // 6: irq nowait 1 - 0xe301, // 7: set pins, 1 [3] - 0xe000, // 8: set pins, 0 - 0x0000, // 9: jmp 0 + 0xc000, // 5: irq nowait 0 + 0xe301, // 6: set pins, 1 [3] + 0xe000, // 7: set pins, 0 + 0x0000, // 8: jmp 0 }; #if !PICO_NO_HARDWARE static const struct pio_program leds_px_pusher_program = { .instructions = leds_px_pusher_program_instructions, - .length = 10, + .length = 9, .origin = -1, };