📄 pci550x_dac1_dma.c
字号:
/* * pci550x user program - DAC1 DMA Acquisition * * This test program uses a clock signal from either the internal DAC1 * PACER clock or the external clock source, DACLKIN, to clock the DAC. * Output data is written directly to the DAC1 FIFO via DMA, and then * clocked to generate the voltage ouput at the DAC1 port. This mode of * operation is referred to as DMA, meaning that interrupts and DMA * functions are used to output the sample data. In this method of * operating the DAC, the non-full DAC1 FIFO is written continuously. If * the output rate exceeds the rate at which the DAC1 FIFO can be kept * non-empty by DMA operations, the DAC1 FIFO will underflow and DAC * conversions are automatically disabled by the hardware. * * Invoke this test program from the command line as follows: * * $ ./pci550x_dac1_dma -f /dev/pci550xN [-p] [-u] [-d USECS] [-s SAMPLES] [-b] * * -f /dev/pci550xN = device node (N=device #) * -p = packed data mode * -u = unipolar * -d USECS = delay between DAC conversions in microseconds * -s SAMPLES = number sample outputs per DMA buffer * -b = brief output listing * * EXAMPLE: run the test on device 3 in packed unipolar data mode at * 10ms DAC conversion rate with 100 samples outputs per DMA buffer * * $ ./pci550x_dac1_dma -f /dev/pci550x3 -p -u -d10000 -s100 * */#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/fcntl.h>#include <sys/ioctl.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <linux/limits.h>#define _PCI550X_USE_DAC_RANGE_TABLES#include "pci550x.h"/* GLOBLA DATA */int i,c;int dac1_status;int dac1_ctrl;unsigned int *buf = NULL;size_t buf_size;ssize_t bytes;char device[PATH_MAX] = "/dev/pci550x0";int packed = PCI550X_DISABLE;int bipolar = PCI550X_ENABLE;unsigned long udelay = PCI550X_NOMINAL_DAC_RATE;unsigned short samples = PCI550X_DAC_FIFO;int gate_enabled = PCI550X_FALSE;int brief = PCI550X_DISABLE;char sentinal[6] = {'-','\\','-','|','-','/'}; unsigned char mm = 0;union {unsigned int dac_data;short bp_dac_data[2];unsigned short up_dac_data[2];} dma;int fd, rc;int brd_type;void sighandler(int signum) { /* Disable DAC1 DMA */ rc = ioctl(fd, PCI550X_IOCT_DA1_DMAEN, PCI550X_DISABLE); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_DMAEN"); free(buf); exit(1); } else { printf("DAC1 DMA halted\n"); } /* free the output buffer */ free(buf); /* close the device */ close(fd); exit(0);}int main(int argc, char **argv) { /* get command line args */ opterr = 0; while ((c = getopt(argc, argv, "f:uphd:s:b")) != -1) switch(c) { case 'd': if ((sscanf(optarg, "%ld", &udelay)) == 0) udelay = 10000; break; case 'f': strncpy(device, optarg, PATH_MAX); break; case 'u': bipolar = PCI550X_DISABLE; break; case 's': if ((sscanf(optarg, "%hd", &samples)) == 0) { printf("error: invalid sample count\n"); exit(1); } if (!samples) { printf("error: sample count is zero\n"); exit(1); } break; case 'p': packed = PCI550X_ENABLE; break; case 'h': printf("usage: pci550x_dac1_dma -f /dev/pci550xN " "[-p] [-u] [-d USECS] [-s SAMPLES]\n"); printf("-f /dev/pci550xN where N = board number\n"); printf("-p, packed data mode\n"); printf("-u, unipolar mode\n"); printf("-d USECS = microseconds delay between " "DAC conversions\n"); printf("-s SAMPLES = number of output samples per DMA " "buffer\n"); printf("-b, brief output listing\n"); exit(0); case 'b': brief = PCI550X_ENABLE; break; default: break; } /* allocate an output buffer */ buf_size = samples << 2; /* DMA requires 4 bytes (32 bit) per sample */ buf = (unsigned int *)malloc(buf_size); if (!buf) { perror("failed to allocate DAC1 DMA output buffer"); exit(1); } /* open the device */ fd = open(device, O_WRONLY); if(fd == -1) { perror("open failed"); free(buf); exit(1); } else { printf("open succeeded on %s\n", device); } /* query device type */ rc = ioctl(fd, PCI550X_IOCG_BRD_TYPE, &brd_type); if(rc == -1) { perror("ioctl PCI550X_IOCG_BRD_TYPE"); free(buf); exit(1); } else { printf("ADAC Board Type: %s\n", brd_names[brd_type]); } /* select DAC1 */ rc = ioctl(fd, PCI550X_IOCT_DAC_SELECT, PCI550X_DAC1); if(rc == -1) { perror("ioctl PCI550X_IOC_DAC_SELECT"); free(buf); exit(1); } else { printf("DAC1 Subsystem selected\n"); } /* select internal Pacer Clock source */ rc = ioctl(fd, PCI550X_IOCT_DA1_CLOCK_SOURCE, DAC1_IP_CLK); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_CLOCK_SOURCE"); exit(1); } else { printf("Internal Pacer Clock Source enabled\n"); } /* select DAC1 Pacer clock rate */ rc = ioctl(fd, PCI550X_IOCS_DAC1_PACER_CLOCK_RATE, &udelay); if(rc == -1) { perror("ioctl " "PCI550X_IOCS_DAC1_PACER_CLOCK_RATE"); exit(1); } else { printf("DAC1 Pacer clock(nsecs): %ld\n", udelay); } /* enable DAC1 FIFO */ rc = ioctl(fd, PCI550X_IOCT_DA1_STATUS_FFEN, PCI550X_ENABLE); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_STATUS_FFEN"); free(buf); exit(1); } else { printf("DAC1 FIFO enabled\n"); } /* Set DMA Buffer Size */ rc = ioctl(fd, PCI550X_IOCT_DAC1_DMA_BYTES, buf_size); if(rc == -1) { perror("ioctl PCI550X_IOCT_DMA_BYTES"); free(buf); exit(1); } else { printf("DMA Buffer Size: %d bytes\n", buf_size); } /* disable/enable packed data mode */ rc = ioctl(fd, PCI550X_IOCT_DA1_PDM, packed); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_PDM"); free(buf); exit(1); } else { if (packed) printf("PDM enabled\n"); else printf("PDM disabled\n"); } /* select bipolar/unipolar mode */ rc = ioctl(fd, PCI550X_IOCT_DA1_UB, bipolar); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_UB"); free(buf); exit(1); } else { if (bipolar) { printf("Bipolar mode enabled\n"); } else { printf("Unipolar mode enabled\n"); } } /* DAC1 output buffer initial values */ if (packed && bipolar) { dma.bp_dac_data[0] = drt.bp_min; dma.bp_dac_data[1] = drt.bp_min + 1; } else if (packed && (!(bipolar))) { dma.up_dac_data[0] = drt.up_min; dma.up_dac_data[1] = drt.up_min + 1; } else if (bipolar) { dma.bp_dac_data[0] = drt.bp_min; dma.bp_dac_data[1] = 0; } else { dma.up_dac_data[0] = drt.up_min; dma.up_dac_data[1] = 0; } /* DAC1 DMA Enable */ rc = ioctl(fd, PCI550X_IOCT_DA1_DMAEN, PCI550X_ENABLE); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_DMAEN"); free(buf); exit(1); } else { printf("DMA enabled\n"); } /* install the signal handler */ signal(SIGINT, &sighandler); while(1) { /* fill output buffer */ for (i = 0; i < samples; i++) { buf[i] = dma.dac_data; if (packed && bipolar) if (dma.bp_dac_data[1] >= (drt.bp_max)) { dma.bp_dac_data[0] = drt.bp_min; dma.bp_dac_data[1] = drt.bp_min + 1; } else { dma.bp_dac_data[0] += 2; dma.bp_dac_data[1] += 2; } else if (packed && (!bipolar)) if (dma.up_dac_data[1] >= (drt.up_max)) { dma.up_dac_data[0] = drt.up_min; dma.up_dac_data[1] = drt.up_min + 1; } else { dma.up_dac_data[0] += 2; dma.up_dac_data[1] += 2; } else if (bipolar) { if (dma.bp_dac_data[0] >= (drt.bp_max)) { dma.bp_dac_data[0] = drt.bp_min; } else { dma.bp_dac_data[0]++; } } else if (dma.up_dac_data[1] >= (drt.up_max)) { dma.up_dac_data[0] = drt.up_min; } else { dma.up_dac_data[0]++; } } /* blocking write to DAC1 */ bytes = 0; while (bytes < buf_size) { bytes += write(fd, (void *)buf + bytes, buf_size - bytes); if(bytes == -1) { perror("pci550x write"); rc = ioctl(fd, PCI550X_IOCQ_DAC1_STATUS); if (rc == -1) { perror("ioctl " "PCI550X_IOCQ_DAC1_STATUS"); free(buf); exit(1); } else { printf("DAC1 status 0x%x:", rc); if (rc & DA1_STATUS_MERR1) printf("merr1\n"); else if (rc & DA1_STATUS_MERR0) printf("merr0\n"); else if (rc & DA1_STATUS_FOVR) printf("fifo overflow\n"); else if (rc & DA1_STATUS_DERR) printf("fifo underflow\n"); else if (rc & DA1_STATUS_CERR) printf("clocking error\n"); else printf("DMA process error\n"); free(buf); exit(1); } free(buf); exit(1); } } /* brief display */ if (brief) { if (packed && bipolar) printf("%c:%s:%s DAC0 writes %d bytes, " "(P,B) %d sample values\n", sentinal[mm++], device, brd_names[brd_type], buf_size, buf_size >> 1); else if (packed & (!bipolar) ) printf("%c:%s:%s DAC0 writes %d bytes, " "(P,U) %d sample values\n", sentinal[mm++], device, brd_names[brd_type], buf_size, buf_size >> 1); else if (bipolar) printf("%c:%s:%s DAC0 writes %d bytes, " "(U,B) %d sample values\n", sentinal[mm++], device, brd_names[brd_type], buf_size, buf_size >> 2); else printf("%c:%s:%s DAC0 writes %d bytes, " "(U,U) %d sample values\n", sentinal[mm++], device, brd_names[brd_type], buf_size, buf_size >> 2); mm %= sizeof(sentinal); } else { /* display output buffer contents */ for (i = 0 ; i < samples; i++ ) { dma.dac_data = buf[i]; if (packed && bipolar) printf("%s:%s DAC1 DMA data " "(P,B):" "0x%04hx; %f Volts\n" "%s:%s DAC1 DMA data " "(P,B):" "0x%04hx; %f Volts\n", device, brd_names[brd_type], dma.bp_dac_data[0], dma.bp_dac_data[0] * drt.bp_res, device, brd_names[brd_type], dma.bp_dac_data[1], dma.bp_dac_data[1] * drt.bp_res); else if (packed && (!bipolar)) printf("%s:%s DAC1 DMA data " "(P,U):" "0x%04hx; %f Volts\n" "%s:%s DAC1 DMA data " "(P,U):" "0x%04hx; %f Volts\n", device, brd_names[brd_type], dma.up_dac_data[0], dma.up_dac_data[0] * drt.up_res, device, brd_names[brd_type], dma.up_dac_data[1], dma.up_dac_data[1] * drt.up_res); else if (bipolar) printf("%s:%s DAC1 DMA data " "(U,B):" "0x%04hx; " " %f Volts\n", device, brd_names[brd_type], dma.bp_dac_data[0], dma.bp_dac_data[0] * drt.bp_res); else printf("%s:%s DAC1 DMA data " " (U,U):" "0x%04hx; " "%f Volts\n", device, brd_names[brd_type], dma.up_dac_data[0], dma.up_dac_data[0] * drt.up_res); } } /* start clocking the DAC on FIFO not empty */ rc = ioctl(fd, PCI550X_IOCG_DA1_STATUS, &dac1_status); if(rc == -1) { perror("ioctl PCI550X_IOCG_DA1_STATUS"); free(buf); exit(1); } if ( (dac1_status & DA1_STATUS_FNE) && (!gate_enabled) ) { /* enable DAC1 to do conversions */ rc = ioctl(fd, PCI550X_IOCT_DA1_CVEN, PCI550X_ENABLE); if(rc == -1) { perror("ioctl PCI550X_IOCT_DA1_CVEN"); free(buf); exit(1); } else { printf("DAC1 enabled to do conversions\n"); } gate_enabled = PCI550X_TRUE; } } /* end while */ free(buf); close(fd); return(0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -