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
35 /****************************************************************/
37 typedef struct bar_mapping_t {
45 int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
50 ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
53 /* add reserve to store each size addr, name, offset, size */
55 s = alloca(ssiz + 6 + 1);
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);
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);
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);
75 int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
77 static size_t page_mask = 0;
82 page_mask = sysconf(_SC_PAGESIZE) - 1;
84 mmap_offset = barmap->offset & ~page_mask;
85 mmap_size = barmap->offset + barmap->size + page_mask - mmap_offset;
86 mmap_size &= ~page_mask;
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) {
93 barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
94 barmap->virt_addr += barmap->offset & page_mask;
99 /****************************************************************/
101 #define BUFF_SMALL 32
103 #define min(a, b) ((a) > (b) ? (b) : (a))
105 /* Hardware specific */
107 #define GPIOC_reg 0x54
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
121 #define DOUT_reg 0x10
132 #define GPIOC_DACEN_mask (1 << 26)
133 #define GPIOC_LDAC_mask (1 << 23)
134 #define GPIOC_EOLC_mask (1 << 17)
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;
140 static uint32_t dac_channel2reg[] = {
151 static uint32_t adc_channel2reg[] = {
162 typedef struct mf624_state_t {
169 int ADC_enabled; // Which ADCs are enabled
172 #define MFST2REG(mfst, bar_num, reg_offs) \
173 ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs)))
175 mf624_state_t mf624_state;
177 /* Print one byte as binary number */
178 void print_8bin(int nr)
181 for (i = 7; i >= 0; i--) {
182 printf("%d" , ((nr & (1 << i)) > 0));
188 static inline int16_t mf624_read16(void *ptr)
190 return *(volatile uint16_t*)ptr;
192 static inline int32_t mf624_read32(void *ptr)
194 return *(volatile uint32_t*) ptr;
197 static inline void mf624_write16(uint16_t val, void *ptr)
199 *(volatile uint16_t*) ptr = val;
202 static inline void mf624_write32(uint32_t val, void *ptr)
204 *(volatile uint32_t*) ptr = val;
207 void DIO_write(mf624_state_t* mfst, int16_t val)
209 mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
212 uint16_t DIO_read(mf624_state_t* mfst)
214 return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
217 void DAC_enable(mf624_state_t* mfst)
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));
226 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
228 if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
231 mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
235 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
237 mfst->ADC_enabled = 0;
239 if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
242 mfst->ADC_enabled = (1 << channel);
244 mfst->ADC_enabled &= 0xFF;
245 mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
246 //print_8bin(ADC_enabled);
251 /* This function blocks until conversion is finished */
252 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
257 // Activate trigger to start conversion
258 mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
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
265 ADC_enable(mfst, channel);
266 result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
268 return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
272 int open_device(char* path) {
275 device_fd = open(path, O_RDWR | O_SYNC);
276 if (device_fd == -1) {
284 void wait_for_interrupts(int device_fd)
286 read(device_fd, NULL, 1);
289 int disable_interrupts(int device_fd)
291 uint32_t control_value = 0;
294 status = write(device_fd, &control_value, sizeof(uint32_t));
303 int enable_interrupts(int device_fd)
305 uint32_t control_value = 1;
308 status = write(device_fd, &control_value, sizeof(uint32_t));
317 void list_available_mem_regions(char* device)
320 char path[] = "/sys/class/uio/";
321 char subdir[] = "/maps/";
322 char directory[BUFF_MID];
323 memset(directory, '\0', BUFF_MID);
328 strncat(directory, path, strlen(path));
329 strncat(directory, device, min(strlen(device), 8));
330 strncat(directory, subdir, strlen(subdir));
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 void list_available_io_ports(char *device)
356 char path[] = "/sys/class/uio/";
357 char subdir[] = "/portio/";
358 char directory[BUFF_MID];
359 memset(directory, '\0', BUFF_MID);
364 strncat(directory, path, strlen(path));
365 strncat(directory, device, min(strlen(device), 8));
366 strncat(directory, subdir, strlen(subdir));
368 status = access(directory, F_OK);
370 printf(" There are no IO port available\n");
374 dip = opendir(directory);
380 while ((dit = readdir(dip)) != NULL) {
381 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
382 printf(" %s\n", dit->d_name);
386 status = closedir(dip);
388 perror("closedir()");
395 void run_simple_tests(char* dev_name)
399 char buff[BUFF_SMALL];
400 memset(buff, '\0', BUFF_SMALL);
402 strncat(buff, "/dev/", 5);
403 strncat(buff, dev_name, min(strlen(dev_name), 8));
405 printf("Opening %s\n", buff);
407 device_fd = open_device(buff);
408 if (device_fd != -1) {
409 printf("Tring to enable interrupts\n");
410 status = enable_interrupts(device_fd);
412 printf(" Probably OK\n");
415 printf("Tring to disable interrupts\n");
416 status = disable_interrupts(device_fd);
418 printf(" Probably OK\n");
423 printf("Checking for available memory regions exported by the UIO driver\n");
424 list_available_mem_regions(dev_name);
426 printf("Checking for available IO ports exported by the UIO driver\n");
427 list_available_io_ports(dev_name);
430 int mmap_regions(mf624_state_t* mfst)
432 if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
433 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
437 if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
438 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
442 if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
443 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
447 if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
448 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
452 if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
453 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
457 if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
458 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
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);
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);
476 int main(int argc, char* argv[])
478 mf624_state_t* mfst = &mf624_state;
479 char buff[BUFF_SMALL];
480 memset(buff, '\0', BUFF_SMALL);
483 printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
487 mfst->uio_dev = argv[1];
489 strncat(buff, "/dev/", 5);
490 strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
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));
497 if (mmap_regions(mfst) < 0) {
498 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
505 printf("Reading DIO: ");
506 print_8bin(DIO_read(mfst));
509 printf("Setting DA1 to 10 V\n");
510 DAC_write(mfst, DA1, 0x3FFF);
513 printf("Reading ADC0: ");
514 printf("%f V\n", ADC_read(mfst, AD0));
517 printf("Reading ADC1: ");
518 printf("%f V\n", ADC_read(mfst, AD1));
521 printf("Setting DIO to 0xff\n");
522 DIO_write(mfst, 0xff);
525 printf("Setting DIO to 0x00\n");
526 DIO_write(mfst, 0x00);
529 printf("Setting DA1 to 5 V\n");
530 DAC_write(mfst, DA1, 0x3000);
533 printf("Reading ADC0: ");
534 printf("%f V\n", ADC_read(mfst, AD0));
537 printf("Reading ADC1: ");
538 printf("%f V\n", ADC_read(mfst, AD1));
540 printf("----------------------\n\n");