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