class ft2232: def open_ft2232(self, vps, itf, sn): # find the device on USB devices = usbtools.UsbTools.find_all(vps) if sn is not None: # filter based on device serial number devices = [dev for dev in devices if dev[2] == sn] if len(devices) == 0: raise IOError("No such device") self.vid = devices[0][0] self.pid = devices[0][1] self.sn = devices[0][2] self.ftdi = Ftdi() self.freq = self.ftdi.open_mpsse(self.vid, self.pid, itf, serial = self.sn, frequency = _FREQ) self.wrbuf = array.array('B') self.gpio_init() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE' def __del__(self): if self.ftdi: self.ftdi.close() def flush(self): """flush the write buffer to the ft2232""" if len(self.wrbuf) > 0: self.ftdi.write_data(self.wrbuf) del self.wrbuf[0:] def write(self, buf, flush = False): """queue write data to send to ft2232""" self.wrbuf.extend(buf) if flush: self.flush() def state_x(self, dst): """change the TAP state from self.state to dst""" if self.state == dst: return tms = tms_mpsse(tap.lookup(self.state, dst)) cmd = _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG self.write((cmd, tms[0], tms[1]), True) self.state = dst def state_reset(self): """from *any* state go to the reset state""" self.state = '*' self.state_x('RESET') def shift_data(self, tdi, tdo, end_state): """ write (and possibly read) a bit stream from the JTAGkey tdi - bit buffer of data to be written to the JTAG TDI pin tdo - bit buffer for the data read from the JTAG TDO pin (optional) end_state - leave the TAP state machine in this state """ wr = tdi.get() io_bits = tdi.n - 1 io_bytes = io_bits >> 3 io_bits &= 0x07 last_bit = (wr[io_bytes] << (7 - io_bits)) & 128 if tdo is not None: read_cmd = _MPSSE_DO_READ read_len = io_bytes + 1 if io_bits: read_len += 1 else: read_cmd = 0 read_len = 0 # write out the full bytes if io_bytes: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_WRITE_NEG num = io_bytes - 1 self.write((cmd, _lsb(num), _msb(num))) self.write(wr[0:io_bytes]) # write out the remaining bits if io_bits: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_BITMODE | _MPSSE_WRITE_NEG self.write((cmd, io_bits - 1, wr[io_bytes])) # the last bit of output data is bit 7 of the tms value (goes onto tdi) # continue to read to get the last bit of tdo data cmd = read_cmd | _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG tms = tms_mpsse(tap.lookup(self.state, end_state)) self.write((cmd, tms[0], tms[1] | last_bit)) self.state = end_state # if we are only writing, return if tdo is None: self.flush() return # make the ft2232 flush its data back to the PC self.write((Ftdi.SEND_IMMEDIATE,), True) rd = self.ftdi.read_data_bytes(read_len, _READ_RETRIES) if io_bits: # the n partial bits are in the top n bits of the byte # move them down to the bottom rd[-2] >>= (8 - io_bits) # get the last bit from the tms response byte (last byte) last_bit = (rd[-1] >> (7 - tms[0])) & 1 last_bit <<= io_bits # add the last bit if io_bits: # drop the tms response byte del rd[-1] # or it onto the io_bits byte rd[-1] |= last_bit else: # replace the tms response byte rd[-1] = last_bit # copy to the bit buffer tdo.set(tdi.n, rd) def scan_ir(self, tdi, tdo = None): """write (and possibly read) a bit stream through the IR in the JTAG chain""" self.state_x('IRSHIFT') self.shift_data(tdi, tdo, self.sir_end_state) def scan_dr(self, tdi, tdo = None): """write (and possibly read) a bit stream through the DR in the JTAG chain""" self.state_x('DRSHIFT') self.shift_data(tdi, tdo, self.sdr_end_state) def gpio_init(self): """setup the gpio lines""" self.gpio_dir = _TCK | _TDI | _TMS self.gpio_val = 0 self.ftdi.write_data((Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) self.ftdi.write_data((Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_wr(self, gpio, val): """write a gpio pin""" self.gpio_dir |= gpio if val: self.gpio_val |= gpio else: self.gpio_val &= ~gpio if gpio <= _GPIOL3: self.ftdi.write_data((Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) else: self.ftdi.write_data((Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_rd(self, gpio): """read a gpio pin""" if gpio <= _GPIOL3: self.ftdi.write_data((Ftdi.GET_BITS_LOW,)) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] else: self.ftdi.write_data((Ftdi.GET_BITS_HIGH,)) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] val <<= 8 return (val & gpio) != 0
def __init__(self, vendor_id, product_id, interface, debug = False): self.vendor = vendor_id self.product = product_id self.interface = interface self.f = Ftdi() self.debug = True self.f.open_bitbang(vendor_id, product_id, interface)
def __init__(self, vendor, product, interface): self.ftdi = Ftdi() try: self.ftdi.open_mpsse(vendor, product, interface) except IOError as e: print "ft2232 jtag driver: %s" % str(e) self.ftdi = None sys.exit(0) self.wrbuf = array.array('B') self.gpio_init() self.tap = tap.tap() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE'
def __init__(self, idVendor=0x0403, idProduct=0x8531, sernum=None, status=False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Artemis will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Artemis" self.interrupts = 0x00 self.events = [] for i in range(INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = ArtemisData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Artemis until a read and reset occurs #self.ping() pass except NysaCommError: pass self.reset() '''
def open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ self.dev = Ftdi() frequency = 30.0E6 latency = 4 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0) #Drain the input buffer self.dev.purge_buffers() #Reset #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) #Configure Clock frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers()
def open_ft2232(self, vps, itf, sn): # find the device on USB devices = usbtools.UsbTools.find_all(vps) if sn is not None: # filter based on device serial number devices = [dev for dev in devices if dev[2] == sn] if len(devices) == 0: raise IOError("No such device") self.vid = devices[0][0] self.pid = devices[0][1] self.sn = devices[0][2] self.ftdi = Ftdi() self.freq = self.ftdi.open_mpsse(self.vid, self.pid, itf, serial=self.sn, frequency=_FREQ) self.wrbuf = array.array('B') self.gpio_init() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE'
def __init__(self, silent_clock=False, cs_count=4): self._ftdi = Ftdi() self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & \ ~(SpiController.CS_BIT - 1) self._ports = [None] * cs_count self._direction = self._cs_bits | \ SpiController.DO_BIT | \ SpiController.SCK_BIT self._cs_high = Array('B') if silent_clock: # Set SCLK as input to avoid emitting clock beats self._cs_high.extend([ Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT ]) # /CS to SCLK delay, use 8 clock cycles as a HW tempo self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xff]) # Restore idle state self._cs_high.extend( [Ftdi.SET_BITS_LOW, self._cs_bits, self._direction]) self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE]) self._frequency = 0.0
def __init__(self, idVendor = 0x0403, idProduct = 0x8530, sernum = None, status = False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Dionysus will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Dionysus" self.interrupts = 0x00 self.events = [] for i in range (INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = DionysusData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Dionysus until a read and reset occurs self.ping() except NysaCommError: pass self.reset() '''
def open_ft2232(self, vps, itf, sn): # find the device on USB devices = usbtools.UsbTools.find_all(vps) if sn is not None: # filter based on device serial number devices = [dev for dev in devices if dev[2] == sn] if len(devices) == 0: raise IOError("No such device") self.vid = devices[0][0] self.pid = devices[0][1] self.sn = devices[0][2] self.ftdi = Ftdi() self.freq = self.ftdi.open_mpsse(self.vid, self.pid, itf, serial = self.sn, frequency = _FREQ) self.wrbuf = array.array('B') self.gpio_init() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE'
def __init__(self, silent_clock=False, cs_count=4): self._ftdi = Ftdi() self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & \ ~(SpiController.CS_BIT - 1) self._ports = [None] * cs_count self._direction = self._cs_bits | \ SpiController.DO_BIT | \ SpiController.SCK_BIT self._cs_high = Array('B') if silent_clock: # Set SCLK as input to avoid emitting clock beats self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT]) # /CS to SCLK delay, use 8 clock cycles as a HW tempo self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8-1, 0xff]) # Restore idle state self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction]) self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE]) self._frequency = 0.0
class jtag_driver: def __init__(self, vendor, product, interface): self.ftdi = Ftdi() try: self.ftdi.open_mpsse(vendor, product, interface) except IOError as e: print "ft2232 jtag driver: %s" % str(e) self.ftdi = None sys.exit(0) self.wrbuf = array.array('B') self.gpio_init() self.tap = tap.tap() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE' def __del__(self): if self.ftdi: self.ftdi.close() def __str__(self): """return a string describing the device""" return self.ftdi.type def flush(self): """flush the write buffer to the ft2232""" if len(self.wrbuf) > 0: self.ftdi.write_data(self.wrbuf) del self.wrbuf[0:] def write(self, buf, flush=False): """queue write data to send to ft2232""" self.wrbuf.extend(buf) if flush: self.flush() def state_x(self, dst): """change the TAP state from self.state to dst""" bits = self.tap.tms(self.state, dst) if not bits: # no state change assert self.state == dst return tms = tms_mpsse(bits) cmd = _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG self.write((cmd, tms[0], tms[1]), True) self.state = dst def state_reset(self): """from *any* state go to the reset state""" self.state = '*' self.state_x('RESET') def shift_data(self, tdi, tdo, end_state): """ write (and possibly read) a bit stream from the JTAGkey tdi - bit buffer of data to be written to the JTAG TDI pin tdo - bit buffer for the data read from the JTAG TDO pin (optional) end_state - leave the TAP state machine in this state """ wr = tdi.get() io_bits = tdi.n - 1 io_bytes = io_bits >> 3 io_bits &= 0x07 last_bit = (wr[io_bytes] << (7 - io_bits)) & 128 if tdo is not None: read_cmd = _MPSSE_DO_READ read_len = io_bytes + 1 if io_bits: read_len += 1 else: read_cmd = 0 read_len = 0 # write out the full bytes if io_bytes: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_WRITE_NEG num = io_bytes - 1 self.write((cmd, _lsb(num), _msb(num))) self.write(wr[0:io_bytes]) # write out the remaining bits if io_bits: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_BITMODE | _MPSSE_WRITE_NEG self.write((cmd, io_bits - 1, wr[io_bytes])) # the last bit of output data is bit 7 of the tms value (goes onto tdi) # continue to read to get the last bit of tdo data cmd = read_cmd | _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG tms = tms_mpsse(self.tap.tms(self.state, end_state)) self.write((cmd, tms[0], tms[1] | last_bit)) self.state = end_state # if we are only writing, return if tdo is None: self.flush() return # make the ft2232 flush its data back to the PC self.write((Ftdi.SEND_IMMEDIATE, ), True) rd = self.ftdi.read_data_bytes(read_len, _READ_RETRIES) if io_bits: # the n partial bits are in the top n bits of the byte # move them down to the bottom rd[-2] >>= (8 - io_bits) # get the last bit from the tms response byte (last byte) last_bit = (rd[-1] >> (7 - tms[0])) & 1 last_bit <<= io_bits # add the last bit if io_bits: # drop the tms response byte del rd[-1] # or it onto the io_bits byte rd[-1] |= last_bit else: # replace the tms response byte rd[-1] = last_bit # copy to the bit buffer tdo.set(tdi.n, rd) def scan_ir(self, tdi, tdo=None): """write (and possibly read) a bit stream through the IR in the JTAG chain""" self.state_x('IRSHIFT') self.shift_data(tdi, tdo, self.sir_end_state) def scan_dr(self, tdi, tdo=None): """write (and possibly read) a bit stream through the DR in the JTAG chain""" self.state_x('DRSHIFT') self.shift_data(tdi, tdo, self.sdr_end_state) def test_reset(self, val): """control the test reset line""" # TODO pass def reset_jtag(self): """reset the TAP of all JTAG devices in the chain""" self.test_reset(True) time.sleep(_TRST_TIME) self.test_reset(False) self.state_reset() def gpio_init(self): """setup the gpio lines""" self.gpio_dir = _TCK | _TDI | _TMS self.gpio_val = 0 self.ftdi.write_data( (Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) self.ftdi.write_data( (Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_out(self, gpio): if gpio <= _GPIOL3: self.ftdi.write_data( (Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) else: self.ftdi.write_data( (Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_set(self, gpio): """set a gpio pin""" self.gpio_dir |= gpio self.gpio_val |= gpio self.gpio_out(gpio) def gpio_clr(self, gpio): """clear a gpio pin""" self.gpio_dir |= gpio self.gpio_val &= ~gpio self.gpio_out(gpio) def gpio_rd(self, gpio): """read a gpio pin""" if gpio <= _GPIOL3: self.ftdi.write_data((Ftdi.GET_BITS_LOW, )) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] else: self.ftdi.write_data((Ftdi.GET_BITS_HIGH, )) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] val <<= 8 return (val & gpio) != 0
class BitBangController(object): DONE_PIN = 0x10 PROGRAM_PIN = 0x40 SOFT_RESET_PIN = 0x80 def __init__(self, vendor_id, product_id, interface, debug = False): self.vendor = vendor_id self.product = product_id self.interface = interface self.f = Ftdi() self.debug = True self.f.open_bitbang(vendor_id, product_id, interface) def hiz(self): pass def is_in_bitbang(self): return self.f.bitbang_enabled() def read_pins(self): return self.f.read_pins() def read_program_pin(self): return (self.PROGAM_PIN & self.f.read_pins() > 0) def read_soft_reset_pin(self): return (self.SOFT_RESET_PIN & self.f.read_pins() > 0) def read_done_pin(self): return (self.DONE_PIN & self.f.read_pins() > 0) def wait_for_done(self): while not self.read_done_pin(): print ".", time.sleep(200) print "Done" def soft_reset_high(self): pins = self.f.read_pins() pins |= self.SOFT_RESET_PIN self.f.write_data(Array('B', [0x01, pins])) def soft_reset_low(self): pins = self.f.read_pins() pins &= ~(self.SOFT_RESET_PIN) self.f.write_data(Array('B', [0x00, pins])) def program_high(self): pins = self.f.read_pins() pins |= self.PROGRAM_PIN self.f.write_data(Array('B', [0x01, pins])) def program_low(self): pins = self.f.read_pins() pins &= ~(self.PROGRAM_PIN) self.f.write_data(Array('B', [0x00, pins])) def set_soft_reset_to_output(self): pin_dir = self.SOFT_RESET_PIN self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir) def set_program_pin_to_output(self): pin_dir = self.PROGRAM_PIN self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir) def set_pins_to_input(self): self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0x00) def set_pins_to_output(self): self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0xFF) def pins_on(self): """ Set all pins high """ self.f.write_data(Array('B', [0x01, 0xFF])) def pins_off(self): """ Set all pins low """ self.f.write_data(Array('B', [0x01, 0x00]))
class Controller(object): def __init__(self, dev=None, vendor_id=0x0403, product_id=0x8531, status=None): super(Controller, self).__init__() self.vendor = vendor_id self.product = product_id self.s = status def upload(self, filepath): """ Write a binary file to the the SPI Prom Args: filepath (String): Path to FPGA Binary (bin) image Returns (boolean): True: Successfully programmed False: Failed to program Raises: IOError: Failed to open binary file """ binf = "" f = open(filepath, "r") binf = f.read() f.close() #Allow the users to handle File Errors #Open the SPI Flash Device manager = serial_flash_manager.SerialFlashManager( self.vendor, self.product, 2) flash = manager.get_flash_device() #Print out the device was found if self.s: self.s.Info("Found: %s" % str(flash)) #Erase the flash if self.s: self.s.Info( "Erasing the SPI Flash device, this can take a minute or two..." ) flash.bulk_erase() #Write the binary file if self.s: self.s.Info("Flash erased, writing binary image to PROM") flash.write(0x00, binf) #Verify the data was read binf_rb = flash.read(0x00, len(binf)) binf_str = binf_rb.tostring() del flash del manager if binf_str != binf: raise NysaError( "Image Verification Failed!, data written is not the same as data read" ) def program(self): """ Send a program signal to the board, the FPGA will attempt to read the binary image file from the SPI prom. If successful the 'done' LED will illuminate Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) if self.s: self.s.Important("Set signals to input") bbc.set_pins_to_input() bbc.set_pins_to_output() bbc.program_high() time.sleep(.5) bbc.program_low() time.sleep(.2) bbc.program_high() bbc.pins_on() bbc.set_pins_to_input() def read_bin_file(self, filepath): """ Read the binary image from the SPI Flash Args: filepath (String): Path to the filepath where the SPI image will be written to Returns: Nothing Raises: IOError: Problem openning file to write to """ manager = serial_flash_manager.SerialFlashManager( self.vendor, self.product, 2) flash = manager.get_flash_device() #Don't know how long the binary file is so we need to read the entire #Image binf_rb = flash.read(0x00, len(flash)) f = open(filepath, "w") binf_rb.tofile(f) f.close() def reset(self): """ Send a reset signal to the board, this is the same as pressing the 'reset' button Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) bbc.set_soft_reset_to_output() bbc.soft_reset_high() time.sleep(.2) bbc.soft_reset_low() time.sleep(.2) bbc.soft_reset_high() bbc.pins_on() bbc.set_pins_to_input() def set_sync_fifo_mode(self): """ Change the mode of the FIFO to a synchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_sync_fifo() def set_debug_mode(self): """ Change the mode of the FIFO to a asynchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_async_fifo() def open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ self.dev = Ftdi() frequency = 30.0E6 latency = 4 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0) #Drain the input buffer self.dev.purge_buffers() #Reset #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) #Configure Clock frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() def ioctl(self, name, arg=None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name)
class Controller(object): def __init__(self, dev = None, vendor_id = 0x0403, product_id = 0x8530, status = None): super (Controller, self).__init__() self.vendor = vendor_id self.product = product_id self.s = status def upload(self, filepath): """ Write a binary file to the the SPI Prom Args: filepath (String): Path to FPGA Binary (bin) image Returns (boolean): True: Successfully programmed False: Failed to program Raises: IOError: Failed to open binary file """ binf = "" f = open(filepath, "r") binf = f.read() f.close() #Allow the users to handle File Errors #Open the SPI Flash Device manager = serial_flash_manager.SerialFlashManager(self.vendor, self.product, 2) flash = manager.get_flash_device() #Print out the device was found if self.s: self.s.Info("Found: %s" % str(flash)) #Erase the flash if self.s: self.s.Info("Erasing the SPI Flash device, this can take a minute or two...") flash.bulk_erase() #Write the binary file if self.s: self.s.Info("Flash erased, writing binary image to PROM") flash.write(0x00, binf) #Verify the data was read binf_rb = flash.read(0x00, len(binf)) binf_str = binf_rb.tostring() del flash del manager if binf_str != binf: raise NysaError("Image Verification Failed!, data written is not the same as data read") def program(self): """ Send a program signal to the board, the FPGA will attempt to read the binary image file from the SPI prom. If successful the 'done' LED will illuminate Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) if self.s: self.s.Important("Set signals to input") bbc.set_pins_to_input() bbc.set_pins_to_output() bbc.program_high() time.sleep(.5) bbc.program_low() time.sleep(.2) bbc.program_high() bbc.pins_on() bbc.set_pins_to_input() def read_bin_file(self, filepath): """ Read the binary image from the SPI Flash Args: filepath (String): Path to the filepath where the SPI image will be written to Returns: Nothing Raises: IOError: Problem openning file to write to """ manager = serial_flash_manager.SerialFlashManager(self.vendor, self.product, 2) flash = manager.get_flash_device() #Don't know how long the binary file is so we need to read the entire #Image binf_rb = flash.read(0x00, len(flash)) f = open(filepath, "w") binf_rb.tofile(f) f.close() def reset(self): """ Send a reset signal to the board, this is the same as pressing the 'reset' button Args: Nothing Returns: Nothing Raises: Nothing """ bbc = BitBangController(self.vendor, self.product, 2) bbc.set_soft_reset_to_output() bbc.soft_reset_high() time.sleep(.2) bbc.soft_reset_low() time.sleep(.2) bbc.soft_reset_high() bbc.pins_on() bbc.set_pins_to_input() def set_sync_fifo_mode(self): """ Change the mode of the FIFO to a synchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_sync_fifo() def set_debug_mode(self): """ Change the mode of the FIFO to a asynchronous FIFO Args: Nothing Returns: Nothing Raises: Nothing """ fifo = FifoController(self.vendor, self.product) fifo.set_async_fifo() def open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ self.dev = Ftdi() frequency = 30.0E6 latency = 4 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0) #Drain the input buffer self.dev.purge_buffers() #Reset #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) #Configure Clock frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() def ioctl(self, name, arg = None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name)
class ft2232: def open_ft2232(self, vps, itf, sn): # find the device on USB devices = usbtools.UsbTools.find_all(vps) if sn is not None: # filter based on device serial number devices = [dev for dev in devices if dev[2] == sn] if len(devices) == 0: raise IOError("No such device") self.vid = devices[0][0] self.pid = devices[0][1] self.sn = devices[0][2] self.ftdi = Ftdi() self.freq = self.ftdi.open_mpsse(self.vid, self.pid, itf, serial=self.sn, frequency=_FREQ) self.wrbuf = array.array('B') self.gpio_init() self.state_reset() self.sir_end_state = 'IDLE' self.sdr_end_state = 'IDLE' def __del__(self): if self.ftdi: self.ftdi.close() def flush(self): """flush the write buffer to the ft2232""" if len(self.wrbuf) > 0: self.ftdi.write_data(self.wrbuf) del self.wrbuf[0:] def write(self, buf, flush=False): """queue write data to send to ft2232""" self.wrbuf.extend(buf) if flush: self.flush() def state_x(self, dst): """change the TAP state from self.state to dst""" if self.state == dst: return tms = tms_mpsse(tap.lookup(self.state, dst)) cmd = _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG self.write((cmd, tms[0], tms[1]), True) self.state = dst def state_reset(self): """from *any* state go to the reset state""" self.state = '*' self.state_x('RESET') def shift_data(self, tdi, tdo, end_state): """ write (and possibly read) a bit stream from the JTAGkey tdi - bit buffer of data to be written to the JTAG TDI pin tdo - bit buffer for the data read from the JTAG TDO pin (optional) end_state - leave the TAP state machine in this state """ wr = tdi.get() io_bits = tdi.n - 1 io_bytes = io_bits >> 3 io_bits &= 0x07 last_bit = (wr[io_bytes] << (7 - io_bits)) & 128 if tdo is not None: read_cmd = _MPSSE_DO_READ read_len = io_bytes + 1 if io_bits: read_len += 1 else: read_cmd = 0 read_len = 0 # write out the full bytes if io_bytes: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_WRITE_NEG num = io_bytes - 1 self.write((cmd, _lsb(num), _msb(num))) self.write(wr[0:io_bytes]) # write out the remaining bits if io_bits: cmd = read_cmd | _MPSSE_DO_WRITE | _MPSSE_LSB | _MPSSE_BITMODE | _MPSSE_WRITE_NEG self.write((cmd, io_bits - 1, wr[io_bytes])) # the last bit of output data is bit 7 of the tms value (goes onto tdi) # continue to read to get the last bit of tdo data cmd = read_cmd | _MPSSE_WRITE_TMS | _MPSSE_BITMODE | _MPSSE_LSB | _MPSSE_WRITE_NEG tms = tms_mpsse(tap.lookup(self.state, end_state)) self.write((cmd, tms[0], tms[1] | last_bit)) self.state = end_state # if we are only writing, return if tdo is None: self.flush() return # make the ft2232 flush its data back to the PC self.write((Ftdi.SEND_IMMEDIATE, ), True) rd = self.ftdi.read_data_bytes(read_len, _READ_RETRIES) if io_bits: # the n partial bits are in the top n bits of the byte # move them down to the bottom rd[-2] >>= (8 - io_bits) # get the last bit from the tms response byte (last byte) last_bit = (rd[-1] >> (7 - tms[0])) & 1 last_bit <<= io_bits # add the last bit if io_bits: # drop the tms response byte del rd[-1] # or it onto the io_bits byte rd[-1] |= last_bit else: # replace the tms response byte rd[-1] = last_bit # copy to the bit buffer tdo.set(tdi.n, rd) def scan_ir(self, tdi, tdo=None): """write (and possibly read) a bit stream through the IR in the JTAG chain""" self.state_x('IRSHIFT') self.shift_data(tdi, tdo, self.sir_end_state) def scan_dr(self, tdi, tdo=None): """write (and possibly read) a bit stream through the DR in the JTAG chain""" self.state_x('DRSHIFT') self.shift_data(tdi, tdo, self.sdr_end_state) def gpio_init(self): """setup the gpio lines""" self.gpio_dir = _TCK | _TDI | _TMS self.gpio_val = 0 self.ftdi.write_data( (Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) self.ftdi.write_data( (Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_wr(self, gpio, val): """write a gpio pin""" self.gpio_dir |= gpio if val: self.gpio_val |= gpio else: self.gpio_val &= ~gpio if gpio <= _GPIOL3: self.ftdi.write_data( (Ftdi.SET_BITS_LOW, _lsb(self.gpio_val), _lsb(self.gpio_dir))) else: self.ftdi.write_data( (Ftdi.SET_BITS_HIGH, _msb(self.gpio_val), _msb(self.gpio_dir))) def gpio_rd(self, gpio): """read a gpio pin""" if gpio <= _GPIOL3: self.ftdi.write_data((Ftdi.GET_BITS_LOW, )) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] else: self.ftdi.write_data((Ftdi.GET_BITS_HIGH, )) val = self.ftdi.read_data_bytes(1, _READ_RETRIES)[0] val <<= 8 return (val & gpio) != 0
class _Artemis(Nysa): """ Artemis Concrete Class that implemented Artemis specific communication functions """ def __init__(self, idVendor=0x0403, idProduct=0x8531, sernum=None, status=False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Artemis will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Artemis" self.interrupts = 0x00 self.events = [] for i in range(INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = ArtemisData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Artemis until a read and reset occurs #self.ping() pass except NysaCommError: pass self.reset() ''' #status = True self.reader_thread = ReaderThread(self.dev, self.interrupt_update_callback, self.lock, status = status) self.reader_thread.setName("Reader Thread") #XXX: Need to find a better way to shut this down self.reader_thread.setDaemon(True) self.reader_thread.start() ''' def __del__(self): #if self.s: self.s.Debug( "Close reader thread") #self.lock.aquire() #if (self.reader_thread is not None) and self.reader_thread.isAlive(): # self.reader_thread.stop() # self.s.Debug( "Waiting to join") # self.reader_thread.join() #self.lock.release() #self.s = True #if self.s: self.s.Debug( "Reader thread joined") #self.dev.close() pass def _open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ #This frequency should go up to 60MHz frequency = 30.0E6 #Latency can go down to 2 but there is a small chance there will be a #crash latency = 2 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0, serial=self.sernum) #Drain the input buffer self.dev.purge_buffers() #Reset #Configure Clock #frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size (Maximum Chunk size) self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) def ipc_comm_response(self, name): try: resp = self.hrq.get(block=True, timeout=ARTEMIS_QUEUE_TIMEOUT) if resp == ARTEMIS_RESP_OK: #print "%s got an OK response!" % current_thread().name return self.d.data else: raise NysaCommError("Artemis response error %s: %d" % (name, resp)) except Queue.Empty: raise NysaCommError("Artemis error %s: timeout: %d" % (name, ARTEMIS_QUEUE_TIMEOUT)) def read(self, address, length=1, disable_auto_inc=False): """read read data from Artemis Command Format ID 02 NN NN NN OO AA AA AA ID: ID Byte (0xCD) 02: Read Command (12 for memory read) NN: Size of Read (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, (4 bytes including offset for mem) Args: address (long): Address of the register/memory to read length (int): Number of 32-bit words to read disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: (Byte Array): A byte array containing the raw data returned from Artemis Raises: NysaCommError """ with self.lock: self.d.data = Array('B', [0xCD, 0x02]) if address >= ARTEMIS_MEMORY_OFFSET: address -= ARTEMIS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) #Add the address addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.length = length self.hwq.put(ARTEMIS_READ) return self.ipc_comm_response("read") def write(self, address, data, disable_auto_inc=False): """write Write data to a Nysa image Command Format ID 01 NN NN NN OO AA AA AA DD DD DD DD ID: ID Byte (0xCD) 01: Write Command (11 for Memory Write) NN: Size of Write (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, #(4 bytes including offset for mem) DD: Data (4 bytes) Args: address (long): Address of the register/memory to write to memory_device (boolean): True: Memory device False: Peripheral device data (array of bytes): Array of raw bytes to send to the devcie disable_auto_inc (boolean): Default False Set to true if only writing to one memory address (FIFO Mode) Returns: Nothing Raises: NysaCommError """ with self.lock: length = len(data) / 4 #Create an Array with the identification byte and code for writing self.d.data = Array('B', [0xCD, 0x01]) if address >= ARTEMIS_MEMORY_OFFSET: address -= ARTEMIS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 #Append the length into the first 24 bits fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.data.extend(data) self.hwq.put(ARTEMIS_WRITE) self.ipc_comm_response("write") def ping(self): """ping Command Format ID 00 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 00: Ping Command 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: Nothing Raises: NysaCommError """ with self.lock: self.hwq.put(ARTEMIS_PING) self.ipc_comm_response("ping") def reset(self): """ reset Software reset the Nysa FPGA Master, this may not actually reset the entire FPGA image ID 03 00 00 00 ID: ID Byte (0xCD) 00: Reset Command 00 00 00: Zeros Args: Nothing Return: Nothing Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(ARTEMIS_RESET) self.ipc_comm_response("reset") def is_programmed(self): """ Check if the FPGA is programmed Args: Nothing Return (Boolean): True: FPGA is programmed False: FPGA is not programmed Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(ARTEMIS_IS_PROGRAMMED) self.dev.purge_buffers() return self.ipc_comm_response("is programmed") def dump_core(self): """ dump_core Returns the state of the wishbone master priorto a reset, this is usefu for statusging a crash Command Format ID 0F 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 0F: Dump Core Command 00 00 00 00 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: (Array of 32-bit Values) to be parsed by the core_analyzer utility Raises: NysaCommError: A failure in communication is detected """ with self.lock: self.hwq.put(ARTEMIS_DUMP_CORE) return self.ipc_comm_response("dump core") def register_interrupt_callback(self, index, callback): """ register_interrupt Setup the thread to call the callback when an interrupt is detected Args: index (Integer): bit position of the device if the device is 1, then set index = 1 callback: a function to call when an interrupt is detected Returns: Nothing Raises: Nothing """ self.worker.register_interrupt_cb(index, callback) def unregister_interrupt_callback(self, index, callback=None): """ unregister_interrupt_callback Removes an interrupt callback from the reader thread list Args: index (Integer): bit position of the associated device EX: if the device that will receive callbacks is 1, index = 1 callback: a function to remove from the callback list Returns: Nothing Raises: Nothing (This function fails quietly if ther callback is not found) """ self.worker.unregister_interrupt_cb(index, callback) def wait_for_interrupts(self, wait_time=1, dev_id=None): """ wait_for_interrupts listen for interrupts for the user specified amount of time The Nysa image will send a small packet of info to the host when a slave needs to send information to the host Response Format DC 01 00 00 00 II II II II DC: Inverted CD is the start of a response 01: Interrupt ID 00 00 00 00 00 00 00 00: Zeros, reserved for future use II II II II: 32-bit interrupts Args: wait_time (Integer): the amount of time in seconds to wait for an interrupt dev_id (Integer): Optional device id, if set the function will look if an interrupt has already been declared for that function, if so then return immediately otherwise setup a callback for this Returns (boolean): True: Interrupts were detected Falses: Interrupts were not detected Raises: NysaCommError: A failure in communication is detected """ if dev_id is None: dev_id = 0 e = self.events[dev_id] #print "Checking events!" with self.lock: #Check if we have interrupts if (self.interrupts & (1 << dev_id)) > 0: #There are already existing interrupts, we're done return True #if we don't have interrupts clear the associated event #Clear the event, the interrupt handler will unblock this e.clear() #Now wait for interrupts if e.wait(wait_time): #Received an interrupt return True #Timed out while waiting for interrupts e.set() return False def interrupt_update_callback(self, interrupts): #print "Entered interrupt update callback" self.interrupts = interrupts for i in range(INTERRUPT_COUNT): if i == 0: if not self.events[i].is_set(): #self.s.Debug( "interrupt!") self.events[i].set() elif (self.interrupts & (1 << i)) > 0: if not self.events[i].is_set(): self.events[i].set() def get_board_name(self): return "Artemis" def upload(self, filepath): artemis_utils.upload(self.vendor, self.product, self.sernum, filepath, self.s) def program(self): artemis_utils.program(self.vendor, self.product, self.sernum, self.s) def ioctl(self, name, arg=None): raise AssertionError( "%s not implemented" % sys._getframe().f_code.co_name, self.s) def list_ioctl(self): raise AssertionError( "%s not implemented" % sys._getframe().f_code.co_name, self.s) def get_sdb_base_address(self): return 0x00000000
class _Dionysus (Nysa): """ Dionysus Concrete Class that implemented Dionysus specific communication functions """ def __init__(self, idVendor = 0x0403, idProduct = 0x8530, sernum = None, status = False): Nysa.__init__(self, status) self.vendor = idVendor self.product = idProduct self.sernum = sernum self.dev = None #Run a full garbage collection so any previous references to Dionysus will be removed gc.collect() self.lock = threading.Lock() self.dev = Ftdi() self._open_dev() self.name = "Dionysus" self.interrupts = 0x00 self.events = [] for i in range (INTERRUPT_COUNT): e = threading.Event() e.set() self.events.append(e) self.hwq = Queue.Queue(10) self.hrq = Queue.Queue(10) self.d = DionysusData() self.worker = WorkerThread(self.dev, self.hwq, self.hrq, self.d, self.lock, self.interrupt_update_callback) #Is there a way to indicate closing self.worker.setDaemon(True) self.worker.start() try: #XXX: Hack to fix a strange bug where FTDI #XXX: won't recognize Dionysus until a read and reset occurs self.ping() except NysaCommError: pass self.reset() ''' #status = True self.reader_thread = ReaderThread(self.dev, self.interrupt_update_callback, self.lock, status = status) self.reader_thread.setName("Reader Thread") #XXX: Need to find a better way to shut this down self.reader_thread.setDaemon(True) self.reader_thread.start() ''' def __del__(self): #if self.s: self.s.Debug( "Close reader thread") #self.lock.aquire() #if (self.reader_thread is not None) and self.reader_thread.isAlive(): # self.reader_thread.stop() # self.s.Debug( "Waiting to join") # self.reader_thread.join() #self.lock.release() #self.s = True #if self.s: self.s.Debug( "Reader thread joined") #self.dev.close() pass def _open_dev(self): """_open_dev Open an FTDI Communication Channel Args: Nothing Returns: Nothing Raises: Exception """ #This frequency should go up to 60MHz frequency = 30.0E6 #Latency can go down to 2 but there is a small chance there will be a #crash latency = 2 #Ftdi.add_type(self.vendor, self.product, 0x700, "ft2232h") self.dev.open(self.vendor, self.product, 0, serial = self.sernum) #Drain the input buffer self.dev.purge_buffers() #Reset #Configure Clock #frequency = self.dev._set_frequency(frequency) #Set Latency Timer self.dev.set_latency_timer(latency) #Set Chunk Size (Maximum Chunk size) self.dev.write_data_set_chunksize(0x10000) self.dev.read_data_set_chunksize(0x10000) #Set the hardware flow control self.dev.set_flowctrl('hw') self.dev.purge_buffers() #Enable MPSSE Mode self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF) def ipc_comm_response(self, name): try: resp = self.hrq.get(block = True, timeout = DIONYSUS_QUEUE_TIMEOUT) if resp == DIONYSUS_RESP_OK: #print "%s got an OK response!" % current_thread().name return self.d.data else: raise NysaCommError("Dionysus response error %s: %d" % (name, resp)) except Queue.Empty: raise NysaCommError("Dionysus error %s: timeout: %d" % (name, DIONYSUS_QUEUE_TIMEOUT)) def read(self, address, length = 1, disable_auto_inc = False): """read read data from Dionysus Command Format ID 02 NN NN NN OO AA AA AA ID: ID Byte (0xCD) 02: Read Command (12 for memory read) NN: Size of Read (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, (4 bytes including offset for mem) Args: address (long): Address of the register/memory to read length (int): Number of 32-bit words to read disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: (Byte Array): A byte array containing the raw data returned from Dionysus Raises: NysaCommError """ with self.lock: self.d.data = Array('B', [0xCD, 0x02]) if address >= DIONYSUS_MEMORY_OFFSET: address -= DIONYSUS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) #Add the address addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.length = length self.hwq.put(DIONYSUS_READ) return self.ipc_comm_response("read") def write(self, address, data, disable_auto_inc = False): """write Write data to a Nysa image Command Format ID 01 NN NN NN OO AA AA AA DD DD DD DD ID: ID Byte (0xCD) 01: Write Command (11 for Memory Write) NN: Size of Write (3 Bytes) OO: Offset (for peripheral, part of address for mem) AA: Address (3 bytes for peripheral, #(4 bytes including offset for mem) DD: Data (4 bytes) Args: address (long): Address of the register/memory to write to memory_device (boolean): True: Memory device False: Peripheral device data (array of bytes): Array of raw bytes to send to the devcie disable_auto_inc (boolean): Default False Set to true if only writing to one memory address (FIFO Mode) Returns: Nothing Raises: NysaCommError """ with self.lock: length = len(data) / 4 #Create an Array with the identification byte and code for writing self.d.data = Array ('B', [0xCD, 0x01]) if address >= DIONYSUS_MEMORY_OFFSET: address -= DIONYSUS_MEMORY_OFFSET self.d.data[1] = self.d.data[1] | 0x10 if disable_auto_inc: self.d.data[1] = self.d.data[1] | 0x20 #Append the length into the first 24 bits fmt_string = "%06X" % length self.d.data.fromstring(fmt_string.decode('hex')) addr_string = "%08X" % (address & 0xFFFFFFFF) self.d.data.fromstring(addr_string.decode('hex')) self.d.data.extend(data) self.hwq.put(DIONYSUS_WRITE) self.ipc_comm_response("write") def ping (self): """ping Command Format ID 00 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 00: Ping Command 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: Nothing Raises: NysaCommError """ with self.lock: self.hwq.put(DIONYSUS_PING) self.ipc_comm_response("ping") def reset (self): """ reset Software reset the Nysa FPGA Master, this may not actually reset the entire FPGA image ID 03 00 00 00 ID: ID Byte (0xCD) 00: Reset Command 00 00 00: Zeros Args: Nothing Return: Nothing Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(DIONYSUS_RESET) self.ipc_comm_response("reset") def is_programmed(self): """ Check if the FPGA is programmed Args: Nothing Return (Boolean): True: FPGA is programmed False: FPGA is not programmed Raises: NysaCommError: Failue in communication """ with self.lock: self.d.data = (self.vendor, self.product) self.hwq.put(DIONYSUS_IS_PROGRAMMED) return self.ipc_comm_response("is programmed") def dump_core(self): """ dump_core Returns the state of the wishbone master priorto a reset, this is usefu for statusging a crash Command Format ID 0F 00 00 00 00 00 00 00 ID: ID Byte (0xCD) 0F: Dump Core Command 00 00 00 00 00 00 00 00 00 00 00: Zeros Args: Nothing Returns: (Array of 32-bit Values) to be parsed by the core_analyzer utility Raises: NysaCommError: A failure in communication is detected """ with self.lock: self.hwq.put(DIONYSUS_DUMP_CORE) return self.ipc_comm_response("dump core") def register_interrupt_callback(self, index, callback): """ register_interrupt Setup the thread to call the callback when an interrupt is detected Args: index (Integer): bit position of the device if the device is 1, then set index = 1 callback: a function to call when an interrupt is detected Returns: Nothing Raises: Nothing """ self.worker.register_interrupt_cb(index, callback) def unregister_interrupt_callback(self, index, callback = None): """ unregister_interrupt_callback Removes an interrupt callback from the reader thread list Args: index (Integer): bit position of the associated device EX: if the device that will receive callbacks is 1, index = 1 callback: a function to remove from the callback list Returns: Nothing Raises: Nothing (This function fails quietly if ther callback is not found) """ self.worker.unregister_interrupt_cb(index, callback) def wait_for_interrupts(self, wait_time = 1, dev_id = None): """ wait_for_interrupts listen for interrupts for the user specified amount of time The Nysa image will send a small packet of info to the host when a slave needs to send information to the host Response Format DC 01 00 00 00 II II II II DC: Inverted CD is the start of a response 01: Interrupt ID 00 00 00 00 00 00 00 00: Zeros, reserved for future use II II II II: 32-bit interrupts Args: wait_time (Integer): the amount of time in seconds to wait for an interrupt dev_id (Integer): Optional device id, if set the function will look if an interrupt has already been declared for that function, if so then return immediately otherwise setup a callback for this Returns (boolean): True: Interrupts were detected Falses: Interrupts were not detected Raises: NysaCommError: A failure in communication is detected """ if dev_id is None: dev_id = 0 e = self.events[dev_id] #print "Checking events!" with self.lock: #Check if we have interrupts if (self.interrupts & (1 << dev_id)) > 0: #There are already existing interrupts, we're done return True #if we don't have interrupts clear the associated event #Clear the event, the interrupt handler will unblock this e.clear() #Now wait for interrupts if e.wait(wait_time): #Received an interrupt return True #Timed out while waiting for interrupts e.set() return False def interrupt_update_callback(self, interrupts): #print "Entered interrupt update callback" self.interrupts = interrupts for i in range (INTERRUPT_COUNT): if i == 0: if not self.events[i].is_set(): #self.s.Debug( "interrupt!") self.events[i].set() elif (self.interrupts & (1 << i)) > 0: if not self.events[i].is_set(): self.events[i].set() def get_board_name(self): return "Dionysus" def upload(self, filepath): dionysus_utils.upload(self.vendor, self.product, self.sernum, filepath, self.s) def program (self): dionysus_utils.program(self.vendor, self.product, self.sernum, self.s) def ioctl(self, name, arg = None): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name, self.s) def list_ioctl(self): raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name, self.s) def get_sdb_base_address(self): return 0x00000000
class SpiController(object): """SPI master. :param silent_clock: should be set to avoid clocking out SCLK when all /CS signals are released. This clock beat is used to enforce a delay between /CS signal activation. When weird SPI devices are used, SCLK beating may cause trouble. In this case, silent_clock should be set but beware that SCLK line should be fitted with a pull-down resistor, as SCLK is high-Z during this short period of time. :param cs_count: is the number of /CS lines (one per device to drive on the SPI bus) """ SCK_BIT = 0x01 DO_BIT = 0x02 DI_BIT = 0x04 CS_BIT = 0x08 PAYLOAD_MAX_LENGTH = 0x10000 # 16 bits max def __init__(self, silent_clock=False, cs_count=4): self._ftdi = Ftdi() self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & \ ~(SpiController.CS_BIT - 1) self._ports = [None] * cs_count self._direction = self._cs_bits | \ SpiController.DO_BIT | \ SpiController.SCK_BIT self._cs_high = Array('B') if silent_clock: # Set SCLK as input to avoid emitting clock beats self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT]) # /CS to SCLK delay, use 8 clock cycles as a HW tempo self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8-1, 0xff]) # Restore idle state self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction]) self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE]) self._frequency = 0.0 def configure(self, vendor, product, interface, frequency=6.0E6): """Configure the FTDI interface as a SPI master""" self._frequency = \ self._ftdi.open_mpsse(vendor, product, interface, direction=self._direction, initial=self._cs_bits, # /CS all high frequency=frequency) def terminate(self): """Close the FTDI interface""" if self._ftdi: self._ftdi.close() self._ftdi = None def get_port(self, cs): """Obtain a SPI port to drive a SPI device selected by cs""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if cs >= len(self._ports): raise SpiIOError("No such SPI port") if not self._ports[cs]: cs_state = 0xFF & ~((SpiController.CS_BIT<<cs) | SpiController.SCK_BIT | SpiController.DO_BIT) cs_cmd = Array('B', [Ftdi.SET_BITS_LOW, cs_state, self._direction]) self._ports[cs] = SpiPort(self, cs_cmd) self._flush() return self._ports[cs] @property def frequency_max(self): """Returns the maximum SPI clock""" return self._ftdi.frequency_max @property def frequency(self): """Returns the current SPI clock""" return self._frequency def _exchange(self, frequency, cs_cmd, out, readlen): """Perform a half-duplex transaction with the SPI slave""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if self._frequency != frequency: freq = self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency write_cmd = struct.pack('<BH', Ftdi.WRITE_BYTES_NVE_MSB, len(out)-1) if readlen: read_cmd = struct.pack('<BH', Ftdi.READ_BYTES_NVE_MSB, readlen-1) cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.fromstring(read_cmd) cmd.extend(self._immediate) cmd.extend(self._cs_high) self._ftdi.write_data(cmd) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.extend(self._cs_high) self._ftdi.write_data(cmd) data = Array('B') return data def _flush(self): """Flush the HW FIFOs""" self._ftdi.write_data(self._immediate) self._ftdi.purge_buffers()
class SpiController(object): """SPI master. :param silent_clock: should be set to avoid clocking out SCLK when all /CS signals are released. This clock beat is used to enforce a delay between /CS signal activation. When weird SPI devices are used, SCLK beating may cause trouble. In this case, silent_clock should be set but beware that SCLK line should be fitted with a pull-down resistor, as SCLK is high-Z during this short period of time. :param cs_count: is the number of /CS lines (one per device to drive on the SPI bus) """ SCK_BIT = 0x01 DO_BIT = 0x02 DI_BIT = 0x04 CS_BIT = 0x08 PAYLOAD_MAX_LENGTH = 0x10000 # 16 bits max def __init__(self, silent_clock=False, cs_count=4): self._ftdi = Ftdi() self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & \ ~(SpiController.CS_BIT - 1) self._ports = [None] * cs_count self._direction = self._cs_bits | \ SpiController.DO_BIT | \ SpiController.SCK_BIT self._cs_high = Array('B') if silent_clock: # Set SCLK as input to avoid emitting clock beats self._cs_high.extend([ Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT ]) # /CS to SCLK delay, use 8 clock cycles as a HW tempo self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xff]) # Restore idle state self._cs_high.extend( [Ftdi.SET_BITS_LOW, self._cs_bits, self._direction]) self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE]) self._frequency = 0.0 def configure(self, vendor, product, interface, frequency=6.0E6): """Configure the FTDI interface as a SPI master""" self._frequency = \ self._ftdi.open_mpsse(vendor, product, interface, direction=self._direction, initial=self._cs_bits, # /CS all high frequency=frequency) def terminate(self): """Close the FTDI interface""" if self._ftdi: self._ftdi.close() self._ftdi = None def get_port(self, cs): """Obtain a SPI port to drive a SPI device selected by cs""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if cs >= len(self._ports): raise SpiIOError("No such SPI port") if not self._ports[cs]: cs_state = 0xFF & ~((SpiController.CS_BIT << cs) | SpiController.SCK_BIT | SpiController.DO_BIT) cs_cmd = Array('B', [Ftdi.SET_BITS_LOW, cs_state, self._direction]) self._ports[cs] = SpiPort(self, cs_cmd) self._flush() return self._ports[cs] @property def frequency_max(self): """Returns the maximum SPI clock""" return self._ftdi.frequency_max @property def frequency(self): """Returns the current SPI clock""" return self._frequency def _exchange(self, frequency, cs_cmd, out, readlen): """Perform a half-duplex transaction with the SPI slave""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if self._frequency != frequency: freq = self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency write_cmd = struct.pack('<BH', Ftdi.WRITE_BYTES_NVE_MSB, len(out) - 1) if readlen: read_cmd = struct.pack('<BH', Ftdi.READ_BYTES_NVE_MSB, readlen - 1) cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.fromstring(read_cmd) cmd.extend(self._immediate) cmd.extend(self._cs_high) self._ftdi.write_data(cmd) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.extend(self._cs_high) self._ftdi.write_data(cmd) data = Array('B') return data def _flush(self): """Flush the HW FIFOs""" self._ftdi.write_data(self._immediate) self._ftdi.purge_buffers()