<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SBC on dev@iostream.pl</title><link>https://dev.iostream.pl/tags/sbc/</link><description>Recent content in SBC on dev@iostream.pl</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 20 Sep 2026 17:15:00 +0200</lastBuildDate><atom:link href="https://dev.iostream.pl/tags/sbc/index.xml" rel="self" type="application/rss+xml"/><item><title>Cold and Darkness (III)</title><link>https://dev.iostream.pl/posts/2026-09-20/</link><pubDate>Sun, 20 Sep 2026 17:15:00 +0200</pubDate><guid>https://dev.iostream.pl/posts/2026-09-20/</guid><description>&lt;p&gt;The third and final episode of the saga about SBC cases and cooling.&lt;/p&gt;
&lt;h1 id="rock-5t"&gt;ROCK 5T
&lt;/h1&gt;&lt;p&gt;The latest SBC to find its way into my home is the &lt;strong&gt;ROCK 5T&lt;/strong&gt; — a serious contender in my Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;It is based on the &lt;strong&gt;Rockchip RK3588&lt;/strong&gt;, an eight-core SoC combining:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;four Cortex-A76 cores,&lt;/li&gt;
&lt;li&gt;four Cortex-A55 cores,&lt;/li&gt;
&lt;li&gt;a Mali-G610 GPU,&lt;/li&gt;
&lt;li&gt;an NPU capable of up to 6 TOPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My unit has &lt;strong&gt;16 GB of RAM&lt;/strong&gt; and a &lt;strong&gt;500 GB NVMe SSD&lt;/strong&gt; — the latter being entirely my own indulgence.&lt;/p&gt;
&lt;p&gt;This configuration should remain useful for years: compiling software, collecting metrics, running heavier cluster workloads, and experimenting with relatively small language models.&lt;/p&gt;
&lt;p&gt;The ROCK 5T also provides two HDMI outputs, one HDMI input, DisplayPort over USB-C, dual 2.5 GbE, and two M.2 M-Key slots for NVMe drives.&lt;/p&gt;
&lt;p&gt;There is also a standard 40-pin GPIO header, which suggests plenty of other possible uses.&lt;/p&gt;
&lt;p&gt;Operating system?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Armbian&lt;/strong&gt;, obviously.&lt;/p&gt;
&lt;p&gt;The ROCK 5T currently has &lt;strong&gt;Platinum&lt;/strong&gt; support there, placing it among the better-supported boards in Armbian&amp;rsquo;s catalogue.&lt;/p&gt;
&lt;p&gt;But first&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;hellip;the board needs a case, proper cooling, and a little stress testing.&lt;/p&gt;
&lt;h2 id="power"&gt;Power
&lt;/h2&gt;&lt;p&gt;The power supply must be purchased separately.&lt;/p&gt;
&lt;p&gt;And here comes the first surprise: the ROCK 5T does not use ordinary USB-C power.&lt;/p&gt;
&lt;p&gt;It accepts &lt;strong&gt;9–20 V DC&lt;/strong&gt; through a 5.5/2.5 mm barrel connector, with &lt;strong&gt;12 V recommended&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Radxa recommends a supply capable of at least &lt;strong&gt;36 W&lt;/strong&gt;, which means 12 V / 3 A or more.&lt;/p&gt;
&lt;p&gt;The USB-C port handles things such as OTG and DisplayPort, but it does &lt;strong&gt;not&lt;/strong&gt; power the board.&lt;/p&gt;
&lt;p&gt;So all those convenient USB-C power supplies already sitting on the shelf?&lt;/p&gt;
&lt;p&gt;Not this time.&lt;/p&gt;
&lt;p&gt;Apparently the marketing department decided that the purchasing experience would be more complete if several parts of a complete computer had to be bought separately.&lt;/p&gt;
&lt;h2 id="cpu-cooling"&gt;CPU Cooling
&lt;/h2&gt;&lt;p&gt;The CPU fan also has to be purchased separately.&lt;/p&gt;
&lt;p&gt;Fortunately, the official active heatsink fits perfectly and requires no improvisation.&lt;/p&gt;
&lt;p&gt;Radxa lists active cooling among the official accessories for the board.&lt;/p&gt;
&lt;p&gt;So at least this time it is clear what the designer intended.&lt;/p&gt;
&lt;h2 id="the-case"&gt;The Case
&lt;/h2&gt;&lt;p&gt;The case&amp;hellip;&lt;/p&gt;
&lt;p&gt;Yes.&lt;/p&gt;
&lt;p&gt;You guessed correctly.&lt;/p&gt;
&lt;p&gt;That must be purchased separately as well.&lt;/p&gt;
&lt;p&gt;I chose the official Radxa metal enclosure.&lt;/p&gt;
&lt;p&gt;The product description warned that the case might not provide proper access to the &lt;strong&gt;HDMI-IN&lt;/strong&gt; connector.&lt;/p&gt;
&lt;p&gt;Naturally, this sounded disappointing.&lt;/p&gt;
&lt;p&gt;When the package arrived, however, the HDMI-IN opening turned out to be perfectly usable.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;GPIO header&lt;/strong&gt;, on the other hand, was not conveniently accessible.&lt;/p&gt;
&lt;p&gt;So the documentation warns about the problem that is not there and forgets to mention the one that is.&lt;/p&gt;
&lt;p&gt;One has to admire the consistency.&lt;/p&gt;
&lt;h2 id="assembly"&gt;Assembly
&lt;/h2&gt;&lt;p&gt;The package contains two thermal pads roughly the size of an &lt;strong&gt;M.2 2280&lt;/strong&gt; drive.&lt;/p&gt;
&lt;p&gt;That makes sense, because the ROCK 5T supports two 2280 NVMe SSDs.&lt;/p&gt;
&lt;p&gt;The pad goes onto the SSD before the board is placed inside the case.&lt;/p&gt;
&lt;p&gt;Once the case is closed, the pad makes contact with the metal enclosure, effectively turning the case itself into a large heatsink for the drive.&lt;/p&gt;
&lt;p&gt;Simple.&lt;/p&gt;
&lt;p&gt;Effective.&lt;/p&gt;
&lt;p&gt;The case also includes two &lt;strong&gt;external Wi-Fi antennas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The original antennas can therefore be disconnected and replaced with the external ones before the enclosure is closed.&lt;/p&gt;
&lt;p&gt;In my case, I removed the Wi-Fi antennas entirely.&lt;/p&gt;
&lt;p&gt;This machine has been connected exclusively through Ethernet from the beginning.&lt;/p&gt;
&lt;p&gt;When a board provides two 2.5 GbE interfaces, it becomes surprisingly difficult to justify making a cluster node send packets through the air.&lt;/p&gt;
&lt;h1 id="testing"&gt;Testing
&lt;/h1&gt;&lt;p&gt;Measurements were taken exactly as in the previous two parts.&lt;/p&gt;
&lt;p&gt;Two thermometers.&lt;/p&gt;
&lt;p&gt;For the NVMe drive:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo nvme smart-log /dev/nvme0 | grep temperature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the CPU:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;armbianmonitor -m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then the two now-familiar stress tests.&lt;/p&gt;
&lt;p&gt;CPU and memory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --cpu &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm-bytes 60% &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --timeout 10m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --metrics-brief
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I/O:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fio &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvme-test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/fio.test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4G &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;readwrite &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --iodepth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --direct&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --runtime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;5m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --time_based &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --group_reporting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As always, &lt;code&gt;fio&lt;/code&gt; writes data to the selected file.&lt;/p&gt;
&lt;p&gt;Here, that file is &lt;code&gt;/tmp/fio.test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Do not casually replace it with a block device unless you intend to begin writing an entirely different article immediately afterward.&lt;/p&gt;
&lt;h1 id="results"&gt;Results
&lt;/h1&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;stress-ng&lt;/code&gt;&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;fio&lt;/code&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;NVMe&lt;/td&gt;
					&lt;td style="text-align: right"&gt;39 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;40 °C&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CPU&lt;/td&gt;
					&lt;td style="text-align: right"&gt;62.8 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;55.5 °C&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Very good.&lt;/p&gt;
&lt;p&gt;The NVMe remains cool, and the CPU stays comfortably below temperatures where thermal throttling would become a concern.&lt;/p&gt;
&lt;p&gt;That means this machine can now be used regularly in the cluster in a way that actually reflects its computing power, memory capacity, and storage.&lt;/p&gt;
&lt;p&gt;In my case, that means heavier CI/CD workloads, metrics, and everything smaller SBCs would accept only with a very audible sigh.&lt;/p&gt;
&lt;h1 id="series-conclusion"&gt;Series Conclusion
&lt;/h1&gt;&lt;p&gt;After three episodes, the conclusion is fairly simple:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cooling is not an optional accessory.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On modern high-performance SBCs, it is part of the basic system design.&lt;/p&gt;
&lt;p&gt;Without a heatsink, fan, or properly designed enclosure, every board described in this series can reach unpleasant temperatures very quickly under sustained load.&lt;/p&gt;
&lt;p&gt;With appropriate cooling, the picture changes completely.&lt;/p&gt;
&lt;p&gt;Every machine tested here maintained reasonable temperatures during both CPU stress and intensive NVMe activity.&lt;/p&gt;
&lt;p&gt;In several cases, the results were better than I expected.&lt;/p&gt;
&lt;p&gt;So the patients survived.&lt;/p&gt;
&lt;p&gt;They are doing well.&lt;/p&gt;
&lt;p&gt;And they can safely be sent back to work.&lt;/p&gt;
&lt;p&gt;If another single-board resident appears in my fortress, this supposedly final trilogy may receive an entirely unplanned fourth episode.&lt;/p&gt;
&lt;p&gt;Because everyone always says:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;this is definitely my last SBC.&lt;/p&gt;

 &lt;/blockquote&gt;</description></item><item><title>Cold and Darkness (II)</title><link>https://dev.iostream.pl/posts/2026-09-15/</link><pubDate>Tue, 15 Sep 2026 15:20:00 +0200</pubDate><guid>https://dev.iostream.pl/posts/2026-09-15/</guid><description>&lt;p&gt;In this episode, two more machines go through the usual treatment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Raspberry Pi 500+&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Odroid M2&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are interesting for very different reasons.&lt;/p&gt;
&lt;p&gt;One is essentially a complete computer hidden inside a keyboard.&lt;/p&gt;
&lt;p&gt;The other is a traditional SBC that still needs a case, cooling, and a little persuasion before it behaves properly under sustained load.&lt;/p&gt;
&lt;h2 id="raspberry-pi-500"&gt;Raspberry Pi 500+
&lt;/h2&gt;&lt;p&gt;The next machine is the &lt;strong&gt;Raspberry Pi 500+&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I bought mine at a very good price, and it turned out to be an excellent purchase.&lt;/p&gt;
&lt;p&gt;It comes with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a mechanical keyboard,&lt;/li&gt;
&lt;li&gt;16 GB of RAM,&lt;/li&gt;
&lt;li&gt;a factory-installed &lt;strong&gt;256 GB NVMe SSD&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The mechanical keyboard obviously has no effect on CPU performance or temperature.&lt;/p&gt;
&lt;p&gt;I simply happen to be a very big fan of mechanical keyboards.&lt;/p&gt;
&lt;p&gt;Perhaps there will be an episode about those one day.&lt;/p&gt;
&lt;p&gt;That is a threat.&lt;/p&gt;
&lt;p&gt;The other two features are considerably more practical.&lt;/p&gt;
&lt;p&gt;A proper SSD is a much better place for an operating system than an SD card, and nobody has ever become ill from having too much RAM.&lt;/p&gt;
&lt;p&gt;Except perhaps after looking at the invoice.&lt;/p&gt;
&lt;p&gt;As mentioned earlier, though, I bought this particular machine at a substantial discount — considerably cheaper than any other bare SBC in my collection with comparable NVMe support.&lt;/p&gt;
&lt;p&gt;The Raspberry Pi 500+ is an all-in-one design, with all the electronics enclosed inside the keyboard case.&lt;/p&gt;
&lt;p&gt;The result looks a little like a modern, simplified &lt;strong&gt;Amiga 500&lt;/strong&gt;, or one of the classic home computers from the 1980s and 1990s.&lt;/p&gt;
&lt;p&gt;That is not accidental.&lt;/p&gt;
&lt;p&gt;Raspberry Pi itself described the 500+ as a tribute to the home computers many of us grew up with.&lt;/p&gt;
&lt;p&gt;What is less obvious without opening the case is how exactly the cooling has been implemented.&lt;/p&gt;
&lt;p&gt;Questions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;how the CPU is cooled,&lt;/li&gt;
&lt;li&gt;where thermal pads are used,&lt;/li&gt;
&lt;li&gt;whether additional heatsinks are present,&lt;/li&gt;
&lt;li&gt;how the NVMe drive is cooled.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The SSD itself is also something you mostly know about from the specification rather than from direct visual inspection.&lt;/p&gt;
&lt;p&gt;Yes, I know.&lt;/p&gt;
&lt;p&gt;I could open the case.&lt;/p&gt;
&lt;p&gt;Unfortunately, one of the screws appears to have made a personal decision to remain exactly where it is.&lt;/p&gt;
&lt;p&gt;And since the machine works perfectly well, for now I am satisfied with knowing that it works perfectly well.&lt;/p&gt;
&lt;p&gt;That is, after all, what I bought it for.&lt;/p&gt;
&lt;h3 id="testing"&gt;Testing
&lt;/h3&gt;&lt;p&gt;The same tests used earlier for the &lt;strong&gt;Orange Pi 5 Plus&lt;/strong&gt; and the &lt;strong&gt;Raspberry Pi 5&lt;/strong&gt; in the DeskPi case work perfectly well here.&lt;/p&gt;
&lt;p&gt;For the NVMe temperature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo nvme smart-log /dev/nvme0 | grep temperature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the Raspberry Pi itself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vcgencmd measure_temp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vcgencmd measure_clock arm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vcgencmd get_throttled
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first command reports CPU temperature.&lt;/p&gt;
&lt;p&gt;The second shows the current ARM clock frequency.&lt;/p&gt;
&lt;p&gt;The third is especially useful because it reveals whether the system has experienced thermal throttling, undervoltage, or related issues.&lt;/p&gt;
&lt;p&gt;The CPU and memory stress test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --cpu &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm-bytes 60% &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --timeout 10m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --metrics-brief
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the I/O test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fio &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvme-test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/fio.test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4G &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;readwrite &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --iodepth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --direct&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --runtime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;5m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --time_based &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --group_reporting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As before, &lt;code&gt;fio&lt;/code&gt; writes data to the selected file.&lt;/p&gt;
&lt;p&gt;In this example, that file is &lt;code&gt;/tmp/fio.test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Do not spontaneously replace it with a block device unless ruining the rest of your day is part of the benchmark.&lt;/p&gt;
&lt;h3 id="results"&gt;Results
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;stress-ng&lt;/code&gt;&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;fio&lt;/code&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;NVMe&lt;/td&gt;
					&lt;td style="text-align: right"&gt;35 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;31 °C&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CPU&lt;/td&gt;
					&lt;td style="text-align: right"&gt;47.7 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;37.8 °C&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Compared with the other SBCs tested so far, these results are excellent.&lt;/p&gt;
&lt;p&gt;Especially considering that the whole computer is enclosed inside a keyboard.&lt;/p&gt;
&lt;p&gt;It looks very much as though the engineers behind the &lt;strong&gt;Raspberry Pi 500+&lt;/strong&gt; did an exceptionally good job.&lt;/p&gt;
&lt;p&gt;One might even say they did their homework.&lt;/p&gt;
&lt;p&gt;Although in Poland in 2026, that metaphor now requires a little caution.&lt;/p&gt;
&lt;h2 id="odroid-m2"&gt;Odroid M2
&lt;/h2&gt;&lt;p&gt;The &lt;strong&gt;Odroid M2&lt;/strong&gt; arrived with its standard case and cooling fan.&lt;/p&gt;
&lt;p&gt;The enclosure is made of plastic, which initially made me wonder whether it would cope well with sustained heat, especially from the NVMe drive.&lt;/p&gt;
&lt;p&gt;As it turns out, the design is quite sensible.&lt;/p&gt;
&lt;p&gt;The top of the case contains ventilation openings directly around the fan area.&lt;/p&gt;
&lt;p&gt;The underside has openings near the NVMe drive.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Top" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="288" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://dev.iostream.pl/posts/2026-09-15/odroid-1.jpg" width="512"&gt;
&lt;img alt="Bottom" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="288" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://dev.iostream.pl/posts/2026-09-15/odroid-2.jpg" width="512"&gt;&lt;/p&gt;
&lt;p&gt;This strongly suggests that the intended cooling strategy is airflow rather than pressing the SSD against the enclosure through a thermal pad.&lt;/p&gt;
&lt;p&gt;So I left it exactly as designed.&lt;/p&gt;
&lt;p&gt;Assembly took perhaps three minutes.&lt;/p&gt;
&lt;p&gt;Which is always suspicious.&lt;/p&gt;
&lt;p&gt;Usually, if assembling an SBC takes only three minutes, it means you forgot something.&lt;/p&gt;
&lt;p&gt;Not this time.&lt;/p&gt;
&lt;p&gt;Hardkernel itself notes that the Odroid M2 can generate enough heat under sustained CPU and GPU load to require active cooling, which is why a fan is included in the kit. Its speed can be controlled using PWM.&lt;/p&gt;
&lt;h3 id="testing-1"&gt;Testing
&lt;/h3&gt;&lt;p&gt;The tests were identical to the previous ones.&lt;/p&gt;
&lt;p&gt;For NVMe temperature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo nvme smart-log /dev/nvme0 | grep temperature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For SoC temperature under Armbian:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;armbianmonitor -m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --cpu &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm-bytes 60% &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --timeout 10m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --metrics-brief
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fio &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvme-test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/fio.test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4G &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;readwrite &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --iodepth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --direct&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --runtime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;5m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --time_based &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --group_reporting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="results-1"&gt;Results
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;stress-ng&lt;/code&gt;&lt;/th&gt;
					&lt;th style="text-align: right"&gt;&lt;code&gt;fio&lt;/code&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;NVMe&lt;/td&gt;
					&lt;td style="text-align: right"&gt;46 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;50 °C&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CPU&lt;/td&gt;
					&lt;td style="text-align: right"&gt;61 °C&lt;/td&gt;
					&lt;td style="text-align: right"&gt;59.2 °C&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Before running the tests, I was slightly concerned that every SBC enclosed in a metal case would outperform the plastic Odroid by a wide margin.&lt;/p&gt;
&lt;p&gt;That did not happen.&lt;/p&gt;
&lt;p&gt;The CPU remained comfortably below troublesome temperatures, and the NVMe temperature was perfectly reasonable as well.&lt;/p&gt;
&lt;p&gt;So plastic does not always mean:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;this is going to get hot.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Sometimes it simply means:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;someone designed the airflow properly.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="to-be-continued"&gt;To Be Continued
&lt;/h2&gt;&lt;p&gt;Next time:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rock 5T&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;More metal.&lt;/p&gt;
&lt;p&gt;More NVMe.&lt;/p&gt;
&lt;p&gt;And more reasons to run &lt;code&gt;stress-ng&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Cold and Darkness</title><link>https://dev.iostream.pl/posts/2026-09-08/</link><pubDate>Tue, 08 Sep 2026 11:10:00 +0200</pubDate><guid>https://dev.iostream.pl/posts/2026-09-08/</guid><description>&lt;p&gt;After several weeks of experimenting with various SBCs, the time finally came to provide them with two basic necessities: a proper case and proper cooling.&lt;/p&gt;
&lt;p&gt;Neither is always as straightforward as it sounds, so I decided to document the process.&lt;/p&gt;
&lt;h1 id="raspberry-pi-5-and-deskpi"&gt;Raspberry Pi 5 and DeskPi
&lt;/h1&gt;&lt;h2 id="assembly"&gt;Assembly
&lt;/h2&gt;&lt;p&gt;For the Raspberry Pi 5, one can buy a &lt;strong&gt;DeskPi&lt;/strong&gt; kit.&lt;/p&gt;
&lt;p&gt;Which is exactly what I did.&lt;/p&gt;
&lt;p&gt;The word &lt;em&gt;kit&lt;/em&gt; is particularly appropriate here, because the box contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the case itself,&lt;/li&gt;
&lt;li&gt;a fan,&lt;/li&gt;
&lt;li&gt;thermal pads,&lt;/li&gt;
&lt;li&gt;a multifunction adapter board.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last item is by far the most interesting part.&lt;/p&gt;
&lt;p&gt;It acts as an M.2 NVMe adapter, converts the Raspberry Pi&amp;rsquo;s micro-HDMI connectors to full-size HDMI, reroutes USB-C power, and adds a proper physical power button.&lt;/p&gt;
&lt;p&gt;In other words, it fixes several things one might reasonably wish had been there from the beginning.&lt;/p&gt;
&lt;p&gt;DeskPi&amp;rsquo;s own product description confirms support for M.2 NVMe drives, full-size HDMI through an adapter board, rerouted USB-C, and a power switch.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Assembly is not particularly difficult.&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Except for the ribbon cable.&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;The first step is to throw the manual into the trash.&lt;/p&gt;
&lt;p&gt;Unless you own a paper shredder.&lt;/p&gt;
&lt;p&gt;In that case, use the shredder.&lt;/p&gt;
&lt;p&gt;I envy you.&lt;/p&gt;
&lt;p&gt;Trust me: the manual will not help much.&lt;/p&gt;
&lt;p&gt;I had already been using an NVMe drive with my Raspberry Pi 5, so I first had to dismantle the existing setup and remove the &lt;strong&gt;Pimoroni NVMe Base&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A very good product, incidentally.&lt;/p&gt;
&lt;p&gt;Just no longer useful in this particular configuration.&lt;/p&gt;
&lt;p&gt;The USB-C and HDMI extension pieces fit without much trouble, and most of the assembly is pleasantly uneventful.&lt;/p&gt;
&lt;p&gt;If you do not already have a fan installed, this is a good moment to add one.&lt;/p&gt;
&lt;p&gt;Remember the thermal pads.&lt;/p&gt;
&lt;p&gt;My Raspberry Pi 5 already had the official active cooler installed, and I decided to keep it because it works perfectly well.&lt;/p&gt;
&lt;p&gt;The one thing that deserves disproportionate attention is the PCIe ribbon cable.&lt;/p&gt;
&lt;p&gt;Yes, it can physically be inserted in more than one orientation.&lt;/p&gt;
&lt;p&gt;No, only one of them is useful.&lt;/p&gt;
&lt;p&gt;The final result should look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="ribbon" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="576" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://dev.iostream.pl/posts/2026-09-08/ribbon.jpg" srcset="https://dev.iostream.pl/posts/2026-09-08/ribbon_hu_4d1fde607d91a351.jpg 800w, https://dev.iostream.pl/posts/2026-09-08/ribbon.jpg 1024w" width="1024"&gt;&lt;/p&gt;
&lt;p&gt;If it does not, you may spend several enjoyable hours wondering why the Raspberry Pi can no longer see the NVMe drive.&lt;/p&gt;
&lt;p&gt;I did.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;No, the manual does not clearly explain the ribbon orientation.&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Do not retrieve it from the trash.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;If the Raspberry Pi already booted from NVMe before moving into the case, there is a good chance it will continue doing so without any additional changes.&lt;/p&gt;
&lt;p&gt;That was exactly what happened in my case.&lt;/p&gt;
&lt;p&gt;No new &lt;code&gt;config.txt&lt;/code&gt; entries.&lt;/p&gt;
&lt;p&gt;No bootloader changes.&lt;/p&gt;
&lt;p&gt;Nothing.&lt;/p&gt;
&lt;p&gt;Null.&lt;/p&gt;
&lt;p&gt;Nada.&lt;/p&gt;
&lt;p&gt;However, my bootloader had already been configured for NVMe booting beforehand, so a fresh setup may require additional preparation.&lt;/p&gt;
&lt;h2 id="testing"&gt;Testing
&lt;/h2&gt;&lt;p&gt;Once everything works and the case is properly assembled, it seems reasonable to perform a few basic stress tests.&lt;/p&gt;
&lt;p&gt;I used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stress-ng&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fio&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvme-cli&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt install nvme-cli fio stress-ng
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The NVMe drive temperature can be read with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo nvme smart-log /dev/nvme0 | grep temperature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The CPU temperature on Raspberry Pi can be checked with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vcgencmd measure_temp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first test applies ten minutes of CPU and memory pressure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --cpu &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm-bytes 60% &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --timeout 10m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --metrics-brief
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second one produces sustained I/O activity:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fio &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvme-test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/fio.test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4G &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;readwrite &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --iodepth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --direct&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --runtime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;5m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --time_based &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --group_reporting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A small warning here:&lt;/p&gt;
&lt;p&gt;the &lt;code&gt;fio&lt;/code&gt; test writes data to the selected file.&lt;/p&gt;
&lt;p&gt;In this example that file is &lt;code&gt;/tmp/fio.test&lt;/code&gt;, which is intentional.&lt;/p&gt;
&lt;p&gt;Do not casually replace it with a block device unless destroying data is part of the experiment.&lt;/p&gt;
&lt;h2 id="results"&gt;Results
&lt;/h2&gt;&lt;p&gt;The NVMe drive peaked at around &lt;strong&gt;50°C&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The CPU reached &lt;strong&gt;73.6°C&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For a Raspberry Pi 5 under sustained load inside a compact case, I consider that perfectly acceptable.&lt;/p&gt;
&lt;h1 id="orange-pi-5-plus-and-the-geekpi-case"&gt;Orange Pi 5 Plus and the GeekPi Case
&lt;/h1&gt;&lt;h2 id="assembly-1"&gt;Assembly
&lt;/h2&gt;&lt;p&gt;The GeekPi case is a black aluminum enclosure.&lt;/p&gt;
&lt;p&gt;It is appropriately ugly.&lt;/p&gt;
&lt;p&gt;It is also extremely well suited to the Orange Pi 5 Plus, which is much more important.&lt;/p&gt;
&lt;p&gt;The case accommodates an &lt;strong&gt;M.2 2280&lt;/strong&gt; drive and has a top-mounted fan that moves air across a larger portion of the board rather than cooling only the SoC.&lt;/p&gt;
&lt;p&gt;The kit also includes thermal pads and small heatsinks.&lt;/p&gt;
&lt;p&gt;Unlike the DeskPi manual, the product page does a reasonably good job of showing where everything belongs.&lt;/p&gt;
&lt;p&gt;Progress.&lt;/p&gt;
&lt;p&gt;There is, however, one complication:&lt;/p&gt;
&lt;p&gt;the fan.&lt;/p&gt;
&lt;p&gt;The Orange Pi 5 Plus provides a dedicated two-pin &lt;strong&gt;FAN&lt;/strong&gt; connector using a small JST-style plug, while the fan included with the case terminates in two separate DuPont connectors intended for GPIO pins.&lt;/p&gt;
&lt;p&gt;If one simply wants the fan to run continuously, it can be connected to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+5V&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GND&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This works.&lt;/p&gt;
&lt;p&gt;The disadvantages are equally obvious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the fan runs all the time,&lt;/li&gt;
&lt;li&gt;there is no temperature control,&lt;/li&gt;
&lt;li&gt;two GPIO header pins are occupied,&lt;/li&gt;
&lt;li&gt;even a quiet fan becomes surprisingly noticeable after several hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wanted the board itself to control the fan.&lt;/p&gt;
&lt;h2 id="modifying-the-fan-cable"&gt;Modifying the Fan Cable
&lt;/h2&gt;&lt;p&gt;The dedicated Orange Pi fan connector is intended to cooperate with software-controlled fan handling.&lt;/p&gt;
&lt;p&gt;On current Linux setups this is typically exposed through the kernel&amp;rsquo;s &lt;code&gt;pwm-fan&lt;/code&gt; mechanism and device-tree configuration. Orange Pi documentation and Armbian discussions show temperature-dependent fan levels rather than a simple permanently powered connection.&lt;/p&gt;
&lt;p&gt;That sounded much better.&lt;/p&gt;
&lt;p&gt;I bought a handful of inexpensive 1.25 mm JST pigtails and prepared to modify the cable.&lt;/p&gt;
&lt;p&gt;&lt;img alt="fan" class="gallery-image" data-flex-basis="409px" data-flex-grow="170" height="271" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://dev.iostream.pl/posts/2026-09-08/fan.jpg" width="462"&gt;&lt;/p&gt;
&lt;p&gt;Before soldering anything, I checked the connector electrically with a multimeter.&lt;/p&gt;
&lt;p&gt;This is highly recommended.&lt;/p&gt;
&lt;p&gt;Do not trust wire colors alone.&lt;/p&gt;
&lt;p&gt;Do not trust random diagrams found in image search.&lt;/p&gt;
&lt;p&gt;Do not trust yourself after midnight.&lt;/p&gt;
&lt;p&gt;I connected a JST pigtail to the FAN header, powered on the Orange Pi, and observed the behavior while increasing CPU temperature with &lt;code&gt;stress-ng&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The test confirmed that the dedicated connector was being controlled according to temperature.&lt;/p&gt;
&lt;p&gt;With that established, the rest was simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cut off the DuPont connectors,&lt;/li&gt;
&lt;li&gt;strip roughly one centimeter of insulation from the fan wires,&lt;/li&gt;
&lt;li&gt;strip the JST pigtail wires,&lt;/li&gt;
&lt;li&gt;slide heat-shrink tubing onto the wires &lt;strong&gt;before soldering&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;solder the matching wires,&lt;/li&gt;
&lt;li&gt;move the heat-shrink tubing over the joints,&lt;/li&gt;
&lt;li&gt;gently heat it until it contracts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The third item deserves special emphasis.&lt;/p&gt;
&lt;p&gt;Most people remember heat-shrink tubing immediately after finishing the solder joint.&lt;/p&gt;
&lt;p&gt;This is one of the traditional stages of electronics education.&lt;/p&gt;
&lt;h2 id="testing-1"&gt;Testing
&lt;/h2&gt;&lt;p&gt;After carefully assembling the case again, it was time for another round of tests.&lt;/p&gt;
&lt;p&gt;First, the tools:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt install nvme-cli fio stress-ng
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The NVMe temperature:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo nvme smart-log /dev/nvme0 | grep temperature
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the Orange Pi under Armbian, system temperature can conveniently be monitored with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;armbianmonitor -m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output refreshes every few seconds and includes the SoC temperature.&lt;/p&gt;
&lt;p&gt;The same stress tests can then be repeated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --cpu &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --vm-bytes 60% &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --timeout 10m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --metrics-brief
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fio &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nvme-test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/tmp/fio.test &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4G &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --rw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;readwrite &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1M &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --iodepth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --direct&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --runtime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;5m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --time_based &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --group_reporting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="results-1"&gt;Results
&lt;/h2&gt;&lt;p&gt;The NVMe drive peaked at &lt;strong&gt;44°C&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The CPU briefly reached &lt;strong&gt;68.4°C&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At that point, the fan came alive.&lt;/p&gt;
&lt;p&gt;Afterward, the temperature rarely exceeded roughly &lt;strong&gt;65°C&lt;/strong&gt; under the same workload.&lt;/p&gt;
&lt;p&gt;That is exactly the kind of behavior I wanted: silent when cooling is unnecessary, audible only when the board actually needs help.&lt;/p&gt;
&lt;p&gt;And, most importantly, controlled by the SBC rather than permanently wired to five volts like a tiny desk fan from 1997.&lt;/p&gt;
&lt;h1 id="to-be-continued"&gt;To Be Continued
&lt;/h1&gt;&lt;p&gt;Two boards down.&lt;/p&gt;
&lt;p&gt;Several still waiting.&lt;/p&gt;
&lt;p&gt;In the next part:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Odroid M2&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raspberry Pi 500+&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One of them has a perfectly reasonable case.&lt;/p&gt;
&lt;p&gt;The other has opinions.&lt;/p&gt;</description></item></channel></rss>