2 * Application using MF624 UIO driver
4 * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>
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.
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.
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.
28 #include <sys/types.h>
30 #include <stdint.h> // uintX_t
36 #include "mf624_SIMULINK.h"
38 /****************************************************************/
41 /* Which uio device node to use */
44 mf624_state_t* mfst=NULL;
45 unsigned mfst_refcnt = 0;
47 static int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
52 static size_t page_size;
54 page_size = sysconf(_SC_PAGESIZE);
56 ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
59 /* add reserve to store each size addr, name, offset, size */
63 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
64 file = fopen(s, "rb");
67 fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
70 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
71 file = fopen(s, "rb");
73 barmap->offset = barmap->phys_addr & (page_size - 1);
75 fscanf(file, "%"SCNi32, &barmap->offset);
79 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
80 file = fopen(s, "rb");
83 fscanf(file, "%"SCNi32, &barmap->size);
86 barmap->mmap_offset = page_size * map_nr + barmap->offset;
91 static int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
93 static size_t page_mask = 0;
98 page_mask = sysconf(_SC_PAGESIZE) - 1;
100 mmap_start = barmap->mmap_offset & ~page_mask;
101 mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
102 mmap_size &= ~page_mask;
104 barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start);
105 if (barmap->mmap_addr == MAP_FAILED) {
109 barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
110 barmap->virt_addr += barmap->mmap_offset & page_mask;
115 static int bar_mapping_destroy(bar_mapping_t *barmap)
119 size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
121 mmap_start = barmap->mmap_offset & ~page_mask;
122 mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
123 mmap_size &= ~page_mask;
125 return munmap(barmap->mmap_addr, mmap_size);
128 /****************************************************************/
130 #define BUFF_SMALL 32
132 #define min(a, b) ((a) > (b) ? (b) : (a))
138 mf624_state_t mf624_state;
140 /* Print one byte as binary number */
141 static void print_8bin(int nr)
144 for (i = 7; i >= 0; i--) {
145 printf("%d" , ((nr & (1 << i)) > 0));
153 void DIO_write(mf624_state_t* mfst, int16_t val)
155 mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
158 uint16_t DIO_read(mf624_state_t* mfst)
160 return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
163 void DAC_enable(mf624_state_t* mfst)
165 // Setting DACEN and LDAC bits in GPIO register influences all DACs
166 mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
167 | GPIOC_DACEN_mask) // enable output
168 & ~GPIOC_LDAC_mask, // enable conversion
169 MFST2REG(mfst, 0, GPIOC_reg));
174 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
176 if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
179 mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
183 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
185 mfst->ADC_enabled = 0;
187 if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
190 mfst->ADC_enabled = (1 << channel);
192 mfst->ADC_enabled &= 0xFF;
193 mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
194 //print_8bin(ADC_enabled);
199 /* This function blocks until conversion is finished */
200 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
205 // Activate trigger to start conversion
206 mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
208 // Check if conversion has finished
209 while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) {
210 for (i = 0; i < 1000; i++) {} // small wait
213 ADC_enable(mfst, channel);
214 result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
216 return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
219 extern uint32_t IRC_mode_change(mf624_state_t* mfst, uint32_t change_mask, uint32_t change_val)
221 /* This sequence should be protected by mutex to protect changes in multirate systems */
222 mfst->IRC_mode = (mfst->IRC_mode & ~change_mask) | (change_val & change_mask);
223 mf624_write32(mfst->IRC_mode, MFST2REG(mfst, 4, IRCCTRL_reg));
224 /*printf("change_mask 0x%08x, change_val 0x%08x\n", change_mask, change_val);*/
225 /*printf("IRC mode set to %08lx\n", mfst->IRC_mode);*/
226 return mfst->IRC_mode;
230 static int open_device(char* path) {
233 device_fd = open(path, O_RDWR | O_SYNC);
234 if (device_fd == -1) {
242 static void wait_for_interrupts(int device_fd)
244 read(device_fd, NULL, 1);
247 static int disable_interrupts(int device_fd)
249 uint32_t control_value = 0;
252 status = write(device_fd, &control_value, sizeof(uint32_t));
261 static int enable_interrupts(int device_fd)
263 uint32_t control_value = 1;
266 status = write(device_fd, &control_value, sizeof(uint32_t));
275 static void list_available_mem_regions(char* device)
278 char path[] = "/sys/class/uio/";
279 char subdir[] = "/maps/";
280 char directory[BUFF_MID];
281 memset(directory, '\0', BUFF_MID);
286 strncat(directory, path, strlen(path));
287 strncat(directory, device, min(strlen(device), 8));
288 strncat(directory, subdir, strlen(subdir));
290 dip = opendir(directory);
296 while ((dit = readdir(dip)) != NULL) {
297 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
298 printf(" %s\n", dit->d_name);
302 status = closedir(dip);
304 perror("closedir()");
311 static void list_available_io_ports(char *device)
314 char path[] = "/sys/class/uio/";
315 char subdir[] = "/portio/";
316 char directory[BUFF_MID];
317 memset(directory, '\0', BUFF_MID);
322 strncat(directory, path, strlen(path));
323 strncat(directory, device, min(strlen(device), 8));
324 strncat(directory, subdir, strlen(subdir));
326 status = access(directory, F_OK);
328 printf(" There are no IO port available\n");
332 dip = opendir(directory);
338 while ((dit = readdir(dip)) != NULL) {
339 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
340 printf(" %s\n", dit->d_name);
344 status = closedir(dip);
346 perror("closedir()");
353 static void run_simple_tests(char* dev_name)
357 char buff[BUFF_SMALL];
358 memset(buff, '\0', BUFF_SMALL);
360 strncat(buff, "/dev/", 5);
361 strncat(buff, dev_name, min(strlen(dev_name), 8));
363 printf("Opening %s\n", buff);
365 device_fd = open_device(buff);
366 if (device_fd != -1) {
367 printf("Tring to enable interrupts\n");
368 status = enable_interrupts(device_fd);
370 printf(" Probably OK\n");
373 printf("Tring to disable interrupts\n");
374 status = disable_interrupts(device_fd);
376 printf(" Probably OK\n");
381 printf("Checking for available memory regions exported by the UIO driver\n");
382 list_available_mem_regions(dev_name);
384 printf("Checking for available IO ports exported by the UIO driver\n");
385 list_available_io_ports(dev_name);
388 static int mmap_regions(mf624_state_t* mfst)
390 if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
391 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
395 if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
396 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
400 if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
401 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
405 if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
406 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
410 if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
411 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
415 if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
416 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
421 printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
422 printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
423 printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
425 printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
426 printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
427 printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
436 * Try to initialize the MF624 UIO driver.
438 * If and only if S is not NULL and initialization fails, then
439 * ssSetErrorStatus() gets called to report the error via Simulink
442 * @param S Pointer to SimStruct for error reporting or NULL.
444 * @return Zero in case of success, -1 in case of error.
446 int mf624_init(SimStruct *S)
449 mfst = malloc(sizeof(mf624_state_t));
452 snprintf(fn, sizeof(fn), "/dev/%s", mfst->uio_dev);
454 mfst->device_fd = open_device(fn);
455 if (mfst->device_fd < 0) {
456 if (S) ssSetErrorStatus(S,"/dev/" UIO ": open failed");
459 if (mmap_regions(mfst) < 0) {
460 if (S) ssSetErrorStatus(S,"/dev/" UIO ": mmap_regions failed");
467 close(mfst->device_fd);
477 if (--mfst_refcnt == 0) {
478 close(mfst->device_fd);
479 bar_mapping_destroy(&mfst->bar0);
480 bar_mapping_destroy(&mfst->bar2);
481 bar_mapping_destroy(&mfst->bar4);
492 * Check whether MF624 card is initialized.
496 * @return Zero if MF624 is initialized, -1 othewise.
498 int mf624_check(SimStruct *S)
501 if (S) ssSetErrorStatus(S, "MF624 is not initialized");
508 /*int main(int argc, char* argv[])
510 mf624_state_t* mfst = &mf624_state;
511 char buff[BUFF_SMALL];
512 memset(buff, '\0', BUFF_SMALL);
515 printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
519 mfst->uio_dev = argv[1];
521 strncat(buff, "/dev/", 5);
522 strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
524 mfst->device_fd = open_device(buff);
525 if (mfst->device_fd < 0) {
526 fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
529 if (mmap_regions(mfst) < 0) {
530 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
537 printf("Reading DIO: ");
538 print_8bin(DIO_read(mfst));
541 printf("Setting DA1 to 10 V\n");
542 DAC_write(mfst, DA1, 0x3FFF);
545 printf("Reading ADC0: ");
546 printf("%f V\n", ADC_read(mfst, AD0));
549 printf("Reading ADC1: ");
550 printf("%f V\n", ADC_read(mfst, AD1));
553 printf("Setting DIO to 0xff\n");
554 DIO_write(mfst, 0xff);
557 printf("Setting DIO to 0x00\n");
558 DIO_write(mfst, 0x00);
561 printf("Setting DA1 to 5 V\n");
562 DAC_write(mfst, DA1, 0x3000);
565 printf("Reading ADC0: ");
566 printf("%f V\n", ADC_read(mfst, AD0));
569 printf("Reading ADC1: ");
570 printf("%f V\n", ADC_read(mfst, AD1));
572 printf("----------------------\n\n");