2 * Common Humusoft MF624 card Simulink code for use with Linux UIO driver
4 * Copyright (C) 2011-2014 Rostislav Lisovy <lisovy@gmail.com>
5 * Copyright (C) 2013 Michal Kreč <krecmich@fel.cvut.cz>
6 * Copyright (C) 2013 Michal Sojka <sojkam1@fel.cvut.cz>
8 * Department of Control Engineering
9 * Faculty of Electrical Engineering
10 * Czech Technical University in Prague (CTU)
12 * The ERT Linux support code can be distributed in compliance
13 * with GNU General Public License (GPL) version 2 or later.
14 * Other licence can negotiated with CTU.
16 * Next exception is granted in addition to GPL.
17 * Instantiating or linking compiled version of this code
18 * to produce an application image/executable, does not
19 * by itself cause the resulting application image/executable
20 * to be covered by the GNU General Public License.
21 * This exception does not however invalidate any other reasons
22 * why the executable file might be covered by the GNU Public License.
23 * Publication of enhanced or derived S-function files is required
26 * Linux ERT code is available from
27 * http://rtime.felk.cvut.cz/gitweb/ert_linux.git
28 * More CTU Linux target for Simulink components are available at
29 * http://lintarget.sourceforge.net/
31 * sfuntmpl_basic.c by The MathWorks, Inc. has been used to accomplish
32 * required S-function structure.
42 #include <sys/types.h>
44 #include <stdint.h> // uintX_t
50 #include "mf624_SIMULINK.h"
52 /****************************************************************/
55 /* Which uio device node to use */
58 mf624_state_t* mfst=NULL;
59 unsigned mfst_refcnt = 0;
61 static int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
66 static size_t page_size;
68 page_size = sysconf(_SC_PAGESIZE);
70 ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
73 /* add reserve to store each size addr, name, offset, size */
77 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
78 file = fopen(s, "rb");
81 fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
84 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
85 file = fopen(s, "rb");
87 barmap->offset = barmap->phys_addr & (page_size - 1);
89 fscanf(file, "%"SCNi32, &barmap->offset);
93 snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
94 file = fopen(s, "rb");
97 fscanf(file, "%"SCNi32, &barmap->size);
100 barmap->mmap_offset = page_size * map_nr + barmap->offset;
105 static int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
107 static size_t page_mask = 0;
112 page_mask = sysconf(_SC_PAGESIZE) - 1;
114 mmap_start = barmap->mmap_offset & ~page_mask;
115 mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
116 mmap_size &= ~page_mask;
118 barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start);
119 if (barmap->mmap_addr == MAP_FAILED) {
123 barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
124 barmap->virt_addr += barmap->mmap_offset & page_mask;
129 static int bar_mapping_destroy(bar_mapping_t *barmap)
133 size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
135 mmap_start = barmap->mmap_offset & ~page_mask;
136 mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
137 mmap_size &= ~page_mask;
139 return munmap(barmap->mmap_addr, mmap_size);
142 /****************************************************************/
144 #define BUFF_SMALL 32
146 #define min(a, b) ((a) > (b) ? (b) : (a))
152 mf624_state_t mf624_state;
154 /* Print one byte as binary number */
155 static void print_8bin(int nr)
158 for (i = 7; i >= 0; i--) {
159 printf("%d" , ((nr & (1 << i)) > 0));
167 void DIO_write(mf624_state_t* mfst, int16_t val)
169 mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
172 uint16_t DIO_read(mf624_state_t* mfst)
174 return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
177 void DAC_enable(mf624_state_t* mfst)
179 // Setting DACEN and LDAC bits in GPIO register influences all DACs
180 mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
181 | GPIOC_DACEN_mask) // enable output
182 & ~GPIOC_LDAC_mask, // enable conversion
183 MFST2REG(mfst, 0, GPIOC_reg));
188 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
190 if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
193 mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
197 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
199 mfst->ADC_enabled = 0;
201 if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
204 mfst->ADC_enabled = (1 << channel);
206 mfst->ADC_enabled &= 0xFF;
207 mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
208 //print_8bin(ADC_enabled);
213 /* This function blocks until conversion is finished */
214 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
219 // Activate trigger to start conversion
220 mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
222 // Check if conversion has finished
223 while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) {
224 for (i = 0; i < 1000; i++) {} // small wait
227 ADC_enable(mfst, channel);
228 result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
230 return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
233 extern uint32_t IRC_mode_change(mf624_state_t* mfst, uint32_t change_mask, uint32_t change_val)
235 /* This sequence should be protected by mutex to protect changes in multirate systems */
236 mfst->IRC_mode = (mfst->IRC_mode & ~change_mask) | (change_val & change_mask);
237 mf624_write32(mfst->IRC_mode, MFST2REG(mfst, 4, IRCCTRL_reg));
238 /*printf("change_mask 0x%08x, change_val 0x%08x\n", change_mask, change_val);*/
239 /*printf("IRC mode set to %08lx\n", mfst->IRC_mode);*/
240 return mfst->IRC_mode;
244 static int open_device(char* path) {
247 device_fd = open(path, O_RDWR | O_SYNC);
248 if (device_fd == -1) {
256 static void wait_for_interrupts(int device_fd)
258 read(device_fd, NULL, 1);
261 static int disable_interrupts(int device_fd)
263 uint32_t control_value = 0;
266 status = write(device_fd, &control_value, sizeof(uint32_t));
275 static int enable_interrupts(int device_fd)
277 uint32_t control_value = 1;
280 status = write(device_fd, &control_value, sizeof(uint32_t));
289 static void list_available_mem_regions(char* device)
292 char path[] = "/sys/class/uio/";
293 char subdir[] = "/maps/";
294 char directory[BUFF_MID];
295 memset(directory, '\0', BUFF_MID);
300 strncat(directory, path, strlen(path));
301 strncat(directory, device, min(strlen(device), 8));
302 strncat(directory, subdir, strlen(subdir));
304 dip = opendir(directory);
310 while ((dit = readdir(dip)) != NULL) {
311 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
312 printf(" %s\n", dit->d_name);
316 status = closedir(dip);
318 perror("closedir()");
325 static void list_available_io_ports(char *device)
328 char path[] = "/sys/class/uio/";
329 char subdir[] = "/portio/";
330 char directory[BUFF_MID];
331 memset(directory, '\0', BUFF_MID);
336 strncat(directory, path, strlen(path));
337 strncat(directory, device, min(strlen(device), 8));
338 strncat(directory, subdir, strlen(subdir));
340 status = access(directory, F_OK);
342 printf(" There are no IO port available\n");
346 dip = opendir(directory);
352 while ((dit = readdir(dip)) != NULL) {
353 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
354 printf(" %s\n", dit->d_name);
358 status = closedir(dip);
360 perror("closedir()");
367 static void run_simple_tests(char* dev_name)
371 char buff[BUFF_SMALL];
372 memset(buff, '\0', BUFF_SMALL);
374 strncat(buff, "/dev/", 5);
375 strncat(buff, dev_name, min(strlen(dev_name), 8));
377 printf("Opening %s\n", buff);
379 device_fd = open_device(buff);
380 if (device_fd != -1) {
381 printf("Tring to enable interrupts\n");
382 status = enable_interrupts(device_fd);
384 printf(" Probably OK\n");
387 printf("Tring to disable interrupts\n");
388 status = disable_interrupts(device_fd);
390 printf(" Probably OK\n");
395 printf("Checking for available memory regions exported by the UIO driver\n");
396 list_available_mem_regions(dev_name);
398 printf("Checking for available IO ports exported by the UIO driver\n");
399 list_available_io_ports(dev_name);
402 static int mmap_regions(mf624_state_t* mfst)
404 if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
405 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
409 if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
410 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
414 if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
415 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
419 if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
420 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
424 if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
425 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
429 if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
430 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
435 printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
436 printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
437 printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
439 printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
440 printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
441 printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
450 * Try to initialize the MF624 UIO driver.
452 * If and only if S is not NULL and initialization fails, then
453 * ssSetErrorStatus() gets called to report the error via Simulink
456 * @param S Pointer to SimStruct for error reporting or NULL.
458 * @return Zero in case of success, -1 in case of error.
460 int mf624_init(SimStruct *S)
463 mfst = malloc(sizeof(mf624_state_t));
466 snprintf(fn, sizeof(fn), "/dev/%s", mfst->uio_dev);
468 mfst->device_fd = open_device(fn);
469 if (mfst->device_fd < 0) {
470 if (S) ssSetErrorStatus(S,"/dev/" UIO ": open failed");
473 if (mmap_regions(mfst) < 0) {
474 if (S) ssSetErrorStatus(S,"/dev/" UIO ": mmap_regions failed");
481 close(mfst->device_fd);
491 if (--mfst_refcnt == 0) {
492 close(mfst->device_fd);
493 bar_mapping_destroy(&mfst->bar0);
494 bar_mapping_destroy(&mfst->bar2);
495 bar_mapping_destroy(&mfst->bar4);
506 * Check whether MF624 card is initialized.
510 * @return Zero if MF624 is initialized, -1 othewise.
512 int mf624_check(SimStruct *S)
515 if (S) ssSetErrorStatus(S, "MF624 is not initialized");
522 /*int main(int argc, char* argv[])
524 mf624_state_t* mfst = &mf624_state;
525 char buff[BUFF_SMALL];
526 memset(buff, '\0', BUFF_SMALL);
529 printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
533 mfst->uio_dev = argv[1];
535 strncat(buff, "/dev/", 5);
536 strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
538 mfst->device_fd = open_device(buff);
539 if (mfst->device_fd < 0) {
540 fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
543 if (mmap_regions(mfst) < 0) {
544 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
551 printf("Reading DIO: ");
552 print_8bin(DIO_read(mfst));
555 printf("Setting DA1 to 10 V\n");
556 DAC_write(mfst, DA1, 0x3FFF);
559 printf("Reading ADC0: ");
560 printf("%f V\n", ADC_read(mfst, AD0));
563 printf("Reading ADC1: ");
564 printf("%f V\n", ADC_read(mfst, AD1));
567 printf("Setting DIO to 0xff\n");
568 DIO_write(mfst, 0xff);
571 printf("Setting DIO to 0x00\n");
572 DIO_write(mfst, 0x00);
575 printf("Setting DA1 to 5 V\n");
576 DAC_write(mfst, DA1, 0x3000);
579 printf("Reading ADC0: ");
580 printf("%f V\n", ADC_read(mfst, AD0));
583 printf("Reading ADC1: ");
584 printf("%f V\n", ADC_read(mfst, AD1));
586 printf("----------------------\n\n");