Date: | 2011-05-02 11:11:29 (12 years 10 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | 6d8c8dd951c4e3f43811b09f17de54e1ee3734f0 |
Message: | ubb-vga: use a free-running counter instead of resetting it for each
line Two benefits: 1) We don't accumulate errors from the delay between the timer reset and the deadline preceding it 2) In the future, we may use WAIT to wait for timer expiration, which should cause less bus activity and is should also reduce jitter - regs4740.h (TFR. TFSR, TFCR, TDHR): added more timer registers - ubb-vga.c (until): renamed to "delay" and changed to measure relative to the last deadline - ubb-vga.c (line, hdelay, frame): replaced "until" with "delay" - ubb-vga.c (hdelay, frame, session): reset the timer only once, at the beginning of the session - ubb-vga.c (frame): we didn't wait for the horizontal back porch of the last image line |
Files: |
ubb-vga/regs4740.h (1 diff) ubb-vga/ubb-vga.c (7 diffs) |
Change Details
ubb-vga/regs4740.h | ||
---|---|---|
50 | 50 | #define TSCR _TCU(0x3c) /* Timer STOP clear */ |
51 | 51 | #define TESR _TCU(0x14) /* Timer counter enable set */ |
52 | 52 | #define TECR _TCU(0x18) /* Timer counter enable clear */ |
53 | #define TFR _TCU(0x20) /* Timer flag */ | |
54 | #define TFSR _TCU(0x24) /* Timer flag set */ | |
55 | #define TFCR _TCU(0x28) /* Timer flag clear */ | |
53 | 56 | #define TCSR(n) _TCU(0x4c+0x10*(n)) /* Timer control */ |
54 | 57 | #define TDFR(n) _TCU(0x40+0x10*(n)) /* Timer data full */ |
58 | #define TDHR(n) _TCU(0x44+0x10*(n)) /* Timer data half */ | |
55 | 59 | #define TCNT(n) _TCU(0x48+0x10*(n)) /* Timer counter */ |
56 | 60 | |
57 | 61 | #define MSC_STRPCL _MSC(0x00) /* Start/stop MMC/SD clock */ |
ubb-vga/ubb-vga.c | ||
---|---|---|
233 | 233 | /* ----- Delay logic ------------------------------------------------------- */ |
234 | 234 | |
235 | 235 | |
236 | static void until(uint16_t cycles) | |
236 | static void delay(uint16_t cycles) | |
237 | 237 | { |
238 | while ((TCNT(TIMER) & 0xffff) < cycles); | |
238 | static uint16_t next = 0; | |
239 | ||
240 | next += cycles; | |
241 | TDHR(TIMER) = next; | |
242 | TFCR = 1 << (TIMER+16); | |
243 | while (!(TFR & (1 << (TIMER+16)))); | |
239 | 244 | } |
240 | 245 | |
241 | 246 | |
... | ... | |
292 | 297 | DTA(DMA) = REG_PADDR(MSC_TXFIFO); /* MUST set this each time */ |
293 | 298 | DTC(DMA) = (mode->xres+63) >> 6; |
294 | 299 | |
295 | until(mode->hback_cycles); | |
300 | delay(mode->hback_cycles); | |
296 | 301 | |
297 | 302 | /* HSYNC */ |
298 | 303 | |
... | ... | |
313 | 318 | (1 << 31) | /* no descriptor */ |
314 | 319 | 1; |
315 | 320 | |
316 | until(mode->hback_cycles+mode->hsync_cycles); | |
321 | delay(mode->hsync_cycles); | |
317 | 322 | |
318 | 323 | // MSC_TXFIFO = 0xffffffff; |
319 | 324 | |
... | ... | |
323 | 328 | PDDATS = HSYNC; |
324 | 329 | PDFUNC = CMD; |
325 | 330 | |
326 | until(mode->line_cycles); | |
331 | delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles); | |
327 | 332 | MSC_TXFIFO = 0; |
328 | 333 | if (MSC_STAT & 3) |
329 | 334 | bad++; |
... | ... | |
333 | 338 | static void hdelay(int cycles) |
334 | 339 | { |
335 | 340 | while (cycles--) { |
336 | TCNT(TIMER) = 0; | |
337 | 341 | PDDATC = HSYNC; |
338 | until(mode->hsync_cycles); | |
342 | delay(mode->hsync_cycles); | |
339 | 343 | PDDATS = HSYNC; |
340 | until(mode->line_cycles); | |
344 | delay(mode->line_cycles-mode->hsync_cycles); | |
341 | 345 | } |
342 | 346 | } |
343 | 347 | |
... | ... | |
359 | 363 | * The horizontal back porch of the previous line is handled inside |
360 | 364 | * "line", so we have to wait for less than a full line here. |
361 | 365 | */ |
362 | TCNT(TIMER) = 0; | |
363 | 366 | PDDATC = HSYNC; |
364 | until(mode->hsync_cycles); | |
367 | delay(mode->hsync_cycles); | |
365 | 368 | PDDATS = HSYNC; |
366 | until(mode->line_cycles-mode->hback_cycles); | |
369 | delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles); | |
367 | 370 | |
368 | /* | |
369 | * Note: resetting the timer just before calling "line" isn't enough. | |
370 | * We have t reset it before the loop and right after returning from | |
371 | * "line". | |
372 | */ | |
373 | TCNT(TIMER) = 0; | |
374 | for (p = f; p != f+mode->yres; p++) { | |
371 | for (p = f; p != f+mode->yres; p++) | |
375 | 372 | line(*p); |
376 | TCNT(TIMER) = 0; | |
377 | } | |
373 | ||
374 | delay(mode->hback_cycles); | |
378 | 375 | |
379 | 376 | /* Back porch */ |
380 | 377 | hdelay(mode->vback_lines); |
... | ... | |
401 | 398 | |
402 | 399 | setup_noirq(); |
403 | 400 | |
401 | TCNT(TIMER) = 0; | |
404 | 402 | for (i = 0; !frames || i != frames; i++) { |
405 | 403 | frame(f_phys); |
406 | 404 | if (DTC(DMA)) { |
Branches:
master