The previous post explored a way of creating a double buffered image and managing an awesome 68*73 pixel image. After a bit of thought I decided that I could do better. The first approach is to try squeeze an extra bit of colour data into each pixel. This usefully means that there is now 4 bits for each pixel meaning two pixels per byte. In theory if I used the same method to do buffering this is not able to be used. After much searching though I came across AVGA that not only managed more this but with a higher resolution. I was intrigued as to how he had achieved this feat. Instead of having an image in the RAM of the chip, addresses to the program memory are in the RAM. The program memory is many times larger than RAM. This means by using a tile system the image can still be double buffered as only address’ have to be stored. The disadvantage to this approach is that everything is in terms of tiles. If you want to having something moving about then you either need many tiles with every eventuality covered or some sort of way to swap between the two methods. For this program each tile is 8 by 8 pixels creating approximately 12*12 tiles visible or a 96*96 pixel image.
Either way first we need a way to output and see just how this high resolution can be achieved.
outputdata: out RGBPORT,r4 ;1 swap r4 ;1 nop ;1 ld r3,X+ ;2 out RGBPORT,r4 ;1 lpm r19, Z+ ;3 add r3,r5 out RGBPORT,r19 ;1 swap r19 ;1 lpm r4,Z+ ;3 out RGBPORT,r19 ;1 lpm r19, Z+ ;3 nop ;1 out RGBPORT,r4 ;1 swap r4 ;1 lpm r19, Z+ ;3 out RGBPORT,r4 ;1 ld ZH, X+ ;2 mov ZL,r3 ;1 adc ZH,r6 out RGBPORT,r19 ;1 swap r19 ;1 lpm r4, Z+;3 out RGBPORT,r19 ;1 dec r16 ;1 sbrs r3,7 ;If in rammem odd number ;2/1 brne outputdata ;2/1
First thing to notice is that this code is only taking 5 cycles between each out command. This means a higher resolution than the previous 7 cycles. R4 contains the current pixel data and needs to be loaded with a value before entering the loop. After an output the data can be swapped to output the next pixel. This is because as said earlier 4bits to each pixel so a nibble swap will bring the correct nibble forward. The Z register contains the address to the current pixel inside the tile. So after two outputs a new R4 value has to be fetched from Z. The X register points to the address of the next tile. As you may note R19 is also used for data sometimes. This is because we need a few spare cycles so pixels are loaded as soon as possible. R16 contains the current loop number we are on so is decremented after 8 outputs and before hand has a value of 512/5/8 = 12.8 = 12. We also need to load the next value of the Z register as early as possible so this has been saved into R3 for later use. R5 and R6 contain the current line of the tile that is being displayed.
The last line of code saying sbrs r3,7 is my clever way of outputting differently if we want to use RAM instead of program memory. I will cover how that works in the next post.
This post will hopefully give you an understanding of how a tile based VGA output with an overlay can be achieved on a AVR microchip.