1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/mman.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <fcntl.h>
7 #include <assert.h>
8
9 #include "peekpoke.h"
10 #include "ep93xx_adc.h"
11
12 #define DATA_PAGE 0x12C00000
13 #define CALIB_LOC 2027 //location of calibration values
14 #define NUM_SAMPLES 5
15 #define NUM_CHANNELS 4
16
17 /* globals */
18 static unsigned long adc_page, syscon_page;
19 char *dr_page;
20
21 /*Calculate the adc value corresponding to 0V*/
22 //val1 is the ADC val corresponding to 0.833V
23 //val2 is the ADC val corresponding to 2.5V
calcZeroVal(int val1,int val2)24 int calcZeroVal(int val1, int val2)
25 {
26 val2 += 0x10000;
27 return (int)(val1 - (((val2 - val1) / (2.5 - 0.833)) * 0.833));
28 }
29
30
31 //return value of 1 indicates the board has no calibration values
32 //return value of 0 indicates the board has calibration values
read_calibration(int buf[NUM_CHANNELS][2])33 int read_calibration(int buf[NUM_CHANNELS][2])
34 {
35 int i, j, k = 0;
36 unsigned short cal[NUM_CHANNELS * 2];
37 // read 16 calibration bytes into buffer
38 FILE *f = fopen("/etc/ADC-calibration.dat", "r");
39
40 if (!f) { goto empty_calibration; }
41
42 printf("Non-virgin board detected, evaluating stored "
43 "calibration values\n");
44 printf("Stored Calibration values [");
45
46 if (fread(cal, NUM_CHANNELS * 4, 1, f) == 1)
47 {
48 fclose(f);
49
50 for (j = 0; j < 2; j++)
51 for (i = 0; i < NUM_CHANNELS; i++)
52 {
53 printf("0x%x", cal[k]);
54 buf[i][j] = cal[k];
55 k++;
56
57 if (k < NUM_CHANNELS * 2)
58 {
59 printf(", ");
60 }
61
62 }
63
64 printf("]\n");
65 return 1;
66 }
67
68 empty_calibration:
69
70 printf("/etc/ADC-calibration.dat not found or it's not readable\n");
71
72 fclose(f);
73
74 return 0;
75 }
76
write_calibration(int cal[NUM_CHANNELS][2])77 void write_calibration(int cal[NUM_CHANNELS][2])
78 {
79 unsigned short buf[16];
80 int i, j, k = 0;
81 FILE *f = fopen("/etc/ADC-calibration.dat", "w");
82
83 //Convert 32 bit vals to 16 bit vals
84 for (j = 0; j < 2; j++)
85 for (i = 0; i < NUM_CHANNELS; i++)
86 {
87 buf[k] = (unsigned short)cal[i][j];
88 k++;
89
90 }
91
92 if (!f) { goto unwrite_calibration; }
93
94 if (fwrite(buf, NUM_CHANNELS * 4, 1, f) == 1) { return; }
95
96 unwrite_calibration:
97
98 printf("Problem writing /etc/ADC-calibration.dat: %m\n");
99 }
100
erase_calibration()101 static void erase_calibration()
102 {
103 printf("Erasing calibration values...\n");
104 unlink("/etc/ADC-calibration.dat");
105 }
106
check_calibration(int cal[NUM_CHANNELS][2],int stored_cal[NUM_CHANNELS][2],int state)107 int check_calibration(int cal[NUM_CHANNELS][2],
108 int stored_cal[NUM_CHANNELS][2], int state)
109 {
110 double pcnt_diff;
111 int i, j, erase_cal = 0;
112 int failure = 0;
113
114 if (state == 0) //no calibration values
115 {
116 printf("Virgin board detected...\n");
117
118 for (j = 0; j < 2; j++)
119 {
120
121 for (i = 0; i < NUM_CHANNELS; i++)
122 {
123
124 if (j == 0)
125 pcnt_diff = (((double)abs(0xa000 -
126 cal[i][j])) / 0xa000) * 100;
127 else
128 pcnt_diff = (((double)abs(0x3300 -
129 cal[i][j])) / 0x3300) * 100;
130
131 if (pcnt_diff > 10)
132 {
133 printf("Calculated calibration "
134 "values out of range...\n");
135
136 exit(-1);
137 }
138
139 }
140 }
141
142 write_calibration(cal);
143
144 }
145 else //calibration values read
146 {
147
148 for (j = 0; j < 2; j++)
149 {
150 for (i = 0; i < NUM_CHANNELS; i++)
151 {
152
153 pcnt_diff = (((double)abs(stored_cal[i][j] -
154 cal[i][j])) / stored_cal[i][j])
155 * 100;
156
157 if (pcnt_diff > 0.25)
158 {
159 if (!failure)
160 {
161 printf("Calibration values out"
162 "of range\n");
163 failure = 1;
164 erase_cal = 1;
165 }
166
167 printf("\tChannel %d: %3.3f%%\n", i
168 , pcnt_diff);
169 }
170 }
171 }
172 }
173
174 if (erase_cal) { erase_calibration(); }
175
176 if (failure) { return 0; }
177
178 return 1;
179 }
180
setDR(char * x,int n,int val)181 void setDR(char *x, int n, int val)
182 {
183 if (n < 0 || n > 8)
184 {
185 return;
186 }
187
188 x[0] = (x[0] & ~(1 << n)) | (val ? (1 << n) : 0);
189 }
190
setD(char * x,int n,int val)191 void setD(char *x, int n, int val)
192 {
193 if (n < 0 || n > 8)
194 {
195 return;
196 }
197
198 x[2] = (x[2] & ~(1 << n)) | (val ? (1 << n) : 0);
199 }
200
get_volts(int val,int zero,int range)201 double get_volts(int val, int zero, int range)
202 {
203 if (val <= 0x7000)
204 {
205 val = val + 0x10000;
206 }
207
208 val = val - zero;
209
210 return ((double)val * 3.3) / range;
211 }
212
calc_calibration(int calibration[NUM_CHANNELS][2],int adc_result_1[NUM_CHANNELS][NUM_SAMPLES],int adc_result_2[NUM_CHANNELS][NUM_SAMPLES])213 void calc_calibration(int calibration[NUM_CHANNELS][2],
214 int adc_result_1[NUM_CHANNELS][NUM_SAMPLES],
215 int adc_result_2[NUM_CHANNELS][NUM_SAMPLES])
216 {
217 int i, j;
218
219 /* zero out our calibration values */
220 for (i = 0; i < NUM_CHANNELS; i++)
221 for (j = 0; j < 2; j++)
222 {
223 calibration[i][j] = 0;
224 }
225
226 //convert 0.833V vals to 0V vals
227 for (i = 0; i < NUM_CHANNELS; i++)
228 {
229 for (j = 0; j < NUM_SAMPLES; j++)
230 {
231 if (i % 2) //odd channels
232 adc_result_1[i][j] =
233 calcZeroVal(adc_result_1[i][j],
234 adc_result_1[0][j]);
235 else
236 adc_result_2[i][j] =
237 calcZeroVal(adc_result_2[i][j],
238 adc_result_2[1][j]);
239 }
240 }
241
242 //sum the readings
243 for (i = 0; i < NUM_CHANNELS; i++)
244 {
245 for (j = 0; j < NUM_SAMPLES; j++)
246 {
247 if (i % 2 == 0)
248 {
249 //0.833 volt values
250 calibration[i][0] = adc_result_2[i][j]
251 + calibration[i][0];
252 //2.5 volt values
253 calibration[i][1] = adc_result_1[i][j]
254 + calibration[i][1];
255 }
256 else
257 {
258 //0.833 volt values
259 calibration[i][0] = adc_result_1[i][j]
260 + calibration[i][0];
261 //2.5 volt values
262 calibration[i][1] = adc_result_2[i][j]
263 + calibration[i][1];
264 }
265 }
266 }
267
268 printf("Calculated Calibration values [");
269
270 for (j = 0; j < 2; j++)
271 {
272 for (i = 0; i < NUM_CHANNELS; i++)
273 {
274 calibration[i][j] = (calibration[i][j] / NUM_SAMPLES);
275
276 printf("0x%x", calibration[i][j]);
277
278 if ((i == NUM_CHANNELS - 1) && (j == 1))
279 {
280 printf("]\n");
281 }
282 else
283 {
284 printf(", ");
285 }
286 }
287 }
288 }
289
290 /************************************************************************
291 *DESCRIPTION: Read the EP93xx onboard ADC. Discard the first
292 *two samples then save the next NUM_SAMPLES.
293 ***********************************************************************/
read_7xxx_adc(int adc_result[NUM_CHANNELS][NUM_SAMPLES])294 static void read_7xxx_adc(int adc_result[NUM_CHANNELS][NUM_SAMPLES])
295 {
296 int i, j, cur_ch;
297
298 for (i = 0; i < NUM_CHANNELS; i++)
299 {
300 switch (i)
301 {
302 case 0:
303 cur_ch = ADC_CH0;
304 break;
305
306 case 1:
307 cur_ch = ADC_CH1;
308 break;
309
310 case 2:
311 cur_ch = ADC_CH2;
312 break;
313
314 case 3:
315 cur_ch = ADC_CH3;
316 break;
317
318 case 4:
319 cur_ch = ADC_CH4;
320 break;
321
322 }
323
324 //discard first two samples
325 read_channel(adc_page, cur_ch);
326 read_channel(adc_page, cur_ch);
327
328 //read more samples
329 for (j = 0; j < NUM_SAMPLES; j++)
330 {
331 hl_usleep(10000);
332 adc_result[i][j] = read_channel(adc_page, cur_ch);
333 }
334 }
335 }
336
test_ADC(int calibration[NUM_CHANNELS][2])337 int test_ADC(int calibration[NUM_CHANNELS][2])
338 {
339 int adc_result_1[NUM_CHANNELS][NUM_SAMPLES];
340 int adc_result_2[NUM_CHANNELS][NUM_SAMPLES];
341 int i, j, return_val;
342 int failure = 0;
343 double voltage;
344
345 setD(dr_page, 0, 1); //ADC1 = ADC3 = 0.833V
346 setD(dr_page, 2, 1); //ADC0 = ADC2 = 2.5V
347 read_7xxx_adc(adc_result_1);
348
349 setD(dr_page, 0, 0); //ADC1 = ADC3 = 2.5V
350 setD(dr_page, 2, 1); //ADC0 = ADC2 = 0.833V
351 read_7xxx_adc(adc_result_2);
352
353 //verify results are within range
354 for (i = 0; i < NUM_CHANNELS; i++)
355 {
356 for (j = 0; j < NUM_SAMPLES; j++)
357 {
358 //use the datasheet values
359 voltage = get_volts(adc_result_1[i][j], 0x9E58, 0xC350);
360
361 //even channels 2.5V(+-150mV)
362 if (i % 2 == 0 &&
363 (voltage < 2.35 || voltage > 2.65))
364 {
365 if (!failure)
366 {
367 failure = 1;
368 printf("EP93XX ADC out of range\n");
369 }
370
371 printf("\tChannel %d: %3.3fV"
372 "(expected 2.5V +- 150mV)\n", i, voltage);
373 //odd channels 0.833(+-50mV)
374 }
375 else if (i % 2 == 1 &&
376 (voltage < 0.333 || voltage > 1.333))
377 {
378 if (!failure)
379 {
380 failure = 1;
381 printf("EP93xx ADC out of range\n");
382 }
383
384 printf("\tChannel %d: %3.3fV"
385 "(expected 0.833V +- 50mV)\n", i, voltage);
386 }
387
388
389 //use the datasheet values
390 voltage = get_volts(adc_result_2[i][j], 0x9E58, 0xC350);
391
392 //odd channels 2.5V(+-150mV)
393 if (i % 2 == 1 &&
394 (voltage < 2.35 || voltage > 2.65))
395 {
396 if (!failure)
397 {
398 failure = 1;
399 printf("EP93XX ADC out of range\n");
400 }
401
402 printf("\tChannel %d: %3.3fV"
403 "(expected 2.5V +- 150mV)\n", i, voltage);
404 //even channels 0.833(+-50mV)
405 }
406 else if (i % 2 == 0 &&
407 (voltage < 0.333 || voltage > 1.333))
408 {
409 if (!failure)
410 {
411 failure = 1;
412 printf("EP93xx ADC out of range\n");
413 }
414
415 printf("\tChannel %d: %3.3fV"
416 "(expected 0.833V +- 50mV)\n", i, voltage);
417 }
418 }
419 }
420
421 calc_calibration(calibration, adc_result_1, adc_result_2);
422
423 if (failure)
424 {
425 return_val = 0;
426 }
427 else { return_val = 1; }
428
429 return return_val;
430 }
431
432
main(void)433 int main(void)
434 {
435 int calibration[NUM_CHANNELS][2];
436 int ret_val;
437 int devmem = open("/dev/mem", O_RDWR | O_SYNC);
438 assert(devmem != -1);
439
440 dr_page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
441 MAP_SHARED, devmem, DATA_PAGE);
442 assert(&dr_page != MAP_FAILED);
443 adc_page = (unsigned long)mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
444 MAP_SHARED, devmem, ADC_PAGE);
445 assert(&adc_page != MAP_FAILED);
446 syscon_page = (unsigned long)mmap(0, getpagesize(), PROT_READ | PROT_WRITE
447 , MAP_SHARED, devmem, SYSCON_PAGE);
448 assert(&syscon_page != MAP_FAILED);
449
450 init_ADC(adc_page, syscon_page);
451 setDR(dr_page, 0, 1);
452 setDR(dr_page, 1, 0);
453 setDR(dr_page, 2, 1);
454 setDR(dr_page, 3, 0);
455
456 if (test_ADC(calibration))
457 {
458 int state;
459 int stored_calibration[NUM_CHANNELS][2];
460 printf("ADC tested ok(data sheet values)\n");
461 state = read_calibration(stored_calibration);
462
463 if (check_calibration(calibration, stored_calibration, state))
464 {
465 ret_val = 0;
466 }
467 else
468 {
469 ret_val = 1;
470 }
471
472 }
473 else
474 {
475 ret_val = 1;
476 }
477
478 close(devmem);
479
480 return ret_val;
481 }
482