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