]> rtime.felk.cvut.cz Git - mf6xx.git/blob - src/uio/mf624/userspace/test_application/main.c
321a22eb33d64e3a1a97e349b0f5537b386633b9
[mf6xx.git] / src / uio / mf624 / userspace / test_application / main.c
1 /* 
2  * Application using MF624 UIO driver
3  * 
4  * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com> 
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <stdio.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <dirent.h>
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 #include <stdint.h> // uintX_t
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include <alloca.h>
34
35 /****************************************************************/
36
37 typedef struct bar_mapping_t {
38         uintptr_t virt_addr;
39         void *    mmap_addr;
40         uintptr_t phys_addr;
41         uint32_t  size;
42         uint32_t  offset;
43 } bar_mapping_t;
44
45 int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
46 {
47         FILE *file;
48         void *s;
49         int ssiz;
50         ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
51         if (ssiz < 0)
52                 return -1;
53         /* add reserve to store each size addr, name, offset, size */
54         ssiz += 6 + 1;
55         s = alloca(ssiz + 6 + 1);
56
57         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
58         file = fopen(s, "rb");
59         fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
60         fclose(file);
61
62         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
63         file = fopen(s, "rb");
64         fscanf(file, "%"SCNi32, &barmap->offset);
65         fclose(file);
66
67         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
68         file = fopen(s, "rb");
69         fscanf(file, "%"SCNi32, &barmap->size);
70         fclose(file);
71
72         return 0;
73 }
74
75 int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
76 {
77         static size_t page_mask = 0;
78         off_t mmap_offset;
79         size_t mmap_size;
80
81         if (!page_mask)
82                  page_mask = sysconf(_SC_PAGESIZE) - 1;
83
84         mmap_offset = barmap->offset & ~page_mask;
85         mmap_size = barmap->offset + barmap->size + page_mask - mmap_offset;
86         mmap_size &= ~page_mask;
87
88         barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_offset);
89         if (barmap->mmap_addr == MAP_FAILED) {
90                 return -1;
91         }
92
93         barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
94         barmap->virt_addr += barmap->offset & page_mask;
95
96         return 0;
97 }
98
99 /****************************************************************/
100
101 #define BUFF_SMALL              32
102 #define BUFF_MID                256
103 #define min(a, b)               ((a) > (b) ? (b) : (a))
104
105 /* Hardware specific */
106 /* BAR0 */
107 #define GPIOC_reg               0x54
108
109 /* BAR2 */
110 #define ADCTRL_reg              0x00
111 #define ADDATA0_reg             0x00
112 #define ADDATA1_reg             0x02
113 #define ADDATA2_reg             0x04
114 #define ADDATA3_reg             0x06
115 #define ADDATA4_reg             0x08
116 #define ADDATA5_reg             0x0a
117 #define ADDATA6_reg             0x0c
118 #define ADDATA7_reg             0x0e
119 #define ADSTART_reg             0x20
120
121 #define DOUT_reg                0x10
122 #define DIN_reg                 0x10
123 #define DA0_reg                 0x20
124 #define DA1_reg                 0x22
125 #define DA2_reg                 0x24
126 #define DA3_reg                 0x26
127 #define DA4_reg                 0x28
128 #define DA5_reg                 0x2A
129 #define DA6_reg                 0x2C
130 #define DA7_reg                 0x2E
131
132 #define GPIOC_DACEN_mask        (1 << 26)
133 #define GPIOC_LDAC_mask         (1 << 23)
134 #define GPIOC_EOLC_mask         (1 << 17)
135
136
137 typedef enum {DA0, DA1, DA2, DA3, DA4, DA5, DA6, DA7} dac_channel_t;
138 typedef enum {AD0, AD1, AD2, AD3, AD4, AD5, AD6, AD7} adc_channel_t;
139
140 static uint32_t dac_channel2reg[] = {
141         [DA0] = DA0_reg,
142         [DA1] = DA1_reg,
143         [DA2] = DA2_reg,
144         [DA3] = DA3_reg,
145         [DA4] = DA4_reg,
146         [DA5] = DA5_reg,
147         [DA6] = DA6_reg,
148         [DA7] = DA7_reg,
149 };
150
151 static uint32_t adc_channel2reg[] = {
152         [AD0] = ADDATA0_reg,
153         [AD1] = ADDATA1_reg,
154         [AD2] = ADDATA2_reg,
155         [AD3] = ADDATA3_reg,
156         [AD4] = ADDATA4_reg,
157         [AD5] = ADDATA5_reg,
158         [AD6] = ADDATA6_reg,
159         [AD7] = ADDATA7_reg,
160 };
161
162 typedef struct mf624_state_t {
163         int device_fd;
164         char *uio_dev;
165         bar_mapping_t bar0;
166         bar_mapping_t bar2;
167         bar_mapping_t bar4;
168         int status;
169         int ADC_enabled; // Which ADCs are enabled
170 } mf624_state_t;
171
172 #define MFST2REG(mfst, bar_num, reg_offs) \
173         ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs)))
174
175 mf624_state_t mf624_state;
176
177 /* Print one byte as binary number */
178 void print_8bin(int nr)
179 {
180         int i;
181         for (i = 7; i >= 0; i--) {
182                 printf("%d" , ((nr & (1 << i)) > 0));
183         }
184
185         printf("\n");
186 }
187
188 static inline int16_t mf624_read16(void *ptr)
189 {
190         return *(volatile uint16_t*)ptr;
191 }
192 static inline int32_t mf624_read32(void *ptr)
193 {
194         return *(volatile uint32_t*) ptr;
195 }
196
197 static inline void mf624_write16(uint16_t val, void *ptr)
198 {
199         *(volatile uint16_t*) ptr = val;
200 }
201
202 static inline void mf624_write32(uint32_t val, void *ptr)
203 {
204         *(volatile uint32_t*) ptr = val;
205 }
206
207 void DIO_write(mf624_state_t* mfst, int16_t val)
208 {
209         mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
210 }
211
212 uint16_t DIO_read(mf624_state_t* mfst)
213 {
214         return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
215 }
216
217 void DAC_enable(mf624_state_t* mfst)
218 {
219         // Setting DACEN and LDAC bits in GPIO register influences all DACs
220         mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
221                 | GPIOC_DACEN_mask) // enable output
222                 & ~GPIOC_LDAC_mask, // enable conversion
223                 MFST2REG(mfst, 0, GPIOC_reg));
224 }
225
226 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
227 {
228         if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
229                 return -1;
230
231         mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
232         return 0;
233 }
234
235 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
236 {
237         mfst->ADC_enabled = 0;
238
239         if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
240                 return -1;
241
242         mfst->ADC_enabled = (1 << channel);
243
244         mfst->ADC_enabled &= 0xFF;
245         mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
246         //print_8bin(ADC_enabled);
247
248         return 0;
249 }
250
251 /* This function blocks until conversion is finished */
252 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
253 {
254         volatile int i;
255         int result;
256
257         // Activate trigger to start conversion
258         mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
259
260         // Check if conversion has finished
261         while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { 
262                 for (i = 0; i < 1000; i++) {} // small wait
263         }
264
265         ADC_enable(mfst, channel);
266         result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
267
268         return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
269 }
270
271
272 int open_device(char* path) {
273         int device_fd;
274
275         device_fd = open(path, O_RDWR | O_SYNC);
276         if (device_fd == -1) {
277                 perror("open()");
278                 return -1;
279         }
280
281         return device_fd;
282 }
283
284 void wait_for_interrupts(int device_fd)
285 {
286         read(device_fd, NULL, 1);
287 }
288
289 int disable_interrupts(int device_fd)
290 {
291         uint32_t control_value = 0;
292         int status;
293
294         status = write(device_fd, &control_value, sizeof(uint32_t));
295         if (status == -1) {
296                 perror("write()");
297                 return -1;
298         }
299
300         return status;
301 }
302
303 int enable_interrupts(int device_fd)
304 {
305         uint32_t control_value = 1;
306         int status;
307
308         status = write(device_fd, &control_value, sizeof(uint32_t));
309         if (status == -1) {
310                 perror("write()");
311                 return -1;
312         }
313
314         return status;
315 }
316
317 void list_available_mem_regions(char* device)
318 {
319         int status;
320         char path[] = "/sys/class/uio/";
321         char subdir[] = "/maps/";
322         char directory[BUFF_MID];
323         memset(directory, '\0', BUFF_MID);
324
325         DIR *dip;
326         struct dirent *dit;
327
328         strncat(directory, path, strlen(path));
329         strncat(directory, device, min(strlen(device), 8));
330         strncat(directory, subdir, strlen(subdir));
331
332         dip = opendir(directory);
333         if (dip == NULL) {
334                 perror("opendir");
335                 return;
336         }
337
338         while ((dit = readdir(dip)) != NULL) {
339                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
340                         printf(" %s\n", dit->d_name);
341                 }
342         }
343
344         status = closedir(dip);
345         if (status == -1) {
346                 perror("closedir()");
347                 return;
348         }
349
350 }
351
352
353 void list_available_io_ports(char *device)
354 {
355         int status;
356         char path[] = "/sys/class/uio/";
357         char subdir[] = "/portio/";
358         char directory[BUFF_MID];
359         memset(directory, '\0', BUFF_MID);
360
361         DIR *dip;
362         struct dirent *dit;
363
364         strncat(directory, path, strlen(path));
365         strncat(directory, device, min(strlen(device), 8));
366         strncat(directory, subdir, strlen(subdir));
367
368         status = access(directory, F_OK);
369         if (status == -1) {
370                 printf(" There are no IO port available\n");
371                 return;
372         }
373
374         dip = opendir(directory);
375         if (dip == NULL) {
376                 perror("opendir");
377                 return;
378         }
379
380         while ((dit = readdir(dip)) != NULL) {
381                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
382                         printf(" %s\n", dit->d_name);
383                 }
384         }
385
386         status = closedir(dip);
387         if (status == -1) {
388                 perror("closedir()");
389                 return;
390         }
391
392 }
393
394
395 void run_simple_tests(char* dev_name)
396 {
397         int status;
398         int device_fd;
399         char buff[BUFF_SMALL];
400         memset(buff, '\0', BUFF_SMALL);
401
402         strncat(buff, "/dev/", 5);
403         strncat(buff, dev_name, min(strlen(dev_name), 8));
404
405         printf("Opening %s\n", buff);
406
407         device_fd = open_device(buff);
408         if (device_fd != -1) {
409                 printf("Tring to enable interrupts\n");
410                 status = enable_interrupts(device_fd);
411                 if (status != -1) {
412                         printf(" Probably OK\n");
413                 }
414         
415                 printf("Tring to disable interrupts\n");
416                 status = disable_interrupts(device_fd);
417                 if (status != -1) {
418                         printf(" Probably OK\n");
419                 }
420         }
421
422
423         printf("Checking for available memory regions exported by the UIO driver\n");
424         list_available_mem_regions(dev_name);
425
426         printf("Checking for available IO ports exported by the UIO driver\n");
427         list_available_io_ports(dev_name);
428 }
429
430 int mmap_regions(mf624_state_t* mfst)
431 {
432         if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
433                 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
434                 return -1;
435         }
436
437         if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
438                 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
439                 return -1;
440         }
441
442         if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
443                 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
444                 return -1;
445         }
446
447         if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
448                 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
449                 return -1;
450         }
451
452         if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
453                 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
454                 return -1;
455         }
456
457         if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
458                 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
459                 return -1;
460         }
461
462 #if 1
463         printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
464         printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
465         printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
466
467         printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
468         printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
469         printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
470 #endif
471
472         return 0;
473 }
474
475
476 int main(int argc, char* argv[])
477 {
478         mf624_state_t* mfst = &mf624_state;
479         char buff[BUFF_SMALL];
480         memset(buff, '\0', BUFF_SMALL);
481
482         if (argc < 2) {
483                 printf("Usage: %s UIO_DEVICE\n   UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
484                 return 1;
485         }
486
487         mfst->uio_dev = argv[1];
488
489         strncat(buff, "/dev/", 5);
490         strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
491
492         mfst->device_fd = open_device(buff);
493         if (mfst->device_fd < 0) {
494                 fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
495                 return 2;
496         }
497         if (mmap_regions(mfst) < 0) {
498                 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
499                 return 2;
500         }
501
502         DAC_enable(mfst);
503
504         while (1){
505                 printf("Reading DIO: ");
506                 print_8bin(DIO_read(mfst));
507                 sleep(1);
508
509                 printf("Setting DA1 to 10 V\n");
510                 DAC_write(mfst, DA1, 0x3FFF);
511                 sleep(1);
512
513                 printf("Reading ADC0: ");
514                 printf("%f V\n", ADC_read(mfst, AD0));
515                 sleep(1);
516
517                 printf("Reading ADC1: ");
518                 printf("%f V\n", ADC_read(mfst, AD1));
519                 sleep(1);
520
521                 printf("Setting DIO to 0xff\n");
522                 DIO_write(mfst, 0xff);
523                 sleep(1);
524
525                 printf("Setting DIO to 0x00\n");
526                 DIO_write(mfst, 0x00);
527                 sleep(1);
528
529                 printf("Setting DA1 to 5 V\n");
530                 DAC_write(mfst, DA1, 0x3000);
531                 sleep(1);
532                 
533                 printf("Reading ADC0: ");
534                 printf("%f V\n", ADC_read(mfst, AD0));
535                 sleep(1);
536
537                 printf("Reading ADC1: ");
538                 printf("%f V\n", ADC_read(mfst, AD1));
539                 sleep(1);
540                 printf("----------------------\n\n");
541         }
542
543
544         return 0;
545 }