I forgot when I saw an article about it, but it was pretty recent, as Kaisen 2.0 was released 14 December. I meant to get it and see what was different, but kept forgetting.
Anyway, I tried to read through the changelog, but it ended up becoming a chore, and I decided to try to search for whisker for the hell of it, expecting no mention. But I was very wrong once I typed s into the search. Had I tried to hold out a little longer, I would've read the line that says Whisker is now the default menu, but no, because ADHD. I doubt my previous post into the void was the cause, but I'm sure someone(s) somewhere either said something on the forums, gitlab, whatever. I was so excited that I had to post about it.
I don't remember if there was a system recovery version of Kaisen, but there is now, which is a lot more of what I want, since my use case is more towards that than having something that I could install and daily drive (Manjaro's still working just fine for me).
A personal blog on my thoughts and feelings of the things I do with hardware and software components of computers, as well as some other miscellany.
17 December 2021
21 September 2021
Ventoy, Kaisen Linux, Clear Linux
I found Kaisen Linux a while ago, but didn't really get around to testing it until early August (I had to download the newer version).
I couldn't remember what USB multi-boot utility I was using after
Back to Kaisen, it's a distro with sysadmin tools, which what originally got me interested in it because I wanted something that was more current and free than Parted Magic (last I remember, Parted Magic made you pay for current versions, but had previous versions for free), and also something less annoying than GParted Live (GParted asks for the keyboard layout during bootup). While Kaisen doesn't boot as fast as Parted Magic or GParted from what I remember, it's something I like more, even though the XFCE menu is the stock one and not the superior Whisker menu. The ISO includes English and French as an option, like Parted Magic does, but the keyboard is QWERTY instead of AZERTY when booting into English (another annoyance with Parted Magic). The menu is categorised appropriately, I think, but for someone like me that's used to the Whisker menu, it was annoying to find
With the power of Ventoy, I wanted to rebuild a set of Linux distros as I previously had on the drive (installing Ventoy wipes the drive), so I poked around to see what else to get besides some obvious choices like Manjaro, openSUSE, and Fedora. I came upon Clear Linux, which is it's own distribution (not forked from anything), and decided to give it a shot since it claims to be optimised for performance. I don't think I've ever booted any faster into a live distro than Clear. I tried to test on Triela, but Clear requires certain CPU instruction sets to run, none of which Triela has (SSSE3 (three Ss, not two), SSE4.1, SSE4.2, CLMUL). Because Melty has those instruction sets (pretty much AMD FX CPUs and newer), I could've tried Clear on Melty, but I didn't really feel like bothering with it. Not really much else to say, since I didn't really do much besides poke a bit at it.
I did try Debian, but I think I had problems or something, but well, I really prefer something that has newer packages like openSUSE Leap. I get that Debian's supposed to be rock solid, but honestly, Manjaro's been pretty solid on Pod for only having installed once. I also tried GhostBSD, but I don't remember if it worked; if it did, I wasn't in it for too long (I was really just after if I could boot into it or not with Triela and Bazett). Oh, one interesting thing when booting into openSUSE Tumbleweed on Bazett was that during the boot, it showed the HP logo.
The logo section was blank when I booted openSUSE Leap on Triela, but it's possible she's too old for that sort of special treatment (or it could just be only on HP laptops, I dunno, I'd need a larger sample size).
I couldn't remember what USB multi-boot utility I was using after
multiboot
, but I couldn't seem to find it? Or it may just have been multiboot
, but regardless, I couldn't find any hint of what it was. I came upon Ventoy, which is kinda multiboot
's successor. Anyway, you install it to the USB drive and then drop the ISOs (or IMGs) directly onto the USB drive. I didn't really read the doc that well since I only read it for installation of Ventoy on the USB drive and then closed the tab, so I didn't realise I just had to plop the ISOs to the drive. It's a lot easier/faster/nicer than multiboot
since it's drag and drop after the initial installation (multiboot
has an install/uninstall ISO process that unpacks/cleans them in a certain way, which takes longer than just dropping/deleting an ISO file). IMGs only really work on UEFI systems btw, I learned this with Memtest86 V4 and Triela.Back to Kaisen, it's a distro with sysadmin tools, which what originally got me interested in it because I wanted something that was more current and free than Parted Magic (last I remember, Parted Magic made you pay for current versions, but had previous versions for free), and also something less annoying than GParted Live (GParted asks for the keyboard layout during bootup). While Kaisen doesn't boot as fast as Parted Magic or GParted from what I remember, it's something I like more, even though the XFCE menu is the stock one and not the superior Whisker menu. The ISO includes English and French as an option, like Parted Magic does, but the keyboard is QWERTY instead of AZERTY when booting into English (another annoyance with Parted Magic). The menu is categorised appropriately, I think, but for someone like me that's used to the Whisker menu, it was annoying to find
gparted
. While I did find it, it's sadly quicker to just Alt+F2 and type for it. I don't think the Whisker menu is customisable like the stock XFCE one, but Whisker does include a search function that makes it easier to find stuff. It'd be nice if the Kaisen team can use Whisker instead or alongside the stock one, but I doubt it'll happen. But with this, definitely not bothering with Parted Magic or GParted Live ever again.With the power of Ventoy, I wanted to rebuild a set of Linux distros as I previously had on the drive (installing Ventoy wipes the drive), so I poked around to see what else to get besides some obvious choices like Manjaro, openSUSE, and Fedora. I came upon Clear Linux, which is it's own distribution (not forked from anything), and decided to give it a shot since it claims to be optimised for performance. I don't think I've ever booted any faster into a live distro than Clear. I tried to test on Triela, but Clear requires certain CPU instruction sets to run, none of which Triela has (SSSE3 (three Ss, not two), SSE4.1, SSE4.2, CLMUL). Because Melty has those instruction sets (pretty much AMD FX CPUs and newer), I could've tried Clear on Melty, but I didn't really feel like bothering with it. Not really much else to say, since I didn't really do much besides poke a bit at it.
I did try Debian, but I think I had problems or something, but well, I really prefer something that has newer packages like openSUSE Leap. I get that Debian's supposed to be rock solid, but honestly, Manjaro's been pretty solid on Pod for only having installed once. I also tried GhostBSD, but I don't remember if it worked; if it did, I wasn't in it for too long (I was really just after if I could boot into it or not with Triela and Bazett). Oh, one interesting thing when booting into openSUSE Tumbleweed on Bazett was that during the boot, it showed the HP logo.

Not the best shot, but I was trying to avoid reflections of myself and the overhead light.
∞ Tumbleweed is right below the shadow of my phone and above the bright spot of the overhead light.
∞ Tumbleweed is right below the shadow of my phone and above the bright spot of the overhead light.
The logo section was blank when I booted openSUSE Leap on Triela, but it's possible she's too old for that sort of special treatment (or it could just be only on HP laptops, I dunno, I'd need a larger sample size).
09 September 2021
Minor-ish Site Update
Decided to make text in the HTML code tag easier to read by increasing the font size a smidge and adding a grey background because it was getting annoying for me to try to read when proofreading posts. A late change, but at least a welcome one. (Also I forgot how I usually do these and couldn't easily find a previous one, so it's like this this time. Yay 2.2.0!)
8-Bit Character LCD/Character LCD Clock Update
In the Character LCD Clock post I mentioned wanting to test out 8-bit communication and having to write my own library for it, and I recently remembered about it to stick it in my projects folder.
I ended up grabbing the datasheet for the 20×4 display that I have and Adafruit's
In the write function, it normally sets the "top" four bits to be written on the pins set to
I used
And because of this, I decided to make the Character LCD Clock have an 8-bit connection just to use up some more pins and not let my library modding go to waste (well, it's not that hard of a mod, but still...).
I ended up grabbing the datasheet for the 20×4 display that I have and Adafruit's
character_lcd.py
source code for references, but when I really started looking at both of them (and playing with some things in a Python shell), I found I didn't need to write my own library and could just modify Adafruit's code. As for what I modified, I changed _LCD_4BITMODE = const(0x00)
to _LCD_4BITMODE = const(0x10)
to set it to 8-bit mode from 4-bit. Yes the variable name didn't get changed, but it means that there is minimal change to the code. The other thing I changed was the __init__(
arguments for the additional data pins, the class variables that are made from those arguments, the write function (specifics soon), and the __init__(
arguments for Character_LCD_Mono
and Character_LCD_RGB
.In the write function, it normally sets the "top" four bits to be written on the pins set to
self.dl4
through self.dl7
, sends a three-part pulse (self._pulse_enable()
function), then sets the "bottom" four bits on the same four pins before another pulse. For 8-bit, all eight pins need to be set, and I just brought up the lines for the "bottom" four bits above the lines for the "top" four bits and then changed the class variables to match the ones I added before. The pulse only needs to be sent once after the eight pins are set.Character_LCD_Mono
and Character_LCD_RGB
have the __init__(
arguments change since they pass the pins over to the parent class (the 20×4 display I have does have a backlight).I used
mpy-cross
to turn it into a smaller .mpy
file and tried it out. I ended up making it the wrong version because I never recompiled mpy-cross
after setting the CircuitPython version to compile when I was compiling CircuitPython. Anyway, after that, the 8-bit library worked just fine, and I thought it seems faster, but I think it's just a placebo. The reason is that the pulse function has three 1-microsecond pauses and the only other limiting factor is the 1-millisecond pause in the write function before it sets all the pins; therefore with 4-bit, 1006 microseconds is spent to write one character, and 1003 microseconds for 8-bit. It's very negligible, and I can understand why Adafruit never bothered with making an 8-bit library or why 4-bit is so much more common, it's because the benefit for eating up four more pins is not worthwhile in any meaningful way. However, 8-bit makes sense when it's a small project that doesn't use all that many pins, which means it's just to connect the pins to something rather than nothing.And because of this, I decided to make the Character LCD Clock have an 8-bit connection just to use up some more pins and not let my library modding go to waste (well, it's not that hard of a mod, but still...).
12 July 2021
User-Made Python Modules
In the Qt5 post, I mentioned that I should break my 4000+ line programme down into modules, and near the start of this month, I decided to try it out with a different programme that is much smaller and simpler. Because the large programme has about 38 classes, I was going to want a separate folder called
Anyway, I did end up finding what I wanted, but I wish it had more graphics instead of a bunch of text and examples to follow along with. I found from there that it was just
Changing the large programme was fairly easy, because I just had to replace
I'll now go over some of the things that might be useful for anyone looking for the information. First, let's start with a file tree that will be used as reference.
Things to know:
I think that's everything, since I have nothing else in my notes.
lib
within the folder that the main script is in, but I was needing to know how to import from it. I searched around for a while, but wasn't finding anything useful, and though I found something, the answer says:Note that injecting directories intoI think the reasoning behind avoiding adding paths tosys.path
is not the usual way to set up Python to search for modules. Usually it is preferable to add/home/jake/Documents
to your PYTHONPATH environment variable.
sys.path
is because it might not work across different computers (not "portable"). CircuitPython MCUs with modules on SD cards require /sd/
to be added to sys.path
because there is no other option (that I know of).Anyway, I did end up finding what I wanted, but I wish it had more graphics instead of a bunch of text and examples to follow along with. I found from there that it was just
import folder.module
, so I went to try it out with the simpler programme and it worked with no other changes besides the import. I went to copying portions of the large programme to make a much smaller testbed, and started off with the common functions, which was aptly named common.py
. There were some changes I did need to make, one of which was to move the global variable regex
into its own class and function to return the regular expression used for input validation. Another was to move the setting clipboard text function from the main window to its own class and function, another was to write/get the required precision to a file because there wouldn't be an easy way to be able to get it from the combo box of the main window, and the last major one was to move the message box function from the main window. I tested a couple simple classes and made adjustments as necessary when Python gave me errors, and eventually played around with stuff in common.py
a bit. I found out that I could just have a function for regex, setting clipboard text, and messagebox, so I made the according changes and it worked just fine.Changing the large programme was fairly easy, because I just had to replace
regex
with regex()
and window.to_clip(
to to_clip(
before I even started modulisation of any of the 37 calculation classes, and the modulisation just required me to import the usual PyQt5 classes, common.py
, changing the working directory when necessary (for reference images), and importing the module in the main script. I also made some quality-of-life improvements to the main script as well (now that it's a few hundred lines instead of a few thousand), and also took the time to insert a "clear/reset calculator" function to each of the modules instead of relying on old code that doesn't always work or causes the programme to crash. Anyway, it's much more manageable, and there's not a whole lot else to really say.I'll now go over some of the things that might be useful for anyone looking for the information. First, let's start with a file tree that will be used as reference.
Example filetree:
- project/
- main.py
- modules/
- module1.py
- module2.py
- sub_modules/
- sub_module1.py
- sub_module2.py
Things to know:
- The
modules/
folder must be in the same place asmain.py
(withinproject/
in this case). - The structure used for import is
modules.module1
formodules/module1.py
, andmodules.sub_modules.sub_module1.py
formodules/sub_modules/sub_module1.py
. - If
main.py
importsmodule2.py
, which needs to importmodule1.py
, thenmodule2.py
would still usemodules.module1
for importing becausemain.py
serves as the basis for the location. - Modules can contain (class-less) functions and classes.
- Use
from modules.module1 import *
instead ofimport modules.module1
if you'd like to use function or class names as-is (function()
instead ofmodules.module1.function()
). (Probably obvious if you've used Python enough.)
I think that's everything, since I have nothing else in my notes.
09 July 2021
Parts Inventory, and Digi-Key and Mouser Data Matrix Barcodes
The first step was to get a barcode scanner that also reads 2D barcodes and is reasonably-priced, and SparkFun's 2D Barcode Scanner Breakout was the answer. When I found it, I thought their stock of 42 would be okay, but when I looked at it the next day, they were all gone! I think I sat for a few days before I found that SparkFun does have a "wait for backorder items before shipping" option, so I went ahead and put in an order, since they said they had about 144 units being made. I technically would've been fine with the module itself, but I don't know if they'll ever be bringing them back in stock, since it's part of their "SparkX" line which is for experimental stuff. Looking through their blog yesterday, I guess the scanner breakout was released 28 May, so maybe because it's such a new product, they're focusing all the modules to the breakout boards until demand goes down. Hell, even as I write this, they're out of stock once again and planning on making 60 more; the "Top Sellers" tab on their front page contains the scanner breakout, and for a good reason.
I got the scanner a couple days ago and played around with it some... I mean I was seriously like this:
And it was great being able to scan something that would be automatically entered in a spreadsheet, text editor, whatever. While the barcode scanner app for Android by ZXing Team is a long-time favourite of mine, it's not a very streamlined approach when I need to get the scanned data to my computer (I have it set to auto-copy the scanned contents to the clipboard, and then I paste it into Discord).
Digi-Key's labels for each bag of parts contains a Data Matrix code (at least the newer ones do, I don't know when they switched over, but I have some Digi-Key bags at work that were from 2015 that has a 1D barcode), and scanning that with the barcode scanner (the one from SparkFun) yielded info similar to this:
[)>06P559-1099-ND1PPS2801A-4-AK1K7013275410K8165562911K14LJPQ1311ZPICK12Z956474013Z5583520Z00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Which I could kinda figure out stuff from, but I needed more info. I did a quick search and found some people trying to figure it out (this being one), but no one had a complete list, so I decided to just figure it out myself. At work, I scanned one with the app and found some non-printing characters as "tofu" and it made a lot more sense to me.
♫A little bit of tofu in the text.♫
Using Discord, I pasted it within a code box so that I don't lose the tofu, and though they don't show, they were still there when I transferred it into Mousepad.
Tofu, demystified.
I use CudaText as my main text editor, but well, the non-printing characters are less obvious. Anyway, Unicode 001d is "Information Separator Three" or "[GS]" (Group Separator), and 001e is "Information Separator Two" or "[RS]" (Record Separator). I didn't really care what they were besides that they were non-printing control characters, but well, the difference between 001d and 001e would kinda serve me later. Looking at the data in Mousepad with the boxed control characters, It was much easier to make things out, and I was able to figure out that the "category" markers precede whatever number they are. I think it'll just be easier to share the findings first before I talk about certain items individually.
Digi-Key barcode data (using data from Mousepad screenshot):I had thought 11K might've been MSL, but nope, the NeoPixels have the same value of 1. The invoice number (10K) stumped me for a little, until I went to check an email that I probably still had, and sure enough, the numbers matched. Since I don't need purchase order numbers for my personal orders, work was the best bet for figuring out K, though before scanning the two samples at work, I wasn't entirely sure how the data was structured.
- [)>
- Probably a scanning software thing.
- 06
- Probably another scanning software thing, this number is the same between Digi-Key and Mouser.
- P559-1099-ND
- Part number, either customer-specified or retailer-specified, prefixed with P.
- 1PPS2801A-4-A
- Manufacturer part number, prefixed with 1P.
- K9438
- Customer purchase order (PO) number, prefixed with K, may be blank.
- 1K70132754
- Sales order (SO) number, prefixed with 1K.
- 10K81655629
- Invoice number, prefixed with 10K.
- 11K1
- No idea what this is, but seems to always be 1, prefixed with 11K.
- 4LJP
- Country of origin, prefixed with 4L, uses ISO 3166-1 alpha-2 codes.
- Q13
- Quantity of items, prefixed with Q.
- 11ZPICK
- No idea what this is, but seems to always be PICK, prefixed with 11Z.
- 12Z9564740
- Part ID, prefixed with 12Z.
- 13Z55835
- Load ID, prefixed with 13Z.
- 20Z00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
- Probably some sort of filler, prefixed with 20Z
While at work, I decided to scan Mouser's to see what it contained, and it was much less. Let's start with a screenshot of the data, and then jump right into the breakdown.
Miniscule compared to Digi-Key.
Mouser barcode data:I wasn't paying too much attention yesterday, so I thought Digi-Key and Mouser use the same structure, but I guess not. It's possible 11K for Digi-Key might be an another invoice number field, but I can't say for sure, and it's something I don't care about in all honesty. I was double-checking 11K for Mouser with some other part and found 1V, which might be something new, but again, not worthwhile for me. At the least, hopefully people looking for the structure find this blog post and is helpful to them.
- >[)>06
- Probably scanning software stuff. There's no 001e control character before 06, but at the least, the 06 is still the same in comparison to Digi-Key.
- K9439
- Customer purchase order (PO) number, prefixed with K, web order number is used if customer does not provide a PO number.
- 14K022
- Line item number (the line the item appears on an invoice, packing list, etc.), prefixed with 14K.
- PTP0194
- Customer-specified part number, prefixed with P.
- 1P02-09-1117 (Cut Strip)
- Manufacturer part number, prefixed with 1P, appears instead if there is no customer-specified part number. (This is from something else and isn't in/from the image.)
- Q10
- Quantity of items, prefixed with Q.
- 11K062059574
- Invoice number, prefixed with 11K.
- 4LLI
- Country of origin, prefixed with 4L, uses ISO 3166-1 alpha-2 codes.
- 1VNeutrik
- Manufacturer name, prefixed with 1V, may not be present.
Moving on. Because I found out about the control characters, I needed to figure out a way for the barcode scanner to send them. I tried the "serial over USB" (USB-COM) mode of the barcode scanner and ended up in an empty
screen
when loading up /dev/ttyACM1
(/dev/ttyACM0
is my Powermate), so I had to go the serial over UART route with a dev board. I used the Trinket M0 because it's small, and hooking up the barcode scanner to it was easy after I got a 6-position header soldered to the barcode scanner. I then pulled up a UART serial Adafruit guide as reference and had to try to fill in the blanks myself. It didn't seem to print anything out properly, and I tried baud rates of 9600 and 115200 in the code which both were claimed as the default in the settings manual (9600 is listed first as the default, but then 115200 is listed as the default three times after that, but eventually, I decided to scan the 115200 baud rate setting. And that was the problem all along, some mysterious default baud rate setting (I had a thought to go through them individually, but I didn't feel like it). I also tried USB-COM mode again and scanned the 115200 baud rate setting, but no dice, so I gave that mode up entirely.A new problem arose, the printed text still contained no control characters, but the code I used has a line for printing the raw data, and after commenting that out, huzzah! I forgot when I swapped my janky wire set up for the 20-position GPIO set I bought along with the barcode scanner, but I did so because the ground wire kept popping off the barcode scanner header, and honestly, I should've done it sooner since it had a much better hold on the header pins. Anyway, the next issue was the fact that the raw data is a bytearray, and I needed to convert it to a string. Well, I thought I did, but I eventually realised that the conversion in the code was actually keeping the control characters, and that
print()
was the culprit of not printing them (I mean, they're called "non-printing" characters for a reason). While trying to see if print()
had some sort of option to maybe print the characters, my eyes glanced over "sep" and I was reminded of replace()
. Huge duh moment. I used a tab character to replace 001d and had replace()
replace 001e with nothing, this would make things much more printable.It was kinda in that mess where I was also thinking of trying to write the raw data to a file, and because I normally use
open()
in text, it took me a moment to remember about its ability to write bytes. While it did work with normal Python, CircuitPython refused to do it in the test because the flash appeared as read-only to it, and though I would've used an SD card over SPI, I didn't want to make things harder than it should be (plus I had just ordered the micro SD card breakout from Adafruit, so I would've had to wait anyway). Anyway, I think it was after I got replace()
into the code (or it might've been a little before?) was when I decided to use the USB-HID library to emulate a keyboard, and because there's a library that allows a string as the input of what to send to the computer, I wanted to utilise that. The problem is that the examples changed with the documentation, so I had to try to figure it out, which wasn't too hard, but I was able to get it to work. It doesn't type nearly as fast as the barcode scanner directly, but at least I can get the control characters for processing before sending to the computer.Because the
.read()
command for the UART serial only lasts for a bit, it was hard to test in the CircuitPython console, but it was fine in the code because of the looping. I also tried to send commands to the barcode scanner, but it was difficult at first because I forgot that there was a command prefix it looks for (^_^
, caret underscore caret, I'm not kidding), and when I got it in there, it worked as intended. There was some other things I did/tried, but I won't talk about it because it's not really worthwhile.
The output (or at least simulated) from the MCU. I forgot the newline, but oh well.
Though I could do all the processing on the MCU of the stuff I care about (manufacturer's part number mainly), I wanted to keep the processing that needs to be done on the MCU as minimal as possible to make the job of scanning the inventory as quick as possible. I also added line in the code to send the save hotkey after it "types" the data, so that it's as automated as it can get. I still need to write the code for processing the file down to part numbers, but that won't be too hard and Pod will have it done before the snap of a finger.
Originally, I was thinking of buying a second barcode scanner (before I even bought the first) for a "scan and display" sort of thing, but this morning, I was considering on buying a third to keep in UART mode so that I don't have to change the settings. Along with this "third" barcode scanner, I also thought to make a custom breakout board with the ATSAMD21E18A-A because I thought I could maybe still get them, but it seems like Mouser's finally run out. Anyway, it would make it a single-board device instead of having two boards and some wires and be a little less awkward to use than the current setup with the Trinket M0. I'll still design it and such, but I won't be able finish the assembly for a while. Because I didn't really go over it that well, one would be in the fairly default mode for when I don't expect to run into control characters that would have the original board, another would be the self-contained "scan and display", and the last would be the UART version for when I need/expect control characters. Anyway, for anyone wanting the code for an Adafruit CircuitPython dev board to be able to get the above output with the barcode scanner, here's the not-entirely-pretty code based off of the code in the Adafruit guide I used:
import board
import busio
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
uart = busio.UART(board.TX, board.RX, baudrate=115200) #you can use any baud rate, just make sure your scanner is set to that rate!
kbd = Keyboard(usb_hid.devices) #make the keyboard object
klo = KeyboardLayoutUS(kbd) #make the keyboard layout object with the keyboard object
while True:
data = uart.read() #because the barcode length is unknown, don't set an amount of bytes to read
if data is not None:
data_string = ''.join([chr(b) for b in data]) #this converts the data to a normal string
data_string = data_string.replace("\x1d", "\t").replace("\x1e", "").replace("\r", "\n") #make the necessary replacements (the barcode scanner defaults to \r for newline, but can be changed to \n, so it's there in case of forgetfulness)
klo.write(data_string) #use the keyboard layout object to "type" the data string
kbd.send(224,22) #send ctrl+s to save the file, 224 is the keycode for control, 22 is the keycode for s
Important thing to note is to keep the focus in the target programme, otherwise you could lose the data from the scan and/or make things weird. Also, make sure RX of the scanner is connected to TX of the dev board, and TX of the scanner is connected to the RX of the dev board! But anyway, with this code, you just use the barcode scanner's scan button like normal and the MCU will spit out the data after it gets and processes it.
I need to double-check what appears in the Mouser barcode for my stuff, since I don't use/have PO numbers, and based on how the P/1P is for Mouser, I'm thinking I'll se a 1K and the corresponding number. I'll edit this when I confirm it and probably will say that I did below.
Found that Mouser uses the web order number for the PO number, so no 1K category in the place of K. Also found that Digi-Key's packing list has some small Data Matrix codes that include Unicode 0004, which is "End of Transmission". I won't modify the above code, but if the codes on the packing list are to be used, just tack on
.replace("\x04","")
to the replacement chain.(Edit: 2021-07-17)
While doing some testing for projects that include a graphic screen of some sort (the aforementioned "scan and display" and maybe the PSU tester), I came across one of my old code tests when I was playing around with the Trinket M0 and various libraries. If you're using Linux of some sort, or at least something that allows you to type Unicode characters using
Ctrl+Shift+U
, then you can actually type any Unicode character using Adafruit's adafruit_hid.keyboard
library. I completely forgot about this and I honestly should've remembered because it saves the chain of replacements. Anyway, the code for raw output:
import board
import busio
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
uart = busio.UART(board.TX, board.RX, baudrate=115200) #you can use any baud rate, just make sure your scanner is set to that rate!
kbd = Keyboard(usb_hid.devices) #make the keyboard object
klo = KeyboardLayoutUS(kbd) #make the keyboard layout object with the keyboard object
def send_unicode(char): #define a function to send the untypeable unicode character
parts = hex(ord(char))[2:] #get the hexadecimal value of the untypable character without the "0x" prefix
kbd.send(224,225,24) #send ctrl+shift+u so that the unicode value can be typed
klo.write(parts) #send the unicode value
kbd.send(44) #send space to finish the unicode entry
while True:
data = uart.read() #because the barcode length is unknown, don't set an amount of bytes to read
if data is not None:
data_string = ''.join([chr(b) for b in data]) #this converts the data to a normal string
for char in data_string: #iterate through each character in data_string
try:
klo.write(char) #try sending the character normally
except:
send_unicode(char) #or send it the other way if it can't be typed
kbd.send(224,22) #send ctrl+s to save the file, 224 is the keycode for control, 22 is the keycode for s
02 July 2021
Charging & Cooling Station
I completely forgot about this project until one of the previous posts. Anyway, it was sometime in 2019 when I fully got onto USB-C PD charging (I don't think I had any PD chargers beforehand), and with my phone or dap getting warm (not dangerously warm), I decided to use a fan to help keep the phone or DAP cool as it charged.
I decided to build my own charging station since all the ones on the market had too many slots, were much larger than I needed, and didn't have a fan. I decided on some ABS plastic from TAP Plastics since I could have them cut into the sizes I need, and I was thinking 0.25 inch thickness would be fine, but I decided on 0.375 inch thickness just to be safe. The fans I decided on was two 80mm fans since that was the best size to keep the plastic sheets all the same size.
I also had a charger with QC (I don't remember which QC version), and decided to use that so I could manage the speed of the fans. I looked around on how the QC thing worked, and found a post where someone used an MCU to be able to get the other voltages. I only needed the voltages that D+ and D- would need to be at for the voltages I wanted (9 and 12), so the rest was brushed off because I was going to do it with discrete parts. Because I knew that stepping 12 (or even 9) volts down to 3.3 volts would heat up the voltage regulator, I was going to need a fan on it and I had a small fan for doing so. With the voltage regulator, I also went with a DPak package because I wanted it simple and beefy (even if the output is 500mA).
With the above table, I only needed 0.6 and 3.3 volts for D+, and GND and 0.6 volts for D-, which made it pretty easy because I could just use a couple signal relays to switch between the voltages. I also used a dual anode to common cathode diode to be able to control the D- relay regardless if I needed 9 or 12 volts since 0.6 was on the normally open leg of the relay. I also used a USB B connector because I wanted something robust. I put some ESD diodes in as well to try to dissipate esd from the mounting screws (and maybe remove any charge from the ABS plastic), but well, I didn't fully understand it and I learned fairly recently that I used them wrong. I wanted to via stitch the unused space for maximum heat dissipation, but I didn't to put all the vias in myself. Rather, I think I started to, but I looked for some other way instead, which was
I was forced to use an SPDT switch for power, since the SPST switch I wanted wasn't normally stocked. I can't remember if the SPDT or SP3T switch has a threaded bushing, but it was what I could get, even if the smooth bushing was what I wanted both to be. I used polyimide tape (aka Kapton tape) to insulate some of the vias or to insulate the parts from the vias just to be safe. Because the fan I was using had only 2 wires (and a two-position connector), I used a two-position header. I think it was after the boards came when I realised that the fan I had to cool the voltage regulator was 45mm and not 40mm, and I bought Noctua's 40×10mm fan as the fix.
I also found an interesting pattern on the bottom of the relay (I'm used to relay pottings not showing any sort of pattern).
It was a couple days later where I had it assembled.
I forgot which of Arctic's fans I used, but it eventually was replaced with the 80mm be quiet! fans that were in Pod's old case. Not too much to talk about with the work done on the ABS sheets, I used calipers to mark the locations of the screwholes and did my best to drill everything on location and as straight as possible.
It was after some usage that the fans just randomly shut off, and I don't think I thought anything of it until it did it again while giving off a smell similar to tooth dust. What had happened was that the tantalum cap went out, and that I had put it backwards because I thought the banded side of the cap was negative. I dunno where the standard for banding the positive side of tantalum caps came from, but I thought it was similar to SMT electrolytic caps and diodes. Anyway, I had spares, so I just plopped a new one on in the correct orientation and I was on my way. A weird thing about this board is that to be able to get to to 9 volts or 12 volts (I leave it at 5 volts by default), I have to switch it to 12 volts for a few seconds before I can either switch to 9 volts for 9 volts or switch to 5 volts and then back to 12 for 12 volts. There's actually a specific thing that I'm actually suppposed to do for proper initialisation (preferrably with an MCU) that Dangerous Prototypes found, but I was only concerned with the D+ and D- voltages back then.
Oh right, I did do a test where I pulled 9 and 12 volts for a bit with the 40mm fan disconnected, and the regulator did get warm/hot as expected, but with the 40mm fan on at 9 and 12 volts, the regulator and board stay cool. I thought I overengineered the board, but it seems like I actually did it just right. The 40mm fan kinda tries to spin at 5 volts, but it's not enough voltage in the pulse for the fan to turn. I think Noctua says the startup voltage is about 6 volts? Anyway, if I give a little nudge when the pulse happens (might just before, I don't remember), the fan will start moving (the fan runs at 5 volts, but won't start at 5 volts). I can also just give the fan 9 or 12 volts to get it spinning and then switch it to 5 volts, but there's no reason for the fan to spin at 5 volts.
I kinda had a thought to redo this board with an MCU because it would get rid of the relays and make the board a little more compact in z-height (especially if I move everything to the side with the USB B connector), but this board works just fine and I'm not sure I want to spend the time on the redesign. If I did redesign the board, I would likely tent the vias and then have certain vias exposed for heat dissipation.
DAP screen-down under a 120mm fan while charging.
I decided to build my own charging station since all the ones on the market had too many slots, were much larger than I needed, and didn't have a fan. I decided on some ABS plastic from TAP Plastics since I could have them cut into the sizes I need, and I was thinking 0.25 inch thickness would be fine, but I decided on 0.375 inch thickness just to be safe. The fans I decided on was two 80mm fans since that was the best size to keep the plastic sheets all the same size.
I also had a charger with QC (I don't remember which QC version), and decided to use that so I could manage the speed of the fans. I looked around on how the QC thing worked, and found a post where someone used an MCU to be able to get the other voltages. I only needed the voltages that D+ and D- would need to be at for the voltages I wanted (9 and 12), so the rest was brushed off because I was going to do it with discrete parts. Because I knew that stepping 12 (or even 9) volts down to 3.3 volts would heat up the voltage regulator, I was going to need a fan on it and I had a small fan for doing so. With the voltage regulator, I also went with a DPak package because I wanted it simple and beefy (even if the output is 500mA).
Voltages D+ and D- need to be at for a specific voltage.
With the above table, I only needed 0.6 and 3.3 volts for D+, and GND and 0.6 volts for D-, which made it pretty easy because I could just use a couple signal relays to switch between the voltages. I also used a dual anode to common cathode diode to be able to control the D- relay regardless if I needed 9 or 12 volts since 0.6 was on the normally open leg of the relay. I also used a USB B connector because I wanted something robust. I put some ESD diodes in as well to try to dissipate esd from the mounting screws (and maybe remove any charge from the ABS plastic), but well, I didn't fully understand it and I learned fairly recently that I used them wrong. I wanted to via stitch the unused space for maximum heat dissipation, but I didn't to put all the vias in myself. Rather, I think I started to, but I looked for some other way instead, which was
create_drill_line_array.ulp
from Dangerous Prototypes. The script, rather user language program (ulp), worked well enough, but I found that there was certain things it didn't like, and also that it will stack vias on top of each other if you're not careful. Though I did the vias one line at a time, it was still faster than doing it one via at a time. I think it's time to show the board...
Vias, vias everwhere.
I was forced to use an SPDT switch for power, since the SPST switch I wanted wasn't normally stocked. I can't remember if the SPDT or SP3T switch has a threaded bushing, but it was what I could get, even if the smooth bushing was what I wanted both to be. I used polyimide tape (aka Kapton tape) to insulate some of the vias or to insulate the parts from the vias just to be safe. Because the fan I was using had only 2 wires (and a two-position connector), I used a two-position header. I think it was after the boards came when I realised that the fan I had to cool the voltage regulator was 45mm and not 40mm, and I bought Noctua's 40×10mm fan as the fix.
I also found an interesting pattern on the bottom of the relay (I'm used to relay pottings not showing any sort of pattern).
It was a couple days later where I had it assembled.
Mostly finished in its mockup location, bottom rear 3/4 view, bottom front 3/4 view with a leg removed.
I forgot which of Arctic's fans I used, but it eventually was replaced with the 80mm be quiet! fans that were in Pod's old case. Not too much to talk about with the work done on the ABS sheets, I used calipers to mark the locations of the screwholes and did my best to drill everything on location and as straight as possible.
It was after some usage that the fans just randomly shut off, and I don't think I thought anything of it until it did it again while giving off a smell similar to tooth dust. What had happened was that the tantalum cap went out, and that I had put it backwards because I thought the banded side of the cap was negative. I dunno where the standard for banding the positive side of tantalum caps came from, but I thought it was similar to SMT electrolytic caps and diodes. Anyway, I had spares, so I just plopped a new one on in the correct orientation and I was on my way. A weird thing about this board is that to be able to get to to 9 volts or 12 volts (I leave it at 5 volts by default), I have to switch it to 12 volts for a few seconds before I can either switch to 9 volts for 9 volts or switch to 5 volts and then back to 12 for 12 volts. There's actually a specific thing that I'm actually suppposed to do for proper initialisation (preferrably with an MCU) that Dangerous Prototypes found, but I was only concerned with the D+ and D- voltages back then.
Oh right, I did do a test where I pulled 9 and 12 volts for a bit with the 40mm fan disconnected, and the regulator did get warm/hot as expected, but with the 40mm fan on at 9 and 12 volts, the regulator and board stay cool. I thought I overengineered the board, but it seems like I actually did it just right. The 40mm fan kinda tries to spin at 5 volts, but it's not enough voltage in the pulse for the fan to turn. I think Noctua says the startup voltage is about 6 volts? Anyway, if I give a little nudge when the pulse happens (might just before, I don't remember), the fan will start moving (the fan runs at 5 volts, but won't start at 5 volts). I can also just give the fan 9 or 12 volts to get it spinning and then switch it to 5 volts, but there's no reason for the fan to spin at 5 volts.
I kinda had a thought to redo this board with an MCU because it would get rid of the relays and make the board a little more compact in z-height (especially if I move everything to the side with the USB B connector), but this board works just fine and I'm not sure I want to spend the time on the redesign. If I did redesign the board, I would likely tent the vias and then have certain vias exposed for heat dissipation.
01 July 2021
Adafruit's Debounce CircuitPython Library
I think it was after whatever previous post that I had mentioned it, I decided to tinker with it some within the Powermate (I also was partially annoyed with the button's input behaviour that I programmed). After making the necessary changes (importing, assigning, etc.), I changed the
Last Friday, I decided to give it another whirl (I think I was thinking about it the night before and figured something out that would probably make it work) and made the necessary changes once again. I don't remember exactly what I did, but I did use
With the script for mine fixed up, I fixed the one for my friend and gave him the library and the new code, even if his button just toggles the LEDs on or off. Button definitely works a lot better than the old code, and definitely planning on using the debouncer library where possible.
if
statements to look for rise or fall instead of the button value, and didn't have much luck getting it to work while tweaking the code. I ended up just undoing all of the changes and leaving the tinkering for another day.Last Friday, I decided to give it another whirl (I think I was thinking about it the night before and figured something out that would probably make it work) and made the necessary changes once again. I don't remember exactly what I did, but I did use
.rose
and .fell
in conjunction with .value
to get it working. I also already had a counter implemented in the old code that counted the amount of cycles the button was being held for, and I had also changed it to accomodate the new sleep time of 10ms (since the debouncer class defaults to 10ms cycles). I found from the library documentation that there's also .current_duration
and .last_duration
and kinda played with those a bit, but .last_duration
didn't seem to be that useful (or at least for me). I tried using .current_duration
for the profile switching, but it ended up being problematic, so I changed it back to read from the counter system. I left .current_duration
where it turns the LEDs to the colour of the current profile because it works fine and it doesn't matter if I use that or my counter system there. I also had tried .current_duration
with what the button does when pressed, but didn't work well.With the script for mine fixed up, I fixed the one for my friend and gave him the library and the new code, even if his button just toggles the LEDs on or off. Button definitely works a lot better than the old code, and definitely planning on using the debouncer library where possible.
PSU Tester
With the power supply problem I had with Pod, I kinda wanted to make my own PSU tester (I sah "Bah!" to the ones I can buy), and I just took some notes down and kinda forgot about it. I decided to use the ATSAMD21E18A-A because it has six analogue input pins, which is more than enough, and I had to figure out the resistor values for the the voltage dividers that would bring 5 and 12 volts down to 1.65 (half of 3.3 volts). I had also gathered some parts that I would need for it and shoved them into my notes, and I also have notes to have a switch to be able to change the 12-volt rail to be checked. I thought to use the leftover NeoPixel Nano 2020 LEDs for indication, but later I thought that an LCD or OLED screen would be a little better.
I also looked up how to measure negative voltages, and wasn't surprised when I found the answer was op-amps. I also found out that the
I also looked up how to measure negative voltages, and wasn't surprised when I found the answer was op-amps. I also found out that the
pwr_ok
signal is actually a timed thing and the voltage on it should come on no sooner than 100ms, so I added that piece of info to my notes. I really don't have a lot done with this project since it actually was started after the MCU/CircuitPython project "craze", and I didn't feel like working on the board much past plopping some of the planned items down. I have notes that I might need a crystal, but I also have no idea where the power for the MCU is going to come from. Ideally, I'd like to keep it separate from the power supply, but it's another decision to make before working on the project more. I probably will just add the crystal and its capacitors in anyway, but we'll see.
Character LCD Clock
I think I was browsing Adafruit when I saw some character LCDs, and also their character LCD backpack. The description mentions 20×4 displays, which is the same size that I use at work for a couple products, but there was the problem that the backpack has the connections in a straight line while the LCDs at work have a row of eight on each side of the board. Because of the incompatibility, I kinda brushed it off for a bit. I think later I went to check the datasheet and compared the pinouts, which proves that it is compatible, but not without some sort of adapter. I decided to grab a spare LCD board from work and an LCD that was literally just collecting dust, and made my own I²C character LCD adapter board with Adafruit's as the basis. (I was fairly hyped about I²C back then because of its use of only two MCU pins to be able to communicate with numerous devices, but also I only had a Trinket M0 as a dev board at the time, so I didn't have a lot of pins to work with. Also, this is probably where I learned about the MCP23008.)
Since the LCD board is laid out weird, I decided to place the board directly over the majority of the used pins and then run some wires over to the other portion. Because the top side of the board would be the side that directly faces the LCD board, I put all the parts on the bottom side and just reserved the top side for the header and wires (where the bottom side of the board would be where the wires are soldered to the board). More wires were used for the connection to the Trinket M0, but with the "Dupont" socket connectors on the end of them. I should have crimped the connectors on before soldering the wires to the board, but I think I thought it would be okay, and well, I had to resolder one of the wires because the Trinket M0 was having troubles picking it up or something.
It did work fine though, but it seemed a bit slow to display, and seemed like lyrics being displayed for a song. I thought it might be some sort of lag or something with the I²C line since the I²C lines were being held up at 5 volts and not 3.3, but I decided to put it aside since I was pretty much done with the tinkering. I was poking around Mouser for character LCDs (to see what kinds there were), and I found an 8×2 character display that has a 2×7 header, which is more convient for custom boards. I forgot how I decided on making a clock with it where the top line would display the time in ISO format (HH:MM:SS) and the second line would display the date in some way. I think I decided with having a format like "30 Jun" and then having the day of the week displayed, but the problem of only having one character was a problem. At first I wanted to stay with Roman characters and looked around other langauages for their days of the week hoping that there would be at least one that has a different first letter for each day of the week. I did find one, but I only kept it in mind as a sort of alternative. I know I also was deciding on using Japanese (and also Chinese, I think) days of the week, but I was having troubles translating the kanji into "pixel art". I ended up with finding a font called PixelMplus, but it took me entirely too long to figure out how to install it before I realised I didn't download the one from the blog page. (It's the second link, but I think I might've scrolled past it without seeing it.) Anyway, it has two pixel sizes of 10 and 12, and I used the kanji from the 10-pixel size to try to make a 5×8 pixel version, but it was just not working out for some of the kanji. While I think I had TU and TH already done before I was trying the kanji stuff, SU and SA were giving me problems because of the S, and was why I was kinda seeking alternatives, but I did eventually figure something out.
I eventually found an I²C isolation board that was a new product at Adafruit and decided to buy it with some STEMMA QT cables so that I could pass 5 volts and ground to the other side of the isolator. Trying it out, it did work fine, but it still had that slow display problem, which I figured to be the that I²C probably isn't fast enough to draw all four lines of the display "instantly" like I remember from the work products. I think it's when I got the ItsyBitsy M4 when I actually had enough pins to directly drive the 4-bit communication instead of having to go through a GPIO expander, and when I had it all set up, it was like it should. There is a slight lag with the last line, but it's still fast enough. I also want to test 8-bit communication, but I'd probably have to write my own library for that.
Anyway, for the board of this project, I started with using the ATSAMD21E18A-A because I wasn't going to need a lot of pins. I was planning on having the RTC set to local time and having a switch to control DST, but eventually I figured it'd probably be better to have the RTC as UTC time instead because it'd be easier to change the timezone offset in the code than have to set the RTC to the new time (if I moved or something). This presented a problem because there was no easy way to properly adjust the date and time (had this just been the time, then it would've been fine). Because the
My options were to either tack an SPI flash chip onto the MCU or to use the ATSAMD51J19A-A, which has double the onboard flash, and for the second revision, I decided to make a board for both routes. As maybe obvious from the notes in the first board, I needed to put the MCU on the bottom of the board and turn it so that I have access to more SERCOM pins, since the first board uses some of the SERCOM pins for the LCD. The reason why I originally had all the parts on top was because they then would be inbetween the board and the LCD and a little better protected from ESD, so while I didn't want to do a board with them and the SPI chip on the bottom, I did anyway.
For the ATSAMD51J route, I had less board space to work with, but I still made it work with everything on top of the board like I wanted. I think it was sometime after I finished this board where I was playing with using the analogue out pin for controlling the contrast, since I'd have a lot more control than a variable resistor as a voltage divider. (The LCD from work says to give the contrast pin about 0.6 volts, and so dividing the voltage from 5 volts makes it a very small window to work with. While I could change the input of the voltage divider to 3.3 volts from the regulator, it wouldn't give me much more to work with.) Making the change removed the variable resistor and its traces and freed up a little bit of space. The second change to make was the fact that the MCU wouldn't have any timekeeping pulses, and because the RTC has the 32kHz output, I was able to just run the trace up to the oscillator in pin (PA00) and connect a pull-up between it and 3.3 volts.
I think it was before removing the voltage divider that I found that the
The SERCOM multiplexing thing started with this project because I wanted to try to have a sort of "direct" connection between the RTC and MCU, but from the Adafruit dev board schematics and how things were set up for those dev boards, my knowledge was limited. PA08 and PA09 are usually the default I²C lines and the alternatives were PA16 and PA17 for one, and PA22 and PA23 for another (assuming those were exposed pins, I don't remember at this point since Adafruit has board names for them that they use instead). After getting the whole SERCOM thing straight, I found that I was able to use PA17 with PA22 because they're both on SERCOM 3. (My explanation on SERCOM multiplexing is in the previous post.)
Whenever I do have this board made and have the MCU for it, it'll be the test for the RTC's 32kHz output as the MCU's crystal, since this board is going to be cheaper than the MCU internet clock one. I'm sure it'll work fine, but I remember not really being able to find any info besides this thread.
Said adapter board.
Since the LCD board is laid out weird, I decided to place the board directly over the majority of the used pins and then run some wires over to the other portion. Because the top side of the board would be the side that directly faces the LCD board, I put all the parts on the bottom side and just reserved the top side for the header and wires (where the bottom side of the board would be where the wires are soldered to the board). More wires were used for the connection to the Trinket M0, but with the "Dupont" socket connectors on the end of them. I should have crimped the connectors on before soldering the wires to the board, but I think I thought it would be okay, and well, I had to resolder one of the wires because the Trinket M0 was having troubles picking it up or something.
Adapter board before the header. I took this as a reference of what colours was what signal.
It did work fine though, but it seemed a bit slow to display, and seemed like lyrics being displayed for a song. I thought it might be some sort of lag or something with the I²C line since the I²C lines were being held up at 5 volts and not 3.3, but I decided to put it aside since I was pretty much done with the tinkering. I was poking around Mouser for character LCDs (to see what kinds there were), and I found an 8×2 character display that has a 2×7 header, which is more convient for custom boards. I forgot how I decided on making a clock with it where the top line would display the time in ISO format (HH:MM:SS) and the second line would display the date in some way. I think I decided with having a format like "30 Jun" and then having the day of the week displayed, but the problem of only having one character was a problem. At first I wanted to stay with Roman characters and looked around other langauages for their days of the week hoping that there would be at least one that has a different first letter for each day of the week. I did find one, but I only kept it in mind as a sort of alternative. I know I also was deciding on using Japanese (and also Chinese, I think) days of the week, but I was having troubles translating the kanji into "pixel art". I ended up with finding a font called PixelMplus, but it took me entirely too long to figure out how to install it before I realised I didn't download the one from the blog page. (It's the second link, but I think I might've scrolled past it without seeing it.) Anyway, it has two pixel sizes of 10 and 12, and I used the kanji from the 10-pixel size to try to make a 5×8 pixel version, but it was just not working out for some of the kanji. While I think I had TU and TH already done before I was trying the kanji stuff, SU and SA were giving me problems because of the S, and was why I was kinda seeking alternatives, but I did eventually figure something out.
The four doubled-up characters. This page was used for doing this, which Adafruit points to in a guide.
I eventually found an I²C isolation board that was a new product at Adafruit and decided to buy it with some STEMMA QT cables so that I could pass 5 volts and ground to the other side of the isolator. Trying it out, it did work fine, but it still had that slow display problem, which I figured to be the that I²C probably isn't fast enough to draw all four lines of the display "instantly" like I remember from the work products. I think it's when I got the ItsyBitsy M4 when I actually had enough pins to directly drive the 4-bit communication instead of having to go through a GPIO expander, and when I had it all set up, it was like it should. There is a slight lag with the last line, but it's still fast enough. I also want to test 8-bit communication, but I'd probably have to write my own library for that.
Anyway, for the board of this project, I started with using the ATSAMD21E18A-A because I wasn't going to need a lot of pins. I was planning on having the RTC set to local time and having a switch to control DST, but eventually I figured it'd probably be better to have the RTC as UTC time instead because it'd be easier to change the timezone offset in the code than have to set the RTC to the new time (if I moved or something). This presented a problem because there was no easy way to properly adjust the date and time (had this just been the time, then it would've been fine). Because the
adafruit_datetime
library is thirty-something kilobytes in size, I didn't have enough room on the MCU's flash to have it, the other libraries, and the code.My options were to either tack an SPI flash chip onto the MCU or to use the ATSAMD51J19A-A, which has double the onboard flash, and for the second revision, I decided to make a board for both routes. As maybe obvious from the notes in the first board, I needed to put the MCU on the bottom of the board and turn it so that I have access to more SERCOM pins, since the first board uses some of the SERCOM pins for the LCD. The reason why I originally had all the parts on top was because they then would be inbetween the board and the LCD and a little better protected from ESD, so while I didn't want to do a board with them and the SPI chip on the bottom, I did anyway.
Tentative second revision.
For the ATSAMD51J route, I had less board space to work with, but I still made it work with everything on top of the board like I wanted. I think it was sometime after I finished this board where I was playing with using the analogue out pin for controlling the contrast, since I'd have a lot more control than a variable resistor as a voltage divider. (The LCD from work says to give the contrast pin about 0.6 volts, and so dividing the voltage from 5 volts makes it a very small window to work with. While I could change the input of the voltage divider to 3.3 volts from the regulator, it wouldn't give me much more to work with.) Making the change removed the variable resistor and its traces and freed up a little bit of space. The second change to make was the fact that the MCU wouldn't have any timekeeping pulses, and because the RTC has the 32kHz output, I was able to just run the trace up to the oscillator in pin (PA00) and connect a pull-up between it and 3.3 volts.
I think it was before removing the voltage divider that I found that the
adafruit_datetime
library also uses "a bunch of memory" and I might've done some testing to confirm this, but I don't remember. Regardless though, the ATSAMD51 route was the route that I would take because of it.The SERCOM multiplexing thing started with this project because I wanted to try to have a sort of "direct" connection between the RTC and MCU, but from the Adafruit dev board schematics and how things were set up for those dev boards, my knowledge was limited. PA08 and PA09 are usually the default I²C lines and the alternatives were PA16 and PA17 for one, and PA22 and PA23 for another (assuming those were exposed pins, I don't remember at this point since Adafruit has board names for them that they use instead). After getting the whole SERCOM thing straight, I found that I was able to use PA17 with PA22 because they're both on SERCOM 3. (My explanation on SERCOM multiplexing is in the previous post.)
Whenever I do have this board made and have the MCU for it, it'll be the test for the RTC's 32kHz output as the MCU's crystal, since this board is going to be cheaper than the MCU internet clock one. I'm sure it'll work fine, but I remember not really being able to find any info besides this thread.
30 June 2021
MCU Internet Clock
While poking around on Adafruit, I found a guide for building an internet clock, and while the dev board used has a ATSAM21G18, it's not using CircuitPython. I eventually found the AirLift series of WiFi boards that have this statement just about everywhere:
I think I started the board off with the seven-segment displays (same ones as the Raspberry Pi clock) and then added the Airlift footprint (that I think still had vias) for the board size, and then had to remove the vias from the Airlift footprint because I was going to need whatever space I could get. I also had a hole in each corner of the board for the standoffs and lens, but later I removed two of them in favour of the simplicity of using the Airlift mounting holes for the same purpose. The USB mini-B jack went on the left side, the button on the right, and the MCU and transistor was plopped in the centre for later placement. For this case, I have PA24 and PA25 facing the USB connector, since I wasn't going to need any of the pins on that side.
Because of the space I would need, I needed SMT headers to connect the Airlift to the board, and also needed the same for the displays. Part of the problem was that I would also need a standoff or space between the two boards, and that I had no way of knowing the insulation height of the header that comes with the Airlift. After a bunch of digging around, I did find a header and socket header combo that came to 10mm. I ended up using the same series of socket headers for the display because it was the one with the smallest pad sizes (which technically are a reference anyway).
Anyway, I think I was planning on the same 74HC595 as the second revision (the smaller but wider package, SSOP), but I didn't have enough space to have everything run properly, so I needed a different solution. I had encountered the MCP23008 on Adafruit sometime before this project, and there was the MCP230xx library that they have, which includes the larger MCP23017. Oh right, I tried the DHVQFN16 package of the 74HC595 on the Raspberry Pi clock before I went to the SSOP/TSSOP package, but I might've tried it here before giving up on it again. Anyway, I think I started with the SSOP package of the MCP23017, but it was still hard to route stuff, so I ended up going with the QFN package. I opted to not connect the exposed thermal pad to anything for that bit of board space, that really only makes it easier to run VCC to Reset for both of them and to A0 for one of them.
A little out of order here (though honestly I think the posts after the backlog and each of those posts aren't fully in chronological order), but because I had learned about multiplexing the signals, it was pretty useful here. I'll go into it here since this would be the slightly better example than the project that kinda sparked the multiplexing. Anyway, while there is a guide from Adafruit on it, it goes the way of Arduino (I almost wanted to type Audino, thanks Pokémon) after kinda explaining it. First we have what are called SERCOM, which is short for SERial COMmunication, and each SERCOM is a module that groups different serial communication protocols together (SPI, I²C, etc). Each SERCOM has pads, which define the signal type for each of the connections to the SERCOM module, and are numbered from zero to three. Each SERCOM module can share pads with other SERCOM modules, but only with modules with the same number (SERCOM 0 can't share pads with SERCOM 1). There is a bit of a caveat, however, in that an MCU pin can be part of two SERCOM modules. Using the ATSAMD21G as an example, PA16 is SERCOM 1 pad 0 by default, but is SERCOM 3 pad 0 alternatively; this means that PA16 can be only be used with SERCOM 1 and SERCOM 3 as pad 0. In terms of I²C, pad 0 is defined as SDA, pad 1 is defined as SCL, pad 2 is defined as SDA_OUT, and pad 3 is defined as SCL_OUT; pad 2 and pad 3 are for 4-wire I²C operation. SPI is trickier than I²C, so let's start with a table I made that condenses the information from the datasheet.
Let's start with explaining some of these acronyms: MISO stands for Main In Secondary Out, MOSI stands for Main Out Secondary In, and SCK stands for Serial ClocK. (Main and secondary used to be master and slave respectively, but well, there's been a push to stop using these terms in favour for others. I think Adafruit uses secondary instead of serial, but I could be wrong, though I'm pretty sure it's where I got secondary from.) Also this table is only for when the MCU is being used to "host" the SPI bus, MOSI and MISO are flipped if the MCU is being used as a "client". Besides the fact that it's obvious that MOSI and SCK are data outputs and thus are in the same column, it's also because the pads to be used need to be on the same address. For example, to have pad 3 as MOSI, SCK can only be pad 1. The MISO pin can be any address, but obviously can't be a pad that's being used by MOSI or SCK. To sum up for this case, SCK can only be pad 1 or pad 3, MOSI can only be pad 0, 2, or 3, and MISO can be any of the unused pads.
The ATSAMD51 is different though, and for pads 0 and 1, the alternate SERCOM pads don't match the default SERCOM pads like the ATSAMD21. For example: PA08 is SERCOM 0 pad 0 as the default, and SERCOM 2 pad 1 as the alternative; PA09 is SERCOM 0 pad 1 as the default and SERCOM 2 pad 0 as the alternative. Weird? Yes. By this, in theory, it wouldn't matter which pin is SDA and SCL for I²C if the pins are on the same default or alternate SERCOMs. Pads 2 and 3 don't exhibit this weird flop between default and alternate SERCOMs, so it's predictable. SPI is kinda weird, but technically easier... Table time!
SCK has to be pad 1, MOSI can be either pad 0 or pad 3, and MISO is, well, whatever's not already used. DOPO addresses 0x1 and 0x3 are reserved and I think it might say somewhere (either the datasheet or somewhere online) the reasoning or use for the reserved addresses. Hopefully I explained this a little clearer than the Adafruit guide, since the guide uses Arduino code to help explain it, and though I can read it, I feel like it's a little messy for someone that's using CircuitPython and trying to multiplex pins. Question you might have is "How do I use this in CircuitPython?", and well, you kinda don't. Certain Adafruit CircuitPython libraries has places to put the respective signals (
What does this whole SERCOM multiplexing have anything to do with this project? It's because I needed to connect the SPI signals from the Airlift to the MCU in a direct manner without using vias to jump over other signal traces and to leave pins for I²C since I blocked off the SPI and I²C pins on the USB side of the MCU. I put the RTC (DS3231) and the temp sensor (MCP9808) at the bottom of the board and left it there while I worked on the other stuff. Though the Airlift board does have a 3.3-volt voltage regulator, I decided to add another one because I knew that one wouldn't be enough to power everything else.
Now that I think about it, the other clock project I've yet to talk about actually came first, due to the fact that its where I originally have the timezone offset set in the code while having a switch for DST control. The same is true for this project, especially since the time that it gets from NTP is UTC. Anyway, the code takes the timezone offset and adds the inverted status of the DST switch to it for the total offset before it adds it to UTC for the local time. To be able to do date and time maths, Adafruit's version of Python's
For flipping the display, I think I started with a third switch, but eventually moved to an accelerometer to make the end usage easier. It wasn't too big of a deal to add the accelerometer, since it has both I²C and SPI interfaces, the I²C traces were already running to the MCP23017 on the "button" side of the board, and there was enough space to do so. I had to hop one of the I²C traces over the other since there wasn't any other way to route the traces, and that I already needed vias to bring the signals up to the top of the board for the MCP23017.
I think I failed to mention the purpose of connecting A0 of one MCP23017 to VCC, but I'll do it now while it's on my mind. The MCP23017 has three addressing pins (A0, A1, A2) that allows the MCP23017 to have eight different addresses, and thus allowing eight MCP23017 to be on the same I²C line. For normal usage, the addressing pins are connected to ground for the default address of 0b100000 (0x20, 32), and when connecting A0 to VCC, the address becomes 0b100001 (0x21, 33). Also with this non-default address, this MCP23017 instance needs to be made with the address, otherwise it would go unnoticed or CircuitPython will raise an error that the device (which is actually the one at the default address) is already in use (or something to that effect).
I think I forgot again that I needed the pull-up resistor and cap for the reset line, so I had to make some late changes to account for it... Or maybe it was the weird pull-up resistor thing on SWDIO for programming the bootloader. With some extra space that would be able to accomodate six switches the size of the reset switch, I wanted to add some buttons, even if I never planned on having them (and thus not knowing what to have them do). Realistically, I could only do three to keep the traces fairly simple (I probably could do one more, but I didn't feel like it was worth the extra work it'd entail), and I already had a placeholder wire that I put in between a couple of traces because I didn't want to lose that bit of routing space, so one of the routes was already partially ran. I later realised that I could do capacitive touch pads instead since the pins I used also support capacitive touch, and that the force needed would be negligible compared to the tactiles that I was using (same as the reset button, but I don't know if I was looking at ones with the same or similar footprint with lower activation force). I had ideas to use a button or two for doing some sort of screen test and maybe to be able to set the timezone offset, but I haven't decided what to do them. I also haven't placed any of the touch pads since I kinda lost interest in them and in the project a bit — the silicon shortage also not helping.
Also, for the RTC's backup battery, I decided to use a CR1225 that has some solder pins welded on, so that I can solder wires to the pins and then solder the wires to the vias in the board. The battery (which would have heatshrink around it) would sit under the display at the centre, since there's no space for a coin cell holder. Routing the positive trace was a bit interesting, since I had to go around and between stuff. I don't think I have anything else to say with the board, so here's the current state of the board:
I forgot when I did during all of this, but I did get an Airlift to poke around with the libraries and such; I was kinda curious with the WiFiManager class that should make it easier to stay connected. Another Adafruit library I found was their NTP library, which is super simple to use. The NTP object is created with the Airlift object, and
I did also use the ATSAMD51J19A-A dev board to test out the automatic syncing of the RTC module I have, and it worked fine since I had to set the RTC module time for the third time. I forgot which project I was working on, but I was using the RTC module to test out the 32kHz output pin and when hooking it up, I didn't realise that I swapped VCC and ground, so while I got nothing, the RTC, board, and backup battery were heating up. I forgot how I realised it, but I did and unplugged the board while heading to the soldering station for one of the fans to cool it down. I was worried that I fried the RTC, but when it was cool enough, it worked just fine and had just lost the set time. I think I had read in the datasheet or somewhere that the 32kHz output only works when the RTC recieves power on VCC, so it was what I was trying to test for, but I didn't have any luck getting a good reading. I had also read that I would need a pull-up resistor for the 32kHz, and I had soldered a 2.2 kilohm resistor according to the post I read (datasheet says anywhere between 1k and 1M) before the test. I also had desoldered one leg of the resistor during the test because I was having troubles getting a reading, but it didn't seem to make a difference. I was using the oscilloscope I use at work because it was more convenient than the one at home (which is some leftover one from work), but got some funky waveform, and tried it on the the oscilliscope that the electrical engineer uses and still got the same weird waveform. I think this is what sparked me to try the one I have at home and either I had the reversed polarity fiasco then or it was before all this, I really can't remember. Regardless though, I ended up getting the frequency metre to read the 32.768kHz it was supposed to read and the wave was square and was close enough to 32kHz. I took the RTC to work again the next day and also got the correct waveform. I know I had some sort of suspicion that it might have something to do with the ground line of the oscilloscope connected to the bench power supply, but it didn't seem to be it. I think with the initial test with the oscilloscopes at work, I did try using the little probe grounding thing with no avail. Dunno what happened, but well, I got what I was looking for in the end. The second time I did the reverse polarity thing was while setting up for the automatic syncing test, and well, I had more of a reason to do it after it cooled down enough.
Anyway, the reasoning for the 32kHz output pin was to see if I might be able to use that instead of having a dedicated crystal circuit for the MCU, and from the post I previously linked, it should be doable. I checked the datasheet for which pin to connect to since one of the two crystal pins is the output and one is the input. I keep forgetting where I read it (it was some Adafruit thing, I know for sure), but the MCU uses the USB pulses for timekeeping on boards that don't have a crystal (or something like that). Since the clock would be connected to some USB charger, it probably wouldn't get the pulses, so I needed to add a crystal in some way. Using the 32kHz output was a lot more space efficient because it would've been a tight fit to get a crystal and its caps near the crystal pins (PA00, PA01). Routing was kinda interesting because I was thinking to redo some traces and kinda take a long way around, but decided to try running it the other way while hugging other traces, which ended up being easier. I only needed to redo the placement of the 6 ground-stiching vias and the via of the 3.3-volt bus on that side.
I don't know if it's the most dense board that I've designed, but it's definitely one with a lot of minimum-width traces. I think that's really all I can say about it until I get boards and stuff. Silicon shortage is also affecting MCP32017 supply as well as the MCU, so double ouch in this case.
While writing this, I (obviously?) had the board layout open and such and was questioning if the extra voltage regulator would really be enough, since the theoretical maximum current draw of the display at 2 volts (their forward voltage) is 640mA. This made me want to try to measure the actual power consumption that the Airlift is using (at the 3.3 volts), and while it should be manageable by lifting the output leg of the regulator and soldering a wire to it, when I actually looked at the physical board, I didn't feel like taking the time to trying to do so. At that point, the friend that helped me name i3rd asked if it might be in the datasheet, and well I hadn't thought to check. While the datasheet doesn't give any meaningful current consumption, I did find that they recommend a minimum of 500mA supplied to the device, and with Adafruit having the 600mA voltage regulator on the Airlift board, it's probably safe to say that I can expect at most that. I did find some voltage regulators that have a maximum output of 700mA and 1A, and probably will use the 1A version so that I really don't have to worry. I was thinking to not have the Airlift's regulator add to the 3.3-volt bus on the board, but it'd probably be for the better that I don't. I might've been fine with 600mA and whatever is left over from the Airlift's regulator, considering that I don't plan on actual 100% brightness for full brightness, but desoldering the regulator to replace it will be annoying.
Having WiFi managed by a separate chip means your code is simpler, you don't have to cache socket data, or compile in & debug an SSL library.Sounds pretty promising, but...
It also works great with CircuitPython, a SAMD51/Cortex M4 minimum required since we need a bunch of RAM.Meaning that I'd need to use the ATSAMD51J19A-A, which isn't a huge deal. While I did find the most compact Airlift breakout board, I kinda wanted just the module so that I can just build my own and such, and though I did find it, half of the product description was a bit concerning.
For advanced users only! This product is just the module - which can be difficult to use. You'll need to solder it onto a board with supporting circuitry (See the Espressif's assembled ESP32 development board for a more complete design). This module is for developers at this time, and is FCC, CE, IC, MIC (Telec), KCC, and NCC certified.So yeah, not the best idea (especially when there's a solder pad underneath it that I wouldn't be able to hand solder). The guide for the breakout board makes it seem fairly easy to use with CircuitPython, but I wasn't all that concerned about the code at that time. I think I made a basic footprint for the Airlift breakout board and used vias for the signals before removing the vias later for more flexibility. What was annoying is that the mounting holes of the Airlift is neither y-aligned, nor is it the same x distance from the edge, and I figured they have their reasons for doing so.
Please note this product is for people who are comfortable compiling via the Tensilica toolchain. There are the beginnings of an Arduino IDE setup, Lua and MicroPython port. We are providing these for the community of advanced hackers, coders and makers who are willing to help make demos, projects and tutorials for the ESP32! Please consider holding off on purchase if you are not planning to contribute to the community coding efforts at this time, thank you! There are no refunds, exchanges, store credit or support in any way for this product.
I think I started the board off with the seven-segment displays (same ones as the Raspberry Pi clock) and then added the Airlift footprint (that I think still had vias) for the board size, and then had to remove the vias from the Airlift footprint because I was going to need whatever space I could get. I also had a hole in each corner of the board for the standoffs and lens, but later I removed two of them in favour of the simplicity of using the Airlift mounting holes for the same purpose. The USB mini-B jack went on the left side, the button on the right, and the MCU and transistor was plopped in the centre for later placement. For this case, I have PA24 and PA25 facing the USB connector, since I wasn't going to need any of the pins on that side.
Because of the space I would need, I needed SMT headers to connect the Airlift to the board, and also needed the same for the displays. Part of the problem was that I would also need a standoff or space between the two boards, and that I had no way of knowing the insulation height of the header that comes with the Airlift. After a bunch of digging around, I did find a header and socket header combo that came to 10mm. I ended up using the same series of socket headers for the display because it was the one with the smallest pad sizes (which technically are a reference anyway).
Anyway, I think I was planning on the same 74HC595 as the second revision (the smaller but wider package, SSOP), but I didn't have enough space to have everything run properly, so I needed a different solution. I had encountered the MCP23008 on Adafruit sometime before this project, and there was the MCP230xx library that they have, which includes the larger MCP23017. Oh right, I tried the DHVQFN16 package of the 74HC595 on the Raspberry Pi clock before I went to the SSOP/TSSOP package, but I might've tried it here before giving up on it again. Anyway, I think I started with the SSOP package of the MCP23017, but it was still hard to route stuff, so I ended up going with the QFN package. I opted to not connect the exposed thermal pad to anything for that bit of board space, that really only makes it easier to run VCC to Reset for both of them and to A0 for one of them.
A little out of order here (though honestly I think the posts after the backlog and each of those posts aren't fully in chronological order), but because I had learned about multiplexing the signals, it was pretty useful here. I'll go into it here since this would be the slightly better example than the project that kinda sparked the multiplexing. Anyway, while there is a guide from Adafruit on it, it goes the way of Arduino (I almost wanted to type Audino, thanks Pokémon) after kinda explaining it. First we have what are called SERCOM, which is short for SERial COMmunication, and each SERCOM is a module that groups different serial communication protocols together (SPI, I²C, etc). Each SERCOM has pads, which define the signal type for each of the connections to the SERCOM module, and are numbered from zero to three. Each SERCOM module can share pads with other SERCOM modules, but only with modules with the same number (SERCOM 0 can't share pads with SERCOM 1). There is a bit of a caveat, however, in that an MCU pin can be part of two SERCOM modules. Using the ATSAMD21G as an example, PA16 is SERCOM 1 pad 0 by default, but is SERCOM 3 pad 0 alternatively; this means that PA16 can be only be used with SERCOM 1 and SERCOM 3 as pad 0. In terms of I²C, pad 0 is defined as SDA, pad 1 is defined as SCL, pad 2 is defined as SDA_OUT, and pad 3 is defined as SCL_OUT; pad 2 and pad 3 are for 4-wire I²C operation. SPI is trickier than I²C, so let's start with a table I made that condenses the information from the datasheet.
Data Out Pinout (DOPO) |
Data In Pinout (DIPO) |
||
---|---|---|---|
Address | MOSI | SCK | MISO |
0x0 | PAD 0 | PAD 1 | PAD 0 |
0x1 | PAD 2 | PAD 3 | PAD 1 |
0x2 | PAD 3 | PAD 1 | PAD 2 |
0x3 | PAD 0 | PAD 3 | PAD 3 |
This table is only for ATSAMD21 or ATSAMDA1 devices!
Let's start with explaining some of these acronyms: MISO stands for Main In Secondary Out, MOSI stands for Main Out Secondary In, and SCK stands for Serial ClocK. (Main and secondary used to be master and slave respectively, but well, there's been a push to stop using these terms in favour for others. I think Adafruit uses secondary instead of serial, but I could be wrong, though I'm pretty sure it's where I got secondary from.) Also this table is only for when the MCU is being used to "host" the SPI bus, MOSI and MISO are flipped if the MCU is being used as a "client". Besides the fact that it's obvious that MOSI and SCK are data outputs and thus are in the same column, it's also because the pads to be used need to be on the same address. For example, to have pad 3 as MOSI, SCK can only be pad 1. The MISO pin can be any address, but obviously can't be a pad that's being used by MOSI or SCK. To sum up for this case, SCK can only be pad 1 or pad 3, MOSI can only be pad 0, 2, or 3, and MISO can be any of the unused pads.
The ATSAMD51 is different though, and for pads 0 and 1, the alternate SERCOM pads don't match the default SERCOM pads like the ATSAMD21. For example: PA08 is SERCOM 0 pad 0 as the default, and SERCOM 2 pad 1 as the alternative; PA09 is SERCOM 0 pad 1 as the default and SERCOM 2 pad 0 as the alternative. Weird? Yes. By this, in theory, it wouldn't matter which pin is SDA and SCL for I²C if the pins are on the same default or alternate SERCOMs. Pads 2 and 3 don't exhibit this weird flop between default and alternate SERCOMs, so it's predictable. SPI is kinda weird, but technically easier... Table time!
Data Out Pinout (DOPO) |
Data In Pinout (DIPO) |
||
---|---|---|---|
Address | MOSI | SCK | MISO |
0x0 | PAD 0 | PAD 1 | PAD 0 |
0x1 | Reserved | PAD 1 | |
0x2 | PAD 3 | PAD 1 | PAD 2 |
0x3 | Reserved | PAD 3 |
This table is only for ATSAMD5x or ATSAME5x devices!
SCK has to be pad 1, MOSI can be either pad 0 or pad 3, and MISO is, well, whatever's not already used. DOPO addresses 0x1 and 0x3 are reserved and I think it might say somewhere (either the datasheet or somewhere online) the reasoning or use for the reserved addresses. Hopefully I explained this a little clearer than the Adafruit guide, since the guide uses Arduino code to help explain it, and though I can read it, I feel like it's a little messy for someone that's using CircuitPython and trying to multiplex pins. Question you might have is "How do I use this in CircuitPython?", and well, you kinda don't. Certain Adafruit CircuitPython libraries has places to put the respective signals (
i2c = busio.I2C(SCL, SDA)
for example) and you would just put the pins you want in their corresponding places and CircuitPython takes care of the rest. From what it seems like with the Arduino, you have to actually set which SERCOM the pin will be using (or something like that) before you can tell whatever library that you want your pin to be used for SCK or whatever.What does this whole SERCOM multiplexing have anything to do with this project? It's because I needed to connect the SPI signals from the Airlift to the MCU in a direct manner without using vias to jump over other signal traces and to leave pins for I²C since I blocked off the SPI and I²C pins on the USB side of the MCU. I put the RTC (DS3231) and the temp sensor (MCP9808) at the bottom of the board and left it there while I worked on the other stuff. Though the Airlift board does have a 3.3-volt voltage regulator, I decided to add another one because I knew that one wouldn't be enough to power everything else.
Now that I think about it, the other clock project I've yet to talk about actually came first, due to the fact that its where I originally have the timezone offset set in the code while having a switch for DST control. The same is true for this project, especially since the time that it gets from NTP is UTC. Anyway, the code takes the timezone offset and adds the inverted status of the DST switch to it for the total offset before it adds it to UTC for the local time. To be able to do date and time maths, Adafruit's version of Python's
datetime
module is needed, which not only takes up quite a bit of space (30 something kilobytes), but also takes up quite a bit of memory (which isn't really said anywhere but the github page, and more of this will be covered in the other clock project if I remember). The switch for time and temp at full brightness was carried over (the idea, not the part) from the Raspberry Pi clock project, and it sat with the DST switch until I was ready to put them in their final locations.For flipping the display, I think I started with a third switch, but eventually moved to an accelerometer to make the end usage easier. It wasn't too big of a deal to add the accelerometer, since it has both I²C and SPI interfaces, the I²C traces were already running to the MCP23017 on the "button" side of the board, and there was enough space to do so. I had to hop one of the I²C traces over the other since there wasn't any other way to route the traces, and that I already needed vias to bring the signals up to the top of the board for the MCP23017.
I think I failed to mention the purpose of connecting A0 of one MCP23017 to VCC, but I'll do it now while it's on my mind. The MCP23017 has three addressing pins (A0, A1, A2) that allows the MCP23017 to have eight different addresses, and thus allowing eight MCP23017 to be on the same I²C line. For normal usage, the addressing pins are connected to ground for the default address of 0b100000 (0x20, 32), and when connecting A0 to VCC, the address becomes 0b100001 (0x21, 33). Also with this non-default address, this MCP23017 instance needs to be made with the address, otherwise it would go unnoticed or CircuitPython will raise an error that the device (which is actually the one at the default address) is already in use (or something to that effect).
I think I forgot again that I needed the pull-up resistor and cap for the reset line, so I had to make some late changes to account for it... Or maybe it was the weird pull-up resistor thing on SWDIO for programming the bootloader. With some extra space that would be able to accomodate six switches the size of the reset switch, I wanted to add some buttons, even if I never planned on having them (and thus not knowing what to have them do). Realistically, I could only do three to keep the traces fairly simple (I probably could do one more, but I didn't feel like it was worth the extra work it'd entail), and I already had a placeholder wire that I put in between a couple of traces because I didn't want to lose that bit of routing space, so one of the routes was already partially ran. I later realised that I could do capacitive touch pads instead since the pins I used also support capacitive touch, and that the force needed would be negligible compared to the tactiles that I was using (same as the reset button, but I don't know if I was looking at ones with the same or similar footprint with lower activation force). I had ideas to use a button or two for doing some sort of screen test and maybe to be able to set the timezone offset, but I haven't decided what to do them. I also haven't placed any of the touch pads since I kinda lost interest in them and in the project a bit — the silicon shortage also not helping.
Also, for the RTC's backup battery, I decided to use a CR1225 that has some solder pins welded on, so that I can solder wires to the pins and then solder the wires to the vias in the board. The battery (which would have heatshrink around it) would sit under the display at the centre, since there's no space for a coin cell holder. Routing the positive trace was a bit interesting, since I had to go around and between stuff. I don't think I have anything else to say with the board, so here's the current state of the board:
The CR1225 holder was just a placeholder to be able to connect the vias, it'll eventually be deleted.
I forgot when I did during all of this, but I did get an Airlift to poke around with the libraries and such; I was kinda curious with the WiFiManager class that should make it easier to stay connected. Another Adafruit library I found was their NTP library, which is super simple to use. The NTP object is created with the Airlift object, and
.set_time()
is called on it to set the MCU's time (the MCU of the board, not the MCU of the Airlift). .valid_time
is provided to be able to know if the NTP sync was successful or not. Setting the RTC to the MCU's time is just as easy, as it just takes rtc.datetime=time.localtime()
to do so if the sync was successful (probably obvious, but time.localtime()
is the time from the MCU). This was another reason that I decided that this project would be better than the Raspberry Pi clock, as I had a lot more unanswered questions with the Raspbery Pi clock that would require testing I didn't feel like putting in the effort for. One of them was if I was still able to access the RTC if it's given to the system, and I had assumed not, so setting the clock via the OS required a shell script and tweaking the list of sudoers was the route I would've needed to go. The other question was if I would even be able to access the I²C line at all, because of the former. With this project, I have a lot less worries about the I²C lines and device access.I did also use the ATSAMD51J19A-A dev board to test out the automatic syncing of the RTC module I have, and it worked fine since I had to set the RTC module time for the third time. I forgot which project I was working on, but I was using the RTC module to test out the 32kHz output pin and when hooking it up, I didn't realise that I swapped VCC and ground, so while I got nothing, the RTC, board, and backup battery were heating up. I forgot how I realised it, but I did and unplugged the board while heading to the soldering station for one of the fans to cool it down. I was worried that I fried the RTC, but when it was cool enough, it worked just fine and had just lost the set time. I think I had read in the datasheet or somewhere that the 32kHz output only works when the RTC recieves power on VCC, so it was what I was trying to test for, but I didn't have any luck getting a good reading. I had also read that I would need a pull-up resistor for the 32kHz, and I had soldered a 2.2 kilohm resistor according to the post I read (datasheet says anywhere between 1k and 1M) before the test. I also had desoldered one leg of the resistor during the test because I was having troubles getting a reading, but it didn't seem to make a difference. I was using the oscilloscope I use at work because it was more convenient than the one at home (which is some leftover one from work), but got some funky waveform, and tried it on the the oscilliscope that the electrical engineer uses and still got the same weird waveform. I think this is what sparked me to try the one I have at home and either I had the reversed polarity fiasco then or it was before all this, I really can't remember. Regardless though, I ended up getting the frequency metre to read the 32.768kHz it was supposed to read and the wave was square and was close enough to 32kHz. I took the RTC to work again the next day and also got the correct waveform. I know I had some sort of suspicion that it might have something to do with the ground line of the oscilloscope connected to the bench power supply, but it didn't seem to be it. I think with the initial test with the oscilloscopes at work, I did try using the little probe grounding thing with no avail. Dunno what happened, but well, I got what I was looking for in the end. The second time I did the reverse polarity thing was while setting up for the automatic syncing test, and well, I had more of a reason to do it after it cooled down enough.
Anyway, the reasoning for the 32kHz output pin was to see if I might be able to use that instead of having a dedicated crystal circuit for the MCU, and from the post I previously linked, it should be doable. I checked the datasheet for which pin to connect to since one of the two crystal pins is the output and one is the input. I keep forgetting where I read it (it was some Adafruit thing, I know for sure), but the MCU uses the USB pulses for timekeeping on boards that don't have a crystal (or something like that). Since the clock would be connected to some USB charger, it probably wouldn't get the pulses, so I needed to add a crystal in some way. Using the 32kHz output was a lot more space efficient because it would've been a tight fit to get a crystal and its caps near the crystal pins (PA00, PA01). Routing was kinda interesting because I was thinking to redo some traces and kinda take a long way around, but decided to try running it the other way while hugging other traces, which ended up being easier. I only needed to redo the placement of the 6 ground-stiching vias and the via of the 3.3-volt bus on that side.
I don't know if it's the most dense board that I've designed, but it's definitely one with a lot of minimum-width traces. I think that's really all I can say about it until I get boards and stuff. Silicon shortage is also affecting MCP32017 supply as well as the MCU, so double ouch in this case.
While writing this, I (obviously?) had the board layout open and such and was questioning if the extra voltage regulator would really be enough, since the theoretical maximum current draw of the display at 2 volts (their forward voltage) is 640mA. This made me want to try to measure the actual power consumption that the Airlift is using (at the 3.3 volts), and while it should be manageable by lifting the output leg of the regulator and soldering a wire to it, when I actually looked at the physical board, I didn't feel like taking the time to trying to do so. At that point, the friend that helped me name i3rd asked if it might be in the datasheet, and well I hadn't thought to check. While the datasheet doesn't give any meaningful current consumption, I did find that they recommend a minimum of 500mA supplied to the device, and with Adafruit having the 600mA voltage regulator on the Airlift board, it's probably safe to say that I can expect at most that. I did find some voltage regulators that have a maximum output of 700mA and 1A, and probably will use the 1A version so that I really don't have to worry. I was thinking to not have the Airlift's regulator add to the 3.3-volt bus on the board, but it'd probably be for the better that I don't. I might've been fine with 600mA and whatever is left over from the Airlift's regulator, considering that I don't plan on actual 100% brightness for full brightness, but desoldering the regulator to replace it will be annoying.
28 June 2021
Apple Keyboard II Revival
For those that might remember, I originally tried to revive the Apple Keyboard II with a Teensy 2.0 (link), but it ultimately failed. I did kinda poke around with it again recently, but still couldn't get it to work. Anyway, with my CircuitPython/MCU "craze", I decided the next best way is to just make my own controller board for it.
The first thing to do was to figure out the array of the membrane keyboard, which was annoying to do but still doable. What was interesting to find was that the modifier keys (control, shift, option, command, caps lock) had their own rows but all had ground as the column. Another interesting thing I found was that the right and left shift keys were tied together, so pressing left shift is no different than pressing right shift — they were both on the same row. I used a spreadsheet later on to clean up the array map and to map the positions of the membrane to the MCU pins.
Another thing I had to do was to get some of the board dimensions and such, but it was a little tough to get reference points because the board's size from the tolerance that Apple put in. I figured out to use the centre of the tactile switch as a reference point because there's a boss in the case underneath the board where the centre of the tactile is (or rather, supposed to be because the boss' circle and the tactile switch's circles are not concentric). I had to go back a lot to get dimensions that I didn't think about and it was a bit annoying having to get the keyboard out and open it multiple times.
I was thinking to use the original FPC connector and desoldered it before measuring the via spacing on the board for it, and came up with some weird numbers, but kinda went with it. I had also looked to see if I could find something that was close or would work, and I think I had found a part, but it was obosolete or non-stocked. Later on, I thought to check the entirety of the spacing or to take the spacing and divide it accordingly, and with measuring centre to centre of the first and last vias, I found that the spacing I originally had wouldn't've worked; I think I also confirmed the issue with the spacing on the keyboard's FPC cable. With this, I realised that the connector was metric and searched for a part using metric dimensions (1.25mm pitch instead of 1.27mm) and found a compatible part that's active and in stock. Looking at its datasheet, I decided to go with it because it was narrower or shorter (I don't remember which) than the original part, which would give me a bit more board space.
One of the things I wanted to keep was the ability to plug the keyboard in from either side, but this was a little easier said than done because I wanted to keep the board cost as low as possible and also trying to avoid running long traces for the D+ and D- USB signals. I decided having remote boards would probably be the best option, but I would need to connect them. For the right side, I decided to use an internal USB cable because of the ~20cm distance, and for the left, I decided on an FPC cable. Because of the internal connections, I wanted to have a way to be able to check if the cables were connected (well one of them would have to be connected for the MCU to get power to do so), so instead of having just 4 connections for each USB signal, I needed 5. The FPC was easy, but the internal USB connection gave me trouble. I wanted to use USB-C because of its size and such, but it seems like the spec says to connect shield to ground because of all the USB-C cables that I have, shield is always tied to ground. What I needed was a shield to shield connection so that I can use it to carry the high signal from the MCU over to the remote board where it would connect to ground (getting the far-side connection status is more useful than the near-side connection status). I had also thought about using USB micro-B, but it was hard to tell if the shield-shield connection was there in the datasheet, and there wasn't any connectors that were easy to hand solder fully (there's usually a couple pads underneath the shell that requires solder paste and reflowing to fully secure the connector to the board). I settled on using USB mini-B on both sides and using a short USB mini-B cable (USB A male to mini-B male) and a short USB mini-B adapter cable (USB A female to mini-B male) for the connection between the boards, and confirmed the shield-shield connections in both items. For the USB connection between the keyboard and the computer, I went with USB B because it's the only option to fill out the ADB port (really, a 4-pin mini-DIN) cutout.
With two USB outputs to the computer, I needed to keep them separate for minimal weirdness, so I opted for a signal relay to do this. I connected a diode between the 5 volts of the USB and the 3.3-volt voltage regulator to keep the two 5-volt lines separate, and behind the diode, I have a small trace running to an inverting level shifter so that the MCU would know which side the power's coming from and adjust the latching relay accordingly. The main problems were that I had the FPC connector for the keyboard in the middle of the board, I wanted to keep the USB traces on the board as short as possible, and that the relay and USB mini-B connector take up quite a bit of space. I also wanted the MCU on the top side of the board to kinda show it off (well, whenever the keyboard was opened up), but I eventually opted to put it on the bottom of the board because I didn't have any other choice. I was going to use a latching signal relay that I had used before (probably one of the soundcard switching ones) which takes up a small area while being kinda tall, but I had to switch to one that took up more area for a reduced height. Originally, I wanted the relay in the top-right corner of the board because of the amount of space that's above the board, but to keep the USB traces sane, I moved it to below the keyboard FPC connector. I also wanted the mini-B connector in the top right, but again, sensible trace routing made me move it to below the FPC connector.
Exact placement of the MCU was weird, it had to be above the FPC vias, but had to keep the pads and traces away from the boss under the tactile and the stabilisation boss next to the tactile. I put the pad egdges a millimetre away from the FPC vias, but had to wait until I had the airwires and some traces in before I could figure out its x position. I also had to do some pin swaps and rerun traces to make it a little easier/cleaner and such.
At some point, I decided to add a piezo buzzer for num lock indication originally, but it evolved into also indicating a broken internal connection (assuming the MCU can get power) and indicating that both sides of the board are plugged in (which would probably very difficult to do, but if it did happen, the MCU wouldn't know which way to switch the relay). I think the piezo buzzer was another piece that made laying out parts weird? It went into the top-right corner.
Board retention is another issue, and I decided to have a 3D-printed part that would make it so that I could screw the boards to the part and set the assembly into the bottom case for the boards to be in a stable position and to not have to try to design the boards for friction-fit placement.
I wanted to try to make one board for both sides, and there was a lot of back and forth between being able to do so and not, but when I did straighten out the insides of the case, I was able to do one for both sides. I was wanting to use the through-hole USB B connector that I used for the cooling/charging station that I never talked about, but because the nature of through-hole parts and the way the board would be, I decided an SMT version would be better. The problem with the SMT versions is that the pads for the shell were not within the design rule region because of where I had the edge of the board, but eventually I moved the edge of the board a little further away because there wasn't anything else I could do. Placement of the other connectors was weird because I had quite a bit of space for the FPC connector and I didn't have a length for the board yet. I think it was after getting the mounting holes and such that I was able to get the connectors into place. With the FPC connector in place, I was able to get a distance to base the length of the FPC cable on (since pre-made FPC cables come in certain sizes and is cheaper than making my own via OSH Park).
The caps lock key is kinda unique in that it is a locking switch, so it clicks into and out of place when you turn it on or off, and because modern keyboard controllers just toggle the caps lock state, this presented a problem. Back when I was fiddling around with the Trinket M0 and keyboard HID library, there was a way to get the lock status with the USB HID library, but it was awkward, but with some update, it was moved to the keyboard HID library and was easier to use. Anyway, the way to solve the problem of properly sending the caps lock toggle with a locking caps lock key is to send the key input whenever the state of the switch is not the same as the caps lock status. For handling the keyboard keys, I used Adafruit's matrix keypad library, which made it a lot easier than having to write the code myself (and I was ready to because I knew how to).
Because Apple's numeric pad section is different than ones for PCs (even still to this day), I was going to move keys around to keep the layout consistent with PCs, but because Apple still uses the same layout, I moved them all back. There is no num lock key, instead it's "clear", but since it's the same key ID, it would be num lock anyway. Because they clear key would be the num lock key, there had to be some sort of indication for num lock status, which I solved with the piezo buzzer. Whenever the num lock turns on, the buzzer sends two ascending notes; the buzzer would send two descending notes when the num lock turns off. I did it this way instead of using LEDs of some sort because I didn't want to modify the case. I also had an idea to use a level shifter to drive the piezo at 5 volts instead of 3.3, and while it is louder, it doesn't seem to fully like it. I also need to test it with a transistor between the piezo and ground to control the volume, so that it might be louder than when at 3.3 volts, but doesn't do the weird thing that it does at 5.
I have the power button set as a funciton key and have a filter set in the code so if there's a set function key, it would strip the corresponding keys out of the pressed keys list before inserting the new key. For example, function and left arrow I have set as home, so in the list of pressed keys, left arrow would be removed and home would be inserted into the list.
Besides the silicon shortage screwing with MCU availability, I still need to get the dimensions I need to CAD the "liner" piece that holds the boards, and I also need to CAD the piece that helps reduce the movement of the USB B connector.
The first thing to do was to figure out the array of the membrane keyboard, which was annoying to do but still doable. What was interesting to find was that the modifier keys (control, shift, option, command, caps lock) had their own rows but all had ground as the column. Another interesting thing I found was that the right and left shift keys were tied together, so pressing left shift is no different than pressing right shift — they were both on the same row. I used a spreadsheet later on to clean up the array map and to map the positions of the membrane to the MCU pins.
Another thing I had to do was to get some of the board dimensions and such, but it was a little tough to get reference points because the board's size from the tolerance that Apple put in. I figured out to use the centre of the tactile switch as a reference point because there's a boss in the case underneath the board where the centre of the tactile is (or rather, supposed to be because the boss' circle and the tactile switch's circles are not concentric). I had to go back a lot to get dimensions that I didn't think about and it was a bit annoying having to get the keyboard out and open it multiple times.
I was thinking to use the original FPC connector and desoldered it before measuring the via spacing on the board for it, and came up with some weird numbers, but kinda went with it. I had also looked to see if I could find something that was close or would work, and I think I had found a part, but it was obosolete or non-stocked. Later on, I thought to check the entirety of the spacing or to take the spacing and divide it accordingly, and with measuring centre to centre of the first and last vias, I found that the spacing I originally had wouldn't've worked; I think I also confirmed the issue with the spacing on the keyboard's FPC cable. With this, I realised that the connector was metric and searched for a part using metric dimensions (1.25mm pitch instead of 1.27mm) and found a compatible part that's active and in stock. Looking at its datasheet, I decided to go with it because it was narrower or shorter (I don't remember which) than the original part, which would give me a bit more board space.
One of the things I wanted to keep was the ability to plug the keyboard in from either side, but this was a little easier said than done because I wanted to keep the board cost as low as possible and also trying to avoid running long traces for the D+ and D- USB signals. I decided having remote boards would probably be the best option, but I would need to connect them. For the right side, I decided to use an internal USB cable because of the ~20cm distance, and for the left, I decided on an FPC cable. Because of the internal connections, I wanted to have a way to be able to check if the cables were connected (well one of them would have to be connected for the MCU to get power to do so), so instead of having just 4 connections for each USB signal, I needed 5. The FPC was easy, but the internal USB connection gave me trouble. I wanted to use USB-C because of its size and such, but it seems like the spec says to connect shield to ground because of all the USB-C cables that I have, shield is always tied to ground. What I needed was a shield to shield connection so that I can use it to carry the high signal from the MCU over to the remote board where it would connect to ground (getting the far-side connection status is more useful than the near-side connection status). I had also thought about using USB micro-B, but it was hard to tell if the shield-shield connection was there in the datasheet, and there wasn't any connectors that were easy to hand solder fully (there's usually a couple pads underneath the shell that requires solder paste and reflowing to fully secure the connector to the board). I settled on using USB mini-B on both sides and using a short USB mini-B cable (USB A male to mini-B male) and a short USB mini-B adapter cable (USB A female to mini-B male) for the connection between the boards, and confirmed the shield-shield connections in both items. For the USB connection between the keyboard and the computer, I went with USB B because it's the only option to fill out the ADB port (really, a 4-pin mini-DIN) cutout.
With two USB outputs to the computer, I needed to keep them separate for minimal weirdness, so I opted for a signal relay to do this. I connected a diode between the 5 volts of the USB and the 3.3-volt voltage regulator to keep the two 5-volt lines separate, and behind the diode, I have a small trace running to an inverting level shifter so that the MCU would know which side the power's coming from and adjust the latching relay accordingly. The main problems were that I had the FPC connector for the keyboard in the middle of the board, I wanted to keep the USB traces on the board as short as possible, and that the relay and USB mini-B connector take up quite a bit of space. I also wanted the MCU on the top side of the board to kinda show it off (well, whenever the keyboard was opened up), but I eventually opted to put it on the bottom of the board because I didn't have any other choice. I was going to use a latching signal relay that I had used before (probably one of the soundcard switching ones) which takes up a small area while being kinda tall, but I had to switch to one that took up more area for a reduced height. Originally, I wanted the relay in the top-right corner of the board because of the amount of space that's above the board, but to keep the USB traces sane, I moved it to below the keyboard FPC connector. I also wanted the mini-B connector in the top right, but again, sensible trace routing made me move it to below the FPC connector.
Exact placement of the MCU was weird, it had to be above the FPC vias, but had to keep the pads and traces away from the boss under the tactile and the stabilisation boss next to the tactile. I put the pad egdges a millimetre away from the FPC vias, but had to wait until I had the airwires and some traces in before I could figure out its x position. I also had to do some pin swaps and rerun traces to make it a little easier/cleaner and such.
At some point, I decided to add a piezo buzzer for num lock indication originally, but it evolved into also indicating a broken internal connection (assuming the MCU can get power) and indicating that both sides of the board are plugged in (which would probably very difficult to do, but if it did happen, the MCU wouldn't know which way to switch the relay). I think the piezo buzzer was another piece that made laying out parts weird? It went into the top-right corner.
Board retention is another issue, and I decided to have a 3D-printed part that would make it so that I could screw the boards to the part and set the assembly into the bottom case for the boards to be in a stable position and to not have to try to design the boards for friction-fit placement.
The (likely final) mainboard with notes and such.
I wanted to try to make one board for both sides, and there was a lot of back and forth between being able to do so and not, but when I did straighten out the insides of the case, I was able to do one for both sides. I was wanting to use the through-hole USB B connector that I used for the cooling/charging station that I never talked about, but because the nature of through-hole parts and the way the board would be, I decided an SMT version would be better. The problem with the SMT versions is that the pads for the shell were not within the design rule region because of where I had the edge of the board, but eventually I moved the edge of the board a little further away because there wasn't anything else I could do. Placement of the other connectors was weird because I had quite a bit of space for the FPC connector and I didn't have a length for the board yet. I think it was after getting the mounting holes and such that I was able to get the connectors into place. With the FPC connector in place, I was able to get a distance to base the length of the FPC cable on (since pre-made FPC cables come in certain sizes and is cheaper than making my own via OSH Park).
The remote board and such.
The caps lock key is kinda unique in that it is a locking switch, so it clicks into and out of place when you turn it on or off, and because modern keyboard controllers just toggle the caps lock state, this presented a problem. Back when I was fiddling around with the Trinket M0 and keyboard HID library, there was a way to get the lock status with the USB HID library, but it was awkward, but with some update, it was moved to the keyboard HID library and was easier to use. Anyway, the way to solve the problem of properly sending the caps lock toggle with a locking caps lock key is to send the key input whenever the state of the switch is not the same as the caps lock status. For handling the keyboard keys, I used Adafruit's matrix keypad library, which made it a lot easier than having to write the code myself (and I was ready to because I knew how to).
Because Apple's numeric pad section is different than ones for PCs (even still to this day), I was going to move keys around to keep the layout consistent with PCs, but because Apple still uses the same layout, I moved them all back. There is no num lock key, instead it's "clear", but since it's the same key ID, it would be num lock anyway. Because they clear key would be the num lock key, there had to be some sort of indication for num lock status, which I solved with the piezo buzzer. Whenever the num lock turns on, the buzzer sends two ascending notes; the buzzer would send two descending notes when the num lock turns off. I did it this way instead of using LEDs of some sort because I didn't want to modify the case. I also had an idea to use a level shifter to drive the piezo at 5 volts instead of 3.3, and while it is louder, it doesn't seem to fully like it. I also need to test it with a transistor between the piezo and ground to control the volume, so that it might be louder than when at 3.3 volts, but doesn't do the weird thing that it does at 5.
I have the power button set as a funciton key and have a filter set in the code so if there's a set function key, it would strip the corresponding keys out of the pressed keys list before inserting the new key. For example, function and left arrow I have set as home, so in the list of pressed keys, left arrow would be removed and home would be inserted into the list.
Besides the silicon shortage screwing with MCU availability, I still need to get the dimensions I need to CAD the "liner" piece that holds the boards, and I also need to CAD the piece that helps reduce the movement of the USB B connector.
Subscribe to:
Posts (Atom)