def open(self): """Open the hardware device.""" self._burn_firmware() # device doesn't like to be reopened immediately after burning # firmware. time.sleep(.5) # open device's second interface (DAQ) self._device = FtdiChip(self.device_id, interface_select=2, device_index=self.device_index)
def open(self): """Open the hardware device.""" self._device = FtdiChip(self.description)
def _burn_firmware(self): """Burn the firmware to the device's FPGA. This was a pain to implement. Understanding this code entails going back and forth between the FTDI and Altera Cyclone manuals, as well as the HiSPARC schematics. The Cyclone has 16 data bits (page 5 in the manual) of which several are general purpose I/O (GPIO). The connections are up to the hardware designers. Connections FTDI <-> Cyclone (HiSPARC III hardware): bit 8: nCONFIG bit 9: CONF_DONE bit 10: nSTATUS Configuration of the FPGA is described on page 9-9 of the Cyclone manual. First, pull nCONFIG low (for at least 500 ns). nSTATUS and CONF_DONE are also pulled low by the device. Then, pull nCONFIG high and the device returns nSTATUS to a high state. If configuration is succesful, CONF_DONE is high. If an error occurs, nSTATUS is pulled low and CONF_DONE remains low. On page 9-13 in the Cyclone manual, the connections between the serial configuration device (the FTDI chip) and the Cyclone are described, along with the data connection and clock settings (page 9-14). References: Altera Cyclone III Device Handbook -- Volume 1 FTDI Application Note AN_108 -- Command Processor for MPSSE and MCU Host Bus Emulation Modes Basic information on using MPSSE mode (useful for understanding the bitmode, clock settings and writing the data): FTDI Application Note AN_135 -- FTDI MPSSE Basics """ # open device's first interface (MPSSE) device = FtdiChip(self.description, interface_select=1) # Select MPSSE mode (0x02) # Direction is not used here, it doesn't seem to work. # We'll set the direction explicitly later. device._device.ftdi_fn.ftdi_set_bitmode(0, 0x02) # Set clock frequency to 30 MHz (0x0000) device.write(bytearray([TCK_DIVISOR, 0, 0])) # Disable divide clock frequency by 5 device.write(bytearray([DISABLE_CLK_DIV5])) # bits 0 and 1 are output that is, bits TCK/SK and TDI/DO, clock and # data device.write(bytearray([SET_BITS_LOW, 0, 0b11])) # pull nCONFIG (low byte bit 0) low device.write(bytearray([SET_BITS_HIGH, 0, 1])) # pull nCONFIG (low byte bit 0) high device.write(bytearray([SET_BITS_HIGH, 1, 1])) # write firmware to device firmware = pkg_resources.resource_string(__name__, "firmware.rbf") for idx in range(0, len(firmware), FPGA_BUFFER_SIZE): xbuf = firmware[idx:idx + FPGA_BUFFER_SIZE] LENGTH = len(xbuf) - 1 LENGTH_L = LENGTH & 0xff LENGTH_H = LENGTH >> 8 & 0xff device.write(bytearray([WRITE_BYTES_PVE_LSB, LENGTH_L, LENGTH_H])) device.write(xbuf) # read device status device.write(bytearray([GET_BITS_HIGH])) time.sleep(.01) data_bits = ord(device.read(1)) # CONF_DONE is bit 8 (high byte, bit 1) conf_done = data_bits & 0b10 if not conf_done: raise HardwareError("Error loading firmware.") device.close()