Git Product home page Git Product logo

picodvi's Introduction

Bitbanged DVI on the RP2040 Microcontroller

640x480 RGB565 image, 640x480p 60 Hz DVI mode. 264 kB SRAM, 2x Cortex-M0+, system clock 252 MHz

Quick links:

Board Schematic

Software Readme and Example Photos

About this Project

This project stems from a stupid idea I had during RP2040 bringup. I couldn't convince myself the idea was too stupid to work, so I took a leap of faith on it, and the results are documented here.

RP2040 was designed to run at 133 MHz, but we found (without too much surprise) that typical silicon can be pushed further. In fact, there was overlap between the maximum system clock, and the TMDS bit clocks of slower DVI video modes. We had done great stuff with VGA on the FPGA platform, which ran at 48 MHz, but wouldn't it be absurd and wonderful to connect your microcontroller straight to an HD TV with no other electronics in between? This seemed unlikely to work out, but I stayed up at night playing around with assembly loops, and I could not convince myself that DVI was out of reach. Everything seemed to fit:

  • With some of the core-local hardware on RP2040, and a neat encoding trick, I could do pixel-doubled TMDS encode on-the-fly using around 60% of an M0+ (running at 252 MHz, for 640x480p 60 Hz DVI)
  • PIO can yeet out data streams at system clock frequency, and drive a 1/10th rate clock on the side, with pretty minimal programming
  • Some of the DMA features are help with putting together the sync/blanking patterns on the fly, rather than having the patterns flat in memory
  • With the second processor utterly unencumbered, you can render some pretty graphics to put on your DVI display. There is even enough RAM for a QVGA framebuffer!

The greatest unknown was driving 252 Mbps serial through the general-purpose digital pads (especially differential serial, emulated with two single-ended pads). By this point I was utterly driven and consumed by the need to find out if DVI could work, so I laid out a board over a few evenings after work.

The Rev A board uses a slightly cursed coupling circuit I first saw (and used) on the ULX3S FPGA board, which just connects 3V3 IOs straight into the HDMI socket through some coupling caps.

Those who understand the TMDS physical layer are probably screaming, but I was fine, because I did not read the electrical section of the spec until after I got this board working. Then I screamed. Before the boards arrived I did some debugging, with these two strategies:

  • Run the entire system at 12 MHz (crystal freq), so that the signals are probeable, but the relative speed of IO, DMA and CPUs is the same. This makes sure my code can keep the PIO state machines fed with data
  • Swap in an alternate PIO program which outputs 10 bit UART data frames instead of direct serial (a 17% drop in throughput). I could then dump the TMDS stream with a logic analyser, and examine and parse it on my machine

I also tried out my slightly harebrained TMDS encoding scheme, which matches the letter but not the spirit of the DVI specification, on an FPGA board with some DVI gateware I wrote for a previous weekend project. This confirmed that the principle was sound, and that my TV and monitor would have no trouble with the output of the matching software encoder on RP2040, provided the chip could physically shove bits out of the pins fast enough.

Because this is a home project, I didn't touch the HDL sim, and stuck to ARM debug, UART and logic analyser for my debugging. This worked some kinks out of the software, and bringup of the freshly-soldered board was smooth. After swapping the blue and red lanes into the right order -- to which I will say, in my defense, I consistently thought the blue+sync lane was lane 2 -- I had a clean RGB565 QVGA 60 Hz static image on my monitor.

Improved Output Circuit

After reading the TMDS electrical section of the DVI spec, and staring quietly out the window for a while, wondering how this board ever worked, I rethought the output circuit. Eight capacitors was clearly not the way to go -- what I really needed was eight resistors. That's what I call a DVI PHY.

I also revised my earlier approach of "turn all the GPIOs up to 11", and reduced the pad drive and slew. At work on Monday, a colleague agreed it would be a great idea to plug my microcontroller monstrosity into the scope setup we use for 4k HDMI testing. Here are the results at VGA 60 Hz (252 Mbps):

I was sitting on the other side of the lab while he was running the test, and when the eye mask appeared he just said "do you wanna see something funny".

A clean bill of health! We also tried 720p30 (372 Mbps), which requires overvoltage on typical silicon (something you can do with one register write on RP2040):

Honestly, this has shaken me. This is a silly amount of bandwidth for a tiny little microcontroller.

Although it passes the eye mask and a few other tests, this circuit is not fully compliant with the DVI spec. In particular, our logic 1 is not quite right, due to the CMOS drive on the GPIOs: any more than a ~60 mV mismatch between the Source and Sink +3V3 rails will push our high-level offset outside of the +- 10 mV allowed by the spec. This is a real nitpick, because a differential receiver is unlikely to care about a 10 mV commmon mode offset, but still -- it is out of spec. A better circuit could use a fast Si diode and a smaller resistor value, e.g. 220 ohm, so that the emulated CML output floats on the sink's +3V3 supply when we output our 3V3 CMOS high level, but still sinks the requisite 10 mA when driving low.

That said, it's compliant enough that I can wander around the office and plug it into every monitor I see, and not even one of them explodes (if my manager is reading this -- hi).

Going Further

Everything we have done is software defined -- there's no video hardware on this chip. That would of course be silly on a microcontroller. Let's list all the hardware resources used to display a pixel-doubled image on screen:

  • 3 out of 8 PIO state machines (the DVI code requires these all be on the same PIO instance, of which there are two, with four state machines each)
  • 6 out of 12 DMA channels (two per TMDS lane: one for control blocks, one for data)
  • 30% of DMA bandwidth and PIO bus endpoint bandwidth
  • 60% of CPU cycles on one core, other core 100% free
  • Just over 50% of RAM with a QVGA RGB565 image (but RGB332 support is simple enough)
  • The PicoDVI board's only HDMI-shaped socket

Hmm. All of these numbers are less than half of the total, and everything else is software. It's a shame there's only one socket I can put an HDMI cable in. I mean, I guess I do have these adorable PMOD-DVI adapters that I keep plugging into FPGA boards and getting away with it:

Oh. Maybe? It fits...

I guess the jig is up at this point, because of course I wouldn't post something so daft-looking if it didn't work:

The code is here.

Example Apps

The software readme has some example apps which put the DVI library through its paces, with pictures for some of the fun ones. I won't duplicate that content here.

Encoding TMDS

DVI uses an encoding scheme called TMDS during the video periods. 8 data bits are represented by a 10 bit TMDS symbol, which is serialised at 10x the pixel clock. 3 lanes transfer 24 bits of data per pixel clock, which for our purposes is one pixel. TMDS is DC-balanced, although DVI as a whole is not DC-balanced on all lanes, due to the control symbol encoding. The algorithm given in the DVI spec is quite fussy, and you are supposed to match its output exactly. It tracks running disparity with a counter, and optionally inverts symbols to bound the disparity, with some tie-break rules for 0-balance symbols.

Key fact about TMDS: if the current running disparity is 0, and you encode data x followed by data x ^ 0x01, this produces a pair of TMDS symbols with 0 net parity. If you manipulate the input data in this way -- duplicating the pixels, and twiddling the LSB -- TMDS becomes stateless, because the running disparity is defined to be 0 at the start of each video period, and returns to 0 after each duplicated pixel pair.

If we have a half-resolution scanline buffer, and are only interested in 7 or fewer bits of significance for each colour channel, we can encode this with a lookup table, where each entry is two TMDS symbols with net balance 0. The toggling of the LSB with each output pixel is not noticeable.

Great. LUTs are fast. On a Cortex-M0+, though, they are not that fast. Each load/store is 2 cycles, and we end up spending a surprising amount of time shifting and masking the data. Here is a vaguely plausible loop for encoding one colour channel, compiled with -O3 -mcpu=cortex-m0plus on gcc 9 (Godbolt link).

C

void tmds_encode_16bpp(const uint16_t *pixbuf, uint32_t *tmdsbuf, size_t n_pix, uint16_t chan_mask, unsigned int chan_shift) {
    for (size_t i = 0; i < n_pix; ++i) {
        unsigned int idx = (pixbuf[i] >> chan_shift) & chan_mask;
        tmdsbuf[2 * i] = tmds_table[idx];
        tmdsbuf[2 * i + 1] = tmds_table[idx + 1];
    }
}

ARMv6M

tmds_encode_16bpp(unsigned short const*, unsigned long*, unsigned int, unsigned short, unsigned int):
        push    {r4, r5, r6, r7, lr}
        ldr     r7, [sp, #20]
        cmp     r2, #0
        beq     .L1
        lsls    r2, r2, #3
        ldr     r5, .L6
        adds    r2, r1, r2

.L4:
        ldrh    r4, [r0]     ; 2 cyc
        adds    r0, r0, #2   ; 1 cyc
        asrs    r4, r4, r7   ; 1 cyc
        ands    r4, r3       ; 1 cyc

        lsls    r6, r4, #2   ; 1 cyc
        ldr     r6, [r5, r6] ; 2 cyc
        adds    r4, r4, #1   ; 1 cyc
        str     r6, [r1]     ; 2 cyc

        lsls    r4, r4, #2   ; 1 cyc
        ldr     r4, [r5, r4] ; 2 cyc
        str     r4, [r1, #4] ; 2 cyc

        adds    r1, r1, #8   ; 1 cyc
        cmp     r2, r1       ; 1 cyc
        bne     .L4          ; 2 cyc if taken
.L1:
        pop     {r4, r5, r6, r7, pc}

Focusing on the loop starting at .L4, this is a surprisingly literal translation -- first load a pixel, bump the pointer, mask and shift (5 cycles). Next transfer a pixel from the LUT to the output buffer (5 cycles) while bumping the LUT index (1 cycle), transfer the second pixel (5 cycles), do a little bookkeeping and branch back to the start (4 cycles). Each loop takes 20 cycles, and encodes one colour channel of 2 output pixels.

We must output a pixel once per 10 system clock cycles (as the system runs at the TMDS bit clock), and since we are doubling pixels horizontally we may as well double vertically too, by using each encoded buffer twice. Taking horizontal blanking into account (1:4 ratio at VGA), we would spend 1.2 of our two cores on TMDS encode, and have 0.8 cores left to generate DVI timing and render graphics.

The compiler has messed up here (or perhaps I have unwittingly constrained it to produce bad code by writing shoddy C), and we can save 4 cycles right off the bat with better instruction selection:

.L4:
        ldrh    r4, [r0]     ; 2 cyc
        adds    r0, r0, #2   ; 1 cyc
        asrs    r4, r4, r7   ; 1 cyc
        ands    r4, r3       ; 1 cyc

        lsls    r4, r4, #2   ; 1 cyc
        ldr     r6, [r5, r4] ; 2 cyc
        stmia   r1!, {r6}    ; 2 cyc

        adds    r4, r4, #4   ; 1 cyc
        ldr     r6, [r5, r4] ; 2 cyc
        stmia   r1!, {r6}    ; 2 cyc

        cmp     r2, r1       ; 1 cyc
        bne     .L4          ; 2 cyc if taken

But this is still painfully slow -- it wouldn't even fit on one core. Some avenues for improvement:

  • Use a word load to fetch two input pixels at once, so we can amortise the load cost, and some of the shift/mask cost
  • Use larger ldmia and stmia on the LUT to squeeze more memory bandwidth out of the M0+ (ldr is 2 cycles and ldmia is n + 1)
  • Use the interpolators on RP2040 to accelerate address generation

The interpolator is a fun piece of hardware for accelerating fixed point arithmetic. Note: "interpolator" is a working title which we will definitely not forget to change to something better before launch. The original plan was a simple configurable 2D phase accumulator that we could use to play Super Mario Kart on the FPGA platform at 48 MHz. Sadly, that game port never materialised, not least because we couldn't publish it. After a lot of back and forth between hardware and software, we realised that making the datapath a little more flexible would go a long way, and this eventually let to the current guise of the interpolator:

Our trick here is loading a one-word pixel pair into one of the accumulators, and configuring the interpolator to extract the correct bits of each pixel, shift them, and add them to a LUT base pointer. The interpolator doesn't have a left shift (not needed for Super Mario Kart) so for the blue channel (least significant in our RGB565 pixel format) we need to do one left shift per two pixels on the processor, to scale up to the LUT entry size. For the other channels we can use a different loop, without the left shift. Here is the encode loop from tmds_encode.S:

// r0: Input buffer (word-aligned)
// r1: Output buffer (word-aligned)
// r2: Input size (pixels)
// r3: Left shift amount

decl_func tmds_encode_loop_16bpp_leftshift
	push {r4, r5, r6, r7, lr}
	lsls r2, #3
	add r2, r1
	mov ip, r2
	ldr r2, =(SIO_BASE + SIO_INTERP0_ACCUM0_OFFSET)
	b 2f
.align 2
1:
.rept TMDS_ENCODE_UNROLL
	ldmia r0!, {r4}             ; 2 cyc
	lsls r4, r3                 ; 1 cyc
	str r4, [r2, #ACCUM0_OFFS]  ; 1 cyc
	ldr r4, [r2, #PEEK0_OFFS]   ; 1 cyc
	ldmia r4, {r4, r5}          ; 3 cyc
	ldr r6, [r2, #PEEK1_OFFS]   ; 1 cyc
	ldmia r6, {r6, r7}          ; 3 cyc
	stmia r1!, {r4, r5, r6, r7} ; 5 cyc
.endr
2:
	cmp r1, ip                  ; 1 cyc
	bne 1b                      ; 2 cyc if taken
	pop {r4, r5, r6, r7, pc}

Assuming TMDS_ENCODE_UNROLL=1, each loop iteration takes 20 cycles, and produces 4 output pixels. Taking the lack of left shift for red and green into account, this works out to 58% of a core to do TMDS encode, which is just over 2x faster than the compiled LUT loop. We can get another 10 or 15% performance by increasing TMDS_ENCODE_UNROLL.

We handle 8bpp pixels in a similar way, but use both interpolators -- one to extract pixels 0 and 1 from the loaded word, and one for pixels 2 and 3. 8bpp encode is slightly faster than 16bpp encode, because we get four pixels for each load from the pixel buffer.

It is just barely possible to do full resolution encode, which is what is shown off in the first image at the top of this Readme. The code is awful, go check it out if you hate yourself.

picodvi's People

Contributors

bruelltuete avatar dlehenbauer avatar leo60228 avatar lowfatcode avatar michaelbell avatar neuschaefer avatar wren6991 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

picodvi's Issues

RGB8 Half screen right

I modified the vista demo just to show a 640x480 pattern in RGB565 which works right

#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/sem.h"
#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/pll.h"
#include "hardware/sync.h"
#include "hardware/gpio.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/vreg.h"

#include "tmds_encode.h"
#include "dvi.h"
#include "dvi_serialiser.h"
#include "common_configs.h"
//#include "C64combo.h"

// TMDS bit clock 252 MHz
// DVDD 1.2V
#define FRAME_WIDTH  640
#define FRAME_HEIGHT 480

#define VREG_VSEL VREG_VOLTAGE_1_20
#define DVI_TIMING dvi_timing_640x480p_60hz

struct dvi_inst dvi0;
struct semaphore dvi_start_sem;

static inline void prepare_scanline(const uint32_t *colourbuf, uint32_t *tmdsbuf) {
	const uint pixwidth = FRAME_WIDTH;
	tmds_encode_data_channel_fullres_16bpp(colourbuf, tmdsbuf + 0 * pixwidth, pixwidth, 4, 0);
	tmds_encode_data_channel_fullres_16bpp(colourbuf, tmdsbuf + 1 * pixwidth, pixwidth, 10, 5);
	tmds_encode_data_channel_fullres_16bpp(colourbuf, tmdsbuf + 2 * pixwidth, pixwidth, 15, 11);
}

// Core 1 handles DMA IRQs and runs TMDS encode on scanline buffers it
// receives through the mailbox FIFO
void __not_in_flash("main") core1_main() {
	dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
	sem_acquire_blocking(&dvi_start_sem);
	dvi_start(&dvi0);

	while (1) {
		const uint32_t *colourbuf = (const uint32_t*)multicore_fifo_pop_blocking();
		uint32_t *tmdsbuf = (uint32_t*)multicore_fifo_pop_blocking();
		prepare_scanline(colourbuf, tmdsbuf);
		multicore_fifo_push_blocking(0);
	}
	__builtin_unreachable();
}

uint16_t img_buf[FRAME_HEIGHT / 3][FRAME_WIDTH];

int __not_in_flash("main") main() {
	vreg_set_voltage(VREG_VSEL);
	sleep_ms(10);
	set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);

	setup_default_uart();

	printf("Configuring DVI\n");

	dvi0.timing = &DVI_TIMING;
	dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
	
	printf("Copy Image pattern\n");
	for (int y=0; y< FRAME_HEIGHT/3; y++) {
		for (int x=0; x< FRAME_WIDTH; x++) {
			int red = x * 32 / FRAME_WIDTH;
			int green = y * 64 / (FRAME_HEIGHT/3);
			int blue = 31 - (x * 32) / FRAME_WIDTH;
			img_buf[y][x] = (x%8>0)&&(y%4>0) ? blue<<11 |green<<5 |red : 0xFFFF;
		}
	}

	dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
    
	printf("Core 1 start\n");
	sem_init(&dvi_start_sem, 0, 1);
	hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
	multicore_launch_core1(core1_main);

	sem_release(&dvi_start_sem);
	while (1) {
		for (int y = 0; y < FRAME_HEIGHT; y+=2) {
			uint32_t *our_tmds_buf, *their_tmds_buf;
			queue_remove_blocking_u32(&dvi0.q_tmds_free, &their_tmds_buf);
			multicore_fifo_push_blocking((uint32_t)img_buf[y/3]);
			multicore_fifo_push_blocking((uint32_t)their_tmds_buf);
	
			queue_remove_blocking_u32(&dvi0.q_tmds_free, &our_tmds_buf);
			prepare_scanline((const uint32_t*)(img_buf[(y+1)/3]), our_tmds_buf);
			
			multicore_fifo_pop_blocking();
			queue_add_blocking_u32(&dvi0.q_tmds_valid, &their_tmds_buf);
			queue_add_blocking_u32(&dvi0.q_tmds_valid, &our_tmds_buf);
		}
	}
	__builtin_unreachable();
}

I made modifications to build the same example in RGB8, left half shows right, right half works with error

#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/sem.h"
#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/pll.h"
#include "hardware/sync.h"
#include "hardware/gpio.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/structs/ssi.h"
#include "hardware/vreg.h"

#include "tmds_encode.h"
#include "dvi.h"
#include "dvi_serialiser.h"
#include "common_configs.h"
//#include "C64combo.h"

// TMDS bit clock 252 MHz
// DVDD 1.2V
#define FRAME_WIDTH  640
#define FRAME_HEIGHT 480

#define VREG_VSEL VREG_VOLTAGE_1_20
#define DVI_TIMING dvi_timing_640x480p_60hz

struct dvi_inst dvi0;
struct semaphore dvi_start_sem;

static inline void prepare_scanline(const uint32_t *colourbuf, uint32_t *tmdsbuf) {
	const uint red_msb   = 7;
	const uint red_lsb   = 5;
	const uint green_msb = 4;
	const uint green_lsb = 2;
	const uint blue_msb  = 1;
	const uint blue_lsb  = 0;
	const uint pixwidth = FRAME_WIDTH;
	tmds_encode_data_channel_8bpp((const uint32_t*)colourbuf, tmdsbuf, pixwidth / 2, blue_msb, blue_lsb);
	tmds_encode_data_channel_8bpp((const uint32_t*)colourbuf, tmdsbuf + pixwidth, pixwidth / 2, green_msb, green_lsb);
	tmds_encode_data_channel_8bpp((const uint32_t*)colourbuf, tmdsbuf + 2 * pixwidth, pixwidth / 2, red_msb, red_lsb);
}

// Core 1 handles DMA IRQs and runs TMDS encode on scanline buffers it
// receives through the mailbox FIFO
void __not_in_flash("main") core1_main() {
	dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
	sem_acquire_blocking(&dvi_start_sem);
	dvi_start(&dvi0);

	while (1) {
		const uint32_t *colourbuf = (const uint32_t*)multicore_fifo_pop_blocking();
		uint32_t *tmdsbuf = (uint32_t*)multicore_fifo_pop_blocking();
		prepare_scanline(colourbuf, tmdsbuf);
		multicore_fifo_push_blocking(0);
	}
	__builtin_unreachable();
}

uint8_t img_buf[FRAME_HEIGHT / 3][FRAME_WIDTH];

int __not_in_flash("main") main() {
	vreg_set_voltage(VREG_VSEL);
	sleep_ms(10);
	set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);

	setup_default_uart();

	printf("Configuring DVI\n");

	dvi0.timing = &DVI_TIMING;
	dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
	
	printf("Copy Image pattern\n");
	for (int y=0; y< FRAME_HEIGHT/3; y++) {
		for (int x=0; x< FRAME_WIDTH; x++) {
			int red = x * 4 / FRAME_WIDTH;
			int green = y * 4 / (FRAME_HEIGHT/3);
			int blue = 8 - (x * 8) / FRAME_WIDTH;
			img_buf[y][x] = (x%8>0)&&(y%4>0) ? blue<<5 |green<<2 | red : 0xFF;
		}
	}

	dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
    
	printf("Core 1 start\n");
	sem_init(&dvi_start_sem, 0, 1);
	hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
	multicore_launch_core1(core1_main);

	sem_release(&dvi_start_sem);
	while (1) {
		for (int y = 0; y < FRAME_HEIGHT; y+=2) {
			uint32_t *our_tmds_buf, *their_tmds_buf;
			queue_remove_blocking_u32(&dvi0.q_tmds_free, &their_tmds_buf);
			multicore_fifo_push_blocking((uint32_t)img_buf[y/3]);
			multicore_fifo_push_blocking((uint32_t)their_tmds_buf);
	
			queue_remove_blocking_u32(&dvi0.q_tmds_free, &our_tmds_buf);
			prepare_scanline((const uint32_t*)(img_buf[(y+1)/3]), our_tmds_buf);
			
			multicore_fifo_pop_blocking();
			queue_add_blocking_u32(&dvi0.q_tmds_valid, &their_tmds_buf);
			queue_add_blocking_u32(&dvi0.q_tmds_valid, &our_tmds_buf);
		}
	}
	__builtin_unreachable();
}

What could I be doing wrong?

Release one core in 640x240 mode

I successfully integrated pico dvi to capture RGB15Khz video (pre VGA) with a triple s&h ADC.
The 320x240 mode leaves 1 core for my HSYNC VSYNC interrupts and to call DMA which calls dedicated pio.
The 640x480 is not working (either capture and pause hdmi or viceversa) since 2 cores are fully used and interrupts are interferring in bad moments.
Since RGB15K uses just 240 vertical lines in progressive mode, could be the code arranged to either generate a black line in odd lines or to repeat the odd line in the even ones.
How could this be achieved?
image

Writing to flash, crashes dvi

Hi Wren6991!

I want to know, if there is a way, to store data in the flash, whitout crashing the app, i'm using a temporary register to store interruptions, do write data cycle, and return interruptions, but dvi crashes, reboot pico, and the data is correctly store, but i need to reboot pico manually.

Trying to write some text in terminal app

Hi Wren6991!

Do you know, how to turn the tmds pins, in input mode, and after 5 segs. turn on again to continue drawing?

I´ve tried:

void tmds_as_input() {
for (int x_tmds = GPIO_12; x_tmds < GPIO_12 + 7; x_tmds++) {
gpio_init(x_tmds);
gpio_set_dir(x_tmds, GPIO_IN);}
}
void tmds_as_output() {
for (int x_tmds = GPIO_12; x_tmds < GPIO_12 + 7; x_tmds++) {
gpio_init(x_tmds);
gpio_set_dir(x_tmds, GPIO_OUT);}
}

With no luck, because it doesn´t send signal again...

Thx in advice!

usb support?

https://www.phoronix.com/scan.php?page=news_item&px=Linux-Generic-USB-Display

this is a fully open spec on how to drive a display over usb, given that the 2nd core is entirely unused, i'm guessing it has enough processing power to be a usb gadget, and implement that protocol, which would then expose the framebuffer to a host over usb!

linux already has drivers to act as either end of that protocol, and there are examples of running it on a pi0 in gadget mode

1280x800 resolution support

As I understand, the maximum supported resolution (with overvoltage) is 1280x720. Would 1280x800 be possible with some more overvoltage?

Why do you use only 1D-Arrays?

Hey @Wren6991,
just trying to dig through the color-terminal example and understand, what's going on.

I noticed that you always use 1D-Arrays, even when representing multi-D Data (2D like the charbuf or 3D like the font or array of colorplanes)

Personally, i find this very counter-intuitive and it gives me a hard time understanding the code and so i am wondering why do you do this?

add beginner-friendly usage documentation and/or use-case driven examples

Hello,
i'm really impressed by what you managed to squeeze out of the RP2040 and very excited to try this myself.
In your readme you explain the creation of this project and the technical details very nicely, but only from a "PicoDVI internal" and somewhat low-level point of view. Your examples do a good job at showcasing the capabilites of the library, but they don't really help applying it to a specific use-case.
I also couldn't find much other ressources about this online (apart from a PiCockpit Blog Entry ).
Also some of the information (e.g about clock frequency, core voltage etc.) is scattered in the text and easily overlooked.

As I'm new to the PiPico/RP2040 world and Microcontrollers are just a hobby for me, I'm really having trouble understanding what's going on in the examples and how to translate it to my intended use-case.
(For me, the terminal-app is closest to my use-case, so my ideas and examples are kind of focued on that but most of it probably applies to the other example-apps as well)

So i suggest adding some more user-oriented / high-level documentation that

  • collects setup prerequisites and their implications in a clear overview. Stuff like:
    • system frequency / overclocking (what's the required system frequency, what are possible side effects of altering it?)
    • altering core voltages (dangers/side effects?)
    • used hardware modules (PIO Blocks, DMA-channels, interpolator etc.)
    • given it's popularity and widespread availability: a section on the Pi Pico (even if it's just a "fully compatible with Pi Pico" or sth)
    • an overview over the different modes and their implications (memory usage, freq & voltage requirements etc.)
  • answers questions like
    • what do i need to take into consideration, if i want to build a project on top of/around this library (both hard- and software)
    • how can i customise it (e.g. adding custom symbols to the font, change it from 8x8 to a more common 5x8 (HD44780 like) font)
    • what are your considerations regarding the assets' data formats (eg. why are you representing 2D or 3D information in 1D arrays)

and maybe also some examples that present a concrete use-case instead of showcasing the library:

  • an example terminal-drivative that reads text from UART/USB stdio and displays it in a terminal-like fashion
  • an example on how to combine apps:
    • display some text in front of an image (like a splash screen) or embed a logo-like image into a terminal output
    • combine text-output with drawing lines to display a fixed-size table (e.g each table cell is 2 rows by 10 characters but the table-lines' thickness is less than one glyphs height or width)
    • a multicolor terminal or table (where fg and bg color can be set per line or cell for example)
      Forget about that, didn't see the color-terminal example since it's not mentioned in the documentation, my bad

  • read sensor data (analog values, digital pins or maybe even via serial) and display it on the screen in simple line or bar-graphs
  • i doubt it's possible, but if you disagree: a turtle-like drawing app

This list is just a compilation of ideas, some of which probably don't make sense or even are outright impossible but i think it illustrates the intention of this issue.
Unfortunately I'm not versed enough in C/C++ and don't really understand your library, so I can't do this myself, but i'd be happy to help as proof-reader or do anything else i can to help.

Background:
The microcontroller-world is a hobby for me. I started to teach myself with Arduino, then advanced to dealing with the underlying Atmel/Microchip MCUs directly and now, encumbered by their limited resources, I'm trying to utilize the RP2040 / Pi Pico for selected projects.

I believe there are many people like me out there who would love to use this library to add a visual interface to all kinds of neat little projects but are not skilled enough (yet) to do so with the rather low-level documentation already provided.

Just to give you an idea: my current Project is a DMX-Monitor.
It reads DMX (digital lighting control protocol) values, displays them on the screen in a table and highlights the last changed value(s)
DMX essentially is a list of 512 8-bit values (so 3 digits for display needed) and i would like to display at least 48 or more).

So i imagine a 10x10 table for the values and change the background for changed values.
I dream of displaying the channel number in grey and the value in white in each cell, but since i have no idea at all how to approach this, fancy stuff hast to wait until basics work.

Red bars on screen

Hey i have a issue and i dont get it why this happens.

I use a DVI Sock for my test and the pico_sock_cfg config but when im compile and uplode to my Pico i get Red Bars
i use the apps whit no Editing to try but when im using the demo programms from BuyZero this works fine.

Anyone have a idea why this happens ?

160x160 scale x3

I'm trying to scale an image that is 160x160 to 480x480, inside 640x480, so there is a black border on left/right. Vertical repeat x3 was easy, but I'm having trouble figuring out if I can do the horizontal repeat x3. Would this require some lower level code modification or is it already possible?

where to ask for help?

As a beginner learning the details of video, this project is great for teaching the basics of how video is sent to a monitor and working with the limitations of hardware. However, I am still new to software engineering. For example, I dont know how to convert a jpg to a .h file. I dont know how to compile just a single app. I managed to walk through your blog entry and got ALL the examples you made to work. But I am little more than a monkey hacking at a keyboard. How could I compile just ONE app?
ThaNK YOU.

640x480@50hz

Is it possible an valid to output 640x480 at 50hz?
I built an RGB2HDMI scanner and the limitation is the memory to store all the video.
If it could be possible to synchronize RGB timings to hdmi timings, I would only need just a few width lines to capture and then render to hdmi.

Making a board for Arduino Nano connect

Hi Luke,

It is a bit offtopic so I hope it is okay to ask you here.
I am trying to make a board for using your lib with the arduino nano connect. Currently my board works with some displays but not all of them (while the sock is flawless with any display). Would you mind having a look at the circuit ? I am kind of a noob when it comes to hardware.

Here is the repo: https://github.com/melkael/2040_nano_dvi

Thanks

Samsung TV?

I can't seem to get any of these examples to word at all on a Samsung TV. The TV does not detect the pico at all, although some of the demos work correctly on computer monitors and even hdmi capture devices.
Could it be that Samsungs don't fully support DVI?

Never mind, forgot the 5v connection, it seems some displays don't need it, some do.

bad_apple mkframes.sh ffmpeg error

[Parsed_threshold_0 @ 0x55f0ec5e7200] First input link default parameters (size 960x720) do not match the corresponding second input link threshold parameters (1920x1080) and/or third input link min parameters (1920x1080) and/or fourth input link max parameters (1920x1080)
[Parsed_threshold_0 @ 0x55f0ec5e7200] Failed to configure output pad on Parsed_threshold_0
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #3:0
Conversion failed!

Not working with older DVI monitors

I've been experimenting with this project on some older DVI monitors and can't get them to display an image. It does work on more modern monitors that have HDMI and DVI connectors. I've been testing with an HP LP2065 and a Dell 2007FPb which are both 1600x1200 4:3 20" monitors with DVI input.

These older monitors also have a problem displaying the output of a raspberry Pi unless the Pi is configured for true DVI output using hdmi_drive=1 in config.txt.

Interestingly, if I put a HDMI splitter between the source and the monitor I can get an image and this works for both PicoDVI and the raspberry Pi when configured for HDMI mode (i.e. NOT using hdmi_drive=1 in config.txt) so it looks like something in the bitstream formatting is upsetting these older DVI monitors.

The splitter I was using was one of these:
https://www.ebay.co.uk/itm/325095286549
I also tried one of these but this one didn't work:
https://www.ebay.co.uk/itm/255345890217
(Maybe the first one is reformatting the bitstream and the other is just buffering it?)

I also tried changing the GPIO drive strength and slew rate settings but that didn't help

Any idea what the problem is?

In file included from .pio\libdeps\development\PicoDVI - Adafruit Fork\src\libdvi\tmds_encode.S:3: .pio\libdeps\development\PicoDVI - Adafruit Fork\src\libdvi\dvi_config_defs.h:12:10: fatal error: pico/config.h: No such file or directory 12 | #include "pico/config.h"

Anybody know how to fix this?

This is an error for the PicoDVI library downloaded from platfrom.
Here is the full build output:

Library Manager: Could not parse manifest -> Extra data: line 1 column 7 (char 6)
Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/raspberrypi/adafruit_feather_dvi.html
PLATFORM: Raspberry Pi RP2040 (1.12.0+sha.503933d) > Feather RP2040 DVI
HARDWARE: RP2040 133MHz, 264KB RAM, 8MB Flash
DEBUG: Current (blackmagic) External (blackmagic, cmsis-dap, jlink, pico-debug, picoprobe, raspberrypi-swd)
PACKAGES:

  • framework-arduinopico @ 1.30800.0+sha.d53d003
  • tool-mklittlefs-rp2040-earlephilhower @ 5.100300.230216 (10.3.0)
  • tool-openocd-rp2040-earlephilhower @ 5.120300.240125 (12.3.0)
  • tool-rp2040tools @ 1.0.2
  • toolchain-rp2040-earlephilhower @ 5.120300.240125 (12.3.0)
    Flash size: 8.00MB
    Sketch size: 8.00MB
    Filesystem size: 0.00MB
    Maximium Sketch size: 8384512 EEPROM start: 0x107ff000 Filesystem start: 0x107ff000 Filesystem end: 0x107ff000
    LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Warning! Ignoring broken library manifest in C:\Users\Carlos\Desktop\Pico4.3_homeassistant\Pico4.3_homeassistant\lib\FT6X36
    Library Manager: Could not parse manifest -> Extra data: line 1 column 7 (char 6)
    Library Manager: Could not parse manifest -> Extra data: line 1 column 7 (char 6)
    Found 73 compatible libraries
    Scanning dependencies...
    Library Manager: Could not parse manifest -> Extra data: line 1 column 7 (char 6)
    Library Manager: Could not parse manifest -> Extra data: line 1 column 7 (char 6)
    Dependency Graph
    |-- lvgl @ 8.3.6
    |-- PicoDVI - Adafruit Fork @ 1.1.0
    |-- Crowbits_DHT20
    |-- Grove - Digital Light Sensor @ 1.0.0
    |-- Adafruit GFX Library @ 1.11.9
    |-- SPI @ 1.0
    |-- WiFi @ 1.0.0
    |-- Wire @ 1.0
    |-- FT6X36
    |-- gt911-arduino-main
    |-- XPT2046_Touchscreen
    Building in release mode
    Compiling .pio\build\development\FrameworkArduinoBootloader\boot2_w25q080_2_padded_checksum.S.o
    Compiling .pio\build\development\src\light.c.o
    Compiling .pio\build\development\src\main.cpp.o
    Compiling .pio\build\development\src\no_light.c.o
    Compiling .pio\build\development\src\ui.c.o
    Compiling .pio\build\development\src\ui_helpers.c.o
    Compiling .pio\build\development\src\ui_img_small_hum_png.c.o
    Compiling .pio\build\development\src\ui_img_small_logo_png.c.o
    Compiling .pio\build\development\src\ui_img_small_off_png.c.o
    Compiling .pio\build\development\src\ui_img_small_temp_png.c.o
    Generating linkerscript C:\Users\Carlos\Desktop\Pico4.3_homeassistant\Pico4.3_homeassistant.pio\build\development/memmap_default.ld
    Compiling .pio\build\development\libf08\FreeRTOS\croutine.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\event_groups.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\heap_3.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\idle_task_static_memory.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\list.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\port.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\queue.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\stream_buffer.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\tasks.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\timers.c.o
    Compiling .pio\build\development\libf08\FreeRTOS\variantHooks.cpp.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_disp.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_event.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_group.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_indev.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_indev_scroll.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_class.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_draw.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_pos.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_scroll.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_style.c.o
    Archiving .pio\build\development\libf08\libFreeRTOS.a
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_style_gen.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_obj_tree.c.o
    Indexing .pio\build\development\libf08\libFreeRTOS.a
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_refr.c.o
    Compiling .pio\build\development\lib3ef\lvgl\core\lv_theme.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\arm2d\lv_gpu_arm2d.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_arc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_img.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_label.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_layer.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_line.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_mask.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_rect.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_transform.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_draw_triangle.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_img_buf.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_img_cache.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\lv_img_decoder.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\pxp\lv_draw_pxp.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\pxp\lv_draw_pxp_blend.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\pxp\lv_gpu_nxp_pxp.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\pxp\lv_gpu_nxp_pxp_osa.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_draw_vglite.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_draw_vglite_arc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_draw_vglite_blend.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_draw_vglite_line.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_draw_vglite_rect.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_vglite_buf.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\nxp\vglite\lv_vglite_utils.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_arc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_bg.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_composite.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_img.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_label.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_layer.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_line.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_mask.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_polygon.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_rect.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_stack_blur.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_texture_cache.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sdl\lv_draw_sdl_utils.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\stm32_dma2d\lv_gpu_stm32_dma2d.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_arc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_blend.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_dither.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_gradient.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_img.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_layer.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_letter.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_line.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_polygon.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_rect.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\sw\lv_draw_sw_transform.c.o
    Compiling .pio\build\development\lib3ef\lvgl\draw\swm341_dma2d\lv_gpu_swm341_dma2d.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\layouts\flex\lv_flex.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\layouts\grid\lv_grid.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\bmp\lv_bmp.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\ffmpeg\lv_ffmpeg.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\freetype\lv_freetype.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\fsdrv\lv_fs_fatfs.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\fsdrv\lv_fs_posix.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\fsdrv\lv_fs_stdio.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\fsdrv\lv_fs_win32.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\gif\gifdec.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\gif\lv_gif.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\png\lodepng.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\png\lv_png.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\qrcode\lv_qrcode.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\qrcode\qrcodegen.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\rlottie\lv_rlottie.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\sjpg\lv_sjpg.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\libs\sjpg\tjpgd.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\lv_extra.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\fragment\lv_fragment.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\fragment\lv_fragment_manager.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\gridnav\lv_gridnav.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\ime\lv_ime_pinyin.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\imgfont\lv_imgfont.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\monkey\lv_monkey.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\msg\lv_msg.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\others\snapshot\lv_snapshot.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\themes\basic\lv_theme_basic.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\themes\default\lv_theme_default.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\themes\mono\lv_theme_mono.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\animimg\lv_animimg.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\calendar\lv_calendar.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\calendar\lv_calendar_header_arrow.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\calendar\lv_calendar_header_dropdown.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\chart\lv_chart.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\colorwheel\lv_colorwheel.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\imgbtn\lv_imgbtn.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\keyboard\lv_keyboard.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\led\lv_led.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\list\lv_list.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\menu\lv_menu.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\meter\lv_meter.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\msgbox\lv_msgbox.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\span\lv_span.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\spinbox\lv_spinbox.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\spinner\lv_spinner.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\tabview\lv_tabview.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\tileview\lv_tileview.c.o
    Compiling .pio\build\development\lib3ef\lvgl\extra\widgets\win\lv_win.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_dejavu_16_persian_hebrew.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_fmt_txt.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_loader.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_10.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_12.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_12_subpx.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_14.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_16.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_18.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_20.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_22.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_24.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_26.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_28.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_28_compressed.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_30.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_32.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_34.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_36.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_38.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_40.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_42.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_44.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_46.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_48.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_montserrat_8.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_simsun_16_cjk.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_unscii_16.c.o
    Compiling .pio\build\development\lib3ef\lvgl\font\lv_font_unscii_8.c.o
    Compiling .pio\build\development\lib3ef\lvgl\hal\lv_hal_disp.c.o
    Compiling .pio\build\development\lib3ef\lvgl\hal\lv_hal_indev.c.o
    Compiling .pio\build\development\lib3ef\lvgl\hal\lv_hal_tick.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_anim.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_anim_timeline.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_area.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_async.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_bidi.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_color.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_fs.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_gc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_ll.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_log.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_lru.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_math.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_mem.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_printf.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_style.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_style_gen.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_templ.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_timer.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_tlsf.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_txt.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_txt_ap.c.o
    Compiling .pio\build\development\lib3ef\lvgl\misc\lv_utils.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_arc.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_bar.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_btn.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_btnmatrix.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_canvas.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_checkbox.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_dropdown.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_img.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_label.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_line.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_objx_templ.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_roller.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_slider.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_switch.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_table.c.o
    Compiling .pio\build\development\lib3ef\lvgl\widgets\lv_textarea.c.o
    Compiling .pio\build\development\lib7ac\Wire\Wire.cpp.o
    Compiling .pio\build\development\libe36\SPI\SPI.cpp.o
    Compiling .pio\build\development\lib2a9\Adafruit BusIO\Adafruit_BusIO_Register.cpp.o
    Compiling .pio\build\development\lib2a9\Adafruit BusIO\Adafruit_I2CDevice.cpp.o
    Compiling .pio\build\development\lib2a9\Adafruit BusIO\Adafruit_SPIDevice.cpp.o
    Archiving .pio\build\development\lib3ef\liblvgl.a
    Indexing .pio\build\development\lib3ef\liblvgl.a
    Archiving .pio\build\development\lib7ac\libWire.a
    Compiling .pio\build\development\lib2f9\Adafruit GFX Library\Adafruit_GFX.cpp.o
    Compiling .pio\build\development\lib2f9\Adafruit GFX Library\Adafruit_GrayOLED.cpp.o
    Indexing .pio\build\development\lib7ac\libWire.a
    Compiling .pio\build\development\lib2f9\Adafruit GFX Library\Adafruit_SPITFT.cpp.o
    Compiling .pio\build\development\lib2f9\Adafruit GFX Library\glcdfont.c.o
    Archiving .pio\build\development\libe36\libSPI.a
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\PicoDVI.cpp.o
    Indexing .pio\build\development\libe36\libSPI.a
    Archiving .pio\build\development\lib2a9\libAdafruit BusIO.a
    Indexing .pio\build\development\lib2a9\libAdafruit BusIO.a
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\dvi.c.o
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\dvi_serialiser.c.o
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\dvi_timing.c.o
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\tmds_encode.S.o
    Compiling .pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\tmds_encode.c.o
    In file included from .pio\libdeps\development\PicoDVI - Adafruit Fork\src\libdvi\tmds_encode.S:3:
    .pio\libdeps\development\PicoDVI - Adafruit Fork\src\libdvi\dvi_config_defs.h:12:10: fatal error: pico/config.h: No such file or directory
    12 | #include "pico/config.h"
    | ^~~~~~~~~~~~~~~
    compilation terminated.
    *** [.pio\build\development\liba13\PicoDVI - Adafruit Fork\libdvi\tmds_encode.S.o] Error 1

No video output

Hey, I'm relatively new with Pico.

I'm getting no signals on screens I have. I'm using pico-dvi-sock (also tried to wire it manually with the resistors) with no result so far. I've tried different examples, different Pico boards, I double-checked that I compiled the project with -DPICO_COPY_TO_RAM=1.

I'm getting a clock signal at 25.2 Mhz. It doesn't look exactly square or sine, but it does look like clock pulses. The reverse clock signal is also there:

Clock

There's some data on the data lines, but it doesn't look like a digital signal. Here're two images – data and clock signals together and differential data signals only:

Clock + Data
Data

I'm not sure of what went wrong and how to troubleshot it further. Any ideas or recommendations?

I would like a simple code, to understand

I come from stm32, programming in c, I would like to understand with a simple code, what synchronicities are, and a simple green line, I have done it in vga, but I can't understand it through dvi-hdmi...

Will this work with MicroMod Big Display Carrier Board

Hi Luke,
This isn't specifically your issue, but I was wondering if you have any experience or knowledge of the Sparkfun MicroMod Big Display Carrier Board and RP2040 MicroMod. I recently bought this setup and the example uf2 files they provide don't appear to work. No responses from their forum as yet.
I only ask because they reference your software and their design is somewhat based on your design (I noticed they still use the capacitive coupling of the HDMI signals).
I've tried compiling your software and it doesn't work on this setup either (compiles fine, but no display).
Any suggestions for troubleshooting? RP2040 seems to load okay, I'll try to get a look at the signals to the HDMI connector with a scope.
MicroMod_Big_Display_Schematic.pdf

Thanks,
Ralph

Link to their board https://www.sparkfun.com/products/17718

RGB 15Khz scanline to HDMI

This is just a question, how feasible you see, knowing the current usage of cpu, to implement an RGB scanline capture that buffers each line into several HDMI video lines?

I started toying with the pico vga to generate video, sincronize to HSYNC and VSYNC from RGB (15Khz) and was working on how to capture fast RGB in 565B with a triple ADC.

The Idea is to make an OSSC on a budget

Assembly troubleshooting?

I ordered a few boards from OSHPark and put them together, but I'm not getting sync on hello_DVI, even with a 1.3V overvolt. I don't have an oscilloscope; is there a good way to troubleshoot assembly? Some macro photos look like every resistor is set properly (none fall off, at least), and there are no bridges on the plug pins, but I'm not confident. With a scope, I'd just look at the outputs, but don't got. Anyone got a clever idea I can borrow?

Alternatively, would there be any gotchas just making the board a half inch longer and using 0603 resistors for a bit more breathing room?

Image Encoding

I have the code up and running but I am interested in trying an example of my own. What was used to create the image H files? Is this code included in this repo? Thanks

Off/On pico dvi, is possible?

Hi Wren6991,

I want to know, if is posible to power off dvi by software, put the tmds pins in input mode for 5 secs. And re init video functions. I've tried multicore functions whitout luck...

I´ve can´t hear something in colour_terminal_audio app...

I´ve made my own test board, and re asign output pines to adapt to my board, i´ve compile the 3 folders with audio extra in the name.

But i´ve only see in the tv, the original image, and in the right, some slim lines moving, the tv shows dvi signal.

In the pdf of ikjordan, i´ve see three new pins, so, i´ve thing, i need it to change mode from dvi to hdmi? can i remap those? Because in my configuration, i´ve use that pines, in tmds signals =(

Question: packtiles option for sprite_bounce

Hello to everyone.
Please tell me packtiles options to make header files for sprite_bounce.

I tried to replace the image of sprite_bounce with my original image.
In order to prepare a header file of my original image, I use the packtiles script in /software/script directry.
But I can not watch my original image bouncing on my display.
Only moving colorful horizontal lines appear.
I tried several options like this.
$ ./packtiles -sdf rgab5515 test_128x128.png test_128x128_rgab5515.h
Of cource I edit the main.c file suitable for my original image replaceng the name of the orginal ones.

PS
I can replace the image of hello_dvi with my original image header file obtaind in use of the option shown above.

DVI and MicroPython support

Is there any way being able to have DVI output from MicroPython script (eg: create a terminal, having REPL available on screen, display some graphics) ?

Reverse 1bpp

Please could we have a version of 1bpp that emits the pixels from each byte in the reverse order.
Many thanks for publishing this library!

HDMI Audio?

Is there any way to support HDMI Audio output with this, maybe with mostly static graphics (now playing or album art)?

Running in flash

Ok, so this isn't really an issue, but I was hoping for some advice (please!).

I've been having lots of fun with this library and have had a go at writing a tmds encoder for a 48k ZX Spectrum. My first attempt at arm assembly, which I'm sure is pretty terrible, but it seems to work fine.

Given that worked, I thought I would try a 128k spectrum but there is not enough RAM with 'copy to ram' set... So I switched it off, and amazingly almost everything keeps working from flash.

But now, when I try to read from the SD card it now stalls the video output, which is visually apparent as white lines on the screen , often followed by the colour channels ending up out of sync.

I figured that I 'just' needed to move some functions to RAM, in particular the isr routines for the SD card. After many random attempts all which had no effect, I thought I would seek some advice.

As some context, the SD card uses dma_irq_0 and a couple of dma channels along with an spi interface. I've set the dvi encoder to use dma_irq_1. I don't think the encoder is under-running as changing the number of buffers makes no difference (although this is a guess).

Any thoughts appreciated, even if it's give up!

Next, input?

This is a really cool project. Bumped into it whilst thinking about line-doubling the output of a VideoNULA fitted to a BBC micro.
To make that work, we'd need input state machines to pick up the 3 x 4bits RGB, HSYNC and VSYNC at max 640x256 pixels.

How to run 640x480 60hz with overclocking upto 416Mhz?

I have ported bunch of emulators like NES/Genesis/GameBoy/Sega Master system to RP2040 and all of them uses VGA output.
Now im hacking them to add HDMI(DVI) output aswell.

But all of them uses Pi Pico with maximum overclocking > 366Mhz (Pico XT runs at 416Mhz).

It's possible to have pico clocked at 416Mhz and have 640x480 60Hz HDMI output? setting sm_config_clckdiv seems not work or i'm doing something wrong.

640x480 8bppx and DVI_SYMBOLS_PER_WORD=1 half right

I'm testing 8bits per pixel (RGB332) in a 640x240 buffer mode using DVI_SYMBOLS_PER_WORD=1

uint8_t framebuf[FRAME_HEIGHT][FRAME_WIDTH];

in core 1 main I'm running the dvi
void __not_in_flash_func(core1_main)() {
	dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
	dvi_start(&dvi0);
        dvi_scanbuf_main_8bpp(&dvi0);
	__builtin_unreachable();
}

video gfx buffer is properly set, but encoding appears to be doing half the screen, what could be wrong?

SDI support?

Feature request (or wondering out loud), could it be possible to support SDI ?

Attemptes to write to flash stall/crash dvi output

I've already seen and read both #21 and #35. #35 just describes a work around which does work for EEPROM but not for littleFS and #21 is just about external flash. On any attempt to write to flash using littleFS both dvi output and the rest of the code crashes, stalls, locks up idk exactly what.
Heres the code I used to test this

#include <PicoDVI.h>
#include <LittleFS.h>
DVIGFX8 display(DVI_RES_320x240p60, true, adafruit_feather_dvi_cfg);
void setup() {  // Runs once on startup
  Serial.begin(9600);
  while (!Serial)
    delay(10);  // Wait for Serial Monitor to open
  Serial.println("Serial started");

  LittleFSConfig cfg;
  cfg.setAutoFormat(true);
  LittleFS.setConfig(cfg);
  
  if (!LittleFS.begin()) {  // Blink LED if insufficient RAM
    Serial.println("LittleFS failed to start");
  } else {
    Serial.println("LittleFS started");
  }

  if (!display.begin()) {  // Blink LED if insufficient RAM
    pinMode(LED_BUILTIN, OUTPUT);
    for (;;)
      digitalWrite(LED_BUILTIN, (millis() / 1000) & 1);
  }
  Serial.println("display started");

  display.setColor(0, 0x0000);  // Color 0: Black
  display.setColor(1, 0xFFFF);  // Color 1: White
  Serial.flush();
}

void loop() {
  display.fillScreen(1);
  delay(3000);
  display.fillScreen(0);
  delay(3000);

  File testFile = LittleFS.open("/Test.txt", "w");
  Serial.println("LittleFS.open");

  testFile.close();
  Serial.println("testFile.close()");

  delay(5000);
  Serial.println("delay(5000);");

  display.swap(false, true);
  Serial.println("display.swap");
}

hdmi connector type

Hello!
Can you give me a name the type of HDMI connector used?
Maybe id or partnumber?
Thank you!

Some examples not working with Pico clone

Hello, everyone!

So I was planning to make a pull request adding support (a pinout description in the "common_dvi_pin_configs.h") for one of our boards - RP2040-PICO-PC (https://www.olimex.com/Products/MicroPython/RP2040-PICO-PC/).

But when tested with the provided examples from this repository it worked well with about half of them.
Here is list of the behavior:
Working fine:
dht_logging, hello_dvi, mandelbrot, terminal, tiles, tiles_parallax
Semi-working:
colour_terminal (colors seem weird), moon (picture is visible but only black and white)
Not working:
bad_apple, christmas_snowflakes, dual_display (understandable since I tested with only 1 display), mandel-full, sprite_bounce, tiles_and_sprites, vista
on all of these I see red screen and sometimes blinking lines somewhere on the screen
Vista-Palette - not working at all - it gives me a message "Input signal out of range".

So I was wondering what could cause some of the examples to work fine, some of the others partially and the rest not working at all?
I don't think it's pinout related since then none of the examples would have worked at all and thus I was thinking of making pull request but I decided to ask for this first.
RP2040-PICO-PC_rev_C.pdf

vscode support

Superv work you've done here.
Just once thing for the ease of use, I created the .vscode folder config files , helps me to have everything in the same place and setting properly my configs.
you can also add a config just to program "pico burn" through sw with "verify reset exit" after programming
launch.json

{
    "version": "0.2.0",
    "configurations": [
        
            { 
            "name": "Pico Debug",
            "device": "RP2040",
            "gdbPath": "arm-none-eabi-gdb",
            "cwd": "${workspaceRoot}",
            "executable": "${command:cmake.launchTargetPath}",
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "openocd",
            "configFiles": [
                "/interface/picoprobe.cfg",
                "/target/rp2040.cfg"
            ],
            "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
            "runToMain": true,
            "searchDir": ["/Users/marcelo.lorenzati/Dev/IoT/openocd/tcl"],
            "postRestartCommands": [
                "break main",
                "continue"
            ]
        }
    ]
}

settings.json

{
    // These settings tweaks to the cmake plugin will ensure
    // that you debug using cortex-debug instead of trying to launch
    // a Pico binary on the host
    "cmake.statusbar.advanced": {
        "debug": {
            "visibility": "hidden"
        },
        "launch": {
            "visibility": "hidden"
        },
        "build": {
            "visibility": "hidden"
        },
        "buildTarget": {
            "visibility": "hidden"
        }
    },
    "cmake.configureSettings": { "PICO_COPY_TO_RAM": "1", "DVI_DEFAULT_SERIAL_CONFIG" :"picodvi_dvi_cfg" },
    "cmake.buildBeforeRun": true,
    "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
    "files.associations": {
        "stdlib.h": "c",
        "hello.pio.h": "c",
        "pio.h": "c",
        "marce.pio.h": "c"
    }
}

Resistor value calculation

This image from the README seems to imply that the resistors are to limit current to 10mA at 3.3V:
image
If that's the case, why are they 270 ohm and not 330 ohm?

Is possible to do fonts more bigs in terminal app?

Hi again Wren6991,

I'm using the color terminal app, and want to know if is possible to do bigger letters, and how to add things to the font[8x8]. I've do it in vga, create fonts, but here i've don't get it, =,(

Question: Could this be adapted to display at higher resolutions at the cost of fps/fill rate?

Awesome project you have here! Got me thinking about other use cases which don't require smooth motion, such as a cheap photo-frame controller or even a cheap DLP 3D printer controller. Even if it took a few seconds to stream in the image off of NAND and fill the display, for the cost it would still be very compelling!

From what I have read, some HDMI receiver ICs really don't like anything below 24Hz, but many are happy down to 15Hz and possibly below (I haven't found any tests below 15Hz). Would be very interesting to see max resolution that could be attained within the bandwidth the RP2040 allows if FPS doesn't matter. 4K even at 0.5 fps would be nuts.

I just got my order of Pico dev boards and will be cobbling together a test bed for your project ASAP, again great work!

Side note: Have also been thinking about MIPI DSI support (8 PIOs vs 8 lane MIPI DSI?) but that seems like a pipe dream, especially since publicly available information on the spec seems almost nonexistent...

Generate custom sprites ?

Hi Luke,

I would like to use my own sprites, could you please indicate how you generate your .h files from the png images ?

Thank you for your great work

EDIT: I tried to use packtiles but was not successful in finding the right parameters (./packtiles --single --format rgab5515 128 eben_128x128.png test.h gives a different file from the one used in the lib which does not display properly)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.