mirror of https://github.com/radex/radmatrix.git
Revert "optimize: use PWM interrupt based delays for precision and pipelining"
This reverts commit 9f9d089e08
.
sd2
parent
647224897e
commit
3880a58137
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue