HCS12 software-based VGA driver
November 19, 2011
This semester, I'm serving as a teaching assistant for ECE470, a class that deals with programming the HCS12 microcontroller. It was a while since I'd taken the class myself, so I thought it would be a good idea to spend a weekend working on a fun project to brush up on things. So, I decided to implement a VGA generator completely in software (a technique commonly known as "bit banging"). Aside from three resistors, no custom hardware is used!
The motivation for this project has its origins in my EGR280 project, where I implemented a Tetris game. At the time, I used a hybrid FPGA/microcontroller approach. The game logic resided in the HCS12, while the FPGA took care of generating the VGA signals. (At the time, I hadn't taken a digital logic class, so I didn't know enough to implement the Tetris game entirely on the FPGA. And I didn't think it was possible to generate VGA signals on the HCS12 without any custom circuitry.)
I decided now to take a look and see if it was possible to do everything on the microcontroller. This runs somewhat counter to my area of research (which is focused on leveraging the incredible flexibility of FPGAs, not trying to cram more into a microcontroller.) Still, I was enthralled with this MacGyverian notion of taking a fixed microprocessor and getting it to do something it wasn't designed for!
My implementation produces 640x480 signals, but the display is limited to 80x60 blocks. This limitation appears to be on two fronts: First, the HCS12 bus can run at 25MHz max, and it takes at least 5 bus cycles to write a byte to an I/O port. For normal VGA, pixels must be written out at a rate of 25MHz. Second, the internal memory is rather limited at only 12kB. An 80x60 byte array takes up 4.8kB, so a double-buffered setup would consume 9.6kB! (Concievably, the resolution could be improved by both overclocking the HCS12 and storing pixels as nibbles instead of bytes.)
The HCS12 timer's modulus down-counter was used to provide an interrupt at the horizontal refresh rate of 31.25kHz. Each firing of this interrupt calls a video routine written in assembly. This was really fun to code! Everything here is timing-critical, and had to be written in assembly, with close attention paid to how many clock cycles each instruction consumed. Further, every branch taken in the code had to be balanced such that each possibility consumed the same number of clock cycles.
The microcontroller is so busy running around displaying video that it only can do useful work during the video blanking periods. This amounts to only 6% usable time to change what's on the screen! The other 94% of the time, its madly toggling I/O pins to get the VGA signal out there. Still, this is more than enough to do meaningful work. The below clip shows a Tetris piece bouncing around on the screen along with some flashing color stripes. The code to do this animation, along with a 5ms dummy loop, resided in the main() function. This proves that a game could certainly be made to work in this tiny 6%.
Below you will the complete code for this project, along with slides from a guest lecture I gave in ECE470 at Oakland University. I've also included slides on the Serial Peripheral Interface standard, including an overview of an SPI-to-VGA peripheral I designed.