Exemplo n.º 1
0
 def test_gpio_loopback(self):
     """Check I/O.
     """
     if self.skip_loopback:
         raise SkipTest('Skip loopback test on multiport device')
     gpio = GpioAsyncController()
     direction = 0xFF & ~((1 << 4) - 1)  # 4 Out, 4 In
     gpio.configure(self.url, direction=direction, frequency=800000)
     for out in range(16):
         # print(f'Write {out:04b} -> {out << 4:08b}')
         gpio.write(out << 4)
         fback = gpio.read()
         lsbs = fback & ~direction
         msbs = fback >> 4
         # check inputs match outputs
         self.assertEqual(lsbs, out)
         # check level of outputs match the ones written
         self.assertEqual(msbs, out)
     outs = list([(out & 0xf) << 4 for out in range(1000)])
     gpio.write(outs)
     gpio.ftdi.read_data(512)
     for _ in range(len(outs)):
         _ = gpio.read(14)
     last = outs[-1] >> 4
     for _ in range(10):
         fbacks = gpio.read(1000)
         for fback in fbacks:
             lsbs = fback & ~direction
             msbs = fback >> 4
             # check inputs match last output
             self.assertEqual(lsbs, last)
             # check level of output match the last written
             self.assertEqual(msbs, last)
     gpio.close()
Exemplo n.º 2
0
	def transmitAsync(self, halfPeriod=0.005):
		gpio = GpioAsyncController()
		gpio.configure(self.device, self.directionArray[0])
		for i in range(len(self.txArray)):
			if (self.directionArray[i] != self.directionArray[i-1]):
				time.sleep(halfPeriod)
				gpio.close()
				gpio = GpioAsyncController()
				gpio.configure(self.device, self.directionArray[i])
				time.sleep(halfPeriod)
				#print("new direction: "+hex(self.directionArray[i]))
			# read the state of the port
			self.rxArray.append( gpio.read() )
			#print("read: "+hex(self.rxArray[-1]))
			# write to the outputs (0 is OK to write to inputs)
			gpio.write(self.txArray[i])
			#print("write: "+hex(self.txArray[i]))
			# wait half a clock cycle
			time.sleep(halfPeriod)
		gpio.close()
Exemplo n.º 3
0
 def test_gpio_baudate(self):
     # this test requires an external device (logic analyser or scope) to
     # check the bitbang read and bitbang write signal (BB_RD, BB_WR) and
     # mesure their frequency. The EEPROM should be configured to enable
     # those signal on some of the CBUS pins, for example.
     gpio = GpioAsyncController()
     direction = 0xFF & ~((1 << 4) - 1)  # 4 Out, 4 In
     gpio.configure(self.url, direction=direction)
     buf = bytes([0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00])
     freqs = [50e3, 200e3, 1e6, 3e6]
     if gpio.ftdi.is_H_series:
         freqs.extend([6e6, 10e6, 12e6])
     gpio.read(128)
     for freq in freqs:
         # set the bitbang refresh rate
         gpio.set_frequency(freq)
         self.assertEqual(gpio.frequency, freq)
         # be sure to leave enough time to purge buffers (HW FIFO) or
         # the frequency changes occur on the current buffer...
         gpio.write(buf)
         gpio.read(128)
         sleep(0.01)
     gpio.close()
Exemplo n.º 4
0
class FtdiDevice:
    """FTDI FT2232H SPI master to access FPGA Control/Status Registers (CSR)
    plus some GPIO control.

    SPI parameters:
      - FTDI channel B:
        * BDBUS0 - SCLK
        * BDBUS1 - MOSI
        * BDBUS2 - MISO
        * BDBUS3 - CSn
      - slave;
      - mode 0 only;
      - most significant bit transmitted first;
      - byte order from high to low;
      - SCK frequency must at least 8 lower than system frequency.

    There are 2 types of SPI transactions:
      - incremental burst -- address increments internally after every data (array)
      - fixed burst -- one adreess, multiple data (FIFO)
    Transaction is done with 8-bit address and 16 bit data words.
    Transaction format:
      - control word (3 bytes):
          * bit 23 -- write (1) or read (0)
          * bit 22 -- burst incremental (1) or fixed (0)
          * bit 21 .. 8 -- 14 bit length (0 - 1 data word, 1 - 2 data words, etc)
          * bits 7 .. 0 -- 8 bit address
      - data word (2 bytes) 1 .. N:
          * bits 15 .. 0 -- data to be written or readen

    GPIO parameters:
      - ADBUS7 - output - active low reset for FPGA configuration (ICE_RESET)
      - BDBUS7 - output - active high reset for FPGA logic (ICE_RESET_FT)
    """

    GPIO_RESET_LOGIC_POS = 7
    GPIO_RESET_CONFIG_POS = 7

    def __init__(self, ftdi_url, spi_freq=1E6):
        """Configure the FTDI interface.

        Keyword arguments:
         ftdi_url -- device url, which can be obtained by Ftdi.show_devices()
         freq -- SPI frequency up to 8E6 (for FPGA running on 64 MHz)
        """
        # Configure SPI master
        self._spi_ctrl = SpiController()
        self._spi_ctrl.configure(ftdi_url + '2')  # second port - channel B
        self._spi_port = self._spi_ctrl.get_port(cs=0, freq=spi_freq, mode=0)
        # Configure FPGA logic reset (ICE_RESET_FT)
        self._spi_gpio = self._spi_ctrl.get_gpio()
        self._spi_gpio.set_direction(1 << self.GPIO_RESET_LOGIC_POS,
                                     1 << self.GPIO_RESET_LOGIC_POS)
        self._spi_gpio.write(0)
        # Configure FPGA configuration reset (ICE_RESET)
        self._gpio_ctrl = GpioAsyncController()
        self._gpio_ctrl.configure(
            ftdi_url + '1',  # first port - channel A
            direction=(1 << self.GPIO_RESET_CONFIG_POS),
            frequency=1e6,
            initial=(1 << self.GPIO_RESET_CONFIG_POS))
        self._gpio_ctrl.write(1 << self.GPIO_RESET_CONFIG_POS)

    def _int_to_bytes(self, i, length=2):
        """Convert integer to bytes"""
        return int.to_bytes(i, length=length, byteorder='big', signed=False)

    def _words_to_bytes(self, words_list):
        """Convert list with 16 bit words to bytes"""
        bytes_str_list = [self._int_to_bytes(w, length=2) for w in words_list]
        return b''.join(bytes_str_list)  # concatenate all strings

    def _bytes_to_words(self, bytes_str):
        """Convert bytes string to list with 16 bit words"""
        return [
            int.from_bytes(bytes_str[b * 2:b * 2 + 2],
                           byteorder='big',
                           signed=False) for b in range(len(bytes_str) // 2)
        ]

    def _prepare_ctrl_word(self, addr, len, burst, wr):
        """Prepare control word for exchange.

           Keyword arguments:
             addr -- 8 bit address
             len -- number of 16 bit data words to write/read (2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
             wr -- 1 for write operation, 0 - for read
        """
        ctrl_word = 0
        ctrl_word |= (wr << 23)
        ctrl_word |= ((burst == 'incr') << 22)
        ctrl_word |= (((len - 1) & 0x3FFF) << 8)
        ctrl_word |= ((addr & 0xFF) << 0)
        return ctrl_word

    def spi_read(self, addr, len=1, burst='fixed'):
        """Read data from address via SPI.

           Keyword arguments:
             addr -- 8 bit address
             len -- number of 16 bit data words to write/read (2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
           Return:
             list of size 'len' with 16 bit data words
        """
        ctrl_word = self._prepare_ctrl_word(addr, len, burst, wr=0)
        rbytes = self._spi_port.exchange(self._int_to_bytes(ctrl_word, 3),
                                         len * 2)
        return self._bytes_to_words(rbytes)

    def spi_write(self, addr, data, burst='fixed'):
        """Write data to address via SPI.

           Keyword arguments:
             addr -- 8 bit address
             data -- list with 16 bit data words to write (list length 2^14 max)
             burst -- 'fixed' address the same for every data, 'incr' - address + 1 for every next data word
         """
        ctrl_word = self._prepare_ctrl_word(addr, len(data), burst, wr=1)
        wbytes = self._int_to_bytes(ctrl_word, 3) + self._words_to_bytes(data)
        self._spi_port.exchange(wbytes)

    def reset_logic_on(self):
        """Activate reset pin ICE_RESET_FT"""
        self._spi_gpio.write((1 << self.GPIO_RESET_LOGIC_POS)
                             | self._spi_gpio.read())

    def reset_logic_off(self):
        """Deactivate reset pin ICE_RESET_FT"""
        self._spi_gpio.write(~(1 << self.GPIO_RESET_LOGIC_POS)
                             & self._spi_gpio.read())

    def reset_config_on(self):
        """Activate reset pin ICE_RESET"""
        self._gpio_ctrl.write(~(1 << self.GPIO_RESET_CONFIG_POS)
                              & self._gpio_ctrl.read())

    def reset_config_off(self):
        """Deactivate reset pin ICE_RESET"""
        self._gpio_ctrl.write((1 << self.GPIO_RESET_LOGIC_POS)
                              | self._gpio_ctrl.read())

    def close_connection(self):
        """Close FTDI interface"""
        self._spi_ctrl.terminate()
        self._gpio_ctrl.close()