From: Dan White Date: Tue, 17 Jul 2012 02:18:57 +0000 (-0500) Subject: bugfix SPI class, change API X-Git-Tag: calibrations~24 X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=a1a6bf3f8973b769503f842f1c767728fce4032f;p=430.git bugfix SPI class, change API For the weird SPI modes 1,3, SK must be in the opposite state than idle before clocking in/out data. The constructor uses a different data structure for argument 'cs'. A tuple of (mode, pinstate) is provided for each key, e.g.: {'_mask': (-1, 0xff), '_idle': (-1, 0xff), 'dev1': (0, 0xf0)} --- diff --git a/python-lib/usbio.py b/python-lib/usbio.py index ead50e7..47bf3ab 100644 --- a/python-lib/usbio.py +++ b/python-lib/usbio.py @@ -313,7 +313,6 @@ class SPI(object): MPSSE_LSB_FIRST = ftdi.MPSSE_LSB def __init__(self, interface=ftdi.INTERFACE_A, cs=None, - mode=0, freq=1e6, vid=0x0403, pid=0x6011, pindir=0xc0, pinstate=0xc0, @@ -328,17 +327,17 @@ class SPI(object): Hence this class.. interface = ftdi.INTERFACE_x or [1,2,3,4] - cs = dict specifying pin states to affect chip-select lines + cs = dict specifying pin states and spi modes for each device with values as + (mode, pinstate) special keys are '_idle': no-cs-asserted pin state '_mask': bitmask with 1's in CS-related pin bits + ^^^^^^^ for these, set 'mode'=-1 other keys specify the pin states to assert that device's CS pin - mode = SPI mode [0,1,2,3]; bitfield of [CPOL, CPHA] pindir = initial bitfield of pin directions pinstate = initial pin state """ self.interface = interface self.cs = cs - #defer mode until chip is init'd #defer freq until chip is init'd self.vid = vid self.pid = pid @@ -367,14 +366,11 @@ class SPI(object): self.set_freq(freq) self._pindir = 0 self._pinstate = 0 - self._mode = mode #hack to get an initial value self.set_pins(pinstate, pindir) - self.set_mode(mode) #cs doesn't (shouldn't) change, cache the values for SPEED self._cs_cmd_cache = {} - for dev in self.cs.keys(): - self._cs_cmd_cache[dev] = self._cs_cmd(dev) + self._mk_cs_cmd_cache() self.ftdi.usb_purge_buffers(self.context) @@ -435,28 +431,6 @@ class SPI(object): """ return self._freq - def set_mode(self, mode): - if mode in range(4): - #ensure pin 0/SK starts in its idle state in case this is a mode change - #yes, the check is done in set_pins(), but paranoia never hurts.. - p = self._pinstate - if mode in (0, 1): - #cpol = 0 - p &= 0xFE - else: - #cpol = 1 - p |= 0x01 - self.set_pins(p) - self._mode = mode - else: - raise Exception, 'Invalid mode %i, must be in range(4)' % mode - - @property - def mode(self): - """Return the current SPI mode. See set_mode() to change it. - """ - return self._mode - def set_pins(self, pinstate=None, pindir=None, audit_cs=True): """Change the GPIO pins [3..7] to the given state and direction. Argument values of None mean "do not change". Audits the values to @@ -468,7 +442,7 @@ class SPI(object): self._pindir = pindir #we are changing pin directions, audit them self._pindir |= 0x03 # pins 0/SK and 1/DO are outputs for sure - self._pindir |= self.cs['_mask'] # chip-select pins are always outputs + self._pindir |= self.cs['_mask'][1] # chip-select pins are always outputs self._pindir &= 0xFB # pin 2/DI is an input for sure # most implementations force pin 3/CS to an output, IT DOES NOT # NEED DO BE. The top 5 pins are available for GPIO, CS, or both @@ -477,19 +451,13 @@ class SPI(object): if pinstate is not None: if audit_cs: - self._pinstate = ((pinstate & ~self.cs['_mask']) + - (self.cs['_idle'] & self.cs['_mask'])) + mask = self.cs['_mask'][1] + idle = self.cs['_idle'][1] + self._pinstate = ((pinstate & mask) + + (idle & mask)) else: self._pinstate = pinstate - #ensure pin 0/SK stays in its idle state, 1/DO stays as-was - if self.mode in (0, 1): - #cpol = 0 - self._pinstate &= 0xFE - else: - #cpol = 1 - self._pinstate |= 0x01 - cmd = chr(self.ftdi.SET_BITS_LOW) + chr(self._pinstate) + chr(self._pindir) self._raw_write(cmd) @@ -516,22 +484,35 @@ class SPI(object): """Construct a pin-setting command which asserts the given device. See __init__() for more info. """ - mask = self.cs['_mask'] + sham, mask = self.cs['_mask'] + mode, pins = self.cs[device] + p = self._pinstate & ~mask - p += self.cs[device] & mask + p += pins & mask + + # ensure SK starts in the correct state + if mode in (0, 1): + p |= 0x01 + elif mode in (2, 3): + p &= 0xfe self._pinstate = p cmd = chr(self.ftdi.SET_BITS_LOW) + chr(p) + chr(self._pindir) return cmd - def _write_cmd(self, data): + def _mk_cs_cmd_cache(self): + for dev in self.cs.keys(): + self._cs_cmd_cache[dev] = self._cs_cmd(dev) + + def _write_cmd(self, device, data): """Return a MPSSE command string which sends data out via the current SPI mode. data is either a string or converted by map(chr, data). """ - cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.mode] | + cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.cs[device][0]] | self.MPSSE_WRITE) cmd += uint16str(len(data) - 1) + #translate data to a string if not isinstance(data, str): data = ''.join(map(chr, data)) @@ -539,13 +520,13 @@ class SPI(object): cmd += data return cmd - def _exchange_cmd(self, data): + def _exchange_cmd(self, device, data): """Return a MPSSE command string which sends data out via the current SPI mode and reads the same amount back. data is either a string or converted by map(chr, data). Interface read buffer contains the read data. """ - cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.mode] | + cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.cs[device][0]] | self.MPSSE_WRITE | self.MPSSE_READ) cmd += uint16str(len(data) - 1) @@ -558,42 +539,43 @@ class SPI(object): cmd += chr(self.ftdi.SEND_IMMEDIATE) return cmd - def _read_cmd(self, n): + def _read_cmd(self, device, n): """Return a MPSSE command string which reads n-bytes via the current SPI mode. NB: The DO line stays in its last state. """ - cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.mode] | + cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.cs[device][0]] | self.MPSSE_READ) cmd += uint16str(n - 1) cmd += chr(self.ftdi.SEND_IMMEDIATE) return cmd - def write(self, data, device): + def write(self, device, data): """Write data out to the selected device via the current SPI mode. The device is used to select the desired CS pin state as cs_active = self.cs[device]. """ cmd = (self._cs_cmd_cache[device] + - self._write_cmd(data) + + self._write_cmd(device, data) + self._cs_cmd_cache['_idle']) self._raw_write(cmd) - def read(self, n, device): + def read(self, device, n): """Read data from the selected device, DO pin stays in its last state. """ - cmd = (self._cs_cmd_cache[device] + self._read_cmd(n) + + cmd = (self._cs_cmd_cache[device] + + self._read_cmd(device, n) + self._cs_cmd_cache['_idle']) self._raw_write(cmd) return self._raw_read(n) - def exchange(self, data, device): + def exchange(self, device, data): """Write data out to the selected device while also reading data in via the current SPI mode. The device is used to select the desired CS pin state as cs_active = self.cs[device]. """ cmd = (self._cs_cmd_cache[device] + - self._exchange_cmd(data) + + self._exchange_cmd(device, data) + self._cs_cmd_cache['_idle']) self._raw_write(cmd) return self._raw_read(len(data)) @@ -1132,7 +1114,7 @@ class DAC8568(object): def __str__(self): #return ''.join(map(chr, self.bytes())) - return int2str(self.word, self.CTL_WIDTH) + return int2str((self.word & 0xffffffff), self.CTL_WIDTH) @property def word(self): @@ -1168,9 +1150,9 @@ class DAC8568(object): self._clear() self._control(0x4) #self._word[10:8] = intbv(mode, max=2**2) - self._word += (mode << 8) #intbv(mode, max=2**2) + self._word += ((mode & 0x3) << 8) #intbv(mode, max=2**2) #self._word[8:0] = intbv(bitfield, max=2**8) - self._word += (bitfield << 0) #intbv(bitfield, max=2**8) + self._word += ((bitfield & 0xff) << 0) #intbv(bitfield, max=2**8) self.send() def reference(self, mode): @@ -1186,7 +1168,7 @@ class DAC8568(object): return b def send(self): - self.bus.write(str(self), 'dac') + self.bus.write(self.cs, str(self)) # # internal functions to help construct a command @@ -1197,21 +1179,21 @@ class DAC8568(object): def _control(self, value): #self._word[28:24] = value #intbv(value, max=2**4) - self._word += (value << 24) #intbv(value, max=2**4) + self._word += ((value & 0xf) << 24) #intbv(value, max=2**4) def _address(self, value): #other values are no-op addresses if (value <= 7) or (value == 15): #self._word[24:20] = value #intbv(value, max=2**4) - self._word += (value << 20) #intbv(value, max=2**4) + self._word += ((value & 0xf) << 20) #intbv(value, max=2**4) def _data(self, value): #self._word[20:20-self.DAC_WIDTH] = value #intbv(value, max=2**self.DAC_WIDTH) - self._word += (value << (20-self.DAC_WIDTH)) #intbv(value, max=2**self.DAC_WIDTH) + self._word += ((value & 0xffff) << (20-self.DAC_WIDTH)) #intbv(value, max=2**self.DAC_WIDTH) def _feature(self, value): #self._word[4:0] = value #intbv(value, max=2**4) - self._word += (value << 0)#intbv(value, max=2**4) + self._word += ((value & 0xf) << 0)#intbv(value, max=2**4) class ADS8201(object): @@ -1251,7 +1233,7 @@ class ADS8201(object): w[8:] = value #intbv(value, max=2**8) #self.bus.SetCS('adc') #self.bus.Start() - self.bus.write(int2str(w, 16), 'adc') + self.bus.write('adc', int2str(w, 16)) #self.bus.Stop() def getRegister(self, address): @@ -1260,7 +1242,7 @@ class ADS8201(object): #print 'sending:', b(w, 16) #self.bus.SetCS('adc') #self.bus.Start() - rval = self.bus.exchange(int2str(w, 16), 'adc') + rval = self.bus.exchange('adc', int2str(w, 16)) #self.bus.Stop() #i = 8 * (len(rval)-1) #r = 0 @@ -1406,7 +1388,7 @@ class ADS8201(object): #self.bus.SetCS('adc') #self.bus.Start() #rval = self.bus.exchange(int2str(w, 16), 'adc') - rval = self.bus.exchange('\x00\x00', 'adc') + rval = self.bus.exchange('adc', '\x00\x00') #self.bus.Stop() i = 8 * (len(rval)-1) r = 0 @@ -1537,13 +1519,12 @@ class AtoiSPI0(SPI): def __init__(self, freq): super(AtoiSPI0, self).__init__( interface=ftdi.INTERFACE_A, - cs={'_idle': 0xc8, - '_mask': 0xff, #TODO - 'flash': 0xc0, - 'dac': 0xd8, - 'adc': 0xe8, - 'convst': 0xf8}, - mode=1, #flash is mode 0, others are 1 + cs={'_idle': (-1, 0xc8), + '_mask': (-1, 0x38), #TODO + 'flash': (0, 0xc0), + 'dac': (1, 0xd8), + 'adc': (1, 0xe8), + 'convst': (1, 0xf8)}, freq=int(freq), vid=0x0403, pid=0x6011, @@ -1552,39 +1533,6 @@ class AtoiSPI0(SPI): latency=1 ) - def SetCS(self, name): - """Setup the chip-select pins for a given 'name'.""" - if name == self._cs: - return - - if name not in self._cs_mode: - raise Exception, 'Unknown CS name: %s' % name - - # different SPI modes require restarting the bus for some reason - if self.context.mode != self._cs_mode[name]: - self.Close() - self.Open(0x0403, 0x6011, - self._cs_mode[name], - self._freq, - interface=mpsse.IFACE_A) - - if name == 'flash': - self.context.pidle = self.context.pstop = 0xc8 - self.context.pstart = 0xc0 - elif name == 'dac': - self.context.pidle = self.context.pstop = 0xc8 - self.context.pstart = 0xd8 - elif name == 'adc': - self.context.pidle = self.context.pstop = 0xc8 - self.context.pstart = 0xe8 - elif name == 'convst': - self.context.pidle = self.context.pstop = 0xc8 - self.context.pstart = 0xf8 - else: - raise Exception, 'Unknown CS name: %s' % name - - #self._cs = name - class AtoiSPI1(mpsse.MPSSE): def __init__(self, freq): @@ -1686,7 +1634,7 @@ class DigiReg(AD524x): class DAC_atoi(DAC8568): """Specific configuration and calibration for devboard DAC.""" - VREF = 2.5 + VREF = 2.5012 GAIN = 1.0 #part options A/B #GAIN = 2.0 #part options C/D POR_VALUE = 0 #part A/C