diff --git a/README.md b/README.md index 61cb4459..55a52723 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. -## Officially Supported hardware systems +## Officially supported hardware systems * WPC95 & WPC -> 128x32 * Data East -> 128x32 & 128x16 @@ -20,6 +20,8 @@ Since not any consumer (especially the Raspberry Pi) can act as an SPI slave thi * Gottlieb/Premier -> 128x32 * Alvin G. & Co -> 128x32 * Homepin -> 128x32 +* Spinball -> 128x32 +* Sleic/Petaco -> 128x32 ## Reading data diff --git a/logicanalyzer/Sleic/Io Moon - Sleic 128x32.sal b/logicanalyzer/Sleic/Io Moon - Sleic 128x32.sal new file mode 100644 index 00000000..1e75bfdf Binary files /dev/null and b/logicanalyzer/Sleic/Io Moon - Sleic 128x32.sal differ diff --git a/logicanalyzer/Spinball/Jolly Park - Spinball 128x32.sal b/logicanalyzer/Spinball/Jolly Park - Spinball 128x32.sal new file mode 100644 index 00000000..42cfdcc5 Binary files /dev/null and b/logicanalyzer/Spinball/Jolly Park - Spinball 128x32.sal differ diff --git a/logicanalyzer/WPC/Cactus Canyon - WPC95 128x32.sal b/logicanalyzer/WPC/Cactus Canyon - WPC95 128x32.sal new file mode 100644 index 00000000..80849bfb Binary files /dev/null and b/logicanalyzer/WPC/Cactus Canyon - WPC95 128x32.sal differ diff --git a/src/dmd_interface.h b/src/dmd_interface.h index 67ce0bbf..e1b243be 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -16,6 +16,7 @@ #include "dmd_interface_desega.pio.h" #include "dmd_interface_gottlieb.pio.h" #include "dmd_interface_homepin.pio.h" +#include "dmd_interface_sleic.pio.h" #include "dmd_interface_sega_hd.pio.h" #include "dmd_interface_whitestar.pio.h" #include "dmd_interface_wpc.pio.h" diff --git a/src/dmd_interface_sleic.pio b/src/dmd_interface_sleic.pio new file mode 100644 index 00000000..1aa861c3 --- /dev/null +++ b/src/dmd_interface_sleic.pio @@ -0,0 +1,54 @@ +.define DE 7 +.define RDATA 6 +.define RCLK 5 +.define COLLAT 4 +.define DOTCLK 3 +.define SDATA 2 +.define FRAME_START_IRQ 5 + +.program dmd_reader_sleic + ; initialize y with 8191, number of pixels ((128 x LSB + 128 x MSB) x 32) - 1 because counting starts at 0. + set x, 31 ; x = 31 (max 5-bit value) + in x, 5 ; shift in 5 bits, isr = 31 + set x, 31 ; x = 31 + in x, 5 ; shift in 5 bits, isr = 1023 + set x, 15 ; x = 15 + in x, 3 ; shift in 3 bits, isr = 8191 + mov y, isr ; y = 8191 + +.wrap_target + mov x, y ; load number of pixels + mov isr, null ; clear ISR and reset shift counter + + irq clear FRAME_START_IRQ + wait irq FRAME_START_IRQ + +dotloop: + wait 0 gpio DOTCLK ; falling edge + in null 1 ; left padding + wait 1 gpio DOTCLK ; raising edge + in pins 1 ; read pin data + jmp x-- dotloop +.wrap + +; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ. +.program dmd_framedetect_sleic + + set x, 3 ; x = 3 + in x, 2 ; shift in 2 bits, isr = 3 + in null, 11 ; shift left by 11 bits = 6144 + +.wrap_target + +wait_low: + mov x, isr ; set x to 6144 + wait 0 gpio DE ; Wait for DE to go low + +delay_loop: + jmp pin, wait_low ; If pin went high early → back to wait_low + jmp x-- delay_loop ; Decrement x and repeat until zero + + ; If after ~100 µs still low → frame start found + wait 1 gpio RDATA + irq FRAME_START_IRQ +.wrap \ No newline at end of file diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 9c5a1890..c5327f54 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -326,12 +326,12 @@ DmdType detect_dmd() { // Data East X16 V1: DOTCLK: 121000 or 60544 | RCLK: 3905 | RDATA: 120 } else if ((dotclk > 55000) && (dotclk < 125000) && (rclk > 3880) && - (rclk < 3930) && (rdata > 110) && (rdata < 120)) { + (rclk < 3930) && (rdata > 110) && (rdata < 125)) { return DMD_DE_X16_V1; // Data East X16 V2: DOTCLK: 121000 or 60544 | RCLK: 3850 | RDATA: 120 } else if ((dotclk > 55000) && (dotclk < 125000) && (rclk > 3825) && - (rclk < 3875) && (rdata > 110) && (rdata < 120)) { + (rclk < 3875) && (rdata > 110) && (rdata < 125)) { return DMD_DE_X16_V2; // Data East X32: DOTCLK: 640000 | RCLK: 2500 | RDATA: 80 @@ -364,7 +364,7 @@ DmdType detect_dmd() { (rclk < 2380) && (rdata > 65) && (rdata < 80)) { return DMD_ALVING; - // Island/SPinball(?) -> DOTCLK: 2323000 | RCLK: 18100 | RDATA: 565 + // Island -> DOTCLK: 2323000 | RCLK: 18100 | RDATA: 565 } else if ((dotclk > 2200000) && (dotclk < 2450000) && (rclk > 17700) && (rclk < 18500) && (rdata > 540) && (rdata < 590)) { return DMD_ISLAND; @@ -374,6 +374,16 @@ DmdType detect_dmd() { (rclk < 1690) && (rdata > 45) && (rdata < 55)) { return DMD_HOMEPIN; + // Spinball -> DOTCLK: 544000 | RCLK: 4250 | RDATA: 130 + } else if ((dotclk > 520000) && (dotclk < 570000) && (rclk > 4100) && + (rclk < 4400) && (rdata > 125) && (rdata < 140)) { + return DMD_SPINBALL; + + // Sleic -> DOTCLK: 599000 | RCLK: 4700 | RDATA: 145 + } else if ((dotclk > 570000) && (dotclk < 630000) && (rclk > 4550) && + (rclk < 4850) && (rdata > 135) && (rdata < 155)) { + return DMD_SLEIC; + // Capcom -> DOTCLK: 4168000 | RCLK: 16280 | RDATA: 510 } else if ((dotclk > 4000000) && (dotclk < 4300000) && (rclk > 16000) && (rclk < 16500) && (rdata > 490) && (rdata < 530)) { @@ -640,7 +650,11 @@ void dmd_dma_handler() { for (int plane = 0; plane < source_planesperframe; plane++) { uint32_t v = planebuf[offset[plane] + px]; if (source_shiftplanesatmerge) { - v <<= plane; + if (dmd_type == DMD_SPIKE1) { + v <<= plane; + } else if (dmd_type == DMD_SLEIC) { + v <<= (source_planesperframe - 1) - plane; + } } pixval += v; } @@ -1201,6 +1215,46 @@ bool dmdreader_init(bool return_on_no_detection) { break; } + case DMD_SPINBALL: { + uint input_pins[] = {RDATA, RCLK}; + dmdreader_programs_init(&dmd_reader_wpc_program, + dmd_reader_wpc_program_get_default_config, + &dmd_framedetect_capcom_program, + dmd_framedetect_capcom_program_get_default_config, + input_pins, 2, 0, SDATA); + // Spinball uses the WPC rendering method (timings are very close actually) + // The Capcom framedetect method is used to find the start of a frame + source_width = 128; + source_height = 32; + source_bitsperpixel = 2; + target_bitsperpixel = 2; + source_planesperframe = 3; + source_planehistoryperframe = 2; + source_lineoversampling = LINEOVERSAMPLING_NONE; + source_mergeplanes = MERGEPLANES_ADD; + break; + } + + case DMD_SLEIC: { + uint input_pins[] = {DE, RDATA}; + dmdreader_programs_init( + &dmd_reader_sleic_program, + dmd_reader_sleic_program_get_default_config, + &dmd_framedetect_sleic_program, + dmd_framedetect_sleic_program_get_default_config, input_pins, 2, + DE, SDATA); + + source_width = 128; + source_height = 32; + source_bitsperpixel = 2; + target_bitsperpixel = 2; + source_planesperframe = 2; + source_planehistoryperframe = 0; + source_lineoversampling = LINEOVERSAMPLING_NONE; + source_mergeplanes = MERGEPLANES_ADDSHIFT; + break; + } + case DMD_CAPCOM: { uint input_pins[] = {RDATA, RCLK}; dmdreader_programs_init(&dmd_reader_capcom_program, diff --git a/src/dmdreader.h b/src/dmdreader.h index c4ea9a3b..d1cf3e1a 100644 --- a/src/dmdreader.h +++ b/src/dmdreader.h @@ -30,6 +30,8 @@ enum DmdType : uint8_t { DMD_ALVING, DMD_ISLAND, DMD_HOMEPIN, + DMD_SPINBALL, + DMD_SLEIC, // CAPCOM needs to be the last two entries: DMD_CAPCOM, DMD_CAPCOM_HD,