TinyComputers.io (Posts about raspberry pi)https://tinycomputers.io/categories/raspberry-pi.atom2024-03-29T01:50:41ZA.C. JokelaNikolaMarlin Firmware - Modified Ender 3 Prohttps://tinycomputers.io/posts/marlin-firmware-modified-ender-3-pro.html2023-02-19T15:11:27-06:002023-02-19T15:11:27-06:00A.C. Jokela<p><img src="https://tinycomputers.io/images/ender_3_pro-IMG_1086.jpg" loading="lazy" style="zoom: 30%; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: left; padding: 45px;"> Just about the only thing original and stock on my two <a href="https://amzn.to/3EljJEo">Creality Ender 3 Pro</a> 3D printers are the extruded aluminum frames and the control interface with its infinite-turn control knob. Everything else has been replaced; <a href="https://amzn.to/3Z48xE8">mainboard</a>, <a href="https://amzn.to/3YYPevS">extruder hot end and direct filament drive</a>, <a href="https://amzn.to/3XKIeSm">Z-axis upgrade with additional stepper motor</a>, <a href="https://amzn.to/3XHF3ur">auto bed leveling</a> and, of course, the <a href="https://github.com/ajokela/ender3pro_marlin-2.0.x">firmware</a> and the addition of printer management software, <a href="https://octoprint.org/">Octo Print</a> via a Raspberry Pi 4b. Oh, and a web camera. The incredibly cluttered photo to left is one of my two heavily upgraded Ender 3 Pro printers.</p>
<p>If you are new to the 3D printer scene, and in particular the world of upgrades and modifications to kit-printers, let's step back and have an brief overview. I won't get into the super-weedy-details because that has likely been covered ad nauseam.</p>
<p>The gist of 3D printing is, you have filament; it can be made of a whole host of materials; everything from nylon with carbon fiber embedded in it, to the more mundane, <a href="https://en.wikipedia.org/wiki/Polylactic_acid">polylactic acid</a> or more commonly called PLA. This filament is softened enough to flow by way of the <em>hot end</em> and is pushed out of a precision nozzle. This hot end is most often mounted on a series X and Z-axis rails. A heated bed is mounted on the Y-axis. All the movement is made possible by the use of <a href="https://amzn.to/3lMdmn6">stepper motors</a>. The motors, the hotend and bed temperatures are all controlled by a mainboard.<br>
<br></p>
<h3>Upgrades</h3>
<p>The <a href="https://amzn.to/3Z48xE8">upgraded mainboard</a> has a STM32 F103 RET6 microcontroller. The upgrade gives you a 32 bit processor versus the original 8 bit -- this allows for more complicated firmware installs. The board also has improved, silent stepper motor controllers. In order to fully take advantage of this motherboard and accessories like the CR Touch or BL Touch, you will need configure and recompile the <a href="https://link.tinycomputers.io/marlin-firmware-ender-3-pro">Marlin Firmware</a>. We get to that later in this post.</p>
<p>The upgrades listed above are what I eventually arrived upon. There was a <a href="https://amzn.to/3EmKZ5n">Micro Swiss Direct Drive Extruder</a>.</p>
<div style="width: 100%;">
<table style="width: 100%; border: thin dotted grey; padding: 2px;">
<tr style="text-align: center; border-bottom: thin dotted grey; margin: 2px;">
<th colspan="2" style="text-align: left; font-weight: bold; margin-left: 2px; padding-left: 10px;">
Upgrade Costs Breakdown
</th>
</tr>
<tr>
<th style="padding-left: 10px;">
Part
</th>
<th>
Cost
</th>
</tr>
<tr style="background-color: #F5F5F5; text-align: left;">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3EmKZ5n">Micro Swiss Direct Drive Extruder</a>
</td>
<td>
$99.75
</td>
</tr>
<tr style="text-align: left;">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3YYPevS">Creality Sprite Direct Drive Extruder Pro Kit</a>
</td>
<td>
$109.99
</td>
</tr>
<tr style="background-color: #F5F5F5; padding-left: 10px; text-align: left; ">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3IAY7WZ">Micro-Swiss All Metal Hotend Kit </a>
</td>
<td>
$63.50
</td>
</tr>
<tr style="text-align: left;">
<td style="text-align: left; padding-left: 10px; text-align: left; ">
<a href="https://amzn.to/3IzmKmW">Ender 3 Dual Z-axis Upgrade Kit</a>
</td>
<td>
$35.79
</td>
</tr>
<tr style="background-color: #F5F5F5; padding-left: 10px; text-align: left; ">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3SetH03">Upgrade X-axis Belt Tensioner</a>
</td>
<td>
$15.98
</td>
</tr>
<tr style="text-align: left; padding-left: 10px;">
<td style="text-align: left; padding-left: 10px; text-align: left; ">
<a href="https://amzn.to/3IzmKmW">Ender 3 Dual Z-axis Upgrade Kit</a>
</td>
<td>
$35.79
</td>
</tr>
<tr style="background-color: #F5F5F5; padding-left: 10px; text-align: left; ">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3SetH03">Spring Steel Flexible Build Surface Magnetic Removable Bed Sheet</a>
</td>
<td>
$15.98 (2x)
</td>
</tr>
<tr style="text-align: left; padding-left: 10px;">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3kbwgU0">Creality Ender 3 Pro 32-bit Silent Board Motherboard V4.2.7</a>
</td>
<td>
$42.99
</td>
</tr>
<tr style="background-color: #F5F5F5; padding-left: 10px; text-align: left; ">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3EkO31V">Raspberry Pi 4b - 2GB</a>
</td>
<td>
$45.00
</td>
</tr>
<tr style="text-align: left; padding-left: 10px;">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3Icd2pe">DC 6V 9V 12V 24V to DC 5V 5A Buck Converter Module, 9-36V Step Down to USB 5V</a>
</td>
<td>
$42.99
</td>
</tr>
<tr style="background-color: #F5F5F5; padding-left: 10px; text-align: left; ">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3IBtBw6">Logitech C920x HD Pro Webcam</a>
</td>
<td>
$69.99
</td>
</tr>
<tr style="text-align: left; padding-left: 10px;">
<td style="text-align: left; padding-left: 10px;">
<a href="https://amzn.to/3EnINL4">Creality BLTouch V3.1 Auto Bed Leveling Sensor Kit</a>
</td>
<td>
$47.99
</td>
</tr>
<tr style="background-color: #F5F5F5; text-align: right; padding-left: 10px;">
<td style="text-align: right; padding-right: 10px; font-weight: bold;">
<a href="https://amzn.to/3YH1elS">Base model Ender 3 Pro</a>
</td>
<td style="font-weight: bold; text-align: left;">
$236.00
</td>
</tr>
<tr style="padding-left: 10px; text-align: left; ">
<td style="text-align: right; padding-right: 10px; font-weight: bold;">
Total
</td>
<td style="font-weight: bold;">
$877.72
</td>
</tr>
</table>
<br>
<span style="font-weight: bold;">UPDATE 2023/02/25:</span> I purchased a <a href="https://amzn.to/3Y4RPDN">Creality Sprite Extruder Pro</a> ($109.99) This is an improvement on the <a href="https://amzn.to/3lWGOqv">Creality Sprite Extruder</a>; it allows for filament temperatures up to 300℃. I have a longer term project in mind that will require printing with material at or above 260℃.
</div>
<div style="padding-top: 50px; padding-bottom: 50px;">
<iframe width="100%" height="480" src="https://www.youtube-nocookie.com/embed/_Pdz96r1Lfo" title="Ender 3 Pro - Benchy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>
<p>As you can see, a base model Ender 3 Pro costs $236.00, but throw in an armful of higher end upgrades (for the retail market), and you suddenly have a setup that has cost nearly $900.00. Yikes! Are all of these upgrades necessary? I would have to say, <em>No</em>. The Creality Direct Drive extruder is well worth the money - never again deal with bowden tubes. The other two must upgrades are the mainboard and adding a CR Touch or BL Touch auto-leveling sensor. Runners up is the dual Z-axis; it really stabilizes the frame.</p>
<h3>Firmware</h3>
<p>In order to take advantage of a CR Touch or BL Touch, you will need to configure the firmware to use it. The probe-to-offset also needs to be changed when using the Sprite Direct Drive as the nozzle is a slight different location than the stock nozzle. I won't go into all the details of, but you can compare <a href="https://github.com/ajokela/ender3pro_marlin-2.0.x/blob/main/Marlin/Configuration_og.h">Configuration_og.h</a> (the original) and <a href="https://github.com/ajokela/ender3pro_marlin-2.0.x/blob/main/Marlin/Configuration.h">Configuration.h</a> as well as <a href="https://github.com/ajokela/ender3pro_marlin-2.0.x/blob/main/Marlin/Configuration_adv_og.h">Configuration_adv_og.h</a> and <a href="https://github.com/ajokela/ender3pro_marlin-2.0.x/blob/main/Marlin/Configuration_adv.h">Configuration_adv.h</a>. The changes range from enabling CR Touch/BL Touch and enabling a comprehensive bed leveling system, to adjusting the position of the nozzle and enabling thermal safety features.</p>
<pre><code class="command">git clone https://github.com/ajokela/ender3pro_marlin-2.0.x.git</code></pre>
<p>Open <a href="https://code.visualstudio.com/">Visual Studio Code</a>, and Open Folder. Navigate to where you cloned the repository to and open it.</p>
<p>If you are wanting configuration and compile your own firmware, checkout <a href="https://link.tinycomputers.io/marlin-platform.io">Marlin and Platform.io</a>. It will get your started. Once Platform.io is installed, you can clone the <a href="https://link.tinycomputers.io/marlin-firmware-ender-3-pro">repo</a> and open it in Visual Code.</p>
<p>Here are the things that were changed in <code>Configuration.h</code> and <code>Configuration_adv.h</code></p>
<div>
<table style="width: 100%; border: thin dotted grey; padding: 2px;">
<tr style="text-align: center; border-bottom: thin dotted grey; margin: 2px;">
<th colspan="2" style="text-align: left; font-weight: bold; margin-left: 2px; padding-left: 10px;">
<code>Configuration.h</code>
</th>
</tr>
<tr>
<td class="code"><pre>#define STRING_CONFIG_H_AUTHOR "(Alex, Ender-3 Pro)"</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Who made the changes.</td>
</tr>
<tr>
<td class="code"><pre>#define CUSTOM_MACHINE_NAME "Ender-3 Pro 4.2.7 - fw v2.0.9.3 - 2023-02-23"</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">I like to put the date and version numbers in firmware so it is easy to identify a <i>what</i> and a <i>when</i></td>
</tr>
<tr>
<td class="code"><pre>#define HEATER_0_MAXTEMP 315</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">You will want to be careful with this setting; it is the temperature of the hotend in celsius; Needed higher than default for printing nylon and PET-G. Because of <code>HOTEND_OVERSHOOT</code>, maximum temperature will always be MAXTEMP - HOTEND_OVERSHOOT<br><b>DO NOT SET AT THIS IF YOU HAVE A STOCK HOTEND<b></b></b></td>
</tr>
<tr>
<td class="code"><pre>#define HOTEND_OVERSHOOT 20
#define BED_OVERSHOOT 15
</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">(°C) Forbid temperatures over MAXTEMP - OVERSHOOT for hotend and (°C) Forbid temperatures over MAXTEMP - OVERSHOOT for bed</td>
</tr>
<tr>
<td class="code"><pre>#define S_CURVE_ACCELERATION</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Smoother curve motions</td>
</tr>
<tr>
<td class="code"><pre>//#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Comment out because we will be using a CR-Touch or BL-Touch</td>
</tr>
<tr>
<td class="code"><pre>#define USE_PROBE_FOR_Z_HOMING</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Force the use of the probe for Z-axis homing</td>
</tr>
<tr>
<td class="code"><pre>#define BLTOUCH</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Enable BL Touch/CR Touch</td>
</tr>
<tr>
<td class="code"><pre>#define NOZZLE_TO_PROBE_OFFSET { -10.0, -10.0, 0 }</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Move the offset for the Sprite Direct Drive hotend</td>
</tr>
<tr>
<td class="code"><pre>#define PROBING_MARGIN 15</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">A little more buffer around the perimeter</td>
</tr>
<tr>
<td class="code"><pre>#define MULTIPLE_PROBING 2
#define EXTRA_PROBING 1</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Add extra probings to eliminate outliers</td>
</tr>
<tr>
<td class="code"><pre>#define PREHEAT_BEFORE_PROBING
#if ENABLED(PREHEAT_BEFORE_PROBING)
#define PROBING_NOZZLE_TEMP 200 // (°C) Only applies to E0 at this time
#define PROBING_BED_TEMP 60
#endif</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Require minimum nozzle and/or bed temperature for probing; bump temperature to match pre-probing temperature</td>
</tr>
<tr>
<td class="code"><pre>#define Y_BED_SIZE 210
#define Z_MAX_POS X_BED_SIZE</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Adjust bed size; I ran into problems where the extruder would overshoot the bed.</td>
</tr>
<tr>
<td class="code"><pre>#define AUTO_BED_LEVELING_UBL</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Unified Bed Leveling. A comprehensive bed leveling system combining the features and benefits
of other systems. UBL also includes integrated Mesh Generation, Mesh
Validation and Mesh Editing systems.</td>
</tr>
<tr>
<td class="code"><pre>#define ENABLE_LEVELING_AFTER_G28</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Always enable
leveling immediately after G28.</td>
</tr>
<tr>
<td class="code"><pre>#define G26_MESH_VALIDATION</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Enable the G26 Mesh Validation Pattern tool.</td>
</tr>
<tr>
<td class="code"><pre>#define GRID_MAX_POINTS_X 6
#define UBL_HILBERT_CURVE
#define UBL_MESH_WIZARD
</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Use Hilbert distribution for less travel when probing multiple points. Run several commands in a row to get a complete mesh.</td>
</tr>
<tr>
<td class="code"><pre>#define LCD_BED_LEVELING</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Add a bed leveling sub-menu for ABL or MBL.</td>
</tr>
<tr>
<td class="code"><pre>#define Z_SAFE_HOMING</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Moves the Z probe (or nozzle) to a defined XY point before Z homing.</td>
</tr>
<tr>
<td class="code"><pre>#define PREHEAT_1_TEMP_HOTEND 200
#define PREHEAT_1_TEMP_BED 60</pre></td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">Bump up the preheat temperatures of hotend and bed</td>
</tr>
</table>
<div style="height: 3em;"></div>
<table style="width: 100%; border: thin dotted grey; padding: 2px;">
<tr style="text-align: center; border-bottom: thin dotted grey; margin: 2px;">
<th colspan="2" style="text-align: left; font-weight: bold; margin-left: 2px; padding-left: 10px;">
<code>Configuration_adv.h</code>
</th>
</tr>
<tr>
<td class="code">
<pre>#define THERMAL_PROTECTION_PERIOD 120 // Seconds
#define THERMAL_PROTECTION_HYSTERESIS 10 // Degrees Celsius</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">False positives with Thermal Runaway</td>
</tr>
<tr>
<td class="code">
<pre>#define EXTRUDER_RUNOUT_PREVENT
#if ENABLED(EXTRUDER_RUNOUT_PREVENT)
#define EXTRUDER_RUNOUT_MINTEMP 195
#define EXTRUDER_RUNOUT_SECONDS 30
#define EXTRUDER_RUNOUT_SPEED 1500 // (mm/min)
#define EXTRUDER_RUNOUT_EXTRUDE 5 // (mm)
#endif</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Extruder runout prevention. If the machine is idle and the temperature over MINTEMP then extrude some filament every couple of SECONDS.
</td>
</tr>
<tr>
<td class="code">
<pre>#define HOTEND_IDLE_TIMEOUT
#if ENABLED(HOTEND_IDLE_TIMEOUT)
#define HOTEND_IDLE_TIMEOUT_SEC (10*60) // (seconds) Time without extruder movement to trigger protection
#define HOTEND_IDLE_MIN_TRIGGER 195 // (°C) Minimum temperature to enable hotend protection
#define HOTEND_IDLE_NOZZLE_TARGET 0 // (°C) Safe temperature for the nozzle after timeout
#define HOTEND_IDLE_BED_TARGET 0 // (°C) Safe temperature for the bed after timeout
#endif</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Hotend Idle Timeout and Prevent filament in the nozzle from charring and causing a critical jam.
</td>
</tr>
<tr>
<td class="code">
<pre>#define PROBE_OFFSET_WIZARD</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Add Probe Z Offset calibration to the Z Probe Offsets menu
</td>
</tr>
<tr>
<td class="code">
<pre>#define PROBE_OFFSET_WIZARD_START_Z -4.0</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Enable to init the Probe Z-Offset when starting the Wizard. Use a height slightly above the estimated nozzle-to-probe Z offset.
</td>
</tr>
<tr>
<td class="code">
<pre>#define PROBE_OFFSET_WIZARD_XY_POS { X_CENTER, Y_CENTER }</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Set a convenient position to do the calibration (probing point and nozzle/bed-distance).
</td>
</tr>
<tr>
<td class="code">
<pre>#define LCD_SET_PROGRESS_MANUALLY</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Add an 'M73' G-code to set the current percentage
</td>
</tr>
<tr>
<td class="code">
<pre>#define USE_M73_REMAINING_TIME
#define ROTATE_PROGRESS_DISPLAY</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Use remaining time from M73 command instead of estimation; and Display (P)rogress, (E)lapsed, and (R)emaining time
</td>
</tr>
<tr>
<td class="code">
<pre>#define LCD_PROGRESS_BAR</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Show a progress bar on HD44780 LCDs for SD printing
</td>
</tr>
<tr>
<td class="code">
<pre>#define BINARY_FILE_TRANSFER</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Add an optimized binary file transfer mode, initiated with 'M28 B1'
</td>
</tr>
<tr>
<td class="code">
<pre>#define BABYSTEP_DISPLAY_TOTAL
#define BABYSTEP_ZPROBE_OFFSET
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#define BABYSTEP_ZPROBE_GFX_OVERLAY
#endif</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Display total babysteps since last G28<br>
Combine M851 Z and Babystepping<br>
Enable graphical overlay on Z-offset editor
</td>
</tr>
<tr>
<td class="code">
<pre>#define HOST_ACTION_COMMANDS
#if ENABLED(HOST_ACTION_COMMANDS)
#define HOST_PAUSE_M76
#define HOST_PROMPT_SUPPORT
#if ENABLED(HOST_PROMPT_SUPPORT)
#define HOST_STATUS_NOTIFICATIONS
#endif
#define HOST_START_MENU_ITEM
#define HOST_SHUTDOWN_MENU_ITEM
#endif</pre>
</td>
<td class="reason" style="text-align: left; padding: 5px; vertical-align: top;">
Tell the host to pause in response to M76<br>
Initiate host prompts to get user feedback<br>
Send some status messages to the host as notifications<br>
Add a menu item that tells the host to start<br>
Add a menu item that tells the host to shut down
</td>
</tr>
<table>
<div class="row">
<div class="column">
<img src="https://tinycomputers.io/images/ender_3_pro-signal-2023-02-19-151541_009.thumbnail.jpeg" loading="lazy" style="width:100%">
</div>
<div class="column">
<img src="https://tinycomputers.io/images/ender_3_pro-signal-2023-02-19-151541_004.thumbnail.jpeg" loading="lazy" style="width:100%">
</div>
<div class="column">
<img src="https://tinycomputers.io/images/ender_3_pro-signal-2023-02-19-151541_003.thumbnail.jpeg" v style="width:100%">
</div>
</div>
<p>Even with all of this add-ons and modifications, the printer remains finicky. It is constantly needing adjustments which is expected to an extent when you are dealing with moving material and high heat.</p>
<p>Does it print well? It depends. It depends upon the nozzle wear, the flexibility and moisture content of the filament, and the type of the filament. These are all variables that any 3d printer would encounter. I just don't know how big of a deal these would be to another printer. I have also two <a href="https://amzn.to/3XDwMYE">Creality CR-6 SE printers</a>, and they worked well until they did not. Maybe someday I will get a higher-end printer and be able to do more comparisons.</p>
<p><a href="https://link.tinycomputers.io/SymH">Download most recent compiled firmware (v2.0.9.3)</a></p></table></table></div>Raspberry Pi Kubernetes Clusterhttps://tinycomputers.io/posts/raspberry-pi-kubernetes-cluster.html2023-01-02T18:14:22-06:002023-01-02T18:14:22-06:00A.C. Jokela<p><img src="https://tinycomputers.io/images/rpi-cluster-nodes-IMG_0779.jpg.webp" loading="lazy"></p>
<p>So, you find your with about nineteen Raspberry Pi 4b single board computers, and you want to run <a href="https://kubernetes.io/">Kubernetes</a>?</p>
<p>Over the course of 2022, I slowly assembled the requisite number of Raspberry Pis, despite the fact that all things Raspberry Pi were in short supply. Basically, I used technology to pay attention to sites selling Pis. It was as simple as that. No automatic buying or the like; I would get a text message and then I would have to act quickly.</p>
<p>Why nineteen when there are clearly only eighteen in the above photo? There needs to be a control node (call it <code>master</code> or <code>controlplane</code>). This is the node that orchestrates the building of the cluster.</p>
<p>Now that you have all of your nodes assembled and in a very <a href="https://uplab.pro/2020/12/raspberry-pi-server-mark-iii/">nice 2U rack mount assembly</a>, it is time to provision things.</p>
<p>We will be using <a href="https://ansible.com/">Ansible</a> for provisioning and it will handle around 95% of the work. The other 5% is manual setup. The manual task is getting a public ssh key onto all of the nodes. If I had been smart, I would have added this into the imaging process with <a href="https://www.raspberrypi.com/software/">Imager</a>, but I did not. When imaging, if you are not setting initial ssh key within Imager, make sure to set the password on all nodes the same. Ideally, you would want to set the ssh key during imaging; doing so, will take out a small portion of the needed manually tasks.</p>
<h4>Pre-game Setup</h4>
<p>We will be executing from the <code>controlplane</code> or <code>master</code> node. Before we get into that, let's establish our base parameters and assumptions.</p>
<ul>
<li>All nodes, including <code>master</code> will be running Raspberry Pi OS 64bit</li>
<li>The <code>master</code> node will be named <code>rpi-cluster-master</code></li>
<li>Each worker node will be named <code>rpi-cluster-[1-18]</code>; e.g. <code>rpi-cluster-1</code> and so one</li>
<li>Each node, <code>master</code> and <code>workers</code> will have IP addresses ranging from <code>10.1.1.100</code> to <code>10.1.1.18</code></li>
<li>You are using <em>ethernet</em> and <strong>not</strong> <em>wifi</em>. </li>
<li><strong>This is important because the <a href="https://github.com/ajokela/rpi-k8s-ansible">Ansible playbooks</a> that we are going to use assume there is <code>eth0</code> and not <code>wlan0</code></strong></li>
<li><strong><em>If you are wanting to insert the ssh key during imaging, run the following command, and then copy the contents of <code>.ssh/id_rsa.pub</code> from the <code>master</code>node to the Advanced section of the setup in <code>Imager</code> where it says ""</em></strong></li>
</ul>
<p>Now, let's distribute our public ssh key. As the user <code>pi</code> on <code>rpi-cluster-master</code>, run the following:</p>
<div class="code"><pre class="code literal-block">pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>ssh-keygen
</pre></div>
<h6>If needing to transfer the public key manually, make the following script (saved as 'dist-key.sh') on <code>master</code></h6>
<div class="code"><pre class="code literal-block"><span class="ch">#!/bin/bash</span>
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.101
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.102
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.103
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.104
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.105
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.106
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.107
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.108
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.109
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.110
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.111
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.112
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.113
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.114
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.115
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.116
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.117
ssh-copy-id<span class="w"> </span><span class="m">10</span>.1.1.118
</pre></div>
<p>Execute!</p>
<div class="code"><pre class="code literal-block">pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>bash<span class="w"> </span>dist-key.sh
</pre></div>
<p>Assuming you set the default password for the <code>pi</code> user when using <code>Imager</code>, you will be prompted eighteen times to accept the connection and then the enter in your password.</p>
<h6>If you are smart and, unlike me, you put your id_rsa.pub key into <code>Imager</code>, it should look like:</h6>
<p><img alt="" src="https://tinycomputers.io/images/rpi-imager-advanced-setup.png.webp"></p>
<p>And then you will not have to dink-around with transferring your key, individually, to each node.</p>
<p>Now, let's <a href="https://www.theurbanpenguin.com/installing-ansible-on-the-raspberry-pi/">install <code>ansible</code></a>on our <code>master</code> node; we will be following <a href="https://www.theurbanpenguin.com/installing-ansible-on-the-raspberry-pi/">this</a>.</p>
<div class="code"><pre class="code literal-block">pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt<span class="w"> </span>update
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>-y<span class="w"> </span>ansible<span class="w"> </span>sshpass
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>tee<span class="w"> </span><span class="se">\</span>
-a<span class="w"> </span>/etc/apt/sources.list
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>dirmngr<span class="w"> </span>-y
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt-key<span class="w"> </span>adv<span class="w"> </span>--keyserver<span class="w"> </span>keyserver.ubuntu.com<span class="w"> </span>--recv-keys<span class="w"> </span>93C4A3FD7BB9C367
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt<span class="w"> </span>update
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>-y<span class="w"> </span>ansible
pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>ansible<span class="w"> </span>--version
ansible<span class="w"> </span><span class="m">2</span>.10.8
<span class="w"> </span>config<span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>None
<span class="w"> </span>configured<span class="w"> </span>module<span class="w"> </span>search<span class="w"> </span><span class="nv">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span><span class="s1">'/home/pi/.ansible/plugins/modules'</span>,<span class="w"> </span><span class="s1">'/usr/share/ansible/plugins/modules'</span><span class="o">]</span>
<span class="w"> </span>ansible<span class="w"> </span>python<span class="w"> </span>module<span class="w"> </span><span class="nv">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>/usr/lib/python3/dist-packages/ansible
<span class="w"> </span>executable<span class="w"> </span><span class="nv">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>/usr/bin/ansible
<span class="w"> </span>python<span class="w"> </span><span class="nv">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">3</span>.9.2<span class="w"> </span><span class="o">(</span>default,<span class="w"> </span>Feb<span class="w"> </span><span class="m">28</span><span class="w"> </span><span class="m">2021</span>,<span class="w"> </span><span class="m">17</span>:03:44<span class="o">)</span><span class="w"> </span><span class="o">[</span>GCC<span class="w"> </span><span class="m">10</span>.2.1<span class="w"> </span><span class="m">20210110</span><span class="o">]</span>
</pre></div>
<p>If you have made it to this point, you should have eighteen nodes with the <code>master</code> node's public ssh key install. You should also have <code>ansible</code> installed.</p>
<h4>Let's get Ansible'ing</h4>
<p>Now, we will be following the steps outlined in <a href="https://github.com/ajokela/rpi-k8s-ansible">this</a> git repo.</p>
<div class="code"><pre class="code literal-block">pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/ajokela/rpi-k8s-ansible.git
</pre></div>
<p>Change directory into <code>rpi-k8s-ansible</code></p>
<div class="code"><pre class="code literal-block">pi@rpi-cluster-master:~<span class="w"> </span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>rpi-k8s-ansible
</pre></div>
<p>Now, if you want to customize your list of nodes, this is the time. Edit <code>cluster.yml</code>; if you only have sixteen nodes, comment out the two you do not have; there are a couple spots where each node is mentioned.</p>
<p>On to provisioning! These steps are fairly intelligent at being atomic and repeatable without causing issues. In provisioning the cluster in the picture (above), some of the steps had to be repeated because of lost ssh connections and other mysterious errors. Let's first see if we have our basic configuration in working order. <strong>The following assumes you are in the directory <code>~/rpi-k8s-ansible</code> on your <code>master</code> node.</strong></p>
<div class="code"><pre class="code literal-block">$<span class="w"> </span>ansible<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>all<span class="w"> </span>-m<span class="w"> </span>ping
</pre></div>
<p>This will execute a simple <code>ping</code>/<code>pong</code> between your <code>master</code> node and the <code>worker</code> nodes.</p>
<div class="code"><pre class="code literal-block"><span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-1.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
<span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-2.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
<span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-3.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
<span class="err">...</span>
<span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-16.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
<span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-17.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
<span class="err">rpi</span><span class="mi">-</span><span class="err">clus</span><span class="kc">ter</span><span class="mf">-18.</span><span class="err">local</span><span class="w"> </span><span class="err">|</span><span class="w"> </span><span class="err">SUCCESS</span><span class="w"> </span><span class="err">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"changed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"ping"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pong"</span>
<span class="p">}</span>
</pre></div>
<p>If you get an error, double you have your nodes correctly named in <code>cluster.yml</code> if all looks good, try Googling the error.</p>
<h5>Update all Your Nodes' Packages</h5>
<div class="code"><pre class="code literal-block">$<span class="w"> </span>ansible-playbook<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>playbooks/upgrade.yml
</pre></div>
<p>As we start to run ansible playbooks, this is where you just might have to rerun a playbook to get beyond an error. The most common error I ran into was peer connections dropped. It is a bit of a mystery why; the aforementioned cluster is connected via a managed HP gigabit switch.</p>
<h5>Install Kubernetes</h5>
<div class="code"><pre class="code literal-block"><span class="c1"># Bootstrap the master and all slaves</span>
$<span class="w"> </span>ansible-playbook<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>site.yml
</pre></div>
<p><strong>This will reboot your cluster nodes</strong> This might cause issues and force you to repeat this step. After my initial execution of that command, I followed it up with:</p>
<div class="code"><pre class="code literal-block"><span class="c1"># When running again, feel free to ignore the common tag as this will reboot the rpi's</span>
$<span class="w"> </span>ansible-playbook<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>site.yml<span class="w"> </span>--skip-tags<span class="w"> </span>common
</pre></div>
<p>This will run everything except the <code>reboot</code> command.</p>
<p>If you want to only rerun a single node and the master node, you can do something like the following:</p>
<div class="code"><pre class="code literal-block"><span class="c1"># Bootstrap a single slave (rpi-cluster-5) and the master node</span>
$<span class="w"> </span>ansible-playbook<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>site.yml<span class="w"> </span>-l<span class="w"> </span>rpi-cluster-master.local,rpi-cluster-5.local
</pre></div>
<h5>Copy over the .kube/config and verification</h5>
<p>We need to copy over your kubernetes configuration file.</p>
<div class="code"><pre class="code literal-block"><span class="c1"># Copy in your kube config</span>
$<span class="w"> </span>ansible-playbook<span class="w"> </span>-i<span class="w"> </span>cluster.yml<span class="w"> </span>playbooks/copy-kube-config.yml
<span class="c1"># Set an alias to make it easier</span>
$<span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="nv">kubectl</span><span class="o">=</span><span class="s1">'docker run -it --rm -v ~/.kube:/.kube -v $(pwd):/pwd -w /pwd bitnami/kubectl:1.21.3'</span>
<span class="c1"># Run kubectl within docker</span>
$<span class="w"> </span>sudo<span class="w"> </span>kubectl<span class="w"> </span>version
Client<span class="w"> </span>Version:<span class="w"> </span>version.Info<span class="o">{</span>Major:<span class="s2">"1"</span>,<span class="w"> </span>Minor:<span class="s2">"21"</span>,<span class="w"> </span>GitVersion:<span class="s2">"v1.21.3"</span>,<span class="w"> </span>GitCommit:<span class="s2">"ca643a4d1f7bfe34773c74f79527be4afd95bf39"</span>,<span class="w"> </span>GitTreeState:<span class="s2">"clean"</span>,<span class="w"> </span>BuildDate:<span class="s2">"2021-07-15T21:04:39Z"</span>,<span class="w"> </span>GoVersion:<span class="s2">"go1.16.6"</span>,<span class="w"> </span>Compiler:<span class="s2">"gc"</span>,<span class="w"> </span>Platform:<span class="s2">"linux/arm64"</span><span class="o">}</span>
Server<span class="w"> </span>Version:<span class="w"> </span>version.Info<span class="o">{</span>Major:<span class="s2">"1"</span>,<span class="w"> </span>Minor:<span class="s2">"21"</span>,<span class="w"> </span>GitVersion:<span class="s2">"v1.21.14"</span>,<span class="w"> </span>GitCommit:<span class="s2">"0f77da5bd4809927e15d1658fb4aa8f13ad890a5"</span>,<span class="w"> </span>GitTreeState:<span class="s2">"clean"</span>,<span class="w"> </span>BuildDate:<span class="s2">"2022-06-15T14:11:36Z"</span>,<span class="w"> </span>GoVersion:<span class="s2">"go1.16.15"</span>,<span class="w"> </span>Compiler:<span class="s2">"gc"</span>,<span class="w"> </span>Platform:<span class="s2">"linux/arm64"</span><span class="o">}</span>
</pre></div>
<p>Let's get a little information about the cluster:</p>
<div class="code"><pre class="code literal-block">$<span class="w"> </span>sudo<span class="w"> </span>kubectl<span class="w"> </span>cluster-info
Kubernetes<span class="w"> </span>control<span class="w"> </span>plane<span class="w"> </span>is<span class="w"> </span>running<span class="w"> </span>at<span class="w"> </span>https://10.1.1.100:6443
CoreDNS<span class="w"> </span>is<span class="w"> </span>running<span class="w"> </span>at<span class="w"> </span>https://10.1.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To<span class="w"> </span>further<span class="w"> </span>debug<span class="w"> </span>and<span class="w"> </span>diagnose<span class="w"> </span>cluster<span class="w"> </span>problems,<span class="w"> </span>use<span class="w"> </span><span class="s1">'kubectl cluster-info dump'</span>.
</pre></div>
<h6>Helm</h6>
<p>If you need to <a href="https://helm.sh/docs/intro/install/">install <code>helm</code></a>; Helm is a package manager for Kubernetes: <em>Helm is the best way to find, share, and use software built for <a href="https://kubernetes.io/">Kubernetes</a></em> - follow these instructions:</p>
<div class="code"><pre class="code literal-block">$<span class="w"> </span>curl<span class="w"> </span>https://baltocdn.com/helm/signing.asc<span class="w"> </span><span class="p">|</span><span class="w"> </span>gpg<span class="w"> </span>--dearmor<span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>tee<span class="w"> </span>/usr/share/keyrings/helm.gpg<span class="w"> </span>><span class="w"> </span><span class="se">\</span>
/dev/null
$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>apt-transport-https<span class="w"> </span>--yes
$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"deb [arch=</span><span class="k">$(</span>dpkg<span class="w"> </span>--print-architecture<span class="k">)</span><span class="s2"> signed-by=/usr/share/keyrings/helm.gpg] \</span>
<span class="s2">https://baltocdn.com/helm/stable/debian/ all main"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="se">\</span>
sudo<span class="w"> </span>tee<span class="w"> </span>/etc/apt/sources.list.d/helm-stable-debian.list
$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update
$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>helm
</pre></div>
<p>If you do not have <code>gpg</code> installed, you will need to install it.</p>
<p>Here is a more in depth look at <a href="https://www.baeldung.com/ops/kubernetes-helm">helm</a> and its role within kubernetes.</p>
<p>This is going to be anticlimactic, but we will start to run our first container on our shiny new kubernetes cluster in our next posting.</p>Raspberry Pi CM4 and Pin Compatible Moduleshttps://tinycomputers.io/posts/raspberry-pi-cm4-and-pin-compatible-modules.html2022-12-22T10:30:00-06:002022-12-22T10:30:00-06:00A.C. Jokela<div style="padding-bottom: 50px; padding-top: 50px;">
<p><span style="font-weight: bold;">UPDATE: 2023/02/04:</span> <a href="https://tinycomputers.io/posts/bigtreetech-cb1-review.html">Review of BIGTREETECH CB1 - RPi CM4 Pin Compatible Module</a>
</p>
</div>
<p>Hardware, in our modern era, does not exist in a vacuum; it requires software to function and be useful. One of main benefits of living within the Raspberry Pi ecosystem is you get up-to-date software that is maintained by a large network of source code contributors. Just for the <a href="https://github.com/raspberrypi/linux/graphs/contributors">linux kernel</a> used in Raspberry Pi OS, there have been over 5,000 people contributing to the project. That's hundreds of thousands of lines of code added, removed and modified. Raspberry Pi is successful because of its ecosystem. It is so large, it is self-sustaining. The Raspberry Pi Compute Module 4 (<em>announcement of the <a href="https://www.seeedstudio.com/blog/2020/10/19/new-raspberry-pi-compute-module-4-cm4-released-from-25-and-up/">"CM4"</a></em>) was introduced about two years ago. <a href="https://datasheets.raspberrypi.com/cm4/cm4-datasheet.pdf">Official Raspberry Pi CM4 Datasheet</a>. It is a followup to the wildly successful <a href="https://rpilocator.com/?cat=PI4" target="_blank">Raspberry Pi 4b</a>. The CM4 is a different form factor from the 4b. Unlike the 4b, it requires a <a href="https://amzn.to/3WpGv4u" target="_blank">carrier or IO board</a> to be useful. The good news is it is compatible with a <a href="https://pipci.jeffgeerling.com/boards_cm">bewildering array of carrier and IO boards</a>.</p>
<h3>Raspberry Pi CM4</h3>
<div style="width: 100%; text-align: center; padding-bottom: 1em;">
<img src="https://tinycomputers.io/images/rpi-cm4-1gb-signal-2022-12-19-162656.png.webp" style="width:45%; text-align:center; float:center; padding: 2px;" loading="lazy"><br>
Raspberry Pi Compute Module 4, 1GB memory
</div>
<div></div>
<p>There are IO boards that give you the same form factor as the RPi 4b, there are also IO boards that turn your CM4 into a KVM for a server management, there are boards with two ethernet ports -- allowing for the creation of a simple router. There also boards that expose the CM4's PCIe bus. This opens up the possibilities for using peripherals like addition network adapters or SATA controllers. More on that later.</p>
<p>Since the CM4's release, there have been a few pin compatible modules developed by other firms. By <em>pin compatible</em>, I mean that these other modules can correctly be attached via <a href="https://www.digikey.com/en/maker/projects/creating-a-raspberry-pi-compute-module-4-cm4-carrier-board-in-kicad/7812da347e5e409aa28d59ea2aaea490">Hirose mating connectors</a> to the IO boards.</p>
<p>One of the primary benefits of using a genuine Raspberry Pi CM4, as I mentioned in the first paragraph, is the ecosystem. The CM4 uses the same operating system as the 4b. This allows for nearly all the same software to be usable across the RPi family of single board computers. This sheds light on one of the most commonly brought up issues with non-Raspberry Pi single board computers: the software ecosystem just is not as robust as Raspberry Pi. This is not limited to the alternatives to the CM4. There are an array of alternatives to the RPi family, like the boards made by <a href="https://www.pine64.com/">Pine64</a>, or <a href="https://libre.computer/products/aml-s905x-cc/">Libre</a>, or <a href="https://www.hardkernel.com/">Hardkernel's</a> Odroid series. These all cannot run the official Raspberry Pi OS.</p>
<p>Jeff Geerling does a fantastic job of <a href="https://www.jeffgeerling.com/blog/2020/raspberry-pi-compute-module-4-review">reviewing the RPi CM4</a>. I am not going to give a complete, indepth review; Jeff has already done that.</p>
<p>Core Features:</p>
<ul>
<li>Optional eMMC, zero to 32GB</li>
<li>Optional Wireless (WiFi and Bluetooth)</li>
<li>Variety of memory sizes, 1GB to 8GB</li>
</ul>
<p>If by some chance you stumbled onto this post and you need assistance in getting Raspberry Pi OS running on a CM4 unit, check out <a href="https://www.jeffgeerling.com/blog/2020/how-flash-raspberry-pi-os-compute-module-4-emmc-usbboot">this</a>. I'm not going to go into details here; it is <a href="https://www.jeffgeerling.com/blog/2020/how-flash-raspberry-pi-os-compute-module-4-emmc-usbboot">a solved problem</a>.</p>
<p>Many of the alternatives to Raspberry Pi OS have a very similar feel and shallow curve for learning and setting up, but they are not 100% the same. Take for example, the the multi-board Linux distribution <a href="https://www.armbian.com/">Armbian</a>. Armbian supports over 160 different single board computers. If you have a well established board, there is a good chance there's an Armbian build for it. Armbian is very similar to RPi OS; they are both derivatives of <a href="https://www.debian.org/">Debian</a>, both can use standard Ubuntu and Debian packages, both have a similar method of writing a disk image to an SD card and booting the OS. There is no guarantee, however, that all software designed for the Raspberry Pi OS will run under Armbian. Particularly when dealing with third party shields and GPIO boards as well as things that I tend to ignore like video encoding/decoding and sound.</p>
<p>The common quip as of late goes something like this: <em>because of the shortage of Raspberry Pi computers, some people have turned to alternatives.</em> This might be the case for some, but this is not going to be my justification for using or testing out the three alternatives that will be present throughout the rest of this article.</p>
<p><strong>All Raspberry Pi single board computers and modules are in tight supply for the retail and hobbists markets. Check out <a href="https://rpilocator.com/">Raspberry Pi Locator</a> for places that might have supply. If you are willing to pay a significant premium, <a href="https://ebay.us/WCHlgs">eBay has quite a few available</a>.</strong></p>
<p>With the RPi CM4 having been covered extensively - like <a href="https://www.jeffgeerling.com/blog/2020/raspberry-pi-compute-module-4-review">Jeff Geerling's Review</a>; instead, I'll be looking at the remaining three modules.
<br><br></p>
<h4>Performance Metrics</h4>
<table style="width: 100%; text-align: center; border: thin dotted grey; padding: 2px;">
<tr style="text-align: center; border-bottom: thin dotted grey; margin: 2px;">
<th colspan="3" style="text-align: left; font-weight: bold; margin-left: 2px; padding-left: 10px;">
<a href="https://www.geekbench.com/" target="_blank">Geekbench Metrics</a>
</th>
</tr>
<tr>
<th>
Module
</th>
<th>
Single CPU Metrics
</th>
<th>
Multi-CPU Metrics
</th>
</tr>
<tr style="background-color: #F5F5F5;">
<td>
<a href="https://browser.geekbench.com/v5/cpu/19380000" target="_blank">Raspberry Pi CM4</a>
</td>
<td>228</td><td>644</td>
</tr>
<tr>
<td>
<a href="https://browser.geekbench.com/v5/cpu/19379584" target="_blank">Radxa CM3</a>
</td>
<td>163</td><td>508</td>
</tr>
<tr style="background-color: #F5F5F5;">
<td>
<a href="https://browser.geekbench.com/v5/cpu/19400478" target="_blank">Pine64 SOQuartz</a>
</td>
<td>156</td><td>491</td>
</tr>
<tr style="text-align: center;">
<td>
<a href="https://browser.geekbench.com/v5/cpu/19254559" target="_blank">Banana Pi CM4</a>
</td>
<td>295</td><td>1087</td>
</tr>
</table>
<div style="height: 3em;"></div>
<table style="width: 100%; text-align: center; border: thin dotted grey; padding: 2px;">
<tr style="text-align: center; border-bottom: thin dotted grey; margin: 2px;">
<th colspan="5" style="text-align: left; font-weight: bold; margin-left: 2px; padding-left: 10px;">
Features Comparison
</th>
</tr>
<tr style="border-bottom: thin dotted grey; text-align: center;">
<th></th>
<th><a href="https://www.raspberrypi.com/documentation/computers/compute-module.html" target="_blank">Raspberry Pi CM4</a></th>
<th><a href="https://wiki.radxa.com/Rock3/CM/CM3" target="_blank">Radxa CM3</a></th>
<th><a href="https://wiki.pine64.org/wiki/SOQuartz" target="_blank">Pine64 SOQuartz</a></th>
<th><a href="https://wiki.banana-pi.org/BPI-CM4_Computer_module_and_development_Kit" target="_blank">Banana Pi CM</a></th>
</tr>
<tr style="background-color: #F5F5F5;">
<td></td>
<td><a href="https://datasheets.raspberrypi.com/cm4/cm4-product-brief.pdf" target="_blank">Specifications</a></td>
<td><a href="https://dl.radxa.com/cm3/docs/radxa-cm3-product-brief_Revision_1.3_g0ecb072.pdf" target="_blank">Specifications</a></td>
<td><a href="https://files.pine64.org/doc/quartz64/SOQuartz_SOM_schematic_v1.1_20210816.pdf" target="_blank">Specifications</a></td>
<td><a href="https://wiki.banana-pi.org/BPI-CM4_Computer_module_and_development_Kit#Features" target="_blank">Specifications</a></td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">Core</td>
<td>Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz</td>
<td>Rockchip RK3566, Quad core Cortex-A55 (ARM v8) 64-bit SoC @ 2.0GHz</td>
<td>Rockchip RK3566, Quad core Cortex-A55 (ARM v8) 64-bit SoC @ 1.8GHz and Embedded 32-bit RISC-V CPU</td>
<td>Amlogic A311D Quad core ARM Cortex-A73 and dual core ARM Cortex-A53 CPU</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">NPU</td>
<td>-</td>
<td>0.8T NPU</td>
<td>0.8 TOPS Neural Network Acceleration Engine</td>
<td>5.0 TOPS</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">GPU</td>
<td>-</td>
<td>Mali G52 GPU</td>
<td>Mali-G52 2EE Bifrost GPU</td>
<td>Arm Mali-G52 MP4 (6EE) GPU</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">Memory</td>
<td>1GB, 2GB, 4GB or 8GB LPDDR4</td>
<td>1GB, 2GB, 4GB or 8GB LPDDR4</td>
<td>2GB, 4GB, 8GB LPDDR4</td>
<td>4GB LPDDR4</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">eMMC</td>
<td>On module - 0GB to 32GB</td>
<td>On module - 0GB to 128GB</td>
<td>External - 16GB to 128GB</td>
<td>On module - 16GB to 128G)</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">Network</td>
<td>1Gbit Ethernet - Option for WiFi5 with Bluetooth 5.0</td>
<td>1Gbit Ethernet - Option for WiFi5 with Bluetooth 5.0</td>
<td>1Gbit Ethernet - WiFi 802.11 b/g/n/ac with Bluetooth 5.0</td>
<td>1Gbit Ethernet</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">PCIe</td>
<td>1-lane</td>
<td>1-lane</td>
<td>1-lane</td>
<td>1-lane</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">HDMI</td>
<td>2x HDMI</td>
<td>1x HDMI</td>
<td>1x HDMI</td>
<td>1x HDMI</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">GPIO</td>
<td>28 pin</td>
<td><a href="https://wiki.radxa.com/Rock3/CM3/IO/GPIO" target="_blank">40 pin</a></td>
<td>28 pin</td>
<td>26 pin</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">Extras</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>SATA ports, one shared with USB 3, one shared with PCIe; Audio Codec</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">Geekbench Score - Single CPU</td>
<td>228</td>
<td>163</td>
<td>156</td>
<td>295</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">Geekbench Score - Multi CPU</td>
<td>644</td>
<td>508</td>
<td>491</td>
<td>1087</td>
</tr>
<tr style="border-bottom: thin dotted grey;">
<td style="border-right: thin dotted grey;">Price of Tested*</td>
<td>$65</td>
<td>$69</td>
<td>$49</td>
<td>$105</td>
</tr>
<tr style="border-bottom: thin dotted grey; background-color: #F5F5F5;">
<td style="border-right: thin dotted grey;">Power Consumption</td>
<td>7 watts</td>
<td>N/A</td>
<td>2 watts</td>
<td>N/A</td>
</tr>
</table>
<div>
* Prices exclude shipping
</div>
<div style="height: 3em;"></div>
<h3>Pine64 SOQuartz</h3>
<div style="width: 100%; text-align: center; padding-bottom: 1em;">
<img src="https://tinycomputers.io/images/signal-2022-11-30-202052_004-SOQuartz-module.png.webp" style="width:45%; text-align:center; float:center; padding: 2px;" loading="lazy"><br>
Pine64 SOQuartz Module, 4GB memory
</div>
<p>For whatever reason, I really like <a href="https://wiki.pine64.org/wiki/SOQuartz">Pine64's SOQuartz module</a>. It is by far the least performant of the four compute modules I have tried. It has a wonky antenna and needs a far from mainstream variety of Linux to be useful. There are two Linux distributions available: <a href="https://dietpi.com/">DietPI</a> and <a href="https://github.com/Plebian-Linux/quartz64-images">Plebian Linux</a>. I settled upon using Plebian. I would have gone with DietPi but my initial use case of making a two ethernet router using a <a href="https://amzn.to/3PIkU5h">Waveshare Dual Gigabit Ethernet Base Board Designed for Raspberry Pi Compute Module 4</a>, but I was unable to get both ethernet ports working. Plebian was simpler. For those interested in trying Plebian, you can download recent disk images by going to <a href="https://github.com/Plebian-Linux/quartz64-images/actions">Plebian Linux's Github Actions</a>, and select one of the recent "Build Quartz64 Images"; at the bottom there will be zipped disk image Artifacts to download for the various flavors of Quartz64. Plebian is a bit rough around the edges. It is derived from Debian Testing (currently codenamed <em>bookworm</em>) and runs a release candidate Linux Kernel. Its developer, <a href="https://github.com/CounterPillow">CounterPillow</a>, also states that "<strong><em>This is a work-in-progress project. Things don't work yet. Please do not flash these images yet unless you are trying to help develop this pipeline.</em></strong>" The interactions with the system feel similar to that of <a href="https://www.netbsd.org/">NetBSD</a> from the early-2010s. It is not to say it is not a modern flavor of Linux, it is simply lacking some of the usual expectations. You want your network interfaces to be named <code>eth0</code>? How about no. Interfaces have not been aliased, if you can get WiFi drivers working, you will end up with a device named something like <code>wlxe84e069541e6</code> instead of <code>wlan0</code>. Given that it is running a testing branch of Debian, things like docker and the like will likely not work without some significant wrangling. </p>
<p>Why do I like this compute module? I like Pine64's products. I like the community that has grown up around the products. In the course of trying to get an operating system up and running, I had numerous questions that I asked on <a href="https://discord.gg/pine64">Pine64's Discord Server</a>. Everyone was extremely helpful and despite my own feelings that some of my questions were simplistic, no one expressed that sentiment. There were no massive egos to speak of.</p>
<p>Core Features:</p>
<ul>
<li>Variety of memory options: 2gb to 8gb</li>
<li>external eMMC module support: 8gb to 128gb</li>
<li>Wifi</li>
</ul>
<p>Getting Plebian running on a SOQuartz module is straightforward; write the appropriate image to an eMMC module, attach the eMMC onto the SOQuartz and place it into a carrier or IO board. You should get working HDMI, one ethernet port, along with USB working. A quick run down of the steps are as follows:</p>
<ol>
<li>
<p>Get a USB to eMMC adapter; Pine64 has <a href="https://pine64.com/product/usb-adapter-for-emmc-module/">one available</a>; you could also try <a href="https://www.ebay.com/itm/284891437420?hash=item4254da596c:g:kY0AAOSwllNiyutf&amdata=enc%3AAQAHAAAA4HwIWh9DOlbgf8Pj6hjQy1odilvD6hb%2FcoV2KHnlBbof6or4iiyXiycys5fN2xKETBm8nKX2KuMRzW5CigAY4jZuzsSE7aAsgJYIrQhX2BIxA4YXkSIApnWqLJy1TrKrL%2F0PBa%2BcWe3Y3l3VR1XFMtifa0q8QE3BTHxTDLwSNlHPe%2Fep49NfMEHEUXc9Hzy7ki8D%2BGtvAVyKT%2BI%2BrlkWRN7GUrseWkw27jHgAF2OudN32Nk8Yx7l1lRwixmPrBRK89zwfieZ3AaOjXY79MitKHi8CyfsL5RwpBi%2BNiiRRtTC%7Ctkp%3ABFBMht3M26Vh">eBay</a>; you may need to get a micro SD to USB adapter, too.</p>
</li>
<li>
<p>Get an eMMC module. Pine64 has <a href="https://pine64.com/product/16gb-emmc-module/">a few available</a></p>
</li>
<li>
<p>Obvious step: connect your eMMC to your USB to eMMC adapter and then connect that to your desktop/laptop/etc.</p>
</li>
<li>
<p>Download a SOQuartz Plebian Linux disk image from <a href="https://github.com/Plebian-Linux/quartz64-images/actions">Plebian Linux's Github Actions</a></p>
</li>
<li>
<p>Download<code>SOQuartz CM4 IO Board Image</code></p>
</li>
<li>Unzip the contents</li>
<li>
<p>You will end up with a file called <code>plebian-debian-bookworm-soquartz-cm4.img.xz</code>;</p>
</li>
<li>
<p>Write to your eMMC module. You could use something <a href="https://www.balena.io/etcher/">balena Etcher</a> or, if you're command-line-comfortable, use <code>dd</code></p>
</li>
<li>
<p>balena Etcher will take care of decompressing <code>plebian-debian-bookworm-soquartz-cm4.img.xz</code></p>
</li>
<li>
<p>using <code>dd</code>, you can do something like this:</p>
<p><code>bash
sudo xzcat plebian-debian-bookworm-soquartz-cm4.img.xz | sudo dd of=/dev/mmcblk1 status=progress</code></p>
<p>where <code>/dev/mmcblk1</code> is the correct device for your USB to eMMC adapter.</p>
<p><img alt="" src="https://tinycomputers.io/images/2022-12-19%2022-28-59.png.webp"></p>
</li>
<li>
<p>Attach your eMMC module to your SOQuartz module and attach the module to an IO or carrier board.</p>
</li>
<li>
<p>Attach peripherals and apply power. You'll eventually get presented with a prompt to set the password for the user <code>pleb</code></p>
</li>
</ol>
<p>If would be more cost effective if you were to buy a SOQuartz module, an USB to eMMC adapter and an eMMC module all at once; for orders being shipped to the United States, it is roughly a $9 flat rate.</p>
<p>Finally, if you really feel like going for an alternative to Linux, <a href="https://www.netbsd.org/">NetBSD</a> will also work on the SOQuartz, but it is more complicated. You will need to download a <a href="https://nycdn.netbsd.org/pub/arm/#HEAD">Generic 64bit</a> image from under the NetBSD-daily HEAD tab. This will need to be written to an eMMC module. Next, you will need to write the appropriate <a href="https://github.com/jaredmcneill/quartz64_uefi/releases">UEFI image</a> to an SD card from Jared McNeill's port of <a href="https://github.com/tianocore/edk2-platforms">Tianocore</a> to the Quartz64 family. UEFI and the disk image cannot exist on the same media. </p>
<p><strong>Pine64 sells <a href="https://pine64.com/product/soquartz-4gb-compute-module-w/">SOQuartz modules</a> directly from their site. The modules I have purchased and used are the 4gb models. They are about $50 excluding shipping.</strong></p>
<h3>Radxa CM3</h3>
<div style="width: 100%; text-align: center; padding-bottom: 1em;">
<img src="https://tinycomputers.io/images/RADXA-CM3-IMG_0733.png.webp" style="width:45%; text-align:center; float:center; padding: 2px;" loading="lazy"><br>
Radxa CM3, 4GB memory, without heatsinks
</div>
<p>As far as performance goes, the <a href="https://shop.allnetchina.cn/products/rock3-computing-module?variant=39486827069542">Radxa CM3</a> is just above Pine64's SOQuartz module but below Raspberry Pi CM4. Radxa is better known for its <a href="https://wiki.radxa.com/Rock3">Rock3</a> and <a href="https://wiki.radxa.com/Rock5">Rock5</a> series of single board computers; available from <a href="https://shop.allnetchina.cn/collections/rock5-model-b">ALLNET.China</a> and <a href="https://ebay.us/CQIZjw">eBay</a>. The CM3 is in the Rock3 series of boards and modules. The series features Rockchip RK3566/RK3568 processors, the RK3566 also is used in Pine64's Quartz64 and SOQuartz boards. Even though the module will function without issue on a carrier or IO board designed for Raspberry Pi CM4, the <a href="https://shop.allnetchina.cn/products/radxa-cm3-io-board?_pos=1&_sid=77ee539b1&_ss=r&variant=39531550867558">CM3 IO board</a> by Radxa exposes two SATA ports in addition to the PCIe 1x lane. The CM3 has an <a href="https://wiki.radxa.com/Rock3/Debian"><em>official</em> Debian</a> and <a href="https://wiki.radxa.com/Rock3/Ubuntu">Ubuntu</a> distributions, but like all the other compute modules, these are artisanally crafted specifically for the CM3. That means, you can not take an actual-official Debian or Ubuntu disk image for <a href="https://wiki.debian.org/Arm64Port">Arm64</a> and have it just have it work. Radxa does, however, maintain an up-to-date Github build pipeline for producing both <a href="https://github.com/radxa/debos-radxa/releases">Debian and Ubuntu images</a> for the CM3. Like the operating system's need to be different, so is the eMMC - it is not flashed in a typical manner - like what you would expect from a Raspberry Pi CM4 or even the Pine64 SOQuartz. In order to install Linux on the onboard eMMC, you need to use tools provided by Rockchip. The <a href="https://wiki.radxa.com/Rock3/installusb-install-radxa-cm3-io#Step_2:_Download_RK356X_Loader">Radxa Wiki page for CM3</a> is a good place to start. The CM3 and its installation process are about as far from Raspberry Pi CM4 territory as you will deal with for the modules presented in this article. The following instructions are available from <a href="https://wiki.radxa.om/">wiki.radxa.com</a> but they are found across a disparate set of pages; some describing the rockchip tools with references to disk images but with no clear and convenient place to download the files. This is an attempt to streamline the process. Let's get at it!</p>
<p>Core Features:</p>
<ul>
<li>On-module eMMC of 16 to 128GB</li>
<li>Two SATA (when using the appropriate IO board)</li>
</ul>
<p>The Rockchip tools are available on Windows as well as macOS/Linux. Downloading, compiling and running the macOS/Linux tool is straightforward; Windows involves a set of drivers and an executable tool.</p>
<h5>Linux/macOS</h5>
<ul>
<li>Install necessary USB and <code>autoconf</code> packages</li>
</ul>
<p><code>sudo apt-get install libudev-dev libusb-1.0-0-dev dh-autoreconf pkg-config libusb-1.0</code></p>
<ul>
<li>Clone the <a href="https://github.com/rockchip-linux/rkdeveloptool">github</a> repository</li>
</ul>
<div class="code"><pre class="code literal-block"><span class="n">git</span><span class="w"> </span><span class="n">clone</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">rockchip</span><span class="o">-</span><span class="n">linux</span><span class="o">/</span><span class="n">rkdeveloptool</span>
<span class="n">cd</span><span class="w"> </span><span class="n">rkdeveloptool</span>
<span class="n">autoreconf</span><span class="w"> </span><span class="o">-</span><span class="n">i</span>
<span class="o">./</span><span class="n">configure</span>
<span class="n">make</span>
<span class="n">sudo</span><span class="w"> </span><span class="n">make</span><span class="w"> </span><span class="n">install</span>
</pre></div>
<ul>
<li>Run <code>rkdeveloptool --help</code>to verify it is installed</li>
</ul>
<h5>Windows</h5>
<ol>
<li>Download <a href="https://dl.radxa.com/tools/windows/RKDevTool_Release_v2.86.zip">RKDevTool</a></li>
<li>Download <a href="https://dl.radxa.com/tools/windows/DriverAssitant_v5.0.zip">RKDriverAssistant</a></li>
<li>Unzip and execute RKDriverAssistant (<code>DriverInstall.exe</code>)</li>
<li>Unzip RKDevTool</li>
<li>Before executing the tool, you will want to change the language to English; change <code>Chinese.ini</code> to <code>Englist.ini</code></li>
</ol>
<p><img alt="" src="https://tinycomputers.io/images/rkdevtools-set-english-config.ini.png.webp"></p>
<p>There is an assumption of using a <a href="https://amzn.to/3PIyaqA">Raspberry Pi CM4 IO Board</a>.</p>
<h5>Boot into maskrom mode</h5>
<ol>
<li>Unplug the board and remove any SD card</li>
<li>Plug a micro USB to USB Type-A cable into the micro USB port on the IO board. The other end of the cable gets plugged into your desktop or laptop. My laptop only has USB-C, so I had to use an <a href="https://amzn.to/3v6EJK6">adapter</a></li>
<li>On the CM3, there is a very tiny golden button; while pressing this, plug the power back in on the IO board</li>
<li>After a few seconds, you can stop pressing the button</li>
<li>Check for a USB device</li>
<li>Linux/macOS should show <code>Bus 001 Device 112: ID 2207:350a Fuzhou Rockchip Electronics Company</code></li>
<li>Windows, you will need to run <code>RKDevTool</code>; the status at the bottom of the application should read <code>maskrom mode</code></li>
</ol>
<div style="width: 100%; text-align: center; padding-bottom: 1em;">
<img src="https://tinycomputers.io/images/radxa-cm3.png.webp" style="width:45%; text-align:center; float:center; padding: 2px;" loading="lazy"><br>
maskrom button
</div>
<h5>Flashing/Writing a Disk Image</h5>
<p>You will need to download two files:</p>
<ol>
<li><a href="https://dl.radxa.com/rock3/images/loader/rk356x_spl_loader_ddr1056_v1.06.110.bin">rk356x_spl_loader_ddr1056_v1.06.110.bin</a></li>
<li>A Radax CM3 disk image from <a href="https://wiki.radxa.com/Rock3/downloads">https://wiki.radxa.com/Rock3/downloads</a> or <a href="https://github.com/radxa-build/radxa-cm3-io/releases/latest">https://github.com/radxa-build/radxa-cm3-io/releases/latest</a> or this <a href="https://ajokela.github.io/aws-s3-bucket-browser/index.html?bucket=https://s3.us-east-1.amazonaws.com/cdn.tinycomputers.io/index.html#radxa-rock3/">mirror</a></li>
</ol>
<p>We will be using <a href="https://github.com/radxa-build/radxa-cm3-io/releases/download/20221101-0118/radxa-cm3-io-ubuntu-focal-server-arm64-20221101-0254-gpt.img.xz">radxa-cm3-io-ubuntu-focal-server-arm64-20221101-0254-gpt.img.xz</a>; it is advisable to follow <a href="https://github.com/radxa-build/radxa-cm3-io/releases/latest">this</a> and download a more recent disk image.</p>
<h5>Linux Flashing</h5>
<div class="code"><pre class="code literal-block"><span class="n">rkdeveloptool</span><span class="w"> </span><span class="n">ld</span>
</pre></div>
<p><code>DevNo=1 Vid=0x2207,Pid=0x350a,LocationID=104 Maskrom</code></p>
<div class="code"><pre class="code literal-block"><span class="n">rkdeveloptool</span><span class="w"> </span><span class="n">db</span><span class="w"> </span><span class="n">rk356x_spl_loader_ddr1056_v1</span><span class="o">.</span><span class="mf">06.110</span><span class="o">.</span><span class="n">bin</span>
<span class="n">rkdeveloptool</span><span class="w"> </span><span class="n">wl</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">radxa</span><span class="o">-</span><span class="n">cm3</span><span class="o">-</span><span class="n">io</span><span class="o">-</span><span class="n">ubuntu</span><span class="o">-</span><span class="n">focal</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">arm64</span><span class="o">-</span><span class="mi">20221101</span><span class="o">-</span><span class="mi">0254</span><span class="o">-</span><span class="n">gpt</span><span class="o">.</span><span class="n">img</span><span class="o">.</span><span class="n">xz</span>
</pre></div>
<p>Reboot CM3</p>
<div class="code"><pre class="code literal-block"><span class="n">rkdeveloptool</span><span class="w"> </span><span class="n">rd</span>
</pre></div>
<h5>Windows Flashing</h5>
<p><img alt="" src="https://tinycomputers.io/images/RKDevTool-complete-english.png.webp"></p>
<p>You will need to specify a <code>loader</code> as well as an <code>image</code>. In the table on the left side of the screenshot, click in right-most the rectangle of the first row. This should bring up a file dialog box. Navigate to where you downloaded <code>rk356x_spl_loader_ddr1056_v1.06.110.bin</code>. Likewise for the second row (<code>image</code>), navigate to where you downloaded <code>radxa-cm3-io-ubuntu-focal-server-arm64-20221101-0254-gpt.img.xz</code></p>
<p>Click <code>Run</code></p>
<p>This operation will take several minutes; be patient.</p>
<p>The CM3 should automatically boot and bring you to a login prompt. <strong>The default user is <code>rock</code> with a password of <code>rock</code></strong></p>
<iframe width="100%" height="480" src="https://www.youtube-nocookie.com/embed/49zG4EZiJKo" title="Radxa CM3 Linux Booting" frameborder="0" loading="lazy" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<p><strong>The Radxa CM3 can be purchased from <a href="https://shop.allnetchina.cn/products/rock3-computing-module?variant=39486827069542">ALLNET.China</a> for about $70 excluding shipping.</strong></p>
<h3>Banana Pi CM4</h3>
<div style="width: 100%; text-align: center; padding-bottom: 1em;">
<img src="https://tinycomputers.io/images/BPi-CM4-IMG_0754.png" style="width:45%; text-align:center; float:center; padding: 2px;" loading="lazy"><br>
Banana Pi CM4, 4GB memory
</div>
<p>Looking at the Geekbench table (above), you will notice at the Banana Pi CM4 seriously outperforms the other three modules I have tested. It is also the most expensive module - including shipping - it was about $120. This was not an inflated Raspberry Pi price, this is directly from <a href="http://www.sinovoip.com.cn/eindex.asp">Sinovoip</a>, the company behind the Banana Pi family of single board computers. But, before you start searching for where you can buy one, as of the time of this writing, I purchased Sinovoip's last module that they had allocated to developers and testers; and they have not started to commercially produce any, yet.</p>
<p><img src="https://tinycomputers.io/images/sinovoip-banana-pi-correspondence.png.webp" style="zoom:45%;" loading="lazy"></p>
<p>Core Features:</p>
<ul>
<li>4 x ARM Cortex-A73 CPU cores</li>
<li>
<p>2 x ARM Cortex-A53 CPU cores</p>
</li>
<li>
<p>4GB of memory</p>
</li>
</ul>
<p>Like the Radxa CM3, operating system software is very limited. For very detail instructions on install an operating system, in this case Android, check out <a href="https://wiki.banana-pi.org/Getting_Started_with_CM4">https://wiki.banana-pi.org/Getting_Started_with_CM4</a>.</p>
<p>Installing and boot Linux is fairly straight forward. You can either boot from an SD card, or you can choose to boot from the on-board eMMC module. That said, nonetheless, you will need an SD card.</p>
<p>Head over to <a href="https://wiki.banana-pi.org/Banana_Pi_BPI-M2S#Linux">https://wiki.banana-pi.org/Banana_Pi_BPI-M2S#Linux</a>, and you find a similar table of distributions images:</p>
<h5>Distributions</h5>
<h6>Ubuntu</h6>
<ul>
<li>2022-06-20-ubuntu-20.04-mate-desktop-bpi-m2s-aarch64-sd-emmc.img.zip
Baidu Cloud: https://pan.baidu.com/s/1kRukI-H-xliNqIqVacXWRw?pwd=8888 (pincode:8888)
Google drive: https://drive.google.com/file/d/1P2YQUwdrREdiwidr8YtCvOdMmwLPerVu/view</li>
</ul>
<p>S3 Mirror: https://s3.us-east-1.amazonaws.com/cdn.tinycomputers.io/banana-pi-m2s-cm4-linux/2022-06-20-ubuntu-20.04-mate-desktop-bpi-m2s-aarch64-sd-emmc.img.zip
MD5:2945f225eadba1b350cd49f47817c0cd</p>
<ul>
<li>2022-06-20-ubuntu-20.04-server-bpi-m2s-aarch64-sd-emmc.img.zip
Baidu Cloud:https://pan.baidu.com/s/1UoYR0k9YH9SE_A-MpqZ2fg?pwd=8888 (pincode: 8888)
Google Drive:https://drive.google.com/file/d/1y0DUVDhLyhw_C7p6SD2q1EjOZLEV_c_w/view
S3 Mirror: https://s3.us-east-1.amazonaws.com/cdn.tinycomputers.io/banana-pi-m2s-cm4-linux/2022-06-20-ubuntu-20.04-server-bpi-m2s-aarch64-sd-emmc.img.zip
MD5:9b17a00cbc17c46e414a906e659e7ca2</li>
</ul>
<h6>Debian</h6>
<ul>
<li>2022-06-20-debian-10-buster-bpi-m2s-aarch64-sd-emmc.img.zip
Baidu Cloud: https://pan.baidu.com/s/1TTsdyy5I7HLWS_Tptg7r2w?pwd=8888 (pincode: 8888)
Google Drive:https://drive.google.com/file/d/116ZydpggYpZ1WoSyVsc4QuchdIa3vGyI/view</li>
</ul>
<p>S3 Mirror: https://s3.us-east-1.amazonaws.com/cdn.tinycomputers.io/banana-pi-m2s-cm4-linux/2022-06-20-debian-10-buster-bpi-m2s-aarch64-sd-emmc.img.zip
MD5:9d39558ad37e5da47d7d144c8afec45e</p>
<h5>Flashing/Writing Images</h5>
<p>Let's assume we are using <code>2022-06-20-debian-10-buster-bpi-m2s-aarch64-sd-emmc.img.zip</code>; the handiest thing to start out with is making a bootable sd card. On your laptop or desktop computer, and assuming you are using a flavor Linux, issue the following at a command line:</p>
<div class="code"><pre class="code literal-block"><span class="nv">unzip</span><span class="w"> </span><span class="mi">2022</span><span class="o">-</span><span class="mi">06</span><span class="o">-</span><span class="mi">20</span><span class="o">-</span><span class="nv">debian</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="nv">buster</span><span class="o">-</span><span class="nv">bpi</span><span class="o">-</span><span class="nv">m2s</span><span class="o">-</span><span class="nv">aarch64</span><span class="o">-</span><span class="nv">sd</span><span class="o">-</span><span class="nv">emmc</span>.<span class="nv">img</span>.<span class="nv">zip</span>
<span class="nv">dd</span><span class="w"> </span><span class="k">if</span><span class="o">=</span><span class="mi">2022</span><span class="o">-</span><span class="mi">06</span><span class="o">-</span><span class="mi">20</span><span class="o">-</span><span class="nv">debian</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="nv">buster</span><span class="o">-</span><span class="nv">bpi</span><span class="o">-</span><span class="nv">m2s</span><span class="o">-</span><span class="nv">aarch64</span><span class="o">-</span><span class="nv">sd</span><span class="o">-</span><span class="nv">emmc</span>.<span class="nv">img</span><span class="w"> </span><span class="nv">of</span><span class="o">=/</span><span class="nv">dev</span><span class="o">/</span><span class="nv">sda0</span>
</pre></div>
<p>Change <code>sda0</code> to the appropriate device.</p>
<p>Instead the sd card into the IO board, and apply power to the board. That's it for booting from an SD card. In order to boot from eMMC, you will need to follow the above steps, but instead of downloading and writing the image from your laptop or desktop, you will be using the BPI CM4 instead. Download and unzip the image file:</p>
<div class="code"><pre class="code literal-block"><span class="nv">unzip</span><span class="w"> </span><span class="mi">2022</span><span class="o">-</span><span class="mi">06</span><span class="o">-</span><span class="mi">20</span><span class="o">-</span><span class="nv">debian</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="nv">buster</span><span class="o">-</span><span class="nv">bpi</span><span class="o">-</span><span class="nv">m2s</span><span class="o">-</span><span class="nv">aarch64</span><span class="o">-</span><span class="nv">sd</span><span class="o">-</span><span class="nv">emmc</span>.<span class="nv">img</span>.<span class="nv">zip</span>
<span class="nv">dd</span><span class="w"> </span><span class="k">if</span><span class="o">=</span><span class="mi">2022</span><span class="o">-</span><span class="mi">06</span><span class="o">-</span><span class="mi">20</span><span class="o">-</span><span class="nv">debian</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="nv">buster</span><span class="o">-</span><span class="nv">bpi</span><span class="o">-</span><span class="nv">m2s</span><span class="o">-</span><span class="nv">aarch64</span><span class="o">-</span><span class="nv">sd</span><span class="o">-</span><span class="nv">emmc</span>.<span class="nv">img</span><span class="w"> </span><span class="nv">of</span><span class="o">=/</span><span class="nv">dev</span><span class="o">/</span><span class="nv">mmcblk0</span>
</pre></div>
<p>Now, power down the IO board, and remove the SD card. Apply power once more, and you should be booting up from eMMC.</p>
<p>As a side note, when I first booted my CM4, it began an unattended system update and that took a while to complete. It will be best if you let it finish this before doing any serious usage. Just use <code>top</code> to check on the running processes.</p>
<h5>Other bits of information:</h5>
<ul>
<li>
<p><a href="https://forum.banana-pi.org/t/banana-pi-bpi-cm4-computer-module-with-amlogic-a311d/13390">Forum posting and associated threads</a> for discussion of BPI CM4 and its release.</p>
</li>
<li>
<p><a href="https://github.com/BPI-SINOVOIP/BPI-M2S-bsp">Linux Board Support Package (BSP)</a></p>
</li>
</ul>
<p><strong>As of this writing, the Banana Pi CM4 is currently unavailable for general purchase.</strong></p>
<h4>Final Thoughts</h4>
<p>If you are needing to operate in a familiar environment, you will want to go with the Raspberry Pi CM4. As of this writing, you will pay a premium - a 100% markup or more. You can get high priced CM4s from <a href="https://ebay.us/XCG14x">eBay</a> or <a href="https://amzn.to/3jlXZk3">Amazon</a>. If you need performance, and are not needing to use crazy shields and hats, you will want to go with the Banana Pi CM4, but the catch is, it has not been released yet. It is hands down the most robust compute module. If you are looking to use bleed-edge Linux and want a bit of a challenge, the Pine64 SOQuartz module is for you. And that leaves the Radxa CM3. If you willing to use the Rockchip tools to flash the eMMC module, and you are not concerned with software compatibility for shields and hats and you want similar performance to an RPi CM4, the Radxa might be a good choice.</p>
<script type="text/javascript">
amzn_assoc_placement = "adunit0";
amzn_assoc_tracking_id = "tinycompute05-20";
amzn_assoc_ad_mode = "search";
amzn_assoc_ad_type = "smart";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_title = "Affiliate Links";
amzn_assoc_default_search_phrase = "raspberry pi compute module";
amzn_assoc_default_category = "All";
amzn_assoc_linkid = "5fc86499de521ab9aacd2a8118914cfd";
amzn_assoc_rows = "4";
amzn_assoc_design = "text_links";
</script>
<script src="//z-na.amazon-adsystem.com/widgets/onejs?MarketPlace=US"></script>