High-Resolution Color TV Using Two Microcontrollers

ECE 476

By Alan Levy





My final project creates a relatively high resolution color TV display by using two microcontrollers with shared access to external memory.


In the fall of 2005, I worked on a microcontroller project to create color video using an Atmel microcontroller.  I had soon realized that since the microcontrollers have a very small amount of SRAM in them (even the mega128 only has 4kB), the resolution that could be achieved without external SRAM would not be very high.  In fact, I was only able to achieve about 64x100 pixels for a color TV display, with 4 bit color, using a mega32.  I was unhappy with these results however, so I wanted to try and increase the resolution that I could achieve by utilizing external memory to hold the video data.


My experience with the previous project also made me realize that even if I did use external memory to display to a color television, I would never have the time in between frames to perform the necessary calculations and update the external memory.  I decided to add a second microcontroller that would access and change the memory between frames and could also perform calculation while the first microcontroller was pushing the external memory contents to a set of DACs.


High-Level Design


As previously mentioned, I had decided to work on this project because I wanted to improve a project I had worked on in the fall of 2005.  This project can be seen at Color Video Generation with the mega32 microcontroller.


The basic idea of the project is that one microcontroller handles all the calculations and memory updates, while the other handles the NTSC encoding.  A block diagram can be seen below:

Hardware and Software Tradeoffs

When I originally began the project, I planned on using two 8 bit counters which the mega32 would increment in order to access the SRAM.  I also planned on using a latch to free up an I/O port on the mega128.  I soon realized that using these parts added a layer of complexity, so I decided to remove them, in order to simplify the design.  In addition, these parts also slowed down the rate at which the memory could be accessed, decreasing the number of pixels that could be displayed on a line and decreasing the number of pixels that could be accessed during the frame downtime.


When I used a single microcontroller to display the color data, I could change the level of the color bits at will.  This was helpful, because at the end of a line, the RGB inputs have to be grounded, so they do not mess up the sync signal.  Unfortunately, when I added the SRAM, I did not have such control, because the data was totally controlled by what was in the SRAM, and putting the SRAM in a high-Z state made the inputs floating instead of grounded.  There were a few solutions to this problem:  The first would involve placing black pixels at the end of each line, so that when the inputs were placed in a high-Z state, they would already have been grounded.  The second solution was to ground the inputs, using transistors.  I decided that this was the best option, because it would allow the user to access the full range of memory and was not too complex to put together.



In order to create color video, I had to conform to the NTSC color TV standard.  This was not too difficult, as all of the sync and color subcarrier information was taken care of by the ELM304 and the AD724.

Hardware Design

Based on the supplied schematic in the appendix, it should be fairly easy for someone to create the same design.  I would advise against using binary counter ICs as previously mentioned, unless they are extremely fast, because the added delay may have an effect the quality on the screen.  In addition, it would be a good idea to try and keep the wires as short as possible to limit the effects of EMI.


The hardware design I used for the mega32/ELM304 interface is similar to what I used in my previous project, but I added a connection to pin6 on the elm304, because this pin went high when in the display portion of the signal.  I borrowed this idea from another group attempting a similar project to my own (ECE 476 Final Project: High-Resolution Color Television by Keith Jamison and Morgan Winer) because it allowed an easy way of knowing when to access the SRAM without having to keep track of line numbers.  I also changed the DAC set up, removing one bit from green and adding it to blue in order to allow blue for a few more shades of blue.  I had sampled two DACs from Analog Devices, but I did not have time to solder them on to prototype boards and then figure out how to use them, so I just went with a simple resistor network.  Before entering the RGB inputs of the AD724, each input was connected to the collector pin of an NPN transistor and the emitter was connected to ground.  The bases of these transistors were connected to PORTD.4 on the mega32, so whenever the port pin went high, the RGB inputs would be forced to ground, effectively shutting off the DACs.  This was also useful for when the mega128 was accessing the memory because the data pins are both input and output and the mega128 could destroy the sync signal while it was changing the contents of the memory.  If I was able to sample and use dual port SRAM this could be avoided, but the 3 NPN transistors worked out perfectly well.


Two pins on the mega32 and mega128 were used to communicate between each other.  One pin told the mega32 when the mega128 was finished accessing the SRAM.  This was used during the initialization sequence, since erasing the entire contents of the memory array would take about 80ms.  In addition, if I wanted to set the background to a certain color or set of colors, this could also be done at this time.  The other pin would inform the mega128 when the mega32 was finished displaying the contents of the memory.  There are two options that could be taken at this point.  If the mega128 has a great deal to write to the screen, it could inform the mega32 of this by pulling the first communication pin low.  This will turn off the display until the pin changes its state, but the screen will also blank if this is done, so care should be taken when doing this.  It may be possible to skip a few frames for a loading sequence, but every other frame should not be skipped.  An interlaced display running at 30Hz looks horrible, and will cause most people to feel some slight discomfort, so care should be taken that all display code will finish in one frame.  Another option, if the mega128 does not have very much to write to the screen, could be to write whatever is necessary without changing the first communication pin.  One thing to keep in mind is that when changing who has control of the memory, the port pins accessing the address bus and/or the data bus on the “disabled” microcontroller are in a high-Z state.  If this did not occur, a large amount of current could be drawn and/or the voltage levels could drop to unacceptable TTL levels.


The mega128 is a 64 pin microcontroller, with substantially more flash, SRAM and EEPROM than the 40 pin megas.  In addition, it has two and a half more ports than the mega32, so it was an excellent choice as the extra ports would allow it to access the memory and change it without a latch in addition to allowing for an input device and/or sound.  Unfortunately due to time constraints and the fact that I was working alone, I was unable to implement either of those things, but they could be easily done as more than enough I/O pins are free.  Three I/O ports and one extra pin are used to access the memory, 16 pins for the address bus and chip enable, 8 pins for the data bus, and 1 single pin for write enable.  The memory was written by writing the address to be written to the two address ports, writing the data to be written to the data port, then pulling the write enable pin low.  Once the write enable pin was pulled high again, the data was written to the address location in the SRAM.

Software Design

Writing the software for this project was extremely difficult.  Writing code to make one microcontroller display color video is hard enough, but trying to make two microcontrollers access the same memory, at different intervals was very hard to accomplish.  Assuming that there are about 20 lines worth of memory access time, with each line lasting 63.5 µs, there is about 1.2ms to change the contents of the memory.  Unfortunately, this is not very much time, so not that much can change on the screen in a single frame.  The memWrite function takes about 25 cycles to run, so assuming an additional overhead of about 20 cycles, only 426 pixels can be changed.  This may seem like a lot, but the screen has a width of about 240 visible pixels, and a height of 128 pixels.  This means that there are 30,720 pixels on the screen, meaning only 1.3% of the pixels can change between frames.  This can be increased with further optimization of the subroutines that call memWrite, but the max limit that can be changed is about 768 pixels, which is still only 2.5%.

In any case, I wrote a few functions that allow easier access to various portions of memory.  These functions and what they do are listed below:



void memWrite (int address, unsigned char output)

Most basic external memory access function.  Allows direct modification of the bytes in VRAM

void textWrite(int address, unsigned char textNum)

Allows an 8x8 texture to be written to a spot on the memory array.  A texture will overwrite what was in the location it was place in.

void sprWrite(int address, unsigned char, sprNum)

Allows an 8x8 sprite to be written to a spot on the memory array.  A 0x01 in a sprite determines transparency.  This means, when writing a sprite to VRAM, it will keep the background on pixels designated as transparent.

void combineSprText(unsigned int address, unsigned char sprNum, unsigned char textNum)

Combines a sprite and texture in a single function, and places the result in the location in memory.


In addition to the functions, there are a few useful variables as well.  The array, textureGrid, is a 32x16 array that contains the texture number of 512 different spots in VRAM.  During initialization, if texture numbers are assigned where asked, the textures will automatically be placed in the memory array, before the mega32 begins to display to the TV.  There is also a structure, sprite_var that contains any variables associated with sprites.  Currently, there is only 1 variable associated with the structure, .address, but many more can be added, if necessary.  It is initialized at whatever the max sprite number is, which is currently set to 4.  In the demo I have currently set up, there are 4 pairs of sprites that represent the Pac-Man video game character.  Every 4 frames, Pac-Man switches from an open mouth, to a closed mouth, and this is accomplished through the sprite_var[].address structure.


The software written for the mega32 basically just reads when the sync signal is, and determines, through pin 6 on the ELM304, if is time to push bytes to the DACs.  The code quickly runs through all the bytes in the external memory, so in order to fill up an entire television screen, each line is repeated twice.  If I was able to combine two SRAM ICs or was able to sample a larger chip, I would have been able to have each line be unique, but unfortunately, I was unable to get any larger memory chips.


In addition to reading the sync signal and pushing bytes to the DACs, the mega32 also alerts the mega128 as to when it is allowed to write to the screen.  The mega128 will run program code until it is alerted, and then it will begin writing to the external RAM.  During the time period, PORTG.0 has been pulled low, to make sure that the mega32 does not try to display.  Once the memory contents have been fully updated, PORTG.1 is set high again.  In the tech demo, this only takes one frame, so there is no flicker present.


The results of the software and hardware combination I designed can be seen in the following movie: Pac-Man Moving.  Although not very noticeable in the movie, in person, there is a bit of a wiggle in the picture.  I discovered that this is probably being caused by fluctuations in Vcc relative to ground, which could be solved by adding several capacitors to the design.  Unfortunately, I did not anticipate this, so there was very little room to add extra capacitors.  I’m sure that if I were able to add two capacitors between Vcc and Ground on the ELM304, I would be able to significantly decrease the amount of wiggle noticeable in the display.  Besides the wiggle, the NTSC signal looked extremely good, with the sync pulses, the color burst, and the video signal very noticeable.


I tried very hard to make me design modular, so it could be useable by other people.  Given enough time, and possibly some extra hardware, I am positive that many great things could be created with my design.



Unfortunately, I did not meet all the expectations I had for my design.  I did not anticipate all of the trouble that I would have interfacing with the external memory between the two microcontrollers.  In addition, even though I knew I should add capacitors to even out Vcc, I did not anticipate the amount of problems I had with voltage fluctuations.  It probably would have been best to put each microcontroller on its own voltage regulator with appropriate capacitors, and then put the other components on their own regulator as well.  In addition, trying to keep the wire lengths as short as possible, given the nature of the color television signal, would definitely improve the quality of the display.  Ideally, given the time and money, creating a PCB for this project would be best, given the number of wires needed to interface with external memory.


If given an opportunity to go back and do the project again, there would be a number of other things I would like to change.  First of all, I probably would have tried to be part of a group, instead of working by myself.  Although I did learn a lot about all the hardware and software by working alone, I was not able to do as much as I would have liked.  For example, one thing that I would have liked would have been a way to draw a picture and then have that saved as a series of 8-bit numbers, in the format BBGGGRRR.  While that may not seem like much, my knowledge of programming on computers is limited, so I would have no idea where to begin.  However, if I had a partner that did know how to do that, or could figure it out, that would have been a huge addition to the project, as it would have allowed a greater number of pictures to be displayed for a tech demo.  Other things that I would have liked to add would have been an input interface, audio, and a hardware based sprite overlay system.  I would have also liked to implement a better communication scheme between the mega32 and mega128, but what is set up currently works fairly well, so this would have been last on my list of things I would have liked to add/changed.


In regards to intellectual property considerations, all of the program code and hardware design was my own, so I do not have to worry about that.  The image I used in my tech demo was Pac-Man, which may have a trademark or copyright associated with it, but since it was only a small tech demo and a previous 476 project created an entire Pac-Man game, I thought using this one image would be perfectly fine.


In designing my project, number 5, 6 and 10 of the IEEE Code of Ethics were probably most relevant.  They state:


5. to improve the understanding of technology, its appropriate application, and potential consequences;

6. to maintain and improve our technical competence and to undertake technological tasks for others only if qualified by training or experience, or after full disclosure of pertinent limitations;


10. to assist colleagues and co-workers in their professional development and to support them in following this code of ethics.


Being a Biological and Environmental Engineer means that my understanding of electronics and their applications may not be as great as some of my ECE counterparts.  Over the past year and a half, however, I became very interested in learning about how various electronic components work and some of theory behind them.  Working on this design project, as well as working on a project with Bruce the semester before this, has greatly increased my knowledge of all things electronic, as well as increased my competency in using these components.  If asked to create some sort of embedded system design, I feel that I would be more than capable of creating a suitable design.


In regards to point 10, I found as I was learning more and more, I felt more comfortable with helping other people in the lab.  I would overhear people talking about various troubles they were having, such as a large amount of 60Hz noise on an oscilloscope (the ground on the probe was not working) or being unable to program their microcontroller on the PC board (the fuse bits had to be unchecked on the STK500), and I felt that since I knew what the problem was, I was obligated to try and help them out.  In addition, last semester I created an interface for color TV (albeit at a lower resolution) that at least one group decided to use.  They were having some trouble with my code, so I thought that it was important that I help them with their troubles, since I was the one that created it.  Other people may feel that it is not their responsibility to fix other people’s problems (especially when we are graded in comparison to one another), but I felt that helping other people was the right thing to do, because not only did it increase their understanding on the problem, but it also increased my own, by teaching to others.



Commented Code

Link to mega128.c

Link to newsynccounter.c, the mega32 source code


Link to schematic picture

Link to schematic.sch


STK501 (rental)


mega128 (rental)


White Board (rental)


PC board


Color TV (rental)




Stuff I didn't use, but purchased


  • Latch


  • 8-bit counter x2


Stuff from my previous project


  • Mega32


  • ELM304


  • AD724


  • My own STK500


  • My own whiteboard


  • My own power supply






This entire project was done by me, so all tasks were completed by me.