diff options
author | Eric Anholt <eric@anholt.net> | 2007-10-18 11:17:38 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2007-10-18 11:29:24 -0700 |
commit | 1f8bf110394cc1df66aae9acf5c818145ae19b52 (patch) | |
tree | 39f44dfec7bf05a91023089a939be4e5b73384c8 /src/scripts | |
parent | 79636b8c776ae024518103c9fa137c8498c21d48 (diff) |
Add some nickle scripts for looking at PLL issues.
While here, move similar nickle scripts under src/scripts/
Diffstat (limited to 'src/scripts')
-rw-r--r-- | src/scripts/clock-graph.5c | 148 | ||||
-rw-r--r-- | src/scripts/clock.5c | 40 | ||||
-rw-r--r-- | src/scripts/fix.5c | 14 | ||||
-rw-r--r-- | src/scripts/tv.5c | 128 |
4 files changed, 330 insertions, 0 deletions
diff --git a/src/scripts/clock-graph.5c b/src/scripts/clock-graph.5c new file mode 100644 index 00000000..98500e1e --- /dev/null +++ b/src/scripts/clock-graph.5c @@ -0,0 +1,148 @@ +autoload Cairo; +import Cairo; +library "examples/sort.5c"; +import Sort; + +int width = 1000, height = 200; + +int min = 0xffffffff; +int max = 0; + +int max_clocks = 1000; +int[4][max_clocks] clocks; +int[4] clock_count = {0...}; + +int[4] p2vals = {5,10,7,14}; + +cairo_t cr = Cairo::new(width, height); + +void calc_p2(int p2i) +{ + int p2 = p2vals[p2i]; + int min_p, max_p; + + clocks[p2i] = (int [max_clocks]){0...}; + + if (p2 == 7 || p2 == 14) { + /* LVDS */ + min_p = 7; + max_p = 98; + } else { + /* SDVO/DAC */ + min_p = 5; + max_p = 80; + } + + for (int m1 = 10; m1 <= 20; m1++) { + for (int m2 = 5; m2 <= 9; m2++) { + for (int n = 3; n <= 8; n++) { + for (int p1 = 1; p1 <= 8; p1++) { + int ref = 96000000; + int m = 5 * (m1 + 2) + (m2 + 2); + int p = p1 * p2; + int vco = floor(ref * m / (n + 2)); + int clock = floor(vco / p); + + if (p < min_p || p > max_p) + continue; + if (m < 70 || m > 120) + continue; + if (m2 > m1) + continue; /* won't happen */ + if (vco < 1400000000 || + vco > 2800000000) + continue; + +/* + printf("clock: %d (%d,%d), %d, " + "(%d,%d)\n", + floor(clock / 1000), + m1, m2, n, p1, p2); +*/ + + clocks[p2i][clock_count[p2i]] = clock; + clock_count[p2i]++; + } + } + } + } +} + +bool sort_p2(poly a, poly b) +{ + return a > b; +} + +int min_rate = 25000 * 1000; +int max_rate = 200000 * 1000; + +real scale_x(real clock) +{ + int min_x = 75, max_x = width - 50; + + real frac = (clock - min_rate) / (max_rate - min_rate); + + return min_x + frac * (max_x - min_x); +} + +for (p2i = 0; p2i < dim(p2vals); p2i++) { + int p2 = p2vals[p2i]; + calc_p2(p2i); + /*qsort(&p2vals[p2i], sort_p2);*/ + + switch (p2) { + case 5: + set_source_rgb(cr, 1,0,0); + break; + case 10: + set_source_rgb(cr, 0,1,0); + break; + case 7: + set_source_rgb(cr, 0,0,1); + break; + case 14: + set_source_rgb(cr, 0,0,0); + break; + } + for (int i = 0; i < clock_count[p2i]; i++) { + int clock = clocks[p2i][i]; + real xpos; + + if (clock < min_rate || clock > max_rate) + continue; + + xpos = scale_x(clock); + move_to(cr, xpos, p2i / (dim(p2vals) + 1) * height); + line_to(cr, xpos, (p2i + 1) / (dim(p2vals) + 1) * height); + stroke(cr); + } + + set_source_rgb(cr, 0, 0, 0); + string p2label = sprintf("p2 = %d", p2); + move_to(cr, 5, (p2i + .5) / (dim(p2vals) + 1) * height + 4); + show_text(cr, p2label); +} + +void label_clock(real clock) { + real center_x = scale_x(clock); + string label = sprintf("%d", floor((clock + 500) / 1000000)); + text_extents_t e = text_extents(cr, label); + real left_x = center_x - e.x_advance / 2; + save(cr); + move_to(cr, left_x, height - 20); + show_text(cr, label); + restore(cr); +} + +label_clock(min_rate); +label_clock(max_rate); +label_clock(140 * 1000 * 1000); +label_clock(115 * 1000 * 1000); +label_clock(100 * 1000 * 1000); +label_clock(82 * 1000 * 1000); + +string xlabel = "Clock in Mhz"; +text_extents_t e = text_extents(cr, xlabel); +move_to(cr, width / 2 - e.x_advance / 2, height - 5); +show_text(cr, xlabel); +sleep(10); diff --git a/src/scripts/clock.5c b/src/scripts/clock.5c new file mode 100644 index 00000000..8ee9d90e --- /dev/null +++ b/src/scripts/clock.5c @@ -0,0 +1,40 @@ +int p2 = 14; +int min_p, max_p; + +if (p2 == 7 || p2 == 14) { + /* LVDS */ + min_p = 7; + max_p = 98; +} else { + /* SDVO/DAC */ + min_p = 5; + max_p = 80; +} + +for (int m1 = 10; m1 <= 20; m1++) { + for (int m2 = 5; m2 <= 9; m2++) { + for (int n = 3; n <= 8; n++) { + for (int p1 = 1; p1 <= 8; p1++) { + int ref = 96000000; + int m = 5 * (m1 + 2) + (m2 + 2); + int p = p1 * p2; + int vco = floor(ref * m / (n + 2)); + int clock = floor(vco / p); + + if (p < min_p || p > max_p) + continue; + if (m < 70 || m > 120) + continue; + if (m2 > m1) + continue; /* won't happen */ + if (vco < 1400000000 || + vco > 2800000000) + continue; + + printf("clock: %d (%d,%d),%d,(%d,%d)\n", + floor(clock / 1000), + m1, m2, n, p1, p2); + } + } + } +} diff --git a/src/scripts/fix.5c b/src/scripts/fix.5c new file mode 100644 index 00000000..b758a433 --- /dev/null +++ b/src/scripts/fix.5c @@ -0,0 +1,14 @@ +/* + * Convert CSC fix point values to floats + */ + +real fixval (int fix) +{ + int exp = fix >> 9; + int mant = fix & ((1 << 9) - 1); + real ret; + if (exp == 0x7) + return 1.0; + ret = (2 ** -exp) * mant / (1 << 9); + return ret; +} diff --git a/src/scripts/tv.5c b/src/scripts/tv.5c new file mode 100644 index 00000000..b4a2ba61 --- /dev/null +++ b/src/scripts/tv.5c @@ -0,0 +1,128 @@ +/* + * tv.5c + * + * Compute tv encoder subcarrier dda constants + * + * The TV encoder subcarrier must be set precisely to the + * required frequency or the cumulative phase errors will be + * quite visible in the output. To accomplish this, the TV encoder + * has a complex circuit that takes a fixed clock, generated by the PLL + * and generates a precise subcarrier clock from that using the following + * formula: + * + * subcarrier = pixel_clock * (S1 + (S2 + (S3/Z3)) / Z2) / 4096 + * + * Careful selection of the constants will provide the necessarily + * precise clock. + * + * In the code below, S1 is represented by dda1, S2/Z2 by dda2 and S3/Z3 + * by dda3. + */ + +typedef struct { + int step; + int size; +} term_t; + +/* + * Find the approximation closest, but no larger than 'v', where + * 0 <= v < 1, and the result denominator must be less than 30000. + */ +term_t approx (rational v) +{ + rational best_dist = 1.0; + term_t best; + + for (int den = 20000; den < 30000; den++) + { + int num = floor (v * den); + term_t approx = { step = num, size = den }; + rational dist = v - approx.step/approx.size; + if (dist >= 0 && dist < best_dist) + { + best_dist = dist; + best = approx; + } + } + return best; +} + +typedef struct { + rational subcarrier; + rational pixel; + rational result; + term_t dda1; + term_t dda2; + term_t dda3; +} dda; + +/* + * Compute the dda constants for the given pixel clock and + * desired subcarrier frequency + */ + +dda find_dda (rational pixel, rational subcarrier) +{ + dda d; + + d.subcarrier = subcarrier; + d.pixel = pixel; + + rational dda1 = subcarrier / pixel * 4096; + d.dda1 = (term_t) { step = floor (dda1), size = 4096 }; + + rational dda2 = dda1 - d.dda1.step; + d.dda2 = approx (dda2); + + rational dda3 = dda2 * d.dda2.size - d.dda2.step; + d.dda3 = approx (dda3); + + /* Compute the resulting pixel clock to compare */ + d.result = d.pixel * (d.dda1.step + + (d.dda2.step + d.dda3.step/d.dda3.size) / + d.dda2.size) / d.dda1.size; + return d; +} + +/* + * Print out the computed constants + */ +void print_dda (dda d) +{ + printf ("\t/* desired %9.7f actual %9.7f clock %g */\n", + d.subcarrier, d.result, d.pixel); + printf ("\t.dda1_inc\t= %6d,\n", d.dda1.step); + printf ("\t.dda2_inc\t= %6d,\t.dda2_size\t= %6d,\n", + d.dda2.step, d.dda2.step != 0 ? d.dda2.size : 0); + printf ("\t.dda3_inc\t= %6d,\t.dda3_size\t= %6d,\n", + d.dda3.step, d.dda3.step != 0 ? d.dda3.size : 0); +} + +/* + * These are all of the required subcarrier frequencies + */ +rational[] subcarriers = { + /* these are the values we use; for some reason, this generates + * a more stable image (at least for NTSC) */ + 3.580, 4.434, 3.582, 3.576, 4.430, + + /* these are the values pulled out of the various specs */ + 3.579545, 4.433618, 3.582056, 3.575611, 4.433618 +}; + +/* + * We fix the pixel clock to a value which the hardware can + * generate exactly + */ +rational pixel = 107.520; + +void main () +{ + for (int i = 0; i < dim(subcarriers); i++) + { + dda d = find_dda (pixel, subcarriers[i]); + print_dda (d); + } +} + +main (); |