1 = VGA Signal Output = 2 3 There are two principal mechanisms for generating a VGA signal demonstrated in 4 this project: 5 6 * Using the CPU to "copy" pixel data to an output port 7 * Using DMA transfers to "copy" pixel data to an output port 8 9 Within the latter, there are a number of variations in the mechanism employed: 10 11 * Use of general-purpose output pins versus parallel mode outputs 12 * Use of large transfer cells containing each entire pixel line versus small 13 transfer cells containing fragments of each line 14 * Use of a single transfer-initiating event versus separate line-initiating 15 and transfer-initiating events 16 17 == Using the CPU for Transfers == 18 19 {{{#!graphviz 20 //format=svg 21 //transform=notugly 22 digraph cpu { 23 node [shape=box,fontsize="13.0",fontname="Helvetica"]; 24 rankdir=TD; 25 26 subgraph { 27 rank=same; 28 29 timer [label="Display line\ntimer",style=filled,fillcolor=gold]; 30 t_0 [label="0",shape=ellipse]; 31 t_hsync [label="hsync",shape=ellipse]; 32 t_limit [label="limit",shape=ellipse]; 33 } 34 35 oc1 [label="Output compare",style=filled,fillcolor=gold]; 36 37 subgraph { 38 rank=same; 39 40 lineirq [label="Display line\ninterrupt handler"]; 41 pixelirq [label="Pixel output\ninterrupt handler"]; 42 } 43 44 subgraph { 45 rank=same; 46 47 pixels [label="Pixel output\nBlack/reset output",style=filled,fillcolor=green,shape=parallelogram]; 48 hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; 49 vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; 50 } 51 52 /* The timer starts at 0 and wraps around at limit. */ 53 54 timer -> t_0 [arrowhead=none]; 55 t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; 56 57 /* The timer initiates the interrupt request for pixel production. */ 58 59 t_0 -> pixelirq; 60 61 /* The interrupt handler generates the pixel output. */ 62 63 pixelirq -> pixels; 64 65 /* The timer feeds the output compare unit, driving hsync. */ 66 67 t_hsync -> oc1; 68 oc1 -> hsync; 69 70 /* The output compare unit initiates the interrupt request for each line, 71 driving vsync. */ 72 73 oc1 -> lineirq; 74 lineirq -> vsync; 75 } 76 }}} 77 78 == Using DMA for Transfers == 79 80 {{{#!graphviz 81 //format=svg 82 //transform=notugly 83 digraph dma { 84 node [shape=box,fontsize="13.0",fontname="Helvetica"]; 85 rankdir=TD; 86 87 subgraph { 88 rank=same; 89 90 timer [label="Display line\ntimer",style=filled,fillcolor=gold]; 91 t_0 [label="0",shape=ellipse]; 92 t_hsync [label="hsync",shape=ellipse]; 93 t_limit [label="limit",shape=ellipse]; 94 } 95 96 oc1 [label="Output compare",style=filled,fillcolor=gold]; 97 98 subgraph { 99 rank=same; 100 101 dma_line [label="Pixel output\nDMA channel",style=filled,fillcolor=lightblue]; 102 dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; 103 lineirq [label="Display line\ninterrupt handler"]; 104 } 105 106 subgraph { 107 rank=same; 108 109 pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; 110 black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; 111 hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; 112 vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; 113 } 114 115 /* The timer starts at 0 and wraps around at limit. */ 116 117 timer -> t_0 [arrowhead=none]; 118 t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; 119 120 /* The timer initiates the DMA transfer for pixel production. */ 121 122 t_0 -> dma_line; 123 124 /* The line channel generates the pixel output. */ 125 126 dma_line -> pixels; 127 128 /* The completion of the line channel initiates the reset channel. */ 129 130 dma_line -> dma_reset; 131 132 /* The reset channel generates black/reset output. */ 133 134 dma_reset -> black; 135 136 /* The black/reset value follows the visible pixels. */ 137 138 pixels -> black [style=dashed]; 139 140 /* The timer feeds the output compare unit, driving hsync. */ 141 142 t_hsync -> oc1; 143 oc1 -> hsync; 144 145 /* The output compare unit initiates the interrupt request for each line, 146 driving vsync. */ 147 148 oc1 -> lineirq; 149 lineirq -> vsync; 150 } 151 }}} 152 153 == Using DMA and Timed Transfers == 154 155 {{{#!graphviz 156 //format=svg 157 //transform=notugly 158 digraph dma { 159 node [shape=box,fontsize="13.0",fontname="Helvetica"]; 160 rankdir=TD; 161 162 subgraph { 163 rank=same; 164 165 timer [label="Display line\ntimer",style=filled,fillcolor=gold]; 166 t_0 [label="0",shape=ellipse]; 167 t_hsync [label="hsync",shape=ellipse]; 168 t_limit [label="limit",shape=ellipse]; 169 } 170 171 oc1 [label="Output compare",style=filled,fillcolor=gold]; 172 173 subgraph { 174 rank=same; 175 176 trtimer [label="Transfer timer",style=filled,fillcolor=gold]; 177 tr_0 [label="0",shape=ellipse]; 178 tr_limit [label="limit",shape=ellipse]; 179 } 180 181 subgraph { 182 rank=same; 183 184 dma_init [label="Initiator\nDMA channel",style=filled,fillcolor=lightblue]; 185 dma_line [label="Pixel output\nDMA channel",style=filled,fillcolor=lightblue]; 186 dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; 187 lineirq [label="Display line\ninterrupt handler"]; 188 } 189 190 subgraph { 191 rank=same; 192 193 pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; 194 black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; 195 hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; 196 vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; 197 } 198 199 /* The line timer starts at 0 and wraps around at limit. */ 200 201 timer -> t_0 [arrowhead=none]; 202 t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; 203 204 /* The transfer timer starts at 0 and wraps around at limit. */ 205 206 trtimer -> tr_0 [arrowhead=none]; 207 tr_0 -> tr_limit -> tr_0 [style=dashed]; 208 209 /* The line timer initiates the DMA transfers for the display line. */ 210 211 t_0 -> dma_init; 212 213 /* The completion of the initiating channel enables the line channel. */ 214 215 dma_init -> dma_line; 216 217 /* Each cell transfer in the line channel is initiated by the transfer 218 timer. */ 219 220 tr_0 -> dma_line; 221 222 /* The line channel generates the pixel output. */ 223 224 dma_line -> pixels; 225 226 /* The completion of the line channel initiates the reset channel. */ 227 228 dma_line -> dma_reset; 229 230 /* The reset channel generates black/reset output. */ 231 232 dma_reset -> black; 233 234 /* The black/reset value follows the visible pixels. */ 235 236 pixels -> black [style=dashed]; 237 238 /* The timer feeds the output compare unit, driving hsync. */ 239 240 t_hsync -> oc1; 241 oc1 -> hsync; 242 243 /* The output compare unit initiates the interrupt request for each line, 244 driving vsync. */ 245 246 oc1 -> lineirq; 247 lineirq -> vsync; 248 } 249 }}} 250 251 == Using DMA and Timed Dual-Channel Transfers == 252 253 {{{#!graphviz 254 //format=svg 255 //transform=notugly 256 digraph dma { 257 node [shape=box,fontsize="13.0",fontname="Helvetica"]; 258 rankdir=TD; 259 260 subgraph { 261 rank=same; 262 263 timer [label="Display line\ntimer",style=filled,fillcolor=gold]; 264 t_0 [label="0",shape=ellipse]; 265 t_hsync [label="hsync",shape=ellipse]; 266 t_limit [label="limit",shape=ellipse]; 267 } 268 269 oc1 [label="Output compare",style=filled,fillcolor=gold]; 270 271 subgraph { 272 rank=same; 273 274 trtimer [label="Transfer timer",style=filled,fillcolor=gold]; 275 tr_0 [label="0",shape=ellipse]; 276 tr_limit [label="limit",shape=ellipse]; 277 } 278 279 subgraph { 280 rank=same; 281 282 dma_init [label="Initiator\nDMA channel",style=filled,fillcolor=lightblue]; 283 dma_line [label="{Pixel output\nDMA channel #1 | Pixel output\nDMA channel #2}",style=filled,fillcolor=lightblue,shape=record]; 284 dma_reset [label="Pixel reset\nDMA channel",style=filled,fillcolor=lightblue]; 285 lineirq [label="Display line\ninterrupt handler"]; 286 } 287 288 subgraph { 289 rank=same; 290 291 pixels [label="Pixel output",style=filled,fillcolor=green,shape=parallelogram]; 292 black [label="Black/reset output",style=filled,fillcolor=black,fontcolor=white,shape=parallelogram]; 293 hsync [label="Horizontal sync",shape=house,style=filled,fillcolor=red]; 294 vsync [label="Vertical sync",shape=house,style=filled,fillcolor=red]; 295 } 296 297 /* The line timer starts at 0 and wraps around at limit. */ 298 299 timer -> t_0 [arrowhead=none]; 300 t_0 -> t_hsync -> t_limit -> t_0 [style=dashed]; 301 302 /* The transfer timer starts at 0 and wraps around at limit. */ 303 304 trtimer -> tr_0 [arrowhead=none]; 305 tr_0 -> tr_limit -> tr_0 [style=dashed]; 306 307 /* The line timer initiates the DMA transfers for the display line. */ 308 309 t_0 -> dma_init; 310 311 /* The completion of the initiating channel enables the line channels. */ 312 313 dma_init -> dma_line; 314 315 /* Each cell transfer in the line channels is initiated by the transfer 316 timer. */ 317 318 tr_0 -> dma_line; 319 320 /* The line channels generate the pixel output. */ 321 322 dma_line -> pixels; 323 324 /* The completion of the line channels initiates the reset channel. */ 325 326 dma_line -> dma_reset; 327 328 /* The reset channel generates black/reset output. */ 329 330 dma_reset -> black; 331 332 /* The black/reset value follows the visible pixels. */ 333 334 pixels -> black [style=dashed]; 335 336 /* The timer feeds the output compare unit, driving hsync. */ 337 338 t_hsync -> oc1; 339 oc1 -> hsync; 340 341 /* The output compare unit initiates the interrupt request for each line, 342 driving vsync. */ 343 344 oc1 -> lineirq; 345 lineirq -> vsync; 346 } 347 }}}