Commit 1fa21579 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'ftdi_eeprom' into 'master'

Add script for initial FTDI EEPROM configuration

See merge request !2
parents 07fd2633 a811acec
#!/usr/bin/python3
"""
Initialize FTDI EEPROM and assign serial number.
Warning: this script may give undefined results if more than one FTDI chip is
connected to USB ports at the same time!
"""
# Copyright (C) 2023 CERN
# Author: Adrian Byszuk
# Released according to the LGPL-2.1-or-later
from pyftdi.eeprom import FtdiEeprom
from pyftdi.misc import hexdump
import struct
# EEPROM chip type (0x46, 0x56 or 0x66)
CHIP_TYPE = 0x56
# Xilinx magic constants for different FTDI chips
MAGIC_232H = 0x584a0002
MAGIC_2232H = 0x584a0003
MAGIC_4232H = 0x584a0004
eeprom = FtdiEeprom()
eeprom.open('ftdi://ftdi:ft4232h/1')
print('Dumping current EEPROM config')
eeprom.dump_config()
print(hexdump(eeprom.data))
try:
if eeprom.has_serial:
print('This FTDI has SN already assigned, aborting!')
exit(1)
except AttributeError:
pass
print('\nInitializing config:')
eeprom.initialize()
# Manufacturer has to be set to 'Xilinx' to stay compatible with Xilinx udev
# rules (part of driver installation package)
eeprom.set_manufacturer_name('Xilinx')
eeprom.set_product_name('DIOT FMC Carrier')
# uncomment to set your own SN instead of random one
# eeprom.set_serial_number('FT5PTILK')
# Now we're fiddling with a low level EEPROM layout. This layout isn't
# documented by FTDI, but it's somewhat documented in libftdi source code.
# There are a few things we need to set here to make FTDI chip recognizable as
# a JTAG dongle by Vivado.
# We need to use a few non-public class fields, so this code is prone to break
# on pyftdi update.
# ATTENTION: bit layout and meaning changes between FTDI device types !!!
#
# - chip type (not really necessary, but let's be nice)
eeprom._chip = CHIP_TYPE
chipoff = eeprom._PROPERTIES[eeprom.device_version].chipoff
eeprom._eeprom[chipoff] = CHIP_TYPE # usually at 0x18 offset
# - switch port A (JTAG), B (I2C) and D (unused) to D2XX type
eeprom._eeprom[0x00] = 0x80 # bit 3 - CH A D2xx, bit 7 - CH C VCP
eeprom._eeprom[0x01] = 0x00 # bit 3 - CH B D2xx, bit 7 - CH D D2XX
# - self powered, no remote wakeup, no battery powered
eeprom._eeprom[0x08] = 0xC0
# - use serial, no suspend_pull_down
eeprom._eeprom[0x0a] = 0x08
# - all channels rs485 disable
eeprom._eeprom[0x0b] = 0x00
# - group settings, other FT4232H dongles have 0 here
eeprom._eeprom[0x0c] = 0x00
eeprom._eeprom[0x0d] = 0x00
# - now the magic sequence at the beginning of user area
useroff = eeprom._PROPERTIES[eeprom.device_version].user
eeprom._eeprom[useroff:useroff+4] = struct.pack('<I', MAGIC_4232H)
# - vendor and product names, but different from generic FTDI ones
bstream = bytearray()
bstream.extend('CERN\0'.encode('utf-8')) # Vendor name
bstream.extend('DIOT FMC Carrier FT4232H\0'.encode('utf-8')) # Product name
eeprom._eeprom[useroff+4:useroff+4+len(bstream)] = bstream
eeprom._dirty.add('eeprom')
eeprom.sync()
eeprom.dump_config()
print(hexdump(eeprom.data))
print('Writing EEPROM...')
if not eeprom.commit(dry_run=False):
print('...done')
else:
print('error, no changes written')
......@@ -4,6 +4,10 @@ Configures Silabs 5341 clock generator.
On DIOT peripheral board there's embedded FTDI (FT4232) UART-to-I2C bridge.
"""
# Copyright (C) 2023 CERN
# Author: Adrian Byszuk
# Released according to the LGPL-2.1-or-later
from pyftdi.ftdi import Ftdi
from pyftdi.i2c import I2cController
from typing import Union, Iterable
......@@ -87,7 +91,7 @@ class si5341:
return
print('Starting NVM burn procedure')
self.write(0xe2, 0xc7)
self.write(0xe3, 0xc7)
while self.read(0xfe) != 0x0F:
pass
......@@ -98,6 +102,8 @@ class si5341:
new_bank = self.read(0xe2)
if (bank == 3 and new_bank == 15) or (bank == 15 and new_bank == 63):
print('NVM programmed properly')
else:
print('NVM programming failed, bank number didn\'t change')
def load_from_csv(self, path: Union[str, Path]) -> None:
"""Send device configuration from CSV file generated by ClockBuilder.
......@@ -149,3 +155,4 @@ dev.configure()
fname = 'Si5341-RevD-CCE-Registers.txt'
print(f'Loading configuration data from {fname}')
data = dev.load_from_csv(fname)
# dev.nvm_write()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment