Figured out that I wasn't properly blanking the signal as well as added those 47 ohm resistors. The image is now very stable, I also corrected the vertical scaling:
No more squished letters! \o/
For initial testing of colour graphics circuits I usually connect one colour's high bit to H0 and maybe H2 or H3 on a lower bit for that colour; and another colour connects to V0 and maybe V2 or V3, and the third colour connects to my blanking signal, giving overall a kind of tartan pattern that makes it easy to see what's going on at the edges of the screen - you can see by eye whether the left/right/top/bottom pixel rows and columns are the same width as the others, and count the repetitions of the secondary lines to check the overall resolution is what you expected - it's easy to have 1/2/4/8 pixels missing from one edge or the other if you get the blanking wrong, and sometimes I've gone ahead for ages without realising I'd done this!
I did a bit of that; however, using the character font gives me a recognizable pattern to look for; as well as giving me some options for some asymmetrical glyphs so I could make sure I was shifting in the right direction. The '299 can shift left or right, and seems completely backwards to how I think of shift left or shift right.... And yes... I did have it shifting the wrong way around at first, causing some of the characters to appear backwards.
If you're using shift registers e.g. for text output then you can instead just connect the bottom few bits of each of the H and V counters to some of the shift register inputs - bypassing any character ROM - to get a really distinctive binary counting pattern that lets you spot if you're missing pixels or even characters at the edge of the display area. I also tweak the monitor settings back and forth so that I can see the edges of the area that it's receiving when checking these things.
I'll keep that in mind. Right now I'm pretty sure that I have the following issue:
The top line appears to be half the size of what it should be, implying that I'm I'm somehow moving to the next line before I should be. I think this is likely because I'm incrementing the vertical count on a rising edge instead of a falling one.
The left most character seems to be completely missing, I'm convinced this is because I'm trying to load that character right on the zero horizontal count, causing me miss the first one as the very slow ROM tries to settle out.
I'm also getting what looks like a couple of pixels shifted over to the left, causing one or two extra columns to appear on the right side of the monitor.
The binary pattern will definitely help with identifying the exact count.
For the flickering though, maybe you could post a video that shows it, so we can see it? I do think that what J64C and BDD were saying is probably true if you're seeing flickering - something is wrong with the sync signals, maybe not all of the time. In my experience modern monitors are more fussy about the consistency than the specific timing. I always try carefully to get the official timing but it doesn't seem to matter much in practice - but if you get a random spike on one of the sync signals mid-frame then it can cause a lot of glitching.
I can, though at the moment it's pretty stable. (Also have to see if I can figure out how to record a decent video of any sort, that's not something I have any kind of setup for.)
There's the flickering and the drops.
I'm guessing the flickering I mentioned, is mostly due to the fact that the signal is getting trashed by going through that really terrible breakout cable I made, having fairly long unshielded wires, plus being loosely connected into a breadboard. Like I said, it's REALLY minor, it might not even show up very well on any video I take, and my suspicion is that it will get cleaned up if/when I move to a proper PCB for this.
As for the drops, I'm fairly sure a lot of that is more due to me sending pixel data in the blanking period than the quality of my signals. The 47 ohm resistor that J64C recommended helped a lot; but also I'm currently relying on the idea that the CPLD will stop telling the '299 to load character data at the right times, thus it will start shifting in 0s from the ground pin as the shift clock continues to run; if that gets off the shift register will continue to send pixels that are on, thus upsetting the monitor's circuitry that tries to workout what level "black" is. If it happens to do this when there's a white pixel being transmitted, then the screen goes dark for a frame or two. This can be exacerbated by selecting a different character to display.
It almost certainty would be better if I were to have this on some kind of tristated latch and then feed that into a transistor that can pull the signal to ground on my end as you recommended before. Thus I could completely disable any possibility of any errant output.
I would look at them on an oscilloscope (on the far side of your series resistor) and check firstly that the timing is what you expect, then see if you're getting at least let's say 3.3V when they're high, how stable that signal is, what the rise/fall times are like when loaded - these should be less than a pixel - and whether there are any obvious reflection effects. The load at the other end of the monitor cable should be high impedance, so it shouldn't draw much current in the steady state, but during switching I wonder if it is drawing more current than the ATF1502 is capable of providing, leading to slow switching times which might upset the monitor. (I don't know the device but the datasheet seems to give a maximum figure in microamps - not milliamps - for a high output to achieve 3.1V.)
Yep, actually checked the signals on the scope before I even attempted to connect it to a monitor. The signals as near as I can tell seem pretty good. The timings are very close to spec and the levels are all really good.
Horizontal Blank:
Vertical Blank:
It does appear there's a consistant 1V spike in the vertical blank there; less than TTL's 1.5 cross over point, but still in that grey area.... Hrm.....
FWIW though I have driven VGA sync signals directly from ATF16V8Bs without problems, so if they have similar drive capabilities then I'd have thought yours would be fine too. But it might depend on the monitor cable, and also the ATF1502 is more complex and may be more sensitive to things like drops in VCC caused by excessive current draw from its output pins. Buffering them through an external flipflop register would be an easy way to ease that burden.
The ATF1502 breakout board has it's own 10uF electrolytic cap for handing some demand spikes here and there, and each one of it's VCC pins has another 0.1uF ceramic cap for filtering any noise as per typical. The bench power supply shows that I'm drawing right about 0.1 amps while the circuit is running, and I've allowed up to a generous 2 amps. I can double check the power rails, but I'm pretty sure it's all stable.
I still want to place some kind of flip flop at the end if for no other reason than to make sure all the signals are arriving at the same time.
What polarity do you have for your hSync and vSync?
I have seen people swear by Ben Eater a being the perfect source in his video, but even he made a few errors in his “Worlds worst GPU” video. The big one being the incorrect polarity of the sync pulses, even though he has the sheet right in front of him when he makes the error.
This is often the source of the issue where people often say “it works perfect on this screen but not on that one”. Some screens are more tolerant than others.
Obviously he's not a perfect source; he's going for ease of explanation/understanding than being perfectly correct.* He does talk about the pulses being negative level logic, so I'm getting the impression that by polarity you mean something other than that.
* The number of time's I've tried to explain a programming topic to someone only for them to get confused by, or hung up on, the error checks in the example code..... x_x
When you get to fixed pixel displays, you have a problem. Syncs are now (almost) always carried separately rather than as part of a composite signal, so they're easy to isolate, and their frequency and polarity informs the display of the resolution of the video signal.
Indeed, with the older analog monitors my guess is they effectively "smeared" the pixels as the beam swept over the phosphors. At least that seems to be my understanding with how older TVs worked with various video game consoles; I presume older analog VGAs did the same thing. (I've been watching too many retro repair videos lately....) With LCDs this needs to get scaled up digitally in some way, either in hardware or software.
I have two LCDs that will still take a standard VGA input, both are 4:3:
One of them is much older and it's scaling is really ugly, it just clumsily doubles up on some pixels. This leads to some pixels being doubled and others not and gives rather uneven sized pixels when you aren't in it's preferred resolution. Not ideal if you're trying to work out if that pixel is being doubled by your bad circuit timing or if it's being done by the monitor itself to just scale the image.
This Dell monitor does a better job of making the scaling look even and correct, despite it's native resolution being 1024x768. It does occasionally "complain" that it's optimized for 1024x768 when I start seeing these sync issues. The implication being there's something not quite right about how I'm sending these signals and it knows it.
But the timing between the horizontal sync pulse and the video signal is _critical_. The display has to unambiguously know where the video actually is relative to the sync so it can sample it. VGA is still an analogue signal; the display has to sample it at the right time and probably use a phase locked loop to derive its phase, at least initially (i.e. when you push the 'auto' button!). The net result of this is that any disturbance in the syncs will at least temporarily break the system. It may result in jitter, longer term picture shift, or even a black screen while the display works out what's going on.
What I'm seeing is the picture will drop for a couple of seconds.