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 diff --git a/src/dmd_interface.h b/src/dmd_interface.h index ef35eef..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) { @@ -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); 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 diff --git a/src/dmd_interface_de_x16_v2.pio b/src/dmd_interface_de_x16_v2.pio index 86f80cc..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 @@ -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) @@ -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 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 diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a144ab0..2602357 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -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; @@ -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 && @@ -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; } @@ -865,11 +877,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 +894,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); } @@ -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)); @@ -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);