diff --git a/README.md b/README.md index 27f8bde..6f69d6e 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Since not any consumer (especially the Raspberry Pi) can act as an SPI slave thi * Stern SPIKE 1 -> 128x32 * Capcom -> 128x32 * Gottlieb/Premier -> 128x32 +* Alvin G. & Co -> 128x32 ## Reading data diff --git a/src/dmd_interface.h b/src/dmd_interface.h index cb8b0cb..4e60c5c 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -8,6 +8,7 @@ #include "dmd_interface_sam.pio.h" #include "dmd_interface_spike.pio.h" #endif +#include "dmd_interface_alving.pio.h" #include "dmd_interface_capcom.pio.h" #include "dmd_interface_capcom_hd.pio.h" #include "dmd_interface_desega.pio.h" diff --git a/src/dmd_interface_alving.pio b/src/dmd_interface_alving.pio new file mode 100644 index 0000000..48dd3f4 --- /dev/null +++ b/src/dmd_interface_alving.pio @@ -0,0 +1,56 @@ +.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_alving + ; initialize y with 16383, number of pixels (128x32x4) - 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, 4 ; shift in 4 bits, isr = 16383 + mov y, isr ; y = 16383 + +.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, 3 ; left padding with 3 zeros + 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_alving + wait 0 gpio RDATA + wait 1 gpio RDATA +; When RDATA turned HIGH, we already missed the start of the first row, so we skip 32 end of rows before sending the first IRQ. +; Alvin G needs to skip 3 COLLAT edges right after for a correct starting point. +.wrap_target + set x, 31 ; 32 rows + set y, 2 ; 3 COLLAT edges + +rclk_loop: + wait 0 gpio RCLK + wait 1 gpio RCLK + jmp x-- rclk_loop + +collat_loop: + wait 0 gpio COLLAT + wait 1 gpio COLLAT + jmp y-- collat_loop + + irq FRAME_START_IRQ +.wrap + diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index ed430cb..853e9bb 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -76,6 +76,7 @@ enum DmdType { DMD_DESEGA, DMD_SEGA_HD, DMD_GOTTLIEB, + DMD_ALVING, // CAPCOM need to be the last entries: DMD_CAPCOM, DMD_CAPCOM_HD, @@ -375,6 +376,11 @@ DmdType detect_dmd() { (de < 13100) && (rdata > 370) && (rdata < 410)) { return DMD_GOTTLIEB; + // Alvin G -> DOTCLK: 1192000 | DE: 9400 | RDATA: 73 + } else if ((dotclk > 1150000) && (dotclk < 1250000) && (de > 9200) && + (de < 9600) && (rdata > 65) && (rdata < 80)) { + return DMD_ALVING; + // Capcom -> DOTCLK: 4168000 | DE: 16280 | RDATA: 510 } else if ((dotclk > 4000000) && (dotclk < 4300000) && (de > 16000) && (de < 16500) && (rdata > 490) && (rdata < 530)) { @@ -628,17 +634,32 @@ void dmd_dma_handler() { src4 = src3 + source_dwordsperline; uint32_t v; - for (int l = 0; l < source_height; l++) { - for (int w = 0; w < source_dwordsperline; w++) { - // On SAM line order is really messed up :-( - v = src4[w] * 8 + src3[w] * 1 + src2[w] * 4 + src1[w] * 2; - dst[w] = v; + if (dmd_type == DMD_SAM) { + for (int l = 0; l < source_height; l++) { + for (int w = 0; w < source_dwordsperline; w++) { + // On SAM line order is really messed up :-( + v = src4[w] * 8 + src3[w] * 1 + src2[w] * 4 + src1[w] * 2; + dst[w] = v; + } + src1 += source_dwordsperline * 4; // source skips 4 lines forward + src2 += source_dwordsperline * 4; + src3 += source_dwordsperline * 4; + src4 += source_dwordsperline * 4; + dst += source_dwordsperline; // destination skips only one line + } + } else { // Alvin G + for (int l = 0; l < source_height; l++) { + for (int w = 0; w < source_dwordsperline; w++) { + // First row captured counts as intensity level 3 <-- + v = src4[w] * 4 + src3[w] * 4 + src2[w] * 4 + src1[w] * 3; + dst[w] = v; + } + src1 += source_dwordsperline * 4; // source skips 4 lines forward + src2 += source_dwordsperline * 4; + src3 += source_dwordsperline * 4; + src4 += source_dwordsperline * 4; + dst += source_dwordsperline; // destination skips only one line } - src1 += source_dwordsperline * 4; // source skips 4 lines forward - src2 += source_dwordsperline * 4; - src3 += source_dwordsperline * 4; - src4 += source_dwordsperline * 4; - dst += source_dwordsperline; // destination skips only one line } } } @@ -849,13 +870,32 @@ void dmdreader_init() { break; } + case DMD_ALVING: { + uint input_pins[] = {RDATA, RCLK, COLLAT}; + dmdreader_programs_init( + &dmd_reader_alving_program, + dmd_reader_alving_program_get_default_config, + &dmd_framedetect_alving_program, + dmd_framedetect_alving_program_get_default_config, input_pins, 2, 0); + + source_width = 128; + source_height = 32; + source_bitsperpixel = 4; + target_bitsperpixel = 4; + source_planesperframe = 1; // in Alvin G there is one plane + // with 4x line oversampling + source_lineoversampling = LINEOVERSAMPLING_4X; + source_mergeplanes = MERGEPLANES_NONE; + break; + } + case DMD_CAPCOM: { uint input_pins[] = {RDATA, RCLK}; dmdreader_programs_init(&dmd_reader_capcom_program, dmd_reader_capcom_program_get_default_config, &dmd_framedetect_capcom_program, dmd_framedetect_capcom_program_get_default_config, - input_pins, 2, 0); + input_pins, 3, 0); source_width = 128; source_height = 32;