Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
746980c
remove algorithm for HD and romstar
PastorL69 Mar 12, 2026
b00b5c8
fix ribbon cable pull for capcom HD
PastorL69 Mar 12, 2026
525857a
more forgiving algorithm
PastorL69 Mar 12, 2026
5df0ffd
add some brackets
PastorL69 Mar 12, 2026
f795884
every third pixel
PastorL69 Mar 12, 2026
33876f0
skip more pixels
PastorL69 Mar 12, 2026
8b200b3
The algorithm is too heavy for Capcom HD.
PastorL69 Mar 12, 2026
916d329
spike check
PastorL69 Mar 12, 2026
2f39cb8
correctly set and parse dmd_clkdiv
PastorL69 Mar 12, 2026
fbe6697
revert sega to previous values because 125MHz clkdiv was set incorrectly
PastorL69 Mar 12, 2026
a1de57b
hook good now?
PastorL69 Mar 12, 2026
1a63e5b
typo
PastorL69 Mar 12, 2026
046c68d
hook specific change, faster detection?
PastorL69 Mar 13, 2026
561254d
sync frame when ribbon cable is pulled
PastorL69 Mar 14, 2026
224c493
try without delay
PastorL69 Mar 14, 2026
6c80c94
reset pio isr instead of DMA.
PastorL69 Mar 14, 2026
1ee84aa
quick one
PastorL69 Mar 14, 2026
23412d2
quick one #2
PastorL69 Mar 14, 2026
2af1a32
correct way of handling resync
PastorL69 Mar 14, 2026
e2d9574
dmd pio
PastorL69 Mar 15, 2026
ffc6dc0
wait blocking
PastorL69 Mar 15, 2026
a70493e
x16 v2 frame sync test
PastorL69 Mar 15, 2026
5237fda
different approach
PastorL69 Mar 15, 2026
a454fa7
revert to only line build
PastorL69 Mar 15, 2026
be55bd3
also clear y in case of lsb msb frame
PastorL69 Mar 15, 2026
0a0543e
stable build
PastorL69 Mar 15, 2026
c3a2216
document x16 v2 resync
PastorL69 Mar 15, 2026
6ab8823
dma reset needed?
PastorL69 Mar 16, 2026
0f1ee36
extra test
PastorL69 Mar 16, 2026
51168ca
clean up code and add comments
PastorL69 Mar 16, 2026
834075e
comments
PastorL69 Mar 16, 2026
e765a12
add back dma reset
PastorL69 Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Pi Pico is directly connected to the 6 DMD data lines. Communication between
On this IRQ line, the Pico signals that new data is available and consumer must start the data transfer.
Since not any consumer (especially the Raspberry Pi) can act as an SPI slave this method is used.

## Currently supported hardware systems
## Officially Supported hardware systems

* WPC95 & WPC -> 128x32
* Data East -> 128x32 & 128x16
Expand Down
12 changes: 4 additions & 8 deletions src/dmd_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@
#include "hardware/gpio.h"
#include "hardware/pio.h"

// Derive divider from current clock so PIO runs at ~125 MHz reference
float dmd_interface_125mhz_clk_divider =
(float)(clock_get_hz(clk_sys)) / 125000000.0f; // scales automatically

// Init the DMD reader (dots) PIO program, common for all DMD types.
void dmd_reader_program_init(PIO pio, uint sm, uint offset, pio_sm_config c,
void dmd_reader_program_init(float dmd_clkdiv, PIO pio, uint sm, uint offset, pio_sm_config c,
uint in_base_pin) {
sm_config_set_in_pins(&c, in_base_pin);

Expand All @@ -48,7 +44,7 @@ void dmd_reader_program_init(PIO pio, uint sm, uint offset, pio_sm_config c,
pio_sm_set_consecutive_pindirs(pio, sm, SDATA_X16_PADDING, 1, false);

// Make sure we run this sm with a 125MHz clk
sm_config_set_clkdiv(&c, dmd_interface_125mhz_clk_divider);
sm_config_set_clkdiv(&c, dmd_clkdiv);
}
// Connect these GPIOs to this PIO block
pio_gpio_init(pio, SDATA);
Expand All @@ -71,7 +67,7 @@ void dmd_reader_program_init(PIO pio, uint sm, uint offset, pio_sm_config c,
}

// Init the framedetect PIO program.
void dmd_framedetect_program_init(PIO pio, uint sm, uint offset,
void dmd_framedetect_program_init(float dmd_clkdiv, PIO pio, uint sm, uint offset,
pio_sm_config c, const uint* input_pins,
uint num_input_pins, uint jump_pin) {
if (jump_pin > 0) {
Expand All @@ -92,7 +88,7 @@ void dmd_framedetect_program_init(PIO pio, uint sm, uint offset,
0);

// Make sure we run this sm with a 125MHz clk
sm_config_set_clkdiv(&c, dmd_interface_125mhz_clk_divider);
sm_config_set_clkdiv(&c, dmd_clkdiv);

// Load our configuration, do not yet start the program
pio_sm_init(pio, sm, offset, &c);
Expand Down
2 changes: 1 addition & 1 deletion src/dmd_interface_capcom_hd.pio
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ rclk_loop:
wait 1 gpio RCLK
wait 0 gpio RCLK
jmp x-- rclk_loop
nop [3]
irq PLANE_START_IRQ
wait 1 gpio RDATA
.wrap
11 changes: 6 additions & 5 deletions src/dmd_interface_de_x16_v2.pio
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
.program dmd_reader_de_x16_v2

wait irq FRAME_START_IRQ ; we only check for an IRQ once because of limitations
mov isr, null ; clean the isr before starting a new frame

.wrap_target

Expand All @@ -32,7 +33,7 @@ dotloop:
jmp y-- start

skip:
mov x, osr ; copy 8192 to x
mov x, osr ; copy 4096 to x
lsb_msb_check:
jmp pin reload_dotloop_y ; if DOTCLK is high, it means we will have a valid LSB + MSB row
jmp x-- lsb_msb_check ; loop for ~65.5 µs (based on 125MHz clkdiv)
Expand Down Expand Up @@ -62,15 +63,15 @@ reload_dotloop_y:

wait_low:
wait 0 gpio DE ; Wait for DE to go low
mov x, osr ; Use x as storage for 3000 iterations
mov x, osr ; Use x as storage for 2500 iterations

delay_loop:
jmp x-- delay_loop ; Decrement x and repeat until zero
jmp x-- delay_loop ; Decrement x and repeat until zero

; After ~16 µs, check if still low
jmp pin, frame_start ; If DE went high early → we found the start
jmp pin, frame_start ; If DE went high early → we found the start
wait 1 gpio DE
jmp wait_low ; DE didn't go high early → restart
jmp wait_low ; DE didn't go high early → restart

frame_start:
irq FRAME_START_IRQ
Expand Down
4 changes: 2 additions & 2 deletions src/dmd_interface_desega.pio
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ dotloop:

wait_low:
wait 0 gpio DE ; Wait for DE to go low
set x, 31 ; Use x as storage for 32 iterations
set x, 20 ; Use x as storage for 20 iterations

delay_loop:
nop [31]
nop [31]
jmp x-- delay_loop [31] ; Decrement x and repeat until zero
jmp x-- delay_loop ; Decrement x and repeat until zero

; After ~10 µs, check if still low
jmp pin, wait_low ; If pin went high early → back to wait_low
Expand Down
37 changes: 27 additions & 10 deletions src/dmdreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,18 @@ void dmd_dma_reset() {
void dmd_dma_handler() {
dmd_set_and_enable_new_dma_target();

if (dmd_type == DMD_DE_X16_V2) {
// Due to the complexity of x16 v2, we use this way to re-sync
// if the signals are noisy, or whatever else could happen.
pio_sm_set_enabled(dmd_pio, dmd_sm, false);
// clear the interrupt for FRAME_START_IRQ 5 in the pio
dmd_pio->irq = (1u << 5);
pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, pio_encode_mov(pio_y, pio_null));
dmd_dma_reset();
pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset));
pio_sm_set_enabled(dmd_pio, dmd_sm, true);
}

// Required as long as CAPCOM is not locked-in:
plane0_shifted = false;
detected_0_1_0_1 = false;
Expand Down Expand Up @@ -650,7 +662,7 @@ void dmd_dma_handler() {
// It seems to be sufficient to check every 8th pixel for these patterns to
// detect sync. So we could avoid bitschifiting of the uint32_t value to
// check every single pixel.
if (dmd_type >= DMD_CAPCOM && !locked_in && !plane0_shifted) {
if (dmd_type == DMD_CAPCOM && !locked_in && !plane0_shifted) {
digitalWrite(LED_BUILTIN, HIGH);
uint8_t value = pixval & 0x0F;
if (value == 2 && (planebuf[px] & 0x0F) != 1 &&
Expand Down Expand Up @@ -724,7 +736,7 @@ void dmd_dma_handler() {
}
}

if (DMD_CAPCOM >= dmd_type && !locked_in && !plane0_shifted &&
if (dmd_type == DMD_CAPCOM && !locked_in && !plane0_shifted &&
detected_0_1_0_1 && detected_1_0_0_0) {
locked_in = true;
}
Expand Down Expand Up @@ -865,20 +877,26 @@ void dmdreader_programs_init(const pio_program_t *dmd_reader_program,
DmdConfigGetter framedetect_get_default_config,
uint *input_pins, uint8_t num_input_pins,
uint8_t jump_pin, uint8_t in_base_pin) {
uint32_t sys_hz = clock_get_hz(clk_sys); // e.g. 125/200/266 MHz
float target_hz = 125000000.0f; // PIO code designed for 125 MHz
float dmd_clkdiv = (float)sys_hz / target_hz; // scales automatically

dmdreader_error_blink(pio_claim_free_sm_and_add_program_for_gpio_range(
dmd_reader_program, &dmd_pio, &dmd_sm, &dmd_offset,
(DE < SDATA_X16) ? DE : SDATA_X16, 8, true));
pio_sm_config dmd_config = reader_get_default_config(dmd_offset);
dmd_reader_program_init(dmd_pio, dmd_sm, dmd_offset, dmd_config, in_base_pin);
dmd_reader_program_init(dmd_clkdiv, dmd_pio, dmd_sm, dmd_offset, dmd_config,
in_base_pin);

// The framedetect program just runs and detects the beginning of a new
// frame
dmdreader_error_blink(pio_claim_free_sm_and_add_program_for_gpio_range(
dmd_framedetect_program, &frame_pio, &frame_sm, &frame_offset,
(DE < SDATA_X16) ? DE : SDATA_X16, 8, true));
pio_sm_config frame_config = framedetect_get_default_config(frame_offset);
dmd_framedetect_program_init(frame_pio, frame_sm, frame_offset, frame_config,
input_pins, num_input_pins, jump_pin);
dmd_framedetect_program_init(dmd_clkdiv, frame_pio, frame_sm, frame_offset,
frame_config, input_pins, num_input_pins,
jump_pin);
pio_sm_set_enabled(frame_pio, frame_sm, true);
}

Expand Down Expand Up @@ -1032,13 +1050,13 @@ bool dmdreader_init(bool return_on_no_detection) {
pio_sm_exec_wait_blocking(dmd_pio, dmd_sm,
pio_encode_mov(pio_y, pio_null));

// load 8192 directly to TX fifo
pio_sm_put(dmd_pio, dmd_sm, 8192);
// load 4096 directly to TX fifo (32uS)
pio_sm_put(dmd_pio, dmd_sm, 4096);
// pull 32 bits from the TX fifo into osr
pio_sm_exec(dmd_pio, dmd_sm, pio_encode_pull(false, false));

// load 3000 directly to TX fifo
pio_sm_put(frame_pio, frame_sm, 3000);
// load 2500 directly to TX fifo (20uS)
pio_sm_put(frame_pio, frame_sm, 2500);
// pull 32 bits from the TX fifo into osr
pio_sm_exec(frame_pio, frame_sm, pio_encode_pull(false, false));

Expand Down Expand Up @@ -1311,7 +1329,6 @@ bool dmdreader_init(bool return_on_no_detection) {
irq_set_exclusive_handler(DMA_IRQ_0, dmd_dma_handler);
irq_set_enabled(DMA_IRQ_0, true);
#endif

// Finally start DMD reader PIO program and DMA
dmd_set_and_enable_new_dma_target();
pio_sm_set_enabled(dmd_pio, dmd_sm, true);
Expand Down
Loading