CW305 SPI Flash AT25SF321 Not Supported as Configuration Memory Device

Hello,

I am using CW305 target with Artix-7 FPGA with part number xc7a100t,
and Vivado 2019.2 on Ubuntu 18.04 connected to the FPGA with JTAG cable.

I am trying to use the SPI flash as a configuration memory device that will provide the bitstream on power-up.

The problem is after clicking “Add configuration memory device…” in hardware manager of Vivado, the window that opens (where I should chose the configuration memory part number) does not include the built in SPI flash that exists on CW305.

The part number of the built in SPI flash is AT25SF321.

If I select one of the config. mem. devices that has the same properties, I get the following critical warning during programming the config. mem. device:

[Labtools 27-2251] Unable to read device properties. Please make sure that the proper configuration memory part is selected.

Also, I noticed that AT25SF321 is not listed as a supported configuration memory device in Vivado Programming and Debugging User Guide.

How should I proceed?

Can Aknesil

Hi Can,

Sorry for the problems here - the SPI flash memory devices seem to keep going obsolete or being out of stock when we do our runs, clearly in one of our subs it lost Vivado support! The schematic shows the original S25FL132 device.

The chip “should” work with the “S25FL032P” device, as that device doesn’t do a full ID-Code check (it checks only for the starting part, 1F). EDIT - This is incorrect - IDCode won’t match here actually, had wrong base conversion in my mind when writing this

The SAM3U might be trying to drive the SPI lines (I’ll need to check if that is the case). Try holding the “USB RST” button down, and re-doing the SPI flash discovery, while holding down the “USB RST” button the whole time (that keeps the SAM3U in reset).

If the IDCode check is failing. The IDCodes are defined in the file \tools\Xilinx\Vivado\2019.2\data\xicom in the file spi.cfg. Rather than adding a new SPI for now (you also need to change the file xicom_cfgmem_part_table.cfg for them to show up), just modify an IDCode.

I would search for S25FL032P_PROPERTY and you should find this line:
IDCODE = 15;

Changing it to match the IDCode of the AT25SF321 should work:
IDCODE = "1F8701";

However - you’ll notice the original IDCode is only a single byte, so it shouldn’t block it as that part should match. EDIT - You can’t do this after all

My FPGA JTAG cable is MIA right now, I think I left it at home during switching some stuff between office/home due to lockdown (back in office now). I’ll try and grab it to confirm this, or someone else might chime in before me.

Thanks,

-Colin

Also - if that seems to show signs of life, you might need to remove R38 & R37. They connect the SPI flash pins to the SAM3U, which even if held in reset means there are 4-5cm of hanging trace that will limit the SPI speed. I think you can configure the SPI speed as part of the PROM file generation, so you could crank the speed way down too. But probably the chip should be detected at least…

I found an old Xilinx JTAG clone cable instead that seems to work… I see the IDCode being reported as 0’s, which apparently Vivado does even if it reads the correctly (see https://forums.xilinx.com/t5/Vivado-Debug-and-Power/Artix-7-SPI-Configuration-Flash-Device-ID-failure/td-p/877289).

My above hacks didn’t work, so looking more into it…

-Colin

The short answer - this is much harder than I thought. Those .cfg files aren’t fully used from what I can tell (you might not be able to add new parts), and Vivado does not support the XIL_IMPACT_SKIPIDCODECHECK=1 which I had somewhat relied on (this is only on Impact). I haven’t had luck getting the SPI programmer working in Vivado.

There are a few options:

Option 1 - Replace SPI Chip
If you’re handy with a soldering iron we can send you a compatible chip.

Option 2 - External SPI Programmer
An external SPI programmer should work. You can either just make a “shim” FPGA bitstream that routes the SPI programming pins to header pins, or you could use a SOIC-8 clip. Bus Pirate, FTDI chips, etc all should work here.

Option 3 - Using SAM3U Programmer
The SAM3U could support SPI programming via the FPGA (a ‘shim’ core is needed), but this isn’t complete yet. We could speed this up as it might be a blocker for you, and this could be the quickest solution in terms of flash programming time.

EDIT: This is now in-progress and should be online in a few days at most. We’ve got the SPI interface up, just need the programming logic, which should be straight-forward.

Option 4 - ISE 14.7 LabTools on Linux

You can still get ISE 14.7, which supports the A100 (but NOT the A35). If you are using the A35 this definitely won’t work, I’m trying to test on an A100 here, but the following are instructions for reference:

  1. Download/extract labtools 14.7.

  2. Install

sudo mkdir /opt/Xilinx
sudo chown <yourname> /opt/Xilinx
sudo chgrp <yourname> /opt/Xilinx
sudo apt-get install libncurses5
./xinstall

Install LabTools to /opt/Xilinx

  1. Get USB Driver working
cd /opt/Xilinx/
git clone git://git.zerfleddert.de/usb-driver
cd usb-driver/
sudo apt install fxload libusb-dev
make
./setup_pcusb /opt/Xilinx/14.7/LabTools/LabTools
sudo udevadm control --reload-rules
  1. Run Impact
export LD_PRELOAD=/opt/Xilinx/usb-driver/libusb-driver.so
export XIL_IMPACT_SKIPIDCODECHECK=1
cd /opt/Xilinx/14.7/LabTools/bin/lin64
./impact

This worked to detect the USB cable for me, however this doesn’t work with the A35 board (as A35 is not supported).

You’ll still need to use the XIL_IMPACT_SKIPIDCODECHECK=1 variable set as above.

Sorry this is such a hassle! When I sub’d the SPI flash chip I was only thinking of compatability of the FPGA itself (i.e., commands FPGA would be using). Vivado didn’t make it in my list…

I made a quick edit to the above post - the SPI programming via the SAM3U (no external hardware required) is now in-progress, so this should actually be very doable in the next few days. The only downside is it requires changing the MODE switches to program I think. But presumably you’re only doing the SPI flash program once development is done, as load the SRAM bitstream via the USB chip is much faster.

This might not be super-fast, but would let you program the SPI chip via the USB interface. This should be a lot smoother (and about 1000x easier than getting ISE/Impact to work IMHO).

The CW305 SPI flash is functional! To get it to work:

  1. git pull the newest ChipWhisperer commits
  2. Update the CW305 USB firmware: https://chipwhisperer.readthedocs.io/en/latest/api.html#firmware-update
  3. Make sure the FPGA is in USB mode
  4. Follow https://chipwhisperer.readthedocs.io/en/latest/api.html#cw305-spi-program and program the SPI flash
  5. Swap the CW305 to SPI mode

Alex

1 Like

Hi,

  1. I am using latest ChipWhisperer development version.
  2. I successfully updated CW305 firmware.
  3. Made sure the FPGA is in USB mode.
  4. ERROR while programming SPI flash.

I am running the following code:

import chipwhisperer as cw

bitstream = "..." # Here I am using config. mem. file generated by Vivado.

fpga = cw.target(None, cw.targets.CW305, fpga_id='100t') #for CW305_100t

spi = fpga.spi_mode()
spi.erase_chip()
spi.program(bitstream) # ERROR happens here.

I am getting following error message:

Traceback (most recent call last):
  File "/home/canaknesil/.local/lib/python3.6/site-packages/usb/core.py", line 1021, in ctrl_transfer
    buff = util.create_buffer(data_or_wLength)
  File "/home/canaknesil/.local/lib/python3.6/site-packages/usb/util.py", line 162, in create_buffer
    return array.array('B', _dummy_s * length)
TypeError: can't multiply sequence by non-int of type 'list'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/canaknesil/.local/lib/python3.6/site-packages/usb/_interop.py", line 92, in as_array
    return array.array('B', data)
TypeError: an integer is required (got type str)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/canaknesil/standalone-programs/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py", line 300, in txrx
    self.usbdev().ctrl_transfer(payload[0], payload[1], payload[2], payload[3], payload[5:], timeout=self._timeout)
  File "/home/canaknesil/.local/lib/python3.6/site-packages/usb/core.py", line 1023, in ctrl_transfer
    buff = _interop.as_array(data_or_wLength)
  File "/home/canaknesil/.local/lib/python3.6/site-packages/usb/_interop.py", line 97, in as_array
    a.fromstring(data) # deprecated since 3.2
TypeError: a bytes-like object is required, not 'list'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/Documents/summer-job-repo/bitstream-extraction/program_flash/program_spi_flash_cw305.py in <module>
     10 spi = fpga.spi_mode()
     11 spi.erase_chip() # can also use spi.erase_block() for smaller/faster erases
---> 12 spi.program(bitstream) # also verifies by default
     13 
     14 

~/standalone-programs/chipwhisperer/software/chipwhisperer/capture/targets/CW305.py in program(self, data, addr, verify, timeout)
    739         while len(data) > data_written:
    740             to_write = min(self.PAGE_SIZE, len(data)-data_written)
--> 741             self.cmd_write_mem(data[data_written:data_written+to_write], addr + data_written, timeout=timeout)
    742             data_written += to_write
    743 

~/standalone-programs/chipwhisperer/software/chipwhisperer/capture/targets/CW305.py in cmd_write_mem(self, data, addr, timeout)
    688         while data_len > data_written:
    689             cmd = data[data_written:data_written + min(64, data_len-data_written)]
--> 690             self.spi_tx_rx(cmd)
    691             data_written += len(cmd)
    692 

~/standalone-programs/chipwhisperer/software/chipwhisperer/capture/targets/CW305.py in spi_tx_rx(self, data)
    602         if len(data) > 64:
    603             raise ValueError("Data is tooooooo long!")
--> 604         self.sendCtrl(self.REQ_FPGASPI_PROGRAM, 0xA4, data)
    605         readdata = self.readCtrl(self.REQ_FPGASPI_PROGRAM, dlen=len(data))
    606         return readdata

~/standalone-programs/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in sendCtrl(self, cmd, value, data)
    676         """
    677         # Vendor-specific, OUT, interface control transfer
--> 678         self.usbseralizer.sendCtrl(cmd, value, data)
    679 
    680     def readCtrl(self, cmd, value=0, dlen=0):

~/standalone-programs/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in sendCtrl(self, cmd, value, data)
    177         cmdpacket = self.make_cmd(self.WRITE_CTRL, cmdpacket)
    178 
--> 179         self.process_rx(self.txrx(tx=cmdpacket))
    180 
    181     def readCtrl(self, cmd, value=0, dlen=0):

~/standalone-programs/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in process_rx(self, inp)
    152 
    153         if resp == self.ERROR:
--> 154             raise payload
    155 
    156         return payload

TypeError: a bytes-like object is required, not 'list'

Hi,

What format is your data? It should be a list of integers (I think an actual bytearray will work as well, but I haven’t tested yet).

Alex

Hi,

I was providing the name of the data file as a “string”.

It works when I provide list of integers read from the data file with the following code:

with open(data_file, mode='rb') as f:
    data = f.read()
data = list(data) # Conversion from "bytes" to "list" of "int".
......
spi.program(data)

Thank you very much,
Can Aknesil

You’re welcome! I’ll update the example in the docs to be more clear about that.

Alex