1
0
Fork 0

Revert "optimize: use PWM interrupt based delays for precision and pipelining"

This reverts commit 9f9d089e08.
sd2
radex 2024-05-27 13:35:38 +02:00
parent 647224897e
commit 3880a58137
Signed by: radex
SSH Key Fingerprint: SHA256:hvqRXAGG1h89yqnS+cyFTLKQbzjWD4uXIqw7Y+0ws30
3 changed files with 24 additions and 73 deletions

View File

@ -3,7 +3,6 @@
#include "mbed_wait_api.h" #include "mbed_wait_api.h"
#include "pico/multicore.h" #include "pico/multicore.h"
#include "hardware/pio.h" #include "hardware/pio.h"
#include "hardware/irq.h"
#include "leds.h" #include "leds.h"
#include "leds.pio.h" #include "leds.pio.h"
@ -11,9 +10,6 @@
PIO pusher_pio = pio0; PIO pusher_pio = pio0;
uint pusher_sm = 255; // invalid uint pusher_sm = 255; // invalid
#define PWM_SLICE 0
volatile bool delayFinished = true;
// NOTE: RCLK, SRCLK capture on *rising* edge // NOTE: RCLK, SRCLK capture on *rising* edge
inline void pulsePin(uint8_t pin) { inline void pulsePin(uint8_t pin) {
gpio_put(pin, HIGH); 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 have COLOR_BITS-bit color depth, so 2^COLOR_BITS levels of brightness
// we go from phase 0 to phase (COLOR_BITS-1) // we go from phase 0 to phase (COLOR_BITS-1)
uint8_t brightnessPhase = 0; uint8_t brightnessPhase = 0;
// in nanoseconds uint8_t brightnessPhaseDelays[COLOR_BITS] = {0, 1, 6, 20, 60};
uint16_t brightnessPhaseDelays[COLOR_BITS] = {500, 1500, 3000, 20000, 60000};
// NOTE: Alignment required to allow 4-byte reads // NOTE: Alignment required to allow 4-byte reads
uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0}; uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0};
@ -82,24 +77,22 @@ void leds_disable() {
outputEnable(ROW_OE, false); outputEnable(ROW_OE, false);
} }
void leds_initPusher();
void leds_init_pwm();
void main2() { void main2() {
leds_initPusher(); // where we're going, we don't need no interrupts
leds_init_pwm(); noInterrupts();
while (true) { while (true) {
leds_render(); leds_render();
} }
} }
void leds_initPusher();
void leds_initRenderer() { void leds_initRenderer() {
leds_initPusher();
multicore_reset_core1(); multicore_reset_core1();
multicore_launch_core1(main2); multicore_launch_core1(main2);
} }
void leds_start_delay();
void leds_render() { void leds_render() {
if (!ledBufferReady) { if (!ledBufferReady) {
outputEnable(ROW_OE, false); outputEnable(ROW_OE, false);
@ -107,14 +100,9 @@ void leds_render() {
} }
// brightness phase // brightness phase
bool brightPhase = brightnessPhase >= 3;
auto buffer = ledBuffer[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 // hide output
outputEnable(ROW_OE, false); outputEnable(ROW_OE, false);
@ -127,6 +115,11 @@ void leds_render() {
int bufferOffset = 0; int bufferOffset = 0;
for (int yModule = 0; yModule < ROW_MODULES; yModule++) { for (int yModule = 0; yModule < ROW_MODULES; yModule++) {
for (int moduleY = 0; moduleY < 20; moduleY++) { 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 // next row
pulsePin(ROW_SRCLK); pulsePin(ROW_SRCLK);
// only one row // only one row
@ -153,33 +146,22 @@ void leds_render() {
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues); 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 // 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(); tight_loop_contents();
} }
pio_interrupt_clear(pusher_pio, 1); pio_interrupt_clear(pusher_pio, pusher_sm);
// enable output for specified time // show for a certain period
leds_start_delay(); outputEnable(ROW_OE, true);
busy_wait_us_32(brightnessPhaseDelays[brightnessPhase]);
outputEnable(ROW_OE, false);
// next row // next row
bufferOffset += COL_MODULES; bufferOffset += COL_MODULES;
} }
} }
// wait until last row's delay is done
while (!delayFinished) {
tight_loop_contents();
}
// next brightness phase // next brightness phase
brightnessPhase = (brightnessPhase + 1) % COLOR_BITS; brightnessPhase = (brightnessPhase + 1) % COLOR_BITS;
} }
@ -222,31 +204,3 @@ void leds_initPusher() {
pio_sm_init(pio, sm, offset, &config); pio_sm_init(pio, sm, offset, &config);
pio_sm_set_enabled(pio, sm, true); 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);
}

View File

@ -22,10 +22,8 @@ end:
jmp x-- end_of_row jmp x-- end_of_row
.wrap .wrap
end_of_row: end_of_row:
; wait for permission to latch onto output
wait 1 irq 0
; indicate to main processor that row was processed ; indicate to main processor that row was processed
irq set 1 irq set 0
; clock RCLK (latch onto register output stage) ; clock RCLK (latch onto register output stage)
set pins, 1 [3] set pins, 1 [3]
set pins, 0 set pins, 0

View File

@ -25,17 +25,16 @@ static const uint16_t leds_px_pusher_program_instructions[] = {
0x7028, // 3: out x, 8 side 0 0x7028, // 3: out x, 8 side 0
0x0045, // 4: jmp x--, 5 0x0045, // 4: jmp x--, 5
// .wrap // .wrap
0x20c0, // 5: wait 1 irq, 0 0xc000, // 5: irq nowait 0
0xc001, // 6: irq nowait 1 0xe301, // 6: set pins, 1 [3]
0xe301, // 7: set pins, 1 [3] 0xe000, // 7: set pins, 0
0xe000, // 8: set pins, 0 0x0000, // 8: jmp 0
0x0000, // 9: jmp 0
}; };
#if !PICO_NO_HARDWARE #if !PICO_NO_HARDWARE
static const struct pio_program leds_px_pusher_program = { static const struct pio_program leds_px_pusher_program = {
.instructions = leds_px_pusher_program_instructions, .instructions = leds_px_pusher_program_instructions,
.length = 10, .length = 9,
.origin = -1, .origin = -1,
}; };