Completed Station Clock

IMG_20160612_174359In an earlier post, I described an arduino-based clock that I made for my amateur radio station. I had to interrupt work on it for a business trip, but got back a few days ago. I’m now far enough past jet lag to operate heavy machinery, so I finished mounting the board on an aluminum faceplate and installed it in the station.

Continue reading “Completed Station Clock”

Reading a rotary encoder with ATmega328

There are a bewildering number of examples, libraries, and opinions about how to write routines to read values from a rotary encoder. I found one that that looked particularly elegant and easy to generalize, so adapted it to the Atmega328 that I’m using for my current project. I used a pretty popular rotary encoder, Adafruit #377, although I think the demo code would work with other quadrature encoders.

Most of the work in done in a relatively light interrupt service routine that receives information from both directional pins on the rotary encoder. I did not do any addition software or hardware debouncing and I didn’t notice any jitter or erratic behavior.

Continue reading “Reading a rotary encoder with ATmega328”

The Antananarivoduino

Blue LEDs make everything more spiffy.
Blue LEDs make everything more spiffy.

With wintertime (and remember, it is winter where I am) comes soldering – I can spend more than ten minutes in the garage without being drenched in sweat. I have a three week travel break before going on summer leave, so I’m trying to wrap up various projects. I have one project breadboarded and wired up to my arduino duemilanove, but I needed another arduino to work on another project in parallel, so I built one up on perf board: the Antananarivoduino.

The Antananrivoduino is about a simple as I could make it: an ATmega328, 16Mhz crystal oscillator, and 5V power. The one frill I added was a 28-pin ZIF socket that I’ve had kicking around for a couple years. The socket lets me seat a chip, program it, and eject it. It’s ideal for cranking out copies of a project or a burning a final chip that will go into an embedded project and won’t need any more programming.

Continue reading “The Antananarivoduino”

Internet backup power

About the time I am wrapping up in the office, the sun has risen and people are getting into work on the East Coast of the United States. I leave early enough to get home so I can make teleconferences that start at 9 Eastern. I’d have quite a phone bill if I dialed direct, but fortunately, I can make most of these calls over the internet. Although Madagascar is a developing country, we have fiber to the house. The upstream connection isn’t entirely stable, but it is up most of the time, and throughput is surprisingly high. However, I still run into problems when the power blinks off.

The ISP has adequate backup power to maintain the connection, at least for some time, so this is my problem in the house. The house too has a backup generator, but there’s a couple seconds to shift over from mains to generator and vice versa. In that time, the houses’s router goes down and takes a minute or so to reboot every time power switches over. What’s needed is a UPS, but the smallest computer UPS here runs around $150. Also, it seems like a UPS is massive overkill when the problem is just to keep a router happy for about a minute.

I have a good stash of small lead acid batteries for portable ham radio use, and it occurred to me that I could probably use a couple in backup power supply projects. At this point, I’ve come up with two designs built of materials squirreled away in my garage. Schematics are below the cut for anyone interested. Continue reading “Internet backup power”

JackYack Rev A

The Version A circuit laid out in Eagle CAD. Top of board view.
The Version A circuit laid out in Eagle CAD. Top of board view.

Back in October, I mentioned an open source keyer developed for the ATTINY 45 and requiring only a few components. The source code for the controller and an example schematic were uploaded to a repository. Subsequently, I decided to try my hand at producing a PC board. Rather than try some sort of printer-based method based on toner transfer, I wanted to try going a more professional route and having the PCB run off by a fab. Initially, I thought I’d have to go overseas and wait upwards of a month for my boards to come back, but I found a domestic fab that provides an amazing service for low volume prototype boards: OSH Park.

I had already laid the schematic out in Eagle CAD, which seems to be popular among hobbyists. Most of my components were available in off-the-shelf libraries, but I had to layout the piezo speaker as a custom part (although I started from another similar piezo speaker and just had to modify the dimensions). It took a while to get the hang of laying everything out on the PCB, laying down ground planes, routing the traces, and making the silk screen look nice, but after many hours with online tutorials, it all looked right. I ran some rules checks, and everything reasonable, as far as I could tell.

Next, I shopped around using the online check and quote tools available from a number of popular fab houses. To upload my design, in most cases, I had to send a zip file of the various Gerber layers — top copper, bottom copper, top silk, etc.  But, for OSH Park, all I had to do was upload the Eagle board file itself. This makes a lot of sense, as the Gerbers are generated from that file, so all the information is already there in the board file.

The OSH Park site interprets the board file on the fly and provides a rendering of approximately what the board will look like when final. There are a number of options regarding cost, turn around, etc., but I opted to get three copies of my design for about ten dollars by agreeing to have my boards made as part of a larger run to take place in about two weeks from the date of submission. The way OSH Park makes prototype boards affordable is by merging multiple designs into one larger board and then cutting that board apart.  Their cost is per square inch, and I had designed my board to be one by two inches — not bad considering that I used all through-hole components and did not go out of my way to pack them tight on the surface of the board. In fact, my design is a little generous in that I give a number of ground connection points, whereas only one is really necessary for the sake of wiring in external components.

The board as rendered immediately after upload at OSH Park.
The board as rendered immediately after upload at OSH Park.

From the time of submission until the envelope arrived, I was able to track progress of the order, so there was particular excitement on the day that I knew the package would be waiting in my mailbox. When I opened the padded shipping packet up, I found three little purple boards, just about identical to the rendering that was provided when I had uploaded the design.

The front of the board, with components added.
The front of the board, with components added.

The back side of the board, before I started soldering.
The back side of the board, before I started soldering.

The PC boards are excellent quality, with no alignment issues. The solder mask went where it was supposed to go, all the vias are functional, and the pads take solder well and have no tendency towards lifting. Components went onto the board without any fuss and when powered up, the board worked perfectly, the first time.  Having verified that the design works, I’ve shared the board on the OSH Park website.

Now that this seems to be working, one option would be to run off more copies of the boards and do something with them — embedded keyers, stand alone kits, etc., but now that I’ve tried out designing a through hole board, I’m curious how much more compact the design would be with surface mount parts (and how much more difficult it would be to assemble).

A tiny and open source CW keyer

att45While working on a new project, I had a choice of either plugging in the output of a free-standing CW keyer or embedding one into the project. I decided to go with the embedded keyer, but then had to either find or write one. K3NG has written a top-notch keyer based on the arduino platform. Its strengths are its modular design and extensive feature list; it can be compiled to run on a number of chips, with features only limited by the flash memory capacity of the targeted chip. However, it does have a certain minimal size, even when the number of features is stripped down to bare essentials. It would have been a reasonable choice if I could have used the same microcontroller for other functions, with a sizeable portion given over to the K3NG keyer, but in this case, I just want a dead-simple CW keyer.

I’ve used K1EL‘s K12 keyer in the past, as well as the N0XAS picokeyer, and this was more what I had in mind — a low power, small chip. After a quick search, I turned up the YACK (yet another CW keyer) project by Jan Lategahn, DK3LJ. He developed it for the ATtiny45, which has only 4k of flash and even less RAM and EEPROM storage. The project was not developed on the arduino platform, so the code has a much, much smaller footprint. Jan deposited the source code in a svn repository at Source Forge: And, this isn’t a matter of trading off features, the YACK supports a number of keying modes, has many configurable features, a beacon mode and even does code practice. Pretty feature-rich, actually.

On that site, it is possible to download not only the source, but the compiled intel hex files for flash and eeprom. Naturally, I went for instant gratification, downloaded these, and flashed them onto the ATtiny using my arduino duemilanove as an in system programmer as previously (but this time, not having to mess with the fuse settings).

I stuck the programmed chip on a protoboard and tried it out. At first I wasn’t sure if it was working at all because it make no sound when powered up, but this was the way it was designed. Next, I tried closing the dit and dah paddles, and heard the expected tone on the piezo buzzer. Holding down either paddle resulted in tones of the correct duration, and holding both resulted in iambic mode B keying. So far, so good.

However, I could not get the keyer to work in command mode. Holding the command key just resulted in rapid clicking on the piezo, perhaps meaning that it was going into and coming out of command mode immediately since it sends an “e” when it exits command mode. Holding the button and closing one or the other paddles resulted in correct behavior: increasing or decreasing the sending speed.

I also noticed that a quick (less than a dit or dah length) tap on the paddles resulted in a shortened dit or dah being sent. This is not the expected behavior for keyers like this. Even if the paddle is released early, the generated tone should be of the correct length, one or three elements long.

jackyackprotoBoth these issues made the keyer unusable, but it seemed like at least the duration issue had been addressed in an earlier changelog entry, so I thought that perhaps the compiled file might not reflect the most recent and presumably most polished version of the project.

I recompiled the project from source (version 0.7) and noted that the resulting hex file was a bit different in size that the one I had previously used. I loaded both the flash and eep files onto the ATtiny and stuck it back in my prototyped keyer circuit. This time, it worked exactly as described in its documentation. Paddle clicks yielded dits and dahs of the right duration and the command button was fully functional. I ran through all the available commands, and each performed as advertised. I ran the keyer output to my FT817, which I had set to make a tone but not transmit when keyed. I had no problems using the keyer to send at various speeds. All good.

I made some minor tweaks to the code and revised the version to 0.75.  This shouldn’t be taken as any sort of official version number, but I needed some way of setting this revision apart from DK3LJ’s original code. I didn’t fix any bugs or make any real improvements, I just optimized the configuration for my purposes. Mostly, this is a matter of taste, and of being used to certain conventions from other keyers. I left most of the user interface alone, though, since I thought Jan had made some very reasonable choices in how he set it up.

Here is a list of what I changed:

  • Power up message: Now, when powered on, the keyer sends a “73” to let you know that it is alive. This is tone-only, no keying. This provides a quick check that the battery is okay and that everything is hooked up right, which could be helpful to anyone building this circuit, or someone who is on their way out the door for field operation and wants to make sure their keyer is healthy.
  • Positive Transmit keying default: In most cases, people will want to positively key their rigs, but the default formerly was that the transmit line would go low to key and remain pulled up to VCC otherwise. I flipped this around, which let me use a cheap NPN circuit with open collector to key.
  • Side tone: For the project that I’m using, a 700Hz side tone is optimal — the keyer is followed by a filter with a 700Hz center frequency, so I changed it in the default settings. I actually prefer 800Hz, but the tone can be changed on the fly, so this isn’t really an issue.
  • Keying mode: This is entirely personal preference – I made the default keying mode iambic A rather than B, because I think it is easier for someone accustomed to Iambic B to send A rather that the reverse. People who are used to iambic A are thrown by the “extra” character that B generates.
  • Speed: I bumped the default speed to 15 wpm. Maybe 12 wpm is more inclusive, but 15 wpm works better. Also, anyone can increase or decrease the speed by holding the command button and pressing one paddle or the other. It is not necessary to send a character correctly to change the speed, so I think I haven’t really excluded slower operators.
  • Exiting command mode sound: Previously, the keyer sent an “e” to indicate that someone intentionally exited command mode by tapping the command button a second time or that the command mode had timed out due to inactivity. I found the “e” a bit short and thought it could be missed. Also, at times I forgot I was in command mode, and whatever else I was doing, it just sounded like an extra dit got in there, without making much sense. I changed the exit sound to “sk”, similar to the picokeyer, because it has a more characteristic sound and would not be expected in the audio stream except at the end of a QSO, so it is more noticeable.
  • Acknowledgment sound : After a valid command is given, the keyer used to acknowledge it with an “OK”. I changed this to “R” because it is shorter and “R” connotes “Roger, received.” This borrows a bit from the K1EL keyers. I only steal from the best.

After testing out my minor revision, I uploaded the project to a repository at google code.  The project files include a schematic in Eagle format as well as a picture of the schematic as a *.png file.  For those who would rather not compile from source, I’ve uploaded the compiled intel hex files on this server: main.hex and main.eep.  I loaded the files into a stock ATtiny45, right out of the box. No need to mess with any of the fuses — the chip is factory configured to run on its internal 8Mhz clock, scaled to 1Mhz.

The last time I checked on mouser, these chips were a bit over a dollar each and the even more spacious ATtiny85s were a bit less — and that’s unit pricing — buy a bunch and the price falls off considerably. The rest of the components in the keyer are dirt cheap and easily substituted. Making a first-rate keyer these days is not an expensive proposition.

[Update 17 May 2016]

Unfortunately, the Google Code repository no longer exists, but before it went down, I migrated everything over to github, so project files are now over there:

Also see my later blog post about design of a PC-board for this project.

[Update 5 June 2016]

KC9ON has put together some nice kits based on the same code base, but with added features, a code practice oscillator and a small keyer board.

The Crossed Bananas Display

orthagonalArguably, the crossed bananas display (CBD) was not the next most needed accessory in my shack. I mean, who needs a crossed bananas display, anyhow? Nonetheless, I built one, and it seems to be working.

The CBD is a tuning aid for frequency-shift keyed modes. At one time, these displays were particularly in vogue among RTTY operators. The original version made use of an XY-mode analogue oscilloscope. The demodulated sound from the radio was filtered at the mark and space frequencies and each signal was then fed to either the X or Y input of the scope. Ideally, the tones would be sine waves, and when one tone would be sent, the other would be off. Each tone corresponds to a “banana” or oval on the XY display. The oval is horizontal for one tone and vertical for the other. When the radio is perfectly tuned, the two tones are located right on the two filter center frequencies. When a RTTY signal is sent, or even while it is idling, there is rapid alternation between the two tones, so the vertical and horizontal ovals appear so quickly that they appear to overlap, hence crossed bananas. When the radio is a bit off frequency, the phase relationship changes and the traced ovals rotate and distort. When only noise is present, the tracing is a random jumble. It’s easier to see this in action than to describe it, so I made a video of how it looks on an oscilloscope and how it looks on my newly minted digital CBD.

I got thinking about RTTY and some other similar modes after working on the PK232 mentioned in earlier posts. The PK232 has a little bar graph that indicates when a signal is centered such that the mark and space tones fall where they should, be it for RTTY, AMTOR, PACTOR I, etc. A lot of the circuitry in the PK232 is dedicated to producing and sensing these tones and telling them apart from noise.  The bar graph tuning indicator is usable, but let’s face it, nowhere as cool looking as the old style crossed bananas displays on an oscilloscope.

My operating position is already cramped enough, though, without tossing an oscilloscope on the pile, plus I need my scope for bench work and don’t have an extra one that can just relax in a corner until it is needed for RTTY. No, what I needed was a small, modern version of the crossed bananas display.  This sounded like a good arduino project. The limiting factors would be timing of the audio samples and speed of updating the display.

My first thought for the display was an LED matrix, preferably one with minimal translational overhead. If the microcontroller could drive it directly or through a shift registers, that seemed like it would be lightning fast, and indeed it probably would be. Unfortunately, to get reasonable resolution, I’d probably need a pretty big array. 8×8 is chunky, but we’re already talking 64 LEDs.

schema_and_boardSo, with some concern about the data transfer and display/buffer update speeds, I took a look at some LCD displays. I found the ST7735R display at Adafruit. It’s 1.8 inches diagonally, with square pixels arranged in a 128 x 160 array. The display comes on a breakout board that makes it easy to work with, taking care of voltage conversion and making it an SPI device. The display includes a video buffer and Adafruit provides a library that abstracts most of the lower level functions. Adafruit also provides a general graphics library that provided methods for most of the things I wanted to do like drawing a pixel, erasing a pixel, writing text, blanking the screen, etc.

The sound coming out of the PK232 turned out to be biased around 7.5V, with swings of +/- 1.25 and 1.5 volts depending on whether it was being driven by the ACC output of my Yaesu FT-817 or Kenwood TS-450, which must output different levels.  Each tone was capacitively coupled to an op-amp channel set up as an inverted amplifier with variable gain. A ganged potentiometer sets the gain between unity and 2x. I used an MC33204PG quad op amp. Of the op-amps I had on hand, it was the best single voltage nearly rail-to-rail chip. I used the third section of the op amp configured as a voltage follower to set the bias voltage at 2.5V for the mark and space op amp sections, so only one out of the four op amp sections was left to twiddle its thumbs. With that bias and  input range, the output of the op amp would stay in a reasonable range, nearly 0-5V, consistent with the requirements for analog input on the ATmega328.

In principle, the XY display plots a point defined by an X-input and Y-input at a single instant, so one concern I had was that there had to be minimal separation between the mark and space voltage reads. I minimized this interval by setting the ADC prescaler to 16, trading off some accuracy for faster acquisition time. Without this tweak, the display was distorted due to delay artifact in the phase relationship of the two inputs.

naked_board back_of_board
Front and back view of the innards of the crossed-banana display

After displaying the self-congratulatory splash screen, the main activity is to read an XY pair, scale it, and plot it.  Given the speed of this process, more than one pixel needs to be displayed at a time to create a reasonably bright display. The solution is to use a circular buffer and to draw one pixel, erase the next pixel in the queue, and crank the index forward by one. This only gets complicated if the size of the queue varies arbitrarily, which is exactly what happens if you twist the brightness potentiometer. The brightness pot is polled every now and then, and when its value changes enough, the size of the queue is modified up or down, resulting in more or less pixels displayed at any one time, and giving the impression of brighter or darker display. When this happens, the size of the queue changes, so there is some housekeeping to do to make sure that all the pixels are taken care of.

The design has one more control, but it’s inside the box in the finished project. The LCD display has a huge range of colors, but having a rainbow XY display was not appealing. I incorporated a dip-switch on the control board, with three bits dedicated to color selection and one to choosing black versus white background. I didn’t think color would be adjusted frequently, so I though it would be okay to leave this control off the front panel. I set my CBD to green dots on a black background, as close as I could get to the appearance of a classic oscilloscope.

chassic_back chassis_front
The aluminum box, before painting, decals, etc.

My metal working facilities are limited, so this project went into the same sort of enclosure as the NEScafe filter, a cast-aluminum bud box. I bought these in bulk to save shipping at one point, so I suppose we’ll be seeing more of them in future projects as well.  At first, it seemed that this box was way too large for this project, but when I started thinking about all the items in the project (LCD panel, control board, two pots, two RCA jacks, a switch, power pole connectors), I became concerned that it all might not fit.

Since I don’t have the patience to send away to an offshore fab facility for a one-off PC board (and since it would likely take more more than one to get it right), I laid the project out on vector board, with some forethought to how it would mount in the bud box and where the screen, controls, and various connectors would emerge. To fit everything in, I had to pack components tightly and cut out two notches in the board to clear wiring runs.  Once again, small nylon spacers from Ace Hardware were my friend, providing stand-offs for the screen and for the control board. A layer of clear plastic provides some protection for the glass LCD display. The plastic is pinned at four corners by the control board stand-off screws, but also held in place with some double-face tape.

top_inside rear_inside
Contents stuffed into the box.

Since every project justifies one hardware purchase, my purchase for this project was a manual screw countersink from Carr-McMaster. It allowed me to use screws on the front panel, but have them flush with the surface of the panel.

The square window for the LCD was roughly cut out with a dremel rotary tool and then carefully finished with a flat file. The rest of the holes were made with a stepped drill bit, except the power pole hole on the back which I made by pin-holing the metal with a bunch of drill holes, widening with a nibbler, and finishing off with a small file.

I posted the code for this project, the schematic and picture of the vector board layout at

[Update 17 May 2016]

Before Google Code evaporated, I moved the repository over to github, so all schematics, code, etc. can now be found at:

Burning ATmega328 bootloaders

I followed the instructions to set up a breadboard as a platform to burn bootloaders onto some factory-fresh ATmega328 chips, according to instructions. Specifically, I set up the breadboard with a 16Mhz crystal rather than using the chip’s onboard clock.

I uploaded the ArduinoISP sketch my  Duemilanove, made all the right cross connections to the breadboard,  changed the “programmer” setting from AVR-ISP mkII to “Arduino as ISP” and made sure that the target was still set to Duemilanove at 16Mhz. Then, I hit “burn bootloader”. There was a pause of a few seconds, followed by the following error message in the IDE:

Error while burning bootloader. avrdude: stk500_getsynch():not in sync: resp=0x15

I found some similar issues and suggestions on the forums, and it seems the problem is the autoreset on the Duemilanove. The solution: before trying to burn the bootloader, connect the Arduino’s reset to 5V through a 120 ohm resistor. Now, when you select “burn bootloader” lights immediately start flashing on the host arduino and after a few moments, the IDE displays a confirmatory message that the operation was successful. Now the target ATmega328 can be popped off the breadboard and another one can be burnt. After burning bootloaders onto as many chips as desired, the whole assembly can be taken down and the 120 ohm resistor removed from the host arduino board.

Stuffing code into an ATTINY 45

For the QLF project, I had to get my code onto an ATTINY 45, which wasn’t so difficult, but also to free up the RESET pin to act as a digital output, which a bit more doing.

My experience with microcontrollers, aside from some PIC activity a decade ago, has been confined to the Arduino, a prototyping platform that hides some of the complexity of creating projects built around some popular Atmel microcontrollers. There are many tools for developing code, transferring code to these chips, and setting the fuse options on these chips, but all I had on hand was my trusty Arduino, so I used it as a middleman to program the ATTINY 45.  There are plenty of other options available to get the compiled code (a hex file) into the flash memory of the chip, for example, the USBtiny or the tiny AVR, or the over-the-top Atmel STK600 programmers.

duemilanove_protoWhile the ATTINY45’s were on order, I worked out the code using the Arduino itself – this is, after all, its job in life: to serve as a rapid prototyping platform. The circuit was laid out on a solderless prototyping board and jumped over to the Arduino for testing. I realized that I’d need to change some of the pins later, but otherwise the code within the Arduino IDE is the same, whether developing for the ATmega328 on my Arduino Duemilanove or for the ATTINY.  There may be differences in the way the code compiles for the different chips, but all that is abstracted away.

With all of the code working when tethered for life support to the Arduino, I needed to migrate it over to ATTINY 45. I found instructions on how to use the Arduino as an in-system programmer (ISP) and how to connect it to the ATTINY on the High-Low Tech website. Their procedure worked for, using my Duemilanove board and version 1.0.1 of the Arduino environment. However, I have a couple comments on their recommended procedure — I didn’t see a place on their website to provide feedback, but it is possible that they’ll have corrected these items in the future:

1.  The general idea of connecting the “ISP header” from the Arduino over to a target can be used to program a number of chips, including the ATTINY. The idea is to connect power, ground, MISO, MOSI, SCK, and RESET from one chip to the other. MOSI goes to MOSI, MISO goes to MISO (rather than crossed wiring). The picture shown on the instruction page is correct, but the pin numbering for the ATTINY described below the picture isn’t. It should read:

  • ATtiny Pin 7 to Arduino digital output 13, physical pin 19 (or SCK of another programmer.
  • ATtiny Pin 6 to Arduino digital output 12, physical pin 18 (or MISO of another programmer)
  • ATtiny Pin 5 to Arduino digital output 11, physical pin 17 (or MOSI of another programmer)
  • ATtiny Reset Pin (1) to Arduino digital output 16, physical pin 16 (or RESET of another programmer)

2.  That tutorial recommends installing ATTINY-specific definition files into the Arduino IDE, and points towards a file found on github,  This file provides a mapping of the pins on the ATTINYx5. A number of basic arduino functions like the ability read and write to pins will work on the ATTINY, but not the tone() function. Instead of using installing the file from github, I found another core on Google Code, arduino-tiny.  This provides not just a pin definition, but a number of libraries like serial, wire, and the tone function that I needed.

3. The 10uF capacitor shown in the picture will not be needed for all versions of arduino; having it probably doesn’t hurt anything, though.

So, to reiterate the main points of that tutorial, the major steps are:

  1. Write code for the ATTINY. Make sure it compiles. Save it.
  2. Close the arduino IDE, add the core definition files to the hardware subdirectory, relaunch the IDE.
  3. Upload the “Arduino as ISP” sketch to the Arduino. This comes with the Arduino distribution.
  4. Connect the Arduino to the ATTINY — six wires.
  5. Select the ATTINY from the “Boards” menu.
  6. Select “Arduino as ISP” from the “Programmer” menu. No change to the serial port settings, please.
  7. By default, without an external clock, the ATTINY will run at 1 Mhz. To get it run faster, make sure that 8Mhz is selected in the board menu, and choose the “burn bootloader” option. It doesn’t really burn a bootloader, but it does set the fuses appropriately in the ATTINY. This operation also wipes out the flash memory in the ATTINY.
  8. Load ATTINY code that you want transferred.
  9. Hit “upload”. The code should transit the Arduino and end up in the ATTINY.

If you want to modify the code, no problem – just edit and upload again.

Physical pin 1 of the ATTINY is typically used for RESET, but to use it for I/O, bit 7 of the high fuse (RSTDISBL) has to be set. Once this happens, the chip cannot be reprogrammed by the ISP method described above — it essentially becomes read-only, unless the chip is restored using a high-voltage programmer – an item that I don’t have on hand (although one can be made with some common parts thanks to various plans online plans).  Once I was sure that the program behaved as desired, I looked for a way to manually set the fuses (short of using avrdude from the command line — I’m not quite there).

I came across a program called “hexloader” that can both upload hex files and set fuses without requiring anything beyond an Arduino in terms of equipment. Unless you modify the hexloader sketch, by default it uses other pins to connect to the ATTINY. Arduino digital pins 4, 5, 6, and 7 connect to ATTINY physical pins 7, 1, 6, and 5, respectively. Refer to the picture on the website.

To change the fuse settings on the ATTINY, open the serial monitor and make sure that the line termination character is set to “newline”. Also, make sure that the serial speed matches up with the hexloader program.  A menu will display in the serial monitor; choose “F” to access fuses. The low, high and extended fuse settings were 0x62, 0xDF, and 0xFF.

Adding a high bit in the 7th position to the high fuse, the desired high fuse setting is 0x5F. You could also consult an online fuse setting calculator to see what options are available.

Follow the menu settings to commit this change to the fuses. Once this is done, the hex loader program reports that it can no longer enter “program mode”  — which makes sense, since the chip is no longer programmable.