mirror of https://github.com/radex/radmatrix.git
pio faster
parent
f2a2b931f8
commit
9307c59b3e
|
@ -16,7 +16,6 @@ inline void pulsePin(uint8_t pin) {
|
||||||
// there are glitches without this (maybe just due to breadboard...)
|
// there are glitches without this (maybe just due to breadboard...)
|
||||||
_NOP();
|
_NOP();
|
||||||
_NOP();
|
_NOP();
|
||||||
_NOP();
|
|
||||||
gpio_put(pin, LOW);
|
gpio_put(pin, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +34,8 @@ inline void outputEnable(uint8_t pin, bool enable) {
|
||||||
uint8_t brightnessPhase = 0;
|
uint8_t brightnessPhase = 0;
|
||||||
uint8_t brightnessPhaseDelays[] = {1, 10, 30, 100};
|
uint8_t brightnessPhaseDelays[] = {1, 10, 30, 100};
|
||||||
|
|
||||||
uint8_t framebuffer[ROW_COUNT * COL_COUNT] = {0};
|
// NOTE: Alignment required to allow 4-byte reads
|
||||||
|
uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0};
|
||||||
|
|
||||||
void leds_init() {
|
void leds_init() {
|
||||||
memset(framebuffer, 0, sizeof(framebuffer));
|
memset(framebuffer, 0, sizeof(framebuffer));
|
||||||
|
@ -98,7 +98,7 @@ void leds_render() {
|
||||||
clearShiftReg(ROW_SRCLK, ROW_SRCLR);
|
clearShiftReg(ROW_SRCLK, ROW_SRCLR);
|
||||||
|
|
||||||
// start selecting rows
|
// start selecting rows
|
||||||
digitalWrite(ROW_SER, HIGH);
|
gpio_put(ROW_SER, HIGH);
|
||||||
|
|
||||||
for (int yCount = 0; yCount < ROW_COUNT; yCount++) {
|
for (int yCount = 0; yCount < ROW_COUNT; yCount++) {
|
||||||
int y = ROW_COUNT - 1 - yCount;
|
int y = ROW_COUNT - 1 - yCount;
|
||||||
|
@ -106,14 +106,12 @@ void leds_render() {
|
||||||
// we want to keep the matrix on during update (except during latch). At low 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
|
// we want it off to actually be dim
|
||||||
bool brightPhase = brightnessPhase >= 2;
|
bool brightPhase = brightnessPhase >= 2;
|
||||||
digitalWrite(ROW_OE, !brightPhase);
|
outputEnable(ROW_OE, brightPhase);
|
||||||
|
|
||||||
// next row
|
// next row
|
||||||
gpio_put(ROW_SRCLK, HIGH);
|
pulsePin(ROW_SRCLK);
|
||||||
busy_wait_us_32(1);
|
|
||||||
gpio_put(ROW_SRCLK, LOW);
|
|
||||||
// only one row
|
// only one row
|
||||||
digitalWrite(ROW_SER, LOW);
|
gpio_put(ROW_SER, LOW);
|
||||||
|
|
||||||
// we use 7/8 stages on shift registers + 1 is unused
|
// we use 7/8 stages on shift registers + 1 is unused
|
||||||
int moduleY = yCount % 20;
|
int moduleY = yCount % 20;
|
||||||
|
@ -126,26 +124,53 @@ void leds_render() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set row data
|
// 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
|
// NOTE: values are loaded right-left
|
||||||
uint8_t pxValue = framebuffer[rowOffset + x];
|
// Optimized implementation: use PIO, avoid division, modulo, etc...
|
||||||
|
// we use 7/8 stages of each shift register + 1 is unused so we need to do
|
||||||
|
// silly shit
|
||||||
|
// TODO: Some ideas for future optimization:
|
||||||
|
// - see if we can disable px pusher delays on improved electric interface
|
||||||
|
// - use a profiler to see how the inner loop can be improved
|
||||||
|
// - do the shift register bullshit once per frame, so that data can be loaded into
|
||||||
|
// registers with aligned access, DMA, etc.
|
||||||
|
// - improve outer loop which adds 2us of processing on each loop
|
||||||
|
// - change busy wait into some kind of interrupt-based thing so that processing can continue
|
||||||
|
// - latch row and clock simultaneously, avoid disabling output
|
||||||
|
uint8_t *buffer = framebuffer + (y * COL_COUNT);
|
||||||
|
for (int xModule = 0; xModule < COL_MODULES; xModule++) {
|
||||||
|
uint32_t pxValues;
|
||||||
|
|
||||||
// we use 7/8 stages on shift registers + 1 is unused
|
// placeholder at 0; pixels 0, 1, 2
|
||||||
int moduleX = x % 20;
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer));
|
||||||
if (moduleX == 0) {
|
// pxValues = pxValues << 8;
|
||||||
pio_sm_put_blocking(pusher_pio, pusher_sm, 0);
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
}
|
|
||||||
if (moduleX == 6 || moduleX == 13 || moduleX == 19) {
|
// pixels 3, 4, 5, placeholder at 6
|
||||||
pio_sm_put_blocking(pusher_pio, pusher_sm, 0);
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer + 3));
|
||||||
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
|
|
||||||
|
// pixels 6, 7, 8, 9
|
||||||
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer + 6));
|
||||||
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
|
|
||||||
|
// pixels 10, 11, 12, placeholder at 13
|
||||||
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer + 10));
|
||||||
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
|
|
||||||
|
// pixels 13, 14, 15, 16
|
||||||
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer + 13));
|
||||||
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
|
|
||||||
|
// pixels 17, 18, placeholder, 19
|
||||||
|
pxValues = *(reinterpret_cast<uint32_t *>(buffer + 17));
|
||||||
|
// pxValues = (pxValues & 0x0000ffff) | ((pxValues & 0x00ff0000) << 8);
|
||||||
|
pio_sm_put_blocking(pusher_pio, pusher_sm, pxValues >> brightnessPhase);
|
||||||
|
|
||||||
|
buffer += 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply brightness
|
// wait for all data to be shifted out
|
||||||
bool gotLight = (pxValue >> (4 + brightnessPhase)) & 1;
|
pio_sm_drain_tx_fifo(pusher_pio, pusher_sm);
|
||||||
// push value
|
|
||||||
pio_sm_put_blocking(pusher_pio, pusher_sm, gotLight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable columns before latch
|
// disable columns before latch
|
||||||
outputEnable(ROW_OE, false);
|
outputEnable(ROW_OE, false);
|
||||||
|
@ -177,6 +202,9 @@ void leds_initPusher() {
|
||||||
pio_sm_config config = leds_px_pusher_program_get_default_config(offset);
|
pio_sm_config config = leds_px_pusher_program_get_default_config(offset);
|
||||||
sm_config_set_clkdiv_int_frac(&config, 1, 0);
|
sm_config_set_clkdiv_int_frac(&config, 1, 0);
|
||||||
|
|
||||||
|
// Shift OSR to the right, autopull
|
||||||
|
sm_config_set_out_shift(&config, true, true, 32);
|
||||||
|
|
||||||
// Set OUT (data) pin, connect to pad, set as output
|
// Set OUT (data) pin, connect to pad, set as output
|
||||||
sm_config_set_out_pins(&config, dataPin, 1);
|
sm_config_set_out_pins(&config, dataPin, 1);
|
||||||
pio_gpio_init(pio, dataPin);
|
pio_gpio_init(pio, dataPin);
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
#define ROW_SRCLR 10
|
#define ROW_SRCLR 10
|
||||||
|
|
||||||
#define ROW_COUNT 40
|
#define ROW_COUNT 40
|
||||||
#define COL_COUNT 40
|
#define COL_MODULES 2
|
||||||
|
#define COL_COUNT COL_MODULES * 20
|
||||||
|
|
||||||
#define FPS 30
|
#define FPS 30
|
||||||
#define MS_PER_FRAME 1000 / FPS
|
#define MS_PER_FRAME 1000 / FPS
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
.side_set 1 opt
|
.side_set 1 opt
|
||||||
.wrap_target
|
.wrap_target
|
||||||
public entry_point:
|
public entry_point:
|
||||||
pull side 0
|
out null, 4 side 0 [0] ; ignore 4 least significant digits
|
||||||
out pins, 1
|
out pins, 1 ; set bit (shifted for brightness phase by C code)
|
||||||
nop side 1 [1]
|
out null, 3 side 1 [1] ; ignore remaining bits, latch data, allow time for latching
|
||||||
.wrap
|
.wrap
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
|
|
||||||
static const uint16_t leds_px_pusher_program_instructions[] = {
|
static const uint16_t leds_px_pusher_program_instructions[] = {
|
||||||
// .wrap_target
|
// .wrap_target
|
||||||
0x90a0, // 0: pull block side 0
|
0x7064, // 0: out null, 4 side 0
|
||||||
0x6001, // 1: out pins, 1
|
0x6001, // 1: out pins, 1
|
||||||
0xb942, // 2: nop side 1 [1]
|
0x7963, // 2: out null, 3 side 1 [1]
|
||||||
// .wrap
|
// .wrap
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue