diff --git a/docs/install-openocd.md b/docs/install-openocd.md deleted file mode 100644 index da97e859..00000000 --- a/docs/install-openocd.md +++ /dev/null @@ -1,39 +0,0 @@ -# OpenOCD - -To upload software to the RP2040, OpenOCD is needed. - -## Installation -``` -sudo apt install automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev -git clone --recurse-submodules --depth 1 --branch rp2040 https://github.com/raspberrypi/openocd.git -cd openocd/ -./bootstrap -./configure --enable-ftdi --enable-sysfsgpio --enable-bcm2835gpio -make -j 4 -sudo make install -``` - -## Configuration -sudo vi /usr/local/share/openocd/scripts/interface/raspberrypi-swd.cfg - -``` -# Use RPI GPIO pins -adapter driver bcm2835gpio - -bcm2835gpio_speed_coeffs 146203 36 - -# SWD swclk swdio -# Header pin numbers -bcm2835gpio_swd_nums 23 22 - -transport select swd - -adapter speed 1000 -``` - -## Usage - -``` -openocd -f interface/raspberrypi-swd.cfg -f target/rp2040.cfg -``` - diff --git a/platformio.ini b/platformio.ini index 956a868b..4eef6051 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,14 +2,14 @@ default_envs = ppucdmd [env:ppucdmd] -platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 +platform = https://github.com/maxgerhardt/platform-raspberrypi#79ce473e1a8010ed8096388690222fd2c94858a6 framework = arduino board = pico board_build.core = earlephilhower board_build.filesystem_size = 0.5m [env:ppucdmd2] -platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 +platform = https://github.com/maxgerhardt/platform-raspberrypi#79ce473e1a8010ed8096388690222fd2c94858a6 framework = arduino board = rpipico2 board_build.core = earlephilhower diff --git a/scripts/program-pbos.sh b/scripts/program-pbos.sh deleted file mode 100755 index f51f77b9..00000000 --- a/scripts/program-pbos.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -if [ "$1" == "" ]; then - echo "start with $0 hostname to program RPO2040 on PBOS" - exit 1 -fi - -echo "Stopping DMDReader..." -sshpass -p pbos scp dmdreader.elf root@$1:/firmware -sshpass -p pbos ssh -l root $1 'pkill dmdreader' -sleep 5 -sshpass -p pbos ssh -l root $1 'pkill -KILL dmdreader' -echo "Programming RP2040..." -sshpass -p pbos ssh -l root $1 'cd /firmware; openocd -f raspberrypi-swd-dmdreader.cfg -f target/rp2040.cfg -c "program dmdreader.elf verify reset exit"' -echo "Rebooting..." -sshpass -p pbos ssh -l root $1 'reboot' diff --git a/scripts/program-pico.sh b/scripts/program-pico.sh deleted file mode 100755 index 5413957c..00000000 --- a/scripts/program-pico.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -openocd -f raspberrypi-swd-dmdreader.cfg -f target/rp2040.cfg -c "program dmdreader.elf verify reset exit" diff --git a/scripts/raspberrypi-swd-dmdreader.cfg b/scripts/raspberrypi-swd-dmdreader.cfg deleted file mode 100644 index f7fe7f56..00000000 --- a/scripts/raspberrypi-swd-dmdreader.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# Use RPI GPIO pins -adapter driver bcm2835gpio - -bcm2835gpio_speed_coeffs 146203 36 - -# SWD swclk swdio -# Header pin numbers -bcm2835gpio_swd_nums 23 22 - -transport select swd - -adapter speed 1000 diff --git a/src/crc32.cpp b/src/crc32.cpp deleted file mode 100644 index 453ca5a5..00000000 --- a/src/crc32.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-1996 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* $Id: crc32.c,v 1.1 2007/10/07 20:47:35 matthias Exp $ */ - -#include "crc32.h" - -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -static uint32_t crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL}; - -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) \ - DO1(buf); \ - DO1(buf); -#define DO4(buf) \ - DO2(buf); \ - DO2(buf); -#define DO8(buf) \ - DO4(buf); \ - DO4(buf); - -uint32_t crc32(uint32_t crc, const uint8_t *buf, uint32_t len) { - if (!buf) return (0L); - crc = crc ^ 0xffffffffL; - while (len >= 8) { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - return (crc ^ 0xffffffffL); -} diff --git a/src/crc32.h b/src/crc32.h deleted file mode 100644 index b9e0e359..00000000 --- a/src/crc32.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CRC32_H -#define CRC32_H - -#include - -uint32_t crc32(uint32_t crc, const uint8_t *buf, uint32_t len); - -#endif \ No newline at end of file diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index a47cd79a..872d5424 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -4,7 +4,6 @@ #include #include -#include "crc32.h" #include "dmd_counter.h" #include "dmd_interface.h" #include "dmdreader_pins.h" @@ -22,8 +21,7 @@ typedef struct buf32_t { // SPI data types and header blocks // header block length should always be a multiple of 32bit -#define SPI_BLOCK_PIX 0xcc33 // DMD frame -#define SPI_BLOCK_PIX_CRC 0x44ee // DMD frame with CRC32 checksum +#define SPI_BLOCK_PIX 0xcc33 // DMD frame typedef struct __attribute__((__packed__)) block_header_t { uint16_t block_type; // block type @@ -34,17 +32,9 @@ typedef struct __attribute__((__packed__)) block_pix_header_t { uint16_t columns; // number of columns uint16_t rows; // number of rows uint16_t bitsperpixel; // bits per pixel - uint16_t padding; + uint16_t padding; // padding bits } block_pix_header_t __attribute__((aligned(4))); -typedef struct __attribute__((__packed__)) block_pix_crc_header_t { - uint16_t columns; // number of columns - uint16_t rows; // number of rows - uint16_t bitsperpixel; // bits per pixel - uint16_t padding; - uint32_t crc32; // crc32 of the pixel data -} block_pix_crc_header_t __attribute__((aligned(4))); - DmdType dmd_type; // Line oversampling @@ -119,13 +109,21 @@ uint8_t *framebuf3; uint8_t *current_framebuf; uint8_t *framebuf_to_send; +// crc array used to prevent duplicate frames +uint8_t *prev_crc; +uint8_t *current_crc; + +size_t crc_bytes; + uint32_t frame_crc = 0; uint32_t crc_previous_frame = 0; + bool detected_0_1_0_1 = false; bool detected_1_0_0_0 = false; bool locked_in = false; bool plane0_shifted = false; bool loopback = false; +bool filled_buffer = false; // SPI PIO PIO spi_pio; @@ -207,23 +205,6 @@ bool spi_busy() { return false; } -/** - * @brief Abort running SPI transfers. This can be necessary in case the SPI - * master hangs - * - */ -void spi_abort() { - if (dma_channel_is_busy(spi_dma_channel)) { - dma_channel_abort(spi_dma_channel); - } - - if (!(pio_sm_is_tx_fifo_empty(spi_pio, spi_sm))) { - pio_sm_clear_fifos(spi_pio, spi_sm); - } - - spi_dma_running = false; -} - /** * @brief Notify on pin SPI0_CS that data are ready on SPI * @@ -240,21 +221,37 @@ void start_spi() { digitalWrite(SPI0_CS, HIGH); } */ void finish_spi() { digitalWrite(SPI0_CS, LOW); } +/** + * @brief Cleanly exit SPI by stopping the DMD pio and sending a blank dummy + * frame. + * + */ +void spi_clean_exit() { + static bool exit_executed = false; + if (spi_busy() || exit_executed) { + return; + } + + pio_sm_set_enabled(dmd_pio, dmd_sm, false); + memset(framebuf1, 0, target_bytes); + memset(framebuf2, 0, target_bytes); + frame_received = exit_executed = true; +} + /** * @brief Send a pix buffer via SPI * * @param pixbuf a frame to send */ -bool spi_send_pix(uint8_t *pixbuf, uint32_t crc32, bool skip_when_busy) { - block_header_t h = {.block_type = SPI_BLOCK_PIX_CRC}; - block_pix_crc_header_t ph = {}; +bool spi_send_pix(uint8_t *pixbuf, bool skip_when_busy) { + block_header_t h = {.block_type = SPI_BLOCK_PIX}; + block_pix_header_t ph = {}; // round length to 4-byte blocks h.len = (((target_bytes + 3) / 4) * 4) + sizeof(h) + sizeof(ph); ph.columns = source_width; ph.rows = source_height; ph.bitsperpixel = target_bitsperpixel; - ph.crc32 = crc32; if (skip_when_busy) { if (spi_busy()) return false; @@ -320,11 +317,10 @@ uint64_t read_clock_count() { } DmdType detect_dmd() { - uint64_t signals = read_clock_count(); uint32_t dotclk = signals >> 32; - uint16_t rclk = signals >> 16; // never exceeds 25000 - uint16_t rdata = signals; // never exceeds 600 + uint16_t rclk = signals >> 16; // never exceeds 25000 + uint16_t rdata = signals; // never exceeds 600 // By checking DOTCLK, RCLK and RDATA we can identify system types // All values are based on a 1000ms sample of data @@ -624,11 +620,39 @@ void dmd_dma_reset() { dmd_set_and_enable_new_dma_target(); } +/** + * @brief Updates the current CRC array with the new frame CRC hash. + * + */ +void save_current_crc() { + if (crc_bytes >= sizeof(uint32_t)) { + memmove(¤t_crc[0], ¤t_crc[sizeof(uint32_t)], + crc_bytes - sizeof(uint32_t)); + memcpy(¤t_crc[crc_bytes - sizeof(uint32_t)], &frame_crc, + sizeof(uint32_t)); + } else { + memcpy(current_crc, &frame_crc, sizeof(uint32_t)); + } +} + +/** + * @brief Updates the previous CRC array with the current CRC array. + * + */ +void save_previous_crc() { + memcpy(prev_crc, current_crc, crc_bytes); +} + /** * @brief Handles DMD DMA requests by switching between the buffers * */ void dmd_dma_handler() { + // get the frame crc by sniffing the DMA transfer at no cpu cost. + // must be called before setting a new dma target! + frame_crc = dma_hw->sniff_data; + dma_hw->sniff_data = 0xFFFFFFFF; // always clean after sniffing. + dmd_set_and_enable_new_dma_target(); if (dmd_type == DMD_DE_X16_V2) { @@ -660,7 +684,8 @@ void dmd_dma_handler() { // used. So only the new plane data is fixed here. for (int i = 0; i < source_dwordsperframe; i++) { v = (buf32_t *)planebuf; - *planebuf = (v->byte3 << 24) | (v->byte2 << 16) | (v->byte1 << 8) | (v->byte0); + *planebuf = + (v->byte3 << 24) | (v->byte2 << 16) | (v->byte1 << 8) | (v->byte0); planebuf++; } @@ -784,8 +809,8 @@ void dmd_dma_handler() { if (dmd_type == DMD_DE_X16_V1 || dmd_type == DMD_DE_X16_V2) { // merge the rows and convert from 4bpp to 2bpp with a LUT uint32_t *dst, *src1, *src2; - dst = framebuf + 64; // start in the middle of 128x32 frame - src1 = framebuf + 511; // everything is stored from here onwards + dst = framebuf + 64; // start in the middle of 128x32 frame + src1 = framebuf + offset_x16; // everything is stored from here onwards src2 = src1 + source_dwordsperline; if (dmd_type == DMD_DE_X16_V1) { @@ -890,15 +915,19 @@ void dmd_dma_handler() { memcpy(current_framebuf, processingbuf, loopback ? source_bytes : target_bytes); - frame_crc = - crc32(0, current_framebuf, loopback ? source_bytes : target_bytes); - switch_buffers(); + if (!filled_buffer) { + filled_buffer = true; + return; + } - if (frame_crc != crc_previous_frame) { - crc_previous_frame = frame_crc; + save_current_crc(); + // perform a comparison check to see if the current CRC bytes differ + if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { frame_received = true; } + + save_previous_crc(); } void dmdreader_error_blink(bool no_error) { @@ -967,28 +996,15 @@ bool dmdreader_init(bool return_on_no_detection) { } while (dmd_type == DMD_UNKNOWN); - // Delay is still needed when blink gets removed above. - // delay(1000); - - // Debug blinking to indicate the detected system: - /* - for (uint8_t i = 0; i < (dmd_type * 3); i++) { - digitalWrite(LED_BUILTIN, HIGH); - delay(200); - digitalWrite(LED_BUILTIN, LOW); - delay(200); - } - */ - // Initialize DMD reader switch (dmd_type) { case DMD_WPC: { 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, 1, 0, SDATA); + 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, 1, 0, + SDATA); // load 4096 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 4095); @@ -1026,16 +1042,15 @@ bool dmdreader_init(bool return_on_no_detection) { source_lineoversampling = LINEOVERSAMPLING_NONE; source_mergeplanes = MERGEPLANES_ADD; break; - } + } case DMD_WHITESTAR: { uint input_pins[] = {RDATA}; dmdreader_programs_init( - &dmd_reader_2bpp_program, - dmd_reader_2bpp_program_get_default_config, + &dmd_reader_2bpp_program, dmd_reader_2bpp_program_get_default_config, &dmd_framedetect_generic_program, - dmd_framedetect_generic_program_get_default_config, input_pins, 1, - 0, SDATA); + dmd_framedetect_generic_program_get_default_config, input_pins, 1, 0, + SDATA); // load 8192 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 8191); @@ -1078,11 +1093,11 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_SAM: { uint input_pins[] = {RDATA}; - dmdreader_programs_init(&dmd_reader_4bpp_program, - dmd_reader_4bpp_program_get_default_config, - &dmd_framedetect_generic_program, - dmd_framedetect_generic_program_get_default_config, - input_pins, 1, 0, SDATA); + dmdreader_programs_init( + &dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, + &dmd_framedetect_generic_program, + dmd_framedetect_generic_program_get_default_config, input_pins, 1, 0, + SDATA); // load 16384 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 16383); @@ -1111,7 +1126,7 @@ bool dmdreader_init(bool return_on_no_detection) { // we need it to sample data on the rising edge source_width = 128; - source_height = 32; // is actually 16, but we process as 32 + source_height = 32; // is actually 16, but we process as 32 source_bitsperpixel = 4; // recorded as 4bpp in the pio target_bitsperpixel = 2; // max pixel value is 3 // in DE-Sega, there's only one plane, @@ -1144,7 +1159,7 @@ bool dmdreader_init(bool return_on_no_detection) { pio_sm_put(frame_pio, frame_sm, 2500); source_width = 128; - source_height = 32; // is actually 16, but we process as 32 + source_height = 32; // is actually 16, but we process as 32 source_bitsperpixel = 4; // recorded as 4bpp in the pio target_bitsperpixel = 2; // max pixvalues are 0, 1, 2, 3 // in DE-Sega, there's only one plane, @@ -1184,8 +1199,7 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_SEGA_HD: { uint input_pins[] = {RDATA}; dmdreader_programs_init( - &dmd_reader_2bpp_program, - dmd_reader_2bpp_program_get_default_config, + &dmd_reader_2bpp_program, dmd_reader_2bpp_program_get_default_config, &dmd_framedetect_generic_program, dmd_framedetect_generic_program_get_default_config, input_pins, 1, 0, SDATA); @@ -1210,8 +1224,7 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_GOTTLIEB: { uint input_pins[] = {RDATA}; dmdreader_programs_init( - &dmd_reader_4bpp_program, - dmd_reader_4bpp_program_get_default_config, + &dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, &dmd_framedetect_generic_program, dmd_framedetect_generic_program_get_default_config, input_pins, 1, 0, SDATA); @@ -1258,8 +1271,7 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_ISLAND: { uint input_pins[] = {RDATA}; dmdreader_programs_init( - &dmd_reader_4bpp_program, - dmd_reader_4bpp_program_get_default_config, + &dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, &dmd_framedetect_generic_program, dmd_framedetect_generic_program_get_default_config, input_pins, 1, 0, SDATA); @@ -1281,8 +1293,7 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_HOMEPIN: { uint input_pins[] = {RDATA}; dmdreader_programs_init( - &dmd_reader_4bpp_program, - dmd_reader_4bpp_program_get_default_config, + &dmd_reader_4bpp_program, dmd_reader_4bpp_program_get_default_config, &dmd_framedetect_homepin_program, dmd_framedetect_homepin_program_get_default_config, input_pins, 1, 0, SDATA); @@ -1309,8 +1320,9 @@ bool dmdreader_init(bool return_on_no_detection) { &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 + // Spinball uses the WPC rendering method (timings are very close + // actually) The Capcom framedetect method is used to find the start of a + // frame // load 4096 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 4095); @@ -1330,12 +1342,11 @@ bool dmdreader_init(bool return_on_no_detection) { case DMD_SLEIC: { uint input_pins[] = {DE, RDATA}; - dmdreader_programs_init( - &dmd_reader_2bpp_program, - dmd_reader_2bpp_program_get_default_config, - &dmd_framedetect_sleic_program, - dmd_framedetect_sleic_program_get_default_config, input_pins, 2, - DE, SDATA); + dmdreader_programs_init(&dmd_reader_2bpp_program, + dmd_reader_2bpp_program_get_default_config, + &dmd_framedetect_sleic_program, + dmd_framedetect_sleic_program_get_default_config, + input_pins, 2, DE, SDATA); // load 8192 - 1 pixels directly to TX fifo pio_sm_put(dmd_pio, dmd_sm, 8191); @@ -1380,12 +1391,11 @@ bool dmdreader_init(bool return_on_no_detection) { 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_program, - dmd_framedetect_capcom_program_get_default_config, input_pins, 2, - 0, SDATA); + dmdreader_programs_init(&dmd_reader_4bpp_program, + dmd_reader_4bpp_program_get_default_config, + &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); @@ -1436,6 +1446,24 @@ bool dmdreader_init(bool return_on_no_detection) { size_t processing_bytes = source_bytes * source_lineoversampling; + // The CRC history needs to be configured here. + // 1 for non planehistory systems, 2 for Gottlieb, and 3 for WPC/similar + // systems. Any new systems that make use of a potential different + // planehistory setup: double check code below. + uint8_t crc_history_count = 1; + if (source_planehistoryperframe > 0) { + if (source_planesperframe - source_planehistoryperframe == 1) { + // WPC: planehistory is sourceplanesperframe - 1. + crc_history_count = source_planesperframe; + } else if (source_planesperframe % source_planehistoryperframe == 0) { + // Gottlieb: planehistory is half the amount of total planes. + crc_history_count = source_planesperframe / source_planehistoryperframe; + } + } + crc_bytes = crc_history_count * sizeof(uint32_t); + + current_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); + prev_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); planebuf1 = alloc_aligned_buffer(plane_bytes, 4, nullptr); planebuf2 = alloc_aligned_buffer(plane_bytes, 4, nullptr); processingbuf = alloc_aligned_buffer(processing_bytes, 8, nullptr); @@ -1449,9 +1477,11 @@ bool dmdreader_init(bool return_on_no_detection) { } framebuf3 = alloc_aligned_buffer(framebuf3_bytes, 8, nullptr); - dmdreader_error_blink(planebuf1 && planebuf2 && processingbuf && - framebuf1 && framebuf2 && framebuf3); + dmdreader_error_blink(current_crc && prev_crc && planebuf1 && planebuf2 && + processingbuf && framebuf1 && framebuf2 && framebuf3); + memset(current_crc, 0, crc_bytes); + memset(prev_crc, 0, crc_bytes); memset(planebuf1, 0, plane_bytes); memset(planebuf2, 0, plane_bytes); memset(processingbuf, 0, processing_bytes); @@ -1473,8 +1503,8 @@ bool dmdreader_init(bool return_on_no_detection) { // Read a 128x16 frame but process as 128x32, so, change the number of // transfers at this stage to trigger a dma transfer at the right time. if (dmd_type == DMD_DE_X16_V1 || dmd_type == DMD_DE_X16_V2) { - source_dwordsperframe /= 2; - source_dwordsperplane /= 2; + source_dwordsperframe /= 2; + source_dwordsperplane /= 2; } // DMA for DMD reader @@ -1485,6 +1515,11 @@ bool dmdreader_init(bool return_on_no_detection) { channel_config_set_dreq(&dmd_dma_channel_cfg, pio_get_dreq(dmd_pio, dmd_sm, false)); + // Configure CRC32 DMA sniffer to detect duplicate frames + channel_config_set_sniff_enable(&dmd_dma_channel_cfg, true); + dma_sniffer_enable(dmd_dma_channel, DMA_SNIFF_CTRL_CALC_VALUE_CRC32, true); + dma_sniffer_set_data_accumulator(0xFFFFFFFF); + // Configure the DMA channel. As soon as the PIO pushed a specified number // of words to its RX FIFO, the DMA transfer will be triggered. The amount // of words to transfer is source_dwordsperframe. @@ -1544,12 +1579,14 @@ void dmdreader_spi_init() { irq_set_enabled(DMA_IRQ_1, true); } -bool dmdreader_spi_send() { +bool dmdreader_spi_send(bool is_restarting) { if (!loopback && frame_received) { frame_received = false; - spi_send_pix(framebuf_to_send, frame_crc, true); + spi_send_pix(framebuf_to_send, true); return true; + } else if (is_restarting) { + spi_clean_exit(); } return false; @@ -1606,4 +1643,4 @@ uint8_t *dmdreader_loopback_render() { } uint16_t dmdreader_get_source_width() { return source_width; } -uint16_t dmdreader_get_source_height() { return source_height; } +uint16_t dmdreader_get_source_height() { return source_height; } \ No newline at end of file diff --git a/src/dmdreader.h b/src/dmdreader.h index 8acb6b5f..fc6460a0 100644 --- a/src/dmdreader.h +++ b/src/dmdreader.h @@ -46,7 +46,7 @@ enum DmdType : uint8_t { bool dmdreader_init(bool return_on_no_detection = false); void dmdreader_spi_init(); -bool dmdreader_spi_send(); +bool dmdreader_spi_send(bool is_restarting = false); void dmdreader_loopback_init(uint8_t *buffer1, uint8_t *buffer2, Color color); void dmdreader_loopback_stop();