1428d7b3dSmrg/*
2428d7b3dSmrg * tv.5c
3428d7b3dSmrg *
4428d7b3dSmrg * Compute tv encoder subcarrier dda constants
5428d7b3dSmrg *
6428d7b3dSmrg * The TV encoder subcarrier must be set precisely to the
7428d7b3dSmrg * required frequency or the cumulative phase errors will be
8428d7b3dSmrg * quite visible in the output. To accomplish this, the TV encoder
9428d7b3dSmrg * has a complex circuit that takes a fixed clock, generated by the PLL
10428d7b3dSmrg * and generates a precise subcarrier clock from that using the following
11428d7b3dSmrg * formula:
12428d7b3dSmrg *
13428d7b3dSmrg *  subcarrier = pixel_clock * (S1 + (S2 + (S3/Z3)) / Z2) / 4096
14428d7b3dSmrg *
15428d7b3dSmrg * Careful selection of the constants will provide the necessarily
16428d7b3dSmrg * precise clock.
17428d7b3dSmrg *
18428d7b3dSmrg * In the code below, S1 is represented by dda1, S2/Z2 by dda2 and S3/Z3
19428d7b3dSmrg * by dda3.
20428d7b3dSmrg */
21428d7b3dSmrg
22428d7b3dSmrgtypedef struct {
23428d7b3dSmrg    int	step;
24428d7b3dSmrg    int	size;
25428d7b3dSmrg} term_t;
26428d7b3dSmrg
27428d7b3dSmrg/*
28428d7b3dSmrg * Find the approximation closest, but no larger than 'v', where
29428d7b3dSmrg * 0 <= v < 1, and the result denominator must be less than 30000.
30428d7b3dSmrg */
31428d7b3dSmrgterm_t approx (rational v)
32428d7b3dSmrg{
33428d7b3dSmrg    rational	best_dist = 1.0;
34428d7b3dSmrg    term_t	best;
35428d7b3dSmrg
36428d7b3dSmrg    for (int den = 20000; den < 30000; den++)
37428d7b3dSmrg    {
38428d7b3dSmrg	int num = floor (v * den);
39428d7b3dSmrg	term_t	    approx = { step = num, size = den };
40428d7b3dSmrg	rational    dist = v - approx.step/approx.size;
41428d7b3dSmrg	if (dist >= 0 && dist < best_dist)
42428d7b3dSmrg	{
43428d7b3dSmrg	    best_dist = dist;
44428d7b3dSmrg	    best = approx;
45428d7b3dSmrg	}
46428d7b3dSmrg    }
47428d7b3dSmrg    return best;
48428d7b3dSmrg}
49428d7b3dSmrg
50428d7b3dSmrgtypedef struct {
51428d7b3dSmrg    rational	subcarrier;
52428d7b3dSmrg    rational	pixel;
53428d7b3dSmrg    rational	result;
54428d7b3dSmrg    term_t	dda1;
55428d7b3dSmrg    term_t	dda2;
56428d7b3dSmrg    term_t	dda3;
57428d7b3dSmrg} dda;
58428d7b3dSmrg
59428d7b3dSmrg/*
60428d7b3dSmrg * Compute the dda constants for the given pixel clock and
61428d7b3dSmrg * desired subcarrier frequency
62428d7b3dSmrg */
63428d7b3dSmrg
64428d7b3dSmrgdda find_dda (rational pixel, rational subcarrier)
65428d7b3dSmrg{
66428d7b3dSmrg    dda	d;
67428d7b3dSmrg
68428d7b3dSmrg    d.subcarrier = subcarrier;
69428d7b3dSmrg    d.pixel = pixel;
70428d7b3dSmrg    
71428d7b3dSmrg    rational	dda1 = subcarrier / pixel * 4096;
72428d7b3dSmrg    d.dda1 = (term_t) { step = floor (dda1), size = 4096 };
73428d7b3dSmrg    
74428d7b3dSmrg    rational	dda2 = dda1 - d.dda1.step;
75428d7b3dSmrg    d.dda2 = approx (dda2);
76428d7b3dSmrg    
77428d7b3dSmrg    rational	dda3 = dda2 * d.dda2.size - d.dda2.step;
78428d7b3dSmrg    d.dda3 = approx (dda3);
79428d7b3dSmrg
80428d7b3dSmrg    /* Compute the resulting pixel clock to compare */
81428d7b3dSmrg    d.result = d.pixel * (d.dda1.step +
82428d7b3dSmrg			  (d.dda2.step + d.dda3.step/d.dda3.size) /
83428d7b3dSmrg			  d.dda2.size) / d.dda1.size;
84428d7b3dSmrg    return d;
85428d7b3dSmrg}
86428d7b3dSmrg
87428d7b3dSmrg/*
88428d7b3dSmrg * Print out the computed constants
89428d7b3dSmrg */
90428d7b3dSmrgvoid print_dda (dda d)
91428d7b3dSmrg{
92428d7b3dSmrg    printf ("\t/* desired %9.7f actual %9.7f clock %g */\n",
93428d7b3dSmrg	    d.subcarrier, d.result, d.pixel);
94428d7b3dSmrg    printf ("\t.dda1_inc\t= %6d,\n", d.dda1.step);
95428d7b3dSmrg    printf ("\t.dda2_inc\t= %6d,\t.dda2_size\t= %6d,\n",
96428d7b3dSmrg	    d.dda2.step, d.dda2.step != 0 ? d.dda2.size : 0);
97428d7b3dSmrg    printf ("\t.dda3_inc\t= %6d,\t.dda3_size\t= %6d,\n",
98428d7b3dSmrg	    d.dda3.step, d.dda3.step != 0 ? d.dda3.size : 0);
99428d7b3dSmrg}
100428d7b3dSmrg
101428d7b3dSmrg/*
102428d7b3dSmrg * These are all of the required subcarrier frequencies
103428d7b3dSmrg */
104428d7b3dSmrgrational[]    subcarriers = {
105428d7b3dSmrg    /* these are the values we use; for some reason, this generates
106428d7b3dSmrg     * a more stable image (at least for NTSC) */
107428d7b3dSmrg    3.580, 4.434, 3.582, 3.576, 4.430,
108428d7b3dSmrg    
109428d7b3dSmrg    /* these are the values pulled out of the various specs */
110428d7b3dSmrg    3.579545, 4.433618, 3.582056, 3.575611, 4.433618
111428d7b3dSmrg};
112428d7b3dSmrg
113428d7b3dSmrg/*
114428d7b3dSmrg * We fix the pixel clock to a value which the hardware can
115428d7b3dSmrg * generate exactly
116428d7b3dSmrg */
117428d7b3dSmrgrational    pixel = 107.520;
118428d7b3dSmrg
119428d7b3dSmrgvoid main ()
120428d7b3dSmrg{
121428d7b3dSmrg    for (int i = 0; i < dim(subcarriers); i++)
122428d7b3dSmrg    {
123428d7b3dSmrg	dda d = find_dda (pixel, subcarriers[i]);
124428d7b3dSmrg	print_dda (d);
125428d7b3dSmrg    }
126428d7b3dSmrg}
127428d7b3dSmrg
128428d7b3dSmrgmain ();
129