1
0
mirror of git://projects.qi-hardware.com/ben-blinkenlights.git synced 2024-11-27 17:05:20 +02:00

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
This commit is contained in:
Werner Almesberger 2011-05-02 06:11:29 -03:00
parent a3cea3573c
commit 6d8c8dd951
2 changed files with 22 additions and 20 deletions

View File

@ -50,8 +50,12 @@
#define TSCR _TCU(0x3c) /* Timer STOP clear */
#define TESR _TCU(0x14) /* Timer counter enable set */
#define TECR _TCU(0x18) /* Timer counter enable clear */
#define TFR _TCU(0x20) /* Timer flag */
#define TFSR _TCU(0x24) /* Timer flag set */
#define TFCR _TCU(0x28) /* Timer flag clear */
#define TCSR(n) _TCU(0x4c+0x10*(n)) /* Timer control */
#define TDFR(n) _TCU(0x40+0x10*(n)) /* Timer data full */
#define TDHR(n) _TCU(0x44+0x10*(n)) /* Timer data half */
#define TCNT(n) _TCU(0x48+0x10*(n)) /* Timer counter */
#define MSC_STRPCL _MSC(0x00) /* Start/stop MMC/SD clock */

View File

@ -233,9 +233,14 @@ static void cleanup(void)
/* ----- Delay logic ------------------------------------------------------- */
static void until(uint16_t cycles)
static void delay(uint16_t cycles)
{
while ((TCNT(TIMER) & 0xffff) < cycles);
static uint16_t next = 0;
next += cycles;
TDHR(TIMER) = next;
TFCR = 1 << (TIMER+16);
while (!(TFR & (1 << (TIMER+16))));
}
@ -292,7 +297,7 @@ static void line(unsigned long line)
DTA(DMA) = REG_PADDR(MSC_TXFIFO); /* MUST set this each time */
DTC(DMA) = (mode->xres+63) >> 6;
until(mode->hback_cycles);
delay(mode->hback_cycles);
/* HSYNC */
@ -313,7 +318,7 @@ static void line(unsigned long line)
(1 << 31) | /* no descriptor */
1;
until(mode->hback_cycles+mode->hsync_cycles);
delay(mode->hsync_cycles);
// MSC_TXFIFO = 0xffffffff;
@ -323,7 +328,7 @@ static void line(unsigned long line)
PDDATS = HSYNC;
PDFUNC = CMD;
until(mode->line_cycles);
delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles);
MSC_TXFIFO = 0;
if (MSC_STAT & 3)
bad++;
@ -333,11 +338,10 @@ static void line(unsigned long line)
static void hdelay(int cycles)
{
while (cycles--) {
TCNT(TIMER) = 0;
PDDATC = HSYNC;
until(mode->hsync_cycles);
delay(mode->hsync_cycles);
PDDATS = HSYNC;
until(mode->line_cycles);
delay(mode->line_cycles-mode->hsync_cycles);
}
}
@ -359,22 +363,15 @@ static void frame(const unsigned long *f)
* The horizontal back porch of the previous line is handled inside
* "line", so we have to wait for less than a full line here.
*/
TCNT(TIMER) = 0;
PDDATC = HSYNC;
until(mode->hsync_cycles);
delay(mode->hsync_cycles);
PDDATS = HSYNC;
until(mode->line_cycles-mode->hback_cycles);
delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles);
/*
* Note: resetting the timer just before calling "line" isn't enough.
* We have t reset it before the loop and right after returning from
* "line".
*/
TCNT(TIMER) = 0;
for (p = f; p != f+mode->yres; p++) {
for (p = f; p != f+mode->yres; p++)
line(*p);
TCNT(TIMER) = 0;
}
delay(mode->hback_cycles);
/* Back porch */
hdelay(mode->vback_lines);
@ -401,6 +398,7 @@ static void session(void (*gen)(void **fb, int xres, int yres), int frames)
setup_noirq();
TCNT(TIMER) = 0;
for (i = 0; !frames || i != frames; i++) {
frame(f_phys);
if (DTC(DMA)) {