From 28581fc2cfc4aaee6cbcb5097ea4ba98d9c1a60f Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 23 Jul 2026 14:40:28 +0200 Subject: [PATCH 01/18] implement DMA sniffer method instead of a slow crc32 lib. --- src/crc32.cpp | 89 ----------------------------------------------- src/crc32.h | 8 ----- src/dmdreader.cpp | 15 +++++--- 3 files changed, 10 insertions(+), 102 deletions(-) delete mode 100644 src/crc32.cpp delete mode 100644 src/crc32.h 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..436b2dc1 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" @@ -629,6 +628,10 @@ void dmd_dma_reset() { * */ void dmd_dma_handler() { + // get the frame crc by sniffing the DMA transfer at no cpu cost + 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) { @@ -890,9 +893,6 @@ 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 (frame_crc != crc_previous_frame) { @@ -1485,6 +1485,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. @@ -1606,4 +1611,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 From f82abd5c4a96570301b3722d7cb01fcb652a21e6 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 23 Jul 2026 18:00:23 +0200 Subject: [PATCH 02/18] try with a crc history implemented --- src/dmdreader.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 436b2dc1..364a95b4 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -84,6 +84,7 @@ uint16_t source_lineoversampling; uint16_t source_dwordsperline; uint16_t source_mergeplanes; uint16_t offset[MAX_PLANESPERFRAME]; +uint32_t crc_history[MAX_PLANESPERFRAME]; static uint8_t *alloc_aligned_buffer(size_t size, size_t alignment, void **base_out) { @@ -561,6 +562,15 @@ upscale_4bit_0_4_to_0_15(uint32_t input) { // upscale_4bit_0_4_to_0_15() END // ------------------------------- +// Keep track of the CRCs for planehistory systems +void update_crc_history() { + crc_previous_frame = crc_history[0]; + for (int i = 0; i < source_planehistoryperframe; i++) { + crc_history[i] = crc_history[i + 1]; + } + crc_history[source_planehistoryperframe] = frame_crc; +} + void switch_buffers() { uint8_t *previousPlaneBuffer = currentPlaneBuffer; // Switch to next plane and frame buffers @@ -579,6 +589,7 @@ void switch_buffers() { source_planehistoryperframe)], previousPlaneBuffer, source_bytesperplane * source_planehistoryperframe); + update_crc_history(); } } @@ -1468,6 +1479,7 @@ bool dmdreader_init(bool return_on_no_detection) { // Calculate offsets for the first pixel of each plane and cache these. for (int i = 0; i < MAX_PLANESPERFRAME; i++) { offset[i] = i * source_dwordsperplane; + crc_history[i] = 0; // initialize to 0 } // Read a 128x16 frame but process as 128x32, so, change the number of From dd13dbfaa6a0be4843ed37a2ca09ad5c67972b12 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Thu, 23 Jul 2026 18:27:50 +0200 Subject: [PATCH 03/18] debug print --- src/dmdreader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 364a95b4..04ff34e5 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -907,6 +907,7 @@ void dmd_dma_handler() { switch_buffers(); if (frame_crc != crc_previous_frame) { + Serial.printf("got frame: %d\n", frame_crc); crc_previous_frame = frame_crc; frame_received = true; } From bb87feed671174d25bc7db2522ff8d57f6c52b23 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 24 Jul 2026 11:20:29 +0200 Subject: [PATCH 04/18] advanced crc array comparing --- src/dmdreader.cpp | 59 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 04ff34e5..184ada2b 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -84,7 +84,6 @@ uint16_t source_lineoversampling; uint16_t source_dwordsperline; uint16_t source_mergeplanes; uint16_t offset[MAX_PLANESPERFRAME]; -uint32_t crc_history[MAX_PLANESPERFRAME]; static uint8_t *alloc_aligned_buffer(size_t size, size_t alignment, void **base_out) { @@ -119,8 +118,15 @@ 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; @@ -562,15 +568,6 @@ upscale_4bit_0_4_to_0_15(uint32_t input) { // upscale_4bit_0_4_to_0_15() END // ------------------------------- -// Keep track of the CRCs for planehistory systems -void update_crc_history() { - crc_previous_frame = crc_history[0]; - for (int i = 0; i < source_planehistoryperframe; i++) { - crc_history[i] = crc_history[i + 1]; - } - crc_history[source_planehistoryperframe] = frame_crc; -} - void switch_buffers() { uint8_t *previousPlaneBuffer = currentPlaneBuffer; // Switch to next plane and frame buffers @@ -589,7 +586,6 @@ void switch_buffers() { source_planehistoryperframe)], previousPlaneBuffer, source_bytesperplane * source_planehistoryperframe); - update_crc_history(); } } @@ -906,11 +902,20 @@ void dmd_dma_handler() { switch_buffers(); - if (frame_crc != crc_previous_frame) { - Serial.printf("got frame: %d\n", frame_crc); - crc_previous_frame = frame_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)); + } + + if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { frame_received = true; + Serial.printf("got legitimate frame: %X08\n", frame_crc); } + memcpy(prev_crc, current_crc, crc_bytes); } void dmdreader_error_blink(bool no_error) { @@ -1448,11 +1453,29 @@ 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 plane systems, 2 for Gottlieb, and 3 for WPC/similar systems. + // Any new systems that make use of a potential different plane/history + // setup -> check code below to see if it grants a desired result. + uint8_t crc_history_count = 1; + if (source_planehistoryperframe > 0) { + if (source_planesperframe - source_planehistoryperframe == 1) { + // WPC and any system using a similar history plane setup + crc_history_count = source_planesperframe; + } else if (source_planesperframe % source_planehistoryperframe == 0) { + // Gottlieb: plane history is half the amount of total planes. + crc_history_count = source_planesperframe / source_planehistoryperframe; + } + } + crc_bytes = crc_history_count * sizeof(uint32_t); + planebuf1 = alloc_aligned_buffer(plane_bytes, 4, nullptr); planebuf2 = alloc_aligned_buffer(plane_bytes, 4, nullptr); processingbuf = alloc_aligned_buffer(processing_bytes, 8, nullptr); framebuf1 = alloc_aligned_buffer(source_bytes, 8, nullptr); framebuf2 = alloc_aligned_buffer(source_bytes, 8, nullptr); + current_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); + prev_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); size_t framebuf3_bytes = target_bytes; size_t loopback_render_bytes = source_width * source_height * 4 / 8; // 4bpp render buffer @@ -1462,7 +1485,8 @@ 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); + framebuf1 && framebuf2 && framebuf3 && + current_crc && prev_crc); memset(planebuf1, 0, plane_bytes); memset(planebuf2, 0, plane_bytes); @@ -1470,6 +1494,8 @@ bool dmdreader_init(bool return_on_no_detection) { memset(framebuf1, 0, source_bytes); memset(framebuf2, 0, source_bytes); memset(framebuf3, 0, framebuf3_bytes); + memset(current_crc, 0, crc_bytes); + memset(prev_crc, 0, crc_bytes); } currentPlaneBuffer = planebuf2; @@ -1480,7 +1506,6 @@ bool dmdreader_init(bool return_on_no_detection) { // Calculate offsets for the first pixel of each plane and cache these. for (int i = 0; i < MAX_PLANESPERFRAME; i++) { offset[i] = i * source_dwordsperplane; - crc_history[i] = 0; // initialize to 0 } // Read a 128x16 frame but process as 128x32, so, change the number of @@ -1565,7 +1590,7 @@ void dmdreader_spi_init() { bool dmdreader_spi_send() { if (!loopback && frame_received) { frame_received = false; - spi_send_pix(framebuf_to_send, frame_crc, true); + spi_send_pix(framebuf_to_send, 0, true); return true; } From 2ec2a6ae7e0773f07699d5e89eef0734a729a915 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 24 Jul 2026 22:17:59 +0200 Subject: [PATCH 05/18] Implement a buffer filled check to prevent sending the first frame as blank, actually send correct stream only. --- src/dmdreader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 184ada2b..4812004b 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -132,6 +132,7 @@ bool detected_1_0_0_0 = false; bool locked_in = false; bool plane0_shifted = false; bool loopback = false; +bool filled_buffer; // SPI PIO PIO spi_pio; @@ -912,8 +913,11 @@ void dmd_dma_handler() { } if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { + if (!filled_buffer) { + filled_buffer = true; + return; + } frame_received = true; - Serial.printf("got legitimate frame: %X08\n", frame_crc); } memcpy(prev_crc, current_crc, crc_bytes); } From dc342d9e2226bbb5e5ca030d32541d2f6e636326 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 24 Jul 2026 22:35:34 +0200 Subject: [PATCH 06/18] call it a little earlier --- src/dmdreader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 4812004b..c83b97cc 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -902,6 +902,10 @@ void dmd_dma_handler() { loopback ? source_bytes : target_bytes); switch_buffers(); + if (!filled_buffer) { + filled_buffer = true; + return; + } if (crc_bytes >= sizeof(uint32_t)) { memmove(¤t_crc[0], ¤t_crc[sizeof(uint32_t)], @@ -913,10 +917,6 @@ void dmd_dma_handler() { } if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { - if (!filled_buffer) { - filled_buffer = true; - return; - } frame_received = true; } memcpy(prev_crc, current_crc, crc_bytes); From ebfb0711b2fd58b058a5ba1c982de13daa3591f1 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 24 Jul 2026 23:37:26 +0200 Subject: [PATCH 07/18] remove unused function, cleanup spi header --- src/dmdreader.cpp | 41 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index c83b97cc..b819ac2e 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -21,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 0x44ee // DMD frame typedef struct __attribute__((__packed__)) block_header_t { uint16_t block_type; // block type @@ -34,16 +33,9 @@ typedef struct __attribute__((__packed__)) block_pix_header_t { uint16_t rows; // number of rows uint16_t bitsperpixel; // bits per pixel uint16_t padding; + uint32_t reserved; } 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 @@ -132,7 +124,7 @@ bool detected_1_0_0_0 = false; bool locked_in = false; bool plane0_shifted = false; bool loopback = false; -bool filled_buffer; +bool filled_buffer = false; // SPI PIO PIO spi_pio; @@ -214,23 +206,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 * @@ -252,16 +227,15 @@ void finish_spi() { digitalWrite(SPI0_CS, LOW); } * * @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; @@ -919,6 +893,7 @@ void dmd_dma_handler() { if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { frame_received = true; } + memcpy(prev_crc, current_crc, crc_bytes); } @@ -1594,7 +1569,7 @@ void dmdreader_spi_init() { bool dmdreader_spi_send() { if (!loopback && frame_received) { frame_received = false; - spi_send_pix(framebuf_to_send, 0, true); + spi_send_pix(framebuf_to_send, true); return true; } From 51d416fd7d01edd4cd9a874654fdfff552a1b4c1 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Fri, 24 Jul 2026 23:43:41 +0200 Subject: [PATCH 08/18] more clean up and formatting --- src/dmdreader.cpp | 111 +++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 65 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index b819ac2e..292f304c 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -301,11 +301,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 @@ -612,7 +611,7 @@ void dmd_dma_reset() { void dmd_dma_handler() { // get the frame crc by sniffing the DMA transfer at no cpu cost frame_crc = dma_hw->sniff_data; - dma_hw->sniff_data = 0xFFFFFFFF; // always clean after sniffing. + dma_hw->sniff_data = 0xFFFFFFFF; // always clean after sniffing. dmd_set_and_enable_new_dma_target(); @@ -645,7 +644,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++; } @@ -769,8 +769,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) { @@ -893,7 +893,7 @@ void dmd_dma_handler() { if (!std::is_permutation(current_crc, current_crc + crc_bytes, prev_crc)) { frame_received = true; } - + memcpy(prev_crc, current_crc, crc_bytes); } @@ -963,28 +963,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); @@ -1022,16 +1009,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); @@ -1074,11 +1060,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); @@ -1107,7 +1093,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, @@ -1140,7 +1126,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, @@ -1180,8 +1166,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); @@ -1206,8 +1191,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); @@ -1254,8 +1238,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); @@ -1277,8 +1260,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); @@ -1305,8 +1287,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); @@ -1326,12 +1309,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); @@ -1376,12 +1358,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); @@ -1434,7 +1415,7 @@ bool dmdreader_init(bool return_on_no_detection) { // The CRC history needs to be configured here. // 1 for non plane systems, 2 for Gottlieb, and 3 for WPC/similar systems. - // Any new systems that make use of a potential different plane/history + // Any new systems that make use of a potential different plane/history // setup -> check code below to see if it grants a desired result. uint8_t crc_history_count = 1; if (source_planehistoryperframe > 0) { @@ -1464,8 +1445,8 @@ 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 && - current_crc && prev_crc); + framebuf1 && framebuf2 && framebuf3 && current_crc && + prev_crc); memset(planebuf1, 0, plane_bytes); memset(planebuf2, 0, plane_bytes); @@ -1490,8 +1471,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 From 23a3a27e3e50bfde46d5e1a069b0c1a796a65100 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 25 Jul 2026 01:18:55 +0200 Subject: [PATCH 09/18] oops, change to the correct frame block type. CRC officially removed. --- src/dmdreader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 292f304c..47c5d877 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -21,7 +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 0x44ee // DMD frame +#define SPI_BLOCK_PIX 0xcc33 // DMD frame typedef struct __attribute__((__packed__)) block_header_t { uint16_t block_type; // block type @@ -32,8 +32,7 @@ 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; - uint32_t reserved; + uint16_t padding; // padding bits } block_pix_header_t __attribute__((aligned(4))); DmdType dmd_type; From 02cf3fed6d58041ddab1a624d8b20418aed42edd Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Sat, 25 Jul 2026 02:21:02 +0200 Subject: [PATCH 10/18] remove more garbage --- docs/install-openocd.md | 39 --------------------------- platformio.ini | 4 +-- scripts/program-pbos.sh | 15 ----------- scripts/program-pico.sh | 2 -- scripts/raspberrypi-swd-dmdreader.cfg | 12 --------- 5 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 docs/install-openocd.md delete mode 100755 scripts/program-pbos.sh delete mode 100755 scripts/program-pico.sh delete mode 100644 scripts/raspberrypi-swd-dmdreader.cfg 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 From 0e1a04ce69717453c24997e52dca01925724deca Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 12:57:14 +0200 Subject: [PATCH 11/18] test clean exit --- src/dmdreader.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 47c5d877..3e5aef06 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -221,6 +221,21 @@ void start_spi() { digitalWrite(SPI0_CS, HIGH); } */ void finish_spi() { digitalWrite(SPI0_CS, LOW); } +/** + * @brief 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); + spi_send_pix(framebuf1, false); + exit_executed = true; +} + /** * @brief Send a pix buffer via SPI * @@ -1546,12 +1561,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, true); return true; + } else if (is_restarting) { + spi_clean_exit(); } return false; From 9e66ddece73a2bc3218cc4d4f49c677de5e8cb85 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 13:05:08 +0200 Subject: [PATCH 12/18] correct some stuff --- src/dmdreader.cpp | 4 ++-- src/dmdreader.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 3e5aef06..e27b741c 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -232,8 +232,8 @@ void spi_clean_exit() { } pio_sm_set_enabled(dmd_pio, dmd_sm, false); memset(framebuf1, 0, target_bytes); - spi_send_pix(framebuf1, false); - exit_executed = true; + memset(framebuf2, 0, target_bytes); + frame_received = exit_executed = true; } /** 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(); From 7e992af5ed7259303b600d8b523fe9aec6d200d5 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 13:19:55 +0200 Subject: [PATCH 13/18] try some debug quickly --- src/dmdreader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index e27b741c..bf7f6074 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -228,12 +228,15 @@ void finish_spi() { digitalWrite(SPI0_CS, LOW); } void spi_clean_exit() { static bool exit_executed = false; if (spi_busy() || exit_executed) { + Serial.printf("was busy or executed.\n"); 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; + Serial.printf("Executed! done.\n"); } /** From 696ec091aa6f141559ac2eb83a5d476044be79c9 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 13:26:16 +0200 Subject: [PATCH 14/18] is too quick --- src/dmdreader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index bf7f6074..b665fb00 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -229,6 +229,7 @@ void spi_clean_exit() { static bool exit_executed = false; if (spi_busy() || exit_executed) { Serial.printf("was busy or executed.\n"); + delay(1); return; } From 14df459eeec5bfcbfa75739ffae9f756193b8e31 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 13:28:47 +0200 Subject: [PATCH 15/18] try --- src/dmdreader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index b665fb00..80b5f1f9 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -228,8 +228,6 @@ void finish_spi() { digitalWrite(SPI0_CS, LOW); } void spi_clean_exit() { static bool exit_executed = false; if (spi_busy() || exit_executed) { - Serial.printf("was busy or executed.\n"); - delay(1); return; } @@ -263,6 +261,7 @@ bool spi_send_pix(uint8_t *pixbuf, bool skip_when_busy) { spi_send_blocking((uint32_t *)&ph, sizeof(ph)); spi_send_dma((uint32_t *)pixbuf, target_bytes); start_spi(); + Serial.printf("SPI sent.\n"); return true; } From 90d7c3bf85ad3ca225011bab4641c57ea2dd6dfc Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 14:45:58 +0200 Subject: [PATCH 16/18] remove debug print --- src/dmdreader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 80b5f1f9..432487f9 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -222,7 +222,8 @@ void start_spi() { digitalWrite(SPI0_CS, HIGH); } void finish_spi() { digitalWrite(SPI0_CS, LOW); } /** - * @brief Exit SPI by stopping the DMD pio and sending a blank dummy frame. + * @brief Cleanly exit SPI by stopping the DMD pio and sending a blank dummy + * frame. * */ void spi_clean_exit() { @@ -235,7 +236,6 @@ void spi_clean_exit() { memset(framebuf1, 0, target_bytes); memset(framebuf2, 0, target_bytes); frame_received = exit_executed = true; - Serial.printf("Executed! done.\n"); } /** @@ -261,7 +261,6 @@ bool spi_send_pix(uint8_t *pixbuf, bool skip_when_busy) { spi_send_blocking((uint32_t *)&ph, sizeof(ph)); spi_send_dma((uint32_t *)pixbuf, target_bytes); start_spi(); - Serial.printf("SPI sent.\n"); return true; } From 4139bf73f516b9333b629b4dc991a40f8e04d224 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 17:22:02 +0200 Subject: [PATCH 17/18] Move crc updating code into their own functions + some comments. --- src/dmdreader.cpp | 58 ++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 432487f9..80aabf9c 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -620,12 +620,36 @@ 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 + // 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. @@ -897,20 +921,13 @@ void dmd_dma_handler() { return; } - 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)); - } - + 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; } - memcpy(prev_crc, current_crc, crc_bytes); + save_previous_crc(); } void dmdreader_error_blink(bool no_error) { @@ -1430,28 +1447,28 @@ 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 plane systems, 2 for Gottlieb, and 3 for WPC/similar systems. - // Any new systems that make use of a potential different plane/history - // setup -> check code below to see if it grants a desired result. + // 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 and any system using a similar history plane setup + // WPC: planehistory is sourceplanesperframe - 1. crc_history_count = source_planesperframe; } else if (source_planesperframe % source_planehistoryperframe == 0) { - // Gottlieb: plane history is half the amount of total planes. + // 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); framebuf1 = alloc_aligned_buffer(source_bytes, 8, nullptr); framebuf2 = alloc_aligned_buffer(source_bytes, 8, nullptr); - current_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); - prev_crc = alloc_aligned_buffer(crc_bytes, 4, nullptr); size_t framebuf3_bytes = target_bytes; size_t loopback_render_bytes = source_width * source_height * 4 / 8; // 4bpp render buffer @@ -1460,9 +1477,8 @@ 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 && current_crc && - prev_crc); + dmdreader_error_blink(current_crc && prev_crc && planebuf1 && planebuf2 && + processingbuf && framebuf1 && framebuf2 && framebuf3); memset(planebuf1, 0, plane_bytes); memset(planebuf2, 0, plane_bytes); From 4a854879c59088984039894c8a643999e3e8e4c0 Mon Sep 17 00:00:00 2001 From: Jan Vos Date: Mon, 27 Jul 2026 17:22:32 +0200 Subject: [PATCH 18/18] oops, place here. --- src/dmdreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dmdreader.cpp b/src/dmdreader.cpp index 80aabf9c..872d5424 100644 --- a/src/dmdreader.cpp +++ b/src/dmdreader.cpp @@ -1480,14 +1480,14 @@ bool dmdreader_init(bool return_on_no_detection) { 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); memset(framebuf1, 0, source_bytes); memset(framebuf2, 0, source_bytes); memset(framebuf3, 0, framebuf3_bytes); - memset(current_crc, 0, crc_bytes); - memset(prev_crc, 0, crc_bytes); } currentPlaneBuffer = planebuf2;