ubb-vga/ubb-vga.c |
| 1 | /* |
| 2 | * ubb-vga.c - Output video on UBB with more or less VGA timing |
| 3 | * |
| 4 | * Written 2011 by Werner Almesberger |
| 5 | * Copyright 2011 Werner Almesberger |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | */ |
| 12 | |
| 13 | /* |
| 14 | * WARNING: this program does very nasty things to the Ben and it doesn't |
| 15 | * like company. In particular, it resents: |
| 16 | * |
| 17 | * - the MMC driver - disable it with |
| 18 | * echo jz4740-mmc.0 >/sys/bus/platform/drivers/jz4740-mmc/unbind |
| 19 | * - the AT86RF230/1 kernel driver - use a kernel that doesn't have it |
| 20 | * - anything that accesses the screen - kill GUI, X server, etc. |
| 21 | * - the screen blanker - either disable it or make sure the screen stays |
| 22 | * dark, e.g., with |
| 23 | * echo 1 >/sys/devices/platform/jz4740-fb/graphics/fb0/blank |
| 24 | * - probably a fair number of other daemons and things as well - best to |
| 25 | * kill them all. |
| 26 | */ |
| 27 | |
| 28 | |
| 29 | #include <stdint.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <stdio.h> |
| 32 | #include <unistd.h> |
| 33 | #include <string.h> |
| 34 | #include <fcntl.h> |
| 35 | #include <sys/mman.h> |
| 36 | |
| 37 | |
| 38 | #define DAT0 (1 << 10) |
| 39 | #define DAT1 (1 << 11) |
| 40 | #define DAT2 (1 << 12) |
| 41 | #define DAT3 (1 << 13) |
| 42 | #define CMD (1 << 8) |
| 43 | #define CLK (1 << 9) |
| 44 | |
| 45 | #define R DAT2 |
| 46 | #define G DAT0 |
| 47 | #define B DAT1 |
| 48 | #define HSYNC CMD |
| 49 | #define VSYNC DAT3 |
| 50 | |
| 51 | #define TIMER 7 |
| 52 | |
| 53 | |
| 54 | #define PAGE_SIZE 4096 |
| 55 | #define SOC_BASE 0x10000000 |
| 56 | #define DEFAULT_COUNT (1000*1000) |
| 57 | |
| 58 | |
| 59 | static uint8_t thres = 63; |
| 60 | |
| 61 | |
| 62 | /* ----- Ben hardware ------------------------------------------------------ */ |
| 63 | |
| 64 | |
| 65 | static volatile uint32_t *icmr, *icmsr, *icmcr; |
| 66 | static uint32_t old_icmr; |
| 67 | |
| 68 | static volatile uint32_t *clkgr; |
| 69 | static uint32_t old_clkgr; |
| 70 | |
| 71 | static volatile uint32_t *pdpin, *pddats, *pddatc; |
| 72 | static volatile uint32_t *pddirs, *pddirc; |
| 73 | |
| 74 | static volatile uint32_t *tssr, *tscr; |
| 75 | static volatile uint32_t *tesr, *tecr; |
| 76 | static volatile uint32_t *tcsr, *tdfr, *tcnt; |
| 77 | |
| 78 | |
| 79 | static void disable_interrupts(void) |
| 80 | { |
| 81 | /* |
| 82 | * @@@ Race condition alert ! If we get interrupted/preempted between |
| 83 | * reading ICMR and masking all interrupts, and the code that runs |
| 84 | * between these two operations changes ICMR, then we may set an |
| 85 | * incorrect mask when restoring interrupts, which may hang the system. |
| 86 | */ |
| 87 | |
| 88 | old_icmr = *icmr; |
| 89 | *icmsr = 0xffffffff; |
| 90 | } |
| 91 | |
| 92 | |
| 93 | static void enable_interrupts(void) |
| 94 | { |
| 95 | *icmcr = ~old_icmr; |
| 96 | } |
| 97 | |
| 98 | |
| 99 | /* |
| 100 | * @@@ Disabling the LCD clock will halng operations that depend on the LCD |
| 101 | * subsystem to advance. This includes the screen saver. |
| 102 | */ |
| 103 | |
| 104 | static void disable_lcd(void) |
| 105 | { |
| 106 | old_clkgr = *clkgr; |
| 107 | *clkgr = old_clkgr | 1 << 10; |
| 108 | } |
| 109 | |
| 110 | |
| 111 | static void enable_lcd(void) |
| 112 | { |
| 113 | *clkgr = old_clkgr; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | static void get_timer(void) |
| 118 | { |
| 119 | *tscr = 1 << TIMER; /* enable clock */ |
| 120 | *tcsr = 1; /* count at PCLK/1 */ |
| 121 | *tdfr = 0xffff; /* count to 0xffff */ |
| 122 | *tesr = 1 << TIMER; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | static void release_timer(void) |
| 127 | { |
| 128 | *tecr = 1 << TIMER; |
| 129 | *tssr = 1 << TIMER; |
| 130 | } |
| 131 | |
| 132 | |
| 133 | static void *map(off_t addr, size_t size) |
| 134 | { |
| 135 | int fd; |
| 136 | void *mem; |
| 137 | |
| 138 | fd = open("/dev/mem", O_RDWR | O_SYNC); |
| 139 | if (fd < 0) { |
| 140 | perror("/dev/mem"); |
| 141 | exit(1); |
| 142 | } |
| 143 | mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr); |
| 144 | if (mem == MAP_FAILED) { |
| 145 | perror("mmap"); |
| 146 | exit(1); |
| 147 | } |
| 148 | |
| 149 | return mem; |
| 150 | } |
| 151 | |
| 152 | |
| 153 | static void ben_setup(void) |
| 154 | { |
| 155 | volatile void *base; |
| 156 | |
| 157 | base = map(SOC_BASE, PAGE_SIZE*3*16); |
| 158 | |
| 159 | icmr = base+0x1004; |
| 160 | icmsr = base+0x1008; |
| 161 | icmcr = base+0x100c; |
| 162 | |
| 163 | clkgr = base+0x20; |
| 164 | |
| 165 | pdpin = base+0x10300; |
| 166 | pddats = base+0x10314; |
| 167 | pddatc = base+0x10318; |
| 168 | |
| 169 | pddirs = base+0x10364; |
| 170 | pddirc = base+0x10368; |
| 171 | |
| 172 | tssr = base+0x202c; |
| 173 | tscr = base+0x203c; |
| 174 | |
| 175 | tesr = base+0x2014; |
| 176 | tecr = base+0x2018; |
| 177 | |
| 178 | tcsr = base+0x204c+0x10*TIMER; |
| 179 | tdfr = base+0x2040+0x10*TIMER; |
| 180 | tcnt = base+0x2048+0x10*TIMER; |
| 181 | |
| 182 | /* |
| 183 | * Ironically, switching the LCD clock on and off many times only |
| 184 | * increases the risk of a hang. Therefore, we leave stop it during |
| 185 | * all the measurements and only enable it again at the end. |
| 186 | */ |
| 187 | disable_lcd(); |
| 188 | get_timer(); |
| 189 | } |
| 190 | |
| 191 | |
| 192 | static void cleanup(void) |
| 193 | { |
| 194 | release_timer(); |
| 195 | enable_lcd(); |
| 196 | } |
| 197 | |
| 198 | |
| 199 | /* ----- Interface --------------------------------------------------------- */ |
| 200 | |
| 201 | |
| 202 | void setup(void) |
| 203 | { |
| 204 | mlockall(MCL_CURRENT | MCL_FUTURE); |
| 205 | ben_setup(); |
| 206 | *pddirs = R | G | B | HSYNC | VSYNC; |
| 207 | } |
| 208 | |
| 209 | |
| 210 | static uint32_t pick(int set, int bit, uint32_t val) |
| 211 | { |
| 212 | return set == bit ? val >> 8 : 0; |
| 213 | } |
| 214 | |
| 215 | |
| 216 | static uint32_t pattern(int set, int r, int g, int b) |
| 217 | { |
| 218 | return pick(set, r, R) | pick(set, g, G) | pick(set, b, B); |
| 219 | } |
| 220 | |
| 221 | |
| 222 | #define BURST 32 |
| 223 | |
| 224 | #define PREFETCH_HSYNC 160 |
| 225 | #define PREFETCH_HFRONT (160-PREFETCH_HSYNC) |
| 226 | #define DELAY_HFRONT 30 |
| 227 | #define DELAY_HBACK 40 |
| 228 | //#define DELAY_VSYNC 3500 |
| 229 | //#define DELAY_VFRONT 56000 |
| 230 | //#define DELAY_VBACK 28000 |
| 231 | #define DELAY_VFRONT 1500 |
| 232 | #define DELAY_LINE 1800 |
| 233 | #define DELAY_HSYNC 210 |
| 234 | |
| 235 | |
| 236 | static inline void prefetch(const uint8_t *prefetch, int words) |
| 237 | { |
| 238 | volatile const uint8_t *p = prefetch; |
| 239 | |
| 240 | while (p != prefetch+words) { |
| 241 | (void) *p; |
| 242 | p += BURST; |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | |
| 247 | static void until(uint16_t cycles) |
| 248 | { |
| 249 | while ((*tcnt & 0xffff) < cycles); |
| 250 | } |
| 251 | |
| 252 | #define US(us) ((uint16_t) ((us)*112)) |
| 253 | |
| 254 | static void line(const uint8_t *line, const uint8_t *fetch) |
| 255 | { |
| 256 | const uint8_t *p = line; |
| 257 | //volatile uint8_t pat = R | B | G; |
| 258 | /* HSYNC */ |
| 259 | *tcnt = 0; |
| 260 | *pddatc = HSYNC; |
| 261 | // prefetch(fetch, PREFETCH_HSYNC); |
| 262 | prefetch(fetch, 160); |
| 263 | until(US(3.77)); |
| 264 | // *tcnt = 0; |
| 265 | *pddats = HSYNC; |
| 266 | |
| 267 | /* Front porch */ |
| 268 | // prefetch(fetch+PREFETCH_HSYNC, PREFETCH_HFRONT); |
| 269 | // until(US(3.77+1.79-3.77)); |
| 270 | until(US(3.77+1.79)); |
| 271 | |
| 272 | while (p != line+320) { |
| 273 | *pddats = *p++ << 8;//pat; //R | G | B; //*p++; |
| 274 | *pddatc = *p++ << 8;//pat;//R | G | B; // *p++; |
| 275 | } |
| 276 | |
| 277 | /* Back porch */ |
| 278 | // until(US(31.77-3.77)); |
| 279 | until(US(31.77)); |
| 280 | until(US(36)); |
| 281 | } |
| 282 | |
| 283 | |
| 284 | static void hdelay(int cycles) |
| 285 | { |
| 286 | while (cycles--) { |
| 287 | *tcnt = 0; |
| 288 | *pddatc = HSYNC; |
| 289 | until(US(3.77)); |
| 290 | *pddats = HSYNC; |
| 291 | until(US(31.77)); |
| 292 | until(US(36)); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | |
| 297 | static void frame(const uint8_t *f) |
| 298 | { |
| 299 | const uint8_t *p; |
| 300 | |
| 301 | /* VSYNC */ |
| 302 | *pddatc = VSYNC; |
| 303 | hdelay(2); |
| 304 | *pddats = VSYNC; |
| 305 | |
| 306 | /* Front porch */ |
| 307 | *tcnt = 0; |
| 308 | *pddatc = HSYNC; |
| 309 | // prefetch(f, PREFETCH_HSYNC); |
| 310 | until(US(3.77)); |
| 311 | // *tcnt = 0; |
| 312 | *pddats = HSYNC; |
| 313 | |
| 314 | // prefetch(f+PREFETCH_HSYNC, PREFETCH_HFRONT); |
| 315 | prefetch(f, 160); |
| 316 | // until(US(31.77-3.77)); |
| 317 | until(US(31.77)); |
| 318 | until(US(36)); |
| 319 | hdelay(31); |
| 320 | |
| 321 | for (p = f; p != f+240*320; p += 320) { |
| 322 | line(p, p+160); |
| 323 | line(p, p+320); |
| 324 | } |
| 325 | |
| 326 | /* Back porch */ |
| 327 | hdelay(14); |
| 328 | } |
| 329 | |
| 330 | |
| 331 | static void tricolor(uint32_t *f) |
| 332 | { |
| 333 | int i; |
| 334 | |
| 335 | for (i = 0; i != 320*240/3; i++) { |
| 336 | f[i & ~1] = R; |
| 337 | f[i | 1] = G | B; |
| 338 | } |
| 339 | for (; i != 320*240*2/3; i++) { |
| 340 | f[i & ~1] = G; |
| 341 | f[i | 1] = R | B; |
| 342 | } |
| 343 | |
| 344 | for (; i != 320*240; i++) { |
| 345 | f[i & ~1] = B; |
| 346 | f[i | 1] = R | G; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | |
| 351 | static void grid(uint8_t *f) |
| 352 | { |
| 353 | static uint32_t col[8] = { |
| 354 | R | G | B, |
| 355 | R, |
| 356 | R | G, |
| 357 | G, |
| 358 | G | B, |
| 359 | B, |
| 360 | R | B, |
| 361 | R | G | B, |
| 362 | }; |
| 363 | int i, x, y; |
| 364 | |
| 365 | for (i = 0; i != 8; i++) { |
| 366 | x = i*40+20; |
| 367 | for (y = 0; y != 240; y++) { |
| 368 | f[y*320+x] = f[y*320+x+1] = col[i] >> 8; |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | |
| 374 | static void grab(uint8_t *f) |
| 375 | { |
| 376 | uint32_t *fb = map(0x01d00000, 4*320*240); |
| 377 | int x, y; |
| 378 | uint32_t pix; |
| 379 | |
| 380 | for (y = 0; y != 240; y++) |
| 381 | for (x = 0; x != 320; x++) { |
| 382 | pix = *fb++; |
| 383 | *f++ = pattern(!(x & 1), |
| 384 | ((pix >> 16) & 255) >= thres, |
| 385 | ((pix >> 8) & 255) >= thres, |
| 386 | (pix & 255) >= thres); |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | |
| 391 | static void session(int n) |
| 392 | { |
| 393 | uint8_t f[320*(240+1)]; |
| 394 | int i; |
| 395 | |
| 396 | memset(f, 0, sizeof(f)); |
| 397 | grab(f); |
| 398 | // grid(f); |
| 399 | |
| 400 | disable_interrupts(); |
| 401 | |
| 402 | for (i = 0; i != n; i++) |
| 403 | frame(f); |
| 404 | |
| 405 | enable_interrupts(); |
| 406 | } |
| 407 | |
| 408 | |
| 409 | int main(int argc, char **argv) |
| 410 | { |
| 411 | thres = atoi(argv[2]); |
| 412 | setup(); |
| 413 | session(atoi(argv[1])); |
| 414 | cleanup(); |
| 415 | return 0; |
| 416 | } |
ubb-vga/ubb-vga.sch |
| 1 | EESchema Schematic File Version 2 date Sun Apr 24 02:16:48 2011 |
| 2 | LIBS:power |
| 3 | LIBS:device |
| 4 | LIBS:8_10-card |
| 5 | LIBS:vga |
| 6 | LIBS:ubb-vga-cache |
| 7 | EELAYER 24 0 |
| 8 | EELAYER END |
| 9 | $Descr A4 11700 8267 |
| 10 | Sheet 1 1 |
| 11 | Title "UBB VGA Adapter" |
| 12 | Date "24 apr 2011" |
| 13 | Rev "20110424" |
| 14 | Comp "Werner Almesberger" |
| 15 | Comment1 "" |
| 16 | Comment2 "" |
| 17 | Comment3 "" |
| 18 | Comment4 "" |
| 19 | $EndDescr |
| 20 | Text Label 8200 3300 0 60 ~ 0 |
| 21 | VSYNC |
| 22 | Text Label 8200 3400 0 60 ~ 0 |
| 23 | HSYNC |
| 24 | Text Label 2100 3800 0 60 ~ 0 |
| 25 | VSYNC |
| 26 | Text Label 2100 3600 0 60 ~ 0 |
| 27 | HSYNC |
| 28 | Text Label 8200 3900 0 60 ~ 0 |
| 29 | B |
| 30 | Text Label 8200 3800 0 60 ~ 0 |
| 31 | G |
| 32 | Text Label 8200 3200 0 60 ~ 0 |
| 33 | R |
| 34 | Wire Wire Line |
| 35 | 2550 3800 1800 3800 |
| 36 | Wire Wire Line |
| 37 | 1800 3800 1800 2550 |
| 38 | Wire Wire Line |
| 39 | 1800 2550 5150 2550 |
| 40 | Wire Wire Line |
| 41 | 5150 3300 5150 2550 |
| 42 | Wire Wire Line |
| 43 | 8850 3300 5150 3300 |
| 44 | Wire Wire Line |
| 45 | 3750 3600 4750 3600 |
| 46 | Wire Wire Line |
| 47 | 4750 3600 4750 4000 |
| 48 | Wire Wire Line |
| 49 | 4750 4000 7000 4000 |
| 50 | Wire Wire Line |
| 51 | 7000 4000 7200 4000 |
| 52 | Wire Wire Line |
| 53 | 7200 3800 6650 3800 |
| 54 | Wire Wire Line |
| 55 | 6650 3800 4850 3800 |
| 56 | Connection ~ 3950 4000 |
| 57 | Wire Wire Line |
| 58 | 3750 4000 3950 4000 |
| 59 | Connection ~ 7000 4000 |
| 60 | Connection ~ 6300 3200 |
| 61 | Wire Wire Line |
| 62 | 6650 3800 6650 4200 |
| 63 | Wire Wire Line |
| 64 | 7000 4600 7000 4800 |
| 65 | Wire Wire Line |
| 66 | 6300 4800 6300 4600 |
| 67 | Wire Wire Line |
| 68 | 8850 3800 7700 3800 |
| 69 | Wire Wire Line |
| 70 | 8850 3700 8650 3700 |
| 71 | Wire Wire Line |
| 72 | 8650 3700 8650 4300 |
| 73 | Wire Wire Line |
| 74 | 7700 4000 7900 4000 |
| 75 | Wire Wire Line |
| 76 | 7900 4000 7900 3900 |
| 77 | Wire Wire Line |
| 78 | 7900 3900 8850 3900 |
| 79 | Wire Wire Line |
| 80 | 8850 3200 7700 3200 |
| 81 | Wire Wire Line |
| 82 | 6650 4600 6650 4800 |
| 83 | Wire Wire Line |
| 84 | 7000 4000 7000 4200 |
| 85 | Wire Wire Line |
| 86 | 6300 3200 6300 4200 |
| 87 | Connection ~ 6650 3800 |
| 88 | Wire Wire Line |
| 89 | 3750 3900 3950 3900 |
| 90 | Wire Wire Line |
| 91 | 3950 3900 3950 4000 |
| 92 | Wire Wire Line |
| 93 | 3950 4000 3950 4200 |
| 94 | Wire Wire Line |
| 95 | 3750 3200 6300 3200 |
| 96 | Wire Wire Line |
| 97 | 6300 3200 7200 3200 |
| 98 | Wire Wire Line |
| 99 | 3750 3400 4850 3400 |
| 100 | Wire Wire Line |
| 101 | 4850 3400 4850 3800 |
| 102 | Wire Wire Line |
| 103 | 8850 3400 5050 3400 |
| 104 | Wire Wire Line |
| 105 | 5050 3400 5050 2650 |
| 106 | Wire Wire Line |
| 107 | 5050 2650 1900 2650 |
| 108 | Wire Wire Line |
| 109 | 1900 2650 1900 3600 |
| 110 | Wire Wire Line |
| 111 | 1900 3600 2550 3600 |
| 112 | NoConn ~ 2550 3200 |
| 113 | NoConn ~ 2550 3400 |
| 114 | NoConn ~ 2550 4000 |
| 115 | Text Label 3950 3600 0 60 ~ 0 |
| 116 | BLUE |
| 117 | Text Label 3950 3400 0 60 ~ 0 |
| 118 | GREEN |
| 119 | Text Label 3950 3200 0 60 ~ 0 |
| 120 | RED |
| 121 | NoConn ~ 3750 3800 |
| 122 | NoConn ~ 3750 3700 |
| 123 | NoConn ~ 3750 3500 |
| 124 | NoConn ~ 3750 3300 |
| 125 | NoConn ~ 3750 3100 |
| 126 | $Comp |
| 127 | L GND #PWR1 |
| 128 | U 1 1 4DB3B0C4 |
| 129 | P 3950 4200 |
| 130 | F 0 "#PWR1" H 3950 4200 30 0001 C CNN |
| 131 | F 1 "GND" H 3950 4130 30 0001 C CNN |
| 132 | 1 3950 4200 |
| 133 | 1 0 0 -1 |
| 134 | $EndComp |
| 135 | $Comp |
| 136 | L GND #PWR4 |
| 137 | U 1 1 4DB3B04B |
| 138 | P 7000 4800 |
| 139 | F 0 "#PWR4" H 7000 4800 30 0001 C CNN |
| 140 | F 1 "GND" H 7000 4730 30 0001 C CNN |
| 141 | 1 7000 4800 |
| 142 | 1 0 0 -1 |
| 143 | $EndComp |
| 144 | $Comp |
| 145 | L GND #PWR3 |
| 146 | U 1 1 4DB3B04A |
| 147 | P 6650 4800 |
| 148 | F 0 "#PWR3" H 6650 4800 30 0001 C CNN |
| 149 | F 1 "GND" H 6650 4730 30 0001 C CNN |
| 150 | 1 6650 4800 |
| 151 | 1 0 0 -1 |
| 152 | $EndComp |
| 153 | $Comp |
| 154 | L GND #PWR2 |
| 155 | U 1 1 4DB3B048 |
| 156 | P 6300 4800 |
| 157 | F 0 "#PWR2" H 6300 4800 30 0001 C CNN |
| 158 | F 1 "GND" H 6300 4730 30 0001 C CNN |
| 159 | 1 6300 4800 |
| 160 | 1 0 0 -1 |
| 161 | $EndComp |
| 162 | $Comp |
| 163 | L GND #PWR5 |
| 164 | U 1 1 4DB3AFED |
| 165 | P 8650 4300 |
| 166 | F 0 "#PWR5" H 8650 4300 30 0001 C CNN |
| 167 | F 1 "GND" H 8650 4230 30 0001 C CNN |
| 168 | 1 8650 4300 |
| 169 | 1 0 0 -1 |
| 170 | $EndComp |
| 171 | NoConn ~ 8850 3600 |
| 172 | NoConn ~ 8850 3500 |
| 173 | $Comp |
| 174 | L DIODE D1 |
| 175 | U 1 1 4DB3AF61 |
| 176 | P 6300 4400 |
| 177 | F 0 "D1" H 6300 4500 40 0000 C CNN |
| 178 | F 1 "1N4148" H 6300 4300 40 0000 C CNN |
| 179 | 1 6300 4400 |
| 180 | 0 -1 1 0 |
| 181 | $EndComp |
| 182 | $Comp |
| 183 | L DIODE D2 |
| 184 | U 1 1 4DB3AF5F |
| 185 | P 6650 4400 |
| 186 | F 0 "D2" H 6650 4500 40 0000 C CNN |
| 187 | F 1 "1N4148" H 6650 4300 40 0000 C CNN |
| 188 | 1 6650 4400 |
| 189 | 0 -1 1 0 |
| 190 | $EndComp |
| 191 | $Comp |
| 192 | L DIODE D3 |
| 193 | U 1 1 4DB3AF5B |
| 194 | P 7000 4400 |
| 195 | F 0 "D3" H 7000 4500 40 0000 C CNN |
| 196 | F 1 "1N4148" H 7000 4300 40 0000 C CNN |
| 197 | 1 7000 4400 |
| 198 | 0 -1 1 0 |
| 199 | $EndComp |
| 200 | $Comp |
| 201 | L R R3 |
| 202 | U 1 1 4DB3AF4D |
| 203 | P 7450 4000 |
| 204 | F 0 "R3" V 7530 4000 50 0000 C CNN |
| 205 | F 1 "1k" V 7450 4000 50 0000 C CNN |
| 206 | 1 7450 4000 |
| 207 | 0 -1 -1 0 |
| 208 | $EndComp |
| 209 | $Comp |
| 210 | L R R2 |
| 211 | U 1 1 4DB3AF4B |
| 212 | P 7450 3800 |
| 213 | F 0 "R2" V 7530 3800 50 0000 C CNN |
| 214 | F 1 "1k" V 7450 3800 50 0000 C CNN |
| 215 | 1 7450 3800 |
| 216 | 0 -1 -1 0 |
| 217 | $EndComp |
| 218 | $Comp |
| 219 | L R R1 |
| 220 | U 1 1 4DB3AF49 |
| 221 | P 7450 3200 |
| 222 | F 0 "R1" V 7530 3200 50 0000 C CNN |
| 223 | F 1 "1k" V 7450 3200 50 0000 C CNN |
| 224 | 1 7450 3200 |
| 225 | 0 -1 -1 0 |
| 226 | $EndComp |
| 227 | $Comp |
| 228 | L 8:10-CARD P1 |
| 229 | U 1 1 4DB3AF38 |
| 230 | P 9150 3500 |
| 231 | F 0 "P1" H 8950 4050 60 0000 C CNN |
| 232 | F 1 "UBB" H 9200 2900 60 0000 C CNN |
| 233 | 1 9150 3500 |
| 234 | 1 0 0 -1 |
| 235 | $EndComp |
| 236 | $Comp |
| 237 | L VGA J1 |
| 238 | U 1 1 4DB3AF2A |
| 239 | P 3150 3550 |
| 240 | F 0 "J1" H 3350 2850 60 0000 C CNN |
| 241 | F 1 "VGA" H 3150 4300 60 0000 C CNN |
| 242 | 1 3150 3550 |
| 243 | -1 0 0 1 |
| 244 | $EndComp |
| 245 | $EndSCHEMATC |
video/ubb-vga.sch |
1 | | EESchema Schematic File Version 2 date Sun Apr 24 02:16:48 2011 |
2 | | LIBS:power |
3 | | LIBS:device |
4 | | LIBS:8_10-card |
5 | | LIBS:vga |
6 | | LIBS:ubb-vga-cache |
7 | | EELAYER 24 0 |
8 | | EELAYER END |
9 | | $Descr A4 11700 8267 |
10 | | Sheet 1 1 |
11 | | Title "UBB VGA Adapter" |
12 | | Date "24 apr 2011" |
13 | | Rev "20110424" |
14 | | Comp "Werner Almesberger" |
15 | | Comment1 "" |
16 | | Comment2 "" |
17 | | Comment3 "" |
18 | | Comment4 "" |
19 | | $EndDescr |
20 | | Text Label 8200 3300 0 60 ~ 0 |
21 | | VSYNC |
22 | | Text Label 8200 3400 0 60 ~ 0 |
23 | | HSYNC |
24 | | Text Label 2100 3800 0 60 ~ 0 |
25 | | VSYNC |
26 | | Text Label 2100 3600 0 60 ~ 0 |
27 | | HSYNC |
28 | | Text Label 8200 3900 0 60 ~ 0 |
29 | | B |
30 | | Text Label 8200 3800 0 60 ~ 0 |
31 | | G |
32 | | Text Label 8200 3200 0 60 ~ 0 |
33 | | R |
34 | | Wire Wire Line |
35 | | 2550 3800 1800 3800 |
36 | | Wire Wire Line |
37 | | 1800 3800 1800 2550 |
38 | | Wire Wire Line |
39 | | 1800 2550 5150 2550 |
40 | | Wire Wire Line |
41 | | 5150 3300 5150 2550 |
42 | | Wire Wire Line |
43 | | 8850 3300 5150 3300 |
44 | | Wire Wire Line |
45 | | 3750 3600 4750 3600 |
46 | | Wire Wire Line |
47 | | 4750 3600 4750 4000 |
48 | | Wire Wire Line |
49 | | 4750 4000 7000 4000 |
50 | | Wire Wire Line |
51 | | 7000 4000 7200 4000 |
52 | | Wire Wire Line |
53 | | 7200 3800 6650 3800 |
54 | | Wire Wire Line |
55 | | 6650 3800 4850 3800 |
56 | | Connection ~ 3950 4000 |
57 | | Wire Wire Line |
58 | | 3750 4000 3950 4000 |
59 | | Connection ~ 7000 4000 |
60 | | Connection ~ 6300 3200 |
61 | | Wire Wire Line |
62 | | 6650 3800 6650 4200 |
63 | | Wire Wire Line |
64 | | 7000 4600 7000 4800 |
65 | | Wire Wire Line |
66 | | 6300 4800 6300 4600 |
67 | | Wire Wire Line |
68 | | 8850 3800 7700 3800 |
69 | | Wire Wire Line |
70 | | 8850 3700 8650 3700 |
71 | | Wire Wire Line |
72 | | 8650 3700 8650 4300 |
73 | | Wire Wire Line |
74 | | 7700 4000 7900 4000 |
75 | | Wire Wire Line |
76 | | 7900 4000 7900 3900 |
77 | | Wire Wire Line |
78 | | 7900 3900 8850 3900 |
79 | | Wire Wire Line |
80 | | 8850 3200 7700 3200 |
81 | | Wire Wire Line |
82 | | 6650 4600 6650 4800 |
83 | | Wire Wire Line |
84 | | 7000 4000 7000 4200 |
85 | | Wire Wire Line |
86 | | 6300 3200 6300 4200 |
87 | | Connection ~ 6650 3800 |
88 | | Wire Wire Line |
89 | | 3750 3900 3950 3900 |
90 | | Wire Wire Line |
91 | | 3950 3900 3950 4000 |
92 | | Wire Wire Line |
93 | | 3950 4000 3950 4200 |
94 | | Wire Wire Line |
95 | | 3750 3200 6300 3200 |
96 | | Wire Wire Line |
97 | | 6300 3200 7200 3200 |
98 | | Wire Wire Line |
99 | | 3750 3400 4850 3400 |
100 | | Wire Wire Line |
101 | | 4850 3400 4850 3800 |
102 | | Wire Wire Line |
103 | | 8850 3400 5050 3400 |
104 | | Wire Wire Line |
105 | | 5050 3400 5050 2650 |
106 | | Wire Wire Line |
107 | | 5050 2650 1900 2650 |
108 | | Wire Wire Line |
109 | | 1900 2650 1900 3600 |
110 | | Wire Wire Line |
111 | | 1900 3600 2550 3600 |
112 | | NoConn ~ 2550 3200 |
113 | | NoConn ~ 2550 3400 |
114 | | NoConn ~ 2550 4000 |
115 | | Text Label 3950 3600 0 60 ~ 0 |
116 | | BLUE |
117 | | Text Label 3950 3400 0 60 ~ 0 |
118 | | GREEN |
119 | | Text Label 3950 3200 0 60 ~ 0 |
120 | | RED |
121 | | NoConn ~ 3750 3800 |
122 | | NoConn ~ 3750 3700 |
123 | | NoConn ~ 3750 3500 |
124 | | NoConn ~ 3750 3300 |
125 | | NoConn ~ 3750 3100 |
126 | | $Comp |
127 | | L GND #PWR1 |
128 | | U 1 1 4DB3B0C4 |
129 | | P 3950 4200 |
130 | | F 0 "#PWR1" H 3950 4200 30 0001 C CNN |
131 | | F 1 "GND" H 3950 4130 30 0001 C CNN |
132 | | 1 3950 4200 |
133 | | 1 0 0 -1 |
134 | | $EndComp |
135 | | $Comp |
136 | | L GND #PWR4 |
137 | | U 1 1 4DB3B04B |
138 | | P 7000 4800 |
139 | | F 0 "#PWR4" H 7000 4800 30 0001 C CNN |
140 | | F 1 "GND" H 7000 4730 30 0001 C CNN |
141 | | 1 7000 4800 |
142 | | 1 0 0 -1 |
143 | | $EndComp |
144 | | $Comp |
145 | | L GND #PWR3 |
146 | | U 1 1 4DB3B04A |
147 | | P 6650 4800 |
148 | | F 0 "#PWR3" H 6650 4800 30 0001 C CNN |
149 | | F 1 "GND" H 6650 4730 30 0001 C CNN |
150 | | 1 6650 4800 |
151 | | 1 0 0 -1 |
152 | | $EndComp |
153 | | $Comp |
154 | | L GND #PWR2 |
155 | | U 1 1 4DB3B048 |
156 | | P 6300 4800 |
157 | | F 0 "#PWR2" H 6300 4800 30 0001 C CNN |
158 | | F 1 "GND" H 6300 4730 30 0001 C CNN |
159 | | 1 6300 4800 |
160 | | 1 0 0 -1 |
161 | | $EndComp |
162 | | $Comp |
163 | | L GND #PWR5 |
164 | | U 1 1 4DB3AFED |
165 | | P 8650 4300 |
166 | | F 0 "#PWR5" H 8650 4300 30 0001 C CNN |
167 | | F 1 "GND" H 8650 4230 30 0001 C CNN |
168 | | 1 8650 4300 |
169 | | 1 0 0 -1 |
170 | | $EndComp |
171 | | NoConn ~ 8850 3600 |
172 | | NoConn ~ 8850 3500 |
173 | | $Comp |
174 | | L DIODE D1 |
175 | | U 1 1 4DB3AF61 |
176 | | P 6300 4400 |
177 | | F 0 "D1" H 6300 4500 40 0000 C CNN |
178 | | F 1 "1N4148" H 6300 4300 40 0000 C CNN |
179 | | 1 6300 4400 |
180 | | 0 -1 1 0 |
181 | | $EndComp |
182 | | $Comp |
183 | | L DIODE D2 |
184 | | U 1 1 4DB3AF5F |
185 | | P 6650 4400 |
186 | | F 0 "D2" H 6650 4500 40 0000 C CNN |
187 | | F 1 "1N4148" H 6650 4300 40 0000 C CNN |
188 | | 1 6650 4400 |
189 | | 0 -1 1 0 |
190 | | $EndComp |
191 | | $Comp |
192 | | L DIODE D3 |
193 | | U 1 1 4DB3AF5B |
194 | | P 7000 4400 |
195 | | F 0 "D3" H 7000 4500 40 0000 C CNN |
196 | | F 1 "1N4148" H 7000 4300 40 0000 C CNN |
197 | | 1 7000 4400 |
198 | | 0 -1 1 0 |
199 | | $EndComp |
200 | | $Comp |
201 | | L R R3 |
202 | | U 1 1 4DB3AF4D |
203 | | P 7450 4000 |
204 | | F 0 "R3" V 7530 4000 50 0000 C CNN |
205 | | F 1 "1k" V 7450 4000 50 0000 C CNN |
206 | | 1 7450 4000 |
207 | | 0 -1 -1 0 |
208 | | $EndComp |
209 | | $Comp |
210 | | L R R2 |
211 | | U 1 1 4DB3AF4B |
212 | | P 7450 3800 |
213 | | F 0 "R2" V 7530 3800 50 0000 C CNN |
214 | | F 1 "1k" V 7450 3800 50 0000 C CNN |
215 | | 1 7450 3800 |
216 | | 0 -1 -1 0 |
217 | | $EndComp |
218 | | $Comp |
219 | | L R R1 |
220 | | U 1 1 4DB3AF49 |
221 | | P 7450 3200 |
222 | | F 0 "R1" V 7530 3200 50 0000 C CNN |
223 | | F 1 "1k" V 7450 3200 50 0000 C CNN |
224 | | 1 7450 3200 |
225 | | 0 -1 -1 0 |
226 | | $EndComp |
227 | | $Comp |
228 | | L 8:10-CARD P1 |
229 | | U 1 1 4DB3AF38 |
230 | | P 9150 3500 |
231 | | F 0 "P1" H 8950 4050 60 0000 C CNN |
232 | | F 1 "UBB" H 9200 2900 60 0000 C CNN |
233 | | 1 9150 3500 |
234 | | 1 0 0 -1 |
235 | | $EndComp |
236 | | $Comp |
237 | | L VGA J1 |
238 | | U 1 1 4DB3AF2A |
239 | | P 3150 3550 |
240 | | F 0 "J1" H 3350 2850 60 0000 C CNN |
241 | | F 1 "VGA" H 3150 4300 60 0000 C CNN |
242 | | 1 3150 3550 |
243 | | -1 0 0 1 |
244 | | $EndComp |
245 | | $EndSCHEMATC |
video/video.c |
1 | | /* |
2 | | * video.c - Output CGA ? video |
3 | | * |
4 | | * Written 2011 by Werner Almesberger |
5 | | * Copyright 2011 Werner Almesberger |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version. |
11 | | */ |
12 | | |
13 | | /* |
14 | | * WARNING: this program does very nasty things to the Ben and it doesn't |
15 | | * like company. In particular, it resents: |
16 | | * |
17 | | * - the MMC driver - disable it with |
18 | | * echo jz4740-mmc.0 >/sys/bus/platform/drivers/jz4740-mmc/unbind |
19 | | * - the AT86RF230/1 kernel driver - use a kernel that doesn't have it |
20 | | * - anything that accesses the screen - kill GUI, X server, etc. |
21 | | * - the screen blanker - either disable it or make sure the screen stays |
22 | | * dark, e.g., with |
23 | | * echo 1 >/sys/devices/platform/jz4740-fb/graphics/fb0/blank |
24 | | * - probably a fair number of other daemons and things as well - best to |
25 | | * kill them all. |
26 | | */ |
27 | | |
28 | | |
29 | | #include <stdint.h> |
30 | | #include <stdlib.h> |
31 | | #include <stdio.h> |
32 | | #include <unistd.h> |
33 | | #include <string.h> |
34 | | #include <fcntl.h> |
35 | | #include <sys/mman.h> |
36 | | |
37 | | |
38 | | #define DAT0 (1 << 10) |
39 | | #define DAT1 (1 << 11) |
40 | | #define DAT2 (1 << 12) |
41 | | #define DAT3 (1 << 13) |
42 | | #define CMD (1 << 8) |
43 | | #define CLK (1 << 9) |
44 | | |
45 | | #define R DAT2 |
46 | | #define G DAT0 |
47 | | #define B DAT1 |
48 | | #define HSYNC CMD |
49 | | #define VSYNC DAT3 |
50 | | |
51 | | #define TIMER 7 |
52 | | |
53 | | |
54 | | #define PAGE_SIZE 4096 |
55 | | #define SOC_BASE 0x10000000 |
56 | | #define DEFAULT_COUNT (1000*1000) |
57 | | |
58 | | |
59 | | static uint8_t thres = 63; |
60 | | |
61 | | |
62 | | /* ----- Ben hardware ------------------------------------------------------ */ |
63 | | |
64 | | |
65 | | static volatile uint32_t *icmr, *icmsr, *icmcr; |
66 | | static uint32_t old_icmr; |
67 | | |
68 | | static volatile uint32_t *clkgr; |
69 | | static uint32_t old_clkgr; |
70 | | |
71 | | static volatile uint32_t *pdpin, *pddats, *pddatc; |
72 | | static volatile uint32_t *pddirs, *pddirc; |
73 | | |
74 | | static volatile uint32_t *tssr, *tscr; |
75 | | static volatile uint32_t *tesr, *tecr; |
76 | | static volatile uint32_t *tcsr, *tdfr, *tcnt; |
77 | | |
78 | | |
79 | | static void disable_interrupts(void) |
80 | | { |
81 | | /* |
82 | | * @@@ Race condition alert ! If we get interrupted/preempted between |
83 | | * reading ICMR and masking all interrupts, and the code that runs |
84 | | * between these two operations changes ICMR, then we may set an |
85 | | * incorrect mask when restoring interrupts, which may hang the system. |
86 | | */ |
87 | | |
88 | | old_icmr = *icmr; |
89 | | *icmsr = 0xffffffff; |
90 | | } |
91 | | |
92 | | |
93 | | static void enable_interrupts(void) |
94 | | { |
95 | | *icmcr = ~old_icmr; |
96 | | } |
97 | | |
98 | | |
99 | | /* |
100 | | * @@@ Disabling the LCD clock will halng operations that depend on the LCD |
101 | | * subsystem to advance. This includes the screen saver. |
102 | | */ |
103 | | |
104 | | static void disable_lcd(void) |
105 | | { |
106 | | old_clkgr = *clkgr; |
107 | | *clkgr = old_clkgr | 1 << 10; |
108 | | } |
109 | | |
110 | | |
111 | | static void enable_lcd(void) |
112 | | { |
113 | | *clkgr = old_clkgr; |
114 | | } |
115 | | |
116 | | |
117 | | static void get_timer(void) |
118 | | { |
119 | | *tscr = 1 << TIMER; /* enable clock */ |
120 | | *tcsr = 1; /* count at PCLK/1 */ |
121 | | *tdfr = 0xffff; /* count to 0xffff */ |
122 | | *tesr = 1 << TIMER; |
123 | | } |
124 | | |
125 | | |
126 | | static void release_timer(void) |
127 | | { |
128 | | *tecr = 1 << TIMER; |
129 | | *tssr = 1 << TIMER; |
130 | | } |
131 | | |
132 | | |
133 | | static void *map(off_t addr, size_t size) |
134 | | { |
135 | | int fd; |
136 | | void *mem; |
137 | | |
138 | | fd = open("/dev/mem", O_RDWR | O_SYNC); |
139 | | if (fd < 0) { |
140 | | perror("/dev/mem"); |
141 | | exit(1); |
142 | | } |
143 | | mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr); |
144 | | if (mem == MAP_FAILED) { |
145 | | perror("mmap"); |
146 | | exit(1); |
147 | | } |
148 | | |
149 | | return mem; |
150 | | } |
151 | | |
152 | | |
153 | | static void ben_setup(void) |
154 | | { |
155 | | volatile void *base; |
156 | | |
157 | | base = map(SOC_BASE, PAGE_SIZE*3*16); |
158 | | |
159 | | icmr = base+0x1004; |
160 | | icmsr = base+0x1008; |
161 | | icmcr = base+0x100c; |
162 | | |
163 | | clkgr = base+0x20; |
164 | | |
165 | | pdpin = base+0x10300; |
166 | | pddats = base+0x10314; |
167 | | pddatc = base+0x10318; |
168 | | |
169 | | pddirs = base+0x10364; |
170 | | pddirc = base+0x10368; |
171 | | |
172 | | tssr = base+0x202c; |
173 | | tscr = base+0x203c; |
174 | | |
175 | | tesr = base+0x2014; |
176 | | tecr = base+0x2018; |
177 | | |
178 | | tcsr = base+0x204c+0x10*TIMER; |
179 | | tdfr = base+0x2040+0x10*TIMER; |
180 | | tcnt = base+0x2048+0x10*TIMER; |
181 | | |
182 | | /* |
183 | | * Ironically, switching the LCD clock on and off many times only |
184 | | * increases the risk of a hang. Therefore, we leave stop it during |
185 | | * all the measurements and only enable it again at the end. |
186 | | */ |
187 | | disable_lcd(); |
188 | | get_timer(); |
189 | | } |
190 | | |
191 | | |
192 | | static void cleanup(void) |
193 | | { |
194 | | release_timer(); |
195 | | enable_lcd(); |
196 | | } |
197 | | |
198 | | |
199 | | /* ----- Interface --------------------------------------------------------- */ |
200 | | |
201 | | |
202 | | void setup(void) |
203 | | { |
204 | | mlockall(MCL_CURRENT | MCL_FUTURE); |
205 | | ben_setup(); |
206 | | *pddirs = R | G | B | HSYNC | VSYNC; |
207 | | } |
208 | | |
209 | | |
210 | | static uint32_t pick(int set, int bit, uint32_t val) |
211 | | { |
212 | | return set == bit ? val >> 8 : 0; |
213 | | } |
214 | | |
215 | | |
216 | | static uint32_t pattern(int set, int r, int g, int b) |
217 | | { |
218 | | return pick(set, r, R) | pick(set, g, G) | pick(set, b, B); |
219 | | } |
220 | | |
221 | | |
222 | | #define BURST 32 |
223 | | |
224 | | #define PREFETCH_HSYNC 160 |
225 | | #define PREFETCH_HFRONT (160-PREFETCH_HSYNC) |
226 | | #define DELAY_HFRONT 30 |
227 | | #define DELAY_HBACK 40 |
228 | | //#define DELAY_VSYNC 3500 |
229 | | //#define DELAY_VFRONT 56000 |
230 | | //#define DELAY_VBACK 28000 |
231 | | #define DELAY_VFRONT 1500 |
232 | | #define DELAY_LINE 1800 |
233 | | #define DELAY_HSYNC 210 |
234 | | |
235 | | |
236 | | static inline void prefetch(const uint8_t *prefetch, int words) |
237 | | { |
238 | | volatile const uint8_t *p = prefetch; |
239 | | |
240 | | while (p != prefetch+words) { |
241 | | (void) *p; |
242 | | p += BURST; |
243 | | } |
244 | | } |
245 | | |
246 | | |
247 | | static void until(uint16_t cycles) |
248 | | { |
249 | | while ((*tcnt & 0xffff) < cycles); |
250 | | } |
251 | | |
252 | | #define US(us) ((uint16_t) ((us)*112)) |
253 | | |
254 | | static void line(const uint8_t *line, const uint8_t *fetch) |
255 | | { |
256 | | const uint8_t *p = line; |
257 | | //volatile uint8_t pat = R | B | G; |
258 | | /* HSYNC */ |
259 | | *tcnt = 0; |
260 | | *pddatc = HSYNC; |
261 | | // prefetch(fetch, PREFETCH_HSYNC); |
262 | | prefetch(fetch, 160); |
263 | | until(US(3.77)); |
264 | | // *tcnt = 0; |
265 | | *pddats = HSYNC; |
266 | | |
267 | | /* Front porch */ |
268 | | // prefetch(fetch+PREFETCH_HSYNC, PREFETCH_HFRONT); |
269 | | // until(US(3.77+1.79-3.77)); |
270 | | until(US(3.77+1.79)); |
271 | | |
272 | | while (p != line+320) { |
273 | | *pddats = *p++ << 8;//pat; //R | G | B; //*p++; |
274 | | *pddatc = *p++ << 8;//pat;//R | G | B; // *p++; |
275 | | } |
276 | | |
277 | | /* Back porch */ |
278 | | // until(US(31.77-3.77)); |
279 | | until(US(31.77)); |
280 | | until(US(36)); |
281 | | } |
282 | | |
283 | | |
284 | | static void hdelay(int cycles) |
285 | | { |
286 | | while (cycles--) { |
287 | | *tcnt = 0; |
288 | | *pddatc = HSYNC; |
289 | | until(US(3.77)); |
290 | | *pddats = HSYNC; |
291 | | until(US(31.77)); |
292 | | until(US(36)); |
293 | | } |
294 | | } |
295 | | |
296 | | |
297 | | static void frame(const uint8_t *f) |
298 | | { |
299 | | const uint8_t *p; |
300 | | |
301 | | /* VSYNC */ |
302 | | *pddatc = VSYNC; |
303 | | hdelay(2); |
304 | | *pddats = VSYNC; |
305 | | |
306 | | /* Front porch */ |
307 | | *tcnt = 0; |
308 | | *pddatc = HSYNC; |
309 | | // prefetch(f, PREFETCH_HSYNC); |
310 | | until(US(3.77)); |
311 | | // *tcnt = 0; |
312 | | *pddats = HSYNC; |
313 | | |
314 | | // prefetch(f+PREFETCH_HSYNC, PREFETCH_HFRONT); |
315 | | prefetch(f, 160); |
316 | | // until(US(31.77-3.77)); |
317 | | until(US(31.77)); |
318 | | until(US(36)); |
319 | | hdelay(31); |
320 | | |
321 | | for (p = f; p != f+240*320; p += 320) { |
322 | | line(p, p+160); |
323 | | line(p, p+320); |
324 | | } |
325 | | |
326 | | /* Back porch */ |
327 | | hdelay(14); |
328 | | } |
329 | | |
330 | | |
331 | | static void tricolor(uint32_t *f) |
332 | | { |
333 | | int i; |
334 | | |
335 | | for (i = 0; i != 320*240/3; i++) { |
336 | | f[i & ~1] = R; |
337 | | f[i | 1] = G | B; |
338 | | } |
339 | | for (; i != 320*240*2/3; i++) { |
340 | | f[i & ~1] = G; |
341 | | f[i | 1] = R | B; |
342 | | } |
343 | | |
344 | | for (; i != 320*240; i++) { |
345 | | f[i & ~1] = B; |
346 | | f[i | 1] = R | G; |
347 | | } |
348 | | } |
349 | | |
350 | | |
351 | | static void grid(uint8_t *f) |
352 | | { |
353 | | static uint32_t col[8] = { |
354 | | R | G | B, |
355 | | R, |
356 | | R | G, |
357 | | G, |
358 | | G | B, |
359 | | B, |
360 | | R | B, |
361 | | R | G | B, |
362 | | }; |
363 | | int i, x, y; |
364 | | |
365 | | for (i = 0; i != 8; i++) { |
366 | | x = i*40+20; |
367 | | for (y = 0; y != 240; y++) { |
368 | | f[y*320+x] = f[y*320+x+1] = col[i] >> 8; |
369 | | } |
370 | | } |
371 | | } |
372 | | |
373 | | |
374 | | static void grab(uint8_t *f) |
375 | | { |
376 | | uint32_t *fb = map(0x01d00000, 4*320*240); |
377 | | int x, y; |
378 | | uint32_t pix; |
379 | | |
380 | | for (y = 0; y != 240; y++) |
381 | | for (x = 0; x != 320; x++) { |
382 | | pix = *fb++; |
383 | | *f++ = pattern(!(x & 1), |
384 | | ((pix >> 16) & 255) >= thres, |
385 | | ((pix >> 8) & 255) >= thres, |
386 | | (pix & 255) >= thres); |
387 | | } |
388 | | } |
389 | | |
390 | | |
391 | | static void session(int n) |
392 | | { |
393 | | uint8_t f[320*(240+1)]; |
394 | | int i; |
395 | | |
396 | | memset(f, 0, sizeof(f)); |
397 | | grab(f); |
398 | | // grid(f); |
399 | | |
400 | | disable_interrupts(); |
401 | | |
402 | | for (i = 0; i != n; i++) |
403 | | frame(f); |
404 | | |
405 | | enable_interrupts(); |
406 | | } |
407 | | |
408 | | |
409 | | int main(int argc, char **argv) |
410 | | { |
411 | | thres = atoi(argv[2]); |
412 | | setup(); |
413 | | session(atoi(argv[1])); |
414 | | cleanup(); |
415 | | return 0; |
416 | | } |