From: Dan White Date: Tue, 8 May 2012 18:22:23 +0000 (-0500) Subject: Fill ADC class functionality X-Git-Tag: calibrations~84 X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=31feb06ab30aed233c23c7460c5b70a8776c1521;p=430.git Fill ADC class functionality --- diff --git a/python-lib/usbio.py b/python-lib/usbio.py index c9e1a6d..3796007 100644 --- a/python-lib/usbio.py +++ b/python-lib/usbio.py @@ -5,6 +5,7 @@ from time import sleep import ftdi import mpsse +from math import log from myhdl import intbv from myhdl import bin as b @@ -38,6 +39,9 @@ from myhdl import bin as b # 7..0 - offset +def log2(x): + return log(x) / log(2) + def truth(v): if isinstance(v, (int, intbv)): # NB: ~True == -2 @@ -826,7 +830,11 @@ class DAC8568(object): self._word[4:0] = intbv(value, max=2**4) + + class ADS8201(object): + """Configures and operates an ADS8201 over the given SPI bus.""" + # register addresses CH01_CCR = 0 CH23_CCR = 1 CH45_CCR = 2 @@ -842,11 +850,23 @@ class ADS8201(object): def __init__(self, spibus): self.bus = spibus + #channel registers are paired + #MUST set these values as _ch[n][a:b] + #this assigns values to bit positions within the created intbv, + # this keeps ch0/1, ch2/3, etc the same object + self._ch = [] + for i in (0, 2, 4, 6): + self._ch.append(intbv(0)[8:]) + self._ch.append(self._ch[-1]) + + self._ADC_SCR = intbv(0)[8:] + self._INT_SCR = intbv(0)[8:] + self._TRIGGER_SCR = intbv(0)[8:] + def setRegister(self, address, value): w = intbv(0x8000)[16:] w[14:10] = intbv(address, max=2**4) w[8:] = intbv(value, max=2**8) - #print 'sending:', b(w, 16) self.bus.SetCS('adc') self.bus.Start() self.bus.Write(int2str(w, 16)) @@ -862,14 +882,148 @@ class ADS8201(object): rval = self.bus.Exchange(int2str(w, 16)) sleep(1e-3) self.bus.Stop() - i = 8 * (len(rval)-1) - r = 0 - for c in rval: - r += ord(c) << i - i -= 8 - return r + #i = 8 * (len(rval)-1) + #r = 0 + #for c in rval: + #r += ord(c) << i + #i -= 8 + #return r + # first byte is xxx00000, second is data + return ord(rval[1]) + + # + # ADC_SCR configuration + # + def channelGain(self, channel, gain): + """Set channel PGA gain to one of 1, 2, 4, or 8.""" + g = int(gain) + if g in (1, 2, 4, 8): + g = int(log2(g)) + else: + raise Exception, 'Gain is only (1, 2, 4, 8), you tried %i' % g + + if (channel % 2) == 0: + self._ch[channel][2:0] = g + else: + self._ch[channel][6:4] = g + + self.setRegister(int(channel/2), self._ch[channel]) + + #channel CCR mode config + SE = 0b00 + DIFF_EVEN = 0b01 + DIFF_ODD = 0b11 + def channelMode(self, channel, mode): + """Setup channel (pair) to SE or differential even/odd modes.""" + if mode not in (0, 1, 3): + raise Exception, 'Invalid mode: %i' % mode + + if ((channel % 2) == 1): + raise Exception, 'Cannot set mode on odd channel: %i' % channel + + self._ch[channel][4:2] = mode + self.setRegister(int(channel/2), self._ch[channel]) + + # + # Channel Select CCR config + # + def mux(self, channel): + """Select Mux input/start channel.""" + self.setRegister(self.CHAN_SEL, channel) + + # + # System Configuration Register config + # + def average(self, results, accurate=True): + if results not in (0, 1, 4, 8, 16): + raise Exception, 'Invalid average number: %i, must be 0, 4, 8, 16' % results + v = 0 + if accurate: + v += 0b100 + if results > 1: + v += int(log2(results / 2)) + print v + self._ADC_SCR[8:5] = v + print hex(self._ADC_SCR) + self.setRegister(self.ADC_SCR, self._ADC_SCR) + + def busy_int(self, level_edge, act_low_high, busy_int): + """Setup busy/interrupt pin and mode. Level/edge triggered, active + low/high, and busy/interrupt mode.""" + self._ADC_SCR[4] = level_edge + self._ADC_SCR[3] = act_low_high + self._ADC_SCR[2] = busy_int + self.setRegister(self.ADC_SCR, self._ADC_SCR) + + def fifo(self, enable=0): + """Enable FIFO buffer=1, disable=0.""" + self._ADC_SCR[1] = enable + self.setRegister(self.ADC_SCR, self._ADC_SCR) + + def convst_spi(self, spi_trigger): + """0 - conversion triggered by CONVST pin + 1 - conversion triggered by sham adc read()""" + self._ADC_SCR[0] = spi_trigger + self.setRegister(self.ADC_SCR, self._ADC_SCR) + + # + # interrupt SCR (INT_SCR) config + # + # NB: from datasheet p.15 "care must be taken to ensure that the ADC is in + # idle mode before writing to the Interrupt SCR." + def powerdown(self, pd): + """Set 1 to shutdown chip.""" + #ensure idle mode + self.triggerMode(self.MODE_IDLE) + self._INT_SCR[7] = pd + self.setRegister(self.INT_SCR, self._INT_SCR) + + # TODO: set/get interrupt sources + + # + # TRIGGER_SCR + # adc operating mode (state machine) + # + MODE_IDLE = 0 + MODE_MANUAL_MANUAL = 2 + MODE_MANUAL_DELAY = 3 + MODE_AUTO_MANUAL = 4 + MODE_AUTO_AUTO_SINGLE = 5 + MODE_AUTO_AUTO_CONTINUOUS = 6 + def triggerMode(self, mode): + """Set trigger operating mode. NB: 0 (idle) is required for setting + most config registers.""" + if mode in (1, 7): + raise Exception, 'Invalid trigger mode: %i' % mode + self._TRIGGER_SCR = intbv(mode, max=2**8) + self.setRegister(self.TRIGGER_SCR, self._TRIGGER_SCR) + + # + # Status SCR + # + def status(self): + """Get ADC status bitvector.""" + return self.getRegister(self.STATUS_SCR) + + # + # Reset SCR + # + def reset(self): + """Send a software reset.""" + self.setRegister(self.RESET_SCR, 0xaa) + + # + # Conversion Delay SCR + # + def conv_delay(self, delay): + """Set the conversion delay.""" + d = intbv(delay, max=2**8) + self.setRegister(self.DELAY_SCR, d) def read(self): + """Read ODR value, meaning of result depends on Mode and FIFO + settings. Last 4 LSB are averaging bits.""" + # TODO: also optionally read 4 TAG bits w = intbv(0x0000)[16:] self.bus.SetCS('adc') self.bus.Start()