Added support for calibration pwm output used for nonlinearity calibration
authorFrank Mori Hess <fmhess@speakeasy.net>
Sun, 8 Jan 2006 16:37:27 +0000 (16:37 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Sun, 8 Jan 2006 16:37:27 +0000 (16:37 +0000)
of m-series boards.

Documentation/comedi/insn_config
comedi/drivers/ni_mio_common.c
comedi/drivers/ni_stc.h
include/linux/comedi.h

index 5c2103fcf4d8908d30148ebaf55bbb75fe662733..9a2b60e3f405eccb7967f597128a2fafdb7a70df 100644 (file)
@@ -85,8 +85,6 @@ ID=xxx: set software gate
   [1] - set/clear gate
 
 
-
-
 Applications:
 
  - Pulse counting:
@@ -167,13 +165,13 @@ Applications:
 
     invert output on gate?primary:secondary source trigger
 
-  -
 
 ID=INSN_CONFIG_ALT_SOURCE: select alternate input source (internal calibration reference)
 
   [0] - ID
   [1] - source
 
+  
 ID=INSN_CONFIG_TIMER_1: Configure an external master clock and divisor
        to divide clock by.  Used with commands by setting scan_begin_src or
        convert_src set to TRIG_OTHER.
@@ -183,3 +181,12 @@ ID=INSN_CONFIG_TIMER_1: Configure an external master clock and divisor
   [2] - primary input chanspec (also specifies polarity and edge/level )
   [3] - primary combining machine configuration (should always be 0x04)
   [4] - divisor
+
+  
+ID=INSN_CONFIG_PWM_OUTPUT: Configure a pulse-width-modulation output.  Returns
+       EAGAIN error with modified values if exact timing is not achievable.
+
+       [0] - ID
+       [1] - flags (rounding mode for up/down times: TRIG_ROUND_NEAREST, etc.)
+       [2] - up time (nanoseconds)
+       [3] - down time (nanoseconds)
index 7e05e3a0ef9b033b7333da858a88f052c360acfa..5eebad0ba90788ff483cfd93fe7e195ddd184a48 100644 (file)
@@ -274,6 +274,9 @@ static int cs5529_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_ins
 static unsigned int cs5529_config_read(comedi_device *dev, unsigned int reg_select_bits);
 static void cs5529_config_write(comedi_device *dev, unsigned int value, unsigned int reg_select_bits);
 
+static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
+       
 enum aimodes
 {
        AIMODE_NONE = 0,
@@ -2975,11 +2978,22 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        /* calibration subdevice -- ai and ao */
        s=dev->subdevices+5;
        s->type=COMEDI_SUBD_CALIB;
-       s->subdev_flags=SDF_WRITABLE|SDF_INTERNAL;
-       s->insn_read=ni_calib_insn_read;
-       s->insn_write=ni_calib_insn_write;
-       caldac_setup(dev,s);
-
+       if(boardtype.reg_type == ni_reg_m_series)
+       {
+               // internal PWM analog output used for AI nonlinearity calibration
+               s->subdev_flags = SDF_INTERNAL;
+               s->insn_config = &ni_m_series_pwm_config;
+               s->n_chan = 1;
+               s->maxdata = 0;
+               ni_writel(0x0, M_Offset_Cal_PWM);
+       }else
+       {
+               s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
+               s->insn_read = &ni_calib_insn_read;
+               s->insn_write = &ni_calib_insn_write;
+               caldac_setup(dev, s);
+       }
+       
        /* EEPROM */
        s=dev->subdevices+6;
        s->type=COMEDI_SUBD_MEMORY;
@@ -3155,6 +3169,48 @@ static int ni_m_series_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,
        return 1;
 }
 
+static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       unsigned up_count, down_count;
+       switch(data[0])
+       {
+       case INSN_CONFIG_PWM_OUTPUT:
+               switch(data[1])
+               {
+               case TRIG_ROUND_NEAREST:
+                       up_count = (data[2] + TIMER_BASE / 2) / TIMER_BASE; 
+                       down_count = (data[3] + TIMER_BASE / 2) / TIMER_BASE;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       up_count = data[2] / TIMER_BASE;
+                       down_count = data[3] / TIMER_BASE;
+                       break;
+               case TRIG_ROUND_UP:
+                       up_count = (data[2] + TIMER_BASE - 1) / TIMER_BASE;
+                       down_count = (data[3] + TIMER_BASE - 1) / TIMER_BASE;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               if(up_count * TIMER_BASE != data[2] ||
+                       down_count * TIMER_BASE != data[3])
+               {
+                       data[2] = up_count * TIMER_BASE;
+                       data[3] = down_count * TIMER_BASE;
+                       return -EAGAIN;
+               }
+               ni_writel(MSeries_Cal_PWM_High_Time_Bits(up_count) | MSeries_Cal_PWM_Low_Time_Bits(down_count), M_Offset_Cal_PWM);
+               return 4;
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
 static void ni_write_caldac(comedi_device *dev,int addr,int val);
 /*
        calibration subdevice
index f877677799e11119c42732d9313c85523b37a0c5..b63b229ba686825e769498a5feeebf1ffa1fe4c6 100644 (file)
@@ -1005,6 +1005,16 @@ enum MSeries_AO_Reference_Attenuation_Bits
        MSeries_Attenuate_x5_Bit = 0x1
 };
 
+static inline unsigned MSeries_Cal_PWM_High_Time_Bits(unsigned count)
+{
+       return (count << 16) & 0xffff0000;
+}
+
+static inline unsigned MSeries_Cal_PWM_Low_Time_Bits(unsigned count)
+{
+       return count & 0xffff;
+}
+
 #define M_SERIES_EEPROM_SIZE 1024
 
 typedef struct ni_board_struct{
index 991c794ed2451ed721447d6ff6ad4c685fbef062..3a69261f34e556b5f3a83d82c8462e7297c7d249 100644 (file)
@@ -237,6 +237,7 @@ enum configuration_ids
        INSN_CONFIG_SERIAL_CLOCK = 26,
        INSN_CONFIG_BIDIRECTIONAL_DATA = 27,
        INSN_CONFIG_DIO_QUERY = 28,
+       INSN_CONFIG_PWM_OUTPUT = 29,
        INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, // Use CTR as single pulsegenerator
        INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, // Use CTR as pulsetraingenerator
        INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, // Use the counter as encoder