CW305 reprograming bitstream issue

I’m working with the CW305 board and following the tutorial here:

I’m using the following code:
target = cw.target(scope, cw.targets.CW305, force=True, fpga_id=fpga_id, platform=platform)

Even with force=True, when I upload a new bitstream to the FPGA, the CW305 continues to run the previous bitstream unless I physically press the USB RST (SW3) button on the board, or power cycle the FPGA.

This is problematic because I’m accessing the PC remotely and need a software-based reset method. I cannot physically press the reset button.

So my questions is:
Is there any way to programmatically reset the FPGA (Artix-7) on CW305 so that the new bitstream takes effect immediately without needing a physical reset?

It isn’t necessary to physically reset the board. What exactly is the command you are using to program your new bitstream? If you’re doing this, it will always load our AES bitstream:

target = cw.target(scope, cw.targets.CW305, force=True, fpga_id=fpga_id, platform=platform)

Instead, do this:

target = cw.target(None, cw.targets.CW305, bsfile="/path/to/bitstream.bit", force=True, platform=platform)

If this is still not working for you, show me exactly the code you’re running so that I can reproduce the issue.

Thank you for your reply but it did not work. The following is the code:
import chipwhisperer as cw

scope = cw.scope()
scope.gain.db = 25
scope.adc.samples = 75 #8500
scope.adc.offset = 0
scope.adc.basic_mode = “rising_edge”
scope.clock.clkgen_freq = 7370000 #100e6 #7370000 #“extclk_x4”
scope.clock.adc_src = “extclk_x4”
scope.clock.extclk_freq = 100e6
scope.trigger.triggers = “tio4”
scope.io.tio1 = “serial_rx”
scope.io.tio2 = “serial_tx”
scope.io.hs2 = “disabled”
scope.default_setup()
scope.clock.clkgen_freq =25e6
scope.adc.offset = 0
scope.adc.basic_mode = “rising_edge”
scope.clock.adc_src = “extclk_x4”
scope.gain.db = 25
scope.adc.samples = 75 #8500
scope.trigger.triggers = “tio4”
scope.io.tio1 = “serial_rx”
scope.io.tio2 = “serial_tx”
scope.io.hs2 = “disabled”

TARGET_PLATFORM = ‘CW305_35t’

fpga_id = ‘35t’
platform = ‘cw305’
bitstream = r"D:/cw305/cw305_top.bit"
target = cw.target(scope, cw.targets.CW305, bsfile=bitstream, force=True)

Strange, that works for me.

  1. How are you determining that the FPGA is not getting programmed; are you 100% sure that it’s not? Does the red FPGA_DONE LED near the middle of the board light up briefly?
  2. What are your M0/1/2 switches set to?
  3. Which version of ChipWhisperer are you using?
  • How am I determining that the FPGA isn’t getting programmed?
    I’m using two different bitstreams, each of which produces a different output on the console. After loading a new bitstream, if I do not perform a hard reset, the output does not change—it continues to run the previous bitstream. This suggests the FPGA is not getting reprogrammed unless I reset the board manually.

  • FPGA_DONE LED behavior:
    After the first successful programming (following a hard reset), the red FPGA_DONE LED turns off. When I try to program again without a hard reset, the LED does not light up at all. It only behaves correctly again after another manual reset.

  • M0/M1/M2 Switch Settings:
    I have the switches set to 1-1-1 (for JTAG mode), as recommended. I also tried 1-0-1, but that didn’t change the behavior.

  • ChipWhisperer Version:
    I believe I’m using firmware version 0.51.

  • Board Information:
    I’m using the CW305 board, part number npcb-artix-cw305-05, as printed on the back of the PCB.

I believe I’m using firmware version 0.51.

This is outdated; on the latest release, CW305 firmware is 0.53.
I meant which ChipWhisperer software version:

import chipwhisperer as cw
print(cw.__version__)

Here’s a quick script you can try, using two of the bitfiles in the chipwhisperer repository.
If you’re on an older CW release you’ll need to adjust the bsfile path.

import chipwhisperer as cw

fpga_id = '100t'
#fpga_id = '35t'

for attempt in ['attempt1', 'attempt2']:
    bsfile = '../software/chipwhisperer/hardware/firmware/cw305/ECDSA256v1_pmul_{}_{}.bit'.format(attempt, fpga_id)
    target = cw.target(None, cw.targets.CW305_ECC, force=True, bsfile=bsfile, platform='cw305')
    print('FPGA buildtime for %s bitfile: %s' % (attempt, target.fpga_buildtime))
    target.dis()

My version is 5.6.1.

print(‘FPGA buildtime for %s bitfile: %s’ % (attempt, target.fpga_buildtime)) creates an error for my version.

AttributeError Traceback (most recent call last)
Cell In[3], line 13
—> 13 print(‘FPGA buildtime for %s bitfile: %s’ % (attempt, target.fpga_buildtime))
14 target.dis()

AttributeError: ‘CW305’ object has no attribute ‘fpga_buildtime’

That’s 3 years old; try upgrading and I suspect all your issues will be resolved.
After upgrading the chipwhisperer software, don’t forget to do any suggested device firmware updates.

I updated the version to 6.0.0. However, it is not reprogramming the FPGA properly if I don’t press USB RST button. I tested the code you shared. It gives the programming time correctly two times. However, it runs the first bitstream execution when I run it. Second bitstream is not loaded without pressing reset button.

bitstream = r"…/cw305_project/cw305_top_correct0.bit"
target = cw.target(None, cw.targets.CW305, force=True, bsfile=bitstream, fpga_id=fpga_id, platform=platform)

I don’t follow. When I run the code, I get the following output:

FPGA buildtime for attempt1 bitfile: 10/20/2023, 09:20
FPGA buildtime for attempt2 bitfile: 10/20/2023, 09:53

which confirms that a different bitfile was loaded each time.

Do you get the same output?

What does this mean exactly? Be explicit; more information is better.

I see the following outputs.
FPGA buildtime for attempt1 bitfile: 5/18/2025, 08:32
FPGA buildtime for attempt2 bitfile: 5/18/2025, 08:32

I have two bitstreams. First bitstream gives the output as 5, the second one gives the output as 2. When I press the USB RST button or power cycle the board (turn it off and on) before loading a bitstream, the correct bitstream loads to the FPGA, and I see the expected output on the console.

However, if I do not press the USB RST button or power cycle the board before loading the bitstream, the output does not reflect the newly loaded bitstream. Instead, the FPGA appears to retain and run the previous bitstream, giving the old result.

…and when you run it with the bitstreams from the chipwhisperer repository (i.e. run my example code exactly as above), do you get the same result that I do?

I’m sorry this is taking a lot of back-and-forth but I am still unable to understand what exactly is happening here.

I see the following results:
FPGA buildtime for attempt1 bitfile: 15/31/2063, 31:63
FPGA buildtime for attempt2 bitfile: 15/31/2063, 31:63

In my code snippet, make sure fpga_id is set to the proper setting for your CW305.

Can you also post a picture of your CW305 board so that I can understand exactly how you’re powering it and what is connected to it.

My version is 35t.

USB cable is connected to the PC.

When I set to “100t”, it gives the following:
FPGA buildtime for attempt1 bitfile: 15/31/2063, 31:63
FPGA buildtime for attempt2 bitfile: 15/31/2063, 31:63

When I set to “35t”, it gives the following:
FPGA buildtime for attempt1 bitfile: 0/0/2000, 00:00
FPGA buildtime for attempt2 bitfile: 0/0/2000, 00:00


I’m going to be very prescriptive; please follow these instructions exactly.

  1. Power off the board.
  2. Make sure any notebook where you’ve connected the CW305 is restarted.
  3. Create a new notebook with my code example above; modify it only to set fpga_id to the correct setting for your board.
  4. Ensure your M0/1/2 switches are all set to 1.
  5. Power on the board.
  6. Run my example code.
  7. What is the output?

I see the following results when I use your code.
target = cw.target(None, cw.targets.CW305_ECC, force=True, bsfile=bsfile, platform=‘cw305’)
FPGA buildtime for attempt1 bitfile: 10/20/2023, 09:17
FPGA buildtime for attempt2 bitfile: 10/20/2023, 09:17

I see the following results when I set target as cw.targets.CW305.
target = cw.target(None, cw.targets.CW305, force=True, bsfile=bsfile, platform=‘cw305’)
FPGA buildtime for attempt1 bitfile: 0/0/2000, 00:00
FPGA buildtime for attempt2 bitfile: 0/0/2000, 00:00

This is definitely strange, we’ve never seen this before.
What if you explicitly erase the FPGA before changing bitfiles?
Run this before the cw.target() command that you use to change bitfiles:

target.fpga.eraseFPGA()
target.dis()

Hopefully this is a workaround for your issue.

I got the same result.
FPGA buildtime for attempt1 bitfile: 10/20/2023, 09:17
FPGA buildtime for attempt2 bitfile: 10/20/2023, 09:17

That’s really weird!

Run this:

import chipwhisperer as cw

#fpga_id = '100t'
fpga_id = '35t'

attempt = 'attempt2'
bsfile = '../software/chipwhisperer/hardware/firmware/cw305/ECDSA256v1_pmul_{}_{}.bit'.format(attempt, fpga_id)
target = cw.target(None, cw.targets.CW305_ECC, force=True, bsfile=bsfile, platform='cw305')
print('FPGA buildtime for %s bitfile: %s' % (attempt, target.fpga_buildtime))

target.fpga.eraseFPGA()
target.dis()

# what is the status of the red FPGA programming LEDs now?

attempt = 'attempt4'
bsfile = '../software/chipwhisperer/hardware/firmware/cw305/ECDSA256v1_pmul_{}_{}.bit'.format(attempt, fpga_id)
target = cw.target(None, cw.targets.CW305_ECC, force=True, bsfile=bsfile, platform='cw305')
print('FPGA buildtime for %s bitfile: %s' % (attempt, target.fpga_buildtime))

and let me know the reported buildtimes, as well as the LED status prior to the second programming attempt?