Dealing with Husky XADC Errors When Target is Powered On#
This entry is specific to Husky because it’s the only capture hardware with an XADC.
What’s an XADC? It’s a module in Husky’s FPGA which continuously monitors temperature and voltage, to keep Husky alive.
Supported Capture Hardware:
❌ CW-Nano
❌ CW-Lite
❌ CW-Pro
✅ CW-Husky
Required ChipWhisperer software installation:
✅ any release (some exceptions and modifications required for version 6.0.0 and earlier, noted below)
You will also need an external logic analyzer or oscilloscope.
Husky can get very hot!
The main culprits for this are:
a high ADC sampling rate
using
scope.glitchusing
scope.traceusing
scope.UARTTriggerusing
scope.LAusing
scope.SAD
Don’t worry: you certainly can use one of more of these features (even all of them simultaneously!) without any risk.
But the more of these you use, the closer you push Husky to its limits.
The reason you don’t need to worry is that Husky has a self-preservation feature: it shuts down all the above modules when its XADC detects either a too-high temperature, or a supply voltage exceeding its recommended operating range.
It then flashes the red ADC and Glitch LEDs to alert you to the issue; the error condition is reported via scope.XADC.
In most cases, this can be managed in various ways (active cooling, slowing down a glitch campaign, etc…). Manually clearing the alarm then re-enables the affected modules (assuming that the condition which triggered the alarm no longer exists).
But there is a special case when you wish to use one of the XADC-affected modules right after a target power-up.
Why? Because target power-up can cause the FPGA supply voltages to briefly exceed their normal range, due to the target’s current inrush.
If you want to capture or glitch from a target power-on, then there is a problem: you cannot manually clear the alarm in time for the capture or glitch that you wanted to execute.
Fortunately there is usually a way to avoid getting into this situation. It requires some manual tweaking; this note shows you how.
%run '../connect.ipynb'
scope.default_setup()
scope.adc.clip_errors_disabled changed from True to False
scope.adc.lo_gain_errors_disabled changed from True to False
We first set up our trigger mechanism.
We use the nrst pin and the edge trigger module: by default, when the target is powered down, nrst is driven low.
We set edges to 2 so that we trigger when nrst goes back high when target_pwr is re-applied.
scope.trigger.triggers = 'nrst'
scope.trigger.module = 'edge_counter'
scope.trigger.edges = 2
Let’s configure the glitch module. We are glitching some time after the target is powered.
scope.glitch.enabled = True
scope.glitch.clk_src = 'pll'
scope.glitch.trigger_src = 'ext_single'
scope.glitch.output = 'enable_only'
scope.glitch.ext_offset = 10000
scope.io.glitch_hp = False
scope.io.glitch_lp = False
We’ll use the Trigger/Glitch Out port to see whether a glitch is successfully issued, and make it wider so it’s easier to see:
scope.io.glitch_trig_mcx = 'glitch'
scope.glitch.repeat = 100
We use this custom capture command to arm the scope and run a capture when scope.io.target_pwr is toggled:
import time
def capture_trace(sendcommand):
scope.arm()
sendcommand()
ret = scope.capture()
if ret:
print("WARNING: Timeout happened during capture")
return None
wave = scope.get_last_trace()
return wave
def target_poweron():
scope.io.target_pwr = False
time.sleep(0.2)
scope.io.target_pwr = True
With your logic analyzer or oscilloscope, probe the target’s 3.3V line and Husky’s Trigger/Glitch port; trigger it from the 3.3V line going high (or alternatively, the nRST line going high).
scope.adc.lo_gain_errors_disabled = True
scope.adc.clip_errors_disabled = True
trace = capture_trace(lambda: target_poweron())
This capture should work, and you should see something like this on your scope:

You can see the 3.3V slowly ramping up like a staircase when the target power is turned on.
This is done purposefully, using a soft power-on scheme tuned to Husky’s SAM4S target to avoid overshooting.
But if we disable the soft power-on, something quite different happens: (Note that the soft-power-on control is hidden; that’s on purpose since you normally shouldn’t be turning this off.)
scope.io.cwe.setTargetPowerSlew(True) # disable soft target power-on
trace = capture_trace(lambda: target_poweron())
The target power goes up much faster and overshoots to over 3.6V.

Unfortunately, this trips our XADC:
scope.XADC.status
'VCCaux alarm, '
… and as a result, no glitch occurred.
Since this is fully managed in hardware, there cannot be an error message in the notebook; you have to pay attention to Husky’s red blinking lights.
Back to our XADC error: what actually happened? This function tells us that the VCCAUX rail overshot its limits: (this function does not exist in ChipWhisperer 6.0.0 and earlier)
scope.XADC.vcc_limits()
| lower | upper | minimum | maximum | |
rail | limit | limit | seen | seen | current | margin
--------+-------+-------+----------+----------+----------+--------
vccint | 0.950 | 1.050 | ✅ 0.984 | ✅ 1.006 | ✅ 0.995 | 0.034
vccaux | 1.709 | 1.890 | ❌ 1.611 | ❌ 1.945 | ✅ 1.794 | -0.099
vccbram | 0.950 | 1.050 | ✅ 0.987 | ✅ 1.004 | ✅ 0.990 | 0.037
When this happens, the XADC error status must be manually cleared before proceeding.
Until you do so, all the scope modules listed at the top of this notebook are disabled.
scope.XADC.status = 0
It’s also a good idea to clear the max/min XADC voltages, which are otherwise sticky: (does not exist in ChipWhisperer 6.0.0 and earlier)
scope.XADC.user_reset()
Everything should now be back to green:
scope.XADC.vcc_limits()
| lower | upper | minimum | maximum | |
rail | limit | limit | seen | seen | current | margin
--------+-------+-------+----------+----------+----------+--------
vccint | 0.950 | 1.050 | ✅ 0.987 | ✅ 1.003 | ✅ 0.998 | 0.037
vccaux | 1.709 | 1.890 | ✅ 1.785 | ✅ 1.797 | ✅ 1.789 | 0.075
vccbram | 0.950 | 1.050 | ✅ 0.987 | ✅ 1.004 | ✅ 0.997 | 0.037
And now we can glitch again:
scope.glitch.trigger_src = 'manual'
scope.glitch.manual_trigger()
scope.glitch.trigger_src = 'ext_single'
If you’re using NewAE targets, you shouldn’t come across this XADC shutdown when powering up your targets (let us know if you do!).
But what if you’re using a different target for which our soft power-on is still too fast?
We’ve made the soft power-on parameters configurable so that you can tune them to your target.
First let’s turn back on the soft power-on mechanism:
scope.io.cwe.setTargetPowerSlew(False) # enable soft target power-on
Everything you need to know about the soft power-on parameters is in the docstrings:
(With ChipWhisperer 6.0.0 and earlier, this is accessible via scope.io.cwe.getHuskySoftPowerOnParameters() and scope.io.cwe.setHuskySoftPowerOnParameters().
You’ll find two sets of pwm_cycles and pwm_off_time parameters; keep the second set as 0 because they do not behave as intended.)
scope.io.husky_soft_poweron?
Type: property
String form: <property object at 0x7fc7e4198270>
Docstring:
Sets the target soft power-on PWM parameters.
When the target is powered on (when :class:`target_pwr` goes from
:code:`False` to :code:`True`), the target power on the 20-pin
connector +3.3V pin doesn't simply go from 0V to 3.3V; instead, a
series of pulses is applied, so that the 3.3V line goes up gently with
minimal overshoot. Without this, a target's sudden power draw can cause
Husky's VCC lines to go out of their recommended operating ranges, which
triggers :class:`scope.XADC <chipwhisperer.capture.scopes.cwhardware.ChipWhispererHuskyMisc.XADCSettings>`
errors and everything that this entails (some Husky logic gets shutdown
as a protective measure).
The soft power-on parameters are tuned for NewAE targets. If you use a
different target, you may need to tweak these parameters in order to
get a smooth, error-free target power-on.
Warning:
Inappropriate values can result in :class:`scope.XADC <chipwhisperer.capture.scopes.cwhardware.ChipWhispererHuskyMisc.XADCSettings>`
alarms firing when the target is powered on.
Args:
settings: list of three parameters as follows:
* pwm_cycles: 8-bit int, number of PWM periods in the soft power-on
* pwm_period: 16-bit int, number of 96 MHz clock cycles in one PWM period
* pwm_off_time: 16-bit int, number of clock cycles in one PWM period where power is off
The soft power-on sequence lasts pwm_cycles * pwm_period cycles of the 96 MHz USB clock.
To better understand, consider this example (these are not necessarily good values!):
* pwm_period = 100
* pwm_cycles = 50
* pwm_off_time = 90
When the target is powered on, power is then applied as follows:
1. first 90 cycles (pwm_off_time): power is off
2. next 10 cycles (pwm_period - pwm_off_time): power is ON
3. repeat steps 1 and 2 50 (pwm_cycles) times
4. keep power ON
The default values are as follows:
* pwm_period = 2000
* pwm_cycles = 35
* pwm_off_time = 1995
Let’s change these from their defaults to demonstrate. We’ll try to get up to 3.3V a bit faster by shortening pwm_period a little bit.
Note that these parameters can be devilishly hard to tweak; they do not behave in a linear fashion!
It’s also important to understand that ramping up too slow or too fast can both result in overshoot.
scope.io.husky_soft_poweron = [17, 1700, 1695]
trace = capture_trace(lambda: target_poweron())
scope.XADC.vcc_limits()
| lower | upper | minimum | maximum | |
rail | limit | limit | seen | seen | current | margin
--------+-------+-------+----------+----------+----------+--------
vccint | 0.950 | 1.050 | ✅ 0.985 | ✅ 1.004 | ✅ 0.993 | 0.035
vccaux | 1.709 | 1.890 | ✅ 1.784 | ✅ 1.797 | ✅ 1.789 | 0.075
vccbram | 0.950 | 1.050 | ✅ 0.987 | ✅ 1.004 | ✅ 0.997 | 0.037

A final and important note here: you may wonder why not simply disable the XADC alarm mechanism for a short time when the target is powered on?
In addition to the risk, there is another problem: FPGAs are not guaranteed to behave “normally” when their supplies (or temperature) are out of recommended range.
FPGAs (and any electronic circuits for that matter) are only guaranteed to operate as intended when their operating conditions are within their recommended ranges.
When you step out of those ranges, all bets are off! Internal FPGA signals may not propagate in the required time and this can cause really strange things to happen.
In this case in particular, you are likely trying to do something important (e.g. glitch) right after the XADC error (otherwise you wouldn’t be in this situation). Imagine that you’re issuing a crowbar glitch for a single clock cycle, but as a result of the out-of-spec operating conditions, the glitch is issued but not cleared; it remains permanently “stuck on”, shorting out VCC and ground…
So it’s a bad idea all around!
If you come across an XADC alarm situation like this one, tweak the soft-power-on parameters until the problem goes away.