I2C Framework Expansion Card

Boards for this project were sponsored by PCBWay (affiliate link).


Illustration

Some time ago I created an UART expansion card for Framework laptop. While card served me well, but MCP2221 around which the whole circuit was created has more to give - I2C. But for that, a bit of rethinking was needed.

The first order of business was a connector. UART realistically requires only 3 wires and thus connector was reasonably small. But, if one wants to express both UART and I2C, at least 5 wires are needed. Still manaegable but not sufficient for what I had in mind.

As I wanted this card to help me test and troubleshoot standalone I2C devices, I also needed to source power. Well, easy enough to expose my internal regulator output on another pin. And that gives us total of 6 pins.

However, if you count pins on my finialized device you will see a 7-pin connector. In order to minimize risk and keep UART connections straight in the middle I decided to add an empty pin with a nice side effect of isolating power pin from other thus making accidental connection less likely.

Illustration

Since I already had UART PCB as a template, creating a new one was easy enough so in no time I uploaded it to PCBWay for manufacturing. 15 minutes later I got a message that something is wrong.

Failure was due to “non-plated slots size should be greater than 0.8mm” and it included a nice picture showing the issue. In a moment I figured an issue - my wide connector was using enough space to leave only slivers of PCB material remaining. Since I was always looking at it on the screen, I never got the feeling how thin PCB that was. However, my reviewer (Elena) did.

After looking into a few different solutions, I decided to maintain PCB’s shape and just cut the bottom off. If you look into PCB carefully, you will see just a sliver of the slot remaining. While it might look like an accident, it actually helps with positioning around the stub in case.

Illustration

Courtesy of fast shipping, PCBs were in my hand in less than two weeks. First thing I noticed was subpar silk screen printing. Yes, I pushed things a bit using such a small lettering but PCBWay usually does better job. It seems that truetype font I used is simply not compatible with their silkscreening process. I know for a fact that vector fonts normally used by PCB tools work flawlessly as I use PCBWay for a lot of non-sponsored content. But truetype font seems to be their cryptonite.

Boards themselves are what you would expect from HASL finish. As you can see on the picture, surface is not as leveled as you would get with ENIG but I found no issues positioning narrow-pitch type-C connector and soldering it in place.

While PCB outline is not really complicated, it’s not trivial either. I had other manufacturers mess board outline routing by using mill end that’s a bit too big. But PCBWay always routed it perfectly (and not just for sponsored boards). I pretty much consider them a first choice when it comes to framework expansion cards.

In any case, a short soldering session later and I had my device ready for testing. UART portion works as you would expect it. System sees it as a serial port and with correct baud rate world is your oyster.

I2C side requires download of a I2C/SMBus Terminal utility. Utility is easy enough that anyone familiar with I2C will quickly get the hang of it. Also you can look in other downloads if you want to create something custom.

Just keep in mind that I2C is not relly designed to be used via USB and inherent latency makes any high-speed communication impossible. Yes, your device might work at 400 kHz, but you still need to wait after every transfer for reply to come back. Inneficient at best.

Regardless, for testing, this is a decent addition for my Framework laptop toolbox.


PS: I got information on the silk screen from PCBWay and issue stems from how truetype font got rendered into gerber on my side. The end result is bunch of small lines that are way too short. In order to make each of those lines visible, they get expanded a bit and thus the result ends up looking too thick and blury. Now, some houses won’t have issue with this as they might drop the lines instead of widening them up but that will probably cause issue with some other truetype font rendering. There is big enough “impedance mismatch” between how fonts and how gerbers work that I would recommend staying clear away from them completely as result will differ both from font to font and fab to fab. Every PCB tool has a vector font that’s properly setup for usage in gerber and you should stick with that one. Lesson learned. :)

PPS: Source files are available on GitHub.

Manually Installing Ubuntu 22.04 on Surface Go (with Hibernation)

Just a few months ago I had a post about installing Ubuntu 22.04 on Surface Go. And that guide is still valid. However, while using my Surface Go during vacation, I noticed I miss hibernation. Yes, deep sleep is nice enough but hibernation is much sweeter deal when you expect your device to wake up after a longer time period.

Do note I am a huge fan of encryption and thus this guide will have both data and swap encrypted thus complicating setup a bit.

As always, all starts with a creation of Ubuntu installation media and booting into it. If done from Windows, you can use the original instructions for both. If you already have Linux installed, you can check how to do it from grub. Either way, I’ll asume you have it all booted and that you selected “Try Ubuntu” when offered.

From there we need to get into Terminal and become a root user.

sudo -i

The very next step should be setting up a few variables - host, user name, and disk. This way we can use them going forward and avoid accidental mistakes.

DISK=/dev/mmcblk0
HOST=smeagol
USER=josip

Disk setup is a bit more wasteful than what you would get following the original guide. While EFI and boot partitions are the same size, the swap partition has been increased to match RAM size (4 GB in my case). While you don’t necessarily need it that big, it will help with hibernation if you do. And yes, I’m cheating a bit since the final swap size will be a bit under as encryption headers will take a bit of space. If you really need all MMC space you can get, system will work (most of the time) fine with 2 GB too.

blkdiscard -f $DISK
sgdisk --zap-all                     $DISK
sgdisk -n1:1M:+63M -t1:EF00 -c1:EFI  $DISK
sgdisk -n2:0:+640M -t2:8300 -c2:Boot $DISK
sgdisk -n3:0:+4G   -t3:8200 -c3:Swap $DISK
sgdisk -n4:0:0     -t4:8309 -c4:Root $DISK
sgdisk --print                       $DISK

While one could encrypt boot partition too, I usually don’t do it as it prevents double prompt (grub has to unlock boot partition separately of others) and that is too annoying for my taste. I do encrypt both data and swap of course. Make sure they use the same password if you don’t want to always enter password twice.

cryptsetup luksFormat -q --type luks2 \
    --cipher aes-xts-plain64 --key-size 256 \
    --pbkdf argon2i ${DISK}p4

cryptsetup luksFormat -q --type luks2 \
    --cipher aes-xts-plain64 --key-size 256 \
    --pbkdf argon2i ${DISK}p3

Once encryption is done, we need to load the devices. For the main partition I like to use hostname as it’s displayed in the prompt.

cryptsetup luksOpen ${DISK}p4 ${HOST}

cryptsetup luksOpen ${DISK}p3 swap

Now we can format (and mount) all partitions.

yes | mkfs.ext4 /dev/mapper/${HOST}
mkdir /mnt/install
mount /dev/mapper/${HOST} /mnt/install/

mkswap /dev/mapper/swap

yes | mkfs.ext4 ${DISK}p2
mkdir /mnt/install/boot
mount ${DISK}p2 /mnt/install/boot/

mkfs.msdos -F 32 -n EFI -i 4d65646f ${DISK}p1
mkdir /mnt/install/boot/efi
mount ${DISK}p1 /mnt/install/boot/efi

To start the fun we need the debootstrap package. Do make sure you have Wireless network connected at this time as otherwise operation will not succeed.

apt update ; apt install --yes debootstrap

And then we can get basic OS on the disk. This will take a while.

debootstrap $(basename `ls -d /cdrom/dists/*/ | grep -v stable | head -1`) /mnt/install/

Our newly copied system is lacking a few files and we should make sure they exist before proceeding.

echo $HOST > /mnt/install/etc/hostname
sed "s/ubuntu/$HOST/" /etc/hosts > /mnt/install/etc/hosts
sed '/cdrom/d' /etc/apt/sources.list > /mnt/install/etc/apt/sources.list
cp /etc/netplan/*.yaml /mnt/install/etc/netplan/

If you are installing via WiFi, you might as well copy your wireless credentials

mkdir -p /mnt/install/etc/NetworkManager/system-connections/
cp /etc/NetworkManager/system-connections/* /mnt/install/etc/NetworkManager/system-connections/

Finally we’re ready to “chroot” into our new system.

mount --rbind /dev  /mnt/install/dev
mount --rbind /proc /mnt/install/proc
mount --rbind /sys  /mnt/install/sys
chroot /mnt/install \
    /usr/bin/env DISK=$DISK HOST=$HOST USER=$USER \
    bash --login

For the new system we need to setup the locale and the time zone.

locale-gen --purge "en_US.UTF-8"
update-locale LANG=en_US.UTF-8 LANGUAGE=en_US
dpkg-reconfigure --frontend noninteractive locales

dpkg-reconfigure tzdata

Now we’re ready to onboard the latest Linux image. And yes, there is a Surface Go specific kernel, but it seems that 5.17 you get with OEM kernels is as good.

apt update
apt install --yes --no-install-recommends linux-oem-22.04

Then we install boot environment packages.

apt install --yes initramfs-tools cryptsetup keyutils grub-efi-amd64-signed shim-signed

Since we’re dealing with encrypted data, we should auto mount it via crypttab. If there are multiple encrypted drives or partitions, keyscript really comes in handy to open them all with the same password…

echo "${HOST} UUID=$(blkid -s UUID -o value ${DISK}p4)  none \
    luks,discard,initramfs,keyscript=decrypt_keyctl" >> /etc/crypttab
echo "swap UUID=$(blkid -s UUID -o value ${DISK}p3) none \
    swap,luks,discard,initramfs,keyscript=decrypt_keyctl" >> /etc/crypttab
cat /etc/crypttab

To mount partitions, we need to do some fstab setup too:

echo "UUID=$(blkid -s UUID -o value /dev/mapper/${HOST}) \
    / ext4 noatime,nofail,x-systemd.device-timeout=5s 0 1" >> /etc/fstab
echo "PARTUUID=$(blkid -s PARTUUID -o value ${DISK}p2) \
    /boot ext4 noatime,nofail,x-systemd.device-timeout=5s 0 1" >> /etc/fstab
echo "PARTUUID=$(blkid -s PARTUUID -o value ${DISK}p1) \
    /boot/efi vfat noatime,nofail,x-systemd.device-timeout=5s 0 1" >> /etc/fstab
echo "UUID=$(blkid -s UUID -o value /dev/mapper/swap) \
    none swap defaults 0 0" >> /etc/fstab
cat /etc/fstab

While defaults are actually matching most of the needed values, I like to explicilty list them and manually configure the time after which sleep will be followed by automatic hybernation (10 minutes in my case).

sed -i 's/.*AllowSuspend=.*/AllowSuspend=yes/' \
    /etc/systemd/sleep.conf
sed -i 's/.*AllowHibernation=.*/AllowHibernation=yes/' \
    /etc/systemd/sleep.conf
sed -i 's/.*AllowSuspendThenHibernate=.*/AllowSuspendThenHibernate=yes/' \
    /etc/systemd/sleep.conf
sed -i 's/.*HibernateDelaySec=.*/HibernateDelaySec=10min/' \
    /etc/systemd/sleep.conf

Lid switch can be then easily setup to use suspend-then-hibernate.

sed -i 's/.*HandleLidSwitch=.*/HandleLidSwitch=suspend-then-hibernate/'
    /etc/systemd/logind.conf
sed -i 's/.*HandleLidSwitchExternalPower=.*/HandleLidSwitchExternalPower=suspend-then-hibernate/'
    /etc/systemd/logind.conf

I also like to adjust swappiness to make system a bit more lively.

echo "vm.swappiness=10" >> /etc/sysctl.conf

With all that out of way, we can finally update our boot environment.

KERNEL=`ls /usr/lib/modules/ | cut -d/ -f1 | sed 's/linux-image-//'`
update-initramfs -u -k $KERNEL

Grub update is the last part we need to make system bootable. And no, the second initramfs update is not optional as it needs to pickup RESUME variable.

sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT.*/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash \
    RESUME=UUID=$(blkid -s UUID -o value /dev/mapper/swap)\"/" \
    /etc/default/grub
update-grub
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu \
    --recheck --no-floppy
update-initramfs -u -k all

Finally we install out GUI environment. I personally like ubuntu-desktop-minimal but you can opt for ubuntu-desktop.

apt install --yes ubuntu-desktop-minimal

Since this will not install any browser, you can add Firefox package too (apt install firefox) but I like to download Chrome.

cd /tmp
wget --inet4-only https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

Having power button do a hibernate action requires a bit more effort. And while you can use suspend-then-hibernate here too, I personally prefer to have it linked to straight hibernate.

gsettings set org.gnome.settings-daemon.plugins.power power-button-action nothing
echo 'event=button/power' > /etc/acpi/events/power
echo 'action=sudo systemctl hibernate' >> /etc/acpi/events/power

Short package upgrade will not hurt.

add-apt-repository universe
apt update ; apt dist-upgrade --yes

The only remaining task before restart is to create the user, assign a few extra groups to it, and make sure its home has correct owner.

adduser --disabled-password --gecos '' -u 1002 $USER
usermod -a -G adm,cdrom,dialout,dip,lpadmin,plugdev,sudo,tty $USER
echo "$USER ALL=NOPASSWD:ALL" > /etc/sudoers.d/$USER
passwd $USER

As install is ready, we can exit our chroot environment.

exit

And now we can unmount our disk, followed by a reboot.

umount /mnt/install/boot/efi
umount /mnt/install/boot
mount | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {}

reboot

If everything went fine, we can now hibernate.

systemctl hibernate

If you see hibernate not supported message, turn off the secure boot. At this time hibernation is not supported when secure boot is turned on.

Desire for a Story Arc

Being on vacation in not always healthy. Take me for example, I decided to binge watch both seasons of Star Trek Picard.

I didn’t come into this from nothing. I did watch a few episodes from the first season before giving up. I was not really sure why but I simply stopped at one point. But idle hands and all that made me finally watch it all. And yes, I still find that Star Trek Picard is a bad series and a sad chapter for Jean Luc Picard.

There are many things wrong with it. And I don’t think a desire to get as many old familiar faces into the show, whether it fits a previously established narrative or not (e.g., Guinan and Dr. Soong being the leading example) is the main fault. It definitely doesn’t help but I think I could live with it.

I belive the main driver for my dislake of the show is mostly connected to show’s desire to have a story arc spanning a season. This makes writers focus on highly unrealistic scenarios just to keep excitement up. And yes, I do understand irony that complaining about unrealistic things in SciFi show might raise. God knows my favorite TNG had many those moments. But they were easier to swallow as they were fleeting and not pushed into viewer’s face.

Here things went from bad to worse in the season two. While one could half-heartedly claim that future is just how it is, decision to have a second season in the year 2024 only served to expose problem more. It’s just freaking two years into the future and you cannot just introduce “database of their entire life history” as a convinient plot point or have borg queen eat lead-acid battery to get Lithum (to name just two of many nonsenses).

I know, it might just be my age catching up to me and I simply don’t understand why Picard is much better than anything else in the Star Trek universe. Be it as it may, I will continue my vacation with TNG decontamination. Good knows I need my Captain.

Encrypting SD Card Using BitLocker

As I wanted to use SD card to move files from my laptop to Surface Go, it made sense to encryt the data. Easy, just right-click on the drive and turn on BitLocker, I thought. However, my SD card didn’t give me such option. For some reason Microsoft decided to not show this option in context menu.

However, one can still encrypt it using command line. Syntax it a bit annyoying but workable. In my example, I had my SD card mounted as drive S:.

manage-bde.exe -on S: -password -s

To check how the process goes, you can use -status parameter.

manage-bde.exe -status

To make things even better, once encrypted, these disks are usable on Ubuntu 22.04 too. You might just want to install exFAT support.

sudo add-apt-repository universe
sudo apt update
sudo apt install exfat-fuse exfatprogs

Post-Quantum Cryptography - The Last Round

See also round 1 and round 2.


Well, after a long time, NIST announced the first four quantum-resistant cryptographic algorithms.

Both of my StarTrek inspired favorites are actually in. CRYSTALS-Kyber is the one selected for a key exchange purposes and I fully expect to see it in some future OpenSSH version. Since dealing with ED25519 would require a quantum computer much bigger than currently available, eliptic curves are still probably the best default choice. However, you don’t want to wait the last moment to switch. Considering there are still some system that only support RSA (yes Mikrotik, I’m talking about you), switch will take a while.

CRYSTALS-Dilithium, a part of the same family, got selected as one of three suggested digital signature algorithms. From practicality side, it will rarely, if ever, be used alone as its signature output is literaly larger than a KB. That said, there are a few suggested modes (e.g., Dilithium3-AES) keeping the reasonable key size AES provides while retaining quantum assurances of a lattice algorthm.

FALCON was also selected despite difficulty of a correct implementation and a huge potential for side-channel attacks. I guess a small memory footprint and impressive performance in embedded applications were enough to ensure its place among finalists.

Lastly, a SPHINCS+ came out of blue (at least for me) to take its place as the last of the finalists. Since it is slower and larger than either of the other two finalists, it’s hardly a first choice. Regardless, using a different math approach compared to other two finalists was valuable enough to get it in.

NewHope, one of the round two finalists and already used by Chrome ended up like the recent Star Wars sequels. An early succes but ultimately not good enough to pursue.