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.

Tag: Blinkies

Blinking & glowing LEDs

  • Discrete LM3909: Green LED at 1.15 V

    Discrete LM3909: Green LED at 1.15 V

    The green-LED discrete LM3909 is still flashing, even with its AA NiMH cells burned down to 1.15 V:

    LM3909 green LED - 1.15 V NiMH
    LM3909 green LED – 1.15 V NiMH

    If the truth be known, one of the cells is now reverse-charged to 200 mV, so that’s a bit beyond as low as it can go.

    The flash period has stretched to 8.7 s:

    LM3909 green LED - 1.17 V - 8.7s period
    LM3909 green LED – 1.17 V – 8.7s period

    The circuit boosts the battery by 800 mV to put 1.94 V across the green LED at the start of each flash:

    LM3909 green LED - 1.15 V - V LED
    LM3909 green LED – 1.15 V – V LED

    Admittedly, the LED isn’t particularly bright at 2.8 mA:

    LM3909 green LED - 1.15 V - LED current
    LM3909 green LED – 1.15 V – LED current

    But it’s still flashing!

    Swapping the cells into the LM3909 with a blue LED doesn’t produce any blinking, which is about what the earlier tests showed.

  • More AAA-to-AA Alkaline Adapters

    More AAA-to-AA Alkaline Adapters

    Having a handful of not-dead-yet AAA alkalines and a bunch of LED blinkies built for AA alkalines, a pair of adapters seemed in order:

    AAA-to-AA Alkaline Adapters - installed
    AAA-to-AA Alkaline Adapters – installed

    The blinkies need a somewhat wider base than they’d get from a pair of AAA alkalines, so it’s not quite as dumb as it may seem.

    In any event, the positive terminal comes from a brass rod:

    AAA-to-AA Alkaline Adapters - brass terminal
    AAA-to-AA Alkaline Adapters – brass terminal

    Nobody will ever see the fancy Hilbert Curve infill around the brass:

    AAA-to-AA Alkaline Adapters - end view
    AAA-to-AA Alkaline Adapters – end view

    In this application, they’ll go from not-dead-yet to oh-it’s-dead faster than AA cells, so I can watch how the blinkies work with lower voltages.

  • Discrete LM3909: Blue LED Radome

    Discrete LM3909: Blue LED Radome

    Dropping a simplified ping-pong ball radome for a Piranha RGB LED atop a discrete LM3909 on the AA alkaline cell holder:

    Discrete LM3909 Radome - AA alkaline
    Discrete LM3909 Radome – AA alkaline

    The solid model has screw holes for the lid and the revised LED spider:

    Astable Multivibrator - Alkaline AA Base - radome - solid model
    Astable Multivibrator – Alkaline AA Base – radome – solid model

    The RGB LED needs only two wires, as the LM3909 circuit can blink only one LED. I tried all three colors, but only blue and green justify the LM3909 hairball; red can get along with the astable circuit.

    The LED wires connect across a 1 MΩ resistor serving as a mechanical strut between the 9.1 kΩ resistor on the left and the 10 Ω ballast resistor on the right.

    Fresh alkaline cells at 3.0 V put 3.3 V across the blue LED with a 37 mA peak current. Older cells at 2.3 V produce 2.9 V at 15 mA. Dead cells at 1.9 V still fire the LED with 2.7 V at 4.2 mA, although the flash is barely visible in ordinary room light.

    The lovely blue ball looks better in person!

    The OpenSCAD source code as a GitHub Gist:

    // Astable Multivibrator
    // Holder for Alkaline cells
    // Ed Nisley KE4ZNU August 2020
    // 2020-09 add LED radome
    /* [Layout options] */
    Layout = "Build"; // [Build,Show,Lid,Spider]
    /* [Hidden] */
    CellName = "AA"; // [AA] — does not work with anything else
    NumCells = 2; // [2] — likewise
    Struts = -1; // [0:None, -1:Dual, 1:Quad] — Quad is dead
    // Extrusion parameters
    /* [Hidden] */
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    HoleWindage = 0.2;
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    function IntegerLessMultiple(Size,Unit) = Unit * floor(Size / Unit);
    Protrusion = 0.1; // make holes end cleanly
    inch = 25.4;
    //- Basic dimensions
    WallThick = IntegerMultiple(3.0,ThreadWidth);
    CornerRadius = WallThick/2;
    FloorThick = IntegerMultiple(3.0,ThreadThick);
    TopThick = IntegerMultiple(2.0,ThreadThick);
    WireOD = 1.5; // battery & LED wiring
    WireOC = 4;
    Gap = 5.0;
    // Cylindrical cell sizes
    // https://en.wikipedia.org/wiki/List_of_battery_sizes#Cylindrical_batteries
    CELL_NAME = 0;
    CELL_OD = 1;
    CELL_OAL = 2;
    // FIXME search() needs special-casing to properly find AAA and AAAA
    // Which is why CellName is limited to AA
    CellData = [
    ["AAAA",8.3,42.5],
    ["AAA",10.5,44.5],
    ["AA",14.5,50.5],
    ["C",26.2,50],
    ["D",34.2,61.5],
    ["A23",10.3,28.5],
    ["CR123A",17.0,34.5],
    ["18650",18.8,65.2], // bare 18650 with button end
    ["18650Prot",19.0,70.0], // protected 18650 = 19670 plus a bit
    ];
    CellIndex = search([CellName],CellData,1,0)[0];
    echo(str("Cell index: ",CellIndex," = ",CellData[CellIndex][CELL_NAME]));
    //- Contact dimensions
    CONTACT_NAME = 0;
    CONTACT_WIDE = 1;
    CONTACT_HIGH = 2;
    CONTACT_THICK = 3; // plate thickness
    CONTACT_TIP = 4; // tip to rear face
    CONTACT_TAB = 5; // solder tab width
    ContactData = [
    ["AA+",12.2,12.2,0.3,1.7,3.5], // pos bump
    ["AA-",12.2,12.2,0.3,5.0,3.5], // half-compressed neg spring
    ["AA+-",28.2,12.2,0.3,5.0,0], // pos-neg bridge
    ["Li+",18.5,16.0,0.3,2.8,5.5],
    ["Li-",18.5,16.0,0.3,6.0,5.5],
    ];
    function ConDat(name,dim) = ContactData[search([name],ContactData,1,0)[0]][dim];
    ContactRecess = 2*ConDat(str(CellName,"+"),CONTACT_THICK);
    ContactOC = CellData[CellIndex][CELL_OD];
    WireBay = 6.0; // room for wiring to contacts
    //- Wire struts
    StrutDia = 1.6; // AWG 14 = 1.6 mm
    StrutSides = 3*4;
    ID = 0;
    OD = 1;
    LENGTH = 2;
    StrutBase = [StrutDia,StrutDia + 2*5*ThreadWidth, // ID = wire, OD = buildable
    FloorThick + CellData[CellIndex][CELL_OD]]; // LENGTH = base is flush with cell top
    //- Holder dimensions
    BatterySize = [CellData[CellIndex][CELL_OAL] + // cell
    ConDat(str(CellName,"+"),CONTACT_TIP) + // pos contact
    ConDat(str(CellName,"-"),CONTACT_TIP) – // neg contact
    2*ContactRecess, // sink into wall
    NumCells*CellData[CellIndex][CELL_OD],
    CellData[CellIndex][CELL_OD]
    ];
    echo(str("Battery space: ",BatterySize));
    CaseSize = [3*WallThick + // end walls + wiring partition
    BatterySize.x + // cell
    WireBay, // wiring bay
    2*WallThick + BatterySize.y,
    FloorThick + BatterySize.z
    ];
    BatteryOffset = (CaseSize.x – (2*WallThick +
    CellData[CellIndex][CELL_OAL] +
    ConDat(str(CellName,"-"),CONTACT_TIP))
    ) /2 ;
    ThumbRadius = 0.75 * CaseSize.z;
    StrutOC = [IntegerLessMultiple(CaseSize.x – 2*CornerRadius -2*StrutBase[OD],5.0),
    IntegerMultiple(CaseSize.y + StrutBase[OD],5.0)];
    StrutAngle = atan(StrutOC.y/StrutOC.x);
    echo(str("Strut OC: ",StrutOC));
    LidSize = [2*WallThick + WireBay + ConDat(str(CellName,"+"),CONTACT_THICK), CaseSize.y, FloorThick/2];
    LidScrew = [2.0,3.8,7.0]; // M2 pan head screw (LENGTH = threaded)
    LidScrewOC = CaseSize.y/2 – CornerRadius – LidScrew[OD]; // allow space around screw head
    //- Piranha LEDs
    PiranhaBody = [8.0,8.0,8.0]; // Z = heatsink fins + body + lens height
    PiranhaPin = 0.0; // trimmed pin length beyond heatsink
    PiranhaPinsOC = [5.0,5.0]; // pin XY distance
    PiranhaRecess = PiranhaBody.z + PiranhaPin/2; // minimum LED recess depth
    BallOD = 40.0; // radome sphere
    BallSides = 4*StrutSides; // nice smoothness
    BallPillar = [norm([PiranhaBody.x,PiranhaBody.y]), // ID
    norm([PiranhaBody.x,PiranhaBody.y]) + 3*WallThick, // OD
    StrutBase[OD] + PiranhaBody.z]; // height to base of chord
    echo(str("Pillar OD: ",BallPillar[OD]));
    BallChordM = BallOD/2 – sqrt(pow(BallOD/2,2) – (pow(BallPillar[OD],2))/4);
    echo(str("Ball chord depth: ",BallChordM));
    //———————-
    // 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);
    }
    // Spider for single LED atop struts, with the ball
    module DualSpider() {
    difference() {
    union() {
    for (j=[-1,1]) {
    translate([0,j*StrutOC.y/2,StrutBase[OD]/2])
    rotate(180/StrutSides)
    sphere(d=StrutBase[OD]/cos(180/StrutSides),$fn=StrutSides);
    translate([0,j*StrutOC.y/2,0])
    rotate(180/StrutSides)
    cylinder(d=StrutBase[OD],h=StrutBase[OD]/2,$fn=StrutSides);
    }
    translate([0,0,StrutBase[OD]/4]) // connecting bars
    cube([StrutBase[OD]*cos(180/StrutSides),StrutOC.y,StrutBase[OD]/2],center=true);
    cylinder(d=BallPillar[OD],h=BallPillar[LENGTH],$fn=BallSides);
    }
    for (j=[-1,1]) // strut wires
    translate([0,j*StrutOC.y/2,-Protrusion])
    PolyCyl(StrutBase[ID],StrutBase[OD]/2,6);
    for (n=[-1,1]) // LED wiring
    rotate(n*90)
    translate([StrutOC.x/3,0,-Protrusion])
    PolyCyl(StrutBase[ID],StrutBase[OD],6);
    translate([0,0,BallOD/2 + BallPillar[LENGTH] – BallChordM]) // ball inset
    sphere(d=BallOD);
    translate([0,0,BallPillar.z – PiranhaRecess + BallPillar.z/2]) // LED inset
    cube(PiranhaBody + [HoleWindage,HoleWindage,BallPillar.z],center=true); // XY clearance
    translate([0,0,StrutBase[OD]/2 + WireOD/2 + 0*Protrusion]) // wire channels
    cube([WireOD,BallPillar[OD] + 2*WallThick,WireOD],center=true);
    }
    }
    //– Overall case with origin at battery center
    module Case() {
    union() {
    difference() {
    union() {
    hull()
    for (i=[-1,1], j=[-1,1])
    translate([i*(CaseSize.x/2 – CornerRadius),
    j*(CaseSize.y/2 – CornerRadius),
    0])
    cylinder(r=CornerRadius/cos(180/8),h=CaseSize.z,$fn=8); // cos() fixes undersize spheres!
    if (Struts)
    for (i = (Struts == 1) ? [-1,1] : -1) { // strut bases
    hull()
    for (j=[-1,1])
    translate([i*StrutOC.x/2,j*StrutOC.y/2,0])
    rotate(180/StrutSides)
    cylinder(d=StrutBase[OD],h=StrutBase[LENGTH],$fn=StrutSides);
    translate([i*StrutOC.x/2,0,StrutBase[LENGTH]/2])
    cube([2*StrutBase[OD],StrutOC.y,StrutBase[LENGTH]],center=true); // blocks for fairing
    for (j=[-1,1]) // hemisphere caps
    translate([i*StrutOC.x/2,
    j*StrutOC.y/2,
    StrutBase[LENGTH]])
    rotate(180/StrutSides)
    sphere(d=StrutBase[OD]/cos(180/StrutSides),$fn=StrutSides);
    }
    }
    translate([BatteryOffset,0,BatterySize.z/2 + FloorThick]) // cells
    cube(BatterySize + [0,0,Protrusion],center=true);
    translate([BatterySize.x/2 + BatteryOffset + ContactRecess/2 – Protrusion/2, // contacts
    0,
    BatterySize.z/2 + FloorThick])
    cube([ContactRecess + Protrusion,
    ConDat(str(CellName,"+-"),CONTACT_WIDE),
    ConDat(str(CellName,"+-"),CONTACT_HIGH)
    ],center=true);
    translate([-(BatterySize.x/2 – BatteryOffset + ContactRecess/2 – Protrusion/2),
    ContactOC/2,
    BatterySize.z/2 + FloorThick])
    cube([ContactRecess + Protrusion,
    ConDat(str(CellName,"+"),CONTACT_WIDE),
    ConDat(str(CellName,"+"),CONTACT_HIGH)
    ],center=true);
    translate([-(BatterySize.x/2 – BatteryOffset + ContactRecess/2 – Protrusion/2),
    -ContactOC/2,
    BatterySize.z/2 + FloorThick])
    cube([ContactRecess + Protrusion,
    ConDat(str(CellName,"-"),CONTACT_WIDE),
    ConDat(str(CellName,"-"),CONTACT_HIGH)
    ],center=true);
    translate([-CaseSize.x/2 + WireBay/2 + WallThick, // wire bay with screw bosses
    0,
    BatterySize.z/2 + FloorThick + Protrusion/2])
    cube([WireBay,
    2*LidScrewOC – LidScrew[ID] – 2*4*ThreadWidth,
    BatterySize.z + Protrusion
    ],center=true);
    for (j=[-1,1]) // screw holes
    translate([-CaseSize.x/2 + WireBay/2 + WallThick,
    j*LidScrewOC,
    CaseSize.z – LidScrew[LENGTH] + Protrusion])
    PolyCyl(LidScrew[ID],LidScrew[LENGTH],6);
    for (j=[-1,1])
    translate([-(BatterySize.x/2 – BatteryOffset + WallThick/2), // contact tabs
    j*ContactOC/2,
    BatterySize.z + FloorThick – Protrusion])
    cube([2*WallThick,
    ConDat(str(CellName,"+"),CONTACT_TAB),
    (BatterySize.z – ConDat(str(CellName,"+"),CONTACT_HIGH))
    ],center=true);
    if (false)
    translate([0,0,CaseSize.z]) // finger cutout
    rotate([90,00,0])
    cylinder(r=ThumbRadius,h=2*CaseSize.y,center=true,$fn=22);
    translate([0,0,ThreadThick – Protrusion]) // recess around name
    cube([0.6*CaseSize.x,8,2*ThreadThick],center=true);
    if (Struts)
    for (i2 = (Struts == 1) ? [-1,1] : -1) { // strut wire holes and fairing
    for (j=[-1,1])
    translate([i2*StrutOC.x/2,j*StrutOC.y/2,FloorThick])
    rotate(180/StrutSides)
    PolyCyl(StrutBase[ID],2*StrutBase[LENGTH],StrutSides);
    for (i=[-1,1], j=[-1,1]) // fairing cutaways
    translate([i*StrutBase[OD] + (i2*StrutOC.x/2),
    j*StrutOC.y/2,
    -Protrusion])
    rotate(180/StrutSides)
    PolyCyl(StrutBase[OD],StrutBase[LENGTH] + 2*Protrusion,StrutSides);
    }
    }
    translate([0,0,0])
    linear_extrude(height=2*ThreadThick + Protrusion,convexity=10)
    mirror([0,1,0])
    text(text="KE4ZNU",size=6,spacing=1.20,font="Arial:style:Bold",halign="center",valign="center");
    }
    }
    module Lid() {
    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/cos(180/8),$fn=8);
    translate([0,0,-LidSize.z]) // remove bottom
    cube([(LidSize.x + 2*Protrusion),(LidSize.y + 2*Protrusion),2*LidSize.z],center=true);
    for (j=[-1,1]) // wire holes
    translate([0,j*WireOC,-Protrusion])
    PolyCyl(WireOD,2*LidSize.z,6);
    for (j=[-1,1])
    translate([0,j*LidScrewOC,-Protrusion])
    PolyCyl(LidScrew[ID],2*LidSize.z,6);
    }
    }
    //——————-
    // Build it!
    if (Layout == "Case")
    Case();
    if (Layout == "Lid")
    Lid();
    if (Layout == "Spider")
    if (Struts == -1)
    DualSpider();
    else
    cube(10,center=true);
    if (Layout == "Build") {
    rotate(90)
    Case();
    translate([0,-(CaseSize.x/2 + LidSize.x/2 + Gap),0])
    rotate(90)
    Lid();
    if (Struts == -1)
    translate([CaseSize.x/2,0,0])
    DualSpider();
    }
    if (Layout == "Show") {
    Case();
    translate([-CaseSize.x/2 + LidSize.x/2,0,(CaseSize.z + Gap)])
    Lid();
    }
  • Discrete LM3909: Blue LED Waveforms

    Discrete LM3909: Blue LED Waveforms

    The circuitry and instrumentation is essentially the same discrete LM3909 as before:

    LM3909 - blue - test setup
    LM3909 – blue – test setup

    With a few minor tweaks:

    • Blue LED, forward voltage 2.56 to 2.97 V
    • 24 Ω R1
    • One Q2 current mirror transistor driving Q3

    With a pair of fresh AA alkaline cells producing 3.1 V (not the NiMH Duracells you see in the picture), the blue LED blinks brightly.

    The 610 mV peak voltage across R1 shows the LED starts at 25.4 mA:

    LM3909 blue - 3.1 V - R1 24 ohm
    LM3909 blue – 3.1 V – R1 24 ohm

    The capacitor reaches 1 V, then goes about 150 mV into reverse charge during the flash (note the different horizontal scales):

    LM3909 blue - 3.1 V - C1 V
    LM3909 blue – 3.1 V – C1 V

    The Darlington version of Q1 seems to do a decent job of keeping the cap out of reverse charge. A Shottky diode would add a few hundred mV, but I doubt there’s anything nasty going on inside the cap as it stands.

    The blue LED has a forward drop of 2.97 V at 20 mA, so I’m surprised the voltage across it hits 3.1 V at 25 mA:

    LM3909 blue - 3.1 V - LED V
    LM3909 blue – 3.1 V – LED V

    Very little of the voltage appears across Q3, the driver transistor:

    LM3909 blue - 3.1 V - Q3 coll
    LM3909 blue – 3.1 V – Q3 coll

    With a pair of nearly dead alkaline cells for a 2.0 V supply, the LED current peak drops to 4.6 mA:

    LM3909 blue - 2.0 V - R1 24 ohm
    LM3909 blue – 2.0 V – R1 24 ohm

    The LED lights brightly, then fades away exactly like you’d expect from that waveform.

    The cap still charges to about 1 V and stays well above 0 V during the (much longer) flash:

    LM3909 blue - 2.0 V - C1 voltage
    LM3909 blue – 2.0 V – C1 voltage

    The voltage across the LED now reaches only 2.7 V, which is substantially higher than the 2.0 V battery supply and exactly why the LM3909 existed:

    LM3909 blue - 2.0 V - LED voltage
    LM3909 blue – 2.0 V – LED voltage

    Q3 continues to saturate, although you can see the effect of the decreased base drive during the flash:

    LM3909 blue - 2.0 V - Q3 coll
    LM3909 blue – 2.0 V – Q3 coll

    The blue LED won’t light at 1.3 V, but still gives out a weak flash at 1.7 V, so I’d say the tweaked LM3909 circuitry works reasonably well.

  • Alkaline AA Astable vs. RGB and Yellow LEDs

    Alkaline AA Astable vs. RGB and Yellow LEDs

    A fresh pair of alkaline AA cells at 3.2(-ish) V can’t light a Vf = 3 V blue LED with any authority, but I laid out an astable multivibrator circuit with a Piranha RGB LED to see how the colors looked:

    Astable AA Alkaline - build test
    Astable AA Alkaline – build test

    Lighting all three LEDs at once doesn’t make much sense, although I did try it just for the amusement. Spoiler: red wins, even with more-or-less equal currents.

    Mounting the hairball on an AA alkaline holder looks better:

    Astable AA Alkaline - RGB LED test
    Astable AA Alkaline – RGB LED test

    Red being the only LED color making any kind of sense meant the Piranha was overqualified for the job, so I replaced all that clutter with a simple 5 mm yellow LED:

    Astable AA Alkaline - yellow
    Astable AA Alkaline – yellow

    It’s shatteringly bright at 20 mA from fresh alkalines at 3.2 V and remains visible down to 1.8 V.

    The original circuit schematic / layout doodle:

    Astable wiring layout - Piranha RGB test
    Astable wiring layout – Piranha RGB test

    No surprise in any of this, as it’s why the discrete LM3909 circuitry happened, but it’s nice to have a simple LED atop some alkalines for show-n-tell. If, of course, show-n-tell events ever happen again …

  • Discrete LM3909 vs. DSO150 Scope

    Discrete LM3909 vs. DSO150 Scope

    Although I’m a big fan of multi-channel scopes and Hall-effect current probes, a dirt-cheap single-trace oscilloscope can get you quite a ways to the goal:

    LM3909 - DSO150 test setup
    LM3909 – DSO150 test setup

    That’s a genuine JYETech DSO150 powered by an 18650 lithium cell and a boost converter set to 9 V. Make sure you get a genuine DSO150 from an authorized seller, rather than one of the myriad knockoffs; it doesn’t cost much more and tends to reward the right folks.

    Anyhow, battery power means you can connect it directly across components to measure what would otherwise be a differential voltage:

    LM3909 - Darl Q1 3x Q2 - 1.5 V - R1 V - DSO150
    LM3909 – Darl Q1 3x Q2 – 1.5 V – R1 V – DSO150

    That’s the voltage across R1, the 39 Ω LED ballast resistor in the discrete LM3909 circuit running from a 1.5 V supply. Divide the 314 mV peak by 39 Ω to get 8 mA of LED current.

    The voltage across C1, the timing and boost capacitor, looks like this:

    LM3909 - Darl Q1 3x Q2 - 1.5 V - C1 V - DSO150
    LM3909 – Darl Q1 3x Q2 – 1.5 V – C1 V – DSO150

    So the cap adds half a volt to the supply in order to put 2.0 V across the LED, which accounts for the relatively low current; the green LED has a forward drop of about 2.2 V at 20 mA and 1.9 V at µA-level current.

    For completeness, the voltage across the LED:

    LM3909 - Darl Q1 3x Q2 - 1.5 V - Green LED V - DSO150
    LM3909 – Darl Q1 3x Q2 – 1.5 V – Green LED V – DSO150

    So, yup, the LED really does see 2.0 V. I love it when the numbers work out.

    Crank the supply to 3 V and see this across R1:

    LM3909 - Darl Q1 3x Q2 - 3.2 V - R1 V - DSO150
    LM3909 – Darl Q1 3x Q2 – 3.2 V – R1 V – DSO150

    The LED current is now 1.23 V / 39 Ω = 33 mA.

    The capacitor just barely enters reverse charge:

    LM3909 - Darl Q1 3x Q2 - 3.2 V - C1 V - DSO150
    LM3909 – Darl Q1 3x Q2 – 3.2 V – C1 V – DSO150

    Pop quiz: what voltage to you expect to see across the LED?

    I’ll leave further investigation to your imagination, but for low-frequency analog work, you can do worse than a DSO150.

  • Discrete LM3909: First Light

    Discrete LM3909: First Light

    Another entry in the “The bigger the blob, the better the job” soldering contest:

    LM3909 - Darl Q1 3x Q2 mirror - installed
    LM3909 – Darl Q1 3x Q2 mirror – installed

    It’s a discrete-transistor version of the LM3909 atop the alkaline AA cell holder, with a little PTC fuse for that good safety vibe. The overall layout follows this doodle:

    LM3909 wiring layout - Darl Q1 - 3x Q2 gain
    LM3909 wiring layout – Darl Q1 – 3x Q2 gain

    The four transistors across the bottom row let me test the simulation suggesting there’s no need for the 3× current gain mentioned in the App Note. Spoiler: future LM3909 circuits have the usual two-transistor mirror.

    Adding some instrumentation required a bit of unsoldering and clip-lead action: to get the Tek current probe around the LED wiring:

    LM3909 - Darl Q1 3x Q2 mirror - test setup
    LM3909 – Darl Q1 3x Q2 mirror – test setup

    The voltage probe is across the LED, although you’ll also see the voltage across the capacitor and differential voltages measured properly with the common clip leads on the battery negative terminal. I unsoldered two of the mirror transistors after verifying a single mirror transistor can saturate Q3.

    Removing the AA cells and feeding it with 3 V from a bench supply:

    LM3909 - Darl Q1 1x Q2 - V on C1 - I 3V VCC 10 mA-div
    LM3909 – Darl Q1 1x Q2 – V on C1 – I 3V VCC 10 mA-div

    The yellow trace is the voltage at the collector of Q3 = positive terminal of C1. The purple trace is the voltage at the LED cathode = negative terminal of C1. The fuzzy white trace is the difference of those two, showing C1 charges to about 1 V at the start of the LED flash. The white wedge over on the left marks the 0 V level, confirming the cap doesn’t enter reverse-charge territory during the flash.

    The green LED produces a bright flash starting at 30 mA (bottom trace, 10 mA/div) for 15 ms. With 1 V on the cap, the LED + 39 Ω ballast resistor see nearly 4 V at the start of the pulse, because Q3 saturates around 20 mV.

    Reducing the supply voltage to 1.5 V flattens the current and lengthens the flash to 35 ms:

    LM3909 - Darl Q1 1x Q2 - V on C1 - I 1.5V VCC 10 mA-div
    LM3909 – Darl Q1 1x Q2 – V on C1 – I 1.5V VCC 10 mA-div

    The cap still charges to 1 V between on-times, but the lower supply puts barely 2.5 V across the LED + 39 Ω resistor and the current peaks at 10 mA. The increased duration turns the flash into a blink.

    It’s good enough, so AA alkalines should last quite a while.