예제 #1
1
파일: ft2232.py 프로젝트: deadsy/pycs
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)
예제 #3
0
파일: ft2232.py 프로젝트: deadsy/py_xsload
 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'
예제 #4
0
    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()
예제 #6
0
 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'
예제 #7
0
 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()



        '''
예제 #9
0
파일: ft2232.py 프로젝트: deadsy/pycs
 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'
예제 #10
0
 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 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()
예제 #12
0
파일: ft2232.py 프로젝트: deadsy/py_xsload
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)
예제 #16
0
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
예제 #17
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
예제 #19
0
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()
예제 #20
0
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()