Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Read and display pinball DMD data
# Read pinball DMD data

This project allows to read the contents of a pinball DMD using the Raspberry Pi Pico.
This project allows to read the contents of a pinball DMD using the Raspberry Pi Pico. Both the RP2040 and RP2350 are supported.

## Hardware
## Pico hardware setup

The Pi Pico is directly connected to the 6 DMD data lines. Communication between the Pi Pico and the consumer is implemented via SPI with an additional IRQ line.
On this IRQ line, the Pico signals that new data is available and consumer must start the data transfer.
Since not any consumer (especially the Raspberry Pi) can act as an SPI slave this method is used.
The Pico is directly connected to all DMD data lines. Communication between the Pico and the consumer is implemented via SPI with an additional IRQ line. On this IRQ line, the Pico signals that a new frame is available, notifying the consumer to start the data transfer as soon as possible. The consumer acts as the SPI master, so it controls the clock frequency used to retrieve the data.

## Officially supported hardware systems
This architecture accommodates consumers (especially Linux hosts like the Raspberry Pi) that are not real-time systems.

## Officially supported pinball hardware systems

* WPC95 & WPC -> 128x32
* Data East -> 128x32 & 128x16
Expand All @@ -27,14 +27,18 @@ Since not any consumer (especially the Raspberry Pi) can act as an SPI slave thi
## Reading data

When reading data, we assume the data is sent correctly.
This means we can read a full frame, containing a predefined amount of bits per pixel.
DMDreader sends complete frames only, containing a predefined amount of bits per pixel.

The process is as follows:
- Wait for a frame to start (DMD frame detect program)
- Read frame (Pixel loop)
- Construct frame based on pixel loop data and system specific code
- Wait for a frame to start (DMD frame detect PIO program)
- Read frame (DMD dotloop PIO program)
- Construct frame based on captured data (dmd_dma_handler IRQ)

## License

This project has been forked from https://github.com/pinballpower/code_dmd after that project changed its license from MIT to GPL v3 on 2022-05-02.
So, the license of this fork is GPL v3.
This project has been forked from https://github.com/pinballpower/code_dmd
Since the original project changed its license from MIT to GPL v3 on 2022-05-02, the license of this fork is now also GPL v3.

## Project credits

DMDreader would not exist without the foundational work done by [Daniel Matuschek](https://github.com/pinballpower). Since then, the project has grown significantly due to extensive contributions from [Markus Kalkbrenner](https://github.com/mkalkbrenner) and [Jan Vos](https://github.com/pastorl69), who have delivered numerous bug fixes, performance optimizations, and support for additional manufacturers.
39 changes: 0 additions & 39 deletions docs/install-openocd.md

This file was deleted.

4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 0 additions & 15 deletions scripts/program-pbos.sh

This file was deleted.

2 changes: 0 additions & 2 deletions scripts/program-pico.sh

This file was deleted.

12 changes: 0 additions & 12 deletions scripts/raspberrypi-swd-dmdreader.cfg

This file was deleted.

66 changes: 0 additions & 66 deletions signals.md

This file was deleted.

89 changes: 0 additions & 89 deletions src/crc32.cpp

This file was deleted.

8 changes: 0 additions & 8 deletions src/crc32.h

This file was deleted.

44 changes: 41 additions & 3 deletions src/dmdreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <cstdint>
#include <cstdlib>

#include "crc32.h"
#include "dmd_counter.h"
#include "dmd_interface.h"
#include "dmdreader_pins.h"
Expand Down Expand Up @@ -119,6 +118,7 @@ uint8_t *framebuf3;
uint8_t *current_framebuf;
uint8_t *framebuf_to_send;

uint8_t dummy_sniff_dst[1];
uint32_t frame_crc = 0;
uint32_t crc_previous_frame = 0;
bool detected_0_1_0_1 = false;
Expand All @@ -142,9 +142,11 @@ uint frame_offset;

// DMA
uint dmd_dma_channel;
uint dma_sniff_channel;
uint spi_dma_channel;

dma_channel_config dmd_dma_channel_cfg;
dma_channel_config dma_sniff_channel_cfg;
dma_channel_config spi_dma_channel_cfg;

volatile bool spi_dma_running = false;
Expand Down Expand Up @@ -624,6 +626,18 @@ void dmd_dma_reset() {
dmd_set_and_enable_new_dma_target();
}

/**
* @brief Takes the freshly processed frame array and runs it through a dummy
* DMA transfer. This is required to sniff the CRC32.
*
*/
void dmd_prepare_dma_sniffer() {
dma_channel_transfer_from_buffer_now(dma_sniff_channel, current_framebuf,
loopback ? source_bytes : target_bytes);
dma_channel_wait_for_finish_blocking(
dma_sniff_channel); // waiting is required.
}

/**
* @brief Handles DMD DMA requests by switching between the buffers
*
Expand Down Expand Up @@ -890,8 +904,10 @@ void dmd_dma_handler() {
memcpy(current_framebuf, processingbuf,
loopback ? source_bytes : target_bytes);

frame_crc =
crc32(0, current_framebuf, loopback ? source_bytes : target_bytes);
dmd_prepare_dma_sniffer();

frame_crc = dma_hw->sniff_data;
dma_hw->sniff_data = 0xFFFFFFFF; // always clean after sniffing!

switch_buffers();

Expand Down Expand Up @@ -1505,6 +1521,28 @@ bool dmdreader_init(bool return_on_no_detection) {
irq_set_exclusive_handler(DMA_IRQ_0, dmd_dma_handler);
irq_set_enabled(DMA_IRQ_0, true);
#endif

// CRC32 DMA sniffer for DMD reader
dma_sniff_channel = dma_claim_unused_channel(true);
dma_sniff_channel_cfg = dma_channel_get_default_config(dma_sniff_channel);
channel_config_set_transfer_data_size(&dma_sniff_channel_cfg, DMA_SIZE_8);
channel_config_set_read_increment(&dma_sniff_channel_cfg, true);
channel_config_set_write_increment(&dma_sniff_channel_cfg, false);

// (bit-reverse) CRC32 specific sniff set-up
channel_config_set_sniff_enable(&dma_sniff_channel_cfg, true);
dma_sniffer_set_data_accumulator(0xFFFFFFFF);
dma_sniffer_set_output_reverse_enabled(true);
dma_sniffer_enable(dma_sniff_channel, DMA_SNIFF_CTRL_CALC_VALUE_CRC32R, true);

dma_channel_configure(
dma_sniff_channel, &dma_sniff_channel_cfg,
dummy_sniff_dst, // Destination pointer
NULL, // Source pointer is set during dmd_dma_handler
0, // We do not know the transfer count yet
false // Do not yet start
);

// Finally start DMD reader PIO program and DMA
dmd_set_and_enable_new_dma_target();
pio_sm_set_enabled(frame_pio, frame_sm, true);
Expand Down