PicoDVI/software
Luke Wren 8ecccce7b7 Support 4-bit grayscale in packtiles 2024-03-21 12:56:26 +00:00
..
apps Add 720x480p 60Hz mode (270 MHz bit clock) 2024-03-21 12:53:42 +00:00
assets More snowflakes 2021-12-25 09:47:31 +00:00
include Add Adafruit Feather RP2040 DVI support 2024-03-21 11:47:22 +00:00
libdvi Add 720x480p 60Hz mode (270 MHz bit clock) 2024-03-21 12:53:42 +00:00
libsprite Faster sprite_blit16 routine, more sprites in sprite_bounce 2021-11-22 02:46:06 +00:00
scripts Support 4-bit grayscale in packtiles 2024-03-21 12:56:26 +00:00
.gitattributes Initial commit 2021-01-21 06:10:49 +00:00
.gitignore Add palette encoding to libdvi, plus example (#8) 2021-03-08 00:23:26 +00:00
CMakeLists.txt Use target_compile_definitions instead of global add_definitions to set DVI_DEFAULT_SERIAL_CONFIG define. Make default PIO instance in common_dvi_pin_configs configurable. 2021-06-17 08:40:31 +01:00
Readme.md DEFAULT_DVI_SERIAL_CONFIG -> DVI_DEFAULT_SERIAL_CONFIG 2021-06-16 08:55:05 +01:00
gdbinit Fix symbol size calculation in dht_logging 2021-03-04 20:13:45 +00:00
pico_sdk_import.cmake Initial commit 2021-01-21 06:10:49 +00:00

Readme.md

Building

You need to have the Pico SDK installed, as well as a recent CMake and arm-none-eabi-gcc.

mkdir build
cd build
PICO_SDK_PATH=path/to/sdk cmake -DPICO_COPY_TO_RAM=1 ..
make -j$(nproc)

This will build all the example apps. You can then do e.g.

cp apps/sprite_bounce/sprite_bounce.uf2 /media/${USER}/RPI-RP2/

To flash a DVI board plugged into your system. Note the PICO_COPY_TO_RAM=1 is important -- some of the apps will not run if this is not passed, because they use the SSI in fast DMA streaming mode. Others might underperform if they have large image assets (larger than the XIP cache) in flash.

Support for Different Boards

The DVI code is configured with which pins and which PIO state machines to use for signal generation, defined by a dvi_serialiser_cfg struct which looks like this:

static const struct dvi_serialiser_cfg picodvi_dvi_cfg = {
	.pio = pio0,
	.sm_tmds = {0, 1, 2},
	.pins_tmds = {10, 12, 14},
	.pins_clk = 8,
	.invert_diffpairs = true
};

Serial configurations for a handful of boards are listed in common_dvi_pin_configs.h. Feel free to raise a PR to add your board to this file. All of the example apps use the DVI_DEFAULT_SERIAL_CONFIG from this header to select their pin configuration, which has a default value of pico_sock_cfg. You can pass -DDVI_DEFAULT_SERIAL_CONFIG=some_other_board to cmake to override this default, so that the example apps will be built with a different serial configuration.

As well as the DVI serial configuration, you may also want to set the PICO_BOARD flag for your target board to pick up things like UART and LED pin settings.

Example Apps

Bad Apple

Plays the Touhou music video at 720p 30FPS (no sound). Because the video is largely black and white silhouettes, it's highly compressible, and there is a shortcut for encoding full-res TMDS scanlines with a 2-colour palette (check the source). Currently around 1 minute of video fits in 16 MiB of flash, with per-scanline RLE compression. Eventually I'd like to fit the whole video.

Vista

Full-resolution VGA RGB565 image viewer. As each raw image is over 600 kB, only a small slice of the image can reside in memory at once, so images are streamed continuously from flash at 40 MB/s. The TMDS encode uses around 95% of both cores, which is why we need a raw image format. The remaining 5% of core 1 handles the horizontal DMA interrupts to keep the DVI signalling going, and core 0 handles the streaming of the image from flash. This is not very practical, but it was a fun project.

NOTE: you must first copy the image data UF2 before running this app

If you define the symbol TMDS_FULLRES_NO_DC_BALANCE then you can remove the DC balance feedback from the TMDS encode, which may give you enough time to do something more interesting with full-resolution RGB graphics, provided your DVI signals are DC-coupled, and your TV is feeling lenient. This is absolutely forbidden by the standard, but don't worry, I won't tell anyone if you do this.

Terminal

Display text with an 8x8px black and white font, displayed at full resolution (so 80x60 characters at 640x480p 60 Hz, or 160x90 characters at 720p30). This originally worked by storing the font as a set of canned pre-balanced TMDS sequences, but this had a significant memory footprint. There is now fast generic full-res encode (code here) which again subverts the intent of the DVI specification to cheat and still get compliant output, so you can display text over DVI with about 30% of a core.

Moon

Use the full-res 1bpp encode to display a dithered black/white image of the Earthrise from Apollo 8. The same encoded buffer is sent out on all 3 lanes during the horizontal active period, but the encode is fast enough that you can do bitplaned RGB111 if you like. There's a 640x480 and a 1280x720 version.

Two variants of this app are built: moon.uf2 and moon_pio_encode.uf2. All the other examples use software TMDS encode, but the second variant uses this PIO program to offload the encode to a fourth state machine, which is then bounced through memory via DMA to the three serialiser state machines.

Hello DVI

Minimal DVI example. Displays a scrolling QVGA RGB565 test card with a 640x480p 60Hz DVI mode.

Mandelbrot

Render a Mandelbrot set to a QVGA RGB565 framebuffer.

Sprite Bounce

A bunch of images bouncing around on the screen, using my sprite library written for ARMv6M. This uses pixel-doubled RGB graphics, with DVI modes ranging from 640x480p 60Hz to 1280x720p 30Hz. Core 0 renders the graphics, one scanline at a time, and passes scanlines to core 1 for encoding and shipping out to the display.