103b705cfSriastradh/*
203b705cfSriastradh * tv.5c
303b705cfSriastradh *
403b705cfSriastradh * Compute tv encoder subcarrier dda constants
503b705cfSriastradh *
603b705cfSriastradh * The TV encoder subcarrier must be set precisely to the
703b705cfSriastradh * required frequency or the cumulative phase errors will be
803b705cfSriastradh * quite visible in the output. To accomplish this, the TV encoder
903b705cfSriastradh * has a complex circuit that takes a fixed clock, generated by the PLL
1003b705cfSriastradh * and generates a precise subcarrier clock from that using the following
1103b705cfSriastradh * formula:
1203b705cfSriastradh *
1303b705cfSriastradh *  subcarrier = pixel_clock * (S1 + (S2 + (S3/Z3)) / Z2) / 4096
1403b705cfSriastradh *
1503b705cfSriastradh * Careful selection of the constants will provide the necessarily
1603b705cfSriastradh * precise clock.
1703b705cfSriastradh *
1803b705cfSriastradh * In the code below, S1 is represented by dda1, S2/Z2 by dda2 and S3/Z3
1903b705cfSriastradh * by dda3.
2003b705cfSriastradh */
2103b705cfSriastradh
2203b705cfSriastradhtypedef struct {
2303b705cfSriastradh    int	step;
2403b705cfSriastradh    int	size;
2503b705cfSriastradh} term_t;
2603b705cfSriastradh
2703b705cfSriastradh/*
2803b705cfSriastradh * Find the approximation closest, but no larger than 'v', where
2903b705cfSriastradh * 0 <= v < 1, and the result denominator must be less than 30000.
3003b705cfSriastradh */
3103b705cfSriastradhterm_t approx (rational v)
3203b705cfSriastradh{
3303b705cfSriastradh    rational	best_dist = 1.0;
3403b705cfSriastradh    term_t	best;
3503b705cfSriastradh
3603b705cfSriastradh    for (int den = 20000; den < 30000; den++)
3703b705cfSriastradh    {
3803b705cfSriastradh	int num = floor (v * den);
3903b705cfSriastradh	term_t	    approx = { step = num, size = den };
4003b705cfSriastradh	rational    dist = v - approx.step/approx.size;
4103b705cfSriastradh	if (dist >= 0 && dist < best_dist)
4203b705cfSriastradh	{
4303b705cfSriastradh	    best_dist = dist;
4403b705cfSriastradh	    best = approx;
4503b705cfSriastradh	}
4603b705cfSriastradh    }
4703b705cfSriastradh    return best;
4803b705cfSriastradh}
4903b705cfSriastradh
5003b705cfSriastradhtypedef struct {
5103b705cfSriastradh    rational	subcarrier;
5203b705cfSriastradh    rational	pixel;
5303b705cfSriastradh    rational	result;
5403b705cfSriastradh    term_t	dda1;
5503b705cfSriastradh    term_t	dda2;
5603b705cfSriastradh    term_t	dda3;
5703b705cfSriastradh} dda;
5803b705cfSriastradh
5903b705cfSriastradh/*
6003b705cfSriastradh * Compute the dda constants for the given pixel clock and
6103b705cfSriastradh * desired subcarrier frequency
6203b705cfSriastradh */
6303b705cfSriastradh
6403b705cfSriastradhdda find_dda (rational pixel, rational subcarrier)
6503b705cfSriastradh{
6603b705cfSriastradh    dda	d;
6703b705cfSriastradh
6803b705cfSriastradh    d.subcarrier = subcarrier;
6903b705cfSriastradh    d.pixel = pixel;
7003b705cfSriastradh    
7103b705cfSriastradh    rational	dda1 = subcarrier / pixel * 4096;
7203b705cfSriastradh    d.dda1 = (term_t) { step = floor (dda1), size = 4096 };
7303b705cfSriastradh    
7403b705cfSriastradh    rational	dda2 = dda1 - d.dda1.step;
7503b705cfSriastradh    d.dda2 = approx (dda2);
7603b705cfSriastradh    
7703b705cfSriastradh    rational	dda3 = dda2 * d.dda2.size - d.dda2.step;
7803b705cfSriastradh    d.dda3 = approx (dda3);
7903b705cfSriastradh
8003b705cfSriastradh    /* Compute the resulting pixel clock to compare */
8103b705cfSriastradh    d.result = d.pixel * (d.dda1.step +
8203b705cfSriastradh			  (d.dda2.step + d.dda3.step/d.dda3.size) /
8303b705cfSriastradh			  d.dda2.size) / d.dda1.size;
8403b705cfSriastradh    return d;
8503b705cfSriastradh}
8603b705cfSriastradh
8703b705cfSriastradh/*
8803b705cfSriastradh * Print out the computed constants
8903b705cfSriastradh */
9003b705cfSriastradhvoid print_dda (dda d)
9103b705cfSriastradh{
9203b705cfSriastradh    printf ("\t/* desired %9.7f actual %9.7f clock %g */\n",
9303b705cfSriastradh	    d.subcarrier, d.result, d.pixel);
9403b705cfSriastradh    printf ("\t.dda1_inc\t= %6d,\n", d.dda1.step);
9503b705cfSriastradh    printf ("\t.dda2_inc\t= %6d,\t.dda2_size\t= %6d,\n",
9603b705cfSriastradh	    d.dda2.step, d.dda2.step != 0 ? d.dda2.size : 0);
9703b705cfSriastradh    printf ("\t.dda3_inc\t= %6d,\t.dda3_size\t= %6d,\n",
9803b705cfSriastradh	    d.dda3.step, d.dda3.step != 0 ? d.dda3.size : 0);
9903b705cfSriastradh}
10003b705cfSriastradh
10103b705cfSriastradh/*
10203b705cfSriastradh * These are all of the required subcarrier frequencies
10303b705cfSriastradh */
10403b705cfSriastradhrational[]    subcarriers = {
10503b705cfSriastradh    /* these are the values we use; for some reason, this generates
10603b705cfSriastradh     * a more stable image (at least for NTSC) */
10703b705cfSriastradh    3.580, 4.434, 3.582, 3.576, 4.430,
10803b705cfSriastradh    
10903b705cfSriastradh    /* these are the values pulled out of the various specs */
11003b705cfSriastradh    3.579545, 4.433618, 3.582056, 3.575611, 4.433618
11103b705cfSriastradh};
11203b705cfSriastradh
11303b705cfSriastradh/*
11403b705cfSriastradh * We fix the pixel clock to a value which the hardware can
11503b705cfSriastradh * generate exactly
11603b705cfSriastradh */
11703b705cfSriastradhrational    pixel = 107.520;
11803b705cfSriastradh
11903b705cfSriastradhvoid main ()
12003b705cfSriastradh{
12103b705cfSriastradh    for (int i = 0; i < dim(subcarriers); i++)
12203b705cfSriastradh    {
12303b705cfSriastradh	dda d = find_dda (pixel, subcarriers[i]);
12403b705cfSriastradh	print_dda (d);
12503b705cfSriastradh    }
12603b705cfSriastradh}
12703b705cfSriastradh
12803b705cfSriastradhmain ();
129