From 746980c49775d18eceb598d9d3ab8d5c494e4e5d Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 16:52:15 +0100 Subject: [PATCH 01/32] remove algorithm for HD and romstar --- src/dmdreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a144ab0..a8d4a9a 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -650,7 +650,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 && @@ -724,7 +724,7 @@ void dmd_dma_handler() { } } - if (DMD_CAPCOM >= dmd_type && !locked_in && !plane0_shifted && + if (DMD_CAPCOM == dmd_type && !locked_in && !plane0_shifted && detected_0_1_0_1 && detected_1_0_0_0) { locked_in = true; } From b00b5c800803dc10227ba4923ad7895a733737d9 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 19:38:03 +0100 Subject: [PATCH 02/32] fix ribbon cable pull for capcom HD --- src/dmd_interface_capcom_hd.pio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmd_interface_capcom_hd.pio b/src/dmd_interface_capcom_hd.pio index 33d8bc3..433d10d 100644 --- a/src/dmd_interface_capcom_hd.pio +++ b/src/dmd_interface_capcom_hd.pio @@ -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 \ No newline at end of file From 525857a95ad310e78a0e5310729af75a385eab03 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 19:38:15 +0100 Subject: [PATCH 03/32] more forgiving algorithm --- src/dmdreader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a8d4a9a..31b09a7 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -650,7 +650,8 @@ 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 && + px & 1 == 0) { digitalWrite(LED_BUILTIN, HIGH); uint8_t value = pixval & 0x0F; if (value == 2 && (planebuf[px] & 0x0F) != 1 && @@ -724,7 +725,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; } From 5df0ffdc24eb0976eef1f32f705d33aa00b4598d Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 20:16:31 +0100 Subject: [PATCH 04/32] add some brackets --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 31b09a7..5fd573a 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -651,7 +651,7 @@ void dmd_dma_handler() { // 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 && - px & 1 == 0) { + (px & 1) == 0) { digitalWrite(LED_BUILTIN, HIGH); uint8_t value = pixval & 0x0F; if (value == 2 && (planebuf[px] & 0x0F) != 1 && From f7958846bc711f3502c260855803515d37559f44 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 20:26:04 +0100 Subject: [PATCH 05/32] every third pixel --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 5fd573a..276b249 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -651,7 +651,7 @@ void dmd_dma_handler() { // 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 && - (px & 1) == 0) { + (px & 2) == 0) { digitalWrite(LED_BUILTIN, HIGH); uint8_t value = pixval & 0x0F; if (value == 2 && (planebuf[px] & 0x0F) != 1 && From 33876f0f840f1e61694f11291e88eeddd539b2f9 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 20:33:41 +0100 Subject: [PATCH 06/32] skip more pixels --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 276b249..fa557fa 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -651,7 +651,7 @@ void dmd_dma_handler() { // 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 && - (px & 2) == 0) { + (px & 3) == 0) { digitalWrite(LED_BUILTIN, HIGH); uint8_t value = pixval & 0x0F; if (value == 2 && (planebuf[px] & 0x0F) != 1 && From 8b200b3b7486d4596cfc583a58810a10ca5ea621 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 20:48:58 +0100 Subject: [PATCH 07/32] The algorithm is too heavy for Capcom HD. --- src/dmdreader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index fa557fa..6e4a5ed 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -650,8 +650,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 && - (px & 3) == 0) { + 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 && @@ -725,7 +724,7 @@ void dmd_dma_handler() { } } - if (dmd_type >= DMD_CAPCOM && !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; } From 916d329e470cc4c7263eaccf0066497904b0a0a6 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 21:02:21 +0100 Subject: [PATCH 08/32] spike check --- src/dmd_interface.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dmd_interface.h b/src/dmd_interface.h index ef35eef..5fd7904 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -91,8 +91,13 @@ void dmd_framedetect_program_init(PIO pio, uint sm, uint offset, false, // no autopush 0); + // Derive divider from current clock so PIO runs at ~125 MHz reference + 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 divider = (float)sys_hz / target_hz; // scales automatically + sm_config_set_clkdiv(&c, divider); // 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_interface_125mhz_clk_divider); // Load our configuration, do not yet start the program pio_sm_init(pio, sm, offset, &c); From 2f39cb8869fbe4d815f16f5bd12695459e7c5c00 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 21:30:06 +0100 Subject: [PATCH 09/32] correctly set and parse dmd_clkdiv --- src/dmd_interface.h | 17 ++++------------- src/dmdreader.cpp | 12 +++++++++--- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/dmd_interface.h b/src/dmd_interface.h index 5fd7904..67ce0bb 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -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); @@ -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); @@ -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) { @@ -91,13 +87,8 @@ void dmd_framedetect_program_init(PIO pio, uint sm, uint offset, false, // no autopush 0); - // Derive divider from current clock so PIO runs at ~125 MHz reference - 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 divider = (float)sys_hz / target_hz; // scales automatically - sm_config_set_clkdiv(&c, divider); // 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); diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 6e4a5ed..2874bc8 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -865,11 +865,16 @@ 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 @@ -877,8 +882,9 @@ void dmdreader_programs_init(const pio_program_t *dmd_reader_program, 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); } From fbe6697fca3f3bdc274a388e83e62535d68a3962 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 21:40:07 +0100 Subject: [PATCH 10/32] revert sega to previous values because 125MHz clkdiv was set incorrectly --- src/dmd_interface_desega.pio | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dmd_interface_desega.pio b/src/dmd_interface_desega.pio index 062ff81..f35b5de 100644 --- a/src/dmd_interface_desega.pio +++ b/src/dmd_interface_desega.pio @@ -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 From a1de57bb21ae3804e7b420e8c2eb9481a9560ffb Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 22:25:10 +0100 Subject: [PATCH 11/32] hook good now? --- src/dmdreader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 2874bc8..351622a 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -1038,13 +1038,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 3096 directly to TX fifo + 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 2000 directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 2000); // pull 32 bits from the TX fifo into osr pio_sm_exec(frame_pio, frame_sm, pio_encode_pull(false, false)); From 1a63e5bfbddd088094a196373c9507065c125cd3 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 12 Mar 2026 23:04:54 +0100 Subject: [PATCH 12/32] typo --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 351622a..55ce287 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -1038,7 +1038,7 @@ 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 3096 directly to TX fifo + // load 4096 directly to TX fifo 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)); From 046c68d09be704c5ab3e772f0bdcee89828250cc Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 13 Mar 2026 16:06:08 +0100 Subject: [PATCH 13/32] hook specific change, faster detection? --- src/dmd_interface_de_x16_v2.pio | 4 ++-- src/dmdreader.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 86f80cc..6a7e394 100644 --- a/src/dmd_interface_de_x16_v2.pio +++ b/src/dmd_interface_de_x16_v2.pio @@ -32,7 +32,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) @@ -62,7 +62,7 @@ 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 diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 55ce287..3399380 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -1038,13 +1038,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 4096 directly to TX fifo + // 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 2000 directly to TX fifo - pio_sm_put(frame_pio, frame_sm, 2000); + // 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)); From 561254daa3840aa0bca43d9ad5574c760907e455 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 17:56:09 +0100 Subject: [PATCH 14/32] sync frame when ribbon cable is pulled --- src/dmd_interface_de_x16_v2.pio | 7 ++++--- src/dmdreader.cpp | 10 +++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 6a7e394..2ab279e 100644 --- a/src/dmd_interface_de_x16_v2.pio +++ b/src/dmd_interface_de_x16_v2.pio @@ -65,12 +65,13 @@ wait_low: 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 + irq clear FRAME_START_IRQ ; through this way, we check for a frame sync in the pio code + jmp wait_low ; DE didn't go high early → restart frame_start: irq FRAME_START_IRQ diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 3399380..a9bb7de 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -753,6 +753,15 @@ void dmd_dma_handler() { } } else { // DMD_DE_X16_V2 case + delayMicroseconds(400); + if(!pio_interrupt_get(frame_pio, 5)) { + // if the IRQ is not set during the execution of this code, it means + // the x16 v2 frame is not synchronized -> reset pio and clear DMA. + pio_sm_set_enabled(dmd_pio, dmd_sm, false); + dmd_dma_reset(); + pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); + pio_sm_set_enabled(dmd_pio, dmd_sm, true); + } for (int l = 0; l < source_height; l++) { for (int w = 0; w < source_dwordsperline; w++) { uint32_t out = w >> 1; // Shifting leads to 0, 0, 1, 1, etc @@ -1317,7 +1326,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); From 224c493c653d0450620f0d021b3cd4bf04e6621b Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 18:21:59 +0100 Subject: [PATCH 15/32] try without delay --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a9bb7de..112e9c4 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -753,7 +753,7 @@ void dmd_dma_handler() { } } else { // DMD_DE_X16_V2 case - delayMicroseconds(400); + // delayMicroseconds(400); if(!pio_interrupt_get(frame_pio, 5)) { // if the IRQ is not set during the execution of this code, it means // the x16 v2 frame is not synchronized -> reset pio and clear DMA. From 6c80c949914b7c9daa8f12e40f4bd0008fc0001e Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 18:45:15 +0100 Subject: [PATCH 16/32] reset pio isr instead of DMA. --- src/dmdreader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 112e9c4..8da6ef7 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -753,12 +753,14 @@ void dmd_dma_handler() { } } else { // DMD_DE_X16_V2 case - // delayMicroseconds(400); + delayMicroseconds(300); if(!pio_interrupt_get(frame_pio, 5)) { // if the IRQ is not set during the execution of this code, it means // the x16 v2 frame is not synchronized -> reset pio and clear DMA. pio_sm_set_enabled(dmd_pio, dmd_sm, false); - dmd_dma_reset(); + //dmd_dma_reset(); + // initialise Y register to zero + pio_sm_exec(dmd_pio, dmd_sm, pio_encode_mov(pio_isr, pio_null)); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } From 1ee84aa0fcf14f6556fcb55e55ce21b1ec7746b3 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 19:02:35 +0100 Subject: [PATCH 17/32] quick one --- src/dmdreader.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 8da6ef7..c949d83 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -592,6 +592,20 @@ void dmd_dma_reset() { void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); + if(dmd_type == DMD_DE_X16_V2) { + delayMicroseconds(400); + if(!pio_interrupt_get(frame_pio, 5)) { + // if the IRQ is not set during the execution of this code, it means + // the x16 v2 frame is not synchronized -> reset pio and clear DMA. + pio_sm_set_enabled(dmd_pio, dmd_sm, false); + //dmd_dma_reset(); + // initialise Y register to zero + pio_sm_exec(dmd_pio, dmd_sm, pio_encode_mov(pio_isr, pio_null)); + 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; @@ -753,17 +767,6 @@ void dmd_dma_handler() { } } else { // DMD_DE_X16_V2 case - delayMicroseconds(300); - if(!pio_interrupt_get(frame_pio, 5)) { - // if the IRQ is not set during the execution of this code, it means - // the x16 v2 frame is not synchronized -> reset pio and clear DMA. - pio_sm_set_enabled(dmd_pio, dmd_sm, false); - //dmd_dma_reset(); - // initialise Y register to zero - pio_sm_exec(dmd_pio, dmd_sm, pio_encode_mov(pio_isr, pio_null)); - pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); - pio_sm_set_enabled(dmd_pio, dmd_sm, true); - } for (int l = 0; l < source_height; l++) { for (int w = 0; w < source_dwordsperline; w++) { uint32_t out = w >> 1; // Shifting leads to 0, 0, 1, 1, etc From 23412d28912d0cf11dce280642a088ef25de22ea Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 19:04:17 +0100 Subject: [PATCH 18/32] quick one #2 --- src/dmdreader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index c949d83..2824d7e 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -598,9 +598,7 @@ void dmd_dma_handler() { // if the IRQ is not set during the execution of this code, it means // the x16 v2 frame is not synchronized -> reset pio and clear DMA. pio_sm_set_enabled(dmd_pio, dmd_sm, false); - //dmd_dma_reset(); - // initialise Y register to zero - pio_sm_exec(dmd_pio, dmd_sm, pio_encode_mov(pio_isr, 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); } From 2af1a32f7628f7ca65ce8340da94d743a0369606 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 14 Mar 2026 22:15:12 +0100 Subject: [PATCH 19/32] correct way of handling resync --- src/dmd_interface_de_x16_v2.pio | 2 +- src/dmdreader.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 2ab279e..69d8d95 100644 --- a/src/dmd_interface_de_x16_v2.pio +++ b/src/dmd_interface_de_x16_v2.pio @@ -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 @@ -70,7 +71,6 @@ delay_loop: ; After ~16 µs, check if still low jmp pin, frame_start ; If DE went high early → we found the start wait 1 gpio DE - irq clear FRAME_START_IRQ ; through this way, we check for a frame sync in the pio code jmp wait_low ; DE didn't go high early → restart frame_start: diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 2824d7e..6422e88 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -593,11 +593,9 @@ void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); if(dmd_type == DMD_DE_X16_V2) { - delayMicroseconds(400); - if(!pio_interrupt_get(frame_pio, 5)) { - // if the IRQ is not set during the execution of this code, it means - // the x16 v2 frame is not synchronized -> reset pio and clear DMA. + if(pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); + pio_interrupt_clear(frame_pio, 5); dmd_dma_reset(); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); From e2d9574f1df7e149317c03ea52c56a7f435b46cb Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 11:54:06 +0100 Subject: [PATCH 20/32] dmd pio --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 6422e88..f456d40 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -595,7 +595,7 @@ void dmd_dma_handler() { if(dmd_type == DMD_DE_X16_V2) { if(pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); - pio_interrupt_clear(frame_pio, 5); + pio_interrupt_clear(dmd_pio, 5); dmd_dma_reset(); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); From ffc6dc090e7fe51dceedae537a61f3ba9b50edf5 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 12:03:45 +0100 Subject: [PATCH 21/32] wait blocking --- src/dmdreader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index f456d40..d1c084d 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -592,12 +592,12 @@ void dmd_dma_reset() { void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); - if(dmd_type == DMD_DE_X16_V2) { - if(pio_interrupt_get(frame_pio, 5)) { + if (dmd_type == DMD_DE_X16_V2) { + if (pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); pio_interrupt_clear(dmd_pio, 5); dmd_dma_reset(); - pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); + pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } } From a70493e08cf2ca9858fd98690860636ee7ddf72b Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 13:06:04 +0100 Subject: [PATCH 22/32] x16 v2 frame sync test --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index d1c084d..46201f3 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -596,8 +596,8 @@ void dmd_dma_handler() { if (pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); pio_interrupt_clear(dmd_pio, 5); - dmd_dma_reset(); pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); + dmd_dma_reset(); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } } From 5237fda040616bf3983ac54d0d1dda275586d6d3 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 13:29:49 +0100 Subject: [PATCH 23/32] different approach --- src/dmd_interface_de_x16_v2.pio | 2 +- src/dmdreader.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 69d8d95..499faa8 100644 --- a/src/dmd_interface_de_x16_v2.pio +++ b/src/dmd_interface_de_x16_v2.pio @@ -10,8 +10,8 @@ .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 + wait irq FRAME_START_IRQ ; we only check for an IRQ once because of limitations .wrap_target diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 46201f3..8664972 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -596,7 +596,10 @@ void dmd_dma_handler() { if (pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); pio_interrupt_clear(dmd_pio, 5); - pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); + pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, + pio_encode_mov(pio_isr, pio_null)); + pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, + pio_encode_jmp(dmd_offset + 1)); dmd_dma_reset(); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } From a454fa75cd77d5c152deb79586d0eb75c5264a33 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 13:45:47 +0100 Subject: [PATCH 24/32] revert to only line build --- src/dmd_interface_de_x16_v2.pio | 2 +- src/dmdreader.cpp | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 499faa8..69d8d95 100644 --- a/src/dmd_interface_de_x16_v2.pio +++ b/src/dmd_interface_de_x16_v2.pio @@ -10,8 +10,8 @@ .program dmd_reader_de_x16_v2 - mov isr, null ; clean the isr before starting a new frame 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 diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 8664972..6422e88 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -592,15 +592,12 @@ void dmd_dma_reset() { void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); - if (dmd_type == DMD_DE_X16_V2) { - if (pio_interrupt_get(frame_pio, 5)) { + if(dmd_type == DMD_DE_X16_V2) { + if(pio_interrupt_get(frame_pio, 5)) { pio_sm_set_enabled(dmd_pio, dmd_sm, false); - pio_interrupt_clear(dmd_pio, 5); - pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, - pio_encode_mov(pio_isr, pio_null)); - pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, - pio_encode_jmp(dmd_offset + 1)); + pio_interrupt_clear(frame_pio, 5); dmd_dma_reset(); + pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } } From be55bd3932c5bb28ae2b714674eb64d76307cc2e Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 13:51:24 +0100 Subject: [PATCH 25/32] also clear y in case of lsb msb frame --- src/dmdreader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 6422e88..edf390f 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -597,6 +597,8 @@ void dmd_dma_handler() { pio_sm_set_enabled(dmd_pio, dmd_sm, false); pio_interrupt_clear(frame_pio, 5); dmd_dma_reset(); + pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, + pio_encode_mov(pio_y, pio_null)); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } From 0a0543e927182d914207b364a8fcd8d0788e91db Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 14:13:02 +0100 Subject: [PATCH 26/32] stable build --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a6685b..61cb445 100644 --- a/README.md +++ b/README.md @@ -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 From c3a2216a3dda4ded342187180ead5c382524ea66 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sun, 15 Mar 2026 14:15:08 +0100 Subject: [PATCH 27/32] document x16 v2 resync --- src/dmdreader.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index edf390f..b9c72ff 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -592,13 +592,15 @@ void dmd_dma_reset() { void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); - if(dmd_type == DMD_DE_X16_V2) { - if(pio_interrupt_get(frame_pio, 5)) { + if (dmd_type == DMD_DE_X16_V2) { + if (pio_interrupt_get(frame_pio, 5)) { + // 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); pio_interrupt_clear(frame_pio, 5); dmd_dma_reset(); pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, - pio_encode_mov(pio_y, pio_null)); + pio_encode_mov(pio_y, pio_null)); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); pio_sm_set_enabled(dmd_pio, dmd_sm, true); } From 6ab88236f356b6131d63de20b6617479e0154483 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 16 Mar 2026 13:54:08 +0100 Subject: [PATCH 28/32] dma reset needed? --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index b9c72ff..5364fae 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -598,7 +598,7 @@ void dmd_dma_handler() { // if the signals are noisy, or whatever else could happen. pio_sm_set_enabled(dmd_pio, dmd_sm, false); pio_interrupt_clear(frame_pio, 5); - dmd_dma_reset(); + // dmd_dma_reset(); pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, pio_encode_mov(pio_y, pio_null)); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); From 0f1ee367a5912f752973be4e4abf6dfd9da4f007 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 16 Mar 2026 14:02:02 +0100 Subject: [PATCH 29/32] extra test --- src/dmdreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 5364fae..f2dcbfc 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -593,7 +593,7 @@ void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); if (dmd_type == DMD_DE_X16_V2) { - if (pio_interrupt_get(frame_pio, 5)) { + // if (frame_pio->irq & (1u << 5)) { // 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); @@ -603,7 +603,7 @@ void dmd_dma_handler() { pio_encode_mov(pio_y, pio_null)); 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: From 51168ca66924a82cd779e09fd15e9b9368fbdc91 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 16 Mar 2026 14:52:04 +0100 Subject: [PATCH 30/32] clean up code and add comments --- src/dmdreader.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index f2dcbfc..204d9a2 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -593,17 +593,14 @@ void dmd_dma_handler() { dmd_set_and_enable_new_dma_target(); if (dmd_type == DMD_DE_X16_V2) { - // if (frame_pio->irq & (1u << 5)) { - // 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); - pio_interrupt_clear(frame_pio, 5); - // dmd_dma_reset(); - pio_sm_exec_wait_blocking(dmd_pio, dmd_sm, - pio_encode_mov(pio_y, pio_null)); - pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); - pio_sm_set_enabled(dmd_pio, dmd_sm, true); - // } + // 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 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)); + 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: From 834075eefe8a7340a1e541f612fd265aff37c67c Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 16 Mar 2026 15:03:06 +0100 Subject: [PATCH 31/32] comments --- src/dmdreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 204d9a2..bb287ad 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -596,7 +596,7 @@ void dmd_dma_handler() { // 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 irq 5 in the pio + // 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)); pio_sm_exec(dmd_pio, dmd_sm, pio_encode_jmp(dmd_offset)); From e765a1292f0d6f678bd6c2c5b17fee33e1ed1520 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Tue, 17 Mar 2026 11:25:27 +0100 Subject: [PATCH 32/32] add back dma reset --- src/dmdreader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index bb287ad..2602357 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -599,6 +599,7 @@ void dmd_dma_handler() { // 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); }