I’ve mentioned a few times that my preferred interface for software-defined radios (SDRs) is HDSDR. I like the way it’s layed out and I especially like how it allows for control of different hardware by simply dropping in a new control DLL.
Ever since I built the previously described Si5351 signal generator, it’s been on my list of things-to-do to write an HDSDR DLL to control it. That only made sense since the whole reason for building the signal generator was to use it as a source when experimenting with various receiver designs. And since I recently received an email asking if just such a DLL was available, I decided it was time to do something about it.
So What Is This Hardware Interface You Mention?
As described in the HDSDR FAQ, HDSDR communicates with hardware through a control module referred to as the External Input Output Dynamic Link Library (ExtIO-DLL). The nice thing about this is the interface for the ExtIO DLL is publicly available. If you have a new piece of hardware you’d like to use with HDSDR, just write a DLL that provides the proper interface, drop it into the HDSDR program directory, and you’re good to go.
Writing the DLL…
If you’ve ever written a DLL for the Windows operating system you won’t have any trouble producing an ExtIO-DLL. The interface description can be found in the specifications available on either the original Winrad page or I2PHD’s WeakSignals page. Of 19 possible entry points, only eight (InitHW, OpenHW, StartHW, StopHW, CloseHW, SetHWLO, GetStatus, and SetCallback) are required.
I had already written a Python library to control the Si5351 so this was the logical place to start. I ported the routines to C and integrated them as appropriate within an ExtIO-DLL project skeleton. Since the required entry points are sufficient to control the Si5351, they’re the only ones I implemented. The source code and precompiled binaries are available from the GitHub repository as a Visual Studio 2008 project. If you’re going to rebuild from souce you’ll also need the libusb-win32 library.
And Using The Hardware
The signal generator uses an Adafruit Trinket with appropriate firmware as a USB-to-I2C interface for the Si5351. When you plug the signal generator into the USB port the first time, Windows will attempt to load a driver once the Trinket gets past its bootloader. The driver can be obtained as part of the original I2CStick project upon which the Trinket firmware is based. Download the zip, extract the driver, and install it as you normally would. The file includes versions for both 32 and 64 bit but I’ve only tested the 64 bit version on Win7.
At this point, drop the ExtIO-DLL from the Visual Studio project (it can be found in the Release or Debug directory, depending upon which you want) into the HDSDR program directory. Start HDSDR as normal and choose the Extio-Si5351 DLL when prompted.
With the DLL as written, the signal generator will produce I and Q signals at the HDSDR local oscillator (LO) frequency on the Si5351 clocks 0 and 1. Since there’s only control for one frequency in the Extio-DLL interface I didn’t bother with clock 2.
Also, even though you can go down to a 0 Hz LO in HDSDR, the Si5351 won’t work that low. It bottoms out somewhere between 1 and 2 MHz so if you’re going lower than that you’ll need some sort of divider circuit.
Finally, while this project was written for the Windows operating system, it could be modified to work under Linux with Wine. This is actually the next improvement I’m looking at since, at least for me. using HDSDR with a Linux native library to control the hardware would definitely be the best of both worlds.
When S/PDIF became available in the Teensy Audio Library I thought this might be the solution to ground loop problems I’d been having when interfacing projects to my PC. However, I quickly realized I didn’t have any sound cards with an S/PDIF interface.
In the belief that I’d rather build than buy I decided to update one of my previous projects, a PCM2904 based sound card, to include an S/PDIF interface. The update was a cinch because TI has a pin-for-pin replacement for the PCM2904 (the PCM2906) with an S/PDIF interface. All I had to do was replace the audio jacks with fiber-optic transmitter/receivers connected to the appropriate pins.
The resulting schematic and prototype are shown below. (If you’re interested, the boards are available through OSH Park)
There’s not a lot to it. It’s simply the reference circuit from the PCM2906 data sheet with portions I don’t expect to use eliminated.
Testing The Interface
To test the interface I looped the transmitted fiber optic signal back to the receiver. When plugged into my Linux laptop it registered as a Texas Instruments PCM2906C Audio Codec as shown below.
Bus 004 Device 003: ID 058f:6366 Alcor Micro Corp. Multi Flash Reader Bus 004 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 003 Device 004: ID 1bcf:2c02 Sunplus Innovation Technology Inc. Bus 003 Device 003: ID 413c:3016 Dell Computer Corp. Optical 5-Button Wheel Mouse Bus 003 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 013: ID 08bb:29c6 Texas Instruments PCM2906C Audio CODEC Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Starting up the PulseAudio Volume Control and playing back a file using VLC, I could see the input and output audio levels varying with the signal from VLC.
If you want to actually hear the looped back audio you can use the PulseAudio loopback module.
Open a terminal and execute the command shown below. The result will be a list of names associated with alsa modules, sources, and sinks.
pactl list | grep Name:
- Look for the alsa analog stereo output to identify the sink. On my system it takes the form alsa_output.pci-0000_00_1b.0.analog-stereo.
- Look for the PCM2906 input to identify the source. Ony my system it took the form alsa_input.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo.
Open a terminal and execute the command:
pactl load-module module-loopback source=<source_name> sink=<sink_name>
where <source_name> and <sink_name> are those identified above. Please note the source and sink names are case sensitive.
You should now hear the looped-back audio through your system speakers.
Lately I’ve been working on some simple receiver designs and decided it’s time to put together a real signal generator. I like the smell of melted solder as much as anyone else but I’m getting tired of rebuilding the wheel for each receiver design I want to try.
With that in mind, I decided to expand upon the Si5351 USB controller I described previously. The original is a useful circuit but if I planned to use this on a regular basis there were a couple of improvements I wanted to make.
First, USB communications using the 3.3V Trinket weren’t as reliable as I would like so I switched to the Trinket 5V version. This meant adding a 3.3V regulator to power the Si5351. In addition, when using the original circuit I usually ended up feeding the clock signals through 5V level shifters so I decided to incorporate them directly.
The resulting schematic is shown in the figure below. The regulator is simply a 78L33 taking its input from the Trinket 5V pin and supplying the Si5351 VDD. The level shifters are CMOS inverters, one for each clock output. The particular chip I used has a single gate per chip but these could just as easily be replaced with a quad gate chip. I just happened to have the single gate chips on hand.
You may notice there are no I2C level shifters between the Trinket and Si5351, despite their operating at different voltage levels. In previous projects I’ve found level shifters aren’t necessary going between 5V and 3.3V chips so long as the bus is powered from the 3.3V supply and the 5V side reads 3.3V as a logic high. It’s not strictly according to specs but it works and saves a few components.
The circuit is powered from the USB bus and uses the same Python library developed for the original circuit. This library can be pulled down from its GitHub repository.
A photo of the completed circuit in its Altoids Tin case is shown below. Like most of the one-off circuits I’ve done lately it’s built on stripboard using adapters for the surface mount parts. Later I may put together a printed circuit board and, if so, will provide an update.