⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 das16m1.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    comedi/drivers/das16m1.c    CIO-DAS16/M1 driver    Author: Frank Mori Hess, based on code from the das16      driver.    Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 2000 David A. Schleef <ds@schleef.org>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*************************************************************************//*Driver: das16m1.oDescription: CIO-DAS16/M1Author: Frank Mori Hess <fmhess@users.sourceforge.net>Devices: [MeasurementComputing] CIO-DAS16/M1 (cio-das16/m1)Status: worksThis driver supports a single board - the CIO-DAS16/M1.As far as I know, there are no other boards that havethe same register layout.  Even the CIO-DAS16/M1/16 issignificantly different.I was _barely_ able to reach the full 1 MHz capabilityof this board, using a hard real-time interrupt(set the TRIG_RT flag in your comedi_cmd and usertlinux or RTAI).  The board can't do dma, so the bottleneck ispulling the data across the ISA bus.  I timed the interrupthandler, and it took my computer ~470 microseconds to pull 512samples from the board.  So at 1 Mhz sampling rate,expect your CPU to be spending almost all of itstime in the interrupt handler.This board has some unusual restrictions for its channel/gain list.  If thelist has 2 or more channels in it, then two conditions must be satisfied:(1) - even/odd channels must appear at even/odd indices in the list(2) - the list must have an even number of entries.Options:        [0] - base io address        [1] - irq (optional, but you probably want it)irq can be omitted, although the cmd interface will not work without it.*/#include <linux/comedidev.h>#include <linux/ioport.h>#include "8255.h"#include "8253.h"#include "comedi_fc.h"#define DAS16M1_SIZE 16#define DAS16M1_SIZE2 8#define DAS16M1_XTAL 100	//10 MHz master clock#define FIFO_SIZE 1024	// 1024 sample fifo/*    CIO-DAS16_M1.pdf    "cio-das16/m1"  0	a/d bits 0-3, mux		start 12 bit  1	a/d bits 4-11		unused  2	status		control  3	di 4 bit		do 4 bit  4	unused			clear interrupt  5	interrupt, pacer  6	channel/gain queue address  7	channel/gain queue data  89ab	8254  cdef	8254  400	8255  404-407 	8254*/#define DAS16M1_AI             0	// 16-bit wide register#define   AI_CHAN(x)             ((x) & 0xf)#define DAS16M1_CS             2#define   EXT_TRIG_BIT           0x1#define   OVRUN                  0x20#define   IRQDATA                0x80#define DAS16M1_DIO            3#define DAS16M1_CLEAR_INTR     4#define DAS16M1_INTR_CONTROL   5#define   EXT_PACER              0x2#define   INT_PACER              0x3#define   PACER_MASK             0x3#define   INTE                   0x80#define DAS16M1_QUEUE_ADDR     6#define DAS16M1_QUEUE_DATA     7#define   Q_CHAN(x)              ((x) & 0x7)#define   Q_RANGE(x)             (((x) & 0xf) << 4)#define   UNIPOLAR               0x40#define DAS16M1_8254_FIRST             0x8#define DAS16M1_8254_FIRST_CNTRL       0xb#define   TOTAL_CLEAR                    0x30#define DAS16M1_8254_SECOND            0xc#define DAS16M1_82C55                  0x400#define DAS16M1_8254_THIRD             0x404static comedi_lrange range_das16m1 ={ 9,	{		BIP_RANGE( 5 ),		BIP_RANGE( 2.5 ),		BIP_RANGE( 1.25 ),		BIP_RANGE( 0.625 ),		UNI_RANGE(10),		UNI_RANGE(5),		UNI_RANGE(2.5),		UNI_RANGE(1.25),		BIP_RANGE(10),	}};static int das16m1_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int das16m1_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int das16m1_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);static int das16m1_cmd_test(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);static int das16m1_cmd_exec(comedi_device *dev,comedi_subdevice *s);static int das16m1_cancel(comedi_device *dev, comedi_subdevice *s);static int das16m1_poll(comedi_device *dev, comedi_subdevice *s);static void das16m1_interrupt(int irq, void *d, struct pt_regs *regs);static void das16m1_handler(comedi_device *dev, unsigned int status);static unsigned int das16m1_set_pacer(comedi_device *dev, unsigned int ns, int round_flag);static int das16m1_irq_bits(unsigned int irq);typedef struct das16m1_board_struct{	char *name;	unsigned int ai_speed;}das16m1_board;static das16m1_board das16m1_boards[]={	{	name:		"cio-das16/m1",	// CIO-DAS16_M1.pdf	ai_speed:	1000,		// 1MHz max speed	},};#define das16m1_num_boards ((sizeof(das16m1_boards)) / (sizeof(das16m1_boards[0])))static int das16m1_attach(comedi_device *dev, comedi_devconfig *it);static int das16m1_detach(comedi_device *dev);static comedi_driver driver_das16m1={	driver_name:	"das16m1",	module:		THIS_MODULE,	attach:		das16m1_attach,	detach:		das16m1_detach,	board_name:	das16m1_boards,	num_names:	das16m1_num_boards,	offset:		sizeof(das16m1_boards[0]),};struct das16m1_private_struct {	unsigned int	control_state;	volatile unsigned int	adc_count;	// number of samples completed	/* initial value in lower half of hardware conversion counter,	 * needed to keep track of whether new count has been loaded into	 * counter yet (loaded by first sample conversion) */	u16 initial_hw_count;	sampl_t ai_buffer[ FIFO_SIZE ];	unsigned int do_bits;	// saves status of digital output bits	unsigned int divisor1;	// divides master clock to obtain conversion speed	unsigned int divisor2;	// divides master clock to obtain conversion speed};#define devpriv ((struct das16m1_private_struct *)(dev->private))#define thisboard ((struct das16m1_board_struct *)(dev->board_ptr))COMEDI_INITCLEANUP(driver_das16m1);static inline sampl_t munge_sample( sampl_t data ){	return ( data >> 4 ) & 0xfff;}static int das16m1_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){	unsigned int err=0, tmp, i;	/* make sure triggers are valid */	tmp=cmd->start_src;	cmd->start_src &= TRIG_NOW | TRIG_EXT;	if(!cmd->start_src || tmp!=cmd->start_src) err++;	tmp=cmd->scan_begin_src;	cmd->scan_begin_src &= TRIG_FOLLOW;	if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src) err++;	tmp=cmd->convert_src;	cmd->convert_src &= TRIG_TIMER | TRIG_EXT;	if(!cmd->convert_src || tmp!=cmd->convert_src) err++;	tmp=cmd->scan_end_src;	cmd->scan_end_src &= TRIG_COUNT;	if(!cmd->scan_end_src || tmp!=cmd->scan_end_src) err++;	tmp=cmd->stop_src;	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;	if(!cmd->stop_src || tmp!=cmd->stop_src) err++;	if(err)return 1;	/* step 2: make sure trigger sources are unique and mutually compatible */	if(cmd->stop_src != TRIG_COUNT &&	   cmd->stop_src != TRIG_NONE) err++;	if(cmd->start_src != TRIG_NOW &&	   cmd->start_src != TRIG_EXT) err++;	if(cmd->convert_src != TRIG_TIMER &&	   cmd->convert_src != TRIG_EXT) err++;	if(err)return 2;	/* step 3: make sure arguments are trivially compatible */	if(cmd->start_arg != 0){		cmd->start_arg = 0;		err++;	}	if(cmd->scan_begin_src == TRIG_FOLLOW){		/* internal trigger */		if(cmd->scan_begin_arg != 0){			cmd->scan_begin_arg = 0;			err++;		}	}	if(cmd->convert_src == TRIG_TIMER)	{		if(cmd->convert_arg < thisboard->ai_speed)		{			cmd->convert_arg = thisboard->ai_speed;			err++;		}	}	if(cmd->scan_end_arg != cmd->chanlist_len){		cmd->scan_end_arg = cmd->chanlist_len;		err++;	}	if(cmd->stop_src==TRIG_COUNT){		/* any count is allowed */	}else{		/* TRIG_NONE */		if(cmd->stop_arg!=0){			cmd->stop_arg=0;			err++;		}	}	if(err) return 3;	/* step 4: fix up arguments */	if(cmd->convert_src == TRIG_TIMER)	{		tmp = cmd->convert_arg;		/* calculate counter values that give desired timing */		i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),			&(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);		if(tmp != cmd->convert_arg) err++;	}	if(err) return 4;	// check chanlist against board's peculiarities	if(cmd->chanlist && cmd->chanlist_len > 1)	{		for(i = 0; i < cmd->chanlist_len; i++)		{			// even/odd channels must go into even/odd queue addresses			if((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2))			{				comedi_error(dev, "bad chanlist:\n"					" even/odd channels must go have even/odd chanlist indices");				err++;			}		}		if((cmd->chanlist_len % 2) != 0)		{			comedi_error(dev, "chanlist must be of even length or length 1");			err++;		}	}	if(err) return 5;	return 0;}static int das16m1_cmd_exec(comedi_device *dev,comedi_subdevice *s){	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	unsigned int byte, i;	if(dev->irq == 0)	{		comedi_error(dev, "irq required to execute comedi_cmd");		return -1;	}	/* disable interrupts and internal pacer */	devpriv->control_state &= ~INTE & ~PACER_MASK;	outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);	// set software count	devpriv->adc_count = 0;	/* Initialize lower half of hardware counter, used to determine how	 * many samples are in fifo.  Value doesn't actually load into counter	 * until counter's next clock (the next a/d conversion) */	i8254_load(dev->iobase + DAS16M1_8254_FIRST, 1, 0, 2);	/* remember current reading of counter so we know when counter has	 * actually been loaded */	devpriv->initial_hw_count = i8254_read(dev->iobase + DAS16M1_8254_FIRST, 1);	/* setup channel/gain queue */	for(i = 0; i < cmd->chanlist_len; i++)	{		outb(i, dev->iobase + DAS16M1_QUEUE_ADDR);		byte = Q_CHAN(CR_CHAN(cmd->chanlist[i])) | Q_RANGE(CR_RANGE(cmd->chanlist[i]));		outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);	}	/* set counter mode and counts */	cmd->convert_arg = das16m1_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);	// set control & status register	byte = 0;	/* if we are using external start trigger (also board dislikes having	 * both start and conversion triggers external simultaneously) */	if(cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT)	{		byte |= EXT_TRIG_BIT;	}	outb(byte, dev->iobase + DAS16M1_CS);	/* clear interrupt bit */	outb(0, dev->iobase + DAS16M1_CLEAR_INTR);	/* enable interrupts and internal pacer */	devpriv->control_state &= ~PACER_MASK;	if(cmd->convert_src == TRIG_TIMER)	{		devpriv->control_state |= INT_PACER;	}else	{		devpriv->control_state |= EXT_PACER;	}	devpriv->control_state |= INTE;	outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);	return 0;}static int das16m1_cancel(comedi_device *dev, comedi_subdevice *s){	devpriv->control_state &= ~INTE & ~PACER_MASK;	outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -