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