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

  • Tone Encoding/Squelch vs. APRS Packet Reception Reliability

    We’ve been using ham radios on our bikes for years, but last year I put together an interface that connects a TinyTrak3+ GPS encoder to the helmet mic amp. This year I’m building two more, about which I’ll write later.

    The problem is that listening to APRS data bursts isn’t all that pleasant, although it’s bearable, but it’ll get much worse when we use 144.39 MHz as our intercom frequency so we can both talk and be tracked: we’d hear all the APRS traffic within digipeater range.

    Now, admittedly, talking on 144.39 isn’t standard. The local APRS wizards have given tentative approval, as we can’t figure out a better way to talk, give position reports, and not carry two radio / battery / antenna / electronics packages on each bike. As long as we don’t do a lot of yakking, we shouldn’t interfere with the digital traffic very much… and we don’t do a lot of talking while riding.

    So I figured I’d send a 100 Hz tone under the audio and enable tone squelch, so we wouldn’t hear packets from anybody else. We’d still hear each other blatting away, but if I set the TT3+ encoders to send a position report every 10 minutes, it ought to be bearable.

    The catch with this is that some receivers / APRS decoders can’t handle subaudible tones. I considered Digital Coded Squelch, but one of our radios doesn’t include that feature, alas.

    To get some idea of how tone would work with the APRS setup around here (which is where we do most of our riding), I set up an HT on the bench with the TT3+ and my interface. The antenna is an HF/VHF discone, indoors, on the basement floor, beside a window. The GPS receiver can see a slice of sky from its perch just outside the basement window under an awning. That’s about as terrible a setup as we have on our bikes: low power, bad antenna, obscured line-of-sight.

    Each test ran 10-14 hours, the TT3+ sent a packet every 5 minutes, and I checked the raw packet results on aprs.fi.

    With tone off and the TT3+ waiting for 3 seconds of audio silence before transmitting, 39% of the packets got through to the APRS-IS backbone.

    With tone on and, thus, the TT3+ unable to hear / avoid other traffic, 47% of the packets got through on one test and 42% on another. The higher rate was overnight, when (I think) there’s less traffic on 144.39.

    Putting the gadgetry back on the bike, parking it beside the garage, and letting it run for 5 hours on a Saturday afternoon showed that 81% of the packets made it to the backbone. Some of the packets were received by stations over 30 miles away, which probably coincided with the the closer receivers hearing transmitters hidden from the more distant ones.

    The only conclusion I can come to is that tone squelch isn’t going to hurt anything around here, where the APRS wizards have done a great job of getting the decoders to cope with subaudible tones. How it’ll work elsewhere is up for grabs, but we’ll burn that bridge when we come to it.

    And it turns out that the radios take about half a second to wake up and activate the audio output with tone squelch enabled, so we don’t actually hear the data bursts: they’re almost always finished and we may hear dead air for a fraction of a second. Because the TT3+ can’t do collision avoidance, we sometimes hear other packets from other transmitters before the squelch closes again, but it’s not objectionable. Whew!

    Update: with the TT3+ set to transmit every 3 minutes, it works fine!

  • Byonics TinyTrak3+ GPS Power Control

    GPS power from MOSFET relay
    GPS power from MOSFET relay

    The Byonics TinyTrak3+ GPS encoder has a “Power Control” output that can switch the power to a radio or GPS interface. J6 provides the interface: pin 1 = common, pin 2 = high active.

    With the “Power Switch” option enabled in the config program, you can set the number of seconds to allow the GPS unit to get up to speed before the next scheduled transmission.

    I glued a surface-mount MOSFET relay to the back of the PCB with urethane adhesive; it fits neatly between the DIP microcontroller’s pins with one output lead soldered to the 5V pad of J7. The other lead goes to the center +V pad; because the relay uses back-to-back MOSFETs, the polarity doesn’t matter.

    That replaces the normal solder bridge across J7 that provides power (on pin 4) to the GPS2 plugged into the DB9 connector. When the relay’s on, it connects the GPS to the power supply. When it’s off, the GPS goes dark.

    The relay input is an LED with a forward drop of 1.3 V max and requires 4 mA to turn on: figure 3.7 V / 4 mA = 925 Ω max. I kludged an 890 Ω resistor by paralleling (stacking!) 1.5 k and 2.2 k resistors; you could probably use anything near that and it’d work fine.

    The relay is an OMRON G3VM-21GR1, part number A11171 from Electronics Goldmine, but I suspect any teeny little solid-state relay would work. The max on resistance is about 1 Ω and the receiver draws about 65 mA. I measured about 20 mV of drop, so the actual resistance is a lot lower than the spec.

    I initially set the power-on delay to 10 seconds, which seemed to be OK: the GPS (green) LED would blink a few times, then go solid. Alas, the warm-start spec for the Byonics GPS2 (see the GPS3 for details) receiver is really 38 seconds, average, and it was definitely producing bogus position data. So I set the delay to 60 seconds and we’ll see how that works; early reports indicate the coordinates still have plenty of jitter.

    [Update: 60 seconds is iffy. 90 seconds seems to work pretty well. A bit of rummaging says that the satellites broadcast their ephemeris data every 30 seconds, so 90 seconds allows for two complete update cycles. Maybe 100 seconds would be even better. Some old background info for Garmin hand-held receivers is there.]

    It’s obviously a tradeoff between accuracy and battery life. This is for use on a bicycle and, believe me, I don’t want to tote a huge battery!

    If the control signal was low-active, then you could use a cheap PNP transistor as a high-side power switch.

    The white/orange wire routes regulated 5 V through an otherwise unused pin to the homebrew interface that combines the GPS data with helmet mic audio. The tiny rectangle is a 1 µF cap that helps cut down digital noise. There’s no need for a connector on that end, as it’s wired directly to the interface circuit board inside a small enclosure.

  • Electronic Ballast Shoplights: So Much For Efficiency

    Just picked up a batch of electronic-ballast shoplights from Lowe’s, motivated by a 10% off card they sent a while ago. Not a killer deal, but it evidently got plenty of folks into the store on a Sunday morning.

    The new lights don’t claim much about their abilities, other than “Electronic Cold Weather Start (0° F)” and that the reflector sizing requires T8 (1″ dia) fluorescent tubes. One would expect an electronic ballast to have a decent power factor and improved efficiency.

    Because I’m that sort of bear, I opened one up to see what was inside. Here’s the ballast:

    Electronic Ballast Dataplate
    Electronic Ballast Dataplate

    Although the fixture is sized for T8 tubes, the ballast would be perfectly happy with T12s. Similarly, the box insists on F32 tubes, but the ballast is OK with F40s.

    I thought a comparison with one of my old magnetic-ballast fixtures would be of interest, so I hitched up the Kill-A-Watt meter and ran some comparisons.

    The results…

    Amp Watt VoltAmp PF
    Old magnetic ballast
    F40T12 0.64 60 76 0.79
    F32T8 1.11 80 126 0.62
    New electronic ballast
    F40T12 0.75 47 89 0.53
    F32T8 0.77 49 91 0.54

    The electronic ballast has a much lower power factor and thus much higher current. The box & ballast don’t say anything about power factor correction and, wow, there sure isn’t any. The power company hates gadgets like this…

    I cannot compare the brightness because the F40 tubes are several years old, but it’s interesting that the electronic ballast runs both tube sizes at essentially the same power (just as the dataplate indicates, sorta-kinda). The magnetic ballast really cooks the piss out of the smaller tubes, though… or it’s dumping a lot of energy into the ballast. Hard to say.

    The T12 tubes are rated for 3000 lumens & 20 k hours. The new box of T8 tubes I got a while back are 2800 lumens and 24 k hours. Frankly, I don’t believe any of those numbers, particularly given the actual power consumption: it looks like either ballast runs them at just 75% of their rated power.

    Anyhow, these were the cheapest shoplights in stock; I bought eight of ’em, because I’ve been replacing one dead fixture every month or two for the last year. I’d like to think I’d get a better ballast if I spent twice as much, but to a good first approximation the additional cost seems to have gone into black plastic trim and a burnished-chrome exterior finish; not what I need in the Basement Laboratory.

    I wish the boxes were more forthcoming so you didn’t need to perform exploratory surgery.

  • Arduino Hack-job LCD Negative Bias Supply

    Most character-mode LCDs seem to be happy with a VEE supply of about 0 V, which produces enough contrast to get by. If you have a negative supply handy, then it’s easy to goose it with a little negative bias and improve the contrast.

    What if you don’t have a negative supply and you’re using an old craptastic LCD that really wants VEE = -1 V and you didn’t realize that until you had everything wired up and it’s a one-off / low-duty-cycle instrument that you don’t want to spend much more time on?

    Just whack up a quick-and-dirty charge pump inverter…

    Quick and dirty LCD VEE Inverter
    Quick and dirty LCD VEE Inverter

    It turns out that the circuitry already had a 33 kHz PWM square-wave signal driving something else, so I air-wired this inverting charge pump to the PWM output. You could, of course, put an otherwise unoccupied PWM output to good use, which is a better idea if you have the option.

    You can use a PWM output, but the charge pump depends on being fully charged & discharged in every cycle. Run your own numbers.

    The LCD’s VEE input dumps about 1 mA to the supply, which means the charge pump must be able to pull out 1 mC/s, more or less. At 33 kHz, each cycle must haul 30 nC.

    Assuming the Arduino (well, any microcontroller will do, but that’s what I’m using) has a 5 V power supply and the output pin isn’t overloaded from the rest of its function and the cap charges & discharges completely during each half-cycle, then the first cap must store that 30 nC of charge. You want a lot more than that so you have a stiff supply to work with.

    Q = CV, so you need at least 30 nC/5 V = 6 nF. Nothing exceeds like excess, so I soldered a 220 nF box cap standing up from the header pin on the circuit board and air-wired the diodes in place. That will transfer lots more charge and keep the voltage nicely negative.

    I have a lifetime supply of 10 µF solid tantalum caps, so that’s what I used for the filter cap. Regulation isn’t critical, but each pump cycle shouldn’t change the voltage on that cap very much. In fact, pulling 220 nF * 5 V = 1 µC from the filter cap while injecting 30 nC from the LCD leaves you with a whopping 970 nC deficit: it’ll stay around -5 V just fine.

    Actually, it won’t. The negative supply will be about two diode drops above -5 V. The diodes aren’t carrying a lot of current, so they’ll be running at maybe half a volt apiece. Call it -4 V, more or less. You could use Schottky diodes if you need more negative volts.

    If the LCD dumps 1 mA into the supply and -1 V produces the right contrast, then a 3 k resistor will drop the necessary voltage from the supply.

    As it turned out, the LCD dumped 800 µA, -0.8 V gave the right contrast, and a 4.7 k resistor worked just fine. Maybe you want a twiddlepot in there to adjust things.

    You need that little cap right at the LCD VEE pin to soak up the spikes from the LCD drive multiplexing, as this “power supply” has nearly 5 k output impedance. Yow!

    If you’re worried about temperature compensation, then you’ll need something fancier. In that case, you’ll also want a Spice model to be sure all these rough-and-ready calculations cut somewhere close to the truth.

    Memo to Self: maybe next time this should be on the PCB right from the start, even if it’s not really needed? Or, much better, just go with a single-chip inverter and be done with it!

    Update: If you’re worried about driving a bare cap from your microcontroller pin, add a small-value series resistor. The time constant should be maybe a third of the square-wave period: 15/3 = 5 µs in this case, so the resistor should be 5 µs/220 nF = 22 Ω. That limits the peak current to no more than 5 V/22 Ω = 230 mA, not a big improvement. Mostly, the microcontroller pin will be OK if you’re using small caps.

  • There’s No Undo Key in CNC

    The Axis user interface for EMC2 has a manual command entry mode, wherein you can type G-Code statements and EMC2 will do exactly what you say. That’s handy for positioning to exact coordinates, but I rarely use it for actual machining, as it’s just too easy to mis-type a command and plow a trench through the clamps.

    OK, on a Sherline mini-mill, you’d maybe just snap off a carbide end mill, but you get the general idea.

    I was making a simple front panel from some ancient nubbly coated aluminum sheet. The LCD and power switch rectangles went swimmingly.

    Then I tried to mill an oval for the test prod wires using G42.1 cutter diameter compensation. I did a trial run 1 mm above the surface, figured out how to make it do what I wanted, then punched the cutter through the sheet at the center of the oval and entered (what I thought were) the same commands by picking them from the history list.

    EMC2 now handles concave corners by automagically inserting fillets, so it must run one command behind your typing. I drove the cutter to the upper-right end of the oval (no motion) so it could engage cutter comp mode, entered the G2 right endcap arc to the lower edge (cuts straight to upper right), and then did something wrong with the next command.

    Epoxy-patched front panel hole
    Epoxy-patched front panel hole

    The cutter carved the endcap properly, then neatly pirouetted around the end and started chewing out an arc in the other direction. Even looking at the command trace I can’t figure out what I mistyped, but as it turns out it doesn’t matter… I was using the wrong dimensions for the hole anyway.

    So it’s now patched with epoxy backed up by a small square of aluminum. When it’s done curing, I’ll manually drill a pair of holes at the right coordinates, manually file out the oval, shoot a couple of coats of paint, and it’ll be OK.

    Nobody will ever know!

    If I recall correctly, Joe Martin of Sherline was the first person to observe that, unlike word processing programs, CNC machines lack an Undo key…

    Update: Like this…

    Patched panel - rear view
    Patched panel – rear view

    The shoot-a-couple-of-coats thing did not go well: a maple seed landed on the front panel. Ah, well, it’s close enough. Here’s a trial fit; the bellyband height extenders on the sides need a dab of epoxy and a shot of paint, too, but I may never get a round ‘tuit for that.

    Front panel trial fit
    Front panel trial fit

    It’s the long-awaited Equivalent Series Resistance meter…

  • Arduino Library for (Old?) Optrex DMC-family LCDs

    Having determined that the existing Arduino LiquidCrystal library routine wouldn’t work for the Optrex DMC-16117 character LCD in my parts heap, I decided to modify it to meet the data and timing requirements mentioned in the datasheet. This is sufficiently slow and old that it should work for contemporary displays built around the Hitachi HD44780 and its ilk, but I certainly haven’t tested it!

    The straight dope on building an Arduino library from scratch is there, but there’s no need to work from First Principles here.

    Start by copying the library files (this FLOSS stuff is wonderful that way), renaming them, and changing all the LiquidCrystal strings to LCD_Optrex:

    cd /opt/arduino/hardware/libraries/
    cp -a LiquidCrystal LCD_Optrex
    cd LCD_Optrex
    rm LiquidCrystal.o
    rename 's/LiquidCrystal/LCD_Optrex/' LiquidCrystal.*
    for f in LCD* k*; do sed -i 's/LiquidCrystal/LCD_Optrex/g' $f; done
    cd examples
    for f in * ; do sed -i 's/LiquidCrystal/LCD_Optrex/g' $f/$f.pde
    cd -
    

    You could do that by hand with an editor if you prefer.

    Depending on how you’ve installed the Arduino files, you may need a sudo to make that work. Better, perhaps, to tweak the permissions for (at least) the LCD_Optrex directory & files therein to grant yourself write access.

    I created a sendraw4() function to send a single 4-bit nibble during the startup sequence, so add that to the private section of LCD_Optrex.h:

    private:
    void send(uint8_t, uint8_t);
    void sendraw4(uint8_t);
    

    The new code is in LCD_Optrex is shamelessly adapted from the existing send() function, minus the mode selection and 8-bit stuff:

    void LCD_Optrex::sendraw4(uint8_t value) {
      digitalWrite(_rs_pin, LOW);
      digitalWrite(_rw_pin, LOW);
    
      for (int i = 0; i < 4; i++) {
        digitalWrite(_data_pins[i], (value >> (i + 4)) & 0x01);
      }
    
      digitalWrite(_enable_pin, HIGH);
      digitalWrite(_enable_pin, LOW);
    }
    

    If I were doing this from scratch, I’d use d7 through d4 rather than d3 through d0 to match the datasheet, but that’s a stylin’ thing.

    Replace the existing LCD panel setup code with an exact mapping of the datasheet’s procedure. For the 4-bit setup, it goes a little something like this:

    delayMicroseconds(16000);       // mandatory delay for Vcc stabilization
    sendraw4(0x30);                 // set 8-bit mode (yes, it's true!)
    delayMicroseconds(5000);        // mandatory delay
    sendraw4(0x30);
    delayMicroseconds(200);
    sendraw4(0x30);
    delayMicroseconds(40);          // command delay
    sendraw4(0x20);                 // finally set 4-bit mode
    delayMicroseconds(40);          // command delay
    
    command(0x28);            // 4-bit, 2-line, 5x7 char set
    command(0x08);            // display off
    command(0x01);            // clear display
    delayMicroseconds(16000);
    command(0x06);            // increment, no shift
    command(0x0c);            // display on, no cursor, no blink
    

    It seems you cannot use the delay() function in the constructor, as interrupts and suchlike aren’t active. The delayMicroseconds() function disables & enables interrupts; I don’t know if that is a Bad Thing or not.

    The 8-bit initialization code, which I haven’t tested, doesn’t need the sendraw4() function, but does need the same alterations. Apart from enabling 4-bit mode, of course.

    Various commands have different timing requirements, as shown on page 39 of the DMC16117 datasheet. Add a delayMicroseconds(16000); to the clear() and home() functions, then add delayMicroseconds(40); to the send() function, like this:

    void LCD_Optrex::clear()
    {
      command(0x01);  // clear display, set cursor position to zero
      delayMicroseconds(16000);
    }
    
    Optrex DMC16117 Instruction Timing
    Optrex DMC16117 Instruction Timing

    With all that in place, fire up the Arduino IDE and compile one of the example programs. That will build the LCD_Optrex.o file, too. If you have such a display, either wire it up as indicated or change the example code to match your connections.

    What should happen is that the LCD should initialize correctly under all conditions… how’s that for anticlimactic?

    Here’s an OpenOffice document with LCD_Optrex.h, LCD_Optrex.cpp, and examples.txt all in one lump: LCD_Optrex Library Files.odt. Save each section as a separate flat-ASCII text file with the appropriate name in the right spot and you’re in business. I’d present a ZIP file, but WordPress isn’t up to that.

    Memo to Self: A function to write a 16-character string to the stupid 16-character DMC16117 which has a single row that’s addressed as two 8-character lines would be nice. That requires keeping track of the current cursor position, which could be tricky. Maybe I should just scrap those suckers out?

  • Arduino LiquidCrystal Library vs Old HD44780 LCD Controller

    I recently attached an ancient Optrex DM16117 LCD to an Arduino and discovered that the standard LiquidCrystal library routine wouldn’t initialize it properly. After turning on the power, the display would be blank. Hitting the Reset button did the trick, but that’s obviously not the right outcome.

    It turns out that initializing one of these widgets is trivially easy after you realize that the data sheet is required reading. If you do everything exactly right, then it works; get one step wrong, then the display might work most of the time, sorta-kinda, but most likely it won’t work, period.

    The catch is that there’s no such thing as a generic datasheet: what you must do depends on which version of the HD44780 controller lives on the specific LCD board in your hands and what oscillator frequency it’s using. The LiquidCrystal library seems to be written for a much newer and much faster version of the HD44780 than the one on my board, but, even so, the code may not be following all the rules.

    Optrex DMC16117 Initialization Sequence
    Optrex DMC16117 Initialization Sequence

    To begin…

    Fetch the Optrex DMC16117 datasheet, which includes the HD44780 timings for that family of LCD modules. There’s also a datasheet for just the Optrex LCD module itself, which isn’t quite what you want. You could get a bare Hitachi HD44780 datasheet, too, but it won’t have the timings you need.

    Pages 32 and 33 of the DMC16117 datasheet present the 8-bit and 4-bit initialization sequences. Given that no sane engineer uses the 8-bit interface, here’s the details of the 4-bit lashup.

    Two key points:

    • The first four transfers are not standard command sequences
    • The delays between transfers are not negotiable

    The starting assumption is that the LCD has not gone through the usual power-up initialization, perhaps because the supply voltage hasn’t risen at the proper rate. You could drive the LCD power directly from a microcontroller pin for a nice clean edge, but most designs really don’t have any pins to spare for that sort of nonsense: code is always cheaper than hardware (if you ignore non-recurring costs, that is, as many beancounters do).

    The Arduino LiquidCrystal library routine initialization sequence (in /opt/arduino/hardware/libraries/LiquidCrystal/LiquidCrystal.cpp) looks like this:

    command(0x28);  // function set: 4 bits, 1 line, 5x8 dots
    command(0x0C);  // display control: turn display on, cursor off, no blinking
    command(0x06);  // entry mode set: increment automatically, display shift, right shift
    clear();
    

    The four-bit version of the command() function sends both nibbles of its parameter, high followed by low, which simply isn’t correct for the first few values the DMC16117 expects. Worse, the timing doesn’t follow the guidelines; there’s no delay at all between any of the outgoing values. Again, this is most likely due to the fact that LiquidCrystal was written for a newer version of the HD44780 chip.

    After a bit of fiddling around, I decided that the only solution was to create a new library routine based on LiquidCrystal with the proper delays and commands: LCD_Optrex. It might not work for newer LCDs, but at least it’ll play with what I have in my parts heap.

    Next, the gory details…

    Memo to Self: The protracted delay after the first Clear is absolutely vital!