1/*
2 * tv.5c
3 *
4 * Compute tv encoder subcarrier dda constants
5 *
6 * The TV encoder subcarrier must be set precisely to the
7 * required frequency or the cumulative phase errors will be
8 * quite visible in the output. To accomplish this, the TV encoder
9 * has a complex circuit that takes a fixed clock, generated by the PLL
10 * and generates a precise subcarrier clock from that using the following
11 * formula:
12 *
13 *  subcarrier = pixel_clock * (S1 + (S2 + (S3/Z3)) / Z2) / 4096
14 *
15 * Careful selection of the constants will provide the necessarily
16 * precise clock.
17 *
18 * In the code below, S1 is represented by dda1, S2/Z2 by dda2 and S3/Z3
19 * by dda3.
20 */
21
22typedef struct {
23    int	step;
24    int	size;
25} term_t;
26
27/*
28 * Find the approximation closest, but no larger than 'v', where
29 * 0 <= v < 1, and the result denominator must be less than 30000.
30 */
31term_t approx (rational v)
32{
33    rational	best_dist = 1.0;
34    term_t	best;
35
36    for (int den = 20000; den < 30000; den++)
37    {
38	int num = floor (v * den);
39	term_t	    approx = { step = num, size = den };
40	rational    dist = v - approx.step/approx.size;
41	if (dist >= 0 && dist < best_dist)
42	{
43	    best_dist = dist;
44	    best = approx;
45	}
46    }
47    return best;
48}
49
50typedef struct {
51    rational	subcarrier;
52    rational	pixel;
53    rational	result;
54    term_t	dda1;
55    term_t	dda2;
56    term_t	dda3;
57} dda;
58
59/*
60 * Compute the dda constants for the given pixel clock and
61 * desired subcarrier frequency
62 */
63
64dda find_dda (rational pixel, rational subcarrier)
65{
66    dda	d;
67
68    d.subcarrier = subcarrier;
69    d.pixel = pixel;
70    
71    rational	dda1 = subcarrier / pixel * 4096;
72    d.dda1 = (term_t) { step = floor (dda1), size = 4096 };
73    
74    rational	dda2 = dda1 - d.dda1.step;
75    d.dda2 = approx (dda2);
76    
77    rational	dda3 = dda2 * d.dda2.size - d.dda2.step;
78    d.dda3 = approx (dda3);
79
80    /* Compute the resulting pixel clock to compare */
81    d.result = d.pixel * (d.dda1.step +
82			  (d.dda2.step + d.dda3.step/d.dda3.size) /
83			  d.dda2.size) / d.dda1.size;
84    return d;
85}
86
87/*
88 * Print out the computed constants
89 */
90void print_dda (dda d)
91{
92    printf ("\t/* desired %9.7f actual %9.7f clock %g */\n",
93	    d.subcarrier, d.result, d.pixel);
94    printf ("\t.dda1_inc\t= %6d,\n", d.dda1.step);
95    printf ("\t.dda2_inc\t= %6d,\t.dda2_size\t= %6d,\n",
96	    d.dda2.step, d.dda2.step != 0 ? d.dda2.size : 0);
97    printf ("\t.dda3_inc\t= %6d,\t.dda3_size\t= %6d,\n",
98	    d.dda3.step, d.dda3.step != 0 ? d.dda3.size : 0);
99}
100
101/*
102 * These are all of the required subcarrier frequencies
103 */
104rational[]    subcarriers = {
105    /* these are the values we use; for some reason, this generates
106     * a more stable image (at least for NTSC) */
107    3.580, 4.434, 3.582, 3.576, 4.430,
108    
109    /* these are the values pulled out of the various specs */
110    3.579545, 4.433618, 3.582056, 3.575611, 4.433618
111};
112
113/*
114 * We fix the pixel clock to a value which the hardware can
115 * generate exactly
116 */
117rational    pixel = 107.520;
118
119void main ()
120{
121    for (int i = 0; i < dim(subcarriers); i++)
122    {
123	dda d = find_dda (pixel, subcarriers[i]);
124	print_dda (d);
125    }
126}
127
128main ();
129