1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#!/usr/bin/env nickle
/*
* Given a main clock frequency,
* compute USART clock freq and a table
* of USART config parameters for our target baud rates
*/
real main_clock = 0;
real usart_clock = 0;
real[] baud_rates = { 4800, 9600, 19200, 57600, 115200 };
void
compute_baud_rate(real rate) {
int divaddval;
int mulval;
real dl_est = usart_clock / (16 * rate);
if (dl_est == floor(dl_est)) {
divaddval = 0;
mulval = 1;
} else {
if (false) {
/* This is how the docs suggest doing it; this
* generates a rate which is reasonably close
*/
real fr_est = 1.5;
/* Compute fractional estimate */
do {
dl_est = floor(usart_clock / (16 * rate * fr_est) + 0.5);
fr_est = usart_clock / (16 * rate * dl_est);
} while (fr_est <= 1.1 || 1.9 <= fr_est);
/* Given fractional estimate, compute divaddval/mulvals that work best */
real best_dist = 1000;
for (int tmp_divaddval = 1; tmp_divaddval < 15; tmp_divaddval++) {
for (int tmp_mulval = 1; tmp_mulval < 16; tmp_mulval++) {
real fr = 1 + tmp_divaddval / tmp_mulval;
real dist = abs(fr - fr_est);
if (dist < best_dist) {
divaddval = tmp_divaddval;
mulval = tmp_mulval;
best_dist = dist;
}
}
}
} else {
/* This exhaustively searches for the best match */
real my_best_dist = 1e20;
int my_best_dl;
int my_best_divaddval;
int my_best_mulval;
for (int my_dl = 1; my_dl < 1024; my_dl++) {
for (int my_mulval = 1; my_mulval < 16; my_mulval++) {
for (int my_divaddval = 0; my_divaddval < my_mulval; my_divaddval++) {
real my_rate = usart_clock / ((16 * my_dl) * (1 + my_divaddval/my_mulval));
real my_dist = abs(rate - my_rate);
if (my_dist == 0 && my_divaddval == 0) {
my_dist = -1;
}
if (my_dist < my_best_dist) {
my_best_dl = my_dl;
my_best_divaddval = my_divaddval;
my_best_mulval = my_mulval;
my_best_dist = my_dist;
}
}
}
}
dl_est = my_best_dl;
divaddval = my_best_divaddval;
mulval = my_best_mulval;
}
}
int dl = floor (dl_est);
real actual = usart_clock / ((16 * dl) * (1 + divaddval/mulval));
printf("\t[AO_SERIAL_SPEED_%d] = { /* actual = %8.2f */\n", floor(rate), actual);
printf("\t\t.dl = %d,\n", dl);
printf("\t\t.divaddval = %d,\n", divaddval);
printf("\t\t.mulval = %d\n", mulval);
printf("\t},\n");
}
void
main() {
if (dim(argv) < 2) {
printf ("usage: %s <main-clock>\n", argv[0]);
exit(1);
}
main_clock = string_to_real(argv[1]);
for (int div = 0; div < 4; div++) {
if (main_clock / (1 << div) <= 12000000) {
usart_clock = main_clock / (1 << div);
break;
}
}
if (usart_clock == 0) {
printf ("can't get usart clock in range\n");
exit(1);
}
printf ("#define AO_LPC_USARTCLK %d\n\n", floor(usart_clock));
printf("static const struct {\n");
printf("\tuint16_t dl;\n");
printf("\tuint8_t divaddval;\n");
printf("\tuint8_t mulval;\n");
printf("} ao_usart_speeds[] = {\n");
for (int i = 0; i < dim(baud_rates); i++) {
compute_baud_rate(baud_rates[i]);
}
printf ("};\n");
}
main();
|