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