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

📄 das1800.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		case TRIG_EXT:			control_a |= TGEN | CGSL;			break;		case TRIG_NOW:			control_a |= CGEN;			break;		default:			break;	}	return control_a;}// returns appropriate bits for control register c, depending on commandstatic int control_c_bits(comedi_cmd cmd){	int control_c;	int aref;	/* set clock source to internal or external, select analog reference,	 * select unipolar / bipolar	 */	aref = CR_AREF(cmd.chanlist[0]);	control_c = UQEN;	//enable upper qram addresses	if(aref != AREF_DIFF)		control_c |= SD;	if(aref == AREF_COMMON)		control_c |= CMEN;	/* if a unipolar range was selected */	if(CR_RANGE(cmd.chanlist[0]) & UNIPOLAR)		control_c |= UB;	switch(cmd.scan_begin_src)	{		case TRIG_FOLLOW:	// not in burst mode			switch(cmd.convert_src)			{				case TRIG_TIMER:					/* trig on cascaded counters */					control_c |= IPCLK;					break;				case TRIG_EXT:					/* trig on falling edge of external trigger */					control_c |= XPCLK;					break;				default:					break;			}			break;		case TRIG_TIMER:			// burst mode with internal pacer clock			control_c |= BMDE | IPCLK;			break;		case TRIG_EXT:			// burst mode with external trigger			control_c |= BMDE | XPCLK;			break;		default:			break;	}	return control_c;}// sets up countersstatic int setup_counters(comedi_device *dev, comedi_cmd cmd){	// setup cascaded counters for conversion/scan frequency	switch(cmd.scan_begin_src)	{		case TRIG_FOLLOW:	// not in burst mode			if(cmd.convert_src == TRIG_TIMER)			{				/* set conversion frequency */				i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2),					&(cmd.convert_arg), cmd.flags & TRIG_ROUND_MASK);				if(das1800_set_frequency(dev) < 0)				{					return -1;				}			}			break;		case TRIG_TIMER:	// in burst mode			/* set scan frequency */			i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2),				&(cmd.scan_begin_arg), cmd.flags & TRIG_ROUND_MASK);			if(das1800_set_frequency(dev) < 0)			{				return -1;			}			break;		default:			break;	}	// setup counter 0 for 'about triggering'	if(cmd.stop_src == TRIG_EXT)	{		// load counter 0 in mode 0		i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, 0);	}	return 0;}// sets up dmastatic void setup_dma(comedi_device *dev, comedi_cmd cmd){	unsigned long lock_flags;	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;	if((devpriv->irq_dma_bits & DMA_ENABLED) == 0)		return;	/* determine a reasonable dma transfer size */	devpriv->dma_transfer_size = suggest_transfer_size(&cmd);	lock_flags = claim_dma_lock();	disable_dma(devpriv->dma0);	/* clear flip-flop to make sure 2-byte registers for	 * count and address get set correctly */	clear_dma_ff(devpriv->dma0);	set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0));	// set appropriate size of transfer	set_dma_count(devpriv->dma0, devpriv->dma_transfer_size);	devpriv->dma_current = devpriv->dma0;	devpriv->dma_current_buf = devpriv->ai_buf0;	enable_dma(devpriv->dma0);	// set up dual dma if appropriate	if(dual_dma)	{		disable_dma(devpriv->dma1);		/* clear flip-flop to make sure 2-byte registers for		 * count and address get set correctly */		clear_dma_ff(devpriv->dma1);		set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1));		// set appropriate size of transfer		set_dma_count(devpriv->dma1, devpriv->dma_transfer_size);		enable_dma(devpriv->dma1);	}	release_dma_lock(lock_flags);	return;}// programs channel/gain list into cardstatic void program_chanlist(comedi_device *dev, comedi_cmd cmd){	int i, n, chan_range;	unsigned long irq_flags;	const int range_mask = 0x3; //masks unipolar/bipolar bit off range	const int range_bitshift = 8;	n = cmd.chanlist_len;	// spinlock protects indirect addressing	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */	outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS);	/*set QRAM address start */	/* make channel / gain list */	for(i = 0; i < n; i++)	{		chan_range = CR_CHAN(cmd.chanlist[i]) | ((CR_RANGE(cmd.chanlist[i]) & range_mask) << range_bitshift);		outw(chan_range, dev->iobase + DAS1800_QRAM);	}	outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS);	/*finish write to QRAM */	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	return;}// analog input do_cmdstatic int das1800_ai_do_cmd(comedi_device *dev, comedi_subdevice *s){	int ret;	int control_a, control_c;	comedi_async *async = s->async;	comedi_cmd cmd = async->cmd;	if(!dev->irq)	{		comedi_error(dev, "no irq assigned for das-1800, cannot do hardware conversions");		return -1;	}	/* disable dma on TRIG_WAKE_EOS, or TRIG_RT	 * (because dma in handler is unsafe at hard real-time priority) */	if(cmd.flags & (TRIG_WAKE_EOS | TRIG_RT))	{		devpriv->irq_dma_bits &= ~DMA_ENABLED;	}else	{		devpriv->irq_dma_bits |= devpriv->dma_bits;	}	// interrupt on end of conversion for TRIG_WAKE_EOS	if(cmd.flags & TRIG_WAKE_EOS)	{		// interrupt fifo not empty		devpriv->irq_dma_bits &= ~FIMD;	}else	{		// interrupt fifo half full		devpriv->irq_dma_bits |= FIMD;	}	// determine how many conversions we need	if(cmd.stop_src == TRIG_COUNT)	{		devpriv->count = cmd.stop_arg * cmd.chanlist_len;	}	das1800_cancel(dev, s);	// determine proper bits for control registers	control_a = control_a_bits(cmd);	control_c = control_c_bits(cmd);	/* setup card and start */	program_chanlist(dev, cmd);	ret = setup_counters(dev, cmd);	if(ret < 0)	{		comedi_error(dev, "Error setting up counters");		return ret;	}	setup_dma(dev, cmd);	outb(control_c, dev->iobase + DAS1800_CONTROL_C);	// set conversion rate and length for burst mode	if(control_c & BMDE)	{		// program conversion period with number of microseconds minus 1		outb(cmd.convert_arg / 1000 - 1, dev->iobase + DAS1800_BURST_RATE);		outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH);	}	outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); // enable irq/dma	outb(control_a, dev->iobase + DAS1800_CONTROL_A);	/* enable fifo and triggering */	outb(CVEN, dev->iobase + DAS1800_STATUS);	/* enable conversions */	return 0;}/* read analog input */static int das1800_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ 	int i, n;	int chan, range, aref, chan_range;	int timeout = 1000;	short dpnt;	int conv_flags = 0;	unsigned long irq_flags;	/* set up analog reference and unipolar / bipolar mode */	aref = CR_AREF(insn->chanspec);	conv_flags |= UQEN;	if(aref != AREF_DIFF)		conv_flags |= SD;	if(aref == AREF_COMMON)		conv_flags |= CMEN;	/* if a unipolar range was selected */	if(CR_RANGE(insn->chanspec) & UNIPOLAR)		conv_flags |= UB;	outb(conv_flags, dev->iobase + DAS1800_CONTROL_C);	/* software conversion enabled */	outb(CVEN, dev->iobase + DAS1800_STATUS);	/* enable conversions */	outb(0x0, dev->iobase + DAS1800_CONTROL_A);	/* reset fifo */	outb(FFEN, dev->iobase + DAS1800_CONTROL_A);	chan = CR_CHAN(insn->chanspec);	/* mask of unipolar/bipolar bit from range */	range = CR_RANGE(insn->chanspec) & 0x3;	chan_range = chan | (range << 8);	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(QRAM, dev->iobase + DAS1800_SELECT);	/* select QRAM for baseAddress + 0x0 */	outb(0x0, dev->iobase + DAS1800_QRAM_ADDRESS);	/* set QRAM address start */	outw(chan_range, dev->iobase + DAS1800_QRAM);	outb(0x0, dev->iobase + DAS1800_QRAM_ADDRESS);	/*finish write to QRAM */	outb(ADC, dev->iobase + DAS1800_SELECT);	/* select ADC for baseAddress + 0x0 */	for(n = 0; n < insn->n; n++)	{		/* trigger conversion */		outb(0, dev->iobase + DAS1800_FIFO);		for(i = 0; i < timeout; i++)		{			if(inb(dev->iobase + DAS1800_STATUS) & FNE)				break;		}		if(i == timeout)		{			comedi_error(dev, "timeout");			return -ETIME;		}		dpnt = inw(dev->iobase + DAS1800_FIFO);		/* shift data to offset binary for bipolar ranges */		if((conv_flags & UB) == 0)			dpnt += 1 << (thisboard->resolution - 1);		data[n] = dpnt;	}	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	return n;}/* writes to an analog output channel */static int das1800_ao_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	int chan = CR_CHAN(insn->chanspec);//	int range = CR_RANGE(insn->chanspec);	int update_chan = thisboard->ao_n_chan - 1;	short output;	unsigned long irq_flags;	//  card expects two's complement data	output = data[0] - (1 << (thisboard->resolution - 1));	// if the write is to the 'update' channel, we need to remember its value	if(chan == update_chan)		devpriv->ao_update_bits = output;	// write to channel	comedi_spin_lock_irqsave(&dev->spinlock, irq_flags);	outb(DAC(chan), dev->iobase + DAS1800_SELECT); /* select dac channel for baseAddress + 0x0 */	outw(output, dev->iobase + DAS1800_DAC);	// now we need to write to 'update' channel to update all dac channels	if(chan != update_chan)	{		outb(DAC(update_chan), dev->iobase + DAS1800_SELECT); /* select 'update' channel for baseAddress + 0x0 */		outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC);	}	comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags);	return 1;}/* reads from digital input channels */static int das1800_di_rbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	data[1] = inb(dev->iobase + DAS1800_DIGITAL) & 0xf;	data[0] = 0;	return 2;}/* writes to digital output channels */static int das1800_do_wbits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){	lsampl_t wbits;	// only set bits that have been masked	data[0] &= (1 << s->n_chan) - 1;	wbits = devpriv->do_bits;	wbits &= ~data[0];	wbits |= data[0] & data[1];	devpriv->do_bits = wbits;	outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL);	data[1] = devpriv->do_bits;	return 2;}/* loads counters with divisor1, divisor2 from private structure */static int das1800_set_frequency(comedi_device *dev){	int err = 0;	// counter 1, mode 2	if(i8254_load(dev->iobase + DAS1800_COUNTER, 1, devpriv->divisor1, 2)) err++;	// counter 2, mode 2	if(i8254_load(dev->iobase + DAS1800_COUNTER, 2, devpriv->divisor2, 2)) err++;	if(err)		return -1;	return 0;}/* converts requested conversion timing to timing compatible with * hardware, used only when card is in 'burst mode' */static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode){	unsigned int micro_sec;	// in burst mode, the maximum conversion time is 64 microseconds	if(convert_arg > 64000)		convert_arg = 64000;	// the conversion time must be an integral number of microseconds	switch(round_mode)	{		case TRIG_ROUND_NEAREST:		default:			micro_sec = (convert_arg + 500) / 1000;			break;		case TRIG_ROUND_DOWN:			micro_sec = convert_arg / 1000;			break;		case TRIG_ROUND_UP:			micro_sec = (convert_arg - 1) / 1000 + 1;			break;	}	// return number of nanoseconds	return micro_sec * 1000;}// utility function that suggests a dma transfer size based on the conversion period 'ns'static unsigned int suggest_transfer_size(comedi_cmd *cmd){	unsigned int size = DMA_BUF_SIZE;	static const int sample_size = 2;	// size in bytes of one sample from board	unsigned int fill_time = 300000000;	// target time in nanoseconds for filling dma buffer	unsigned int max_size;	// maximum size we will allow for a transfer	// make dma buffer fill in 0.3 seconds for timed modes	switch(cmd->scan_begin_src)	{		case TRIG_FOLLOW:	// not in burst mode			if(cmd->convert_src == TRIG_TIMER)				size = (fill_time / cmd->convert_arg) * sample_size;			break;		case TRIG_TIMER:			size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) * sample_size;			break;		default:			size = DMA_BUF_SIZE;			break;	}	// set a minimum and maximum size allowed	max_size = DMA_BUF_SIZE;	// if we are taking limited number of conversions, limit transfer size to that	if(cmd->stop_src == TRIG_COUNT &&		cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)		max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;	if(size > max_size)		size = max_size;	if(size < sample_size)		size = sample_size;	return size;}

⌨️ 快捷键说明

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