One of the frustrating thing when you deal with small embedded systems is when you want to go for graphic capability (at least medium to high resolution) you must use Linux or another high level OS (and moreover not real time). The reason is the bloody closed source code driver for all these cheap ARM chip (Broadcom, TI, ...). There are some projects that try to do bare-metal on the chip (on RasPI for example) but that's time consuming.
Then I decided to launch HOMER. With HOMER, you'll have the key to do some beautiful graphics, GUI and even games on a classic PC monitor.
HOMER SPECIFICATION:
- 1280x720 (HD) @ 8bpp @ 60Hz (-> done)
- Full palette over 24bit (-> done)
- Double buffering (2 SRAM blocs) (-> done)
- 2D hardware acceleration (HOMER command example: line(0,0,120,500,option) ) (-> done)
- FPGA config file USB upgradable (nobody wants to buy a blaster II) (-> done)
- ESD protected (-> done)
- HDMI output (-> done)
- Audio (-> not worked on this yet)
How Homer works (see the sketch) ?
Homer can connect to any host with a SPI interface or the USB interface if connected to a PC. Supplying Homer is done via SPI connector, via USB interface, or both.
The host (PC, uC, Arduino, ESP8266, whatever...) sends high level commands to the SPI or USB interface (the max speed of SPI is not yet defined, I'm using 10Mbps now). The commands are then pushed to the FIFO. The 2D GPU engine pull the commands and process them. Basically, the engine contains a set of primitives (drawLine, putTxt, circle, fill, blobCopy, selectPalette,...) that read/write the non-displayed frame buffer (FB). Some primitives like putTxt and blobCopy take data from the FLASH and send them to the non-displayed FB. The flash contains user pre-loaded fonts, glyphs and images that are transferred (with processing) to FB with single commands. The host has only to store the useful data in FLASH at once. A special command (SwapBuffers() or whatever the name) ask HOMER to switch the FB that is displayed. Internally, the 2D engine ask the FB controller to do the switch. As soon as the FB controller did it, it sends an ack to the 2D GPU engine, the following commands are then applied to the new non-displayed FB. Transparency management is on work a̶l̶t̶h̶o̶u̶g̶h̶ ̶i̶t̶ ̶i̶s̶ ̶s̶l̶o̶w̶e̶r̶ ̶(̶a̶ ̶“̶r̶e̶a̶d̶ ̶b̶e̶f̶o̶r̶e̶ ̶w̶r̶i̶t̶e̶”̶ ̶o̶f̶ ̶F̶B̶ ̶i̶s̶ ̶n̶e̶c̶e̶s̶s̶a̶r̶y̶)̶. Displaying the content to the screen is done via a simple FB scanning: the CPLD has a counter, synchronised with the FPGA one, that increment the FB RAM addresses. The RAM data are transferred to FB controller then to one of the user-stored palettes. Actually, palettes are LUT with 256 entries and 24bits outputs (8bit per color). The data are then transferred to the HDMI PHY chip with the right timing.
Typically, a host program looks like this:
selectPaletteStrings(3);
selectPaletteBlobs(1);
Loop() {
Clear(); /// or fill(...) or nothing
putString(X,Y, fontIDX, ”blablabla”, foregroundColor, backgroundColor);
...
copyBlob(flashMemAddress, X, Y, W, H, operation); ///operation = bitwise
...
drawLine(X1, Y1, X2, Y2, color, option); ///option will include antialiasing (slower)
...
swapBuffers();
}
Host can implement the commands like this (big endian, SPI 8 bits):
Example for drawLine(X1, Y1, X2, Y2, color, option):
buff[0] = X1U; buff[1] = X1L; buff[2] = Y1U; buff[3] = Y1L;
buff[4] = X2U; buff[5] = X2L; buff[6] = Y2U; buff[7] = Y2L;
buff[8] = color; buff[9] = option;
sendSPI(buff, 10); /// send the buffer to SPI, length = 10
The Frames Per Second (FPS) is 60 maximum, it corresponds to the HD refresh rate of 60Hz. Depending of the 2D engine charge, the FPS may be lower.
It's a long time since this project was released. In the mean time a lot of new things has been landed to the market.
One of which is the unique and spectacular RP2040 (rppico) with it's PIO state machines feature.
Using one core of the RP2040 to output a 720p signal has been done already (https://github.com/Wren6991/PicoDVI).
I think that going in this direction is far more cheaper than using any FPGA.
Then this project (with FPGA) is definitively stopped.