Skip to content

Commit 1539249

Browse files
njhollinghurstpelwell
authored andcommitted
piolib/examples: dpi_csync: Restore support for Equalizing Pulses.
Add support for equalizing pulses when generating CSync for 625/25i and 525/30i TV standards only (distinguished by VSW parameter). Unlike an older version of this example, we no longer require HSync to be a square-wave, or assume fixed ratios between pulse widths. Helper->CSync latency is now 2.5 or 3.0 scanlines. Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent 61e4bec commit 1539249

File tree

1 file changed

+134
-7
lines changed

1 file changed

+134
-7
lines changed

piolib/examples/dpi_csync.c

+134-7
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,30 @@ static void usage(const char * progname)
3737
fprintf(stderr, "\t-o <goio> Select output GPIO pin number. Default 1\n");
3838
fprintf(stderr, "\t-s <us> Set HSync width in microseconds. Default 4.7\n");
3939
fprintf(stderr, "\t-t <us> Set line period in microseconds. Default 64.0\n");
40-
fprintf(stderr, "\t-w <halflines> Set VSync in half-lines when interlaced. Default 6\n");
40+
fprintf(stderr, "\t-e <us> Set EQ pulse width when interlaced. Default 0.0\n");
41+
fprintf(stderr, "\t-w <halflines> Set VSW in half-lines when interlaced. Default 6\n");
4142
fprintf(stderr, "\t-i | --interlace Generate serrated CSync for an interlaced mode\n");
42-
fprintf(stderr, "\t-p | --pal Equivalent to -i -s 4.7 -t 64.0 -w 5\n");
43-
fprintf(stderr, "\t-n | --ntsc Equivalent to -i -s 4.7 -t 63.56 -w 6\n");
43+
fprintf(stderr, "\t-p | --pal Equivalent to -i -s 4.7 -t 64.0 -e 2.35 -w 5\n");
44+
fprintf(stderr, "\t-n | --ntsc Equivalent to -i -s 4.7 -t 63.56 -e 2.3 -w 6\n");
4445
}
4546

4647
unsigned int opt_hpos = 0;
4748
unsigned int opt_vpos = 0;
4849
unsigned int opt_cpos = 0;
4950
unsigned int opt_gpio = 1;
5051
unsigned int opt_ilace = 0;
52+
unsigned int opt_vsw = 6;
5153
double opt_hsw = 4.7;
5254
double opt_period = 64.0;
53-
double opt_vsw = 6;
55+
double opt_eqp = 0.0;
5456

5557
static void setpal()
5658
{
5759
opt_ilace = 1;
5860
opt_hsw = 4.7;
5961
opt_period = 64.0;
6062
opt_vsw = 5;
63+
opt_eqp = 2.35;
6164
}
6265

6366
static void setntsc()
@@ -66,6 +69,7 @@ static void setntsc()
6669
opt_hsw = 4.7;
6770
opt_period = 63.56;
6871
opt_vsw = 6;
72+
opt_eqp = 2.3;
6973
}
7074

7175
static int getopts(int argc, const char **argv)
@@ -109,6 +113,11 @@ static int getopts(int argc, const char **argv)
109113
argv++;
110114
opt_period = atof(argv[1]);
111115
break;
116+
case 'e':
117+
if (--argc < 2) return -1;
118+
argv++;
119+
opt_eqp = atof(argv[1]);
120+
break;
112121
case 'w':
113122
if (--argc < 2) return -1;
114123
argv++;
@@ -335,17 +344,135 @@ static int setup_pio_for_csync_ilace(PIO pio)
335344
return 0;
336345
}
337346

347+
/*
348+
* COMPOSITE SYNC (TV-STYLE) for 625/25i [-w 5] and 525/30i [-w 6] only.
349+
*
350+
* DPI VSYNC (GPIO2) must be a modified signal which is always active-low.
351+
* It should go low for 1 or 2 scanlines, VSyncWidth/2.0 or (VSyncWidth+1)/2.0
352+
* lines before Vsync-start, i.e. just after the last full active TV line
353+
* (noting that RP1 DPI does not generate half-lines).
354+
*
355+
* This will push the image up by 1 line compared to customary DRM timings in
356+
* "PAL" mode, or 2 lines in "NTSC" mode (which is arguably too low anyway),
357+
* but avoids a collision between an active line and an equalizing pulse.
358+
*
359+
* Another wrinkle is that when the first equalizing pulse aligns with HSync,
360+
* it becomes a normal-width sync pulse. This was a deliberate simplification.
361+
* It is unlikely that any TV will notice or care.
362+
*/
363+
364+
static int setup_pio_for_csync_tv(PIO pio)
365+
{
366+
static const int wrap_target = 6;
367+
static const int wrap = 27;
368+
unsigned short instructions[] = { /* This is mutable */
369+
0x3703, // 0: wait 0 gpio, 3 side 1 [7] ; while (HSync) delay;
370+
0x3083, // 1: wait 1 gpio, 3 side 1 ; do { @HSync
371+
0xa7e6, // 2: mov osr, isr side 0 [7] ; CSYNC: rewind sequence
372+
0x2003, // 3: wait 0 gpio, 3 side 0 ; CSYNC: HSync->CSync
373+
0xb7e6, // 4: mov osr, isr side 1 [7] ; delay
374+
0x10c1, // 5: jmp pin, 1 side 1 ; } while (VSync)
375+
// .wrap_target ; while (true) {
376+
0xd042, // 6: irq clear 2 side 1 ; flush stale IRQ
377+
0xd043, // 7: irq clear 3 side 1 ; flush stale IRQ
378+
0xb022, // 8: mov x, y side 1 ; X = EQWidth - 3
379+
0x30c2, // 9: wait 1 irq, 2 side 1 ; @midline
380+
0x004a, // 10: jmp x--, 10 side 0 ; CSYNC: while (x--) ;
381+
0x6021, // 11: out x, 1 side 0 ; CSYNC: next pulse broad?
382+
0x002e, // 12: jmp !x, 14 side 0 ; CSYNC: if (broad)
383+
0x20c3, // 13: wait 1 irq, 3 side 0 ; CSYNC: @BroadRight
384+
0x7021, // 14: out x, 1 side 1 ; sequence not finished?
385+
0x1020, // 15: jmp !x, 0 side 1 ; if (finished) break
386+
0xd041, // 16: irq clear 1 side 1 ; flush stale IRQ
387+
0xb022, // 17: mov x, y side 1 ; X = EQWidth - 3
388+
0x3083, // 18: wait 1 gpio, 3 side 1 ; @HSync
389+
0x0053, // 19: jmp x--, 19 side 0 ; CSYNC: while (x--) ;
390+
0x6021, // 20: out x, 1 side 0 ; CSYNC: next pulse broad?
391+
0x0037, // 21: jmp !x, 23 side 0 ; CSYNC: if (broad)
392+
0x20c1, // 22: wait 1 irq, 1 side 0 ; CSYNC: @BroadLeft
393+
0x7021, // 23: out x, 1 side 1 ; sequence not finished?
394+
0x1020, // 24: jmp !x, 0 side 1 ; if (finished) break
395+
0x10c6, // 25: jmp pin, 6 side 1 ; if (VSync) continue
396+
0xb0e6, // 26: mov osr, isr side 1 ; rewind sequence
397+
0x7022, // 27: out x, 2 side 1 ; skip 2 bits
398+
// .wrap ; }
399+
};
400+
struct pio_program prog = {
401+
.instructions = instructions,
402+
.length = sizeof(instructions)/sizeof(instructions[0]),
403+
.origin = -1
404+
};
405+
pio_sm_config cfg = pio_get_default_sm_config();
406+
unsigned int i, offset;
407+
unsigned int tc[3];
408+
unsigned int sm = 0;
409+
410+
pio_claim_sm_mask(pio, 1);
411+
412+
/* Compute mid-line and broad-sync time constants and start the 3 "timer" SMs */
413+
tc[1] = 5.0e-7 * opt_period * (double)clock_get_hz(clk_sys);
414+
tc[0] = tc[1] - 1.0e-6 * opt_hsw * (double)clock_get_hz(clk_sys);
415+
tc[2] = tc[1] + tc[0];
416+
if (start_timers(pio, opt_hpos ? 0 : 1, tc) < 0) {
417+
pio_sm_unclaim(pio, sm);
418+
return -1;
419+
}
420+
421+
/* Adapt program code according to CSync polarity; configure program */
422+
pio_sm_set_enabled(pio, sm, false);
423+
for (i = 0; i < prog.length; i++) {
424+
if (opt_cpos)
425+
instructions[i] ^= 0x1000;
426+
if (!opt_hpos && (instructions[i] & 0xe07f) == 0x2003)
427+
instructions[i] ^= 0x0080;
428+
}
429+
offset = pio_add_program(pio, &prog);
430+
if (offset == PIO_ORIGIN_ANY)
431+
return -1;
432+
433+
/* Configure pins and SM */
434+
sm_config_set_wrap(&cfg, offset + wrap_target, offset + wrap);
435+
sm_config_set_sideset(&cfg, 1, false, false);
436+
sm_config_set_sideset_pins(&cfg, opt_gpio);
437+
pio_gpio_init(pio, opt_gpio);
438+
sm_config_set_jmp_pin(&cfg, 2); /* DPI VSync "helper" signal is GPIO 2 */
439+
pio_sm_init(pio, sm, offset, &cfg);
440+
pio_sm_set_consecutive_pindirs(pio, sm, opt_gpio, 1, true);
441+
442+
/* Load parameters (Vsync pattern; EQ pulse width) into ISR and Y */
443+
tc[0] = (unsigned)(1.0e-6 * opt_eqp * (double) clock_get_hz(clk_sys));
444+
pio_sm_put(pio, sm, (opt_vsw <= 5) ? 0x02ABFFAA : 0xAABFFEAA);
445+
pio_sm_put(pio, sm, tc[0] - 3);
446+
pio_sm_exec(pio, sm, pio_encode_pull(false, false));
447+
pio_sm_exec(pio, sm, pio_encode_out(pio_y, 32));
448+
pio_sm_exec(pio, sm, pio_encode_in(pio_y, 32));
449+
pio_sm_exec(pio, sm, pio_encode_pull(false, false));
450+
pio_sm_exec(pio, sm, pio_encode_out(pio_y, 32));
451+
pio_sm_set_enabled(pio, sm, true);
452+
453+
/* Start the SM */
454+
pio_sm_set_enabled(pio, sm, true);
455+
456+
return 0;
457+
}
458+
338459
int main(int argc, const char **argv)
339460
{
461+
int r = 0;
462+
340463
if (getopts(argc, argv)) {
341464
const char * progname = (argc > 0 && argv[0]) ? argv[0] : "dpi_csync";
342465
usage(progname);
343466
return 1;
344467
}
345468

346-
int r = opt_ilace ?
347-
setup_pio_for_csync_ilace(pio0) :
348-
setup_pio_for_csync_prog(pio0);
469+
if (!opt_ilace)
470+
r = setup_pio_for_csync_prog(pio0);
471+
else if (opt_eqp <= 0 || opt_vsw < 5 || opt_vsw > 6)
472+
r = setup_pio_for_csync_ilace(pio0);
473+
else
474+
r = setup_pio_for_csync_tv(pio0);
475+
349476
if (r) {
350477
fprintf(stderr, "PIO setup failed\n");
351478
return 1;

0 commit comments

Comments
 (0)