A power table is only half of a power budget. The milliwatt table says what the chip burns; the envelope says what the package and the board can carry away. A chip that meets every power row but exceeds its junction temperature still fails, slowly and in the field. NanoSoC is a cool chip, which makes it the safe place to learn the check that hot chips live or die by.
Junction temperature is ambient plus power times thermal resistance: Tj = Ta + P x theta-JA. The NanoSoC specification gives P in every state; the package gives theta-JA and the product gives Tj, which must stay under the rated maximum with margin. Three envelopes matter, not one. The sustained envelope covers continuous RUN: average power against the steady-state resistance. The peak envelope covers short bursts above it: thermal capacitance absorbs brief peaks, but a peak held too long becomes sustained. The state envelope covers duty-cycled operation: average power is the time-weighted mean of RUN, IDLE and SLEEP, which is why the power-state table exists.
# not-run: NanoSoC thermal sketch, illustrative package values
RUN power 82.74 mW. Illustrative package theta-JA 30 K/W, ambient 55 C:
rise = 0.08274 x 30 = 2.48 K; Tj about 57.5 C. Comfortable.
Sustained limit (illustrative) 500 mW: NanoSoC uses 17% of it.
Peak check: no NanoSoC workload exceeds 100 mW for longer than
microseconds; capacitance covers it with no throttling needed.
Duty-cycled mean (10% RUN, 30% IDLE, 60% SLEEP): about 14.2 mW.The script checks the envelope arithmetic: sustained rise, duty-cycled mean from the state table, and the energy of one DMA job as the unit peak event. Package numbers are labelled illustrative wherever the NanoSoC specification is silent.
p_run, p_idle, p_sleep = 82.74e-3, 16.89e-3, 1.40e-3
theta_ja = 30.0 # illustrative package value (specification is silent)
ambient = 55.0 # illustrative ambient (specification is silent)
t_j = ambient + p_run * theta_ja
assert abs(t_j - 57.48) < 0.05, t_j
assert t_j < 105.0 # illustrative junction limit
mean = 0.10 * p_run + 0.30 * p_idle + 0.60 * p_sleep
assert abs(mean * 1e3 - 14.18) < 0.05, mean * 1e3
energy_job = 82.74e-3 * 750e-9 # RUN power across the 64-word job
assert abs(energy_job - 62.1e-9) < 0.2e-9, energy_job
# The worst supported duty cycle triples the mean: the check must be run there.
mean_50 = 0.50 * p_run + 0.30 * p_idle + 0.20 * p_sleep
assert abs(mean_50 * 1e3 - 46.7) < 0.1, mean_50 * 1e3
assert mean_50 > 3 * mean
print(f"PASS: Tj {t_j:.1f} C, duty mean {mean*1e3:.2f} mW (50% RUN: {mean_50*1e3:.1f} mW), job {energy_job*1e9:.1f} nJ")All package thermal values labelled illustrative or NanoSoC teaching values, never presented as typical of any vendor.
Three envelopes checked: sustained, peak duration, and duty-cycled mean.
The throttling order written down: what slows first, and what software does about it.
Recompute the mean whenever the duty cycle changes: a product that runs 50% RUN instead of 10% multiplies the mean by four. Ask which duty cycle the envelope assumes, and test the firmware governor against the one beyond it; the pitfall below is what happens when nobody asks.
Treat the peak envelope as a time limit, not a power limit: brief excursions above sustained are absorbed by thermal capacitance, but a peak held past the package time constant becomes the new sustained. The firmware governor therefore needs two thresholds — a power trip that sheds load at once and a temperature trip that duty-cycles work over seconds — with the power trip set below the point where the regulator droops. NanoSoC never approaches either, which is why the lesson records the structure rather than tuning the values; the deeper throttling and DVFS treatment belongs to the power-architecture section.
Sustained power near the illustrative 500 mW envelope — a far hotter workload or a far worse package. Then the governor slows the clock or duty-cycles work, trading throughput for temperature.