📄 ni_mio_common.c
字号:
if(cmd->scan_begin_src==TRIG_TIMER){ tmp=cmd->scan_begin_arg; ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->scan_begin_arg)err++; } if(cmd->convert_src==TRIG_TIMER){ if( boardtype.reg_611x == 0){ tmp=cmd->convert_arg; ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->convert_arg)err++; if(cmd->scan_begin_src==TRIG_TIMER && cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){ cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg; err++; } } } if(err)return 4; return 0;}static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s){ comedi_cmd *cmd=&s->async->cmd; int timer; int mode1=0; /* mode1 is needed for both stop and convert */ int mode2=0; int start_stop_select=0; unsigned int stop_count; int interrupt_a_enable=0; MDPRINTK("ni_ai_cmd\n"); win_out(1,ADC_FIFO_Clear); ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist); /* start configuration */ win_out(AI_Configuration_Start,Joint_Reset_Register); switch(cmd->start_src){ case TRIG_INT: case TRIG_NOW: win_out(AI_START2_Select(0)| AI_START1_Sync|AI_START1_Edge|AI_START1_Select(0), AI_Trigger_Select_Register); break; case TRIG_EXT: { int chan = CR_CHAN(cmd->start_arg); win_out(AI_START2_Select(0)| AI_START1_Sync | AI_START1_Edge | AI_START1_Select(chan + 1), AI_Trigger_Select_Register); break; } } mode2 &= ~AI_Pre_Trigger; mode2 &= ~AI_SC_Initial_Load_Source; mode2 &= ~AI_SC_Reload_Mode; win_out(mode2, AI_Mode_2_Register); start_stop_select |= AI_STOP_Sync; if( boardtype.reg_611x ){ start_stop_select |= AI_STOP_Polarity; start_stop_select |= AI_STOP_Select( 31 ); }else{ start_stop_select |= AI_STOP_Select( 19 ); } win_out(start_stop_select, AI_START_STOP_Select_Register); devpriv->ai_cmd2 = 0; switch(cmd->stop_src){ case TRIG_COUNT: stop_count = cmd->stop_arg - 1; if( boardtype.reg_611x ){ // have to take 3 stage adc pipeline into account stop_count += num_adc_stages_611x; } /* stage number of scans */ win_out2( stop_count, AI_SC_Load_A_Registers); mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once; win_out(mode1,AI_Mode_1_Register); /* load SC (Scan Count) */ win_out(AI_SC_Load,AI_Command_1_Register); devpriv->ai_continuous = 0; if( stop_count == 0 ){ devpriv->ai_cmd2 |= AI_End_On_End_Of_Scan; interrupt_a_enable|=AI_STOP_Interrupt_Enable; } break; case TRIG_NONE: /* stage number of scans */ win_out(0,AI_SC_Load_A_Registers); win_out(0,AI_SC_Load_A_Registers+1); mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous; win_out(mode1,AI_Mode_1_Register); /* load SC (Scan Count) */ win_out(AI_SC_Load,AI_Command_1_Register); devpriv->ai_continuous = 1; break; } switch(cmd->scan_begin_src){ case TRIG_TIMER: /* stop bits for non 611x boards AI_SI_Special_Trigger_Delay=0 AI_Pre_Trigger=0 AI_START_STOP_Select_Register: AI_START_Polarity=0 (?) rising edge AI_START_Edge=1 edge triggered AI_START_Sync=1 (?) AI_START_Select=0 SI_TC AI_STOP_Polarity=0 rising edge AI_STOP_Edge=0 level AI_STOP_Sync=1 AI_STOP_Select=19 external pin (configuration mem) */ start_stop_select |= AI_START_Edge | AI_START_Sync; win_out(start_stop_select, AI_START_STOP_Select_Register); mode2 |= AI_SI_Reload_Mode(0); /* AI_SI_Initial_Load_Source=A */ mode2 &= ~AI_SI_Initial_Load_Source; //mode2 |= AI_SC_Reload_Mode; win_out(mode2, AI_Mode_2_Register); /* load SI */ timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST); win_out2(timer,AI_SI_Load_A_Registers); win_out(AI_SI_Load,AI_Command_1_Register); break; case TRIG_EXT:/* Level trigger usually doesn't work, making it the default * doesn't make sense. Disabling it. *//* if( cmd->scan_begin_arg & CR_EDGE ) */ start_stop_select |= AI_START_Edge; /* AI_START_Polarity==1 is falling edge */ if( cmd->scan_begin_arg & CR_INVERT ) start_stop_select |= AI_START_Polarity; if( cmd->scan_begin_src != cmd->convert_src || ( cmd->scan_begin_arg & ~CR_EDGE ) != ( cmd->convert_arg & ~CR_EDGE ) ) start_stop_select |= AI_START_Sync; start_stop_select |= AI_START_Select(1+(cmd->scan_begin_arg&0xf)); win_out(start_stop_select, AI_START_STOP_Select_Register); break; } switch(cmd->convert_src){ case TRIG_TIMER: case TRIG_NOW: if( cmd->convert_arg == 0 || cmd->convert_src == TRIG_NOW ) timer = 1; else timer=ni_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST); win_out(1,AI_SI2_Load_A_Register); /* 0,0 does not work. */ win_out(timer,AI_SI2_Load_B_Register); /* AI_SI2_Reload_Mode = alternate */ /* AI_SI2_Initial_Load_Source = A */ mode2 &= ~AI_SI2_Initial_Load_Source; mode2 |= AI_SI2_Reload_Mode; win_out( mode2, AI_Mode_2_Register); /* AI_SI2_Load */ win_out(AI_SI2_Load,AI_Command_1_Register); mode2 |= AI_SI2_Reload_Mode; // alternate mode2 |= AI_SI2_Initial_Load_Source; // B win_out(mode2,AI_Mode_2_Register); break; case TRIG_EXT: mode1 |= AI_CONVERT_Source_Select(1+cmd->convert_arg); if( ( cmd->convert_arg & CR_INVERT ) == 0 ) mode1 |= AI_CONVERT_Source_Polarity; win_out(mode1,AI_Mode_1_Register); mode2 |= AI_Start_Stop_Gate_Enable | AI_SC_Gate_Enable; win_out(mode2, AI_Mode_2_Register); break; } if(dev->irq){ /* interrupt on FIFO, errors, SC_TC */ interrupt_a_enable |= AI_Error_Interrupt_Enable| AI_SC_TC_Interrupt_Enable;#ifndef PCIDMA interrupt_a_enable|=AI_FIFO_Interrupt_Enable;#endif if(s->async->cb_mask&COMEDI_CB_EOS){ /* wake on end-of-scan */ devpriv->aimode=AIMODE_SCAN; }else{ devpriv->aimode=AIMODE_HALF_FULL; } switch(devpriv->aimode){ case AIMODE_HALF_FULL: /*generate FIFO interrupts and DMA requests on half-full */#ifdef PCIDMA win_out(AI_FIFO_Mode_HF_to_E, AI_Mode_3_Register);#else win_out(AI_FIFO_Mode_HF, AI_Mode_3_Register);#endif break; case AIMODE_SAMPLE: /*generate FIFO interrupts on non-empty */ win_out(AI_FIFO_Mode_NE, AI_Mode_3_Register); break; case AIMODE_SCAN:#ifdef PCIDMA win_out(AI_FIFO_Mode_NE, AI_Mode_3_Register);#else win_out(AI_FIFO_Mode_HF, AI_Mode_3_Register);#endif interrupt_a_enable|=AI_STOP_Interrupt_Enable; break; default: break; } win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */ ni_set_bits(dev, Interrupt_A_Enable_Register, interrupt_a_enable, 1); MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n",devpriv->int_a_enable_reg); }else{ /* interrupt on nothing */ ni_set_bits(dev, Interrupt_A_Enable_Register, ~0, 0); /* XXX start polling if necessary */ MDPRINTK("interrupting on nothing\n"); } /* end configuration */ win_out(AI_Configuration_End,Joint_Reset_Register); switch(cmd->scan_begin_src){ case TRIG_TIMER: win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm, AI_Command_1_Register); break; case TRIG_EXT: /* XXX AI_SI_Arm? */ win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm, AI_Command_1_Register); break; }#ifdef PCIDMA ni_ai_setup_MITE_dma(dev,cmd); //mite_dump_regs(devpriv->mite);#endif switch(cmd->start_src){ case TRIG_NOW: /* AI_START1_Pulse */ win_out( AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register ); s->async->inttrig=NULL; break; case TRIG_EXT: s->async->inttrig=NULL; break; case TRIG_INT: s->async->inttrig=ni_ai_inttrig; break; } MDPRINTK("exit ni_ai_cmd\n"); return 0;}static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s, unsigned int trignum){ if(trignum!=0)return -EINVAL; win_out( AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register ); s->async->inttrig=NULL; return 1;}static int ni_ai_config_analog_trig(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);static int ni_ai_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ if(insn->n<1)return -EINVAL; switch(data[0]){ case INSN_CONFIG_ANALOG_TRIG: return ni_ai_config_analog_trig(dev,s,insn,data); case INSN_CONFIG_ALT_SOURCE: { unsigned int calib_source; unsigned int calib_source_adjust; calib_source = data[1] & 0xf; calib_source_adjust = ( data[1] >> 4 ) & 0xff; if(calib_source >= 8) return -EINVAL; devpriv->ai_calib_source = calib_source; if( boardtype.reg_611x ){ ni_writeb( calib_source_adjust, Cal_Gain_Select_611x ); } return 2; } } return -EINVAL;}static int ni_ai_config_analog_trig(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ unsigned int a,b,modebits; int err=0; /* data[1] is flags * data[2] is analog line * data[3] is set level * data[4] is reset level */ if(!boardtype.has_analog_trig)return -EINVAL; if(insn->n!=5)return -EINVAL; if((data[1]&0xffff0000) != COMEDI_EV_SCAN_BEGIN){ data[1]&=~(COMEDI_EV_SCAN_BEGIN&0xffff); err++; } if(data[2]>=boardtype.n_adchan){ data[2]=boardtype.n_adchan-1; err++; } if(data[3]>255){ /* a */ data[3]=255; err++; } if(data[4]>255){ /* b */ data[4]=255; err++; } /* * 00 ignore * 01 set * 10 reset * * modes: * 1 level: +b- +a- * high mode 00 00 01 10 * low mode 00 00 10 01 * 2 level: (a<b) * hysteresis low mode 10 00 00 01 * hysteresis high mode 01 00 00 10 * middle mode 10 01 01 10 */ a=data[3]; b=data[4]; modebits=data[1]&0xff; if(modebits&0xf0){ /* two level mode */ if(b<a){ /* swap order */ a=data[4]; b=data[3]; modebits=((data[1]&0xf)<<4)|((data[1]&0xf0)>>4); } devpriv->atrig_low = a; devpriv->atrig_high = b; switch(modebits){ case 0x81: /* low hysteresis mode */ devpriv->atrig_mode = 6; break; case 0x42: /* high hysteresis mode */ devpriv->atrig_mode = 3; break; case 0x96: /* middle window mode */ devpriv->atrig_mode = 2; break; default: data[1]&=~0xff; err++; } }else{ /* one level mode */ if(b!=0){ data[4]=0; err++; } switch(modebits){ case 0x06: /* high window mode */ devpriv->atrig_high = a; devpriv->atrig_mode = 0; break; case 0x09: /* low window mode */ devpriv->atrig_low = a; devpriv->atrig_mode = 1; break; default: data[1]&=~0xff; err++; } } if(err)return -EAGAIN; return 5;}/* munge data from unsigned to 2's complement for analog output bipolar modes */static void ni_ao_munge(comedi_device *dev, comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index ){ comedi_async *async = s->async; unsigned int range; unsigned int i; unsigned int offset; unsigned int length = num_bytes / sizeof( sampl_t ); sampl_t *array = data; offset = 1 << (boardtype.aobits - 1); for(i = 0; i < length; i++) { range = CR_RANGE( async->cmd.chanlist[ chan_index ] ); if(boardtype.ao_unipolar == 0 || (range & 1) == 0 ) array[i] -= offset;#ifdef PCIDMA array[i] = __cpu_to_le16( array[i] );#endif chan_index++; chan_index %= async->cmd.chanlist_len; }}static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s, unsigned int chanspec[], unsigned int n_chans){ unsigned int range; unsigned int chan; unsigned int conf; int i, bits; int invert = 0; if( boardtype.reg_611x ){ ao_win_out( CLEAR_WG, AO_Misc_611x); bits = 0; for(i = 0; i < n_chans; i++){ chan = CR_CHAN( chanspec[i] ); bits |= 1 << chan; ao_win_out( chan, AO_Waveform_Generation_611x); } ao_win_out(bits, AO_Timed_611x); }else{ for(i=0;i<n_chans;i++){ chan = CR_CHAN(chanspec[i]); range = CR_RANGE(chanspec[i]); conf = AO_Channel(chan); if(boardtype.ao_unipolar){ if((range&1) == 0){ conf |= AO_Bipolar; invert = (1<<(boardtype.aobits-1)); }else{ invert = 0; } if(range&2) conf |= AO_Ext_Ref; }else{ conf |= AO_Bipolar; invert = (1<<(boardtype.aobits-1)); } /* not all boards can deglitch, but this shouldn't hurt */ if(chanspec[i] & CR_DEGLITCH) conf |= AO_Deglitch; /* analog reference */ /* AREF_OTHER connects AO ground to AI ground, i think */ conf |= (CR_AREF(chanspec[i])==AREF_OTHER)? AO_Ground_Ref : 0; devpriv->ao_conf[chan] = conf; ni_writew(conf,AO_Configuration); } } return invert;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -