VGA DAC calculator

56 views
Skip to first unread message

charli va

unread,
Oct 31, 2025, 1:57:23 PMOct 31
to fpga-wars-explora...@googlegroups.com
Hello everyone, I'm starting a new thread to introduce this small color palette calculator/visualizer.

https://icestudio.io/play/vga-dac-calc/

Captura de pantalla 2025-10-31 a las 18.56.01.png

We've already discussed it in the thread about the multimedia shield designed by Jesús, but I'm bringing it up now to avoid cluttering this thread.

The calculator allows you to test different resistor values in VGA DAC models so you can see the generated color palettes and check if they fall within the voltage ranges allowed by the VGA standard.

Currently, it includes two DACs: a simple 2-bit/channel one (like the one currently used in the Alhambra's AP-VGA or the one in the shield) and a 4-bit/channel one provided by Jesús and designed for his SIMRETRO board.

With this, for example, you can see why a DAC might display muted colors. It could also be useful for finding specific palettes; for instance, if you want to create a system that generates images with a Game Boy color aesthetic, you could experiment with resistor values until you find a color palette you like.

If I see that this is useful, I want to do the reverse: give it a color palette and have it provide the resistor configuration that most closely matches that palette.

I'll upload the code in a few days. I'm reorganizing my "digital life" and I'm going to change quite a few things, including where I upload my code. If anyone wants or needs the code for this while I'm reorganizing, just ask and I'll send it to you. As always, the license will be completely open.

Good night!

Jo mo

unread,
Oct 31, 2025, 5:10:32 PMOct 31
to FPGAwars: explorando el lado libre
Hello Chali,

One year ago i also used a 4 bit ladder Vga/XGA interface
For  R_ladder i also used 180 ohms but for the R_series i used 360 ohm (two times R_ladder ). Not sure why Jesus used 330ohm (maybe because it is available in the E12 resistors serie) (360 ohm is in the E24 serie).

in February 2025, I also managed (with strong help from AI) to create a python script that takes as input a colored picture and gives has output a palette of 16 colors (chosen automatically in the 4096 possible colors of RGB444)
The objective of this was to minimize the space needed to store (eg in BRAM ) a colored image while keeping a good quality!

i need to sort out some problems i add with my FPGA/icestudio setup last time i used it (few month ago), then will make a proper post in my xga thread documenting the use of that script!

But if you want to try it.  i am joining the script, 
And  the command is:      python image_to_13_colors_rgb444v11.py stone.bmp
Iit should plot an image like the one bellow  (+generate 2 files with image data using the generated palette).
-Top left:         is the original image
- top right:      generated palette
- bottom left:  image using only the 15 colors of the palette
- bottom right: same but with dithering

Figure_stone2.png

A hug and have a nice week-end guys
stone.bmp
image_to_13_colors_rgb444v11.py

charli va

unread,
Oct 31, 2025, 5:30:10 PMOct 31
to fpga-wars-explora...@googlegroups.com
Hi Joaquim! I remember your project! It's very interesting, and I'm really curious to see how it develops. If you need anything or have any suggestions, let us know—you know we're always up for anything! XD

Your scripts are interesting and useful; the fact that they're made with AI is beside the point. If they've helped you and you've gotten results that have allowed you to move forward, then keep at it.

I actually uploaded the calculator because it came up in the thread about the new board, and I thought it would be interesting to share it. It's more of an experiment, a seed or an idea for a possible toolset for working with palettes than something concise. For example, I often wonder what colors I could use for this with the 2-bit palette, and here we can already find out, with the DAC configuration, which colors are available and what their values are.

Or, for example, with a graphics project that I think I'll release soon to keep the list going, I ran into a problem: I didn't know if I had a bug or what was wrong because my reference image differed in color from what I was seeing on screen. That's where this came from. Being able to input the AP-VGA values of the Alhambra and see the palette it generated allowed me to see that the problem was with the DAC, which wasn't properly utilizing the entire color spectrum, resulting in muted colors and an inability to implement the full gamut.

Your scripts make me think it might be interesting to be able to pass an image to a given DAC and have it return a quantized version as faithfully as possible to your palette. Because if you don't take the DAC into account, the dithering is blind to what you can actually represent... I don't know, I'll keep thinking about it. In any case, cool topics.

Thanks a lot, Joaquim!

--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/75ddaf07-cf45-4b56-9bf9-98ee46810f8en%40googlegroups.com.

Jesus Arias

unread,
Oct 31, 2025, 5:43:11 PMOct 31
to FPGAwars: explorando el lado libre
Hi Joaquim,
I used 330ohm because the FPGA pins also have about 25ohm of series resistance that are added to the 2R resistors of the ladder. This result in 355ohm, quite close to the desired 360ohm.

Carlos, In the Circuit Diagram for the R-2R ladder the pin order looks reversed. Pin 0 is the MSB (bit #3). It may be convenient to state it on the image, just in case...

Good night

charli va

unread,
Oct 31, 2025, 5:56:37 PMOct 31
to fpga-wars-explora...@googlegroups.com
Uo!!! Fixed! thanks for the review!

--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el...@googlegroups.com.

Jo mo

unread,
Nov 1, 2025, 3:35:01 PMNov 1
to FPGAwars: explorando el lado libre
Ahh, Yes Jesus, i forgot about those internal 30 ohm resistance.
In my designed it worked fine with  the 360/180 R2R network because i am using a buffer between each fpga output and vga dac input bits.

But, it seams to me that we already discussed  in another tread, about that "buffers or not buffer on vga dacs" subject. And you concluded something like "that it is not mandatory but it doesn't  hurt"!  :-)
We are like hamsters running in their wheel—at some point, we end up right back where we started. That's life  :))

Good night guys.

charli va

unread,
Nov 1, 2025, 5:18:58 PMNov 1
to fpga-wars-explora...@googlegroups.com

Hey Joaquim! Speaking of hamsters, I’ve jumped on your wheel — I found a potential use for the calculator beyond just checking the color palette.

Your dithering exercise is great, but for low-resource situations (computational limits, memory, FPGA pins, etc.), it doesn’t really help us much.

What I mean is, for example, with your image — if I quantize it to 64 colors like you did, even without using dithering it already looks pretty decent:


00_stone_quant64_self_palette_fs.jpg

We can zoom in and look at the pixelation details caused by the quantization, but as we can see, it’s quite “readable” or easy to visualize.


Captura de pantalla 2025-11-01 a las 21.49.45.png

In short, we look for the most frequent colors and then find the closest match, like you did with k-means or similar algorithms, narrowing it down to a palette of just 64 colors, resulting in something like this:

stone_quant64_self_palette_preview.png

That would be great if we could actually choose those colors to draw, for example, on the VGA with the Alhambra. But the reality is that on the Alhambra we only have these colors (obtained with the calculator and the resistor configuration from Jesús’s board):


palette64_preview.png

If we loaded the image into the FPGA and displayed it, we’d see this (the same image as above, quantized to 64 colors):


01_stone_self_indices_to_given_palette_1to1.jpg

Zooming in, we can see the colors it actually uses, since our real display palette has nothing to do with the original image:

Captura de pantalla 2025-11-01 a las 21.52.12.png

I’m sure anyone who’s played with VGA on the Alhambra at 2 bits per pixel and tried to render an image has run into something like this.

If we implemented a similarity-based color remapping system—working in Lab color space and doing thousands of floating-point operations—we could make the image look this good on the Alhambra with our palette. That could be pretty interesting, but on these small FPGAs it only really makes sense to do it offline and use images already prepped for our palette:


02_self_to_given.jpg

In the close-up, we can see that the algorithm blends colors to create similar visual impressions when viewed from a distance:

Captura de pantalla 2025-11-01 a las 21.55.58.png

The problem is that doing this in real time is not feasible on our small FPGAs, but—as I said—it’s very appealing if what you need is to show a few fixed images or sprites that you can precompute beforehand.

With that in mind, it occurred to me that we could use a couple of algorithms very close to the three-color printing process, and they’d be implementable on our FPGA in real time. I kept running some proof-of-concept tests and, starting from your original image (the raw one, with no conversions), rendered on the VGA with our palette it would look like this (Bayer 8×8):


03_bayer8x8.jpg

Captura de pantalla 2025-11-01 a las 22.00.15.png

…and here’s another one—slightly lower quality, but it should use far fewer resources (2×2 superpixels):


03_superpixels_2x2.jpg
Captura de pantalla 2025-11-01 a las 22.01.36.png

At some point I’ll implement this on the FPGA—it seems interesting and useful, and it lines up with a few ideas I’ve had. But if anyone wants to take a crack at it in the meantime… ;) If you’re interested in the code, let me know and I’ll share it. I threw it together quickly just to test the concept and it’s not presentable right now, but if there’s interest I’ll clean it up properly.

As for the calculator, it might be nice to export palettes to CSV or some other script-friendly format (I exported from the browser console, and it made me think a handy “button” would be useful), and maybe even include some of these algorithms to convert images based on the palettes. What do you think?

Thanks a lot, Joaquim! With everyone’s input, really cool things come out.

Good night!







Jesus Arias

unread,
Nov 1, 2025, 6:16:20 PMNov 1
to FPGAwars: explorando el lado libre
Hi Carlos
The algorithm for this is the "Floyd–Steinberg dithering", that actually doesn't require any floating point arithmetic and only storage for two lines of the image.
These are some examples, please open then in separate tabs for full resolution (640x480) and to avoid Moire artifacts:

1 bpp, monochrome:
d1.png
3 bpp, color (2 levels for red, green, and blue):
d3.png
6 bpp, AP-VGA like (4 levels for reg, green, and blue):
d6.png
8 bpp, RGB 332 (8 levels for red and green, 4 levels for blue):
d8.png

12 bpp like Commodore Amiga, (16 levels for red, green, and blue):
d12.png

Good night

charli va

unread,
Nov 2, 2025, 2:17:59 AMNov 2
to fpga-wars-explora...@googlegroups.com
The large calculation I was referring to wasn't using the dithering algorithm directly to reduce the number of bits, but rather converting from the image's color space and palette and finding the best color in the target palette. Simpler approximations could be used, although they would be less precise.

The last two algorithms that i post (8x8 Bayes and 2x2 SuperPixels) are extremely efficient in terms of resources and calculations, i only use in software but they are very hardware friendly.

I think it will be a very interesting exercise to do with your new shield, comparing the pros and cons of each.

Jo mo

unread,
Nov 4, 2025, 1:52:36 PMNov 4
to FPGAwars: explorando el lado libre
Hola Charli and Jesus
Welcome in the hamster wheel ;-)

@ Carlos: few clarifying points:
1- on my script, we have a quantization to a palette of 16 colors (not 64)
2- About this image you posted "quantized to the 64 colors for Alhambra" i think your simple replacement of the two 64 palettes is weird. there is a big palette usage problem here, due to a rotation 180 degrees between the 2 palettes, your images looks like a negative one!? (eg; the almost black spaces which are between the stones appears almost white in your converted image)

Imodified my RGB444 script to generated the mini-palette of 16 colors chosen in the RGB222 palette (future Jesus Alhambra hat friendly ;-))  see joined script
and it gives the following result.

Figure_1 stone2 rgb222.png

or something with a larger colors spectrum .
Figure_2 parachute rgb222.png
And you can see that on the palette (top-right plot). the number for the RGB colors  look 8 bits(up to 256 values), but if you look carefully, only 0, 85 ,170 and 256  values are used. So we really have 2bit for every RGB color.

remark1: if you want to have a closer look at the quality of the images; the plot generate when running the python script. allow to navigate in the image plots. by using
navigation.JPG
remark 2 : on these two pictures, dithering improves slightly the quality but yes it make the data size bigger !  Up to the user to know what e wants. that is why this script generates the two datafiles (.txt).

remark 3: this being said, for the Alhambra vga hat rgb222, we do not gain a lot of bit use a 16 palette colors as i did.  We just go from 6 bit to 4bits per pixel. 
And also in the colors usage percentage of the 2 images quantized above, we see that some colors of the chosen palette are not use at all (they where chosen because the script want 16 colors). 
Maybe for RGB222 we do not lost a lot of quality if we go to a palette of 8 colors(3 bits/pixel).
But maybe it is better to just use the full 6 bit rgb222 instead of using a restricted palette.
All this is a question of trade off between quality of image and FPGA resources usage (Bram but also logic cells if we do some graphic treatment on the images like image/sprite rotation for example)!  

And yes, my actual idea here is to precalculate these "complex" images with python (or Matlab scripts). to make it "usable" in our FPGAs as sprite or backgrounds. And use FPGA power to move/rotate precalculated images. And later, compute/generate very simple geometric shapes (lines, circles, numbers...).
It is not about complex computing on complex images in the fpga itself. (unless one day, maybe using a processor core in the fpga for that)

@ Carlos: about you "algorithms very close to the three-color printing process" I know nothing ;-)! So i will wait for you test results to see their potential advantages !

Have a good evening guys.
parachute.JPG
image_to_13_colors_rgb222v7.py
stone2.jpg
Reply all
Reply to author
Forward
0 new messages