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,
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
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)
"""
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
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
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)
"""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))
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)
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))
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):
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):
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
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):
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):
#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
#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
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,
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):
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