Skip to content

Commit

Permalink
{device,target}: add FPGA/I2C health check after bitstream load.
Browse files Browse the repository at this point in the history
There have been reports of issues that are suspected to be manufacturing
defects related to the I2C bus, for example #688. These issues cause
a failure in one of the post-configuration code paths related to the I2C
bus, where it's difficult to display a good error message. This commit
adds a dedicated health check register and a dedicated error message:

    E: g.cli: FPGA health check failed; if you are using a newly
    manufactured device, ask the vendor of the device for return and
    replacement, else ask for support on community channels
  • Loading branch information
whitequark committed Sep 21, 2024
1 parent d7041e4 commit b3fed0d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
18 changes: 14 additions & 4 deletions software/glasgow/device/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,20 +459,30 @@ async def bitstream_id(self):

async def download_bitstream(self, bitstream, bitstream_id=b"\xff" * 16):
"""Download ``bitstream`` with ID ``bitstream_id`` to FPGA."""
# Send consecutive chunks of bitstream.
# Sending 0th chunk resets the FPGA.
# Send consecutive chunks of bitstream. Sending 0th chunk also clears the FPGA bitstream.
index = 0
while index * 1024 < len(bitstream):
await self.control_write(usb1.REQUEST_TYPE_VENDOR, REQ_FPGA_CFG,
0, index, bitstream[index * 1024:(index + 1) * 1024])
index += 1
# Complete configuration by setting bitstream ID.
# This starts the FPGA.
# Complete configuration by setting bitstream ID. This starts the FPGA.
try:
await self.control_write(usb1.REQUEST_TYPE_VENDOR, REQ_BITSTREAM_ID,
0, 0, bitstream_id)
except usb1.USBErrorPipe:
raise GlasgowDeviceError("FPGA configuration failed")
try:
# Each bitstream has an I2C register at address 0, which is used to check that the FPGA
# has configured properly and that the I2C bus function is intact. A small subset of
# production devices manufactured by 1bitSquared fails this check.
magic, = await self.control_read(usb1.REQUEST_TYPE_VENDOR, REQ_REGISTER, 0x00, 0, 1)
except usb1.USBErrorPipe:
magic = 0
if magic != 0xa5:
raise GlasgowDeviceError(
"FPGA health check failed; if you are using a newly manufactured device, "
"ask the vendor of the device for return and replacement, else ask for support "
"on community channels")

async def download_target(self, plan, *, reload=False):
if await self.bitstream_id() == plan.bitstream_id and not reload:
Expand Down
5 changes: 5 additions & 0 deletions software/glasgow/target/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ def __init__(self, revision, multiplexer_cls=None, with_analyzer=False):
self.i2c_target = I2CTarget(self.platform.request("i2c", dir={"scl": "-", "sda": "-"}))
self.registers = I2CRegisters(self.i2c_target)

# Always add a register at address 0x00, to be able to check that the FPGA configuration
# succeeded and that I2C communication works.
addr_health_check = self.registers.add_existing_ro(0xa5)
assert addr_health_check == 0x00

self.fx2_crossbar = FX2Crossbar(self.platform.request("fx2", dir={
"sloe": "-", "slrd": "-", "slwr": "-", "pktend": "-", "fifoadr": "-",
"flag": "-", "fd": "-"
Expand Down

0 comments on commit b3fed0d

Please sign in to comment.