From c1ef9fdeaa256186b1d1af0331da3fdf824fbb36 Mon Sep 17 00:00:00 2001 From: Dan White Date: Thu, 12 Jul 2012 21:18:24 -0500 Subject: [PATCH] make SPI class work --- python-lib/usbio.py | 144 +++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/python-lib/usbio.py b/python-lib/usbio.py index 77833f7..e1e82a7 100644 --- a/python-lib/usbio.py +++ b/python-lib/usbio.py @@ -311,13 +311,13 @@ class SPI(object): 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. @@ -327,7 +327,6 @@ class SPI(object): 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 @@ -337,40 +336,40 @@ class SPI(object): 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 @@ -378,21 +377,20 @@ class SPI(object): #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): @@ -401,8 +399,6 @@ class SPI(object): """ # 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) @@ -413,14 +409,14 @@ class SPI(object): 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 @@ -436,7 +432,7 @@ class SPI(object): #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: @@ -453,7 +449,7 @@ class SPI(object): """ 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 @@ -464,7 +460,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'] # 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 @@ -473,8 +469,8 @@ class SPI(object): 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 @@ -486,11 +482,11 @@ class SPI(object): #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 @@ -517,7 +513,7 @@ class SPI(object): 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): @@ -551,7 +547,7 @@ class SPI(object): 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): @@ -561,7 +557,7 @@ class SPI(object): 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): @@ -590,7 +586,7 @@ class SPI(object): 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)) @@ -1175,11 +1171,7 @@ class DAC8568(object): 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 @@ -1237,19 +1229,19 @@ class ADS8201(object): 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: @@ -1391,9 +1383,9 @@ class ADS8201(object): 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 @@ -1520,20 +1512,24 @@ class M25PExx(object): -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'.""" @@ -1566,7 +1562,7 @@ class AtoiSPI0(mpsse.MPSSE): else: raise Exception, 'Unknown CS name: %s' % name - self._cs = name + #self._cs = name class AtoiSPI1(mpsse.MPSSE): -- 2.25.1