#include <sys/types.h>
#include <sys/mman.h>
#include <stdint.h> // uintX_t
+#include <inttypes.h>
#include <unistd.h>
+#include <alloca.h>
+
+/****************************************************************/
+
+typedef struct bar_mapping_t {
+ uintptr_t virt_addr;
+ void * mmap_addr;
+ uintptr_t phys_addr;
+ uint32_t size;
+ uint32_t offset;
+} bar_mapping_t;
+
+int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
+{
+ FILE *file;
+ void *s;
+ int ssiz;
+ ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
+ if (ssiz < 0)
+ return -1;
+ /* add reserve to store each size addr, name, offset, size */
+ ssiz += 6 + 1;
+ s = alloca(ssiz + 6 + 1);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
+ fclose(file);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNi32, &barmap->offset);
+ fclose(file);
+
+ snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
+ file = fopen(s, "rb");
+ fscanf(file, "%"SCNi32, &barmap->size);
+ fclose(file);
+
+ return 0;
+}
+
+int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
+{
+ static size_t page_mask = 0;
+ off_t mmap_offset;
+ size_t mmap_size;
+
+ if (!page_mask)
+ page_mask = sysconf(_SC_PAGESIZE) - 1;
+
+ mmap_offset = barmap->offset & ~page_mask;
+ mmap_size = barmap->offset + barmap->size + page_mask - mmap_offset;
+ mmap_size &= ~page_mask;
+
+ barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_offset);
+ if (barmap->mmap_addr == MAP_FAILED) {
+ return -1;
+ }
+
+ barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
+ barmap->virt_addr += barmap->offset & page_mask;
+
+ return 0;
+}
+
+/****************************************************************/
#define BUFF_SMALL 32
#define BUFF_MID 256
#define DA6_reg 0x2C
#define DA7_reg 0x2E
-
-
#define GPIOC_DACEN_mask (1 << 26)
-#define GPIOC_LDAC_mask (1 << 23)
+#define GPIOC_LDAC_mask (1 << 23)
#define GPIOC_EOLC_mask (1 << 17)
-#define BAR0_offset (0 * sysconf(_SC_PAGESIZE))
-#define BAR2_offset (1 * sysconf(_SC_PAGESIZE))
-#define BAR4_offset (2 * sysconf(_SC_PAGESIZE))
-
typedef enum {DA0, DA1, DA2, DA3, DA4, DA5, DA6, DA7} dac_channel_t;
typedef enum {AD0, AD1, AD2, AD3, AD4, AD5, AD6, AD7} adc_channel_t;
+static uint32_t dac_channel2reg[] = {
+ [DA0] = DA0_reg,
+ [DA1] = DA1_reg,
+ [DA2] = DA2_reg,
+ [DA3] = DA3_reg,
+ [DA4] = DA4_reg,
+ [DA5] = DA5_reg,
+ [DA6] = DA6_reg,
+ [DA7] = DA7_reg,
+};
+
+static uint32_t adc_channel2reg[] = {
+ [AD0] = ADDATA0_reg,
+ [AD1] = ADDATA1_reg,
+ [AD2] = ADDATA2_reg,
+ [AD3] = ADDATA3_reg,
+ [AD4] = ADDATA4_reg,
+ [AD5] = ADDATA5_reg,
+ [AD6] = ADDATA6_reg,
+ [AD7] = ADDATA7_reg,
+};
+
+typedef struct mf624_state_t {
+ int device_fd;
+ char *uio_dev;
+ bar_mapping_t bar0;
+ bar_mapping_t bar2;
+ bar_mapping_t bar4;
+ int status;
+ int ADC_enabled; // Which ADCs are enabled
+} mf624_state_t;
-int status;
-void* mf624_BAR0 = NULL;
-void* mf624_BAR2 = NULL;
-void* mf624_BAR4 = NULL;
-int BAR0_phys_addr;
-int BAR2_phys_addr;
-int BAR4_phys_addr;
-int ADC_enabled; // Which ADCs are enabled
+#define MFST2REG(mfst, bar_num, reg_offs) \
+ ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs)))
+mf624_state_t mf624_state;
/* Print one byte as binary number */
void print_8bin(int nr)
printf("\n");
}
-static inline int16_t mf624_read16(uint16_t *ptr)
+static inline int16_t mf624_read16(void *ptr)
{
- return (volatile uint16_t) *ptr;
+ return *(volatile uint16_t*)ptr;
}
-static inline int32_t mf624_read32(uint32_t *ptr)
+static inline int32_t mf624_read32(void *ptr)
{
- return (volatile uint32_t) *ptr;
+ return *(volatile uint32_t*) ptr;
}
-static inline void mf624_write16(uint16_t val, uint16_t *ptr)
+static inline void mf624_write16(uint16_t val, void *ptr)
{
*(volatile uint16_t*) ptr = val;
}
-static inline void mf624_write32(uint32_t val, uint32_t *ptr)
+static inline void mf624_write32(uint32_t val, void *ptr)
{
*(volatile uint32_t*) ptr = val;
}
-void DIO_write(int16_t val)
+void DIO_write(mf624_state_t* mfst, int16_t val)
{
- mf624_write16(val, mf624_BAR2 + DOUT_reg);
+ mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
}
-uint16_t DIO_read()
+uint16_t DIO_read(mf624_state_t* mfst)
{
- return mf624_read16(mf624_BAR2 + DIN_reg) & 0xFF;
+ return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
}
-void DAC_enable()
+void DAC_enable(mf624_state_t* mfst)
{
// Setting DACEN and LDAC bits in GPIO register influences all DACs
- mf624_write32((mf624_read32(mf624_BAR0 + GPIOC_reg)
- | GPIOC_DACEN_mask) // enable output
+ mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
+ | GPIOC_DACEN_mask) // enable output
& ~GPIOC_LDAC_mask, // enable conversion
- mf624_BAR0 + GPIOC_reg);
+ MFST2REG(mfst, 0, GPIOC_reg));
}
-void DAC_write(dac_channel_t channel, int val) {
- switch (channel) {
- case DA0:
- mf624_write16(val, mf624_BAR2 + DA0_reg);
- break;
- case DA1:
- mf624_write16(val, mf624_BAR2 + DA1_reg);
- break;
- case DA2:
- mf624_write16(val, mf624_BAR2 + DA2_reg);
- break;
- case DA3:
- mf624_write16(val, mf624_BAR2 + DA3_reg);
- break;
- case DA4:
- mf624_write16(val, mf624_BAR2 + DA4_reg);
- break;
- case DA5:
- mf624_write16(val, mf624_BAR2 + DA5_reg);
- break;
- case DA6:
- mf624_write16(val, mf624_BAR2 + DA6_reg);
- break;
- case DA7:
- mf624_write16(val, mf624_BAR2 + DA7_reg);
- break;
- default:
- printf("FFFUUU!\n");
- }
+int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
+{
+ if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
+ return -1;
+
+ mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
+ return 0;
}
-void ADC_enable(adc_channel_t channel)
+int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
{
- ADC_enabled = 0;
-
- switch (channel) {
- case AD0:
- ADC_enabled = (1 << 0);
- break;
- case AD1:
- ADC_enabled = (1 << 1);
- break;
- case AD2:
- ADC_enabled = (1 << 2);
- break;
- case AD3:
- ADC_enabled = (1 << 3);
- break;
- case AD4:
- ADC_enabled = (1 << 4);
- break;
- case AD5:
- ADC_enabled = (1 << 5);
- break;
- case AD6:
- ADC_enabled = (1 << 6);
- break;
- case AD7:
- ADC_enabled = (1 << 7);
- break;
- default:
- printf("FFFUUU!\n");
- }
-
- ADC_enabled &= 0xFF;
- mf624_write16(ADC_enabled, mf624_BAR2 + ADCTRL_reg);
+ mfst->ADC_enabled = 0;
+
+ if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
+ return -1;
+
+ mfst->ADC_enabled = (1 << channel);
+
+ mfst->ADC_enabled &= 0xFF;
+ mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
//print_8bin(ADC_enabled);
+
+ return 0;
}
/* This function blocks until conversion is finished */
-double ADC_read(adc_channel_t channel)
+double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
{
- int i;
+ volatile int i;
int result;
// Activate trigger to start conversion
- mf624_read16(mf624_BAR2 + ADSTART_reg);
+ mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
// Check if conversion has finished
- while((mf624_read32(mf624_BAR0 + GPIOC_reg) & GPIOC_EOLC_mask)) {
+ while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) {
for (i = 0; i < 1000; i++) {} // small wait
}
- ADC_enable(channel);
- result = mf624_read16(mf624_BAR2 + ADDATA0_reg);
+ ADC_enable(mfst, channel);
+ result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
}
int open_device(char* path) {
- status = open(path, O_RDWR);
- if (status == -1) {
+ int device_fd;
+
+ device_fd = open(path, O_RDWR | O_SYNC);
+ if (device_fd == -1) {
perror("open()");
return -1;
}
- return status;
+ return device_fd;
}
void wait_for_interrupts(int device_fd)
int disable_interrupts(int device_fd)
{
uint32_t control_value = 0;
+ int status;
status = write(device_fd, &control_value, sizeof(uint32_t));
if (status == -1) {
int enable_interrupts(int device_fd)
{
uint32_t control_value = 1;
+ int status;
status = write(device_fd, &control_value, sizeof(uint32_t));
if (status == -1) {
void list_available_mem_regions(char* device)
{
+ int status;
char path[] = "/sys/class/uio/";
char subdir[] = "/maps/";
char directory[BUFF_MID];
perror("closedir()");
return;
}
-
+
}
void list_available_io_ports(char *device)
{
+ int status;
char path[] = "/sys/class/uio/";
char subdir[] = "/portio/";
char directory[BUFF_MID];
void run_simple_tests(char* dev_name)
{
+ int status;
int device_fd;
char buff[BUFF_SMALL];
memset(buff, '\0', BUFF_SMALL);
if (status != -1) {
printf(" Probably OK\n");
}
-
+
printf("Tring to disable interrupts\n");
status = disable_interrupts(device_fd);
if (status != -1) {
list_available_io_ports(dev_name);
}
-void mmap_regions(int device_fd, char* uio_dev)
+int mmap_regions(mf624_state_t* mfst)
{
- char path[BUFF_MID];
- FILE *file;
-
- sprintf(path, "/sys/class/uio/%s/maps/map0/addr", uio_dev);
- file = fopen(path, "rb");
- fscanf(file, "%llx", &BAR0_phys_addr);
- fclose(file);
-
- sprintf(path, "/sys/class/uio/%s/maps/map1/addr", uio_dev);
- file = fopen(path, "rb");
- fscanf(file, "%llx", &BAR2_phys_addr);
- fclose(file);
-
- sprintf(path, "/sys/class/uio/%s/maps/map2/addr", uio_dev);
- file = fopen(path, "rb");
- fscanf(file, "%llx", &BAR4_phys_addr);
- fclose(file);
-
+ if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
+ fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
+ return -1;
+ }
- mf624_BAR0 = mmap(0, 1 * sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, BAR0_offset);
- if (mf624_BAR2 == MAP_FAILED) {
- perror("mmap()");
+ if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
+ fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
+ return -1;
}
- mf624_BAR0 += (BAR0_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
+ if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
+ fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
+ return -1;
+ }
- mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, BAR2_offset);
- if (mf624_BAR2 == MAP_FAILED) {
- perror("mmap()");
+ if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
+ fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
+ return -1;
}
- mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
+ if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
+ fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
+ return -1;
+ }
- mf624_BAR4 = mmap(0, 1 * sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, BAR4_offset);
- if (mf624_BAR2 == MAP_FAILED) {
- perror("mmap()");
+ if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
+ fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
+ return -1;
}
- mf624_BAR4 += (BAR4_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
- /*
- printf("BAR0_phys_addr = %x\n", BAR0_phys_addr);
- printf("BAR2_phys_addr = %x\n", BAR2_phys_addr);
- printf("BAR4_phys_addr = %x\n", BAR4_phys_addr);
+#if 1
+ printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
+ printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
+ printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
+
+ printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
+ printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
+ printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
+#endif
- printf("mf624_BAR0 = %x\n", mf624_BAR0);
- printf("mf624_BAR2 = %x\n", mf624_BAR2);
- printf("mf624_BAR4 = %x\n", mf624_BAR4);
- */
+ return 0;
}
int main(int argc, char* argv[])
{
- int device_fd;
+ mf624_state_t* mfst = &mf624_state;
char buff[BUFF_SMALL];
memset(buff, '\0', BUFF_SMALL);
if (argc < 2) {
printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
return 1;
- }
+ }
+
+ mfst->uio_dev = argv[1];
strncat(buff, "/dev/", 5);
- strncat(buff, argv[1], min(strlen(argv[1]), 8));
+ strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
- device_fd = open_device(buff);
- if (device_fd < 0) {
- printf("%s does not exist!\n", argv[1]);
+ mfst->device_fd = open_device(buff);
+ if (mfst->device_fd < 0) {
+ fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
+ return 2;
+ }
+ if (mmap_regions(mfst) < 0) {
+ fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
return 2;
}
- mmap_regions(device_fd, argv[1]);
- if (device_fd != -1) {
- DAC_enable();
+ DAC_enable(mfst);
- while (1){
- printf("Reading DIO: ");
- print_8bin(DIO_read());
- sleep(1);
+ while (1){
+ printf("Reading DIO: ");
+ print_8bin(DIO_read(mfst));
+ sleep(1);
- printf("Setting DA1 to 10 V\n");
- DAC_write(DA1, 0x3FFF);
- sleep(1);
+ printf("Setting DA1 to 10 V\n");
+ DAC_write(mfst, DA1, 0x3FFF);
+ sleep(1);
- printf("Reading ADC0: ");
- printf("%f V\n", ADC_read(AD0));
- sleep(1);
-
- printf("Reading ADC1: ");
- printf("%f V\n", ADC_read(AD1));
- sleep(1);
-
- printf("Setting DIO to 0xff\n");
- DIO_write(0xff);
- sleep(1);
-
- printf("Setting DIO to 0x00\n");
- DIO_write(0x00);
- sleep(1);
-
- printf("Setting DA1 to 5 V\n");
- DAC_write(DA1, 0x3000);
- sleep(1);
-
- printf("Reading ADC0: ");
- printf("%f V\n", ADC_read(AD0));
- sleep(1);
-
- printf("Reading ADC1: ");
- printf("%f V\n", ADC_read(AD1));
- sleep(1);
- printf("----------------------\n\n");
- }
+ printf("Reading ADC0: ");
+ printf("%f V\n", ADC_read(mfst, AD0));
+ sleep(1);
+
+ printf("Reading ADC1: ");
+ printf("%f V\n", ADC_read(mfst, AD1));
+ sleep(1);
+
+ printf("Setting DIO to 0xff\n");
+ DIO_write(mfst, 0xff);
+ sleep(1);
+
+ printf("Setting DIO to 0x00\n");
+ DIO_write(mfst, 0x00);
+ sleep(1);
+
+ printf("Setting DA1 to 5 V\n");
+ DAC_write(mfst, DA1, 0x3000);
+ sleep(1);
+
+ printf("Reading ADC0: ");
+ printf("%f V\n", ADC_read(mfst, AD0));
+ sleep(1);
+
+ printf("Reading ADC1: ");
+ printf("%f V\n", ADC_read(mfst, AD1));
+ sleep(1);
+ printf("----------------------\n\n");
}