diff --git a/README.md b/README.md index 55a5272..f3c8e6f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Since not any consumer (especially the Raspberry Pi) can act as an SPI slave thi * Homepin -> 128x32 * Spinball -> 128x32 * Sleic/Petaco -> 128x32 +* Dotmation -> 192x64 ## Reading data diff --git a/logicanalyzer/WPC/Dotmation 192x64.sal b/logicanalyzer/WPC/Dotmation 192x64.sal new file mode 100644 index 0000000..795473e Binary files /dev/null and b/logicanalyzer/WPC/Dotmation 192x64.sal differ diff --git a/src/dmd_interface.h b/src/dmd_interface.h index bbc3053..e86811c 100644 --- a/src/dmd_interface.h +++ b/src/dmd_interface.h @@ -14,35 +14,32 @@ #include "pio/dmd_framedetect_sleic.pio.h" #include "pio/dmd_framedetect_spike.pio.h" -// Init the DMD reader (dots) PIO program, common for all DMD types. +// Init the DMD reader (dotloop) PIO program void dmd_reader_program_init(float dmd_clkdiv, PIO pio, uint sm, uint offset, pio_sm_config c, - uint in_base_pin) { + uint dmd_type, uint in_base_pin) { sm_config_set_in_pins(&c, in_base_pin); - if (in_base_pin != SDATA_X16) { - // We only send, so disable the TX FIFO to make the RX FIFO deeper. - // Joining is not possible with data east x16 - sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); - } else { - // -- Data East 128x16 case -- - // We need to set DOTCLK as the jump pin + if (dmd_type == DMD_DOTMATION || dmd_type == DMD_DE_X16_V1 || + dmd_type == DMD_DE_X16_V2) { + // set DOTCLK as the jmp pin sm_config_set_jmp_pin(&c, DOTCLK); + // Make sure we run the sm with a 125MHz clk + sm_config_set_clkdiv(&c, dmd_clkdiv); + } + if (in_base_pin == SDATA_X16) { pio_gpio_init(pio, SDATA_X16); // Extra data line for Data East X16 pio_gpio_init(pio, SDATA_X16_PADDING); // used as a padding 0 bit pio_sm_set_consecutive_pindirs(pio, sm, SDATA_X16, 1, false); 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_clkdiv); } + // Connect these GPIOs to this PIO block pio_gpio_init(pio, SDATA); pio_gpio_init(pio, DOTCLK); - // Set the pin direction at the PIO, handle pins seprately to support alphaDMD - // as well + // Set the pin direction at the PIO pio_sm_set_consecutive_pindirs(pio, sm, SDATA, 1, false); pio_sm_set_consecutive_pindirs(pio, sm, DOTCLK, 1, false); diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a8c27ec..58311f2 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -323,6 +323,11 @@ DmdType detect_dmd() { (rclk < 4000) && (rdata > 115) && (rdata < 130)) { return DMD_WPC; + // DOTMATION: DOTCLK: 1900000 | RCLK: 9950 | RDATA: 155 + } else if ((dotclk > 1800000) && (dotclk < 2000000) && (rclk > 9700) && + (rclk < 10200) && (rdata > 140) && (rdata < 170)) { + return DMD_DOTMATION; + // 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 < 125)) { @@ -383,13 +388,18 @@ DmdType detect_dmd() { (rclk < 4850) && (rdata > 135) && (rdata < 155)) { return DMD_SLEIC; + // ROMSTAR -> DOTCLK: 4000000 | RCLK: 15625 | RDATA: 245 + } else if ((dotclk > 3900000) && (dotclk < 4100000) && (rclk > 15300) && + (rclk < 15900) && (rdata > 230) && (rdata < 260)) { + return DMD_ROMSTAR; + // Capcom -> DOTCLK: 4168000 | RCLK: 16280 | RDATA: 510 } else if ((dotclk > 4000000) && (dotclk < 4300000) && (rclk > 16000) && (rclk < 16500) && (rdata > 490) && (rdata < 530)) { return DMD_CAPCOM; // Capcom HD -> DOTCLK: 4168000 | RCLK: 16280 | RDATA: 255 - } else if ((dotclk > 3900000) && (dotclk < 4300000) && (rclk > 15500) && + } else if ((dotclk > 4100000) && (dotclk < 4300000) && (rclk > 15900) && (rclk < 16500) && (rdata > 240) && (rdata < 270)) { return DMD_CAPCOM_HD; } @@ -421,7 +431,7 @@ uint64_t convert_2bit_to_4bit_fast(uint32_t input) { // --------------------------------- static constexpr uint8_t map_nibble_de_x16(uint8_t p) { - return (p <= 3) ? p : (p == 4) ? 1 : (p == 8) ? 2 : (p == 10) ? 0 : 3; + return (p <= 3) ? p : (p == 4) ? 1 : (p == 7) ? 0 : (p == 8) ? 2 : 3; } static constexpr uint8_t make_lut_entry_de_x16(uint16_t b) { @@ -625,13 +635,11 @@ void dmd_dma_handler() { // Fix byte order within the buffer uint32_t *planebuf = (uint32_t *)currentPlaneBuffer; buf32_t *v; - uint32_t res; // source_dwordsperframe is not the entire frame buffer if plane history is // used. So only the new plane data is fixed here. for (int i = 0; i < source_dwordsperframe; i++) { v = (buf32_t *)planebuf; - res = (v->byte3 << 24) | (v->byte2 << 16) | (v->byte1 << 8) | (v->byte0); - *planebuf = res; + *planebuf = (v->byte3 << 24) | (v->byte2 << 16) | (v->byte1 << 8) | (v->byte0); planebuf++; } @@ -676,7 +684,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 && @@ -689,7 +697,7 @@ void dmd_dma_handler() { // 0/1/1/1 => 3 // 1/0/1/1 => 3 // 1/1/0/1 => 3 - // 1/1/1/0 => 3 + // 1/1/1/0 => 3 (checking whether value 3 appears is actually enough) // // 0/0/0/1 => 1 // 0/0/1/0 => 1 @@ -698,11 +706,8 @@ void dmd_dma_handler() { // 1/0/1/0 => 2 // 1/1/0/0 => 2 // 0/0/1/1 => 2 - else if (value == 3 || value > 4 || - (value == 1 && (planebuf[px] & 0x0F) != 1) || - (value == 2 && ((planebuf[px] & 0x0F) == 1 || - planebuf[offset[2] + px] & 0x0F) == 1)) { - // An unsynchronized has been found. + else if (value == 3 || value > 4) { + // An unsynchronized frame has been found. // Disable the state machine, clean the DMA channel and restart. // As a result, we will skip exactly one plane. pio_sm_set_enabled(dmd_pio, dmd_sm, false); @@ -749,8 +754,9 @@ 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) { + digitalWrite(LED_BUILTIN, LOW); locked_in = true; } @@ -782,7 +788,7 @@ void dmd_dma_handler() { for (int l = 0; l < source_height / 2; l++) { for (int w = 0; w < source_dwordsperline; w++) { uint32_t out = w >> 1; // Shifting leads to 0, 0, 1, 1, etc - uint16_t v16 = convert_4bit_to_2bit_de_x16((src1[w] + src2[w] * 2)); + uint16_t v16 = convert_4bit_to_2bit_de_x16((src1[w] * 2 + src2[w])); if ((w & 1) == 0) { // Write first 8 pixel in upper 16 Bit. dst[out] = (uint32_t)v16 << 16; @@ -900,7 +906,7 @@ void dmdreader_programs_init(const pio_program_t *dmd_reader_program, (DE < SDATA_X16) ? DE : SDATA_X16, 8, true)); pio_sm_config dmd_config = reader_get_default_config(dmd_offset); dmd_reader_program_init(dmd_clkdiv, dmd_pio, dmd_sm, dmd_offset, dmd_config, - in_base_pin); + dmd_type, in_base_pin); // The framedetect program just runs and detects the beginning of a new // frame @@ -911,7 +917,6 @@ void dmdreader_programs_init(const pio_program_t *dmd_reader_program, 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); } bool dmdreader_init(bool return_on_no_detection) { @@ -945,12 +950,12 @@ bool dmdreader_init(bool return_on_no_detection) { // Initialize DMD reader switch (dmd_type) { case DMD_WPC: { - uint input_pins[] = {RDATA, DE, DOTCLK}; + uint input_pins[] = {RDATA}; dmdreader_programs_init(&dmd_reader_2bpp_program, dmd_reader_2bpp_program_get_default_config, &dmd_framedetect_generic_program, dmd_framedetect_generic_program_get_default_config, - input_pins, 3, 0, SDATA); + input_pins, 1, 0, SDATA); // load 4096 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 4095); @@ -966,6 +971,30 @@ bool dmdreader_init(bool return_on_no_detection) { break; } + case DMD_DOTMATION: { + uint input_pins[] = {RDATA, RCLK}; + dmdreader_programs_init(&dmd_reader_dotmation_program, + dmd_reader_dotmation_program_get_default_config, + &dmd_framedetect_capcom_program, + dmd_framedetect_capcom_program_get_default_config, + input_pins, 2, 0, SDATA); + + // load 12288 - 1 pixels directly to TX fifo + pio_sm_put(dmd_pio, dmd_sm, 12287); + // load 64 - 1 rows directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 63); + + source_width = 192; + source_height = 64; + source_bitsperpixel = 2; + target_bitsperpixel = 2; + source_planesperframe = 3; + source_planehistoryperframe = 2; + source_lineoversampling = LINEOVERSAMPLING_NONE; + source_mergeplanes = MERGEPLANES_ADD; + break; + } + case DMD_WHITESTAR: { uint input_pins[] = {RDATA}; dmdreader_programs_init( @@ -993,12 +1022,12 @@ bool dmdreader_init(bool return_on_no_detection) { } case DMD_SPIKE1: { - uint input_pins[] = {RCLK, RDATA}; + uint input_pins[] = {COLLAT}; dmdreader_programs_init(&dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, &dmd_framedetect_spike_program, dmd_framedetect_spike_program_get_default_config, - input_pins, 2, RDATA, SDATA); + input_pins, 1, COLLAT, SDATA); // load 16384 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 16383); @@ -1076,13 +1105,10 @@ 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 (32uS) + // load 4096 delay cycles directly to TX fifo (32uS) pio_sm_put(dmd_pio, dmd_sm, 4096); - - // load 2500 directly to TX fifo (20uS) + // load 2500 delay cycles 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)); source_width = 128; source_height = 32; // is actually 16, but we process as 32 @@ -1172,15 +1198,17 @@ bool dmdreader_init(bool return_on_no_detection) { } case DMD_ALVING: { - uint input_pins[] = {RDATA, RCLK, COLLAT}; + uint input_pins[] = {RDATA, COLLAT}; dmdreader_programs_init(&dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, &dmd_framedetect_alving_program, dmd_framedetect_alving_program_get_default_config, - input_pins, 3, 0, SDATA); + input_pins, 2, 0, SDATA); // load 16384 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 16383); + // load 128 - 1 COLLAT edges directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 127); source_width = 128; source_height = 32; @@ -1253,6 +1281,8 @@ bool dmdreader_init(bool return_on_no_detection) { // load 4096 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 4095); + // load 32 - 1 rows directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 31); source_width = 128; source_height = 32; @@ -1276,6 +1306,8 @@ bool dmdreader_init(bool return_on_no_detection) { // load 8192 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 8191); + // load 6144 delay cycles directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 6144); source_width = 128; source_height = 32; @@ -1298,6 +1330,8 @@ bool dmdreader_init(bool return_on_no_detection) { // load 127 directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 127); + // load 32 - 1 rows directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 31); source_width = 128; source_height = 32; @@ -1310,17 +1344,20 @@ bool dmdreader_init(bool return_on_no_detection) { break; } + case DMD_ROMSTAR: case DMD_CAPCOM_HD: { uint input_pins[] = {RDATA, RCLK}; dmdreader_programs_init( &dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, - &dmd_framedetect_capcom_hd_program, - dmd_framedetect_capcom_hd_program_get_default_config, input_pins, 2, + &dmd_framedetect_capcom_program, + dmd_framedetect_capcom_program_get_default_config, input_pins, 2, 0, SDATA); // load 16384 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 16383); + // load 64 - 1 rows directly to TX fifo + pio_sm_put(frame_pio, frame_sm, 63); source_width = 256; source_height = 64; @@ -1336,6 +1373,7 @@ bool dmdreader_init(bool return_on_no_detection) { // pull 32 bits of data (if configured) from the TX fifo into osr pio_sm_exec(dmd_pio, dmd_sm, pio_encode_pull(false, false)); + pio_sm_exec(frame_pio, frame_sm, pio_encode_pull(false, false)); // Calculate display parameters source_pixelsperbyte = 8 / source_bitsperpixel; @@ -1436,6 +1474,7 @@ bool dmdreader_init(bool return_on_no_detection) { #endif // Finally start DMD reader PIO program and DMA dmd_set_and_enable_new_dma_target(); + pio_sm_set_enabled(frame_pio, frame_sm, true); pio_sm_set_enabled(dmd_pio, dmd_sm, true); return true; diff --git a/src/dmdreader.h b/src/dmdreader.h index d1cf3e1..b17944e 100644 --- a/src/dmdreader.h +++ b/src/dmdreader.h @@ -19,6 +19,7 @@ enum class Color : uint8_t { enum DmdType : uint8_t { DMD_UNKNOWN, DMD_WPC, + DMD_DOTMATION, DMD_WHITESTAR, DMD_SPIKE1, DMD_SAM, @@ -28,6 +29,7 @@ enum DmdType : uint8_t { DMD_SEGA_HD, DMD_GOTTLIEB, DMD_ALVING, + DMD_ROMSTAR, DMD_ISLAND, DMD_HOMEPIN, DMD_SPINBALL, diff --git a/src/pio/dmd_dotloop.pio b/src/pio/dmd_dotloop.pio index 672399c..17768d0 100644 --- a/src/pio/dmd_dotloop.pio +++ b/src/pio/dmd_dotloop.pio @@ -13,7 +13,7 @@ ; An IRQ initiates the read process, allowing execution to enter the ; dotloop section and capture a preconfigured number of pixels. -; Almost every system makes use of the 2bpp or 4bpp reader, except Capcom 128x32 and Data East 128x16. +; Almost every system makes use of the 2bpp or 4bpp reader, except Capcom 128x32, Data East 128x16 and Dotmation. ; Therefore, all dotloop programs have been put into a single pio file. ; // --------------- // @@ -142,10 +142,10 @@ 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) - set x, 5 ; 0b101 + set x, 7 ; 0b111 set y, 31 no_lsb_msb_padding: - ; Shift in 0101 0101 32 times. We record 64 pixels like this as the missing MSB row. + ; Shift in 0111 0111 32 times. We record 64 pixels like this as the missing MSB row. in x, 4 in x, 4 jmp y-- no_lsb_msb_padding @@ -155,4 +155,30 @@ no_lsb_msb_padding: reload_dotloop_y: set y, 1 +.wrap + +; // -------------------- // +; // dmd_reader_dotmation // +; // -------------------- // + +.program dmd_reader_dotmation +.wrap_target + mov x, osr ; loads number of configured pixels + mov isr, null ; clear ISR and reset shift counter + + irq clear START_READING_IRQ + wait irq START_READING_IRQ + +dotloop: + wait 0 gpio DOTCLK ; falling edge + in null 1 ; left padding with 1 zero + +dot_check_loop: + wait 1 gpio DOTCLK [16] ; wait 17 * 8ns = 136ns to confirm the dot + jmp pin legit_dot + jmp dot_check_loop + +legit_dot: + in pins 1 ; read pin data + jmp x-- dotloop .wrap \ No newline at end of file diff --git a/src/pio/dmd_framedetect_alving.pio b/src/pio/dmd_framedetect_alving.pio index 529bd70..5bbabb2 100644 --- a/src/pio/dmd_framedetect_alving.pio +++ b/src/pio/dmd_framedetect_alving.pio @@ -6,26 +6,15 @@ .define SDATA 2 .define FRAME_START_IRQ 5 -; 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 + mov x, osr ; set x to 127, we need to skip 128 COLLAT edges + wait 1 gpio RDATA collat_loop: wait 0 gpio COLLAT wait 1 gpio COLLAT - jmp y-- collat_loop + jmp x--collat_loop irq FRAME_START_IRQ -.wrap - +.wrap \ No newline at end of file diff --git a/src/pio/dmd_framedetect_capcom.pio b/src/pio/dmd_framedetect_capcom.pio index 293c3e0..0334ed7 100644 --- a/src/pio/dmd_framedetect_capcom.pio +++ b/src/pio/dmd_framedetect_capcom.pio @@ -8,36 +8,15 @@ ; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ. .program dmd_framedetect_capcom - 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. .wrap_target - set x, 31 ; 32 rows - -rclk_loop: - wait 1 gpio RCLK - wait 0 gpio RCLK - jmp x-- rclk_loop - irq PLANE_START_IRQ - wait 1 gpio RDATA -.wrap - -.program dmd_framedetect_capcom_hd - set x, 31 ; x = 31 (max 5-bit value) - in x, 5 ; shift in 5 bits, isr = 31 - set x, 1 ; x = 1 - in x, 1 ; shift 1 bit, isr = 63 + mov x, osr ; 32 or 64 rows, depending on 128x32, 256x64 or 192x64 wait 0 gpio RDATA - wait 1 gpio RDATA -; When RDATA turned HIGH, we already missed the start of the first row, so we skip 64 end of rows before sending the first IRQ. -.wrap_target - mov x, isr ; 64 rows + wait 1 gpio RDATA ; we just missed the start, so skip x amount of rows rclk_loop: wait 1 gpio RCLK wait 0 gpio RCLK jmp x-- rclk_loop irq PLANE_START_IRQ - wait 1 gpio RDATA .wrap \ No newline at end of file diff --git a/src/pio/dmd_framedetect_desega.pio b/src/pio/dmd_framedetect_desega.pio index 7aa9c3d..6762344 100644 --- a/src/pio/dmd_framedetect_desega.pio +++ b/src/pio/dmd_framedetect_desega.pio @@ -20,13 +20,11 @@ wait_low: delay_loop: nop [31] - nop [31] - jmp x-- delay_loop ; Decrement x and repeat until zero + jmp x-- delay_loop [31] ; 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 irq FRAME_START_IRQ ; Pin remained low long enough → frame started wait 1 gpio DE ; Wait again for it to go high before restarting cycle - jmp wait_low ; went high, time to go back to wait_low -.wrap +.wrap \ No newline at end of file diff --git a/src/pio/dmd_framedetect_generic.pio b/src/pio/dmd_framedetect_generic.pio index e059f73..4e3952b 100644 --- a/src/pio/dmd_framedetect_generic.pio +++ b/src/pio/dmd_framedetect_generic.pio @@ -9,6 +9,9 @@ ; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ. .program dmd_framedetect_generic .wrap_target + +; This program is in use by WPC/WPC95, Stern SAM, Stern Whitestar, Gottlieb/Premier, Sega HD and Island + wait 0 gpio RDATA wait 1 gpio RDATA irq FRAME_START_IRQ diff --git a/src/pio/dmd_framedetect_homepin.pio b/src/pio/dmd_framedetect_homepin.pio index 274d921..e23d0d0 100644 --- a/src/pio/dmd_framedetect_homepin.pio +++ b/src/pio/dmd_framedetect_homepin.pio @@ -9,7 +9,6 @@ ; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ. .program dmd_framedetect_homepin .wrap_target - wait 0 gpio RDATA wait 1 gpio RDATA wait 0 gpio RDATA irq FRAME_START_IRQ diff --git a/src/pio/dmd_framedetect_sleic.pio b/src/pio/dmd_framedetect_sleic.pio index 4f357af..c42ebfa 100644 --- a/src/pio/dmd_framedetect_sleic.pio +++ b/src/pio/dmd_framedetect_sleic.pio @@ -8,15 +8,10 @@ ; 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 + mov x, osr ; set x to 6144 wait 0 gpio DE ; Wait for DE to go low delay_loop: diff --git a/src/pio/dmd_framedetect_spike.pio b/src/pio/dmd_framedetect_spike.pio index 7970027..bdc94cf 100644 --- a/src/pio/dmd_framedetect_spike.pio +++ b/src/pio/dmd_framedetect_spike.pio @@ -8,44 +8,23 @@ ; Frame detection program runs in parallel to the reader program and signals the start of a new frame using an IRQ. .program dmd_framedetect_spike - ; Frame detection in Spike: - ; Wait for RDATA to go HIGH - ; Check if it is still HIGH 150-250ms later - in this case, this is the most significant bit which is the last plane - ; Then wait for RDATA to go LOW and HIGH again, this is the beginning of a new frame - ; Based on 125MHz clock frequency we have to wait 18750-31250 clock cycles - ; We use 24576 here, because it0s 0b11 << 13 - - ; initialize isr with 24576 - set x, 3 - in x, 2 - in null, 13 - .wrap_target -; synchronize on the least significant plane - -waitrdata: - ; wait for RDATA to measure the length of the impulse - wait 1 gpio RDATA - - mov x, isr -delayloop: - jmp x-- delayloop - - ; check if RDATA is still HIGH - jmp pin longrdata ; jump if rdata is HIGH +; Stern SPIKE 1 frame start detection +; ~1.1µs is the longest state in which COLLAT can be high without it being a new frame +; ~2µs is the usual time of COLLAT for it to be a legitimate frame start. +; We go with 1.5µs to be safe and confirm the start of a new frame. - ; RDATA pin was LOW, wait for next - jmp waitrdata +wait_low: + wait 1 gpio COLLAT ; Wait for COLLAT to go high + set x, 5 ; Use x as storage for 6 iterations -longrdata: +delay_loop: + jmp x-- delay_loop [31] ; Decrement x and repeat until zero - ; skip the next 30 lines - set x,30 -lineloop: - wait 1 gpio RCLK - wait 0 gpio RCLK - jmp x-- lineloop + jmp pin, trigger_irq ; If pin still high → trigger irq + jmp wait_low +trigger_irq: irq FRAME_START_IRQ -.wrap +.wrap \ No newline at end of file