1
0
Fork 0

Merge branch 'main' into sd2

sd2
radex 2024-06-02 14:06:35 +02:00
commit 20acc815de
Signed by: radex
SSH Key Fingerprint: SHA256:hvqRXAGG1h89yqnS+cyFTLKQbzjWD4uXIqw7Y+0ws30
7 changed files with 116 additions and 27 deletions

View File

@ -56,3 +56,52 @@ int32_t gfx_decoder_handleLoop() {
} }
return 0; return 0;
} }
void gfx_decoder_setTestFrame() {
uint8_t buffer[ROW_COUNT * COL_COUNT] = {0};
// le boxes
for (int i = 0; i < 8; i++) {
uint8_t color = 1 << i;
int startX = (i % 4) * 10;
int startY = (i / 4) * 10;
// box with only 1<<n color
for (int x = startX; x < startX + 10; x++) {
for (int y = startY + 5; y < startY + 10; y++) {
buffer[y * ROW_COUNT + x] = color;
}
}
// box with 1<<n - 1 color for comparison
for (int x = startX; x < startX + 10; x++) {
for (int y = startY; y < startY + 5; y++) {
buffer[y * ROW_COUNT + x] = color - 1;
}
}
}
// full color
for (int x = 30; x < ROW_COUNT; x++) {
for (int y = 20; y < 25; y++) {
buffer[y * ROW_COUNT + x] = 255;
}
}
// smooth gradient - lower range
for (int x = 0; x < ROW_COUNT; x++) {
for (int y = 30; y < 35; y++) {
buffer[y * ROW_COUNT + x] = x;
}
}
// smooth gradient
float delta = 256 / (COL_COUNT);
for (int x = 0; x < ROW_COUNT; x++) {
for (int y = 35; y < 40; y++) {
buffer[y * ROW_COUNT + x] = (x + 1) * delta;
}
}
leds_set_framebuffer(buffer);
}

View File

@ -10,5 +10,6 @@ extern uint8_t gfxFrameBuffer[6400];
int32_t gfx_decoder_loadNextFrame(); int32_t gfx_decoder_loadNextFrame();
int32_t gfx_decoder_handleLoop(); int32_t gfx_decoder_handleLoop();
void gfx_decoder_setTestFrame();
#endif #endif

View File

@ -11,6 +11,8 @@ uint pusher_sm = 255; // invalid
uint delay_sm = 255; // invalid uint delay_sm = 255; // invalid
uint row_sm = 255; // invalid uint row_sm = 255; // invalid
#define LEDS_PIO_CLKDIV 1
// 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);
@ -34,16 +36,36 @@ inline void outputEnable(uint8_t pin, bool enable) {
uint8_t brightnessPhase = 0; uint8_t brightnessPhase = 0;
// delays in nanoseconds // delays in nanoseconds
#define NS_TO_DELAY(ns) ns / NS_PER_CYCLE #define NS_TO_DELAY(ns) (ns / NS_PER_CYCLE / LEDS_PIO_CLKDIV)
uint32_t brightnessPhaseDelays[COLOR_BITS] = { uint32_t brightnessPhaseDelays[COLOR_BITS] = {
NS_TO_DELAY(50), // NOTE: 100ns seems to be the minimum that's (barely) visible
NS_TO_DELAY(100), /* 1 */ NS_TO_DELAY(170),
NS_TO_DELAY(200), /* 2 */ NS_TO_DELAY(180),
NS_TO_DELAY(500), /* 4 */ NS_TO_DELAY(210),
NS_TO_DELAY(1500), /* 8 */ NS_TO_DELAY(540),
NS_TO_DELAY(6000), /* 16 */ NS_TO_DELAY(2300), // x2
NS_TO_DELAY(20000), /* 32 */ NS_TO_DELAY(3000), // x4
NS_TO_DELAY(60000), /* 64 */ NS_TO_DELAY(2500), // x10
/* 128 */ NS_TO_DELAY(3300), // x20
};
#define DITHERING_PHASES 20;
uint8_t ditheringPhase = 0;
uint8_t brightnessPhaseDithering[COLOR_BITS] = {
// Out of DITHERING_PHASES, how many of these should a given
// brightness phase be displayed?
// NOTE: This is done brecause for small delays, pixel pushing dominates the time, making
// the display's duty cycle (and hence brightness) low. But since these less significant bits
// contribute little to the overall brightness, and overall displaying time is short (a fraction of
// a framerate), we can skip displaying these small brightness levels most of the time.
/* 1 */ 1,
/* 2 */ 1,
/* 4 */ 1,
/* 8 */ 1,
/* 16 */ 2,
/* 32 */ 4,
/* 64 */ 10,
/* 128 */ 20,
}; };
// NOTE: Alignment required to allow 4-byte reads // NOTE: Alignment required to allow 4-byte reads
@ -102,18 +124,18 @@ void leds_set_framebuffer(uint8_t *buffer) {
} }
// set row shifting data // set row shifting data
bool firstRow = y == (ROW_COUNT - 1); bool firstRow = y == 0;
uint32_t rowPulses = 1; uint32_t extraPulses = 0;
if (moduleY == 0) { if (moduleY == 0) {
rowPulses++; extraPulses++;
} }
if (moduleY == 7 || moduleY == 14 || (moduleY == 0 && yModule != 0)) { if (moduleY == 7 || moduleY == 14 || (moduleY == 0 && yModule != 0)) {
rowPulses++; extraPulses++;
} }
uint32_t rowData = firstRow | (rowPulses << 1); uint32_t rowData = firstRow | (extraPulses << 1);
ledBuffer[bi][outputYOffset + COL_MODULES] = rowData; ledBuffer[bi][outputYOffset + COL_MODULES] = rowData;
} }
} }
@ -183,11 +205,16 @@ void leds_initRenderer() {
multicore_launch_core1(main2); multicore_launch_core1(main2);
} }
void leds_nextPhase();
void leds_render() { void leds_render() {
if (!ledBufferReady) { if (!ledBufferReady) {
return; return;
} }
// next brightness phase
leds_nextPhase();
auto buffer = ledBuffer[brightnessPhase]; auto buffer = ledBuffer[brightnessPhase];
auto delayData = brightnessPhaseDelays[brightnessPhase]; auto delayData = brightnessPhaseDelays[brightnessPhase];
@ -209,9 +236,19 @@ void leds_render() {
// set delay data // set delay data
pio_sm_put_blocking(leds_pio, delay_sm, delayData); pio_sm_put_blocking(leds_pio, delay_sm, delayData);
} }
}
// next brightness phase void leds_nextPhase() {
brightnessPhase = (brightnessPhase + 1) % COLOR_BITS; brightnessPhase++;
if (brightnessPhase == COLOR_BITS) {
brightnessPhase = 0;
ditheringPhase = (ditheringPhase + 1) % DITHERING_PHASES;
}
while (ditheringPhase >= brightnessPhaseDithering[brightnessPhase]) {
brightnessPhase++;
}
} }
void leds_initPusher() { void leds_initPusher() {
@ -222,7 +259,7 @@ void leds_initPusher() {
uint offset = pio_add_program(pio, &leds_px_pusher_program); uint offset = pio_add_program(pio, &leds_px_pusher_program);
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, LEDS_PIO_CLKDIV, 0);
// Shift OSR to the right, autopull // Shift OSR to the right, autopull
sm_config_set_out_shift(&config, true, true, 32); sm_config_set_out_shift(&config, true, true, 32);
@ -262,7 +299,7 @@ void leds_initRowSelector() {
uint offset = pio_add_program(pio, &leds_row_selector_program); uint offset = pio_add_program(pio, &leds_row_selector_program);
pio_sm_config config = leds_row_selector_program_get_default_config(offset); pio_sm_config config = leds_row_selector_program_get_default_config(offset);
sm_config_set_clkdiv_int_frac(&config, 1, 0); sm_config_set_clkdiv_int_frac(&config, LEDS_PIO_CLKDIV, 0);
// Shift OSR to the right, autopull // Shift OSR to the right, autopull
sm_config_set_out_shift(&config, true, true, 32); sm_config_set_out_shift(&config, true, true, 32);
@ -291,7 +328,7 @@ void leds_initDelay() {
uint offset = pio_add_program(pio, &leds_delay_program); uint offset = pio_add_program(pio, &leds_delay_program);
pio_sm_config config = leds_delay_program_get_default_config(offset); pio_sm_config config = leds_delay_program_get_default_config(offset);
sm_config_set_clkdiv_int_frac(&config, 1, 0); sm_config_set_clkdiv_int_frac(&config, LEDS_PIO_CLKDIV, 0);
// Shift OSR to the right, autopull // Shift OSR to the right, autopull
sm_config_set_out_shift(&config, true, true, 32); sm_config_set_out_shift(&config, true, true, 32);

View File

@ -24,10 +24,10 @@
#define COLOR_BITS 8 #define COLOR_BITS 8
#define FPS 30 #define FPS 30
#define MS_PER_FRAME 1000 / FPS #define MS_PER_FRAME (1000 / FPS)
#define CPU_MHZ 125 #define CPU_MHZ 125
#define NS_PER_CYCLE 1000 / CPU_MHZ #define NS_PER_CYCLE (1000 / CPU_MHZ)
void leds_init(); void leds_init();
void leds_initRenderer(); void leds_initRenderer();

View File

@ -1,6 +1,6 @@
.define public irq_did_latch 0 .define public irq_did_latch 0
.define public irq_delaying 1
.define public irq_row_selected 1 .define public irq_row_selected 1
.define public irq_delaying 2
; TODO: check if delays can be lowered with a PCB ; TODO: check if delays can be lowered with a PCB
.define public srclk_0_delay 1 .define public srclk_0_delay 1
@ -48,7 +48,7 @@ entry_point:
.wrap_target .wrap_target
; LSB=1 indicates first (bottom) row, ergo, high SER for the first pulse ; LSB=1 indicates first (bottom) row, ergo, high SER for the first pulse
out pins, 1 side 0 [srclk_0_delay] out pins, 1 side 0 [srclk_0_delay]
; The rest of the word indicates number of SRCLK pulses ; The rest of the word indicates number of extra SRCLK pulses
out x, 31 out x, 31
loop: loop:
; pulse SRCLK x times ; pulse SRCLK x times

View File

@ -9,8 +9,8 @@
#endif #endif
#define irq_did_latch 0 #define irq_did_latch 0
#define irq_delaying 1
#define irq_row_selected 1 #define irq_row_selected 1
#define irq_delaying 2
#define srclk_0_delay 1 #define srclk_0_delay 1
#define srclk_1_delay 2 #define srclk_1_delay 2
#define rclk_1_delay 3 #define rclk_1_delay 3
@ -29,7 +29,7 @@ static const uint16_t leds_px_pusher_program_instructions[] = {
0x1a41, // 2: jmp x--, 1 side 1 [2] 0x1a41, // 2: jmp x--, 1 side 1 [2]
0x7028, // 3: out x, 8 side 0 0x7028, // 3: out x, 8 side 0
0x0020, // 4: jmp !x, 0 0x0020, // 4: jmp !x, 0
0x2041, // 5: wait 0 irq, 1 0x2042, // 5: wait 0 irq, 2
0x20c1, // 6: wait 1 irq, 1 0x20c1, // 6: wait 1 irq, 1
0xc000, // 7: irq nowait 0 0xc000, // 7: irq nowait 0
0xe301, // 8: set pins, 1 [3] 0xe301, // 8: set pins, 1 [3]
@ -98,10 +98,10 @@ static inline pio_sm_config leds_row_selector_program_get_default_config(uint of
static const uint16_t leds_delay_program_instructions[] = { static const uint16_t leds_delay_program_instructions[] = {
// .wrap_target // .wrap_target
0x20c0, // 0: wait 1 irq, 0 0x20c0, // 0: wait 1 irq, 0
0xc001, // 1: irq nowait 1 0xc002, // 1: irq nowait 2
0x6020, // 2: out x, 32 0x6020, // 2: out x, 32
0x1043, // 3: jmp x--, 3 side 0 0x1043, // 3: jmp x--, 3 side 0
0xd841, // 4: irq clear 1 side 1 0xd842, // 4: irq clear 2 side 1
// .wrap // .wrap
}; };

View File

@ -30,6 +30,8 @@ void setup() {
sd_loadPlaylist(); sd_loadPlaylist();
loadVideo(0); loadVideo(0);
// gfx_decoder_setTestFrame();
} }
size_t currentVideoIndex = 0; size_t currentVideoIndex = 0;