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 "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);
}

View File

@ -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

View File

@ -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,
};