Just Screw It

Sometimes something that ought to be simple might lead you to the wild goose chase. This time, I was searching for humble 2.5" SSD screws.

And yes, this was the first time in my life I had to search for them. Back in Croatia I have a bin full of leftover PC screws. It would have been easy to just grab them.

However, I moved to the US years ago and I never bothered to bring assorted screws with me. Not that I missed them - pretty much all cases accepting 2.5" drives came with screws. It wasn’t until I made a 3D printed cage for 2.5" drives that I figured I have none laying around.

So, simple enough, I needed between 10 screws to fully screw 2 disks in and attach them to the chassis. I mean, I could have gotten away with using just 3. But, since I was buying screws anyhow, I might as well fill all the holes.

It was easy to find that the screw is a flat top M3 with fine threads (0.5mm). But for length I saw multiple values. Everything from 2 to 5 millimeters.

So I went on to measure the screws I had in my computers, only to find three different dimensions: 3, 3.5, and 4 mm. And that was based on the total of 4 sets of screws (1/1/2 distribution, for curious). I discounted M3x3.5 almost immediately since it was hard to find it at a reasonable price. That left me with M3x3mm and M3x4mm as seemingly equaiy good candidates.

But then I struck the gold - WDs specification. There, in black and white, it’s clearly stated that a 2.5" inch drive will accommodate up to 3mm screw length for side mounting holes and up to 2.5mm for the holes on the bottom. Minimum thread requirements were 1.5mm for the side hole and 1mm for the bottom hole. If I wanted an universall screw for any set of holes, I had to aim for something that has thread length between 1.5 and 2.5 mm.

If we account for sheet metal holding the drive, that means M3x3mm is a clear universal winner. At least in theory.

But how come 2 of my screw sets were 4mm? Wouldn’t that present a problem? Well, all 2.5" drives I had (2 spinning rust, 4 SATA SSD) accepted the full 4mm for the side holes without any issue. All SSD drives with bottom holes were happy to accept the same. And, based on my (limited) sample, using M3x4mm will work just fine - even on WD’s own drives.

In the end I ordered the M3x3mm. Just in case.


PS: For 3.5" drives, check this WD’s mounting specification.

Framework HDMI Missing Sound Output

After watching stuttering 1080p@60 video once too many, I decided to retire my old NUC5i3RYH and switch it with Gen 11 Framework board I had lying around. It was supposed to be a quick swap. Just take SSD from old computer, move it to the new one, place new one into a Cooler Master case, and connect back all the cables. What could go wrong?

Well, everything. First, there was an issue with mounting. NUC uses “sorta” VESA 100mm, Framework uses VESA 100mm, while TV uses VESA 200mm. Thus I assumed I could use NUC’s mounting. Albeit, 200-to-100mm adapter used for NUC was just a fraction too thick for placing Framework screws. So I spent an hour with a dremel making slots slightly thinner. Funny how shaving metal looks awfully like shaving yak.

Well, at least after mounting my case onto TV, there would be no issues. Full of hope, I turned on the computer and … nothing. Gen 11 motherboards have an issue where they would literally destroy their CMOS battery. And then it would refuse to start until battery charges enough. Some time back I fixed that using a soldering mod to use laptop battery instead. However, guess what my newly mounted laptop didn’t have? Yep, Cooler Master case contains no battery. So, coaxing board to power on took another 30 minutes and future order for ML1220 battery.

With system powered on, there was an additional issue lurking. My NUC used mini-HDMI output while Framework provides HDMI via its expansion card. So, that required a trip to the garage and going over all the cables. I am ashamed to say there was not a single 4K@60Hz cable to be found. So, I took the best looking one and tried it out. It actually worked with just a bit of “shimmering”. Downgrading my settings to 4K@30 solved that issue.

And now finally I was able to relax and watch some Starcraft. Notice the use of word “watch” since I definitely noticed there was no sound. After all that, my “new” computer wouldn’t give me a peep. I mean, output was there. And all was connected. But TV didn’t understand that.

And on this I spent ages. First I tried different HDMI expansion cards - since I did a soldering mod on mine, I thought that might be an issue. Then I tried connecting things using analog audio - it took a while to find analog 3.5mm cable and it took much longer banging my head into the wall when I noticed that TV as no analog input. Then I tried bluetooth on my soundbar - that one kinda worked until you switch input on TV when HDMI ARC would take over and bluetooth would turn off. I was half-tempted to leave it like this.

But, in the moment of desperation I though of connecting via bluetooth to my TV and then using existing ARC connection to my soundbar. Unfortunately, it was then when I found out my TV only has bluetooth output and no bluetooth input. Fortunately, search for non-existent bluetooth input settings led me to audio “Expert Settings”. There I saw “HDMI Input Audio Format” setting. With NUC my TV has happy to work in “Bitstream” mode. However, switching this to “PCM” actually made my Framework work properly.

Now, why my TV had Bitstream set? I have no idea. Why NUC was happy to output compressed audio on HDMI while Framework wasn’t? I have no idea. Will I remember this next time I change computer? Definitely not.

After a long day, I did get to watch some Starcraft. So, I guess this can be considered a success.

Making Xiao into a Trmnl

Illustration

A while ago I got myself a Trmnl device. However, I didn’t really want to use it for its Trmnl capabilities (which are admittedly great). What I wanted is to use Trmnl firmware with my server. And support for Trmnl firmware was the reason I got myself XIAO 7.5" ePaper Panel. I mean, it even comes with Trmnl firmware flashing instructions.

So, with Xiao display in my hand I tried following the instructions only to mostly fail. Why I say “mostly”? Well, display didn’t work and it still had picture that came from factory. But, since I was using my own server, I could easily see that it actually did communicate to my server. It did everything I expected it to, except showing the image.

The next step was, of course, contacting support. After following their steps, display did update using Arduino examples. But I didn’t want those - I wanted Trmnl firmware. So, I decided to dig into a Trmnl firmware itself. And one of the first thing I saw was that ESP32-C3 support was just added in 1.5.6. So much for the device supporting Trmnl firmware out of box. :)

Looking into source, it was easy to see that it contained defines for BOARD_TRMNL and BOARD_SEEED_XIAO_ESP32C3. The following was GPIO config for BOARD_TRMNL:

#define EPD_SCK_PIN  7
#define EPD_MOSI_PIN 8
#define EPD_CS_PIN   6
#define EPD_RST_PIN  10
#define EPD_DC_PIN   5
#define EPD_BUSY_PIN 4

And BOARD_SEEED_XIAO_ESP32C3 had these:

#define EPD_SCK_PIN  8
#define EPD_MOSI_PIN 10
#define EPD_CS_PIN   3
#define EPD_RST_PIN  2
#define EPD_DC_PIN   5
#define EPD_BUSY_PIN 4

Yep, e-paper control constants were completely different fitting what I saw happening. Firmware was running due to the same microcontroller. But Trmnl firmware literally couldn’t communicate with my display.

Fix was easy. I simply ignored instructions provided as method 1. Since I didn’t want to use old firmware, I also ignored method 2. This nicely led me to method 3. Building directly from source.

I already had PlatformIO installed from before so I only needed to figure out how to flash the firmware. What worked for me was holding “Boot” button and pressing “Reset”. Then wait for 2-3 seconds and press “Reset” twice in row. Sometimes it would be ok to double-click “Reset” only - but not every time. In PlatformIO one can now select seeed_xiao_esp32c3 as a device and upload working firmware.

With the properly firmware uploaded, my device finally worked. Curiously, the only thing missing was reading battery voltage. Worst case scenario, this will need a bit of hardware modification to work. But that is story for another time.

Epson V600 under Bazzite

Illustration

After I upgraded my family PC from Windows 11 to Bazzite, I found nothing lacking. At least for a few week. It took me a while but I finally noticed that my Epson V600 scanner, connected to that PC was no longer working.

Well, onto Epson site I went and, lo and behold, they had Linux drivers. While Bazzite is an atomic distribution and not supported by drivers directly, you can still install RPMs using rpm-ostree. So, with drivers unpacked, I tried just that:

sudo rpm-ostree install data/iscan-data-1.39.1-2.noarch.rpm
sudo rpm-ostree install core/iscan-2.30.4-2.x86_64.rpm
sudo rpm-ostree install plugins/iscan-plugin-gt-x820-2.2.1-1.x86_64.rpm

While the first two packages installed just fine, the third package was attempting to change stuff installed by the first two. And, due to atomic nature of Bazzite, it ran into a mkdir: cannot create directory ‘/var/lib/iscan’: Read-only file system error. And no, it doesn’t matter if you install all three RPMs together or all at once - the last one always fails.

Well, if we cannot get packages installed on Bazzite, how about we give it a separate system? Enter, Distrobox. Without going into too many details, it’s essentially container for your Linux distribution. To create it, just enter and you will be asked which distribution you want to create. I went with Fedora.

toolbox enter

After it pulls all packages, you have essentially running Fedora system inside your Bazzite. And, since Fedora is supported by Epson drivers, you can simply use the provided ./install.sh script to install it. If you run it manually, software can now start.

iscan

Since everybody in the family needed this application, I really wanted application in the start menu. However, Distrobox for some reason doesn’t provide this functionality. So, you need to do a bit of manual magic.

cp /usr/share/applications/iscan.desktop ~/.local/share/applications/
sed -i 's|^Exec=.*|Exec=distrobox enter -- iscan|' ~/.local/share/applications/iscan.desktop

Illustration

With that, you can finally find Image Scan! for Linux in your start menu.

After all this effort to have it running, I expected something like Epson’s Windows application. Only to be faced with barely functional application. Definitelly not satisfactory.

But, before I went onto creating Widnows dual boot, I decided to check if Flatpak has something to offer. And, wouldn’t you know it, somebody already packed Epson Scan 2. While still not really equivalent to the Windows counterpart, this one was actually good enough for my use case. And it could be installed without trickery.

Lesson learned for a millionth time.

Percentage Based on LiIon Voltage

As part of my LocalPaper project, I wanted to have a battery indicator. However, Trmnl device I use reports only voltage, leaving conversion to percent reading to the software. So, how to convert it?

After charging the Trmnl device, I saw that fully charged its voltage goes to 4.1V. If I check docs, I can see that voltage cutoff for their battery is at 2.75V. So, one could be tempeted to set those as limits. But, there are two issues with that approach.

First, you should not wait until cutoff point as this means you are close to (potentially) damaging the battery. You should probably report 0% before you allow battery’s safety to kick in. Also, I have only 1 device and thus 4.1V measured here might not be what other devices would show.

Fortunately, for more data, we can turn to flashlight crowd. While not conclusive, we can see that 4.1V maximum is probably spot-on. For minium, we could just go with 2.75V safety cut-off, but I would actually recommend 3.1V. Why? Well, it’s higher than safety cut-off and it actually makes math really easy. So, my suggested formula for turning voltage in percentages would be:

Percent = (Vmeasured - 3.1) * 100;

And yes, this could go under 0% or over 100% so we might want to adjust it a bit:

Percent = (int)Math.Min(Math.Max(Math.Ceiling( (Vmeasured - 3.1) * 100 ), 0), 100);

Is this precise? Not really. But thanks to LiIon rather linear voltage curve, it’s actually precise enough. We lie at the top range because we don’t want users to overcharge the battery and/or end with fully charged battery showing 99%. We lie at the bottom range because we don’t want to drain battery fully before user goes to recharge. But overall, we do use most of energy stored in the battery. And, we’re not stopping user from going down to the cut-off point. We’re just not going to encourage it.

But what if you have somee other priorities and you want to select other points? Well, formula above would probably not work since it depends on 1V range. We need something slighlty more general.

Vmin = 3.1;
Vmax = 4.1;
Percentage = (int)Math.Min(Math.Max(Math.Ceiling( 100.0 * (Vmeasured - Vmin) / (Vmax - Vmin) ), 0), 100);

Not precise, but probably good enough for any purpose you might need it for.