ChipWhisper Husky targeting simple trigger board

Hopefully a easy one, I’m just trying to create a basic test with the “simple trigger” target board.

I’ve got tio4 connected on the husky to the “run” led on the target board to act as trigger. I’m
trying to then count 2 edges (i.e. blinks of the led) and then send a glitch to the chipshouter.

What I’m seeing is the husky sends a glitch almost immediately after “scope.arm()” and reporting that it has seen 0 edges, so I don’t understand how it or what it causing it to trigger.

This is the following code I’m using:

    scope = cw.scope(name='Husky')
    
    # Setup the clock to use and what speed to run it at
    scope.clock.clkgen_src = 'system'       # "system" or "internal": An onboard crystal
    scope.clock.clkgen_freq = 20e6          # This is used for the glitching clock i.e. the higher the more accurate the 
                                            # glitch occurs from the trigger The maximum is 200MHz (Husky)
    scope.clock.adc_mul = 1                 # Sets a new ADC clock frequency by multiplying this value by clkgen_freq
                                            # setting to 1 just leaves the clk freq at scope.clock.clkgen_freq
    scope.adc.trig_count 
    # Setup what and how we are going to be triggered 
    scope.trigger.triggers = 'tio4'         # This is the I/O pin 1 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 2
    
    
    logging.debug(scope.trigger)            # Display the trigger settings
    
    # Setup and enable the glitch output
    scope.io.glitch_trig_mcx = "glitch"     # This is what the MCX connector on the Husky should be used for
                                            # we want to send a glitch pulse to the chipshouter so we use glitch
    scope.glitch.enabled = True             # This enables the glitch module
    scope.glitch.clk_src = 'pll'            # This is the clock source on the husky, so the offset and widths relate to this clock
    #scope.clock.pll.update_fpga_vco(600e6)  # ???
    
    # Choice of how the output glitch is formed 
    # by the clock or by the trigger
    #scope.glitch.output = 'glitch_only'    # This is sync'd with the clk_src and can change the width (how long to pulse) and offset (time after the trigger)
    scope.glitch.output = 'enable_only'    # This doesn't enable control of the glitch width it just a offset from
                                            # the trigger and a number of repeats
    
    # This is what will happen once the scope is triggered 
    scope.glitch.trigger_src = 'ext_single' # Once the scope is armed, one set of glitch events is emitted when the 
                                            # trigger condition is satisfied. Subsequent trigger conditions are ignored 
                                            # unless the scope is re-armed
                                            # ext_continuous ext_single
    
    scope.glitch.arm_timing = 'after_scope' # “after_scope”: The scope is armed first. This is the default

    # Works with enable_only
    # As we are doing a external trigger using the husky it 
    # controls the pulse width of the chipshouter
    scope.glitch.repeat = 1                # The number of glitch pulses to generate per trigger
    scope.glitch.ext_offset = 0             # Only works with enable_only after the glitch module is triggered, it waits for a number of clock cycles before generating glitch pulses. This delay allows the glitch to be inserted at a precise moment during the target’s execution to glitch specific instructions.
    
    
    assert scope.glitch.mmcm_locked         # ???


    
    logging.debug(f"offset {scope.glitch.offset}, width {scope.glitch.width}, repeat {scope.glitch.repeat}")

    
    shouter = ChipSHOUTER(port)
    shouter.armed = False
    logging.debug(f"{shouter.state}")
    shouter.faults_current = 0
    logging.debug("ARM Scope first time")
    
    scope.arm()                             # Once armed a glitch can occur 
    shouter.armed = True
    logging.debug(f"Edges seen: {scope.trigger.edges_seen}")
    scope.dis()                             # Disconnect from the Husky

    exit()
    2025-03-16 21:07:25,209 chip_whisperer.py:58 -                 main() - DEBUG    - sequencer_enabled = False
module            = edge_counter
triggers          = tio4
edges             = 2

2025-03-16 21:07:25,222 chip_whisperer.py:96 -                 main() - DEBUG    - offset 0, width 0, repeat 1
2025-03-16 21:07:25,522 chip_whisperer.py:108 -                 main() - DEBUG    - disarmed
2025-03-16 21:07:25,666 chip_whisperer.py:111 -                 main() - DEBUG    - ARM Scope first time
2025-03-16 21:07:25,763 chip_whisperer.py:132 -                 main() - DEBUG    - Edges seen: 0

What’s the “simple trigger” target board?

Setting aside the ChipShouter for now, your Husky code looks ok, except that when calling scope.arm() directly like this, it needs to get explicitly disarmed before it can get armed again, with scope.sc.arm(False).

I recommend you take CS out of the equation for now and start by working out how to reliably trigger from your target.

Thanks for responding!

So the board I’m targeting is the CW322 (Simple Target - CW322 Simple EMFI Target - This site is now deprecated. Visit chipwhisperer.readthedocs.io instead!).

I’ve connected a wire to the “run” led which generates a square wave of period around 300ms ms (3hz) at 3V, and connected that to the IO4 to act as my trigger.

As suggested I’ve removed the chipshouter code and just focused on the scope side.

    scope = cw.scope(name='Husky')
    # Setup the clock to use and what speed to run it at
    scope.clock.clkgen_src = 'system'       # "system" or "internal": An onboard crystal
    scope.clock.clkgen_freq = 20e6          # This is used for the glitching clock i.e. the higher the more accurate the 
                                            # glitch occurs from the trigger The maximum is 200MHz (Husky)
    scope.clock.adc_mul = 1                 # Sets a new ADC clock frequency by multiplying this value by clkgen_freq
                                            # setting to 1 just leaves the clk freq at scope.clock.clkgen_freq
    # Setup what and how we are going to be triggered 
    scope.trigger.triggers = 'tio4'         # This is the I/O pin 4 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 2
    
    print("ARM Scope first time")
    
    scope.sc.arm(enable=False)
    scope.sc.arm(enable=True)

    print(f"Edges seen: {scope.trigger.edges_seen}")
    
    scope.dis()                             # Disconnect from the Husky

I assumed that once scope.sc.arm(enable=True) is called that it would block until it received a edge. Unfortunately the code completes and has seen no edges

ARM Scope first time
Edges seen: 0

Ah right, now I understand the issue: “arm” is non-blocking (look at its documentation).

Look at how we do this in our Jupyter notebooks, e.g. chipwhisperer-jupyter/courses/fault101/SOLN_Fault 1_2 - Clock Glitching to Bypass Password.ipynb at main · newaetech/chipwhisperer-jupyter · GitHub

1 Like

Ahhh ok thanks, I’ll take a look and apply the concepts to my problem and post back how I go!

For anyone else following along the key was setting the adc timeout and then calling scope.capture().

So now the code becomes:

    scope = cw.scope(name='Husky')
    # Setup the clock to use and what speed to run it at
    scope.clock.clkgen_src = 'system'       # "system" or "internal": An onboard crystal
    scope.clock.clkgen_freq = 20e6          # This is used for the glitching clock i.e. the higher the more accurate the 
                                            # glitch occurs from the trigger The maximum is 200MHz (Husky)
    scope.clock.adc_mul = 1                 # Sets a new ADC clock frequency by multiplying this value by clkgen_freq
                                            # setting to 1 just leaves the clk freq at scope.clock.clkgen_freq
    # Setup what and how we are going to be triggered 
    scope.trigger.triggers = 'tio4'         # This is the I/O pin 4 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 1
    scope.adc.timeout = 2
    
    print("ARM Scope and glitcher")
    scope.sc.arm(enable=False)
    scope.arm()
    print(f"Start Capture timeout (sec): {scope.adc.timeout }")
    if(scope.capture()):                        # Blocks until scope.adc.timeout reached or matching signal found at scope.trigger.triggers
        print("Timeout occurred no edges seen")
    else:
        print(f"Edges seen: {scope.trigger.edges_seen}")
    scope.sc.arm(enable=False)
    scope.dis()                             # Disconnect from the Husky
    
    exit()

And I’m seeing edges now!

ARM Scope and glitcher
Start Capture timeout (sec): 2
Edges seen: 1

Now I’ll add back in the chipshouter code and see how things go

Now I’ve got the chipshouter sending a pulse based on the trigger which is great.

scope = cw.scope(name='Husky')
    
    # Setup the clock to use and what speed to run it at
    scope.clock.clkgen_src = 'system'       # "system" or "internal": An onboard crystal
    scope.clock.clkgen_freq = 20e6          # This is used for the glitching clock i.e. the higher the more accurate the 
                                            # glitch occurs from the trigger The maximum is 200MHz (Husky)
    scope.clock.adc_mul = 1                 # Sets a new ADC clock frequency by multiplying this value by clkgen_freq
                                            # setting to 1 just leaves the clk freq at scope.clock.clkgen_freq
    # Setup what and how we are going to be triggered 
    scope.trigger.triggers = 'tio4'         # This is the I/O pin 4 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 1
    scope.adc.timeout = 2

    # Setup the chipshouter to glitch
    scope.io.glitch_trig_mcx = "glitch"     # Setup the MCX on the husky to output for a glitch
    scope.glitch.enabled = True             # This enables the glitch module
    scope.glitch.clk_src = 'pll'            # This is the clock source on the husky, so the offset and widths relate to this clock
    scope.clock.pll.update_fpga_vco(600e6) 

    #scope.glitch.output = "enable_only"
    scope.glitch.output = "glitch_only"
        
    scope.glitch.trigger_src = "ext_single" # XXX ext_single in real use case
    scope.glitch.arm_timing = "after_scope"

    scope.glitch.repeat = 1                # The number of glitch pulses to generate per trigger
    #scope.glitch.ext_offset = 100       # Only works with enable_only after the glitch module is triggered, it waits for a number of clock cycles before generating glitch pulses. This delay allows the glitch to be inserted at a precise moment during the target’s execution to glitch specific instructions.
    scope.glitch.offset = 100            # only works with glitch_only
    scope.glitch.width = 20             # only works when glitch_only
    
    assert scope.glitch.mmcm_locked         # ???
    
    shouter = ChipSHOUTER(port)
    shouter.voltage = 400
    #print(shouter)
    print("ARM Scope and glitcher")
    shouter.faults_current = 0
    #print(shouter.faults_latched)
    
    scope.sc.arm(False)
    scope.arm()
    if not shouter.armed:
        shouter.armed = True
        print("Chip shouter not armed, arming")
        time.sleep(3) # wait for arming of chipshouter
    print(f"Start Capture timeout (sec): {scope.adc.timeout }")
    if(scope.capture()):                        # Blocks until scope.adc.timeout reached or matching signal found at scope.trigger.triggers
        print("Timeout occurred no edges seen")
    else:
        print(f"Edges seen: {scope.trigger.edges_seen}")
    scope.dis()                             # Disconnect from the Husky
    
    exit()

Now I’m just having trouble understanding if I’m setting the offset and width correctly.

My current understanding is that when I’m using scope.glitch.output = "glitch_only" that I can then control the chipshouter’s wave form through scope.glitch.offset = 100 and scope.glitch.width = 20 and these values are related for the husky.

For CW-Husky, width is expressed as the number of phase shift steps.  Minimum width is obtained at 0.Maximum width is obtained at scope.glitch.phase_shift_steps/2

So the scope.glitch.phase_shift_steps/2 is 840 (i.e. 1680/2). I can’t workout yet why the width and offset don’t seem to be having a effect when I look on my oscilloscope i.e. the pulse width doesn’t change width as I change scope.glitch.width?

scope.glitch.offset is a useful setting to play with since it determines the timing of the glitch, however scope.glitch.width is irrelevant here.

In the CS user guide we advise setting scope.glitch.output = 'enable_only'; you also need scope.io.glitch_lp = True.

Great thanks for the clarification which makes sense looking at the following diagram:

So I’ve played with trying different sizes of repeat (from 1-500), but can’t see a change in the glitch size, I keep getting a glitch peak of 50ns.

The yellow line is the trigger, the blue line the glitch from the chipshouter, and the purple line the start line.

Is there something I need to change for the clock source?

Your ChipWhisperer’s clock is 20 MHz, so setting scope.glitch.repeat to X should indeed give you a glitch output (from the Husky) of 50ns times X.

However the EM pulse that CS can generate from this is limited by physics. Setting scope.glitch.repeat = 500 will definitely not give you a 25000ns EM pulse! Have a look at the “Inserted Pulse Characteristics” of the CS user manual.

Thanks for clearing up the EM pulse width this is a huge help in bring together the fundamentals for me and hopefully others following along.

For reference I’m using the 1mm injection tip:

So I played with the changing the scope.clock.clkgen_freq from 20Mhz (50ns pulse) down to 60Mhz (15ns) pulse and I couldn’t get it to change the pulse width. I tried 40MHz to see if I would get at least half the size of what I had but I see no change. The images below show the a example of two of the settings I tried.

Expected 50ns (20Mhz set) pulse


Expected 25ns (40Mhz set) pulse

The other problem which could be related is that after the pulse is sent I end up with the following latched faults [‘fault_trigger_error’, ‘fault_trigger_glitch’] which I then manually reset by holding the arm button down for 8 seconds. I’m not sure why this occurs as the chipshouter is armed, there should be only one pulse to glitch for the observed trigger based on the trigger settings I’m using:

    scope.trigger.triggers = 'tio4'         # This is the I/O pin 4 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 1

And what was scope.glitch.repeat set to?

If you capture Husky’s trigger output, are you getting the expected pulse width?

The scope.glitch.repeat is set to 1.

I’ll grab a capture of the husky pulse width a check.

So from the Husky’s MCX trigger output I’m getting the following, which looks nothing like what I was expecting:

So just to clarify where I’m at:

  • I’ve attached a probe to the “Trigger / Glitch out (3.3v)” MCX connector and got the above trace
  • scope.glitch.repeat = 1
  • I’ve removed all chipshouter references in the code now so its just the husky code
  • The husky is detecting the edge as I get scope.trigger.edges_seen = 1

Reading through the chipshouter user manual on page 26 it shows a connection from the crowbar to the chipshouter:

From the code I’ve been using it looks like I’m using the MCX connector, but also enabling the crowbar SMA connector?

 scope.io.glitch_trig_mcx = "glitch"     # Setup the MCX on the husky to output for a glitch
    scope.glitch.enabled = True             # This enables the glitch module
    scope.glitch.clk_src = 'pll'            # This is the clock source on the husky, so the offset and widths relate to this clock
    scope.clock.pll.update_fpga_vco(600e6) 

    scope.glitch.trigger_src = "ext_single" # XXX ext_single in real use case
    scope.glitch.output = "enable_only"
    #scope.glitch.output = "glitch_only"
    scope.io.glitch_lp = True 

But putting a probe on the Crowbar SMA port I get no signal…

I can’t reproduce this; it works as expected for me. Maybe I’m misunderstanding something about your setup.
What is the full output of print(scope)?

I tried to just do a print(scope) but it gave the following error:

......
......
......
chipwhisperer/capture/scopes/cwhardware/ChipWhispererHuskyMisc.py", line 1337, in sampling_clock_frequency
    return self._scope.trace.clock.swo_clock_freq
           ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'clock'

Since I don’t set a trace I’ve just printed out anything I’ve set, hopefully that has the information you need?

    print(scope.fw_version)
    print(scope.fw_version_str)
    print("Scope Glitch:")
    print(scope.glitch)
    print("Scope Trigger:")
    print(scope.trigger)
    print("Scope IO:")
    print(scope.io)
    print("Scope Clock:")
    print(scope.clock)
{'major': 1, 'minor': 5, 'debug': 0}
1.5.0

Scope Glitch:
enabled           = True
num_glitches      = 1
clk_src           = pll
mmcm_locked       = True
width             = 0
offset            = 0
trigger_src       = ext_single
arm_timing        = after_scope
ext_offset        = 0
repeat            = 1
output            = enable_only
phase_shift_steps = 840

Scope Trigger:
sequencer_enabled = False
module            = edge_counter
triggers          = tio4
edges             = 1

Scope IO:
tio1            = serial_tx
tio2            = serial_rx
tio3            = high_z
tio4            = high_z
pdid            = high_z
pdic            = high_z
nrst            = high_z
glitch_hp       = False
glitch_lp       = True
extclk_src      = hs1
hs2             = None
target_pwr      = True
tio_states      = (1, 1, 1, 0)
cdc_settings    = bytearray(b'\x01\x00\x00\x00')
aux_io_mcx      = high_z
glitch_trig_mcx = glitch

Scope Clock:
clkgen_src             = system
clkgen_freq            = 40000000.0
adc_mul                = 1
adc_freq               = 40000000.0
freq_ctr               = 0
freq_ctr_src           = extclk
clkgen_locked          = True
adc_phase              = 0.0
extclk_monitor_enabled = False
extclk_error           = False
extclk_tolerance       = 1144409.1796875

Just looking at the Husky when its running the ADC and Glitch leds flash, is there a way to determine why they would be flashing?

If they are flashing continuously while Husky is idle, this indicates an error condition:
scope.errors. This is explained here: chipwhisperer-jupyter/demos/husky/01 - Introduction to ChipWhisperer-Husky.ipynb at main · newaetech/chipwhisperer-jupyter · GitHub

I strongly recommend that you go over the set of Husky demos there as they cover things specific to Husky that are not covered in our course notebooks.

Otherwise the glitch LED will flash whenever you generate a glitch (which is normal here), and the ADC light will flash when Husky’s PLL becomes unlocked (which can happen momentarily when you change something about Husky’s clock).

This is very strange. Can you share the full notebook which leads to this, so I can try to reproduce the issue here?

Thanks for suggesting the husky error page, I’ve added some specific print statements in and there is a “gain to low error”, reading the details on the error it looks like its more of a warning than a error (Scope API — ChipWhisperer Documentation).

I’m not using a notebook it’s just a python script, as I was just trying to keep it as simple as possible so I could understand, I’ve added in printing the specific errors and updated the output for you also. Hopefully it gives you some ideas for what could be causing the issue…


import chipwhisperer as cw

from chipwhisperer.common.results.glitch import GlitchController

from glitcher import Glitcher
from chipshouter import ChipSHOUTER
import time
import logging
import sys

port = "/dev/ttyUSB0"

def main():
    
    scope = cw.scope(name='Husky')
    scope.adc.lo_gain_errors_disabled = True
    print(scope.fw_version)
    print(scope.fw_version_str)
    
    # Setup the clock to use and what speed to run it at
    scope.clock.clkgen_src = 'system'       # "system" or "internal": An onboard crystal
    scope.clock.clkgen_freq = 40e6          # This is used for the glitching clock i.e. the higher the more accurate the 
                                            # glitch occurs from the trigger The maximum is 200MHz (Husky)
    scope.clock.adc_mul = 1                 # Sets a new ADC clock frequency by multiplying this value by clkgen_freq
                                            # setting to 1 just leaves the clk freq at scope.clock.clkgen_freq
    scope.adc_test()
    # Setup what and how we are going to be triggered 
    scope.trigger.triggers = 'tio4'         # This is the I/O pin 4 we will be getting the trigger signal from
    scope.trigger.module = 'edge_counter'   # Choose how to trigger, in this case its based on the number of edges 
                                            # we see i.e. like a clock
    scope.trigger.edges = 1
    scope.adc.timeout = 2

    # Setup the chipshouter to glitch
    scope.io.glitch_trig_mcx = "glitch"     # Setup the MCX on the husky to output for a glitch
    scope.glitch.enabled = True             # This enables the glitch module
    scope.glitch.clk_src = 'pll'            # This is the clock source on the husky, so the offset and widths relate to this clock
    scope.clock.pll.update_fpga_vco(600e6) 

    scope.glitch.trigger_src = "ext_single" # XXX ext_single in real use case
    scope.glitch.output = "enable_only"
    #scope.glitch.output = "glitch_only"
    scope.io.glitch_lp = True    
    
    scope.glitch.arm_timing = "after_scope"

    scope.glitch.repeat = 1               # The number of glitch pulses to generate per trigger
    scope.glitch.ext_offset = [0,0]       # Only works with enable_only after the glitch module is triggered, it waits for a number of clock cycles before generating glitch pulses. This delay allows the glitch to be inserted at a precise moment during the target’s execution to glitch specific instructions.
    print(f"Offset: {scope.glitch.ext_offset}")
    #scope.glitch.offset = 500            # only works with glitch_only
    #scope.glitch.width = 500             # only works when glitch_only
    print(f"Phase shift steps: {scope.glitch.phase_shift_steps}")
    print(f"The glitch repeats: {scope.glitch.repeat}")
    assert scope.glitch.mmcm_locked         # ???
    
    print("Scope Glitch:")
    print(scope.glitch)
    print("Scope Trigger:")
    print(scope.trigger)
    print("Scope IO:")
    print(scope.io)
    print("Scope Clock:")
    print(scope.clock)
    # print("Sleeping")
    # time.sleep(2)
    # shouter = ChipSHOUTER(port)
    # print(f"Clear and ARM: {shouter.clr_armed}")
    # while not shouter.trigger_safe:
    #         continue
    # shouter.voltage = 400
    # print(shouter)
    
    # shouter.faults_current = 0
    # print(f"Faults latched: {shouter.faults_latched}")
    
    # if shouter.faults_current != 0:
    #     exit(-1)

    scope.sc.arm(False)
    scope.arm()
    print("ARM Scope and glitcher")
    
    # if not shouter.armed:
    #     shouter.armed = True
    #     print("Chip shouter not armed, arming")
    #     time.sleep(3) # wait for arming of chipshouter
    print(f"Start Capture timeout (sec): {scope.adc.timeout }")
    if(scope.capture()):                        # Blocks until scope.adc.timeout reached or matching signal found at scope.trigger.triggers
        print("Timeout occurred no edges seen")
    else:
        print(f"Edges seen: {scope.trigger.edges_seen}")
    
    print(f"XADC errors: {scope.XADC.status}")
    print(f"ADC errors: {scope.adc.errors}")
    print(f"Extclk errors:{scope.clock.extclk_error}")
    print(f"Trace errors {scope.trace.errors}")
    print(scope.errors)
    
    scope.dis()                             # Disconnect from the Husky
    
    exit()
  
if __name__ == "__main__": 
    main()

The full output, note the error occurs from calling the scope.trace.errors.

$ python ./chip_whisperer_husky_forum.py 
{'major': 1, 'minor': 5, 'debug': 0}
1.5.0
Offset: 0
Phase shift steps: 840
The glitch repeats: 1
Scope Glitch:
enabled           = True
num_glitches      = 1
clk_src           = pll
mmcm_locked       = True
width             = 0
offset            = 0
trigger_src       = ext_single
arm_timing        = after_scope
ext_offset        = 0
repeat            = 1
output            = enable_only
phase_shift_steps = 840

Scope Trigger:
sequencer_enabled = False
module            = edge_counter
triggers          = tio4
edges             = 1

Scope IO:
tio1            = serial_tx
tio2            = serial_rx
tio3            = high_z
tio4            = high_z
pdid            = high_z
pdic            = high_z
nrst            = high_z
glitch_hp       = False
glitch_lp       = True
extclk_src      = hs1
hs2             = None
target_pwr      = True
tio_states      = (1, 1, 1, 0)
cdc_settings    = bytearray(b'\x01\x00\x00\x00')
aux_io_mcx      = high_z
glitch_trig_mcx = glitch

Scope Clock:
clkgen_src             = system
clkgen_freq            = 40000000.0
adc_mul                = 1
adc_freq               = 40000000.0
freq_ctr               = 0
freq_ctr_src           = extclk
clkgen_locked          = True
adc_phase              = 0.0
extclk_monitor_enabled = False
extclk_error           = False
extclk_tolerance       = 1144409.1796875

ARM Scope and glitcher
Start Capture timeout (sec): 2
Edges seen: 1
XADC errors: good
ADC errors: gain too low error, 
Extclk errors:False
Traceback (most recent call last):
  File "/home/user/workspace/glitch/source/./chip_whisperer_husky_forum.py", line 105, in <module>
    main()
  File "/home/user/workspace/glitch/source/./chip_whisperer_husky_forum.py", line 97, in main
    print(f"Trace errors {scope.trace.errors}")
                          ^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'errors'

I’m sorry this is taking so long to resolve. There are (at least!) two issues here:

  1. You can’t access scope.trace.errors because scope.trace appears to return None. This is not normal. What version of ChipWhisperer are you using (cw.__version__)? Have you modified ChipWhisperer’s Python source code in any way?
  2. You have said that you can’t create a proper single pulse output on Husky’s Trigger/Glitch Output MCX whose width is controlled by scope.glitch.repeat. I’ve not been able to reproduce that; it works exactly as expected for me. Please share code which reproduces the problem that you’ve seen.

Please no need to apologies, thanks for providing so much guidance and help.

  1. I’ve using version 5.7.0 as I didn’t want to change to 6.0.0 while I was sorting out what was happening. I’ve not made any changes to the chipwhisperer lib.
>>> import chipwhisperer as cw
>>> cw.__version__
'5.7.0'
  1. I’ve just been using the code from above the only changes that I would make is either making changes to scope.clock.clkgen_freq = 40e6 increase/decrease to change the pulse width with no change observed. Or I would increase/decrease scope.glitch.repeat = 1 but I wouldn’t see any change on the scope.

I’m just away from the setup for the next few days but I will double check when I get back.