--- /dev/null
+#!/usr/bin/env python
+
+import usbio
+
+
+#
+# devboard conversion constants
+#
+#VREF = 2.5 #output of DAC Vref generator
+
+# Supply current sense circuitry
+RS = { 'Vdd_ns430': 1.0,
+ 'DVdd_ns430': 100.0,
+ 'Vdd_digi': 1.0,
+ 'AVdd_atoi': 20.0 }
+
+IPS_CH = { 'Vdd_ns430': 0,
+ 'DVdd_ns430': 1,
+ 'Vdd_digi': 0,
+ 'AVdd_atoi': 1 }
+
+PGA = { 'Vdd_ns430': 1.0,
+ 'DVdd_ns430': 1.0,
+ 'Vdd_digi': 1.0,
+ 'AVdd_atoi': 1.0 }
+
+GM = { 'Vdd_ns430': 5e-6/1e-3,
+ 'DVdd_ns430': 5e-6/1e-3,
+ 'Vdd_digi': 5e-6/1e-3,
+ 'AVdd_atoi': 5e-6/1e-3 }
+
+RG = { 'Vdd_ns430': 10e3,
+ 'DVdd_ns430': 10e3,
+ 'Vdd_digi': 10e3,
+ 'AVdd_atoi': 10e3 }
+
+
+
+def count2volt(c, warn=True):
+ """Properly handle 14-b data from 12b ADC value. Average bits
+ originate from 12b samples, so max value is 0xfff0 NOT 0xfffc.
+ """
+ if warn and c >= 0xfff0:
+ print 'WARNING: clipped ADC value'
+ return dac.VREF * (((c >> 0) / 16.0) / 2**12)
+
+
+def ips(name, count, warn=True):
+ """For a given measurement name, take the ADC count and return the
+ corresponding supply current in A.
+ """
+ return ((count2volt(count, warn) / PGA[name]) /
+ (GM[name] * RG[name] * RS[name]))
+
+
+def isupply_resolution(printit=False):
+ """Return the supply current maximum measurable values and LSB
+ resolutions. Optionally print to stdout.
+ """
+ r = {}
+ if printit:
+ print
+ print 'PS current sense max / resolution:'
+ for name in RS.keys():
+ imax = ips(name, 0x10000, False)
+ ires = imax/2**12
+ r[name] = [imax, ires]
+ if printit:
+ print 'Max current: %-10s %8.2f uA / %5.2f uA' % (
+ name, 1e6*imax, 1e6*ires)
+
+
+def meas_isupply():
+ """Return a dict of measured power supply currents.
+ """
+ result = {}
+
+ # ensure IRQ pin is an input
+ PIN_IRQ = 2
+ i2c.set_pindir(i2c.io & ~(1 << PIN_IRQ))
+
+ # ADC global setup
+ adc.reset()
+ adc.triggerMode(adc.MODE_IDLE)
+ adc.channelMode(0, adc.SE)
+ adc.average(16)
+ adc.convst_spi(1)
+
+ # 430-specific settings
+ for name in ('Vdd_ns430', 'DVdd_ns430'):
+ adc.channelGain(IPS_CH[name], PGA[name])
+
+ # select 430 outputs, give time to settle
+ vatoi.gpo1 = 0
+ v430.gpo1 = 1
+ sleep(1e-3)
+
+ # convert the two 430 results
+ adc.triggerMode(adc.MODE_MANUAL_MANUAL)
+ for name in ('Vdd_ns430', 'DVdd_ns430'):
+ adc.mux(IPS_CH[name])
+ adc.read()
+ result[name] = ips(name, adc.read())
+
+ # atoi-specific settings
+ for name in ('Vdd_digi', 'AVdd_atoi'):
+ adc.channelGain(IPS_CH[name], PGA[name])
+
+ # select atoi outputs, give time to settle
+ v430.gpo1 = 0
+ vatoi.gpo1 = 1
+ sleep(1e-3)
+
+ #get the two results
+ for name in ('Vdd_digi', 'AVdd_atoi'):
+ adc.mux(IPS_CH[name])
+ adc.read()
+ result[name] = ips(name, adc.read())
+
+ return result
+
+
+def dump_config():
+ """Return a hierarchical dict of settings appropriate for passing to the
+ individual constructors.
+ """
+ s = {}
+ # configuration
+ # chip SPI config
+ s['chain'] = chain.dump_config()
+ s['mux'] = mux.dump_config()
+ s['arb'] = arb.dump_config()
+ s['amux'] = amux.dump_config()
+ # power supply / bias Rpots
+ s['vatoi'] = vatoi.dump_config()
+ s['v430'] = v430.dump_config()
+ s['ibias'] = ibias.dump_config()
+ # interface busses
+ s['spi0'] = spi0.dump_config()
+ s['spi1'] = spi1.dump_config()
+ s['i2c'] = i2c.dump_config()
+
+ # current information
+ s['date'] = dt.now().strftime('%Y-%m-%d_%H:%M:%S')
+ s['isupply'] = meas_isupply()
+ return s
+
+
+def save_config(name=None):
+ """Write current config to a file.
+ """
+ cfg = dump_config()
+ if name is None:
+ name = 'config.%s.yaml' % cfg['date']
+ yaml.dump(cfg, open(name, 'wb'))
+ return cfg
+
+
+#
+# Module-level names. Define here so they are found in the module scope
+#
+spi0 = None
+spi1 = None
+i2c = None
+ibias = None
+vatoi = None
+v430 = None
+dac = None
+adc = None
+chain = None
+mux = None
+arb = None
+amux = None
+
+def init_devboard(name='devboard-defaults.yaml'):
+ try:
+ load_config(name)
+ return
+ except:
+ print 'WARNING: could not find "%s", using built-in defaults' % name
+
+ # No defaults available, fallback on object-level defaults
+ psdefaults()
+
+ ##############################################################################
+ # Setup FTDI serial ports
+ spi0 = usbio.AtoiSPI0(1000e3) #port A
+ spi1 = usbio.AtoiSPI1(1000e3) #port B
+ i2c = usbio.I2C(interface=usbio.ftdi.INTERFACE_C, scl=0, sda=1,
+ vid=0x0403, pid=0x6011, delay=100e-6)
+
+ ##############################################################################
+ # Analog bias
+ # (bias generator also uses DAC_1 and DAC_3,
+ # need to make a wrapper class to do e.g. ibias.buf = 10 uA)
+ ibias = usbio.AD524x(i2c, 0)
+
+ ##############################################################################
+ # Power supplies
+ vatoi = usbio.DigiReg(i2c, 2, (0.5015, 1.3887), (1.9552, 2.8304))
+ vatoi.alias('va', 'vdigi')
+ vatoi.alias('vb', 'avdd')
+
+ v430 = usbio.DigiReg(i2c, 3, (1.9535, 2.7137), (0.5013, 1.2617))
+ v430.alias('va', 'dvdd')
+ v430.alias('vb', 'vdd')
+
+ ##############################################################################
+ # DAC
+ # default mode is dac.INPUT_UPDATE_SINGLE
+ dac = usbio.DAC_atoi(spi0, 'dac')
+
+ VCM = 1.2500 # multimeter says 0.0 mV between ref/2 and vcmi(VCM)
+ dac.vcmi(VCM)
+ dac.vina(VCM)
+ dac.vinb(VCM)
+ dac.vbias_core(000e-3)
+ dac.vbias_buf(000e-3)
+
+ ##############################################################################
+ # ADC
+ # (TODO: see 'ADC testing stuff' section below)
+ adc = usbio.ADS8201(spi0)
+
+ ##############################################################################
+ # AtoI digital SPI config
+ # jumper on devboard accesses MISO for each chain
+ chain = usbio.Chain(spi1, 'chain0_conf', length=48)
+ mux = usbio.Mux(spi1, 'chain0_mux')
+
+ # MISO is not available
+ arb = usbio.Chain(spi1, 'chain1_conf', length=16)
+ amux = usbio.Mux(spi1, 'chain1_mux')
+
+
+
+def load_config(name):
+ """Given a dict or a filename containing a yaml dump of settings, load them
+ and (re-)initialize all components.
+ """
+ if isinstance(name, dict):
+ cfg = name
+ else:
+ cfg = yaml.load(name)
+
+ ##########################################################################
+ # Setup FTDI serial ports
+ spi0 = usbio.AtoiSPI0(**cfg['spi0'])
+ spi1 = usbio.AtoiSPI1(**cfg['spi1'])
+ i2c = usbio.I2C(**cfg['i2c'])
+
+ ##########################################################################
+ # Analog bias
+ # (bias generator also uses DAC_1 and DAC_3,
+ # need to make a wrapper class to do e.g. ibias.buf = 10 uA)
+ ibias = usbio.AD524x(i2c, **cfg['ibias'])
+
+ ##########################################################################
+ # Power supplies
+ vatoi = usbio.DigiReg(i2c, **cfg['vatoi'])
+ #vatoi = usbio.DigiReg(i2c, 2, (0.5015, 1.3887), (1.9552, 2.8304))
+ #vatoi.alias('va', 'vdigi')
+ #vatoi.alias('vb', 'avdd')
+
+ v430 = usbio.DigiReg(i2c, **cfg['vatoi'])
+ #v430 = usbio.DigiReg(i2c, 3, (1.9535, 2.7137), (0.5013, 1.2617))
+ #v430.alias('va', 'dvdd')
+ #v430.alias('vb', 'vdd')
+
+
+ ##########################################################################
+ # DAC
+ # default mode is dac.INPUT_UPDATE_SINGLE
+ dac = usbio.DAC_atoi(spi0, **cfg['dac'])
+ #VCM = 1.2500 # multimeter says 0.0 mV between ref/2 and vcmi(VCM)
+ #dac.vcmi(VCM)
+ #dac.vina(VCM)
+ #dac.vinb(VCM)
+ #dac.vbias_core(000e-3)
+ #dac.vbias_buf(000e-3)
+
+ ##########################################################################
+ # ADC
+ # (TODO: see 'ADC testing stuff' section below)
+ adc = usbio.ADS8201(spi0)
+
+ ##########################################################################
+ # AtoI digital SPI config
+ # jumper on devboard accesses MISO for each chain
+ chain = usbio.Chain(spi1, **cfg['chain'])
+ mux = usbio.Mux(spi1, **cfg['mux'])
+ #chain = usbio.Chain(spi1, 'chain0_conf', length=48)
+ #mux = usbio.Mux(spi1, 'chain0_mux')
+
+ # MISO is not available
+ arb = usbio.Chain(spi1, **cfg['arb'])
+ amux = usbio.Mux(spi1, **cfg['amux'])
+ #arb = usbio.Chain(spi1, 'chain1_conf', length=16)
+ #amux = usbio.Mux(spi1, 'chain1_mux')
+
+
+
+# define power supply defaults
+def psdefaults():
+ vatoi.vdigi = 1.2
+ v430.vdd = 1.2
+ vatoi.avdd = 2.5
+ v430.dvdd = 2.5
+
+
+
+