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