Mar 262017

Yesterday’s post was rather long, but was intended for mostly technical audiences outside of amateur radio.  This post serves as a brain dump of volatile memory before I go to sleep for the night.  (Human conscious memory is more like D-RAM than one might realise.)

Radio interface

So, many in our group use packet radio TNCs already, with a good number using the venerable Kantronics KPC3.  These have a DB9 port that connects to the radio and a second DB25 RS-323 port that connects to the computer.

My proposal: we make an audio interface that either plugs into that DB9 port and re-uses the interface cables we already have, or directly into the radio’s data port.

This should connect to an audio interface on the computer.

For EMI’s sake, I’d recommend a USB sound dongle like this, or these, or this as that audio interface.  I looked on Jaycar and did see this one, which would also work (and burn a hole in your wallet!).

If you walk in and the asking price is more than $30, I’d seriously consider these other options.  Of those options, U-Mart are here in Brisbane; go to their site, order a dongle then tell the site you’ll come and pick it up.  They’ll send you an email with an order number when it’s ready, you just need to roll up to the store, punch that number into a terminal in the shop, then they’ll call your name out for you to collect and pay for it.

Scorptec are in Melbourne, so you’ll have to have items shipped, but are also worth talking to.  (They helped me source some bits for my server cluster when U-Mart wouldn’t.)

USB works over two copper pairs; one delivers +5V and 0V, the other is a differential pair for data.  In short, the USB link should be pretty immune from EMI issues.

At worst, you should be able to deal with it with judicious application of ferrite beads to knock down the common mode current and using a combination of low-ESR electrolytic and ceramic capacitors across the power rails.

If you then keep the analogue cables as short as absolutely possible, you should have little opportunity for RF to get in.

I don’t recommend the TigerTronics Signalink interfaces, they use cheap and nasty isolation transformers that lead to serious performance issues.

Receive audio

For the receive audio, we feed the audio from the radio and we feed that via potentiometer to a 3.5mm TRS (“phono”) plug tip, with sleeve going to common.  This plugs into the Line-In or Microphone input on the sound device.

Push to Talk and Transmit audio

I’ve bundled these together for a good reason.  The conventional way for computers to drive PTT is via an RS-232 serial port.

We can do that, but we won’t unless we have to.

Unless you’re running an original SoundBLASTER card, your audio interface is likely stereo.  We can get PTT control via an envelope detector forming a minimal-latency VOX control.

Another 3.5mm TRS plug connects to the “headphone” or “line-out” jack on our sound device and breaks out the left and right channels.

The left and right channels from the sound device should be fed into the “throw” contacts on two single-pole double-throw toggle switches.

The select pin (mechanically operated by the toggle handle) on each switch thus is used to select the left or right channel.

One switch’s select pin feeds into a potentiometer, then to the radio’s input.  We will call that the “modulator” switch; it selects which channel “modulates” our audio.  We can again adjust the gain with the potentiometer.

The other switch first feeds through a small Schottky diode then across a small electrolytic capacitor (to 0V) then through a small resistor before finally into the base of a small NPN signal transistor (e.g. BC547).  The emitter goes to 0V, the collector is our PTT signal.

This is the envelope detector we all know and love from our old experiments with crystal sets.  In theory, we could hook a speaker to the collector up to a power source and listen to AM radio stations, but in this case, we’ll be sending a tone down this channel to turn the transistor, and thus or PTT, on.

The switch feeding this arrangement we’ll call the “PTT” switch.

By using this arrangement, we can use either audio channel for modulation or PTT control, or we can use one channel for both.  1200-baud AFSK, FreeDV, etc, should work fine with both on the one channel.

If we just want to pass through analogue audio, then we probably want modulation separate, so we can hold the PTT open during speech breaks without having an annoying tone superimposed on our signal.

It may be prudent to feed a second resistor into the base of that NPN, running off to the RTS pin on an RS-232 interface.  This will let us use software that relies on RS-232 PTT control, which can be added by way of a USB-RS232 dongle.

The cheap Prolific PL-2303 ones sold by a few places (including Jaycar) will work for this.  (If your software expects a 16550 UART interface on port 0x3f8 or similar, consider running it in a virtual machine.)

Ideally though, this should not be needed, and if added, can be left disconnected without harm.


There are a few “off-the-shelf” packages that should work fine with this arrangement.

AX.25 software

AGWPE on Windows provides a software TNC.  On Linux, there’s soundmodem (which I have used, and presently mirror) and Direwolf.

Shouldn’t need a separate PTT channel, it should be sufficient to make the pre-amble long enough to engage PTT and rely on the envelope detector recognising the packet.

Digital Voice

FreeDV provides an open-source digital voice platform system for Windows, Linux and MacOS X.

This tool also lets us send analogue voice.  Digital voice should be fine, the first frame might get lost but as a frame is 40ms, we just wait before we start talking, like we would for regular analogue radio.

For the analogue side of things, we would want tone-driven PTT.  Not sure if that’s supported, but hey, we’ve got the source code, and yours truly has worked with it, it shouldn’t be hard to add.

Slow-scan television

The two to watch here would be QSSTV (Linux) and EasyPal (Windows).  QSSTV is open-source, so if we need to make modifications, we can.

Not sure who maintains EasyPal these days, not Eric VK4AES as he’s no longer with us (RIP and thank-you).  Here, we might need an RS-232 PTT interface, which as discussed, is not a hard modification.


Most is covered by FLDigi.  Modes with a fairly consistent duty cycle will work fine with the VOX PTT, and once again, we have the source, we can make others work.

Custom software ideas

So we can use a few off-the-shelf packages to do basic comms.

  • We need auditability of our messaging system.  Analogue FM, we can just use a VOX-like function on the computer to record individual received messages, and to record outgoing traffic.  Text messages and files can be logged.
  • Ideally, we should have some digital signing of logs to make them tamper-resistant.  Then we can mathematically prove what was sent.
  • In a true  emergency, it may be necessary to encrypt what we transmit.  This is fine, we’re allowed to do this in such cases, and we can always turn over our audited logs for authorities anyway.
  • Files will be sent as blocks which are forward-error corrected (or forward-erasure coded).  We can use a block cipher such as AES-256 to encrypt these blocks before FEC.  OpenPGP would work well here rather doing it from scratch; just send the OpenPGP output using FEC blocks.  It should be possible to pick out symmetric key used at the receiving end for auditing, this would be done if asked for by Government.  DIY not necessary, the building blocks are there.
  • Digital voice is a stream, we can use block ciphers but this introduces latency and there’s always the issue of bit errors.  Stream ciphers on the other hand, work by generating a key stream, then XOR-ing that with the data.  So long as we can keep sync in the face of bit errors, use of a stream cipher should not impair noise immunity.
  • Signal fade is a worse problem, I suggest a cleartext (3-bit, 4-bit?) gray-code sync field for synchronisation.  Receiver can time the length of a fade, estimate the number of lost frames, then use the field to re-sync.
  • There’s more than a dozen stream ciphers to choose from.  Some promising ones are ACHTERBAHN-128, Grain 128a, HC-256, Phelix, Py, the Salsa20 family, SNOW 2/3G, SOBER-128, Scream, Turing, MUGI, Panama, ISAAC and Pike.
  • Most (all?) stream ciphers are symmetric.  We would have to negotiate/distribute a key somehow, either use Diffie-Hellman or send a generated key as an encrypted file transfer (see above).  The key and both encrypted + decrypted streams could be made available to Government if needed.
  • The software should be capable of:
    • Real-time digital voice (encrypted and clear; the latter being compatible with FreeDV)
    • File transfer (again, clear and encrypted using OpenPGP, and using good FEC, files will be cryptographically signed by sender)
    • Voice mail and SSTV, implemented using file transfer.
    • Radioteletype modes (perhaps PSK31, Olivia, etc), with logs made.
    • Analogue voice pass-through, with recordings made.
    • All messages logged and time-stamped, received messages/files hashed, hashes cryptographically signed (OpenPGP signature)
    • Operation over packet networks (AX.25, TCP/IP)
    • Standard message forms with some basic input validation.
    • Ad-hoc routing between interfaces (e.g. SSB to AX.25, AX.25 to TCP/IP, etc) should be possible.
  • The above stack should ideally work on low-cost single-board computers that are readily available and are low-power.  Linux support will be highest priority, Windows/MacOS X/BSD is a nice-to-have.
  • GNU Radio has building blocks that should let us do most of the above.
Nov 202016

The Yaesu FT-897D has the de-facto standard 6-pin Mini-DIN data jack on the back to which you can plug a digital modem.  Amongst the pins it provides is a squelch status pin, and in the past I’ve tried using that to drive (via transistors) the carrier detect pin on various computer interfaces to enable the modem to detect when a signal is incoming.

The FT-897D is fussy however.  Any load at all pulling this pin down, and you get no audio.  Any load.  One really must be careful about that.

Last week when I tried the UDRC-II, I hit the same problem.  I was able to prove it was the UDRC-II by construction of a crude adapter cable that hooked up to the DB15-HD connector, converting that to Mini-DIN6: by avoiding the squelch status pin, I avoided the problem.

One possible solution was to cut the supplied Mini-DIN6 cable open, locate the offending wire and cut it.  Not a solution I relish doing.  The other was to try and fix the UDRC-II.

Discussing this on the list, it was suggested by Bryan Hoyer that I use a 4.7k pull-up resistor on the offending pin to 3.3V.  He provided a diagram that indicated where to find the needed signals to tap into.

With that information, I performed the following modification.  A 1206 4.7k resistor is tacked onto the squelch status pin, and a small wire run from there to the 3.3V pin on a spare header.

UDRC-II modification for Yaesu FT-897D

UDRC-II modification for Yaesu FT-897D

I’m at two minds whether this should be a diode instead, just in case a radio asserts +12V on this line, I don’t want +12V frying the SoC in the Raspberry Pi.  On the other hand, this is working, it isn’t “broke”.

Doing the above fixed the squelch drive issue and now I’m able to transmit and receive using the UDRC-II.  Many thanks to Bryan Hoyer for pointing this modification out.

Nov 072015

Well, I’ve been thinking a lot lately about single board computers. There’s a big market out there. Since the Raspberry Pi, there’s been a real explosion available to the small-end of town, the individual. Prior to this, development boards were mostly in the 4-figures sort of price range.

So we’re now rather spoiled for choice. I have a Raspberry Pi. There’s also the BeagleBone Black, Banana Pi, and several others. One gripe I have with the Raspberry Pi is the complete absence of any kind of analogue input. There’s an analogue line out, you can interface some USB audio devices (although I hear two is problematic), or you can get an I2S module.

There’s a GPU in there that’s capable of some DSP work and a CLKOUT pin that can generate a wide range of frequencies. That sounds like the beginnings of a decent SDR, however one glitch, while I can use the CLKOUT pin to drive a mixer and the GPIOs to do band selection, there’s nothing that will take that analogue signal and sample it.

If I want something wider than audio frequencies (and even a 192kHz audio CODEC is not guaranteed above ~20kHz) I have to interface to SPI, and the pickings are somewhat slim. Then I read this article on a DIY single board computer.

That got me thinking about whether I could do my own. At work we use the Technologic Systems TS-7670 single-board computers, and as nice as those machines are, they’re a little slow and RAM-limited. Something that could work as a credible replacement there too would be nice, key needs there being RS-485, Ethernet and a 85 degree temperature rating.

Form factor is a consideration here, and I figured something modular, using either header pins or edge connectors would work. That would make the module easily embeddable in hobby projects.

Since all the really nice SoCs are BGA packages, I figured I’d first need to know how easy I could work with them. We’ve got a stack of old motherboards sitting in a cupboard that I figured I could raid for BGAs to play with, just to see first-hand how fine the pins were. A crazy thought came to me: maybe for prototyping, I could do it dead-bug style?

Key thing here being able to solder directly to a ball securely, then route the wire to its destination. I may need to glue it to a bit of grounded foil to keep the capacitance in check. So, the first step I figured, would be to try removing some components from the boards I had laying around to see this first-hand.

In amongst the boards I came across was one old 386 motherboard that I initially mistook for a 286 minus the CPU. The empty (PLCC) socket is for an 80387 math co-processor. The board was in the cupboard for a good reason, corrosion from the CMOS battery had pretty much destroyed key traces on one corner of the board.

Corrosion on a motherboard caused by a CMOS battery

Corrosion on a motherboard caused by a CMOS battery

I decided to take to it with the heat gun first. The above picture was taken post-heatgun, but you can see just how bad the corrosion was. The ISA slots were okay, and so where a stack of other useful IC sockets, ICs, passive components, etc.

With the heat gun at full blast, I’d just wave it over an area of interest until the board started to de-laminate, then with needle-nose pliers, pull the socket or component from the board. Sometimes the component simply dropped out.

At one point I heard a loud “plop”. Looking under the board, one of the larger surface-mounted chips had fallen off. That gave me an idea, could the 386 chip be de-soldered? I aimed the heat-gun directly at the area underneath. A few seconds later and it too hit the deck.

All in all, it was a successful haul.

Parts off the 386 motherboard

Parts off the 386 motherboard

I also took apart an 8-bit ISA joystick card. It had some nice looking logic chips that I figured could be re-purposed. The real star though was the CPU itself:

Intel NG80306SX-20

Intel NG80306SX-20

The question comes up, what does one do with a crusty old 386 that’s nearly as old as I am? A quick search turned up this scanned copy of the Intel 80386SX datasheet. The chip has a 16-bit bus with 23 bits worth of address lines (bit 0 is assumed to be zero). It requires a clock that is double the chip’s operating frequency (there’s an internal divide-by-two). This particular chip runs internally at 20MHz. Nothing jumped out as being scary. Could I use this as a practice run for making an ARM computer module?

A dig around dug up some more parts:

More parts

More parts

In this pile we have…

I also have some SIMMs laying around, but the SDRAM modules look easier to handle since the controllers on board synchronise with what would otherwise be the front-side bus.  The datasheet does not give a minimum clock (although clearly this is not DC; DRAM does need to be refreshed) and mentions a clock frequency of 33MHz when set to run at a CAS latency of 1.  It just so happens that I have a 33MHz oscillator.  There’s a couple of nits in this plan though:

  • the SDRAM modules a 3.3V, the CPU is 5V: no problem, there are level conversion chips out there.
  • the SDRAM modules are 64-bits wide.  We’ll have to buffer the output to eight 8-bit registers.  Writes do a read-modify-write cycle, and we use a 2-in-4 decoder to select the CE pin on two of the registers from address bits 1 and 2 from the CPU.
  • Each SDRAM module holds 32MB.  We have a 23-bit address bus, which with 16-bit words gives us a total address space of 16MB.  Solution: the old 8-bit computers of yesteryear used bank-switching to address more RAM/ROM than they had address lines for, we can interface an 8-bit register at I/O address 0x0000 (easily decoded with a stack of Schottky diodes and a NOT gate) which can hold the remaining address bits mapping the memory to the lower 8MB of physical memory.  We then hijack the 386’s MMU to map the 8MB chunks and use the page faults to switch memory banks.  (If we put the SRAM and ROM up in the top 1MB, this gives us ~7MB of memory-mapped I/O to play with.)

So, not show stoppers.  There’s an example circuit showing interfacing an ATMega8515 to a single SDRAM chip for driving a VGA interface, and some example code, with comments in German. Unfortunately you’d learn more German in an episode of Hogan’s Heroes than what I know, but I can sort-of figure out the sequence used to read and write from/to the SDRAM chip. Nothing looks scary there either.  This SDRAM tutorial seems to be a goldmine.

Thus, it looks like I’ve got enough bits to have a crack at it.  I can run the 386 from that 33MHz brick; which will give me a chip running at 16.5MHz.  Somewhere I’ve got the 40MHz brick laying around from the motherboard (I liberated that some time ago), but that can wait.

A first step would be to try interfacing the 386 chip to an AVR, and feed it instructions one step at a time, check that it’s still alive.  Then, the next steps should become clear.

Sep 272015

Well, lately I’ve been doing a bit of work hacking the firmware on the Rowetel SM1000 digital microphone.  For those who don’t know it, this is a hardware (microcontroller) implementation of the FreeDV digital voice mode: it’s a modem that plugs into the microphone/headphone ports of any SSB-capable transceiver and converts FreeDV modem tones to analogue voice.

I plan to set this unit of mine up on the bicycle, but there’s a few nits that I had.

  • There’s no time-out timer
  • The unit is half-duplex

If there’s no timeout timer, I really need to hear the tones coming from the radio to tell me it has timed out.  Others might find a VOX feature useful, and there’s active experimentation in the FreeDV 700B mode (the SM1000 currently only supports FreeDV 1600) which has been very promising to date.

Long story short, the unit needed a more capable UI, and importantly, it also needed to be able to remember settings across power cycles.  There’s no EEPROM chip on these things, and while the STM32F405VG has a pin for providing backup-battery power, there’s no battery or supercapacitor, so the SM1000 forgets everything on shut down.

ST do have an application note on their website on precisely this topic.  AN3969 (and its software sources) discuss a method for using a portion of the STM32’s flash for this task.  However, I found their “license” confusing.  So I decided to have a crack myself.  How hard can it be, right?

There’s 5 things that a virtual EEPROM driver needs to bear in mind:

  • The flash is organised into sectors.
  • These sectors when erased contain nothing but ones.
  • We store data by programming zeros.
  • The only way to change a zero back to a one is to do an erase of the entire sector.
  • The sector may be erased a limited number of times.

So on this note, a virtual EEPROM should aim to do the following:

  • It should keep tabs on what parts of the sector are in use.  For simplicity, we’ll divide this into fixed-size blocks.
  • When a block of data is to be changed, if the change can’t be done by changing ones to zeros, a copy of the entire block should be written to a new location, and a flag set (by writing zeros) on the old block to mark it as obsolete.
  • When a sector is full of obsolete blocks, we may erase it.
  • We try to put off doing the erase until such time as the space is needed.

Step 1: making room

The first step is to make room for the flash variables.  They will be directly accessible in the same manner as variables in RAM, however from the application point of view, they will be constant.  In many microcontroller projects, there’ll be several regions of memory, defined by memory address.  This comes from the datasheet of your MCU.

An example, taken from the SM1000 firmware, prior to my hacking (stm32_flash.ld at r2389):

/* Specify the memory areas */
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
  RAM (rwx)       : ORIGIN = 0x20000000, LENGTH = 128K
  CCM (rwx)       : ORIGIN = 0x10000000, LENGTH = 64K

The MCU here is the STM32F405VG, which has 1MB of flash starting at address 0x08000000. This 1MB is divided into (in order):

  • Sectors 0…3: 16kB starting at 0x08000000
  • Sector 4: 64kB starting at 0x0800c000
  • Sector 5 onwards: 128kB starting at 0x08010000

We need at least two sectors, as when one fills up, we will swap over to the other. Now it would have been nice if the arrangement were reversed, with the smaller sectors at the end of the device.

The Cortex M4 CPU is basically hard-wired to boot from address 0, the BOOT pins on the STM32F4 decide how that gets mapped. The very first few instructions are the interrupt vector table, and it MUST be the thing the CPU sees first. Unless told to boot from external memory, or system memory, then address 0 is aliased to 0x08000000. i.e. flash sector 0, thus if you are booting from internal flash, you have no choice, the vector table MUST reside in sector 0.

Normally code and interrupt vector table live together as one happy family. We could use a couple of 128k sectors, but 256k is rather a lot for just an EEPROM storing maybe 1kB of data tops. Two 16kB sectors is just dandy, in fact, we’ll throw in the third one for free since we’ve got plenty to go around.

However, the first one will have to be reserved for the interrupt vector table that will have the space to itself.

So here’s what my new memory regions look like (stm32_flash.ld at 2390):

/* Specify the memory areas */
  /* ISR vectors *must* be placed here as they get mapped to address 0 */
  VECTOR (rx)     : ORIGIN = 0x08000000, LENGTH = 16K
  /* Virtual EEPROM area, we use the remaining 16kB blocks for this. */
  EEPROM (rx)     : ORIGIN = 0x08004000, LENGTH = 48K
  /* The rest of flash is used for program data */
  FLASH (rx)      : ORIGIN = 0x08010000, LENGTH = 960K
  /* Memory area */
  RAM (rwx)       : ORIGIN = 0x20000000, LENGTH = 128K
  /* Core Coupled Memory */
  CCM (rwx)       : ORIGIN = 0x10000000, LENGTH = 64K

This is only half the story, we also need to create the section that will be emitted in the ELF binary:

  .isr_vector :
    . = ALIGN(4);
    . = ALIGN(4);
  } >FLASH

  .text :
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
    _exit = .;
  } >FLASH…

There’s rather a lot here, and so I haven’t reproduced all of it, but this is the same file as before at revision 2389, but a little further down. You’ll note the .isr_vector is pointed at the region called FLASH which is most definitely NOT what we want. The image will not boot with the vectors down there. We need to change it to put the vectors in the VECTOR region.

Whilst we’re here, we’ll create a small region for the EEPROM.

  .isr_vector :
    . = ALIGN(4);
    . = ALIGN(4);

  .eeprom :
    . = ALIGN(4);
    *(.eeprom)         /* special section for persistent data */
    . = ALIGN(4);

  .text :
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */

THAT’s better! Things will boot now. However, there is still a subtle problem that initially caught me out here. Sure, the shiny new .eeprom section is unpopulated, BUT the linker has helpfully filled it with zeros. We cannot program zeroes back into ones! Either we have to erase it in the program, or we tell the linker to fill it with ones for us. Thankfully, the latter is easy (stm32_flash.ld at 2395):

  .eeprom :
    . = ALIGN(4);
    KEEP(*(.eeprom))   /* special section for persistent data */
    . = ALIGN(4);
  } >EEPROM = 0xff

Credit: Erich Styger

We have to do two things. One, is we need to tell it that we want the region filled with the pattern 0xff. Two, we need to make sure it gets filled with ones by telling the linker to write one as the very last byte. Otherwise, it’ll think, “Huh? There’s nothing here, I won’t bother!” and leave it as a string of zeros.

Step 2: Organising the space

Having made room, we now need to decide how to break this data up.  We know the following:

  • We have 3 sectors, each 16kB
  • The sectors have an endurance of 10000 program-erase cycles

Give some thought as to what data you’ll be storing.  This will decide how big to make the blocks.  If you’re storing only tiny bits of data, more blocks makes more sense.  If however you’ve got some fairly big lumps of data, you might want bigger blocks to reduce overheads.

I ended up dividing the sectors into 256-byte blocks.  I figured that was a nice round (binary sense) figure to work with.  At the moment, we have 16 bytes of configuration data, so I can do with a lot less, but I expect this to grow.  The blocks will need a header to tell you whether or not the block is being used.  Some checksumming is usually not a bad idea either, since that will clue you in to when the sector has worn out prematurely.  So some data in each block will be header data for our virtual EEPROM.

If we don’t care about erase cycles, this is fine, we can just make all blocks data blocks, however it’d be wise to track this, and avoid erasing and attempting to use a depleted sector, so we need somewhere to track this.  256 bytes gives us enough space to stash an erase counter and a map of what blocks are in use within that sector.

So we’ll reserve the first block in the sector to act as this index for the entire sector.  This gives us enough room to have 16-bits worth of flags for each block stored in the index.  That gives us 63 blocks per sector for data use.

It’d be handy to be able to use this flash region for a few virtual EEPROMs, so we’ll allocate some space to give us a virtual ROM ID.  It is prudent to do some checksumming, and the STM32F4 has a CRC32 module, so in that goes, and we might choose to not use all of a block, so we should throw in a size field (8 bits, since the size can’t be bigger than 255).  If we pad this out a bit to give us a byte for reserved data, we get a header with the following structure:

15 14 13 12 11 10 19 8 7 6 5 4 3 2 1 0
+0 CRC32 Checksum
+4 ROM ID Block Index
+6 Block Size Reserved

So that subtracts 8 bytes from the 256 bytes, leaving us 248 for actual program data. If we want to store 320 bytes, we use two blocks, block index 0 stores bytes 0…247 and has a size of 248, and block index 1 stores bytes 248…319 and has a size of 72.

I mentioned there being a sector header, it looks like this:

15 14 13 12 11 10 19 8 7 6 5 4 3 2 1 0
+0 Program Cycles Remaining
+8 Block 0 flags
+10 Block 1 flags
+12 Block 2 flags

No checksums here, because it’s constantly changing.  We can’t re-write a CRC without erasing the entire sector, we don’t want to do that unless we have to.  The flags for each block are currently allocated accordingly:

15 14 13 12 11 10 19 8 7 6 5 4 3 2 1 0
+0 Reserved In use

When the sector is erased, all blocks show up as having all flags set as ones, so the flags is considered “inverted”.  When we come to use a block, we mark the “in use” bit with a zero, leaving the rest as ones.  When we erase, we mark the entire flags block as zeros.  We can set other bits here as we need for accounting purposes.

Thus we have now a format for our flash sector header, and for our block headers.  We can move onto the algorithm.

Step 3: The Code

This is the implementation of the above ideas.  Our code needs to worry about 3 basic operations:

  • reading
  • writing
  • erasing

This is good enough if the size of a ROM image doesn’t change (normal case).  For flexibility, I made my code so that it works crudely like a file, you can seek to any point in the ROM image and start reading/writing, or you can blow the whole thing away.


It is bad taste to leave magic numbers everywhere, so constants should be used to represent some quantities:

  • VROM_SECT_SZ=16384:
    The virtual ROM sector size in bytes.  (Those watching Codec2 Subversion will note I cocked this one up at first.)
    The number of sectors.
  • VROM_BLOCK_SZ=256:
    The size of a block
  • VROM_START_ADDR=0x08004000:
    The address where the virtual ROM starts in Flash
    The base sector number where our ROM starts
  • VROM_MAX_CYCLES=10000:
    Our maximum number of program-erase cycles

Our programming environment may also define some, for example UINTx_MAX.

Derived constants

From the above, we can determine:

  • VROM_DATA_SZ = VROM_BLOCK_SZ – sizeof(block_header):
    The amount of data per block.
    The number of blocks per sector, including the index block
    The number of application blocks per sector (i.e. total minus the index block)

CRC32 computation

I decided to use the STM32’s CRC module for this, which takes its data in 32-bit words.  There’s also the complexity of checking the contents of a structure that includes its own CRC.  I played around with Python’s crcmod module, but couldn’t find some arithmetic that would allow it to remain there.

So I copy the entire block, headers and all to a temporary copy (on the stack), set the CRC field to zero in the header, then compute the CRC. Since I need to read it in 32-bit words, I pack 4 bytes into a word, big-endian style. In cases where I have less than 4 bytes, the least-significant bits are left at zero.

Locating blocks

We identify each block in an image by the ROM ID and the block index.  We need to search for these when requested, as they can be located literally anywhere in flash.  There are probably cleverer ways to do this, but I chose the brute force method.  We cycle through each sector and block, see if the block is allocated (in the index), see if the checksum is correct, see if it belongs to the ROM we’re looking for, then look and see if it’s the right index.

Reading data

To read from the above scheme, having been told a ROM ID (rom), start offset and a size, the latter two being in byte sand given a buffer we’ll call out, we first need to translate the start offset to a sector and block index and block offset.  This is simple integer division and modulus.

The first and last blocks of our read, we’ll probably only read part of.  The rest, we’ll read entire blocks in.  The block offset is only relevant for this first block.

So we start at the block we calculate to have the start of our data range.  If we can’t find it, or it’s too small, then we stop there, otherwise, we proceed to read out the data.  Until we run out of data to read, we increment the block index, try to locate the block, and if found, copy its data out.

Writing and Erasing

Writing is a similar affair.  We look for each block, if we find one, we overwrite it by copying the old data to a temporary buffer, copy our new data in over the top then mark the old block as obsolete before writing the new one out with a new checksum.

Trickery is in invoking the wear levelling algorithm on an as-needed basis.  We mark a block obsolete by setting its header fields to zero, but when we run out of free blocks, then we go looking for sectors that are full of obsolete blocks waiting to be erased.  When we encounter a sector that has been erased, we write a new header at the start and proceed to use its first data block.

In the case of erasing, we don’t bother writing anything out, we just mark the blocks as obsolete.


The full C code is in the Codec2 Subversion repository.  For those who prefer Git, I have a git-svn mirror (yes, I really should move it off that domain).  The code is available under the Lesser GNU General Public License v2.1 and may be ported to run on any CPU you like, not just ST’s.

May 032015

The Problem

I’ve been running a station from the bicycle for some time now and I suppose I’ve tried a few different battery types on the station.

Originally I ran 9Ah 12V gel cells, which work fine for about 6 months, then the load of the radio gets a bit much and I find myself taking two with me on a journey to work because one no longer lasts the day.  I replaced this with a 40Ah Thundersky LiFePO4 pack which I bought from EVWorks, which while good, weighed 8kg!  This is a lot lighter than an equivalent lead acid, gel cell or AGM battery, but it’s still a hefty load for a bicycle.

At the time that was the smallest I could get.  Eventually I found a mob that sold 10Ah packs. These particular cells were made by LiFeBatt, and while pricey, I’ve pretty much recouped my costs. (I’d have bought and disposed of about 16 gel cell batteries in this time at $50 each, versus $400 for one of these.)   These are what I’ve been running now since about mid 2011, and they’ve been pretty good for my needs.  They handle the load of the FT-857 okay on 2m FM which is what I use most of the time.

A week or two back though, I was using one of these packs outside with the home base in a “portable” set-up with my FT-897D.  Tuned up on the 40m WICEN net on 7075kHz, a few stations reported that I had scratchy audio.  Odd, the radio was known to be good, I’ve operated from the back deck before and not had problems, what changed?

The one and only thing different is I was using one of these 10Ah packs.  I’ve had fun with RF problems on the bicycle too.  On transmit, the battery was hovering around the 10.2V mark, perhaps a bit low.  Could it be the radio is distorting on voice peaks due to input current starvation?  I tried after the net swapping it for my 40Ah pack, which improved things.  Not totally cleared up, but it was better, and the pack hadn’t been charged in a while so it was probably a little low too.

The idea

I thought about the problem for a bit.  SSB requires full power on voice peaks.  For a 100W radio, that’s a 20A load right now.  Batteries don’t like this.  Perhaps there was a bit of internal resistance from age and the nature of the cells?  Could I do something to give it a little hand?

Supercapacitors are basically very high capacity electrolytic capacitors with a low breakdown voltage, normally in the order of a few volts and capacitances of over a farad.  They are good for temporarily storing charge that needs to be dumped into a load in a hurry.  Could this help?

My cells are in a series bank of 4: ~3.3V/cell with 4 cells gives me 13.2V.  There’s a battery balancer already present.  If a cell gets above 4V, that cell is toast, so the balancer is present to try to prevent that from happening.  I could buy these 1F 5.5V capacitors for only a few dollars each, so I thought, “what the hell, give it a try”.  I don’t have much information on them other that Elna Japan made them.  The plan was to make some capacitor “modules” that would hook in parallel to each cell.

My 13.2V battery pack, out of case

My 13.2V battery pack, out of its case



For my modules, the construction was simple, two reasonably heavy gauge wires tacked onto the terminals, the whole capacitor then encased in heatshrink tubing and ring lugs crimped to the leads. I was wondering whether I should solder a resistor and diode in parallel and put that in series with the supercap to prevent high in-rush current, but so far that hasn’t been necessary.

The re-assembled pack

I’ve put the pack back together and so far, it has charged up and is ready to face its first post-retrofit challenge.  I guess I’ll be trying out the HF station tomorrow to see how it goes.

Assembled pack

Assembled pack

The Verdict

Not a complete solution to the RF feedback, it seems to help in other ways. I did a quick test on the drive way first with the standard Yaesu handmic and with the headset. Headset still faces interference problems on HF, but I can wind it up to about 30W~40W now instead of 20.

More pondering to come but we’ll see what the other impacts are.

Jan 032015

I’ve been riding on the road now for some years, and while I normally try to avoid it, I do sometimes find myself riding on the road itself rather than on the footpath or bicycle path.

Most of the time, the traffic is fine.  I’m mindful of where everyone is, and there aren’t any problems, but I have had a couple of close calls from time to time.  Close calls that have me saying “ode for a horn”.

By law we’re required to have a bell on our bikes.  No problem there, I have a mechanical one which is there purely for legal purposes.  If I get pulled over by police, and they ask, I can point it out and demonstrate it.  Requirement met?  Tick to that.

It’s of minimal use with pedestrians, and utterly useless in traffic.

Early on with my riding I developed a lighting system which included indicators.  Initially this was silent, I figured I’d see the lights flashing, but after a few occasions forgetting to turn indicators off, I fitted a piezo buzzer.  This was an idea inspired by the motorcycles ridden by Australia Post contractors, which have a very audible buzzer.  Jaycar sell a 85dB buzzer that’s waterproof, overkill in the audio department but fit for purpose.  It lets me know I have indicators on and alerts people to my presence.

That is, if they equate the loud beep to a bicycle.  Some do not.  And of course, it’s still utterly useless on the road.

I figured a louder alert system was in order.  Something that I could adjust the volume on, but loud enough to give a pedestrian a good 30 seconds warning.  That way they’ve got plenty of time to take evasive action while I also start reducing speed.  It’s not that I’m impatient, I’ll happily give way, but I don’t want to surprise people either.  Drivers on the other hand, if they do something stupid it’d be nice to let them know you’re there!

My workplace looks after a number of defence bases in South-East Queensland, one of which has a railway crossing for driver training.  This particular boom gate assembly copped a whack from a lightning strike, which damaged several items of equipment, including the electronic “bells” on the boom gate itself.  These “bells” consisted of a horn speaker with a small potted PCB mounted to the back which contained an amplifier and bell sound generator.  Apply +12V and the units would make a very loud dinging noise.  That’s in theory; in practise, all that happened was a TO-220 transistor got hot.  Either the board or the speaker (or both) was faulty.

It was decided these were a write-off, and after disassembly I soon discovered why: the voice coils in the horn speakers had been burnt out.  A little investigation, and I figured I could replace the blown out compression drivers and get the speakers themselves working again, building my own horn.

A concept formed: the horn would have two modes, a “bell” mode with a sound similar to a bicycle bell, and a “horn” mode for use in traffic.  I’d build the circuit in parts, the first being the power amplifier then interface to it the sound effect generator.

To make life easier testing, I also decided to add a line-in/microphone-in feature which would serve to debug construction issues in the power amplifier and add a megaphone function.  (Who knows, might be handy with WICEN events.)

Replacing the compression drivers

Obviously it’d be ideal to replace it with the correct part, but looking around, I couldn’t see anything that would fit the housing.  That, and what I did see, was more expensive than buying a whole new horn speaker.

There was a small aperture in the back about 40mm in diameter.  The original drivers were 8ohms, and probably rated at 30W and had a convex diaphragm which matched the concave geometry in the back of the horn assembly.

Looking around, I saw these 2W mylar cone speakers.  Not as good as a compression driver, but maybe good enough?  It was cheap enough to experiment.  I bought two to try it out.

I got them home, tacked some wires onto one of them and plugged it into a radio.  On its own, not very loud, but when I held it against the back of a horn assembly, the amplification was quite apparent.  Good enough to go further.  I did some experiments with how to mount the speakers to the assembly, which required some modifications to be made.

I soon settled on mounting the assembly to an aluminium case with some tapped holes for clamping the speaker in place.  There was ample room for a small amplifier which would be housed inside the new case, which would also serve as a means of mounting the whole lot to the bike.

Bell generator

I wasn’t sure what to use for this, I had two options: build an analogue circuit to make the effect, or program a microcontroller.  I did some experiments with an ATMega8L, did manage to get some sound out of it using the PWM output, but 8kB of flash just wasn’t enough for decent audio.

A Freetronics LeoStick proved to be the ticket.  32kB flash, USB device support, small form factor, what’s not to like?  I ignored the Arduino-compatible aspect and programmed the device directly.  Behind the novice-friendly pin names, they’re an ATMega32U4 with a 16MHz crystal.  I knocked up a quick prototype that just played a sound repeatedly.  It sounded a bit like a crowbar being dropped, but who cares, it was sufficient.

Experimenting with low-pass filters I soon discovered that a buffer-amp would be needed, as any significant load on the filter would render it useless.

A 2W power amplifier

Initially I was thinking along the lines of a LM386, but after reading the datasheet I soon learned that this would not cut it.  They are okay for 500mW, but not 2W.  I didn’t have any transistors on hand that would do it and still fit in the case, then I stumbled on the TDA 1905.  These ICs are actually capable of 5W into 4 ohms if you feed them with a 14V supply.  With 9V they produce 2.5W, which is about what I’m after.

I bought a couple then set to work with the breadboard.  A little tinkering and I soon had one of the horn speakers working with this new amplifier.  Plugged into my laptop, I found the audio output to be quite acceptable, in fact turned up half-way, it was uncomfortable to sit in front of.

I re-built the circuit to try and make use of the muting feature.  For whatever reason, I couldn’t get this to work, but the alternate circuit provided a volume control which was useful in itself.

The pre-amplifier

For the line-level audio, there’s no need for anything more fancy than a couple of resistors to act as a passive summation of the left and right channels, however for a microphone and for the LeoStick, I’d need a preamp.  I grabbed a LM358 and plugged that into my breadboard alongside the TDA1905.

Before long, I had a working microphone preamp working using one half of the LM358, based on a circuit I found.  I experimented with some resistor values and found I got reasonable amplification if I upped some of the resistor values to dial the gain back a little.  Otherwise I got feedback.

For the LeoStick, it already puts out 5V TTL, so a unity-gain voltage follower was all that was needed.  The second half of the LM358 provided this.  A passive summation network consisting of two resistors and DC-blocking capacitor allowed me to combine these outputs for the TDA1905.

One thing I found necessary, the TDA1905 and LM358 misbehave badly unless there’s a decent size capacitor on the 9V rail.  I found a 330uF electrolytic helped in addition to the datasheet-prescribed 100nF ceramics.

Power supply

Since I’m running on batteries with no means of generating power, it’s important that the circuit does not draw power when idle.  Ideally, the circuit should power on when either I:

  • plug the USB cable in (for firmware update/USB audio)
  • toggle the external source switch
  • press the bell button

We also need two power rails: a 9V one for the analogue electronics, and a 5V one for the LeoStick.  A LM7809 and LM7805 proved to be the easiest way to achieve this.

To allow software control of the power, a IRF9540N MOSFET was connected to the 12V input and supplies the LM7809.  The gate pin is connected to a wired-OR bus.  The bell button and external source switch connect to this bus with signal diodes that pull down on the gate.

Two BC547s also have collectors wired up to this bus, one driven from the USB +5V supply, and the other from a pin on the LeoStick.  Pressing the Bell button would power the entire circuit up, at which point the LeoStick would assert its power on signal (turning on one of the BC547s) then sample the state of the bell button and start playing sound.  When it detects the button has been released, it finishes its playback and turns itself off by releasing the power on signal.

Sound effect generator

Earlier I had prototyped a bell generator, however it wasn’t much use as it just repeatedly made a bell noise regardless of the inputs.  To add insult to injury, I had lost the source code I used.  I had a closer look at the MCU datasheet, deciding to start from a clean slate.

The LeoStick provides its audio on pin D11, which is wired up to Port B Pin 7.  Within the chip, two possible timers hook up: Timer 0, which is an 8-bit timer, and Timer 1, which is 16-bits.  Both are fed from the 16MHz system clock.  The bit depth affects the PWM carrier frequency we can generate, the higher the resolution, the slower the PWM runs.  You want the PWM frequency as high as possible, ideally well above 20kHz so that it’s not audible in the audio output, and obviously well above the audio sampling rate.

At 16MHz, a 16-bit timer would barely exceed 240Hz, which is utterly useless for audio.  A 10-bit timer fares better, with 15kHz, older people may not hear it but I certainly can hear 15kHz.  That leaves us with 8-bits which gets us up to 62kHz.  So no point in using Timer 1 if we’re only going to be using 8-bits of it, we might as well use Timer 0.

Some of you familiar with this chip may know of Timer 4, which is a high-speed 10-bit timer fed by a separate 64MHz PLL.  It’s possible to do better quality audio from here, either running at 10-bits with a 62kHz carrier, or dropping to 8-bits and ramping the frequency to 250kHz.  Obviously it’d have been nice, but I had already wired things up by this stage, so it was too late to choose another pin.

Producing the output voltage is only half the equation though: once started, the PWM pin will just output a steady stream of pulses, which when low-passed, produces a DC offset.  In order to play sound, we need to continually update the timer’s Capture Compare register with each new sample at a steady rate.

The most accurate way to do this, is to use another timer.  Timer 3 is another 16-bit timer unit, with just one capture compare output available on Port C pin 3.  It is an ideal candidate for a timer that has no external influence, so it gets the job of updating the PWM capture compare value with new samples.

Timer 1 is connected to pins that drive two of the three LEDs on the LeoStick, with Timer 4 driving the remaining one, so if I wanted, I could have LEDs fade in and out with it instead of just blinking.  However, my needs are basic, and I need something to debounce switches and visibly blink LEDs.  So I use that with a nice long period to give me a 10Hz timer.

Here is the source code.  I’ll add schematics and other notes to it with time, but the particular bits of interest for those wanting to incorporate PWM-generated sound in their AVR projects are the interrupt routine and the sound control functions.

To permit gapless playback, I define two buffers which I alternate between, so while one is being played back, the other can be filled up with samples.  I define these on line 139 with the functions starting at line 190.  The interrupt routine that orchestrates the playback is at line 469.

When sound is to be played, the first thing that needs to happen is for the initial buffer to be loaded with samples using the write_audio function.  This can either read from a separate buffer in RAM (e.g. from USB) or from program memory.  One of the options permits looping of audio.  Having loaded some initial data in, we can then call start_audio to set up the two timers and get audio playback rolling.  start_audio needs the sample rate to configure the sample rate timer, and can accept any sample rate that is a factor of 16MHz (so 8kHz, 16kHz up to 32kHz).

The audio in this application is statically compiled in, taking the form of an array of uint8_t‘s in PROGMEM.

Creating the sounds

I initially had a look around to see if I could get a suitable sound effect.  This proved futile, I was ideally looking around for a simple openly-licensed audio file.  Lots of places offered something, but then wanted you to sign up or pay money.  Fine, I can understand the need to make a quid, and if I were doing this a lot, I’d pay up, but this is a once-off.

Eventually, I found some recordings which were sort of what I was after, but not quite.  So I downloaded these then fired up Audacity to have a closer look.

The bicycle bell

Bicycle bells have a very distinctive sound to them, and are surprisingly complicated.  I initially tried to model it as an exponentially decaying sinusoid of different frequencies, but nothing sounded quite right.

The recording I had told me that the fundamental frequency was just over 2kHz.  Moreover though, the envelope was amplitude-modulated by a second sinusoid: this one about 15Hz.  Soon as I plugged this second term in, things sounded better.  This script, was the end result.  The resulting bell sounds like this:

So somewhat bell-like.  To reduce the space, I use a sample rate of 6.4kHz.  I did try a 4kHz sample rate but was momentarily miffed at the result until I realised what was going on: the bell was above the Nyquist frequency at 4kHz, 6.4kHz is the minimum practical rate that reproduces the audio.

I used Audacity to pick a point in the waveform for looping purposes, to make it sound like a bell being repeatedly struck.

The horn

I wanted something that sounded a little gutsy.  Like an air-horn on a truck.  Once again, I hit the web, and found a recording of a train horn.  Close enough, but not long enough, and a bit noisy.  However opening it up in Audacity and doing a spectrum analysis, I saw there were about 5 tones involved.  I plugged these straight into a Python script and decided to generate those directly.  Using a raised cosine filter to shape the envelope at the start and end, and I soon had my horn effect.  This script generates the horn.  The audio sounds like this:

Using other sound files

If you really wanted, you could use your own sound recordings.  Just keep in mind the constraints of the ATMega32U4, namely, 32kB of flash has to hold both code and recordings.  An ATMega64 would do better.  The audio should be mono, 8-bits and unsigned with as lower sample rate as you can get away with.  (6.4kHz proved to be sufficient for my needs.)

Your easiest bet would be to either figure out how to read WAV files (in Python: wave module), or alternatively, convert to raw headerless audio files, then code up a script that reads the file one byte at a time. The Python scripts I’ve provided might be a useful starting point for generating the C files.

Alternatively, you can try interfacing a SDCard and embedding a filesystem driver and audio file parser (not sure about WAVE but Sun Audio is easily parsed), this is left as an exercise for the adventurous.

Finishing up

I’ll put schematics and pictures up soonish.  I’m yet to try mounting the whole set up, but so far the amplifier is performing fine on the bench.

Oct 262014

Earlier this week I had an idea.  We’ve got an old clock radio that picks up interference from the fridge when it turns on and the buttons on it are starting to fail with age.

I thought: “Why not build a new one?”

So the requirements are simple.  We need a real-time clock, display driver, and of course, a receiver.  The unit we have spends most of its time tuned to 792kHz AM (4QG or “ABC Radio National”), so a simple direct conversion receiver was what I was thinking of.  But what about the LO?

Now I do have some clock radio ICs that implement the timing circuitry, alarm function and LED panel driver somewhere in a junk box.  You feed them with the 50Hz or 60Hz waveform that comes out of the transformer and they use that as the timing source.  Easy to use a 555 timer for the time source, and I’d make a traditional receiver.  Another option is to use a AVR microcontroller, I have a few ATMega8Ls in the junk box with a NXP I2C RTC chip which I also have a few of.

The ATMega8L has a couple of PWM channels one 16-bit and one 8-bit: could they be used as an LO?

So: after digging around and locating my bought-years-ago and not-yet-used AVR programmer, and dusting off a breadboard that had an ATMega8L on it from a previous experiment I set to work.

This page explains in good detail how the PWM channels work. I started with those examples as a guide and tweaked from there.

For the PWM channel to work as a receiver LO, I want it to cover 540kHz to ~2MHz, with reasonable granularity. Question is, how far can I crank this? I have a 4MHz crystal, not the fastest I can use with this chip, but the absolute top of the range for the ATMegas isn’t much higher: 16MHz or maybe 20MHz. So if you’ve got a 16MHz crystal, you can expect to quadruple what I do here.

I started off with some blink code. If you take out all the delays, you get the following code:

#include <avr/io.h>
int main(void)
        DDRB |= (1 << DDB1);
        while (1)
                PORTB ^= (1 << DDB1);

and the following waveform:

Waveform done in software with GPIOs

Waveform done in software with GPIOs

The yellow waveform there is off one of the crystal pins. The cyan one is the PWM pin output, which in this case is a software driven GPIO. Even if this one worked, you wouldn’t want to do it this way unless your chip was doing only this task, and who’d use a programmable chip like an ATMega8L for that?

So, after reading through the documentation and examples, I loaded in the following code:

#include <avr/io.h>

#define TCCR1_COM1A     1
#define TCCR1_COM1B     0
#define TCCR1_FOC1A     0
#define TCCR1_FOC1B     0
#define TCCR1_WGM1      0xf
#define TCCR1_ICNC1     0
#define TCCR1_ICES1     0
#define TCCR1_CS1       1
#define TCCR1A_VAL      (                       \
                        (TCCR1_COM1A    << 6)   \
                |       (TCCR1_COM1B    << 4)   \
                |       (TCCR1_FOC1A    << 3)   \
                |       (TCCR1_FOC1B    << 2)   \
                |       (TCCR1_WGM1 & 0x3)      )
#define TCCR1B_VAL      (                       \
                        (TCCR1_ICNC1    << 7)   \
                |       (TCCR1_ICES1    << 6)   \
                |       (((TCCR1_WGM1 & 0xc) >> 2) << 3) \
                |       TCCR1_CS1)

int main (void)
        DDRB |= (1 << DDB1);
        OCR1A = 0x001;
        TCCR1A = TCCR1A_VAL;
        TCCR1B = TCCR1B_VAL;

The frequency can be adjusted by playing with OCR1A. If I leave it at 1 (basically as fast as the PWM can go) I get the following:

Waveform from AVR PWM

Waveform from AVR PWM

Bump it up one, and it sinks to 600kHz. Way too coarse for what I want sadly. I guess I was hopeful, but maybe the above might serve as a useful spring-off point for experiments with PWM.

Jun 152014

This is a simple vertical groundplane antenna intended for mounting atop a 10m Squid Pole. These can be made to nearly any frequency you desire, and can be self-supporting if needed. The main limitation is the stiffness of the wire used.

The antenna gets its name as the original was one I quickly knocked up just prior to a horse endurence ride event that took place at Donnybrook in 2011. I was assisting Brisbane Area WICEN with the emergency communications at this event, and this antenna, worked very well. 10W was more than sufficient to get back to base on 2m FM.

The design is very simple. You’ll need some stiff copper wire, and a panel-mount BNC connector. I used some strands from a thick mains cable: this was being tossed out at a ham radio meeting some years back. The cable had a black plastic coating and inside were 7 strands of solid copper, each about 2mm thick. Perfect for small antennas.

Similar wire can be found in non-stranded house mains cable.

First step is to work out what length to cut the elements. They should all be roughly the same length. This can be calculated by the simple formula:


which if you take v as being the velocity of light in a vacuum (~3\times10^8 m/s; radio will travel a little slower through air, but who’s counting?) and f as being 147.050\times10^6 and solve for \lambda you get 2.04m as the wavelength.  We want ¼ of this, so I’ve aimed for 51cm long elements.

Don’t worry about them being perfectly straight when measuring, extra length is good at this point, you’ll want a good 2cm extra.  You can make a wire shorter, you can’t make it longer.

Measuring the elements

Measuring the elements

Measure and cut the 4 elements. 3 will become your groundplane, and the 4th the radiating element. Also cut off about 10cm or so, give or take, which will be the ground wire used to hook the groundplane elements to the BNC connector. Also add to your parts list, some small velcro strips: you’ll find these handy to strap the coax to the squid pole.

Procured parts

Procured parts

Start with the short piece of wire. You’ll want to bend it into a rough triangle shape, with loops of wire at the corners. The groundplane radials will loop through these holes. The excess wire should be coiled up to one side: this is the loop the squid pole will pass through. The BNC connector will be fitted in between the 3 small loops.

Ground wire

donnybrook-03-ground-wire Ground wire

Be sure you can still put the nut back on.

Take 3 of the four elements, and make a hook at one end. Pass this hook through each of the small loops in the triangle. Try to make them sit roughly straight out from the centre of the triangle, then solder each hook into the loop.

Hooking the radials

Soldering the radialsAttaching the radials

Having done this, put the BNC connector in and do the nut up tight. You can do away with the eyelet with the solder tag. To finish off, take your remaining element, make a hook just big enough to go around the centre pin of the BNC connector, then solder into place.

Preparing radiating element

Hooking radiating elementSoldering the radiating element Attaching the radiating element

To finish off, bend this until it is vertical. The antenna is now ready for tuning.

Completed untuned antenna

Completed untuned antenna

Double check the length is about right. It should be around the 51~52cm mark.

Checking length

Checking length (close) Checking length

To check the tuning, use a SWR meter or antenna analyser if you have one. Here, I used the built-in SWR meter on my Yaesu FT-857D. When using a SWR meter, ensure you’re running minimum power. The following are some results from my set.  It is at this point, you do any trimming of your antenna.  The following are without trimming the antenna, you’ll note that in most examples, the SWR is very low, just a point or so showing up on the left side of the screen.

On 2m:

donnybrook-13-test-144500 donnybrook-13-test-145500 donnybrook-13-test-146500 donnybrook-13-test-147500

On 70cm:

donnybrook-13-test-432100 donnybrook-13-test-433100 donnybrook-13-test-434100 donnybrook-13-test-438100 donnybrook-13-test-439100 donnybrook-13-test-440100

To mount the antenna on your squid pole, feed the tip of the squid pole through the remaining loop.  Bend the tip of the antenna around the tip of the squid pole.  Hook your coaxial cable to the BNC connector and use velcro straps at regular points to hold the coax to the side of the squid pole.

Mounted antenna

Mounted antenna

Recommended coax for this purpose is RG-195.  RG-58 will work, but is lossy, RG-213 and LMR400 are too heavy to use on a squid pole and will cause it to bend or collapse.

Update: This antenna performed quite well.  Saturday, we used it for 2m packet, providing a digipeater for the stations in our area in case they couldn’t reach the main node (at “the pineapple farm” just outside Imbil).  We had stable packet communications all day.  Since the stations around us found they could work the main node directly, we swapped antennas around and used it instead for a VHF/UHF cross-band voice repeater.  Signal reports were good through the Imbil state forest.

Aug 132011

This post may also be read here.

Well, today I did some more work on the 2m linear.  Earlier this week I ordered some SMA connectors and some 1N5711 diodes for the project.

Two 1N5711 diodes will be used to make a voltage peak detector, to detect when the amplifier is subjected to power above 60mW.  The SMA connectors will be the interconnects between the modules.  This afternoon’s effort was spent soldering the SMA connectors onto two of the boards, and mounting the 2m amplifier module onto the heatsink.

The EME157B2 preamplifier kit was originally intended to be mounted in a masthead box, with BNC connectors soldered to the PCB, and stuck up a pole near the antenna.  In my application, I wanted it to be in the same enclosure (with suitable shielding) as the power amp, so that I could use its RF detection to automatically switch the power amplifier on.  I will also be using different relays, mounted on a separate board.

Instead of mounting the SPDT relays for the kit on the EME157B2 board, I’ve instead left these off.  I also omitted the 2N7000 MOSFET which turns on the relays, and L4, an RF-blocking choke which permits the preamp to run from a 12V source supplied up the coax.  I instead will power the preamp directly.

Since the relays will be on a separate board, the plan is to run wires from the gate and source connections where the 2N7000 belongs, and run those out to a controller board.  With the relays gone, the RF detection and the preamp are essentially two distinct circuits.  So 3 SMA connectors will be needed.  Here is the completed board with the SMA connectors fitted, and suitable jumpers installed, ready for tuning.

Completed 2m preamplifier

Completed 2m preamplifier. Connectors going left-to-right: Antenna input, Amplifier output, RF detector input.

Next, I finished off the power amplifier board, mounting it to the heatsink.  I have left one EMC filter disconnected for now, as the instructions say to power it up first with it disconnected to set the trim pot for 4.5V bias.  Rather than mounting the board flat on the heatsink, I have instead opted to mount the PCB at 90? to the module.  I had to make the supplied eyelets a fraction longer to accommodate this.  I also mounted SMA connectors on this board.

Completed 2m power amplifier

Completed 2m power amplifier. RF input is on the left.

The plan is, I’ll route RG195 coax on the left side to a small module which will contain the overload detection circuit and two SMAs for an external attenuator module.  On the right, a low-pass filter will be connected.  I also had a stab at tapping holes into the sides of the heatsink for mounting a bracket.  This bracket would hold the fans on top, and would bolt onto the main enclosure.  In doing this, I managed to bugger up two of the 8 holes, and thus what I’ll probably do, is buy a M4 tap tomorrow, drill them all out to 3mm and tap them to 4mm.  These are structural holes, so bigger is probably better anyway.

Much of today though was spent designing the controller.  I’m still finalising the design, but a rough schematic is below.

2m amplfier controller

2m amplfier controller

So, not yet going, but big parts are built now.

Aug 042011

This build log is also viewable here.


A few months back, I grabbed the trusty FT-290R II ready to do my weekly run from The Gap to Tarragindi.  Quick test to check everything’s okay… the power meter swings to full scale, but strange, I’m not hitting any repeaters.

Okay, grabbed the FT-897D instead, and I just did my weekly radio duties with that instead.  When I came home that evening, I had a closer look.  The FT-290R II was emitting a signal, the hand-held was picking that up.  It was also receiving just fine.  On a hunch I took off the FL-2025 linear, and hooked the antenna up directly to the radio.  Bingo… the radio works, the linear does not.

So, the linear had died, and thus I was in need of a new one.  Hand helds really don’t have much punch for mobile use, in fact, the FT-290 has been brilliant on the bike.  Not menu driven, so it’s real easy to drive while riding, simple, no frills, and sufficient grunt to get out of a bad area.  It also does SSB (and CW, but I’ll leave that to LY2KW).

I could buy a new set, in fact, I may get a FT-857D, as the 897D is a heavy lump of a radio to lug around, and there are times when HF capability is useful.  It is less than ideal on the bike however due to its size and weight.  There was nothing wrong with the FT-290, just its linear was dead, thus I was limited to its barefoot transmit power of 2.5W, even less than most handhelds.

So, I decided I’d try my hand at a semi-homebrew linear amplifier.

The concept

I wanted an amplifier that could achieve at least 25W of transmit power using SSB.  As I’d likely use it for things like WIA broadcasts, I wanted one that would also handle transmitting for a long period of time.

Designing a full blown amplifier on 2m is a bit beyond me with my limited homebrew experience.  It is also an issue sourcing the PCB material needed for VHF projects.  A lot out there call for FR4 grade fibreglass PCBs.  I have no idea what Jaycar sell.  So this was going to be a potential minefield.  Thus, I opted for a kit.

Minikits sell one based on the Mitsubishi RA30H1317M.  The same kit, can also take the 60W module, which sounded good to me.  Most of the time I’d be running it at 30W, but having 60W capability sounded good.  I purchased this, along with the 30W module as well just in case.

I also thought a pre-amp would be nice.  The same supplier sells this preamp kit.  The kit also offers RF sensing, which would allow the amplifier to auto-detect the radio transmitting, and switch into transmit mode automatically.  This also allows for filtering, to prevent reception of pagers (not fun copping an earful of one of those when you’re wearing a helmet-embedded headset riding a bicycle).


Minikits recommends using a Pentium 4 heatsink for 30W modules, however it wasn’t clear if this would be sufficient for 60W modules.

I wanted the amplifier module to stay below 100?C while operating with ambient temperatures at 40?C.  Pretty sure I don’t want to operate a radio under such conditions, so it should work fine in all conditions that I’m likely to encounter.

The amplifier module is about 45% efficient, thus about 135W is dissipated when operating at full power.  By my calculations, I was looking for cooling that can provide 0.22?C/W.

A quick search revealed that I could get one via Conrad which in the open air achieves 0.84?C/W.  Combined with a fan, it can achieve 0.24?C/W.  Jaycar sell this fan, which is quite capable.  In fact, two of them will fit across the back of the heatsink, so with dual fans, I should be well and truly within limits.

I placed the order for the heatsink a fortnight ago.  Due to a mix-up, I didn’t get it until Wednesday, but that’s fine, I wasn’t in any hurry.  With the heatsink now in my possession, I today headded to Jaycar to pick up some of the bits and pieces I’d need for this project, starting with the enclosure.

One thing I did neglect to procure today, were the fans… but no biggie, I’ll get those later.

Prior work

Well, technically day one was some time ago.  I had already mostly built the amplifier kit, and the preamp.  The preamp got built way back when I first obtained the kits.

The power amp was built later, however the instructions suggested that I wait until I have the amplifier module mounted on the heatsink before I go soldering it to the PCB.

Amplifier kit and 60W module

Amplifier kit and 60W module

Day 1

Having got the heatsink, enclosure and tools, I set to work.  Initially I positioned, drilled and tapped the two M3 holes for mounting the amplifier module.  I haven’t tried putting the amplifier in place yet, but it looks like the holes are positioned pretty well.

Amplifier module on heatsink

Amplifier module on heatsink

My plan, is to bend the pins on the module at 90? and mount the PCB horizontally.  Both module and PCB would be passed through the side wall of the enclosure, with the heatsink outside.  I originally wanted the heatsink inside the case (with vent holes), but of course, Jaycar are not good at providing internal dimensions, and I soon discovered it’d be awkward to fit.

It took a bit of experimentation to cut the hole in the side.  No, I won’t be winning any prizes for my metal work, in fact, it never was one of my best subjects.

Heatsink and empty enclosureHeatsink and empty enclosure (side view)

Heatsink and empty enclosure

Next steps:

My immediate next step will be to mount the amplifier module, solder it to the PCB, and mount the PCB inside the case.  Then I mount the heatsink and fans to the case.

I have a controller that I have designed at digital logic level, however I’ll need to do some further design work to make sure it’ll do what I intend, before procuring the parts and building it.