News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

VGA through rpi pico - How many colors possible on border?

Started by gregg, 15:46, 15 April 24

Previous topic - Next topic

Deevee and 2 Guests are viewing this topic.

gregg

This is my first post on this forum, so first of all Hello Everyone!

I am just trying to build simple and cheap VGA output for Amstrad based on Raspberry Pi Pico. So far it is going well, except the limitations caused by low amount of available RAM.
I have a little bit above 256k RAM available and I need to squeeze each output video frame there. I am storing each pixel on one byte (actually using only 6 bits). Output resolution is a standard VGA 640x480 (but I could try to use something bigger) so at this point I am keeping 640x400 pixels in memory - max Amstrad resolution with each line doubled to keep reasonable proportions. That means I use exactly 256k RAM.

But... I would like to add at least part of the screen border. So I have 2 questions to you guys:

1. Is border always filled with one color or there may be multiple colors? I think, during loading from tape there are color lines on border, but maybe at least I can assume one color per line? This way I could easily store border info in remaining RAM.

2. In mode 3, what is the real maximum number of colors on screen? I know there are 2 colors, but maybe border can have different color?
I am asking because if my previous idea would not work, then other option (harder but still doable) would be to read only 320 pixels per line and keep twice more pixels in RAM (with at least part of border) except the case when I detect there is a mode 3, and then detect what are the two colors being used and keep high resolution but 1 bit per pixel.

Thanks, and sorry if the questions are too basic, but I am just starting my adventure with Amstrad.

Greg

McArti0

You kill all software that uses overscan 768 points per line. Better use 2 x less memory and display two copy one lines.
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

McArti0

CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

gregg

Thanks for quick reply.

yep. I forgot about overscan. How big is the max resolution with overscan? You just said 768 pixels per line. Is it max? And how many max lines can be used in overscan?

Idea with one line displayed twice would be the best option i ntheory, but I just did not find a way to do it yet. I was using some open source library to do VGA on Pico, just modified it to use half brightness, too. The idea is that I just set up DMA that send array with the whole frame to PIO that it just displays it line by line. PIO is really dumb and can't have too much logic, also the timing is really tight. I can't also use chained dmas to have one dma per line, because there is not enough dma channels. I would need to use some trick like two PIO state machines, each of them gets 200 line per frame (I would do the same DMA to both of them) then, synchronize them so it is like, first state machine displays first line, then waits and triggers second one. Second one repeats it and lets the first one display second line etc. Overall it would be great to avoid it... still if it is an only option, that is doable.

gregg

OK, but that 125 colors are rather POC to show it is possible, right? Not something I would see in games or demos.
Besides that I think it uses dithering? That I think is a separate thing. Alternative (still much more expensive and bigger) for my solution is e.g. GBS8200 that will not do dithering simulation either.
And... RPI pico could potentially do dithering simulation if I manage to squeeze it better in RAM. At least something simple, like adding 2 more levels of brightness, detecting checkerboard pattern and doing something like average for some pixels. At this point one of my ARM cores does literally nothing, and other almost nothing. All the logic to read amstrad video and output vga is in PIOs.

McArti0

768x256 but ... i can 1024x480  :-\ but not on original CRT.
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

gregg

768x256 sound reasonable (the other one is scary :) ). I would need less than 200kB if I manage to really keep exactly this resolution in RAM, not the doubled one. I could use e.g. 800x600 output resolution, or even something closer to input resolution if monitors support it.
Thanks a lot for all the info! I will focus now on how to display each line twice. It looks like that is the only reasonable option. I hope it will work.

SerErris

It should be possible to race the beam with PIOs. That would free up the memory. I have not thought it through totally but it should be possible
Proud owner of 2 Schneider CPC 464, 1 Schneider CPC 6128, GT65 and lots of books
Still learning all the details on how things work.

SerErris

Proud owner of 2 Schneider CPC 464, 1 Schneider CPC 6128, GT65 and lots of books
Still learning all the details on how things work.

gregg

What you mean by "race a beam? Do you mean converting the input pixel to output ones in a streaming fashion, without storing anything in memory? Or rather do it line by line?
Or something like this - twice more pixels per line on output then on input, read one pixel on input, then write two on output - so we get VGAish timing.
Then PIO need one loop that reads pixel and writes it twice with correct timing. hmmm... It could work.

gregg


eto

Quote from: SerErris on 18:40, 15 April 24Aha, as I said... here is something for the Sinclair QL
I think that's more or less just a scan-doubler that digitizes the QL output and sends each line twice to the monitor. If I understand gregg correctly he is rather mirroring the screen RAM and listens to the CRTC/GateArray registers.

@gregg in case I am right with that assumption that you are not just digitizing the screen output and replay it again, then you also have to consider double and triple screen buffering.  Many games switch the screen address between frames. If you are mirroring the screen contents you also have to keep 2 or 3 screens in the PICO Ram.


gregg

Quote from: eto on 18:47, 15 April 24
Quote from: SerErris on 18:40, 15 April 24Aha, as I said... here is something for the Sinclair QL
I think that's more or less just a scan-doubler that digitizes the QL output and sends each line twice to the monitor. If I understand gregg correctly he is rather mirroring the screen RAM and listens to the CRTC/GateArray registers.

@gregg in case I am right with that assumption that you are not just digitizing the screen output and replay it again, then you also have to consider double and triple screen buffering.  Many games switch the screen address between frames. If you are mirroring the screen contents you also have to keep 2 or 3 screens in the PICO Ram.


Nope... I am more like doing a scandoubler, just the simplified one that assumes Amstrad palette, so it is easy to use just digital pins, voltage comparators on input and 6 resistors on output.

I was considering mirroring the ram, but I got scared :) double and triple buffering is just a beginning. What about reading the palette etc. That's too much for me  :D

genesis8

Do you have a github or a web site with more informations about the state of your work ?
____________
Amstrad news site at Genesis8 Amstrad Page

eto

Quote from: gregg on 18:56, 15 April 24Nope... I am more like doing a scandoubler, just the simplified one that assumes Amstrad palette, so it is easy to use just digital pins, voltage comparators on input and 6 resistors on output.

I was considering mirroring the ram, but I got scared :) double and triple buffering is just a beginning. What about reading the palette etc. That's too much for me  :D
ah... in that case the QL project might indeed be close to what you want to do. 

Well... I am looking forward to it :-) 

gregg

Quote from: genesis8 on 21:39, 15 April 24Do you have a github or a web site with more informations about the state of your work ?
Nope. I just have a messy code on my pc, and messy electronics on a breadboard. I will for sure put everything on GitHub, especially that my knowledge in electronics is really poor, so I would like to get some feedback. But first I need to clean it up at least to the point when code is readable.

As for current status - output is almost OK. Code works well, I was able to display Amstrad palette, or something close to it. I need to experiment more with resistors values to make colors better, e.g. white is a bit greenish. Input in terms of schematics is much more WIP. I am just going to order some new voltage comparators, because old ones were too slow. So far I was testing with only 1 bit per input. Except those limitations with ram, when I was trying to just use 640x200 with no border, it looks ok - just small details to improve like screen is shifted a bit, or problems with catching sync after resetting Pico with Amstrad running. So it should not be much work left.

genesis8

If you have time and energy, would it be possible to do a short video on youtube to show your work for us poor hungry for informations  ;D ?

It's so more sexy when you can see things.
____________
Amstrad news site at Genesis8 Amstrad Page

Sykobee (Briggsy)

#17
I envision the process would be implemented as similar to the below (as VGA is 31kHz and input is 15kHz)

Two buffers, 768 pixels each.

Some magic to find out when a scanline starts from VSYNC and HSYNC signals.
Repeat {
  Scan-out 768 pixels VGA from buffer A | Read half-scanline display data into buffer B (384 pixels incorporating left border and LHS of screen)
  Scan-out 768 pixels VGA from buffer A | Read other half-scanline display data into buffer B (384 pixels incorporating RHS of screen and right border)
  Scan-out VGA from buffer B | Read half-scanline display data into buffer A
  Scan-out VGA from buffer B | Read other half-scanline display data into buffer A
}

Presumably for an 800 wide VGA screen you'd publish the first pixel 17 times before the rest of the line, and then the final pixel 17 times, to hit 800 pixels. You might want a configurable black border option too here.
You'd also publish X blank lines before and after the display.

The tough thing is sampling at the right rate to get the precise MODE 2 pixel sampling correct.

The above is how OSSC does it, I believe, but that's overkill hardware for a CPC. It's very low latency.

You will need some magic for R3 horizontal scrolling funkery. You can test that using Relentless.

gregg

Quote from: genesis8 on 08:26, 16 April 24If you have time and energy, would it be possible to do a short video on youtube to show your work for us poor hungry for informations  ;D ?

It's so more sexy when you can see things.
I am just learning electronics (I am software engineer), so I think I could rather learn from videos :) It is also my first project on RPI Pico... actually on any microcontroller. I am doing it mostly to learn. I even don't have an Amstrad yet (testing on a prototype of a replica that I am trying to build), so I don't think such a video would be valuable. First I would rather like to at least see it working.

If you want some more info, it is a short summary:
I connected vsync and hsync to pi's input GPIOs. RGB will go through voltage comparators (now they are just a bunch of resistors and capacitors to adjust voltage levels) to convert it to 6 pins total. Each pair represents one color. There is 00 (no color), 01 or 10 (half brightness) or 11 (full brightness). Pico works in 128Mhz so it makes it really easy to synchronize because one pixel in mode 3 is 7 cycles on Pico. PIO code that reads it just waits for HSYNC to go up, then down, then waits a couple more cycles (will not do it when I will support overscan). After each pixel is read, PIO sends it to queue, then it goes through DMA to host that stores it in an array that represents one line. Once line is done (next HSYNC starts), host copies line to two consecutive lines on output buffer (that will change if I want to store each line only once). I repeat it 312 times and start again from beginning (next frame). (I will rather sync it using VSYNC in future). 
On output side, second PIO generates HSYNC, VSYNC and just reads the buffer representing VGA screen that it receives through DMA from host (the one that I was filling so far). For each pixel it sets again 6 output GPIO, using the same format - 00 is no color, 01 or 10 is half brightness, 11 is full brightness. Each GPIO has a resistor, that are connected on other side, so we have "analog" signal there that goes directly to VGA. That's it.


SerErris

Quote from: gregg on 18:44, 15 April 24What you mean by "race a beam? Do you mean converting the input pixel to output ones in a streaming fashion, without storing anything in memory? Or rather do it line by line?
Or something like this - twice more pixels per line on output then on input, read one pixel on input, then write two on output - so we get VGAish timing.
Then PIO need one loop that reads pixel and writes it twice with correct timing. hmmm... It could work.

Just to fill that answer, as I was away some days:

Race the beam is a programming technique often used in games (ATARI was famous for it). It means, that you actually read only the current pixel and then directly output it. So you do not do anything other than that. This will convert it to a 15khz VGA signal.

If you need a 30khz VGA signal, you would need to buffer a single line, and then output it two times.

gregg has already answered that.
Proud owner of 2 Schneider CPC 464, 1 Schneider CPC 6128, GT65 and lots of books
Still learning all the details on how things work.

gregg

Thanks Guys again and I have some more questions, and some good news.

First a quick question to McArti0 - which exactly 256 lines I should use? I looked at the output from Amstrad with an oscilloscope and I see the following for each frame:
16 lines - hsync signal
10 lines - totally black
46 lines - top border
200 lines - actual screen
40 lines - bottom border
In total 312 lines.

So far I used 200 lines from the actual screen with a similar sized parts of both borders that gave me 256 and I am not 100% sure I am using the right part.

My second question is to everyone. I am getting close to be done with programming (still some electronics work left after that) and I am thinking what else I am missing. One of those is potentially a support for using csync instead of separate vsync and hsync. That may be needed depending on how it will be installed. I am considering a couple options. At this point I need: rgb output from gate array or video connector, hsync and vsync e.g. from gate array pins, 5v for rpi and ground. So I see a couple solutions. Which one would be the best in your opinion:

1. Put everything on a board that is installed outside of amstrad. It would be connected to video port, and it needs 5v. Maybe it could be plugged to both video output port and power input port. Then it would have a connectors for vga input and power adapter input. Something like - power goes into the board, then it powers pico and also goes to power socket in amstrad to power amstrad.
Pros: Simple to install - no need to change anything inside Amstrad or case.
Cons: The board would be bigger. I need to handle csync, that I am not yet 100% sure is doable in Pico.

2. Put it inside, on a board that plugs into Gate Array socket, and Gate Array is plugged into the board. It could be really small especially is we would not use the whole Pico board but rather directly install processor and a couple or parts on our board. I get all the signals from Gate Array. There would be e.g. a pin connector to connect vga socket on a tape that could go to anywhere, even potentially outside of Amstrad through some existing hole in case.
Pros: No need to cut anything in case, or remove any existing socket. I don't need csync. Smaller board. Lower total cost.
Cons: Need to open Amstrad. Need to put vga socket somewhere.

3. The same as 2 but vga socket is installed on the same board close to main board edge. Cut the hole in case for vga socket.
Pros: It is very simple.
Cons: Need to cut hole in case. Separate version for each Amstrad.

4. The same but different board shape so vga socket replaces video socket.
Pros: The same + no modifications to the case.
Cons: Need to remove original video socket. Separate version for each Amstrad.

Which option would be the best? Maybe some other, better solution I did not think about?
In my case it will be simpler because I plan to make it a part of my Amstrad clone board - much simplified to just play some games in living room, but I would like to make it useful for normal Amstrads.

And some good news:
I managed to make Pico double each line using a weird trick with two dmas. The only limitation is that number of lines that goes to VGA must be a power of 2. I am keeping 800x312 screen from Amstrad in memory and then output part of it with doubled lines (800x512) to 800x600 vga (actually I think it is svga) screen. It works well with all the monitors I found at home. The only bad thing are spare black 88 lines on a screen. I will try to do something about them, but I don't have idea yet.




McArti0

Quote from: gregg on 16:01, 22 April 24First a quick question to McArti0 - which exactly 256 lines I should use?
if you meet a malicious programmer's code, you will have to use 286 lines.
CPC 6128, Whole 6128 and Only 6128, with .....
NewPAL v3 for use all 128kB RAM by CRTC as VRAM
TYPICAL :) TV Funai 22FL532/10 with VGA-RGB-in.

gregg

Quote from: McArti0 on 18:02, 22 April 24
Quote from: gregg on 16:01, 22 April 24First a quick question to McArti0 - which exactly 256 lines I should use?
if you meet a malicious programmer's code, you will have to use 286 lines.
OK, but if I understand correctly it is some extreme case? How many existing software use 286 lines?
If I understood correctly your previous post, there is quite much software that uses overscan with 256 lines. So my question is just which 256 lines? Is it always the same 256 lines or each software use different ones?

Or maybe I can ask it in a different way - if you turn on Amstrad with original monitor, how many lines and columns do you see and which ones?
I would like use vga monitor and see about the same, and if some software draws anything on a border that would be visible on original Amstrad monitor, I would also like to see it.

eto

Quote from: gregg on 16:01, 22 April 24I need to handle csync, that I am not yet 100% sure is doable in Pico.
You can split sync with a LM1881. That might help.

I would prefer option 1. I have different CPC machine and connect them to different screens. An external solution would be more flexible here.

Option 2-4: Keep in mind that there are 2(3) variations of the GateArray. You would need 2 different PCBs to cover that. And the 40007 GateArray requires to have a heat sink installed. I'm not sure if there is still enough space and if the heat sink can still be mounted with another PCB in between.

Btw: did you do some tests with games and demos that use scrolling and/or overscan? Many scandoublers fail with scrolling. A good test is e.g. Ghosts'n Goblins (easy, many scan doublers work fine) or Super Edge Grinder and Relentless (haven't found a scan doubler yet that works fine). Overscan will reduce/remove the borders so you will get up to 288 lines with content and no more borders.

gregg

Quote from: eto on 18:53, 22 April 24
Quote from: gregg on 16:01, 22 April 24I need to handle csync, that I am not yet 100% sure is doable in Pico.
You can split sync with a LM1881. That might help.

I would prefer option 1. I have different CPC machine and connect them to different screens. An external solution would be more flexible here.

Option 2-4: Keep in mind that there are 2(3) variations of the GateArray. You would need 2 different PCBs to cover that. And the 40007 GateArray requires to have a heat sink installed. I'm not sure if there is still enough space and if the heat sink can still be mounted with another PCB in between.

Btw: did you do some tests with games and demos that use scrolling and/or overscan? Many scandoublers fail with scrolling. A good test is e.g. Ghosts'n Goblins (easy, many scan doublers work fine) or Super Edge Grinder and Relentless (haven't found a scan doubler yet that works fine). Overscan will reduce/remove the borders so you will get up to 288 lines with content and no more borders.
Idea is LM1881 is great. Thanks. I will do it with if I don't manage to handle it in code.
Yep... forgot about different gate arrays. That would make it complicated.

I am only testing it with start screen and boulderdash that I have in rom. There is no real scroll there, so for sure I will test it with games you suggested. I am a bit afraid of potential screen tearing. What artifacts with scandoublers do you see in those games?
And first I need to fix one more issue with hsync timing. There is some jitter added by Pico that makes lines moving to the sides a little bit sometimes, so that would probably affect those tests.


Powered by SMFPacks Menu Editor Mod