CountChocula wrote:
- At 180º, bring the PIC on the bus.
Rather than putting the PIC on the data bus, I would probably add an extra 8-bit D flipflop to latch the data that the CPU wants to output, and let the CPU write directly to this whenever it wants to. So the CPU interface is just to write an address, then write a data byte, and it can kind of forget about it after that so long as it doesn't write anything else for a while. Essentially it's a 1-deep FIFO. Unless the CPU is actually sharing a clock with the video system (which is actually what I do in practice) I wouldn't trouble the CPU with trying to synchonize with the video clock for anything, just make sure the FIFO can cope.
It's important that the video circuit, that's reading the FIFO, doesn't try to read it while it's being updated. My plan for this was to have a D flipflop that the CPU sets when it writes the data byte (it can be automatic). Then the video circuit can use that to determine whether there is data to be written, and it can reset the flipflop to say that the data was written. Potentially the CPU can then read that state back to check the FIFO is empty, before writing new data.
It seems prudent for the video circuit to also buffer this flipflop, sample its state in advance of a potential write cycle and only execute the write cycle if the flipflop was set in advance. So that adds up to a one cycle delay to the write, but seems like it would make things more stable, and avoid triggering the write behaviour halfway through a cycle without doing the right setup first.
This doesn't solve the timing problem of how you fit all the reads and writes into the video clock cycle, and it can be tough. I do all this at half the speed you are using, which makes it easier, but a lot of the parts I'm using are also slower and my timings are borderline. I would think in times though, rather than angles, and try to fit it to the clock cycle afterwards.
My general approach is to identify which things I need to control directly - such as enabling/disabling various chips writing to the buses, or enabling/disabling the RAM's write enable line. I think of these as synchronous events, which I'm going to trigger based on the clock. Then between these, various things happen asynchronously - such as the address bus settling down after I change what is driving it, the RAM getting used to a new address on the bus and starting to output it, or the latch having a setup time during which its input data should remain steady. I don't need to explicitly say when one of these transitions into the other - it doesn't need to happen on a clock boundary. But I need to add them all up and make sure I don't trigger the latch until enough time has passed for all these asynchronous things to have occurred in sequence.
My spreadsheet is mostly about summarizing the times for these stages from the datasheets, identifying which things I need to directly control, and determining which time periods can't start until after other time periods end. If something is based on a synchronous event then I also need to round it up to the next clock cycle (about 40ns). That's a big deal for me because there are only four clock cycles in total; it's even worse for you because there are only two!
In general though, yes, it's tricky and requires quite a bit of thought to get these writes happening between pixels. But very effective if you can do it!
Quote:
I'm not sure how one would go about isolating the edges from each other—i.e.: how do you prevent something that needs to happen only at 90º from also happening at 270º?
The easiest way is using a PLD, they are very effective for this.
Otherwise you can use flipflops to delay low-frequency signals by one high-frequency period. e.g. if you use a '163 style counter to generate ~12.5MHz, ~6.25MHz, etc from your ~25MHz clock, you can also phase shift the 6.25MHz by 40ns by re-sampling it based on the original 25MHz clock using a D flipflop. And you can shift it by a little over 20ns by re-sampling it based on the inverted 25MHz clock. This is what I used to do before moving to a PLD.
Quote:
Similarly, I wouldn't know how to pulse /WE for less than 1/4 of the clock cycle.
One way I've considered (but not tried) to synthesize more clock edges is to invert the clock signal, as I mentioned above, so you now have twice as many rising edges. i.e. if your crystal clock rises once every 40ns, then if you invert it then you have another signal that also rises once every 40ns, but delayed by a little over 20ns, so overall you have clock edges that you can trigger from roughly every 20ns.
Quote:
An optimization that I think I
can implement now is something that I already alluded earlier in the thread: right now, the PIC has to wait for a full scanline before writing a pixel; otherwise, there is no guarantee that there will be enough time left for the write cycle to complete before the next visible field begins. This can be fixed by having the ROM emit an auxiliary signal (called MBLANK in the schematic) that allows for enough time before the end of a blanking interval to account for the critical section of the PIC code that performs the actual write. This would probably speed up things quite considerably, since right now the design is limited to ~31,500 pixels per second. This is something that I haven't implemented yet mostly because it requires pulling the EEPROM out of the circuit to reprogram it, and I'm a little worried about accidentally disconnecting too many cables
Yes, that sounded like a good idea and a good use of extra ROM output lines that otherwise go unused.