Fill ADC class functionality
authorDan White <dan@whiteaudio.com>
Tue, 8 May 2012 18:22:23 +0000 (13:22 -0500)
committerDan White <dan@whiteaudio.com>
Tue, 8 May 2012 18:22:23 +0000 (13:22 -0500)
python-lib/usbio.py

index c9e1a6dbcdc04b8b2276752a7b8fa2655cfdc7a8..379600710c2e6081b38655a8fd81c1795d57c6f1 100644 (file)
@@ -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()