MPSSE_BITWISE_MODE = ftdi.MPSSE_BITMODE
MPSSE_LSB_FIRST = ftdi.MPSSE_LSB
- def __init__(self, interface=ftdi.INTERFACE_A, csidle=0, cs=None,
+ def __init__(self, interface=ftdi.INTERFACE_A, cs=None,
mode=0,
freq=1e6,
vid=0x0403, pid=0x6011,
pindir=0xc0, pinstate=0xc0,
- latency=1,
- delay=0.001, timeout=100):
+ latency=1
+ ):
"""SPI port using the MPSSE on compatible FTDI devices with flexible
chip-select and composite command sequences. Uses the libftdi python
bindings.
Hence this class..
interface = ftdi.INTERFACE_x or [1,2,3,4]
- csidle = 8-bit port state for no chip-selects asserted
cs = dict specifying pin states to affect chip-select lines
special keys are '_idle': no-cs-asserted pin state
'_mask': bitmask with 1's in CS-related pin bits
pinstate = initial pin state
"""
self.interface = interface
- self.csidle = csidle
self.cs = cs
#defer mode until chip is init'd
#defer freq until chip is init'd
self.vid = vid
self.pid = pid
- #self._pindir = pindir
- #self._pinstate = pinstate
-
- self.DELAY = delay
- self.TIMEOUT = timeout
+ self.latency = latency
# setup the driver for this interface, init usb
- self.context = ftdi.new()
- ftdi.set_interface(self.context, interface)
+ self.ftdi = ftdi #local reference to speed lookups
+ self.context = self.ftdi.new()
+ self.ftdi.set_interface(self.context, interface)
# TODO: what should chunksize be? 4k is libftdi default,
# 4232h uses 2k FIFOs
# 2232h uses 4k FIFOs
- #ftdi.write_data_set_chunksize(self.context, 4096)
- #ftdi.read_data_set_chunksize(self.context, 4096)
+ #self.ftdi.write_data_set_chunksize(self.context, 4096)
+ #self.ftdi.read_data_set_chunksize(self.context, 4096)
# libftdi has several ways of selecting the desired device, see its
# source
- e = ftdi.usb_open(self.context, vid, pid)
+ e = self.ftdi.usb_open(self.context, vid, pid)
if e != 0:
- raise Exception, ftdi.get_error_string(self.context)
+ raise Exception, self.ftdi.get_error_string(self.context)
- ftdi.set_bitmode(self.context, int(self.pindir), ftdi.BITMODE_RESET)
- ftdi.set_bitmode(self.context, int(self.pindir), ftdi.BITMODE_MPSSE)
- self.set_mode(mode)
+ self.ftdi.set_latency_timer(self.context, max(1, min(255, latency)))
+ self.ftdi.set_bitmode(self.context, int(pindir), self.ftdi.BITMODE_RESET)
+ self.ftdi.set_bitmode(self.context, int(pindir), self.ftdi.BITMODE_MPSSE)
self.set_freq(freq)
+ self._pindir = 0
+ self._pinstate = 0
+ self._mode = mode #hack to get an initial value
self.set_pins(pinstate, pindir)
- ftdi.usb_purge_buffers(self.context)
+ self.set_mode(mode)
+ self.ftdi.usb_purge_buffers(self.context)
def _raw_write(self, data):
"""Write data as
#translate data to a string
if not isinstance(data, str):
data = ''.join(map(chr, data))
- ret = ftdi.write_data(self.context, data, len(data))
- if ret != 0:
- raise Exception, ftdi.get_error_string(self.context)
+ ret = self.ftdi.write_data(self.context, data, len(data))
+ if ret < 0:
+ raise Exception, self.ftdi.get_error_string(self.context)
def _raw_read(self, n):
"""Read n bytes from buffer."""
nread = 0
r = ''
while len(r) < n:
- s = ftdi.read_data(self.context, n)
- #does this really catch errors??
- if not s:
- raise Exception, ftdi.get_error_string(self.context)
+ ret, s = self.ftdi.read_data(self.context, n)
+ if ret < 0:
+ raise Exception, self.ftdi.get_error_string(self.context)
r += s
- ftdi.usb_purge_rx_buffer(self.context)
+ self.ftdi.usb_purge_rx_buffer(self.context)
return r
def set_freq(self, freq):
"""
# calc rates for both x5 and /5 modes and choose the closest, prefer
# the /5 mode if a tie
- f = CLK / ((1+divisor)*2)
- options = [] # (prescale, divisor, actual)
CLK = 12000000
div5 = max(int(round((CLK / (2.0 * freq)))) - 1, 0) #ensure >= 0
div1 = max(int(round((5*CLK / (2.0 * freq)))) - 1, 0)
div = div5
act = act5
#reset state has 60 MHz / 5 prescaler enabled
- #ftdi.write_data(self.context, chr(ftdi.EN_DIV_5), 1)
+ #self.ftdi.write_data(self.context, chr(self.ftdi.EN_DIV_5), 1)
else:
div = div1
act = act1
- ftdi.write_data(self.context, chr(ftdi.DIS_DIV_5), 1)
+ self.ftdi.write_data(self.context, chr(self.ftdi.DIS_DIV_5), 1)
- cmd = chr(ftdi.TCK_DIVISOR) + uint16str(div)
- ftdi.write_data(self.context, cmd, len(cmd))
+ cmd = chr(self.ftdi.TCK_DIVISOR) + uint16str(div)
+ self.ftdi.write_data(self.context, cmd, len(cmd))
self._freq = act
return act
#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 self.mode in (0, 1):
+ if mode in (0, 1):
#cpol = 0
p &= 0xFE
else:
"""
return self._mode
- def set_pins(pinstate=None, pindir=None, audit_cs=True):
+ 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
keep the SPI SK/DO/DI pins and configured chip-select pins in correct
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'] # 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.csidle & self._cs_mask))
+ self._pinstate = ((pinstate & ~self.cs['_mask']) +
+ (self.cs['_idle'] & self.cs['_mask']))
else:
self._pinstate = pinstate
#cpol = 1
self._pinstate |= 0x01
- cmd = chr(ftdi.SET_BITS_LOW) + chr(self._pinstate) + chr(self._pindir)
+ cmd = chr(self.ftdi.SET_BITS_LOW) + chr(self._pinstate) + chr(self._pindir)
self._raw_write(cmd)
def get_pins(self):
- cmd = chr(ftdi.GET_BITS_LOW) + chr(ftdi.SEND_IMMEDIATE)
+ cmd = chr(self.ftdi.GET_BITS_LOW) + chr(self.ftdi.SEND_IMMEDIATE)
self._raw_write(cmd)
p = self._read_raw(1)
self._pinstate = p
p += self.cs[device] & mask
self._pinstate = p
- cmd = chr(ftdi.SET_BITS_LOW) + chr(p) + chr(self._pindir)
+ cmd = chr(self.ftdi.SET_BITS_LOW) + chr(p) + chr(self._pindir)
return cmd
def _write_cmd(self, data):
data = ''.join(map(chr, data))
cmd += data
- cmd += chr(ftdi.SEND_IMMEDIATE)
+ cmd += chr(self.ftdi.SEND_IMMEDIATE)
return cmd
def _read_cmd(self, n):
cmd = chr(self.MPSSE_SPI_MODE_CONFIG[self.mode] |
self.MPSSE_READ)
cmd += uint16str(n - 1)
- cmd += chr(ftdi.SEND_IMMEDIATE)
+ cmd += chr(self.ftdi.SEND_IMMEDIATE)
return cmd
def write(self, data, device):
cmd = (self._cs_cmd(device) + self._exchange_cmd(data) +
self._cs_cmd('_idle'))
self._raw_write(cmd)
- return self._raw_read(n)
+ return self._raw_read(len(data))
return tuple(b)
def send(self):
- self.bus.SetCS('dac')
- #self.bus.Start()
- #self.bus.Write(str(self))
- #self.bus.Stop()
- self.bus.Exchange(str(self))
+ self.bus.exchange(str(self), 'dac')
#
# internal functions to help construct a command
w = intbv(0x8000)[16:]
w[14:10] = intbv(address, max=2**4)
w[8:] = intbv(value, max=2**8)
- self.bus.SetCS('adc')
- self.bus.Start()
- self.bus.Write(int2str(w, 16))
- self.bus.Stop()
+ #self.bus.SetCS('adc')
+ #self.bus.Start()
+ self.bus.write(int2str(w, 16), 'adc')
+ #self.bus.Stop()
def getRegister(self, address):
w = intbv(0x4000)[16:]
w[14:10] = intbv(address, max=2**4)
#print 'sending:', b(w, 16)
- self.bus.SetCS('adc')
- self.bus.Start()
- rval = self.bus.Exchange(int2str(w, 16))
- self.bus.Stop()
+ #self.bus.SetCS('adc')
+ #self.bus.Start()
+ rval = self.bus.exchange(int2str(w, 16), 'adc')
+ #self.bus.Stop()
#i = 8 * (len(rval)-1)
#r = 0
#for c in rval:
settings. Last 4 LSB are averaging bits."""
# TODO: also optionally read 4 TAG bits
w = intbv(0x0000)[16:]
- self.bus.SetCS('adc')
+ #self.bus.SetCS('adc')
#self.bus.Start()
- rval = self.bus.Exchange(int2str(w, 16))
+ rval = self.bus.exchange(int2str(w, 16), 'adc')
#self.bus.Stop()
i = 8 * (len(rval)-1)
r = 0
-class AtoiSPI0(mpsse.MPSSE):
+class AtoiSPI0(SPI):
def __init__(self, freq):
- super(AtoiSPI0, self).__init__()
- self._freq = int(freq)
- self.Open(0x0403, 0x6011, mpsse.SPI1, int(freq),
- interface=mpsse.IFACE_A)
- self._cs = None
- self._cs_mode = {
- 'flash': mpsse.SPI0,
- 'dac': mpsse.SPI1,
- 'adc': mpsse.SPI1,
- 'convst': mpsse.SPI1,
- }
-
+ 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
+ freq=int(freq),
+ vid=0x0403,
+ pid=0x6011,
+ pindir=0xc0,
+ pinstate=0xc8,
+ latency=1
+ )
def SetCS(self, name):
"""Setup the chip-select pins for a given 'name'."""
else:
raise Exception, 'Unknown CS name: %s' % name
- self._cs = name
+ #self._cs = name
class AtoiSPI1(mpsse.MPSSE):