Microcontroller: Microchip PICLF4220
Program Memory: 4K bytes (2K instructions)
RAM: 512 bytes
EEPROM: 256 bytes

SRAM: 32Kx8
Address lines: 15
Data lnes: 8

PIC microcontroller integrated with SRAM

The primary motivation in moving video RAM out of the PIC microcontroller is to increase the potential screen resolution. Since each pixel comes from SRAM, computation in the microcontroller simply becomes a memory address increment. Block(?) diagram The PIC INCF instruction executes in only one instruction cycle. At 10MIPS, this gives a theoretical maximum of 251 instructions or 251 horizontal pixels.

This approach yields one byte per pixel. I will initially just use one bit per color for testing - which is 8 colors (23). Since a full byte is available, I hope to expand this to 256 colors. The odd thing is that 8 is an even number and doesn't divide by 3 "nicely". What I am hoping will work out is to divide the bits up into XYRRGGBB. "XY" will be prepended to each color pixel - giving XYRR for red, XYGG for green, and XYBB for blue.

The SRAM, being 32K in size, has an address bus of 15 bits. Using 8 bits for horizontal resolution leaves 7 bits, or 128 lines, for vertical resolution.

The ultimate goal: achieve approximately 250 x 120 pixels.

The PIC pinouts are as follows:
• ADDR (low): PORTB<0:7>
• ADDR (high): PORTC<0:5>, PORTA<6>
• DATA: PORTD<0:7>
• Hsync: PORTA<2>
• Vsync: PORTA<3>

Source Code
App. Note TB011

v1 - 20031007 - Memory Test

Never having worked with SRAM, I decided the best approach was to simply try to read and write memory. Fortunately, Microchip has an article that describes how to work with SRAM and a PIC16 microcontroller. This application first turns on two leds and then turns off one of them to indicate status. There is a commented block of code that should also force the memory test to fail. The intention is to have it succeed, re-program the microcontroller, and then re-run the test and have it fail.


v1b - Include video routines

I initialy tried to tack the video routines directly in with the test. This didn't work at all, of course. No video signal what-so-ever, so my timing must have been really out of whack. I didn't keep any code or anything!

Source Code
VGA timing information

v2 - 20031011 - Stripe Test

Not being sure what went wrong, I removed the SRAM from the equation. The memory increment was changed from the address lines to the databus, which created the pattern seen in the picture. By simplifying the equation, I was able to solve my timing and programming issues.

As usual, I measured the Hsync pulse with a borrowed multimeter. It measured 31.44 - so I was within range!

The last piece of this test was to check horizontal resolution - and it appears that 240 pixels across is possible!

Source Code

v3 - 20031014 - Vertical height check

As usual, somebody else pointed out the obvious: The VGA spec includes a 640x480 mode which would allow me to achieve 120 lines of resolution instead of 100. After some quick code switches, I generated this picture to "prove" that 120 vertical lines are possible. (Note that vertical timing really isn't the issue - horizontal timing is the driver.)

Source Code

v4 - 20031021 - First working version with SRAM?

Wow. I think this thing is working! I copied (literally) the setup code from the memory test, made a few modifications in the form of setting an error LED, and the memory tests ran just fine. I then made the quick modifications to the VGA video driver, and it appeared to work! The first version had a vertical pattern - and I didn't quite believe it.

I then modified the setup to write the line (Y coordinate) instead of the column (X coordinate) to generate a straight line pattern. When I stuck the chip in, I think the memory test failed. The wrong LED went on, but the lack of activity with Hsync and Vsync was quite apparante. I didn't even bother to check frequency of Hsync.

So, what's a good hack to do? Why, remove the memory test and see if it works anyway. And, it did!

There are some items to fix up:

  • I think PORTA<6> was a bad choice for the the high bit in the address bus. PORTA<7> is the CLKIN pin and PORTA<6> has CLKOUT as a function. With HS-PLL mode, I think this is always CLKOUT. I need to verify this.
  • Patterns are to simple. Time to adapt the graphics routines - that'll make me 100% certain that this isn't a fluke.
  • You may have observed that the horizontal pattern takes up the entire monitor. This should be a side-effect of not changing to some background color. This should be black although the results here suggest it could be something else - I seem to remember the Apple IIGS having a blue border around the screen instead of the black border. There are a number of solutions, but because of timing limitations, I think I'll just store the background color at line offset 0xFF for each line. The reasons are because this needs to be done in one instruction - and the PIC chip has a SETF instruction which can set the addrLo location to 0xFF in one instruction. Otherwise, I'd need to turn off OE on the SRAM chip and then set the background color - and only 0xFF (white) and 0x00 (black) are avilable in that setup. Otherwise I need to use a MOVFF instruction which adds yet one more cycle. If I take any more time than a normal pixel, the right-most pixel gets really fat. I don't want that now, do I??

Source Code
VGA timing information

v5 - 20031028 - SRAM controlled video

It most definately works! In general terms, the design works well as designed. I achieved my goal and a bit better - 255x120 pixels. I think the "extra" pixels are actually stolen from the front and/or back porch area (see the VGA timing information resource for more information). Additionally, I found better ways to optimize the code... actually, this code is pretty messy, so I'll clean it up in a later version.

The first design issue that I realized during this phase: I need to be able to disconnect the databus from the RGB lines leading into the monitor. Why? That will either leave random dots on the screen if the monitor is drawing in a visible section of the monitor. Or something funky will happen - for instance, I had some issues with the timing of what I was drawing. It appeared that pixels begin drawn outside of the active video area would cause the monitor to actually *not* draw pieces of the image. It certainly could have been something else, but it did appear that if drawing pixels went too far to the left, colors would drop out - for instance, the purple lines would disappear. Same code setting up the drawing but they didn't appear. As I commented out one line at a time, I would get to a point where everything came back to where it shoudl be. Weird, but once I figured that out, it all came together quickly.

The second design issue is more of a software issue. My code to steal the high address bit and slap it onto a different pin appears to be incorrect. The memory tests wouldn't catch a non-functioning address line. I settled on using 7 pins from PORTC - which removed any possibility of connecting serially. The PIC chips multiplex MSSP/SPI/I2C and the UART on this one port and they cannot be reassigned. I need to revisit this soon!


An early application experimenting serial communication and sprites

It's time to try a (somewhat) practical application! I think I've taken this particular design to its conclusion without adding more components. Check the video future section if you're curious about other thoughts I have.

Contrary to what it appears - my ultimate goal is to use the video within a homebuilt 65xx computer. I don't quite think I'm where I want to be for the computer, and yet I'd really like to have something to show for the work done thus far. I guess I'm a bit impatient.

I've included a simplified circuit diagram indicating design. This is still microcontroller-based, so I'm using another PIC chip. I'll use this second PIC chip as the real-world interface. The joystick is a spare arcade joystick (4-way, not analog) I happen to have along with two spare buttons. Both PIC chips sport a USART - so I'll use this as the communication mechanism. I don't really know what impact this will have on the video controller itself, but I hope it's not too painful!

The sample applications that I have chosen are:

  • A drawing program. This should be fairly simple to implement and I can use a sprite as the cursor.
  • Chase the dot game. Simple-simple-simple. Do not mistake with fun-fun-fun!!
  • Basic missle command. Maybe, just maybe, I can do a missle command!

What does this accomplish? Quite a number of things, actually:

  • Inter-chip communication. This is my first step. I will remove all the drawing code from the video microcontroller and move it into the interface chip (change it a bit so I can see a difference). A command "interpreter" will be added to the graphics controller. The line drawing, bitmap drawing, and character drawing remain in the graphics controller. Just the "application" is moving.
  • Simple menuing. I want to be able to detect mouse up/down and left/right navigation.
  • Sprite implementatin. I can experiment with methods of implementing a sprite. Nothing fancy - the graphics microcontroller has only 512 bytes of RAM. The method that makes sense is to save a copy of the sprite itself in PIC RAM as well as the piece of background that is occluded by the sprite on-screen.
  • Buttons. Most likely debounce techniques. Whether this is hardware (a capacitor I'd guess) or software, I don't know yet. I also want to press down and hold the command button in the draw program - up/down changes command and left/right changes options. For instance, to change the color, I'd press command, use up/down to get the color option showing and then left/right to choose the appropriate color.


Status as of 2004

Project was terminated around December 2003. I was unable to resolve some basic communication issues and then Christmas intervened. We needed the dining room table for Christmas dinner and I needed to pickup. )c:

I have no pictures... the code is somewhere in CVS, so it's not lost. As I remember, my impression was that my serial communication was interfering with the timing of my video interrupts. I'm sure someone more experienced could have resolved it - given enough time and will-power, I could have too, I imagine.

The good news - I have my new laptop, a workspace in the basement (yup, just me and the mice that hide down there), and there is a design for Video3 laying around somewhere!

For those that don't use source code control: I was missing it sorely and finally realized that I had it right under my nose. I use Eclipse for my Java development and have a Linux server that acts as my CVS repository. I started using TortoiseCVS for managing the files, and I find it works very nicely. Since it's integrated into Explorer, it is always available. Works beautifully with MPLAB and Eclipse can pull in the archives too, so I can exchange between tools without them getting into some sort of fistfight.