The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Electronics Workbench

Electrical & Electronic gadgets

  • Cast Iron Pan Electrolysis: Anode Fragment

    Sacrificing a scrap EMI shield from a junked PC as the electrolysis anode, I grabbed a tab with the battery charger clamp:

    Cast iron pan electrolysis - bucket
    Cast iron pan electrolysis – bucket

    Turns out it didn’t survive the encounter:

    Cast iron pan electrolysis - anode front
    Cast iron pan electrolysis – anode front

    That white blob extends around to the other side:

    Cast iron pan electrolysis - anode rear
    Cast iron pan electrolysis – anode rear

    Yeah, it got hot enough to melt a blob from the 6 gallon plastic bucket before burning through.

    I tossed that into the garage so I wouldn’t forget it aaaand here we are …

  • Kindle Fire Power Switch Rebuild

    The single moving part on my first-generation (2011) Kindle Fire tablet stopped working: the power switch became erratic, to the point where the only dependable way to turn the thing on required the USB charging cable. Obviously not a long-term solution.

    Having nothing to lose, I consulted the Internet’s vast steaming pile of advice on how to pop the Kindle’s cover, picked one, and ran with it. Basically, you jam a sharp tool into the end with the speakers, then crack the back off along both sides, leading to this:

    Kindle Fire - pre-teardown overview
    Kindle Fire – pre-teardown overview

    Things to note:

    • No need to remove the battery: pull the heavy connector straight out
    • Disconnect the battery first, before unplugging anything else
    • Most of the ribbon cable connectors have a white flip-up latch
    • You will break the ground shield from the flex PCB to the battery along the left edge
    • The antenna must make that 270° turn into the minuscule U.FL connector
    • The four-wire cable to the speakers has a pull-out connector in the lower right corner
    • The PCB backplate on the large video (?) connector in the upper right pulls straight up-and-out

    Remove the six obvious screws, pull the battery edge of the board upward, and rotate the whole affair out of the chassis:

    Kindle Fire - power LED board - in place
    Kindle Fire – power LED board – in place

    Protip: the power switch is not mounted on the tiny PCB (under the ribbon cable with the blue tab) sometimes advertised as the Power Button Board. That tiny PCB suspends an amber/green LED behind the visible button, but a yoke surrounds the LED to transfer the button motion to the power switch soldered to the CPU board. Replacing that board will not cure an erratic power switch; I think the entire CPU board is the FRU.

    Fortunately, I can actually see the power switch and know sorta-kinda what to expect.

    A bit of awkward multimeter probing showed the switch was defunct, with intermittent action and generally high resistance when pressed. I unsoldered the switch, verified that it didn’t work in isolation, and examined some likely candidates from the Big Box o’ Small Switches:

    Kindle Fire - potential power switches
    Kindle Fire – potential power switches

    Some could be made to fit and maybe actually function, with effort ranging from tedious to Really Hard.

    Then it occurred to me that maybe, just maybe, I could refurbish / clean / repair the Kindle’s switch contacts. Shaving off the two heat-staked plastic bumps on the front and prying the side latches outward produced an explosion of small parts:

    Kindle Fire - disassembled power switch
    Kindle Fire – disassembled power switch

    That’s after cleaning the expected grunge from the three contact strips in the body and the innermost of the two (!) buckling-spring contact doodads (bottom left). I scrubbed with the cardboard-ish stem of a cotton swab and, as always, a dot of DeoxIT Red, inserted the unused-and-pristine contact spring doodad (bottom right) first, and reassembled the switch in reverse order.

    The metal shell around the body has two locating tabs that fit in two PCB holes, giving the switch positive alignment and good strain relief. The front view shows the three human-scale components amid a sea of 0201 SMD parts:

    Kindle Fire - repaired power switch - front
    Kindle Fire – repaired power switch – front

    For completeness, the view from the battery side:

    Kindle Fire - repaired power switch - rear
    Kindle Fire – repaired power switch – rear

    It’s worth noting that you can see right through the 3.5 mm headphone jack, which accounts for the remarkable amount of dust & fuzz I blew out of the chassis. The overall dust sealing isn’t great, but after five years of life in my pocket, I suppose that’s to be expected.

    Installing the board requires holding all the cables out of the way (tape the antenna & speaker wires to the battery), aiming the USB connector into its cutout, rotating the battery edge of the board downward, pushing the mesh EMI shield along the battery upward to clear the board edge, not forcing anything, and eventually it slides into place.

    Insert cables, latch latches, plug in the battery, snap the rear cover in place, and It Just Works again. The power switch responds to a light touch with complete reliability; it hasn’t worked this well in a year.

    Bonus: To my utter & complete astonishment, disconnecting the battery for few hours had no effect on the stored data: it powered up just fine with all the usual settings in place. I expected most of the settings to live in the Flash file system, but apparently nothing permanent lives in RAM.

    Take that, entropy!

  • Vacuum Tube LEDs: Now With Morse Code

    Adding Mark Fickett’s non-blocking Morse Arduino library turns the tubes into transmitters:

    21HB5A on platter - orange green
    21HB5A on platter – orange green

    The plate cap LED blinks the message in orange, while both LEDs continue to slowly change color as before.

    You define a Morse sender object (C++, yo!) by specifying its output pin and code speed in words per minute, dump a string into it, then call a continuation function fast enough to let it twiddle the output bit for each pulse. Obviously, the rate at which the callback happens determines the timing granularity.

    However, setting a knockoff Neopixel to a given color requires more than just a binary signal on an output pin. The continuation function returns false when it’s done with the message, after which you can initialize and send another message. There’s no obvious (to me, anyhow) way to get timing information out of the code.

    The easiest solution: called the Morse continuation function at the top of the main loop, read its output pin to determine when a dit or dah is active, then set the plate cap color accordingly:

    LEDMorseSender Morse(PIN_MORSE, (float)MORSE_WPM);
    ...
    Morse.setup();
    Morse.setMessage(String("       cq cq cq de ke4znu       "));
    PrevMorse = ThisMorse = digitalRead(PIN_MORSE);
    ...
    if (!Morse.continueSending()) {
      Morse.startSending();
    }
    ThisMorse = digitalRead(PIN_MORSE);
    ...
    if (ThisMorse) {             // if Morse output high, overlay
        strip.setPixelColor(PIXEL_MORSE,MorseColor);
    }
    PrevMorse = ThisMorse;
    strip.show();               // send out precomputed colors
    ...
    <<compute colors for next iteration as usual>>
    

    I use the Entropy library to seed the PRNG, then pick three prime numbers for the sine wave periods (with an ugly hack to avoid matching periods):

    uint32_t rn = Entropy.random();
    ...
    randomSeed(rn);
    ...
    
    Pixels[RED].Prime = PrimeList[random(sizeof(PrimeList))];
    
    do {
      Pixels[GREEN].Prime = PrimeList[random(sizeof(PrimeList))];
    } while (Pixels[RED].Prime == Pixels[GREEN].Prime);
    
    do {
      Pixels[BLUE].Prime = PrimeList[random(sizeof(PrimeList))];
    } while (Pixels[BLUE].Prime == Pixels[RED].Prime ||
            Pixels[BLUE].Prime == Pixels[GREEN].Prime);
    
    printf("Primes: (%d,%d,%d)\r\n",Pixels[RED].Prime,Pixels[GREEN].Prime,Pixels[BLUE].Prime);
    

    In the spirit of “Video or it didn’t happen”: YouTube!

    The Arduino source code as a GitHub Gist:

    // Neopixel mood lighting for vacuum tubes
    // Ed Nisley – KE4ANU – June 2016
    // September 2016 – Add Morse library and blinkiness
    #include <Adafruit_NeoPixel.h>
    #include <morse.h>
    #include <Entropy.h>
    //———-
    // Pin assignments
    const byte PIN_NEO = A3; // DO – data out to first Neopixel
    const byte PIN_HEARTBEAT = 13; // DO – Arduino LED
    #define PIN_MORSE 12
    //———-
    // Constants
    #define PIXELS 2
    #define PIXEL_MORSE 1
    #define MORSE_WPM 10
    #define UPDATEINTERVAL 50ul
    const unsigned long UpdateMS = UPDATEINTERVAL – 1ul; // update LEDs only this many ms apart (minus loop() overhead)
    // number of steps per cycle, before applying prime factors
    #define RESOLUTION 250
    // want to randomize the startup a little?
    #define RANDOMIZE true
    //———-
    // Globals
    // instantiate the Neopixel buffer array
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN_NEO, NEO_GRB + NEO_KHZ800);
    uint32_t FullWhite = strip.Color(255,255,255);
    uint32_t FullOff = strip.Color(0,0,0);
    uint32_t MorseColor = strip.Color(255,191,0);
    struct pixcolor_t {
    byte Prime;
    unsigned int NumSteps;
    unsigned int Step;
    float StepSize;
    byte MaxPWM;
    };
    unsigned int PlatterSteps;
    byte PrimeList[] = {3,5,7,13,19,29};
    // colors in each LED
    enum pixcolors {RED, GREEN, BLUE, PIXELSIZE};
    struct pixcolor_t Pixels[PIXELSIZE]; // all the data for each pixel color intensity
    uint32_t UniColor;
    unsigned long MillisNow;
    unsigned long MillisThen;
    // Morse code
    LEDMorseSender Morse(PIN_MORSE, (float)MORSE_WPM);
    uint8_t PrevMorse, ThisMorse;
    //– Figure PWM based on current state
    byte StepColor(byte Color, float Phi) {
    byte Value;
    Value = (Pixels[Color].MaxPWM / 2.0) * (1.0 + sin(Pixels[Color].Step * Pixels[Color].StepSize + Phi));
    // Value = (Value) ? Value : Pixels[Color].MaxPWM; // flash at dimmest points
    return Value;
    }
    //– Helper routine for printf()
    int s_putc(char c, FILE *t) {
    Serial.write(c);
    }
    //——————
    // Set the mood
    void setup() {
    pinMode(PIN_HEARTBEAT,OUTPUT);
    digitalWrite(PIN_HEARTBEAT,LOW); // show we arrived
    Serial.begin(57600);
    fdevopen(&s_putc,0); // set up serial output for printf()
    printf("Vacuum Tube Mood Light\r\nEd Nisley – KE4ZNU – September 2016\r\n");
    Entropy.initialize(); // start up entropy collector
    // set up Neopixels
    strip.begin();
    strip.show();
    // lamp test: a brilliant white flash
    printf("Lamp test: flash white\r\n");
    for (byte i=0; i<3 ; i++) {
    for (int j=0; j < strip.numPixels(); j++) { // fill LEDs with white
    strip.setPixelColor(j,FullWhite);
    }
    strip.show();
    delay(500);
    for (int j=0; j < strip.numPixels(); j++) { // fill LEDs with black
    strip.setPixelColor(j,FullOff);
    }
    strip.show();
    delay(500);
    }
    // set up real random numbers
    uint32_t rn = Entropy.random();
    if (RANDOMIZE) {
    printf("Preloading LED array with seed: %08lx\r\n",rn);
    randomSeed(rn);
    }
    else {
    printf("Start not randomized\r\n");
    }
    printf("First random number: %ld\r\n",random(10));
    // set up the color generators
    Pixels[RED].Prime = PrimeList[random(sizeof(PrimeList))];
    do {
    Pixels[GREEN].Prime = PrimeList[random(sizeof(PrimeList))];
    } while (Pixels[RED].Prime == Pixels[GREEN].Prime);
    do {
    Pixels[BLUE].Prime = PrimeList[random(sizeof(PrimeList))];
    } while (Pixels[BLUE].Prime == Pixels[RED].Prime ||
    Pixels[BLUE].Prime == Pixels[GREEN].Prime);
    printf("Primes: (%d,%d,%d)\r\n",Pixels[RED].Prime,Pixels[GREEN].Prime,Pixels[BLUE].Prime);
    Pixels[RED].MaxPWM = 255;
    Pixels[GREEN].MaxPWM = 255;
    Pixels[BLUE].MaxPWM = 255;
    for (byte c=0; c < PIXELSIZE; c++) {
    Pixels[c].NumSteps = RESOLUTION * (unsigned int) Pixels[c].Prime;
    Pixels[c].Step = RANDOMIZE ? random(Pixels[c].NumSteps) : (3*Pixels[c].NumSteps)/4;
    Pixels[c].StepSize = TWO_PI / Pixels[c].NumSteps; // in radians per step
    printf("c: %d Steps: %d Init: %d",c,Pixels[c].NumSteps,Pixels[c].Step);
    printf(" PWM: %d\r\n",Pixels[c].MaxPWM);
    }
    // set up Morse generator
    printf("Morse %d wpm\n",MORSE_WPM);
    Morse.setup();
    Morse.setMessage(String(" cq cq cq de ke4znu "));
    PrevMorse = ThisMorse = digitalRead(PIN_MORSE);
    MillisNow = MillisThen = millis();
    }
    //——————
    // Run the mood
    void loop() {
    if (!Morse.continueSending()) {
    Morse.startSending();
    }
    ThisMorse = digitalRead(PIN_MORSE);
    MillisNow = millis();
    if (((MillisNow – MillisThen) > UpdateMS) || // time for color change?
    (PrevMorse != ThisMorse)) { // Morse output bit changed?
    digitalWrite(PIN_HEARTBEAT,HIGH);
    if (ThisMorse) { // if Morse output high, overlay
    strip.setPixelColor(PIXEL_MORSE,MorseColor);
    }
    PrevMorse = ThisMorse;
    strip.show(); // send out precomputed colors
    for (byte c=0; c < PIXELSIZE; c++) { // compute next increment for each color
    if (++Pixels[c].Step >= Pixels[c].NumSteps) {
    Pixels[c].Step = 0;
    printf("Cycle %d steps %d at %8ld delta %ld ms\r\n",c,Pixels[c].NumSteps,MillisNow,(MillisNow – MillisThen));
    }
    }
    byte Value[PIXELSIZE];
    for (byte c=0; c < PIXELSIZE; c++) { // … for each color
    Value[c] = StepColor(c,0.0); // figure new PWM value
    }
    UniColor = strip.Color(Value[RED],Value[GREEN],Value[BLUE]);
    for (int j=0; j < strip.numPixels(); j++) { // fill all LEDs with color
    strip.setPixelColor(j,UniColor);
    }
    MillisThen = MillisNow;
    digitalWrite(PIN_HEARTBEAT,LOW);
    }
    }
    view raw TubeMorse.ino hosted with ❤ by GitHub
  • Rewiring a Baofeng Battery Eliminator

    An aftermarket “battery eliminator” for Baofeng UV-5R radios costs under seven bucks delivered:

    Baofeng Battery Eliminator - overview
    Baofeng Battery Eliminator – overview

    That label seemed … odd:

    Baofeng Battery Eliminator - Li-ion Label
    Baofeng Battery Eliminator – Li-ion Label

    The OEM battery, tucked inside a case that’s for all intents and purposes identical to this one, sports an 1800 mA·h rating that I regarded as mmmm optimistic; I’d expect maybe 1000 mA·h, tops. From what I can tell, the 3800 mA·h label should go on an extended-capacity “big” battery that wraps around the bottom of the radio. Maybe the factory produced a pallet of mis-labeled small packs that they couldn’t fob off on actual customers with a straight face and couldn’t justify the labor to peel-and-stick the proper labels.

    Anyhow, it’s not a battery.

    The circuitry inside shows considerably more fit & finish than I expected:

    Baofeng Battery Eliminator - interior
    Baofeng Battery Eliminator – interior

    It’s not clear how effective that heatsink could be, given that it’s trapped inside a compact plastic enclosure snugged against the radio’s metal chassis, but it’s a nice touch. Two layers of foam tape anchor the terminals at the top and hold the heatsink / LM7808-class TO-220 regulator in place.

    Although I wanted the DC input to come from the side, rather than the bottom, so the radio could stand up, the pack simply isn’t thick enough to accommodate the jack in that orientation. I drilled out the existing wire hole to fit a coaxial power plug and deployed my own foam tape:

    Baofeng Battery Eliminator - rewired interior
    Baofeng Battery Eliminator – rewired interior

    Replacing the foam tape at the top holds the bent-brass (?) terminals in more-or-less the proper orientation, with Genuine 3M / Scotch Plaid adding a festive touch. A groove in the other half of the shell captures the free ends of those terminals, so they’re not flopping around in mid-air.

    The jack fits an old-school 7.5 V transformer wall wart that produces 11 V open-circuit. It’s probably still a bit too high with the UV-5R’s minimal receive-only load, but I refuse to worry.

    Now KE4ZNU-10 won’t become a lithium fire in the attic stairwell…

    While I had the hood up, I used Chirp to gut the radio’s stored frequencies / channels / memories and set 144.39 in Memory 0 as the only non-zero value. With a bit of luck, that will prevent it from crashing and jamming a randomly chosen frequency outside the amateur bands…

  • More Cheap eBay Hardware Failures

    Data points…

    Another knockoff Neopixel failed in the usual way, after a few days of operation: the first W2812B chip in the string gave off intermittent and random flashes of pure primary colors, the second was dead in the water. Replacing the first chip with Yet Another Knockoff from the same lot restored the tube to good health.

    Some oscilloscope probing revealed a pooched serial data output with no active pullup, so the output data rarely exceeded VCC/2 and generally wouldn’t be accepted by the downstream W2812B. Nothing to show for it, as I couldn’t be bothered to upload a scope shot. Maybe next time.

    One of the counterfeit FTDI USB-to-serial adapters in another tube base failed after a few weeks of operation, with symptoms ranging from hangs while downloading the Arduino program to readback verify mismatches. Replacing the failed adapter and the knockoff Arduino Pro Mini with a knockoff Arduino Nano (using a CH340 USB interface, presumably not a counterfeit) from a recently arrived envelope restored that tube to good health.

    All in all, those knockoff Neopixels have been a constant source of amusement; worth every penny just for the privilege of holding them up for ridicule. The “genuine” FTDI chips weren’t much of a surprise, but I am mildly surprised they work so poorly.

  • Vacuum Tube LEDs: Octal Tube Base Drilling

    Clamping the octal tube into the Sherline let me set the XY=0 origin to the center of the base with the laser dot (visible near the front):

    Octal tube clamped on Sherline mill
    Octal tube clamped on Sherline mill

    Find the edges, touch off the half the 32.2 mm diameter, then align the drill at XY=0 directly over the exposed evacuation tip:

    Octal Tube - drill alignment
    Octal Tube – drill alignment

    Make a very shallow cut to verify the alignment:

    Octal Tube - drill first touch
    Octal Tube – drill first touch

    Just inside the scuffed ring from the drill, you can see the fractured ring where the original one-piece Bakelite spigot / key / post broke off.

    Then extract the drill from the chuck, file more relief behind the cutting edges so they actually cut, re-chuck, and continue the mission:

    Octal Tube - drilling
    Octal Tube – drilling

    Pick a nice Bakelite ring out of the drill:

    Octal Tube - drilled ring
    Octal Tube – drilled ring

    And eventually you can see all the way to the glass envelope:

    Octal Tube - base opening
    Octal Tube – base opening

    The (knockoff) Neopixel LED sits directly below the evacuation tip and is about the same diameter, so much of that enlarged opening will be in shadow. Despite that, the tube does seem noticeably brighter:

    Octal Tube - drilled base opening
    Octal Tube – drilled base opening

    Drilling that tube was so harrowing that I can’t imagine similar surgery on an intact octal base.

    Perhaps just slicing off the tip of the Bakelite spigot and gluing a single very bright red/orange LED in place, rather using than a (knockoff) Neopixel a few millimeters away, will suffice.

    Or just give up, top-light these tubes, and move on?

  • Vacuum Tube LEDs: Miniature 7-pin Tubes With a Bottom Shield

    Apart from the Bakelite bases on octal tubes, I figured there should be no problem shining a light up through the glass envelope. Come to find out that some of the tubes with Miniature 7 bases have an electrostatic shield (?) across the bottom that pretty well blocks the light.

    This 6BJ6 has a neatly trimmed octagon:

    6BJ6 - octagon shield
    6BJ6 – octagon shield

    The shield plate, if that’s what it is, doesn’t have a standardized shape. This 6CB6 sports a simple square:

    6CB6 Square Shield
    6CB6 Square Shield

    The Box o’ Hollow State Electronics contains one 6BE6 tube (a heptode with five grids connected to four pins) without a shield:

    6BE6 - Clear base
    6BE6 – Clear base

    Yeah, those pins are rather grotendous.

    And another 6BE6 with a semitransparent smudge not connected to anything else; it would look accidental if it weren’t inside the tube:

    6BE6 - Tinted Base
    6BE6 – Tinted Base

    All the shielded tubes are pentodes, for whatever difference that makes.

    These tubes may be a bit too small compared to the hard drive platters; Novals will work just fine for my simple purposes.