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

  • JYE Tech DSO150 Oscilloscope vs. Actual Signals

    The DSO150 oscilloscope’s specs give a 200 kHz bandwidth, so a 50 kHz sine wave looks pretty good:

    DSO150 - sine wave 50 kHz 10 us-div
    DSO150 – sine wave 50 kHz 10 us-div

    A 100 kHz sine wave looks chunky, with maybe 25 samples per cycle:

    DSO150 - sine wave 100 kHz 10 us-div
    DSO150 – sine wave 100 kHz 10 us-div

    The DSO150 tops out at 10 µs/div, so you can’t expand the waveform more than you see; 25 samples in 10 µs seems to be 2.5 Msample/s, exceeding the nominal 1 Msample/s spec. I have no explanation.

    A 10 kHz square wave shows a blip just before each transition that isn’t on the actual signal:

    DSO150 - square wave 10 kHz 20 us-div
    DSO150 – square wave 10 kHz 20 us-div

    At 50 kHz, there’s not much square left in the wave:

    DSO150 - square wave 50 kHz 10 us-div
    DSO150 – square wave 50 kHz 10 us-div

    And, just for completeness, a 200 kHz square wave completely loses its starch:

    DSO150 - square wave 200 kHz 10 us-div
    DSO150 – square wave 200 kHz 10 us-div

    A 10% (-ish) duty cycle pulse at 25 kHz has frequency components well beyond the scope’s limits, so it’s more of a blip than a pulse:

    DSO150 - pulse 25 kHz 10 us-div
    DSO150 – pulse 25 kHz 10 us-div

    The pulse repetition frequency beats with the scope sampling and sweep speeds to produce weird effects:

    DSO150 - pulse 25 kHz 100 us-div
    DSO150 – pulse 25 kHz 100 us-div

    Tuning the pulse frequency for maximum weirdness:

    DSO150 - pulse 15 kHz 200 us-div
    DSO150 – pulse 15 kHz 200 us-div

    None of this is unique to the DSO150, of course, as all digital scopes (heck, all sampled-data systems) have the same issues. The DSO150’s slow sampling rate just makes them more obvious at lower frequencies.

    Key takeaway: use the DSO150 for analog signals in the audio range, up through maybe 50 kHz, and it’ll produce reasonable results.

    Using it for digital signals, even at audio frequencies, isn’t appropriate, because the DSO150’s low bandwidth will produce baffling displays.

     

  • JYE Tech DSO150 Oscilloscope: Battery Power

    With the DSO150 scope running, I printed Geoff’s DSO150 case + battery holder from Thingiverse, added a few bits & pieces from the heap, and came up with a completely portable scope:

    DSO150 battery hack - first light
    DSO150 battery hack – first light

    The only scope mod consists of embedding a JST-ish connector in the back panel:

    DSO150 battery hack - rear panel connector
    DSO150 battery hack – rear panel connector

    Then soldering it to the battery pads and applying generous hot-melt glue blobs:

    DSO150 battery hack - PCB power
    DSO150 battery hack – PCB power

    Add a scrap 18650 Li-Ion cell, a regulated boost converter, and a switch:

    DSO150 battery hack - interior
    DSO150 battery hack – interior

    The switch is directly below the DSO150 BNC connector to get a little protection for its handle, which would otherwise stick out in harm’s way. This being an afterthought, I drilled the switch hole, rather than modify the solid model.

    Some testing with a bench supply showed that the DSO150 will not operate correctly from the voltages produced by a pair of lithium cells, despite what you’d think from looking at the case. Below 8 V, the internally generated negative supply becomes larger than the positive supply, so the 0 V point isn’t properly centered and the scope loses headroom for large signals; monitoring the internal 3.3 V test signal makes the problem painfully obvious.

    More color commentary from my summary email:

    • Combining a case from Thingiverse with a Li-Ion cell and a regulated boost converter produces a portable scope.
    • The PCB has provision for battery input, so I drilled / filed a square hole for a teeny JST-ish connector on the back panel, secured it with a blob of hot melt glue, and globbed the wires onto the PCB battery pads.
    • The boost converter draws about 400 mA from the cell, so a 2500-ish mA·h cell should last Long Enough™. This is a scrap cell from the recycle box and gave out after maybe four hours.
    • It idles at 8 mA, so I drilled a hole in the back of the case for a toggle switch disconnecting the battery; you’d want the hole in the solid model. Perhaps a better converter would have lower idle current; you’d never be able to tell from the eBay descriptions.
    • Aaaaand it switches around 200 kHz under load, just barely beyond the scope bandwidth. It doesn’t add much noise to the signal, at least with a 50 Ω terminator jammed in the BNC, but the square-wave “cal” output looks awful at 50 mV/div; a real scope shows even more noise. I assume the noise comes directly from the logic supply; with luck, the DSO150’s analog circuitry has Good Enough™ filtering.
    • Which might not matter for logic-level and moderate analog signals, of course, which is the whole point of the DSO150.
    • Conspicuous by their absence: a Li-Ion cell protection PCB and any way to recharge the poor thing …

    I’ve occasionally wanted a portable scope and now I have one!

  • JYE Tech DSO150 Oscilloscope: Build Notes

    I did a quick build of a JYE Tech DSO150 oscilloscope to see how it’d work in a proposed Squidwrench advanced soldering class / kit build session.

    The main board requires adding only a few switches and headers, then removing a 0 Ω jumper resistor:

    DSO150 - main board - bottom
    DSO150 – main board – bottom

    The analog board requires a handful of 1/8 W resistors, various capacitors, switches, and the BNC connector:

    DSO150 - main board - front
    DSO150 – main board – front

    Some (lightly edited) color commentary from my summary email:

    • Just finished assembling the kit, which required two hours; I’m admittedly fussy. The one joint I missed on the input coupling switch required a complete disassembly, but all the rest worked fine.
    • The UI is much better than the DSO138.
    • Soldering the BNC connector requires lots of heat. My ordinary Hakko iron had inadequate grunt, so I deployed the hulking Radio Shack 150 W gun and did the job in seconds.
    • The resistors require a meter to measure them during installation, because they’re 1% 1/8 W jobbies with many teeny color strips in Chinese tints you’ve never seen before. I could not sort them visually, even with a lighted headband magnifier, and I know what I’m looking for.
    • The caps are marked, but using a meter builds confidence.
    • And, yes, the kit had all the right parts and they all worked. The instructions call for powering up the main board before starting assembly, then again after removing a 0 Ω jumper resistor, but that’s the extent of the “testing” required.
    • They recommend a flush cutter and I’d say it’s pretty much required. An ordinary diagonal cutter won’t get close enough to the PCB.
    • I needed an angle-tip tweezer to lay the PCB screws in place.
    • Don’t install the knob until the very last step and maybe wait until you’ve verified all the functions. You have been warned.
    • The minimum power supply voltage really is 8.0 V, not the 7.4 V from a not-quite-fully-charged pair of lithium cells. A 9 V alkaline battery will last a few minutes. A noisy boost converter / crappy 9 V wall wart translates directly into noise on the display, particularly on the internal calibration signal.
    • The “0.1 V” calibration signal turned out to be 150 mV, as measured on a real scope, at 1 kHz. The 3.3 V signal is closer to reality. Both are noisy from a noisy supply.
    • All in all, it’s a pretty good scope for thirty bucks!
    • Newbies will find it a challenging three hour build, for sure.

    The next step involves adding a case and battery power:

    DSO150 battery hack - first light
    DSO150 battery hack – first light
  • Astable Multivibrator vs. Charged NP-BX1 Lithium Battery

    Hitching a charged, albeit worn, NP-BX1 lithium battery to the astable multivibrator produces a blinding flash:

    NP-BX1 Holder - SMT pogo pins
    NP-BX1 Holder – SMT pogo pins

    The current pulse shows the wearable LED really takes a beating:

    Astable - NP-BX1 4V - 100mA-div
    Astable – NP-BX1 4V – 100mA-div

    The current trace is at 100 mA/div: the pulse starts at 400 mA, which seems excessive even to me, and tapers down to 200 mA. It’s still an order of magnitude too high at the end of the pulse.

    On the other paw, maybe a 14% duty cycle helps:

    Astable - NP-BX1 4V - base V - 100mA-div
    Astable – NP-BX1 4V – base V – 100mA-div

    The top trace shows the base drive voltage dropping slightly, although I suspect the poor little transistor can’t take the strain.

    The LED really does need a ballast resistor …

  • Sony NP-BX1 Battery Holder: SMT Pogo Pin Contacts

    The original camera battery test fixtures used contact pins conjured from hulking gold-plated connector pins and coil springs:

    Canon NB-6L holder - contact pin detail
    Canon NB-6L holder – contact pin detail

    The Sony HDR-AS30V camera chewed up and spat out a handful of batteries, all tested in the NP-BX1 test fixture:

    NP-BX1 Holder - show layout
    NP-BX1 Holder – show layout

    Nowadays, SMT pogo pins produce a much more compact holder, so I figured I could put all those batteries to good use:

    NP-BX1 Holder - SMT pogo pins
    NP-BX1 Holder – SMT pogo pins

    That’s the long-suffering astable multivibrator, still soldered to its CR123A holder.

    Obviously, the battery holder should grow ears to anchor the 14 AWG copper posts and would look better in black PETG:

    NP-BX1 Battery Holder - 1.5mm pins - solid model
    NP-BX1 Battery Holder – 1.5mm pins – solid model

    The battery lead wires get soldered to the ends of the pogo pins and are recessed into the slot in the end of the fixture. I used clear epoxy to anchor everything in place.

    Fits perfectly and works fine!

    The OpenSCAD source code as a GitHub Gist:

    // Holder for Sony NP-BX1 Li-Ion battery
    // Ed Nisley KE4ZNU January 2013
    // 2018-11-15 Adapted for wire leads from 1.5 mm test pins, added upright wire bases
    // Layout options
    Layout = "Show"; // Show Build Fit Case Lid Pins
    //- Extrusion parameters – must match reality!
    // Print with +2 shells and 3 solid layers
    ThreadThick = 0.25;
    ThreadWidth = 0.35;
    HoleWindage = 0.2;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    BuildOffset = 3.0; // clearance for build layout
    Gap = 2.0; // separation for Fit parts
    //- Battery dimensions – rationalized from several samples
    // Coordinate origin at battery contact face with key openings below contacts
    Battery = [43.0,30.0,9.5]; // X = length, Y = width, Z = thickness
    Contacts = [[-0.75,6.0,6.2],[-0.75,16.0,6.2]]; // relative to battery edge, front, and bottom
    KeyBlocks = [[1.75,3.70,2.90],[1.75,3.60,2.90]]; // recesses in battery face set X position
    //- Pin dimensions
    ID = 0;
    OD = 1;
    LENGTH = 2;
    PinShank = [1.5,2.0,6.5]; // shank, flange, compressed length
    PinFlange = [1.5,2.0,0.5]; // flange, length included in PinShank
    PinTip = [0.9,0.9,2.5]; // extended spring-loaded tip
    PinChannel = PinFlange[LENGTH] + 0.5; // cut behind flange for solder overflow
    PinRecess = 3.0; // recess behind pin flange end for epoxy fill
    echo(str("Contact tip dia: ",PinTip[OD]));
    echo(str(" .. shank dia: ",PinShank[ID]));
    OverTravel = 0.5; // space beyond battery face at X origin
    //- Holder dimensions
    GuideRadius = ThreadWidth; // friction fit ridges
    GuideOffset = 7; // from compartment corners
    WallThick = 4*ThreadWidth; // holder sidewalls
    BaseThick = 6*ThreadThick; // bottom of holder to bottom of battery
    TopThick = 6*ThreadThick; // top of battery to top of holder
    ThumbRadius = 10.0; // thumb opening at end of battery
    CornerRadius = 3*ThreadThick; // nice corner rounding
    CaseSize = [Battery.x + PinShank[LENGTH] + OverTravel + PinRecess + GuideRadius + WallThick,
    Battery.y + 2*WallThick + 2*GuideRadius,
    Battery.z + BaseThick + TopThick];
    CaseOffset = [-(PinShank[LENGTH] + OverTravel + PinRecess),-(WallThick + GuideRadius),0]; // position around battery
    LidOverhang = 2.0; // over top of battery for retention
    LidSize = [-CaseOffset.x + LidOverhang,CaseSize.y,TopThick];
    LidOffset = [0.0,CaseOffset.y,0];
    //———————-
    // Useful routines
    module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
    Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
    FixDia = Dia / cos(180/Sides);
    cylinder(r=(FixDia + HoleWindage)/2,h=Height,$fn=Sides);
    }
    //——————-
    //– Guides for tighter friction fit
    module Guides() {
    translate([GuideOffset,-GuideRadius,0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    translate([GuideOffset,(Battery.y + GuideRadius),0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    translate([(Battery.x – GuideOffset),-GuideRadius,0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    translate([(Battery.x – GuideOffset),(Battery.y + GuideRadius),0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    translate([(Battery.x + GuideRadius),GuideOffset/2,0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    translate([(Battery.x + GuideRadius),(Battery.y – GuideOffset/2),0])
    PolyCyl(2*GuideRadius,(Battery.z – Protrusion),4);
    }
    //– Contact pins
    // Rotated to put them in their natural oriention
    // Aligned to put tip base / end of shank at Overtravel limit
    module PinShape() {
    translate([-(PinShank[LENGTH] + OverTravel),0,0])
    rotate([0,90,0])
    rotate(180/6)
    union() {
    PolyCyl(PinTip[OD],PinShank[LENGTH] + PinTip[LENGTH],6);
    PolyCyl(PinShank[ID],PinShank[LENGTH] + Protrusion,6); // slight extension for clean cuts
    PolyCyl(PinFlange[OD],PinFlange[LENGTH],6);
    }
    }
    // Position pins to put end of shank at battery face
    // Add wire exit channel between pins
    // Does not include recess access
    module PinAssembly() {
    union() {
    for (p = Contacts)
    translate([0,p.y,p.z])
    PinShape();
    translate([-(PinShank[LENGTH] + OverTravel) + PinChannel/2,
    (Contacts[1].y + Contacts[0].y)/2,
    Contacts[0].z])
    cube([PinChannel,(Contacts[1].y – Contacts[0].y),PinFlange[OD]],center=true);
    }
    }
    //– Case with origin at battery corner
    module Case() {
    difference() {
    union() {
    difference() {
    translate([(CaseSize.x/2 + CaseOffset.x), // basic case shape
    (CaseSize.y/2 + CaseOffset.y),
    (CaseSize.z/2 – BaseThick)])
    hull()
    for (i=[-1,1], j=[-1,1], k=[-1,1])
    translate([i*(CaseSize.x/2 – CornerRadius),
    j*(CaseSize.y/2 – CornerRadius),
    k*(CaseSize.z/2 – CornerRadius)])
    sphere(r=CornerRadius,$fn=8);
    translate([-OverTravel,-GuideRadius,0])
    cube([(Battery.x + GuideRadius + OverTravel),
    (Battery.y + 2*GuideRadius),
    (Battery.z + Protrusion)]); // battery space
    }
    Guides(); // improve friction fit
    translate([-OverTravel,-GuideRadius,0]) // battery keying blocks
    cube(KeyBlocks[0] + [OverTravel,GuideRadius,0],center=false);
    translate([-OverTravel,(Battery.y – KeyBlocks[1].y),0])
    cube(KeyBlocks[1] + [OverTravel,GuideRadius,0],center=false);
    }
    translate([(-OverTravel), // battery top access
    (CaseOffset.y – Protrusion),
    Battery.z])
    cube([CaseSize.x,(CaseSize.y + 2*Protrusion),(TopThick + Protrusion)]);
    translate([(CaseOffset.x – Protrusion), // battery insertion allowance
    (CaseOffset.y – Protrusion),
    Battery.z])
    cube([(CaseSize.x + 2*Protrusion),(CaseSize.y + 2*Protrusion),(TopThick + Protrusion)]);
    translate([(Battery.x – Protrusion), // remove thumb notch
    (CaseSize.y/2 + CaseOffset.y),
    (ThumbRadius)])
    rotate([90,0,0])
    rotate([0,90,0])
    cylinder(r=ThumbRadius,
    h=(WallThick + GuideRadius + 2*Protrusion),
    $fn=22);
    PinAssembly();
    translate([CaseOffset.x + PinRecess/2 + Protrusion/2,(Contacts[1].y + Contacts[0].y)/2,Contacts[0].z])
    cube([PinRecess + Protrusion,
    (Contacts[1].y – Contacts[0].y + PinFlange[OD]),
    2*PinFlange[OD]],center=true);
    }
    }
    // Lid position offset to match case
    module Lid() {
    translate([-LidSize.x/2 + LidOffset.x + LidOverhang,LidSize.y/2 + LidOffset.y,0])
    difference() {
    hull()
    for (i=[-1,1], j=[-1,1], k=[-1,1])
    translate([i*(LidSize.x/2 – CornerRadius),
    j*(LidSize.y/2 – CornerRadius),
    k*(LidSize.z – CornerRadius)]) // double thickness for flat bottom
    sphere(r=CornerRadius,$fn=8);
    translate([0,0,-LidSize.z/2])
    cube([(LidSize.x + 2*Protrusion),(LidSize.y + 2*Protrusion),LidSize.z],center=true);
    cube([LidSize.x/4,0.75*LidSize.y,4*ThreadThick],center=true); // epoxy recess
    }
    }
    //——————-
    // Build it!
    if (Layout == "Case")
    Case();
    if (Layout == "Lid")
    Lid();
    if (Layout == "Pins") {
    color("Silver",0.5)
    PinShape();
    PinAssembly();
    }
    if (Layout == "Show") { // reveal pin assembly
    difference() {
    Case();
    translate([(CaseOffset.x – Protrusion),
    Contacts[1].y,
    Contacts[1].z])
    cube([(-CaseOffset.x + Protrusion),
    CaseSize.y,
    (CaseSize.z – Contacts[0].z + Protrusion)]);
    translate([(CaseOffset.x – Protrusion),
    (CaseOffset.y – Protrusion),
    0])
    cube([(-CaseOffset.x + Protrusion),
    Contacts[0].y + Protrusion – CaseOffset.y,
    CaseSize.z]);
    }
    color("Silver",0.15)
    PinAssembly();
    translate([0,0,Battery.z + Gap])
    Lid();
    }
    if (Layout == "Build") {
    translate([-(CaseSize.x/2 + CaseOffset.x),-(CaseOffset.y – BuildOffset),BaseThick])
    Case();
    translate([CaseSize.y/2,(CaseOffset.x/2 – BuildOffset),0])
    rotate([0,0,90])
    Lid();
    }
    if (Layout == "Fit") {
    Case();
    translate([0,0,(Battery.z + Gap)])
    Lid();
    color("Silver",0.25)
    PinAssembly();
    }
  • Vacuum Tube LEDs: 21HB5A on a Guilloche Platter

    With the Joggy Thing running in LinuxCNC 2.7, touching XY off on the fixture was trivially easy:

    LinuxCNC - Sherline Mill - Logitech Gamepad
    LinuxCNC – Sherline Mill – Logitech Gamepad

    The pips are 100 mm apart at (-50,-50) and (+50,50). Astonishingly, the laser aligner batteries are in fine shape.

    I should have protected the platter before drilling all those holes:

    Guilloche platter - drilling
    Guilloche platter – drilling

    All’s well that ends well:

    21HB5A - Guilloche platter
    21HB5A – Guilloche platter

    It looks even better in the dark, although you’d never know it from this picture:

    21HB5A - Guilloche platter - dark
    21HB5A – Guilloche platter – dark

    I wish I could engrave those patterns on already-drilled platters, but dragging a diamond point into a hole can’t possibly end well. I could deploy the Tiny Sandblaster with a vinyl mask, if I had enough artistic eptitude to lay out a good-looking mask.

  • Kindle Fire Picture Frame: Side Block

    A steel frame that Came With The House™ emerged from a hidden corner and, instants before tossing it in the recycle heap, I realized it had excellent upcycling potential:

    Kindle Fire Picture Frame - Test Run
    Kindle Fire Picture Frame – Test Run

    Stipulated: I need better pictures for not-so-techie audiences.

    Anyhow, my long-disused Kindle Fire fits perfectly into the welded-on clips, with just enough room for a right-angle USB cable, and Photo Frame Slideshow Premium does exactly what’s necessary to show pictures from internal storage with no network connection.

    All I needed was a small block holding the Kindle against the far side of the frame:

    Kindle Frame - side blocks
    Kindle Frame – side blocks

    A strip of double-stick carpet tape holds the block onto the frame. To extract the Kindle, should the need arise, slide it upward to clear the bottom clips, rotate it rearward, and out it comes.

    Getting a good block required three tries, because the basement has cooled off enough to trigger Marlin’s Thermal Runaway protection for the M2’s platform heater. A test fit after the first failure showed the long leg was 1 mm too wide and, after the second failure, I reduced the fan threshold to 15 s and the minimum layer time to 5 s, producing the third block without incident.

    The platform heater runs at 40 V and I considered bumping it to 43 V for a 15% power boost, but it has no trouble keeping up when the fan isn’t blowing chilly basement air across its surface.

    The OpenSCAD source code, such as it is, doesn’t deserve its own GitHub Gist:

    // Block to hold Kindle in a picture frame mount
    // Ed Nisley - KE4ZNU
    // November 2018
    
    Protrusion = 0.1;
    
    difference() {
    
      cube([18,44,10]);
      translate([-Protrusion,-Protrusion,-Protrusion])
        cube([18-4 + Protrusion,44-10 + Protrusion,10 + 2*Protrusion]);
    
    }