Field notes / 10–12 September 2026 · executive summary

Transmit overheats the card.
The image throttles it.

Only sustained transmit pushes the NanoPi Zero2’s Intel BE200 to its limit. The sensor image’s thermal governor holds it under 80 °C, at the cost of about half the transmit rate while it is engaged.

BE200 temperature during sustained transmit, governor on and offWith the governor off the card reached the 80 °C stop at 3:11. With it on the card peaked at 77 °C and the run completed 7:00.50°55°60°65°70°75°80°85°012345678 min80 °C stop75 °C governor
Governor off 80 °C stop at 3:11 · Governor on completed 7:00, peak 77 °CSame board, solid boot, 0.5 mm BE200 thermal pad, no fan, 1.8 GHz ceiling, both from 58 °C, 11 September. Runs off1-tx and gov3-tx, shipped 75/68 °C thresholds.
The problem
Without a fan, every ungoverned transmit run longer than 75 seconds hit our 80 °C stop, after 0:41 to 8:59. Receive and capture peaked at 67 °C. The CPU clock made no difference.
The fix
The sensor image runs a governor, wc-thermal, on by default. From 75 °C it cuts the card’s transmit power, then its own power budget, and releases below 68 °C. All 4 governed runs finished with no stop, peaking at 72–77 °C over 4–8 minutes.
The cost
Sustained transmit drops to 285–366 Mbps while the governor is engaged, against 555–765 Mbps without it. Receive and capture stay below 75 °C, so they never trigger it.
With a fan
A 40 mm intake fan kept transmit at 73 °C for 10 minutes at full rate (708–726 Mbps), with no governor at all.

What this does not cover. These are single passes on NanoPi images 1.0.7 and 1.0.9, at bench range, without an ambient reading. The current unified image ships the same governor but has not had its own thermal campaign. The shipped order, a 16 dBm transmit-power cap first and the power budget behind it, has not been measured end to end; the graphed governor run used the budget alone.

The full measurements

Every run, every trace and the method behind the summary above, including the failures.

These are Wi-Fi card temperatures, not CPU temperatures.The 10 September image exposed the BE200 sensor only. Image 1.0.9 adds an RK3528 SoC sensor (see section 03); regulator hot spots are still unmeasured.
01 / Compare the measurements

Pick your runs.
See the difference.

Compare the four cooling setups, CPU ceilings and workloads from 10 September, the 11 September power-budget governor and transmit-power runs, and the 12 September vented-case runs that measure each thermal guard on its own. Every line comes from the original BE200 temperature log: one-second samples on 10 September, two-second samples afterwards.

Loading the 40 recorded temperature traces…

Original figures and measurement files

Keep the original fixed comparisons for reference, or download the full measurement files.

02 / The cooling comparison

The fan changed the result.

Same 0.5 mm BE200 pad. CPU-to-case pad installed throughout. The final fan blows into the case.

BE200 peaks · 2.016 GHz / 1.800 GHz CPU ceilings
WorkloadPad, no fanPad + intake fanWhat changed
Transmit80° / 80°Stopped at 8:59 / 2:5473° / 73°Both completed 10 minutesHigher achieved traffic, lower peak.Fan-on receiver: 708 / 726 Mbps
Receive67° / 67°Both completed 10 minutes56° / 55°Both completed 10 minutes11–12°C lower peaks.Closely matched traffic: about 448 Mbps
Capture → phone63° / 62°52° / 51°Packet gaps in both filesIncomplete capture comparisons.Temperature logs continued; packet recording did not.

Single passes, with different starting temperatures and some different achieved rates. The 80°C stop is a laboratory guard, not a manufacturer limit. These tests do not establish long-term reliability.

03 / 11 September: the card’s own power budget

Transmit heats the card.
So throttle transmit.

The CPU ceiling never moved the BE200; 2.016, 1.8 and 1.608 GHz all peaked at 79–80°C on transmit. The lever that does move it is the card’s own power budget.

What the governor does

The BE200’s iwlwifi driver registers a cooling device that is Intel’s configurable TDP budget: 20 steps, root-writable, and bound to nothing by the kernel. Sensor image 1.0.9 runs a hysteresis governor on it in wc-thermal. At 75°C it steps the budget up two steps every 10 s; at 80°C it jumps to its cap, step 15; in band it eases one step back every 30 s; under 68°C it releases one step every 15 s. From wc-thermal 0.5 the first rung is a transmit-power cap of 16 dBm, restored to automatic on release. Thresholds live in /etc/default/wc-thermal, and WIFI_THROTTLE=off disables it for case or fan A/B tests.

The budget is airtime duty-cycling, not a rate cut. In every run where the station dump was logged, the modulation stayed at EHT MCS 12–13 while bits per second fell. The card is told to transmit less often, not more slowly.

The pre-check that found the lever

Before the image was reflashed, the cooling-device step was forced by hand during a 300 s transmit on image 1.0.7, pad only, no fan. The raw log was lost with that SD card, so the figures below are the summary recorded at the time.

Forced budget step · image 1.0.7 · pad only, no fan · summarised, raw log not retained
Budget stepThroughputBE200
0600–670 Mbps62–65°
10490–590 Mbps60–64°
16200–330 Mbps52–58°
0 again600+ within one intervalrising again

Governor on versus off

Four-stream transmit · 1.8 GHz ceiling · image 1.0.9 · 0.5 mm BE200 pad · no fan
RunPeakOutcome
gov1 · on, 66/60°C thresholds72°240 s completedLadder 2→15 in 90 s; held 60–64° at ~300 Mbps; 366 Mbps mean
gov2 · on, 66/60°C thresholds, warm start 56°74°360 s completedOscillated 14–15; 290–350 Mbps; 352 Mbps mean
gov3 · on, shipped 75/68°C thresholds77°420 s completed331 Mbps mean; the app showed its warning chip
off1–off5 · off, 22 dBm79–81°80°C stop every time41 s to 6.6 min from 54–62° starts; 686–765 Mbps sender

Transmit power versus budget

Three 75 s transmits from 59–60°C · governor off · pad only, no fan
ConfigThroughputPeakMCS seen
22 dBm · budget 0702 Mbps79°EHT 10–13
16 dBm cap · budget 0734 Mbps76°EHT 12–13
22 dBm · budget step 10 held581 Mbps77°EHT 12–13

At bench range the 6 dB power cut took 3°C off the peak at no throughput cost, so it is now the governor’s first rung. At range it would cost MCS before the budget does; that has not been measured.

SoC

The RK3528 now has a thermometer

Three kernel patches from Jonas Karlman’s OpenWrt series add the RK3528 TSADC driver and a soc-thermal zone: 41°C idle, 48°C after a 60 s four-core spin, with passive trips at 70 and 85°C, an orderly shutdown at 95°C and a hardware cut at 100°C. Its cpufreq cooling device lowered the ceiling from 1.8 to 1.608 GHz at step 2. Nothing in these transmit tests heated the SoC far enough to trigger a trip.

WLAN Commander 1.1 shows both sensors with a severity (Wi-Fi elevated at 75°C and hot at 80°C; SoC at 80 and 90°C, under the kernel’s trips), a “Transmit power reduced (step N of 19)” line, a warning chip on every screen, and a background notification when a device turns hot. The governor runs gov3, off4 and off5 doubled as tests of that banner and notification.

Single passes with different starting temperatures. No fan was fitted at any point on 11 September. gov1 and gov2 ran with thresholds lowered to 66/60°C so the ladder would engage quickly from the pad-only board’s 58–60°C idle; gov3 used the shipped 75/68°C. The governor keeps throughput down until the card is under 68°C, so its cost is sustained rate, not peak temperature. Ambient temperature was not measured.

04 / 12 September: a vented case, and one guard at a time

Cutting transmit power beats
rationing the power budget.

The board moved into a vented SMA boot: three recessed chevron vents per grip and an open interior pocket. Same 0.5 mm BE200 pad, same CPU-to-case pad, no fan, 1.8 GHz ceiling, same AP and channel, four TCP streams. Then each of the two software guards was applied on its own.

The vented boot is better, modestly

Idle is the only comparison here with no confound: the vented boot settled at 52°C on the BE200 and 43°C on the SoC, against 58–62°C and roughly 50–55°C in the solid boot, on the same board running the same services.

Governor off · full effort · time to the 80°C stop
CaseStartTo the stopData movedRatePeak
Solid bootoff158°3 min 11 s15.3 GB686 Mbps81°
Vented bootvent-off-full54°4 min 35 s17.8 GB555 Mbps79°

Data moved before the stop is the fairer number, because the achieved link rate differed between the two sessions: the vents bought about 16% more work for the same thermal budget. Time-to-stop flatters them, since a lower rate makes less heat per second and the vented run also started 4°C cooler, which is itself a property of the case.

The two guards, isolated

The governor was switched off so it could not intervene, and the runner applied one lever per run, logging the interface transmit power and the budget step in every two-second sample.

Vented boot · governor off · 1.8 GHz · four-stream transmit
GuardStartOutcomeData movedRatePeak
None54°80°C stop at 4:3517.8 GB555 Mbps79°
Transmit power capped to 16 dBmBudget free at step 058°600 s completed28.9 GB414 Mbps78°
Power budget held at step 10Transmit power free at 22 dBm57°80°C stop at 4:0011.7 GB417 Mbps79°

At the same throughput, the power cap did two and a half times the work. The two guarded runs achieved 414 and 417 Mbps from starting temperatures within 1°C of each other. Capping the amplifier held the card under 80°C for the full ten minutes and moved 28.9 GB; holding the power budget reached the stop in four minutes having moved 11.7 GB. Cutting radiated power by 6 dB removes heat where it is made, while the budget only duty-cycles airtime, so the amplifier still runs flat out whenever the card transmits. The 75-second comparisons on 11 September pointed the same way but could not separate the two levers.

Bug

One governed run was budget-only, and did not say so

The eight-minute governed run in the vented case completed with no stop, peaking at 76°C and holding 70–76°C with the budget settling at step 12–14 — but transmit power read 22.00 dBm in all 233 samples. The cap rung never fired: the service enumerated radios in the host namespace while the test harness had moved this one into a namespace of its own, so it found nothing to cap and skipped silently. Applying 16 dBm by hand in the host namespace worked. The governor now reports its cap as applied, unavailable or off, so a guard that cannot act is visible rather than assumed. Read that run (vent-gov-tx) as budget-only, not as both guards together.

Single passes again, with unmatched starting temperatures, at bench range, with no ambient measurement. One run that day is published as contaminated: its configuration was edited without restarting the service, so the governor was still active in a run intended to have it off. On this evidence the power cap deserves to be the governor’s primary response and the budget its backstop, but that trades throughput, so it wants a repeat of the isolated pair before it becomes the default.

05 / The recorded runs

Keep the failed runs in view.

Completed runs, thermal stops, capture faults and one contaminated run are all included. A lower temperature does not turn an incomplete workload into a successful test.

Start and peak: BE200 °C. CPU: maximum GHz. Duration: recorded phase or source seconds.
RunCPU ceilingCooling setupStartPeakSecondsTrafficResult
Transmit01-tx2.016No BE200 pad · no fan52°80°60643.85partial sender Mbps80°C stop
Transmit02-tx1.800No BE200 pad · no fan54°80°51658.77partial sender Mbps80°C stop
Transmit03-tx2.016No BE200 pad · exhaust fan48°79°600.2790.64receiver MbpsCompleted
Transmit04-tx1.800No BE200 pad · exhaust fan49°80°357.1751.25partial sender Mbps80°C stop
Transmit04b-tx-1608Exploratory 1.608 GHz run1.608No BE200 pad · exhaust fan48°79°600.2776.67receiver MbpsCompleted
Transmit05-tx2.0160.5 mm BE200 pad · solid boot · no fan46°80°539.1579.17partial sender Mbps80°C stop
Transmit06-tx1.8000.5 mm BE200 pad · solid boot · no fan57°80°174594.34partial sender Mbps80°C stop
Receive01-rx2.016No BE200 pad · no fan48°65°600.1445.68receiver MbpsCompleted
Receive02-rx1.800No BE200 pad · no fan54°67°600.1443.28receiver MbpsCompleted
Receive03-rx2.016No BE200 pad · exhaust fan49°60°600.1444.92receiver MbpsCompleted
Receive04-rx1.800No BE200 pad · exhaust fan47°59°600.1447.75receiver MbpsCompleted
Receive05-rx2.0160.5 mm BE200 pad · solid boot · no fan57°67°600.1448.17receiver MbpsCompleted
Receive06-rx1.8000.5 mm BE200 pad · solid boot · no fan58°67°600.1444.64receiver MbpsCompleted
Transmit08-tx2.0160.5 mm BE200 pad · intake fan46°73°600.1708.45receiver MbpsCompleted
Transmit09-tx1.8000.5 mm BE200 pad · intake fan49°73°600.1726.37receiver MbpsCompleted
Receive08-rx2.0160.5 mm BE200 pad · intake fan49°56°600.1447.69receiver MbpsCompleted
Receive09-rx1.8000.5 mm BE200 pad · intake fan46°55°600.1448.64receiver MbpsCompleted
Capture → phone01-stream2.016No BE200 pad · no fan58°65°600481.52source MbpsCompleted
Capture → phone02-stream1.800No BE200 pad · no fan60°67°600515.82source MbpsFirmware restart
Capture → phone05-stream2.0160.5 mm BE200 pad · solid boot · no fan60°63°600389.89source MbpsCompleted
Capture → phone06-stream1.8000.5 mm BE200 pad · solid boot · no fan58°62°600405.49source MbpsCompleted
Capture → phone08-stream2.0160.5 mm BE200 pad · intake fan48°52°600477.36source MbpsPacket gaps
Capture → phone09-stream1.8000.5 mm BE200 pad · intake fan47°51°600482.34source MbpsPacket gaps
Transmitgov1-txGovernor run 1 · thresholds lowered to 66/60 °C1.8000.5 mm BE200 pad · solid boot · no fanGovernor on · 22 dBm · peak budget step 1552°72°239366.00receiver Mbps10.2 GB movedCompleted
Transmitgov2-txGovernor run 2 · thresholds 66/60 °C, in-band easing1.8000.5 mm BE200 pad · solid boot · no fanGovernor on · 22 dBm · peak budget step 1556°74°360352.00receiver Mbps14.8 GB movedCompleted
Transmitgov3-txGovernor run 3 · app warning test1.8000.5 mm BE200 pad · solid boot · no fanGovernor on · 22 dBm · peak budget step 1558°77°420331.00receiver Mbps16.2 GB movedCompleted
Transmitoff1-txGovernor off1.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 058°81°191686.00partial sender Mbps15.3 GB moved80°C stop
Transmitoff2-txGovernor off · warm start1.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 061°79°41704.00partial sender Mbps3.39 GB moved80°C stop
Transmitoff3-txGovernor off · warm start1.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 062°80°49693.00partial sender Mbps4.07 GB moved80°C stop
Transmitoff4-txGovernor off · app notification test1.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 058°80°137713.00partial sender Mbps11.5 GB moved80°C stop
Transmitoff5-txGovernor off · app notification test 21.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 054°79°397765.00partial sender Mbps35.4 GB moved80°C stop
Transmit22dbm-txComparison A · 22 dBm, budget 01.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 060°79°74702.00receiver Mbps6.14 GB movedCompleted
Transmit16dbm-txComparison B · 16 dBm cap, budget 01.8000.5 mm BE200 pad · solid boot · no fanGovernor off · 16 dBm cap · 16 dBm · peak budget step 060°76°73734.00receiver Mbps6.42 GB movedCompleted
Transmitstep10-txComparison C · 22 dBm, budget held at step 101.8000.5 mm BE200 pad · solid boot · no fanGovernor off · budget step 10 · 22 dBm · peak budget step 1059°77°74581.00receiver Mbps5.09 GB movedCompleted
Transmitvent-gov-contam-txContaminated · intended governor-off, but the config was edited without restarting the service, so the governor was active1.8000.5 mm BE200 pad · vented boot · no fanGovernor on · 22 dBm · peak budget step 1052°76°75374.00receiver Mbps3.28 GB movedCompleted
Transmitvent-off75-txGovernor off · 75 s pair to the contaminated run1.8000.5 mm BE200 pad · vented boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 053°76°74390.00receiver Mbps3.42 GB movedCompleted
Transmitvent-off-full-txGovernor off · full effort · vented-case counterpart to off11.8000.5 mm BE200 pad · vented boot · no fanGovernor off · 22 dBm · 22 dBm · peak budget step 054°79°273555.00partial sender Mbps17.8 GB moved80°C stop
Transmitvent-gov-txGovernor on · shipped 75/68 °C thresholds · budget only in effect: the TX-power rung never fired1.8000.5 mm BE200 pad · vented boot · no fanGovernor on · 22 dBm · peak budget step 1456°76°479285.00receiver Mbps15.9 GB movedCompleted
Transmitvent-16dbm-txIsolated guard · 16 dBm PA cap, budget free at step 01.8000.5 mm BE200 pad · vented boot · no fanGovernor off · 16 dBm cap · 16 dBm · peak budget step 058°78°599414.00receiver Mbps28.9 GB movedCompleted
Transmitvent-step10-txIsolated guard · budget held at step 10, PA free at 22 dBm1.8000.5 mm BE200 pad · vented boot · no fanGovernor off · budget step 10 · 22 dBm · peak budget step 1057°79°240417.00partial sender Mbps11.7 GB moved80°C stop

Native run durations span workload samples, including exit or drain time; phone rows show source duration. Interrupted TX uses a partial sender rate, not receiver throughput. Phone traffic is the generator’s achieved rate, not the capture file’s write rate. Phone “start” is the final ambient-streaming baseline reading; native “start” is the first workload reading. Missing values are shown as —. 11 and 12 September rows: two-second samples, start is the first telemetry sample, and stopped runs show the sender rate because the receiver total was never reported. Data moved is iperf3’s own sender total for the run, so for a stopped run it is the work completed before the stop.

Download measurement summary · JSON

40 recorded runs across the three days. Measurements and review status only; no packet captures or network metadata.

Exploratory tests and the first failed fan-on capture

The additional 1.608 GHz, no-BE200-pad exhaust-fan TX run completed ten minutes at a 79°C peak. It is labeled exploratory in the table.

A separate two-minute fan-direction check, without the BE200 pad, reached 75°C with intake versus 76°C in the first two minutes of the exhaust run. Intake began 4°C cooler and achieved about 41% less sender throughput. That does not establish a better fan direction.

The first fan-plus-pad 2.016 GHz phone attempt lost its SSH connection. Its 35,912-packet file ended before offered traffic began; the controller stopped the source after 5.838 seconds. This preparation/failure record is retained separately from the 23-run summary. A firmware restart occurred during that attempt’s preparation, before its baseline.

06 / Test conditions

One board. Four cooling setups.
Then a governor, then vents.

Cooling tests ran September 10 on image 1.0.7 and were reviewed September 11. The governor and transmit-power runs followed on September 11 on image 1.0.9, and the vented-case and isolated-guard runs on September 12 on the same image: same board, same radio firmware, same AP and channel throughout.

What stayed the same

Hardware
NanoPi Zero2 / RK3528, Intel BE200, metal finned case
CPU thermal path
CPU-to-case pad installed for every run
Test software
10 Sept: sensor image 1.0.7, Linux 7.3.0-rc1, BE200 firmware 106; phone runs used WC 1.1.0. 11 and 12 Sept: image 1.0.9, same kernel and firmware, governor in wc-thermal
Radio link
Same 5 GHz AP, 5785 MHz primary, 80 MHz width; power saving on
CPU policy
Ondemand, 1.2 GHz minimum, ceilings of 2.016 and 1.800 GHz; one exploratory 1.608 GHz run
Load and baseline
10 Sept: four TCP streams for 600 seconds; at least five baseline minutes with four 30-second means within 1°C. Phone baselines include ambient streaming. 11 and 12 Sept: four TCP streams for 75–600 seconds, started at whatever the card read after the previous run; no baseline hold.

What changed

  1. No BE200 pad, no fanCPU-to-case pad still installed.
  2. No BE200 pad, exhaust fanNoctua 40 × 40 × 10 mm, 5 V USB, resting on the case fins and blowing away.
  3. 0.5 mm BE200 pad, no fanPad material and exact contact path were not independently documented.
  4. 0.5 mm BE200 pad, intake fanThe same fan reversed to blow into the case. Both pads retained.
  5. 11 September: 0.5 mm BE200 pad, solid SMA boot, no fan, governor on or offThe fan was never fitted that day. Transmit only, 1.8 GHz ceiling; 16 dBm cap and a held budget step 10 as single comparisons.
  6. 12 September: the same pad in a vented SMA boot, no fanThree recessed chevron vents per grip and an open interior pocket. Transmit only, 1.8 GHz ceiling, with the transmit-power cap and the held budget step measured one at a time.

The earlier fan stage used exhaust; the final stage used intake. Comparing those stages changes both the BE200 pad and fan direction.

07 / What remains unresolved

Cooling improved. One guard clearly wins. Capture still needs work.

01

Packet gaps at low reported temperatures

The final fan-on phone files contained gaps of up to 23.144 seconds at 2.016 GHz and 42.044 seconds at 1.8 GHz. Remote capture output also paused, while temperature samples continued with zero writeback. The 2.016 GHz retry ended 14.474 seconds before its traffic window ended and lacked its controller and positioning sidecars. Both are incomplete continuous-capture comparisons.

Both final source loads ran for ten minutes with no firmware fault in their kernel logs, but fewer packets and bytes were recorded than in the pad-only captures. The capture-processing loads were therefore not identical. Kernel capture-drop counters are unavailable from this WC build.

02

Firmware recovery is a separate finding

The earlier no-pad 1.8 GHz phone capture had a firmware restart during load. Another restart occurred during preparation of the first fan-plus-pad capture attempt. Neither establishes a thermal cause. The clean final TX/RX tests do not resolve those faults.

03

No regulator temperature measurement, and no SoC reading before image 1.0.9

On 10 September the only reading was the BE200’s sensor. Image 1.0.9 adds an SoC sensor, but regulator hot spots, case temperature, ambient temperature, fan RPM and input power were still not measured on either day. CPU frequency ceilings are not fixed operating clocks, and these network workloads are not all-core CPU stress tests. These single passes cannot establish safe unattended operation.

04

The governor is measured in single passes, not soaked

The longest run in either governor campaign was ten minutes, none was repeated under identical conditions, and the 80°C stop remains our laboratory guard rather than Intel’s rating. The governor’s cost is sustained throughput: it holds the budget down until the card is under 68°C, and the two-up, one-down asymmetry settles a step or two above the minimum that would hold the line. The 16 dBm cap was tested at bench range only, where it costs little; at range it would give up modulation before the budget does, and that has not been measured.

05

What 12 September did not settle

Making the transmit-power cap the governor’s primary response is not done: it trades throughput, and the isolated pair wants repeating before the default changes. There is still no soak test, no ambient measurement and no regulator or voltage-regulator temperature. A thermal-camera attempt on the open board caught only a warm, unloaded board and is not published. The vented boot was compared to the solid one in single passes with unmatched starting temperatures, and the one governed run in the vented case turned out to be budget-only.

Image status. These runs were made on image 1.0.9, an unpublished build. Sensor image 1.0.11, published 12 September 2026, is the first release to carry the governor and the SoC sensor, with the transmit-power cap as the governor's first rung and the 75/68 °C thresholds used in the gov3 run above. The figures here were not re-measured on it. Image 1.0.8 and 1.0.10 were intermediate builds that were never published. Download it from the NanoPi Zero2 setup.

Evidence: archived one-second (10 Sept) and two-second (11 and 12 Sept) sensor logs, iperf3 summaries, station-dump rates, kernel logs, and whole-file packet timestamp reviews. All original failures remain in the local campaign archive. Measurements and graphs on this page were reviewed September 12, 2026.

NanoPi Zero2 on the unified image →