Archives for category: Uncategorized

A few weeks ago my house was burgled, and the thief stole most of my construction tools. I was devastated. However, my friends came together and created a fund that has enabled me not only to replace the stuff that was stolen — I’ve also been able to add a big new tool. Wow, my friends are great!

The tool I added is a SawStop Jobsite Table Saw. I got it for a lot of reasons; here are the top two. First, I want a table saw big enough to cut big plywood but small enough to store in the garage. This one is pretty easy to move around on its integrated hand truck.

Second, I wanted a saw with tech that recognizes a finger and refuses to cut it off. I’m very, very impressed by the testimonials from YouTubers I admire (like this one and this one) about how the SawStop actually stopped and they walked away from a situation where they could have been very seriously injured.

A table saw blade turns about 4000 rpm, the teeth are moving at about 200 feet per second, around 1365 mph. The teeth point toward the user (into the board you’re cutting), so the teeth can (and sometimes do) catch a finger and pull it into the blade. It happens so fast that you can be seriously injured multiple milliseconds before a signal can make its way to your brain. I decided to do the math.

A signal from hand to brain takes about 20-40 milliseconds (that’s just the transmission time, not considering any thought from the brain, let alone a reaction and retransmission). In half the shortest possible transmission time, 10ms, the teeth on the blade move about 2 feet. There are 50 teeth on my blade, so in 10ms, about 30 teeth pass through a given point. When I hit my hand slowly on just one tooth (like when I’m installing a blade), I get a good nick. 30 teeth (driven with effectively infinite power) could easily sever a finger in half the time it would take for the signal to reach my brain.

This model has a capacitive touch sensor in the blade. When it touches something conductive, like, say, a finger, it stops in <0.0004 seconds, which is less than the travel time for one blade tooth. The videos and testimonials are amazing. I love the one where they push a piece of steak into the blade and it stops with only a tiny nick. I bought this model bc I think it will reduce the chance of losing something important when I’m distracted for an instant.

However, I’m a little sad I can’t also have a hyper-precise Byrnes Mini Saw. It looks absolutely gorgeous. However, they’re not being made right now, and it would really be too small for anything other than building small enclosures for my electronics. But then again, most of what I want to do is build small enclosures. You can see the dilemma.

Availability won out, and I got the SawStop. Right away I noticed that making cuts with the fence isn’t precisely square. The key test is to cut a board on each side in turn, and then check square on the final cut. A simple cut using the saw’s fence is not all that close: look at all the light under the rule.

I decided to build a cross-cut sled, which seemed to me perhaps the most fundamental helper tool for a table saw. I followed the basic pattern described by Tamar at 3×3 Custom, though mine is somewhat simpler. There are tons of videos online about how to do this, so I’ll hit the highlights:

  • cut plywood for the back and front fence; I used two sheets of 1/2" glued together. I clamped them to a monster 1/4" thick chunk of aluminum L frame I have from an old project to make sure that as the glue dried, the fences stay as flat as possible. After they dried, I trimmed them so they are flush.
  • I cut runners out of a maple board; I used the sneak-up-on-the-cut method that Newbie Dan describes. I don’t know whether I cut the strips properly to account for how they shift with the weather. I used a Grr-Ripper to control the wood as I cut it. (btw I like the Grr-Ripper a lot).

The image below is the bottom of the sled after I secured the back fence with a zillion screws.

The sled itself is about 18" deep by 24" wide, with a big chunk cut off the back left where I don’t think I need too much support and I can reduce weight (this idea comes from Tamar).

By far the most important part of the sled is getting the back fence perpendicular to the blade. There’s an amazing trick for this, invented by William Ng, called the "five-cut" method. The idea is to cut a board on each side in turn. The error (i.e., the amount the cut differs from perpendicular to the blade) compounds with each cut because the cut side becomes the base of the next cut. The amplification of the error makes it easier to measure and to correct.

I’ll leave the explanation of the method to others – there are tons of great explanations of how to do the cuts and the calculations. Here’s my final cut with the associated measurements.

(note: the A measurement is 1.1700, and B is 1.1575; when. I wrote on the board, I omitted the ‘1’ in the tenths position, oops). From this, you can calculate that my sled’s error is ((A-B)/4)/len(test) = 0.00033 per inch. That is, cuts made with this sled will be off square about 3 ten-thousands of an inch over every inch of cut.

So if I cut a board 24" square, the diagonal in one direction would be around 0.02" different from the diagonal in the other direction. I can definitely live with that! Of course this sled is too small to cut 24" square, but you get the point.

This is a first attempt. The runners aren’t great, the fences should be 3/4" rather than 1/2", and the whole thing should be made of higher-quality plywood. But it’s a great "hello, world" with my new saw.

And it’s a great lesson that in woodworking (probably in other areas, too), the great tool only gets you part of the way. There’s some skill, sure, but also some technique (which isn’t quite the same as skill).

Finally, I’m really glad to have a way to cut seriously square. This is a great first post-burglary project. I’m deeply grateful to my friends.

PS: yes, we changed & upgraded all the locks, and we added cameras that save video to an online repository (the "cloud"), but crucially for me, the cameras do not connect to the police. And in the garage, the saw is chained to a bolt drilled & epoxied into the foundation. Of course we could be burgled again, but it’s going to be tougher for the next thief.

After many years, my 2012-era MacBookPro began rebooting so often that I could not continue. Furthermore it was often losing track of Arduinos plugged into the USB, and while that may have been an issue with the Arduino IDE, I was unable to fix it, and it was annoying.

Let’s take a minute to honor the MacBookPro. It’s been to Burning Man at every year since 2015, I’ve taken it to around 20 countries, I wrote an immense amount of code, email, and prose on it. It hasn’t been my primary work computer for at least 5 years, but it’s been in the lab, and it’s been the host for a stack of thunderbolt-connected RAID drives. It’s a very fine little beast, and I expect it will have a dignified retirement.

However, after the fifth reboot of the antique MacBookPro in a single day a couple weeks ago, I lost patience and bought a System76 Meerkat mini. I’ve been a happy manager of a System76 server for about five years (it’s been great except for a frequently-failing cooling system that I’ve replaced 4 or 5 times now), so I’m happy to do more business with these folks.

But while I waited for the new computer to be delivered, I managed to use a RaspberryPi 4 to program some Arduinos using vim, python, and platformio (platformio is amazeballs). I’d had a lot of trouble getting platformio running under MacOS, which is weird and surprising, but under rasbian-linux, it Just Worked. Using a RPi as if it was a real computer was great! It got me psyched for a new desktop linux machine.

I used desktop+laptop linux from about 1999-2007. I tried again in 2015, and it wasn’t successful. There are too many little connections that Apple makes completely transparent that I couldn’t get a linux box to do, even with a huge amount of fiddly work. However, I think that in the lab it should go better. Here I think around 95% of my work is in a browser and a terminal, and linux should do well.

The Meerkat arrived yesterday, and it’s totes adorbs. In the photo above, it’s mounted on the wall on the right. The photo below shows the unboxing.

It’s just a box. Put video in with HDMI, attach a keyboard+mouse, add a network connection, and we’re off!

First, the Pop!OS is a terrific set of themes for gnome. It looks fantastic, and so far I’m really enjoying their version of tiling windows and workspaces. The hardware and the GUI tuning make the UI as responsive as anything I’ve ever used. The keybindings are all a little off from my MacOS muscle memory, but it’s close enough.

In about a half-hour, I had my key apps running: the Arduino IDE from the pop shop, Spotify from Ubuntu’s snap installation utility, and Scopy for the M2K multi-instrument in a flatpak.

It’s weird to have all these different package managers. There’s the "pop shop" and of course apt-get (because Pop is Ubuntu which is Debian), and snap and flatpack and the Adruino IDE’s library manager. I use anaconda python and I can add libraries with conda but also directly through python’s pip. For math, I use RStudio which leverages the Comprehensive R Archive Network, and the TinyTex package to write Rmarkdown and LaTeX. TinyTeX uses the tlmgr manager for LaTeX sty files. Platformio manages it’s own libraries for microcontroller hacking. Even my editor has it’s own package manager.

It’s going to be a headache to keep these straight, esp popshop-apt-snap-flatpak mix. I know that I’ve had issues keeping conda and pip straight, so this is going to be a little challenging. But for now, everything on this list is working (with one exception, see the next graf). And best of all, it all worked pretty much just by installing with the aforementioned package managers. I’m impressed.

There’s a confusing partial-overlap between the UI settings managed by gnome-tweaks and those in the Pop!OS settings app. For example, to turn on the unix-standard readline keybindings for within-text navigation, and to fiddle with gnome-menu-extensions I had to use gnome-tweaks. Then it didn’t work until gnome-shell was rebooted some arbitrary and large number of times. But it did start working! Maybe I’m missing something in the settings app. All this said, the GUIs for settings are miles ahead of last time I played with desktop linux.

So far, nearly everything has worked almost without having to google a weird error message. The piece that doesn’t work yet is Scopy+M2K. For some reason, Scopy doesn’t see the M2K on the USB connection. The kernel sees the M2K, which I can tell by dmesg. I’ll figure this out. edit: after adding the ADALM2000 udev rules and a bunch of reboots, it just started working. Well, ok, then.

My initial impression is that the Meerkat is fantastic. It’s tiny, reasonably cheap, powerful as all heck. The software System76 has prepared is really first-rate. Well done, FLOSS vendor! So far I’m a v happy customer.

I got a ADALM2000 from digikey. It arrived quickly and without incident.

This device connects to a computer via USB and enables a lot of different measurements and kinds of signals. It doesn’t have a screen or controls, everything happens through the software on the laptop. I’ve been shopping for an arbitrary waveform generator, and this little box offers a pretty solid set of features for waveforms. In addition, it has a ton of other features, some of which I didn’t know about. It’s just arrived, so let’s take it for a spin.

First, I’m using this on MacOS 10.15.3, and the documentation says to install device drivers so the M2K is recognized by the operating system. The software they suggested gave errors when I tried to install it, but it turned out to be unnecessary anyway. I installed the control software, Scopy. And as all the best YouTubers say, let’s get started.

The device was incredibly easy to install and attach, so I’m going to skip that part. We forget about the stuff that Just Works. It’s a little annoying to have to figure out which of the many F dupont leads is the one I’m supposed to use for each feature, but I suspect I’ll just leave more useful leads in the appropriate connections.

The oscilloscope is the first tool. I attached it to my oscilloscope’s signal generator which emits a constant 1kHz square wave. And it looks exactly right. I didn’t play with the triggers, but the timebase and the volts/division were easy to set. Even easier was the autoset feature – it made a pretty good decision. I can imagine all the rest of the oscope stuff working pretty easily.

The network analyzer is another tool I’ve never used before. As far as I can make out, it’s basically a tool to test electronic filters. It generates a "stimulus" which it puts into the circuit. We measure the circuit at it’s input (going into the resistor) and its output (at the junction between the resistor and a capacitor). The resulting curve on the response channel shows how different frequencies are permitted or attenuated by the filter. The filter I put together (with a 1K resistor and a 2.2nF cap) starts attenuating at 1kHz and is strongest at 10MHz. Interesting.

I bought this thing for the waveform generation. I attached the W1 lead to my oscope’s lead, and GND to GND. I set it to a sine wave at 1kHz at 1v peak-to-peak, and it’s dead on. It’s also dead-on at 1MHz (shown), but it tops out at 30MHz, and at that speed, the signal is a tiny bit wobbly. To be fair, these are unshielded leads, and I think this speed is pushing my oscope’s ability to capture the signal reasonably, so I’m impressed.

The square wave is a little less stable. At 10MHz it’s a wobbly mess. However, by 1MHz, it looks square and stable. Similarly the triangle was wobbly at 10MHz but looks great below around 4MHz. In the image below, the sawtooth at 3MHz is a little wobbly.

There are the usual waveforms (sine, square, triangle, sawtooth) and options to input user-generated waves or output from math functions. This is exactly what I wanted. Just this is enough to make me pretty happy with this device.

The logic analyzer might for me be this device’s killer app. This is for figuring out whatever is going on in digital signals. I want to know.

I’ve been playing with some APA102 LEDs (Adafruit calls these DotStars) and a Teensy4. I write into the LEDs using the FastLED library. The protocol that the software on the Teensy uses to shove bytes down the wire is called SPI.

The wires that go to the LED strand go through a chip called a 74HCT245. This chip shifts the voltage from a barely readable-400mV to a stable 0/5v LOW/HIGH pattern. I’ve been curious if anything else happens in this chip, like say, a bunch of noise.

The logic analyzer lets me read the signals as they go through the line. Even more cool, it freakin’ decodes the signals so I can see what’s going on. In th eimage below, channels DIO1 and DIO3 measure the clock signal. Whenever the clock rises, the LED chips read the signal (HIGH or LOW) on the data line (which is measured on DIO0 and DIO2). Signals DIO0 and DIO1 are measured coming out of the Teensy, while DIO2 and DIO3 are measured coming out of the 74HCT245. This enables me to compare the two to see if they differ.

All this is happening one million times per second. Wow. This is a great tool.

The pattern generator creates digital patterns like the ones that the logic analyzer reads. In some sense, a signal generator is to an oscilloscope as a pattern generator is to a logic analyzer.

The digital IO is pretty easy to figure out: you can put a 5v signal on a channel, or measure one. Since there are 16 channels, that makes this a pretty convenient breadboard helper.

The voltmeter is interesting. First off, it’s helpful to have two channels. But be clear: this is a "voltmeter" in a sense similar to Adafruit’s fantastic ina260 measurement board. It’s delicate, will fry from reverse voltage, and has a very limited range. And it’s not all that accurate.

I connected the Adafruit LM4040 voltage reference board. I used the M2K voltmeter first on the high reference voltage. It should be 4.096v, but my Siglent SDM3055 says 4.103v (the Siglent is still within its calibration period). Meanwhile, the M2K thinks the voltage is somewhere between 4.055 and 4.162, a range of over 100mV. In this case, the truth does indeed lie in the middle, but that’s a wide range. Checking the low reference (nominally 2.048v), I see 2.0505v on the Siglent, but 2.007-2.078v on the M2K; it’s in range but has trouble figuring out where. I measured the voltage coming out of the power supply and found it to be a little high (5.044-5.142v): my antique but very reliable Fluke 45 says 5.005v.

The last tool on the M2K is a low-current power supply (good for up to 50mA). To use this, you have to attach a second USB cable. Ok. I measured both the positive and negative supplies over a 390K resistor. The power supply says it’s delivering 2.999v and the Siglent reports 2.999v; on the negative side, similarly the reported VDC is within 1 mV of what I’m measuring. Nice! It’s really helpful to have a negative power supply to prototype op-amps. For very low current applications, this is a great addition. I wonder if it has a fuse? Or short protection? (It’s an open source tool, so I could look up the schematics) I really needed another power supply, so this is a great addition to my bench.

Cons

What don’t I like? Well, the docs are horrible. There are basically no wiring examples (except for the network analyzer). Much of the documentation just narrates what I can see in the software without telling me how to set it up or why I should use it.

Possibly the more meaningful documentation is in what looks like a very impressive set of lab exercises that are a companion for the M2K. I’m looking forward to reading through it all.

The device feels cheap and crappy. The leads don’t fit smoothly into the housing. The dupont leads are definitely going to break or bend or otherwise become trash pretty quickly. I’m amazed that they didn’t print a sticker for the pinouts like their really useful internals diagram. I’ll be adding that.

And as I’ve mentioned, the voltmeter isn’t very good.

Pros

These minor issues aside, the M2K is a fantastic tool for my bench. The Scopy software is really good. The device has done exactly what I expected, and the software was a big help. I love that it’s open source hardware. I’m excited to log more stuff which this will make really easy. The ADALM2K + Scopy will complement my other bench instruments (power supply, multimeters, oscilloscope) by adding a few more channels and slightly easier logging. Adding the analyzers, generators, and digital IO, and we have a great package. I look forward to a lot more fun with this thing.

So I’ve wanted to do a project that accomplished several goals. First, I need more blinky stuff in my lab. What good is a lab if there aren’t bunsen burners bubbling, inscrutable machines whirring, and, best of all, little lights blinking?

Second, I wanted to learn how to use basic integrated circuits, and one of the most useful and classic is the 74HC595. This chip is a shift register which means that it takes a serial input and writes it to 8 parallel outputs. You can chain several of these together, and so still using only 3 wires from a microcontroller (like an Arduino, which is what I’m using here), drive 24 signals. Here’s what it looks like on an oscilloscope:

These are the signals from the Arduino to the 74HC595. Let’s read the oscilloscope from the bottom up. The purple line is the latch. When this signal is pulled LOW, the 74HC595 listens for data. The blue line in the middle is the clock: when it rises from LOW to HIGH, the 74HC595 checks the input signal. So when the blue line rises on the left, the 74HC595 checks the signal measured by the yellow line (called serial), and sees that it’s HIGH. That’s a 1. The blue line cycles down, then back up, and the 74HC595 reads again: another 1. And so forth, in my case, for 24 bits.

When the latch is set, the bits are pushed into the chip. Each 74HC595 only remembers 8 bits, so if there are more, it pushes the rest out on pin 9, called $Q_H’$, which is read by the next chip (if there is one). I chained 3 chips together, thus 24 bits in each latch-unlatch cycle. This all happens in about 450 microseconds, which is pretty fast for people, but pretty slow for electronics (this means we could only do about 2000 of these cycles per second). This chip was invented in the early 1980s, though there were very similar versions long before this time. I think it’s amazing to use something from that era for a useful purpose now.

To build this, I need a way to take the 3 signals from the Arduino to the 3 chips. After a lot of prototyping, I wired the chips together with a header for the Arduino (in the middle of the wires) and with headers for the LEDs (below the chips) together on this great strip board. This photo is when two of the chips are soldered, waiting for the third.

Of course I need a clock. I used a cheap DS3232RT with this library. We’re going to need to introspect a little bit, so I added a somewhat clunky but entirely functional 20×4 LCD screen that speaks I2c. And I added a giant, blinking arcade button.

I spent a long time figuring out the layout. I should have done this with some kind of modeling software (which I really need to learn so I can do CNC milling and 3d printing), but I just Old Skool drafted it.

I put the enclosure together in a bit of 1/4" hobby plywood from the hardware store, stained to look like it isn’t totally crappy. One of the pieces that took me longest to figure out is how to cut a hole out of the middle of the board, and make it square and parallel. This wasn’t easy because I’m a seriously crappy craftsman.

The basic idea is to drill 3/8" holes in the corners, then use a jigsaw to cut between the holes. I built three different jigs to try to get cuts straight and square. Nope, then nope, then nopest. Finally I saw a YouTube video (which I’ve now lost) that said, like everybody just knows this, to put the panel on a vise, then file the sides flat and square.

The key I discovered is to cut rough using the technique above, but then put aluminum L stock on the vise jaws, and align the panel with the L stock up just barely under the mark for the edge of the hole. Then file the wood flat to the L stock, and the filed line with follow the line of the L stock. If I’ve set up the L stock up correctly, we’ll get a good square. It worked! The hole is square and parallel to the board used for the front panel. And now I have a set of Very Serious Nicholson files (I love good tools so much). The LCD dropped nicely into the hole, and I secured it there with some sugru and a few tiny screws. The LCD shows the decimal and binary values for each of the four variables shown by the LEDs as a kind of cheat sheet.

I mounted the LEDs into the front panel with hot glue. Note to self: big LEDs fit perfectly in a hole 13/64", while the little LEDs slot into a 1/8" hole.

I put a 330Ω resistor on each LED’s cathode and then soldered it to strips of copper tape I affixed to the back of the front panel as a ground bus. I put pre-crimped leads from Pololu on the anodes. I organized the wires in connector housings that I could attach to the PCBs. I made 3 bundles of 8 wires (one for each 74HC595) plus a ground wire.

There are 2 boards: one for a I2c bus for the clock and the LCD, and a pullup resistor for the button; and one for the 74HC595s.

The front panel is connected to the back by 1/4" bolts through little blocks I cut out of 2x4s. A bolt through the back panel, the block, and the front panel with an acorn nut holds it all together. Perhaps I’ll cut acrylic sheet for the currently-open sides.

It works! I’ll post the code below until such time as I get a minor GitHub repo set up. I’m grateful to Slobberchops for his help: I’ve never sliced bytes and twiddled bits before (I live a little higher in the stack), and I’m delighted to have done it with his help. I hope to make this compile with arduino Makefile. That’s the next rev, and I’ll update this post with a GitHub link when I get this a little cleaner.

/*    Author: wylbur  https://wylbursinnergeek.net 
 *    
 *    Date: 2020-04-23
 *    License: GPL v2+
 *   
 *    building on the shoulders of others. Thanks. 
 *  
*/

#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>  // https://github.com/mathertel/LiquidCrystal_PCF8574
#include <DS3232RTC.h>              // https://github.com/JChristensen/DS3232RTC
#include <FastLED.h>

#define DEBUG 1
#ifdef DEBUG
  #define DEBUG_PRINT(x) Serial.print(x)
  #define DEBUG_PRINTLN(x) Serial.println(x)
#else
  #define DEBUG_PRINT(x)
  #define DEBUG_PRINTLN(x)
#endif 


const int ledPin = 3; 
const int buttonPin = 2; 
const int dataPin = 7;
const int latchPin = 5; 
const int clockPin = 6; 

LiquidCrystal_PCF8574 lcd(0x27); // set the LCD address to 0x27 for a 16 chars and 2 line display

// https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format
// part 1
const char *bit_rep[16] = {
    [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
    [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
    [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
    [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
};


boolean fadeDirection = 1;
byte fadeValue = 0; 

volatile boolean displayMode = 0; 
boolean lastDisplay = 0; 
volatile unsigned long last_button = 0;
int last_second = -1; 
unsigned long last_us = -1; 

char line1[21] = ""; 
char line2[21] = ""; 
char line3[21] = ""; 
char line4[21] = ""; 
byte r1 = 0; 
byte r2 = 0; 
byte r3 = 0;
byte days;
byte hours;
byte mins; 
byte secs; 
byte dd;  // 5 bits
byte hh;  // 5 bits
byte mm;  // 6 bits
byte ss;  // 6 bits


void setup() {
  Serial.begin(9600);
  delay(250); 
  Wire.begin();

  attachInterrupt(digitalPinToInterrupt(buttonPin), modeSwitch, FALLING); 

  pinMode(latchPin, OUTPUT); 
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, OUTPUT); 
  
  DEBUG_PRINT("LCD...");
  printf_init(lcd); 
  Wire.beginTransmission(0x27);
  int error = Wire.endTransmission();
  if (error == 0) {
    DEBUG_PRINTLN(": LCD found.");
    lcd.begin(20, 4); // initialize the lcd
    lcd.setBacklight(255);
    lcd.home();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Hello binclock");
    // lcd.setCursor(0, 1);l
    // lcd.printf("hello world %d\n", 42); 
    delay(2000); 
  } else {
    DEBUG_PRINTLN("LCD not found."); 
  }
  setSyncProvider(RTC.get);   // the function to get the time from the RTC

  #ifdef DEBUG
  if(timeStatus() != timeSet)
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time"); 
  #endif 
    
  lcd.clear(); lcd.noDisplay(); lcd.setBacklight(0);
} 


#ifdef DEBUG
unsigned long loopctr = 0; 
#endif

void loop() {
    EVERY_N_MILLISECONDS(25) {
      if (displayMode == 0) {    
          if (fadeDirection == 1) { 
            fadeValue += 3; 
          } else {
            fadeValue -= 2; 
          }        
          if (fadeValue >= 150) {
            fadeDirection = 0; 
          } else if (fadeValue <= 0) {
            fadeDirection = 1;
          } 
      } else {
          fadeValue = 0;
      }
      analogWrite(ledPin, fadeValue); 
    }

    #ifdef DEBUG_A
    Serial.print(fadeValue); Serial.print("  "); 
    Serial.print(fadeDirection); Serial.print("  "); 
    Serial.print(displayMode); Serial.print("  "); 
    Serial.print(millis()); Serial.print("  "); Serial.println(last_button); 
    #endif 
   
    EVERY_N_MILLISECONDS(50) {
      byte secs = second();
      if (secs != last_second | displayMode != lastDisplay) {
        time2bytes(); 
        bytes2serial(); 
        update_lcd(); 
        last_second = secs; 
      }
    } 

    #ifdef DEBUG
    EVERY_N_MILLISECONDS(1000) {
      Serial.print(fadeDirection); Serial.print("  "); 
      unsigned long us_elapsed = micros() - last_us;
      Serial.print("us_elapsed="); Serial.print(us_elapsed); 
      Serial.print("; loops in elapsed="); Serial.print(loopctr); 
      float loops_per_ms = loopctr/(us_elapsed/1000); 
      Serial.print("; loops_per_ms="); Serial.println(loops_per_ms); 
      last_us = micros();
      loopctr = 0; 
    }
    loopctr++; 
    #endif
    
} 


void bytes2serial() {
  // push r1,r2,r3 to serial.
  digitalWrite(latchPin, LOW); 
  shiftOut(dataPin, clockPin, LSBFIRST, r3); 
  shiftOut(dataPin, clockPin, LSBFIRST, r2); 
  shiftOut(dataPin, clockPin, LSBFIRST, r1); 
  digitalWrite(latchPin, HIGH); 
}


void modeSwitch() {
  // it's a very noisy button
  if (millis() > last_button + 300) {
    displayMode = !displayMode; 
    last_button = millis(); 
  } 
}


void time2bytes() {
   days = day();
   hours = hour();
   mins = minute(); 
   secs = second(); 
   dd = days & 0x1F;  // 5 bits
   hh = hours & 0x1F;  // 5 bits
   mm = mins & 0x3F;  // 6 bits
   ss = secs & 0x3F;  // 6 bits

   r1 = (dd << 1) & 0xFF; // r1 has the rightmost 7 bits of dd (first two are 00)
   r1 |= (hh >> 4);       // hh is only 5 bits, so right shft 4 puts hh's first bit at end of r1
   r1 |= 0x80;           // to set only first bit
   /* 
   r1 |= 0xC0;  // to set both first bits on
   r1 |= 0x40;  // to set only second bit
   */ 
   
   r2 = (hh << 4) & 0xFF; // hh is 5 bits, so left shift 4 leaves bits4-7 at left of r2
   r2 |= (mm >> 2);       // getting the left 4 bits of mm (first two are 00)
   r3 = (mm << 6) & 0xFF; // rightmost 2 bits of mm
   r3 |= ss;              // ss is 6 bits wide and all go here
}

void update_lcd() {
   if (displayMode == 1) {
      sprintf(line1, "  dd: %02d  %s%s", days, bit_rep[dd >> 4], bit_rep[dd & 0x0F]); 
      sprintf(line2, "  hh: %02d  %s%s", hours, bit_rep[hh >> 4], bit_rep[hh & 0x0F]); 
      sprintf(line3, "  mm: %02d  %s%s", mins, bit_rep[mm >> 4], bit_rep[mm & 0x0F]); 
      sprintf(line4, "  ss: %02d  %s%s", secs, bit_rep[ss >> 4], bit_rep[ss & 0x0F]); 
      
      if (lastDisplay != 1) {
         lcd.clear(); lcd.display();  lcd.setBacklight(255);
         lastDisplay = displayMode; 
      }
      lcd.setCursor(0, 0);   lcd.print(line1); 
      lcd.setCursor(0, 1);   lcd.print(line2);  
      lcd.setCursor(0, 2);   lcd.print(line3); 
      lcd.setCursor(0, 3);   lcd.print(line4); 
     
    } else {
       if (lastDisplay != 0) {
           lcd.noDisplay(); lcd.setBacklight(0);
          lastDisplay = displayMode; 
       }
    }
}


// done. 

I suck at craft. I can’t cut straight with a razor or a saw, and get a cut square? Forgetaboutit. I’ve got a Kreg square cut, and that helps a lot. It works a treat when I need to cut a 2-by with a substantial length on each side, or for a short plywood cut. However, it’s useless for small pieces, and it’s often cumbersome because you need to hold it carefully with the left hand while managing the saw with the right. Awkward can be scary when a circular saw is involved.

Crucially, I don’t have a table saw. Ok, I do have a teensy-tiny NovelLife Mini Hobby Saw, and it’s really great. I’ve managed to cut soft wood up to 1/2" and plywood up to 5/8", but very very slowly. It chokes a lot, and the table is only 9" deep. It’s a great tool, and I’ve learned a ton using it, but it’s usable only for the smallest stuff. I’m going to burn it up with overuse in the not too distant future, I suspect. All to say that to cut real lumber, I’m pretty much limited to my circular saw.

After much review on YouTube, I decided to make a crosscut jig. The idea is that the circular saw sits in metal tracks which make sure it cuts straight. Then mount a board square to the tracks. Wood to be cut goes against the square board, and even I should be able to get a square cut. Here we go.

First thing is to build a table for it. I used a scrap of 5/8" plywood onto which I glued a sheet of hardboard. On top of that I glued and screwed 2x4s to hold everything together. In the photo, I’m waiting for all the glue to set.

Then I need rails. I had some 1/2" steel L rods from another project (that totally didn’t work out), so I cut them with a dremel (dramatic sparks!) and drilled holes to mount them onto the 2x4s.

I mounted the rails to the 2x4s and found that the clearance underneath them was a little too tight to cut 2-by lumber. So I pulled the rails off and added a 1/4" layer of plywood between the rails and the 2x4s.

Then I found that I really need the whole run of the rails, and it wasn’t quite long enough. The screws securing the rails were in the way of the saw’s bed. I pulled the screws out again, countersunk them with a 3/8" carbide bit (man, carbide bits just eat steel, pretty cool). Then I reset the rails, adding wood glue to the screws so they’ll adhere to the somewhat-stripped holes. Now the saw bed can run smoothly over the screws.

After I got the fence in place, I ran the saw back and forth, scoring the hardboard. I found that the saw can’t quite go to it’s maximum depth because the motor housing bumps into the rail, so I lose the last 1/4" or so of the saw’s possible depth. Ideally the rails would be 3/8", not 1/2", but, well, I had the 1/2" steel, so there we are. The saw cuts into the hardboard about 1/16", so it’s just barely enough to cut a board cleanly.

Next I need a fence. After several fails, I used a poplar 1×2, and glued a piece of finished 1/2" plywood onto it. The plywood will be the fence, so it needs to be both flat and square to the vertical. I drilled and countersunk pilot holes in the poplar to affix it to the table.

Finally I squared the fence to the cuts previously I made in the hardboard. I glued it and then set it with a bunch of screws, very carefully checking the square many times.

And it works! Yay! A little less craft-personship will be needed from here on. The rails need to be rubbed down with steel wool and then oiled, but that’s just maintenance.

I recently read Four Favorite Tools, a collection of essays from BoingBoing. I liked the style and the idea, so I thought I’d write about my four favorite tools.

Arduino hacking in NeoVim

There’s no competition: my favorite and most-used tool is NeoVim. This is a text editor, mostly for programming, but I use it for email and documents as well.

I write inside a unix terminal. People who are used to GUIs find the terminal clunky, but once you become accustomed to it, you’ll find it’s far and away the most efficient way to interact with a computer. By "efficient," I mean I can do the maximum amount of changing with the fewest keystrokes and arm movements. I can (and often do) wax a bit lyrical about vim and it’s many, many variants, but vim is worth it.

Note: I’m 30K words into a book written using NeoVim and markdown — and I’m writing this blogpost using a WordPress Markdown block — and I’ve found that Markdown is a pretty good basis for a long-ish book. The terminal+(Neo)Vim workflow lends itself naturally to keeping the book in version control in my GitHub account.

My 10-year-old Amprobe 37XR-A multimeter was the first tool I bought a second time. Before then I had a really cheap multimeter, I think the bottom-of-the-line that Adafruit offered. I bought the Amprobe at Fry’s because an old engineer recommended the brand to me. It’s a beast. I measure resistance, continuity, DC volts, and capacitance all the time (and DC current occasionally). This one has been to Burning Man 8 times, I just wash it with a little vinegar, soap and water in the sink when I get home. Really. It’s incredibly rugged, turns itself off automatically, and is accurate enough. I’ve got other multimeters now, and they’re much faster, more accurate, and have various cool features. This guy is the one I’m taking whenever I leave the lab. It’s been with me as I learned to be a maker, and I really like it.

Ratcheting wire strippers were truly one of the pieces that got me making. I couldn’t figure out how to strip wires without destroying strands, and the frustration built over several months until I got my first pair of these. I’ve got a few, various brands, and they’ve all been terrific. They work across a really wide range of wire gauges and insulation thicknesses. Nice.

The DeWalt DCF680 is a magical tool. It’s motion-activated. The idea is that you align the tool to the screw or bolt you intend to turn, push and hold the black button, then with a flick of the wrist in either a clockwise or counter-clockwise direction, it turns. You control the speed of the tool with the strength of the flick.

After I used it for about 10 minutes, I found it incredibly intuitive. There are a variety of other power screwdrivers like this, notably the tiny motion control screwdriver Adafruit sells. I have a tiny one, and it’s nice, but the cheaper and vastly more powerful DeWalt is also subtler: I find that I can control the speed of the DeWalt with a lot of precision. Furthermore, the clutch on the DeWalt lets me set and then screw something until the clutch slips, no thinking and no stripping. Great stuff.

I have a bunch of other tools I’m really, really enjoying right now. Some are new, like the Siglent SPD1305x power supply makes controlling voltage and current so easy that it greatly reduces the chance I’ll blow something up with a short or reversed polarity. Or the soon-to-be-discontinued Rigol 1054Z which I’m slowly learning to use. Others I’ve used for decades, like the unix shell environment and tools. I’ll close with two slides from a talk I gave at the Linux Foundation a few years ago. I love tools.

What are your favorite tools?

(Updated with info on the Siglent)

A voltnut, or "metrology enthusiast" as our Brit and DownUnder friends say, is a person who gets really excited about knowing to many decimal places how much voltage and current is running through our little devices. I don’t really need all that, but when I’m playing with digital-to-analog conversion, I do need to know pretty accurately what the real analog voltage is.

I’d like to know to the millivolt, which at 5v means 0.02% accuracy, or "4 1/2 digits," in metrology-speak. Turns out that’s about five times more accurate than anything I have now.

This Fluke was built while I was in college.

I’ve connected the reference to all threefour of my measurement devices. First I have an ancient but wonderful Fluke 45 multimeter which claims precision to a tenth of a millivolt at the medium reading speed at 3v, or 0.02% (I can’t quite tell from their table). It has a calibration seal dated in December, 2000.

The newest toy on my bench is a Siglent SDM3055 multimeter. I won’t say more about it because mjlorton at YouTube has done a great review. The calibration cert on mine is good thru May 2020.

The Siglent multimeter is gorgeous

Next is my 10-year-old Amprobe 37XR-A, a beefy tool for serious electricians. This beast has been to Burning Man about 8 or so times, but it cleans up nicely for lab work.

Finally I’m using Adafruit’s ina260 voltage and current sensor which they report as "better than 1% accuracy."

In this test, I’m using Adafruit’s Precision LM4040 Voltage Reference Breakout. I give it about 5v, and it puts out 2.048v or 4.096v at 0.1% accuracy. That means +/- about 2mV and 4mV at the two output voltages, respectively. Setup in the pic below.

Not to put too fine a point on it, I’d like to know which of these devices is the most accurate. Alas, this test doesn’t really tell me. The results are in the table below.

device 2.048v 4.096v
Siglent SDM3055 2.0503 4.1032
Fluke45 2.0506 4.1036
Amprobe 37XR-A 2.047 4.098
ina260 breakout 2.052 4.103

The good news is (i) the calibrated Siglent and the Fluke are indistinguishable at 4.096v, and nearly so at the 2.048v reference (I believe the Siglent). They vary by less than half a millivolt here and in other tests. (ii) The Amprobe and the ina260 are within their tolerances at the 2.048v level, and the Amprobe is still within reference at 4.096.

The ina260 is within it’s stated 1% tolerance, indeed, it’s nearly as good as the other two with better tolerances. This said, it is not a voltmeter: it’s a very delicate IC on a breakout board. Reverse the polarity and you’ll fry the IC, and you can fry an upstream microcontroller’s I2C bus connected to the ina260 board. How do I know this? you wonder.

All this said, I can’t tell from this test which is the most accurate because most of the variation is within the variation on the LM4040. I also bought a AD584 reference, but it produced arbitrary values and seems to be defective.

Three action items emerge: (1) replace the AD584; (2) get the Fluke calibrated. And (3) indulge in a fancy new DMM, which I did. It’s great.

I’m building an r2r ladder which is a way to convert a group of binary voltage inputs to a continuous analog output. For example, an 8-bit r2r ladder would output a single voltage from 0-Vcc at 255 discrete voltage points that are about 20 mV apart.

This is a digital-to-analog conversion (DAC), and I want one in order to build an arbitrary waveform generator (like this one or this one). The DAC will take 8 pins from the arduino, treat them like the bits of a byte, then output a voltage between GND and whatever the Arduino is outputting (Vcc = 3.3 or 5v). That is, we use the DAC to go from a set of digital values in a given waveform to an analog voltage. We need that for any waveform that  has a progression from 0-Vcc, such as a sawtooth, a triangle, or a sine. 

IMG_1091

So I built it, added 8 pins from an Arduino, wrote a sketch to step through 0-255 and write the resulting byte to the 8 pins. I measured the result, and it wasn’t quite what I hoped. First, here’s what it looks like on an oscilloscope. 

DS1Z_QuickPrint5

The problem is those occasional big dropouts, the vertical yellow lines that seem to dribble down off the main diagonal. I wrote the data to a file and started analyzing it. First, the voltage-by-byte. I ran over the 0-255 values 30 times to get a decent distribution. It’s not quite the same as the oscilloscope because the ina260 I used to measure the voltage does two things: first, it measures for 140us, which is about 7000 times slower than the oscope. Second, it measures 16 times and then reports the mean of the measures, so in practice, the ina260 is more than 100,000 times slower than the oscope.

DAC-mV-by-byte

This looks mostly good, except for the two notches which turn out to be at 129 and 178. Yikes, and yuck. If we’re concerned about a stable increment between bytes, let’s look at the first differences, that is, (voltage at byte_k) – (voltage at byte_{k-1}). These are called lagged diffs.

DAC-mV-diff-histogram

As we might expect, the difference clusters around 20mV, which makes plenty of sense. Unfortunately, there’s a second small cluster between -40 and -20. Those turn out to belong to bytes 129 and 174. There’s absolutely nothing interesting about those values, in a binary sense, which is a clue that this isn’t about a wiring error. If the glitches happened at 32 or 64 or 128, that would suggest that I’d done something wrong at a specific resistor.

Looking at the histogram just for 129, 174 there’s also nothing special in the distribution of lagged diffs.

Back to basics: what’s an r2r network anyway? Basically it’s a big voltage divider, and the stability of the output depends on the ratios among the resistances.

The reason we use the r2r pattern is specifically because the combination of 8 voltage dividers in one circuit allows each bit to contribute a unique chunk of voltage to the output. For example, the least significant bit of an 8-bit ladder contributes b/2^8 volts, where b is either 0 (if the bit is 0) or Vcc  if the bit is 1. The next-least-significant bit contributes b/2^7 volts, and the one after that contributes b/2^6 volts, etc. The sum of these 8 contributions creates 255 unique voltage values.

That transformation works because in the voltage divider, all the r values are the same, and the 2r values are the same and = 2*r. But unfortunately, that’s not how most resistors really are. The ones I have on hand are 5% tolerances, so r is around 10K, and 2r is in the neighborhood of 20K. I started testing the resistances, and they came in between 9766 and 10055 ohms; the 2r values came in 19789-20129 ohms. These bits of imprecision yield enough weirdness to create the notches and nonlinearities in the graphs above.

Hmm. After a little reading, it became clear that this is how r2r networks fail: inconsistent values, and even more, inconsistent r/2r ratios, lead to nonlinearities –glitches — in the progression of output voltages. This is exactly what I’m seeing. There’s even a Hackaday post about trimming resistors to make them more consistent for this purpose.

I’m not going to do that because I’m lazy. I ordered a few 10K and 20K resistors with 0.1% tolerances from Mouser, and I’ll try again when they arrive.

When you wire a button or a switch into a digital circuit, it might seem as though when the button is pushed, a circuit is closed, and there’s a digital HIGH or 1 available.

It’s not that straightforward, unfortunately. At the microscopic scale, the switch has tiny burrs that connect and disconnect several (or hundreds) times before it settles closed so that current can flow. This is called “bouncing,” and it’s the topic of many really great videos and blogposts. I even wrote one a few years ago, but now I have an oscilloscope so I can dig in a lot more deeply.

Mostly people handle it in software: if you see a button press, ignore everything for (about) the next 100ms, so you only count one press. A similar technique is to poll the button frequently, watching for a series of HIGH values, then counting only once it’s HIGH for a long enough period.

I am going to follow this video and report my findings (also a nice diagram and roundup of simple software techniques in this post). Here’s a picture of what button bouncing looks like.

The button is wired on one leg to ground, and on the other leg, through a 10K resistor which connects to 3.3v. The probe is attached to the 3.3v side of the resistor. When I push the button, there’s an initial jump to 3.3 that lasts only about 120 nanoseconds (the solid white vertical line marks when I pushed, and I zoomed in to measure the time of the first bounce). After about 100μs (note that microsecond is abbreviated μs), the contact gets a little closer, and the jumps upward become more insistent. At about 240μs after I pushed the button, the button settles at a HIGH signal (note the dashed vertical line when this happens). I released the button only another 100μs later, and it dropped nicely to LOW (note that there’s not usually much bouncing when a switch opens because all the little rough bits are pulled apart more quickly than when they are closing).

The Teensy 4.0 I’m using here runs at 600MHz, about 6 cycles/μs. So there are more than 1500 cycles during the 262μs this button is bouncing. It’s easily capable of counting the 8-10 bounces above 1.8v (where it counts HIGH). That creates a mess when you’re trying to count button pushes.

For my test, I’m doing 2 separate things to the signal. First, I smooth the bouncing using a resistor-capacitor (RC) circuit. I can’t explain RC circuits, that’s a bit above my skills so far, but I recommend the Art of Electronics Lab Course, chapter 2. I’m digging through it now.

When the switch closes, the capacitor discharges according to the time constant, τ = R x C. The idea is that it takes about 5τ for the RC circuit to charge or discharge. The charging is exponential, not linear, and there’s a great tutorial about it here but alas, the graphics seem to be missing.

My graphics aren’t great, but here they are. R1 is the pullup resistor, and it’s 2K. The RC circuit starts with R2 at 680Ω and the capacitor is 1μF. That means that τ = 6.8e-4 secs, so it charges or discharges in 5τ = 3.4ms.

This is what happens when I press the button and measure the signal in parallel with the RC (before IC1 in the schematic above). Note that the two vertical lines mark the beginning and end of the capacitor’s discharge. BX-AX is about 4.6ms, which is pretty close to the theoretical 5τ = 3.4ms. I’m happy when my experiments match theory.

The point of this is to get a digital signal to the microprocessor, but the RC signal isn’t really square, it’s curved which forces the microprocessor to decide when the signal is HIGH. The Teensy can do that, of course, but once we start building this circuit, shouldn’t we get a square signal out of it?

The answer is an inverting Schmitt trigger, an integrated circuit that shifts from 1 to 0 at some higher threshold, and from 0 to 1 at a lower threshold. It’s an inverting trigger, which means that it’s output is always the opposite of the input, as seen in the image above. The yellow line is from the RC circuit which is the input to the trigger. For the trigger, I’m using a 74HC14, an integrated circuit (i.e., a chip) which switches from high to low when the input voltage hits about 1.8v (when the input voltage to the chip is 3.3v).

Note that as the yellow line gently climbs, when it hits 1.8 volts, BAM, the Schmitt trigger output shown by the blue line drops from HIGH to LOW. The datasheet reports that the drop happens in about 7-19ns; My oscilloscope sees the transition in 14.8ns: good job, datasheet. By comparison, the CPU on the Teensy is running at 600mHz, which means about one cycle takes 1/600th of a million-th of a second, which is approximately 2 nanoseconds. While it only takes one cycle to read the digital pin (in the very best case, usually it’s more), the Arduino is doing other stuff and can’t check the pin every cycle, so it won’t read the pin more than every 50-100 ns. The Schmitt trigger switches in about 15ns, 8x slower than the CPU. There’s very little chance chance that the Teensy will be confused during the trigger’s transition.

Here’s what it looks like wired.

The code that runs the counter is below. I’ve banged on this button something fierce, and it counts once and only once every time I hit it. There’s no software debouncing at all, the hardware is doing all the work.

I like it! It’s pretty unnecessary: I’ve found that a simple delay works for nearly all my applications, and in exceptional cases like rotary encoders, state machines work a treat. However, I’m really happy to have had a reason to look more deeply into this topic and to have another tool in my kit if a switch acts up.

/*
   testing button press counts 
   wylbur, 25 Dec 2019
*/

const int CHIP_PIN = 15; 
int chip_count = 0; 
int last_chip_count = -1; 

void setup() {
  //start serial connection
  Serial.begin(57600);
  pinMode(CHIP_PIN, INPUT_PULLDOWN); 
  attachInterrupt(digitalPinToInterrupt(CHIP_PIN), isrChip, RISING);
  Serial.println("init complete."); 
}


void loop() {
  if (chip_count != last_chip_count) {
     Serial.print(millis()); 
     Serial.print(F(": chip=")); 
     Serial.println(chip_count); 
     last_chip_count = chip_count; 
  }
}


void isrChip() {
  chip_count++; 
}

// done. 

My friend Bear was on the BM cleanup crew this year, and he came upon a seriously tricked-out bike that had been abandoned, locked to a bike rack at a big sound camp. He removed the electronics for me to study. There are 8 strands of analog (not individually-addressed) 12v RGB LEDs, like this one.

So 8 * 3 (RGB) connections (each of which sinks) is a quick tip here. Of course there’s an Arduino.

Then it gets more interesting for me. The Arduino sends a serial signal to a series of 3 74HC595N shift registers, thereby splitting the serial signal into 24 (ahem, 8 * 3) parallel 5v outputs.

But the LEDs are 12v, and will need to sink a lot of current. Here’s where the lost inventor does something I would not have thought of: they used 3 ULN2803AN ICs to sink a lot of current (again 24 signals, but at 12v!), switched by the Arduino at 3.3v.

Note that the ULN2803ANs are stacked, one on top of another, putting them in parallel so each output can sink up to 1A. Good thinking, and careful soldering.

There’s a lot for me to learn with this teardown. Using the ULN2803AN as an array of Darlington transistors is pretty cool. I’ve used single Darlingtons before, and it seems that arrays of transistors and resistors is something I’m learning about right now (more on this in a later post).

Even more, the inventor has srsly used perf board before. They organized the chips and the headers to minimize the wiring in smart ways that I’m going to keep studying.

It sure is great to have a lab to study stuff like this! Thx to Bear for spotting this in the dust and schlepping it home for me.