Recently I started a new series of project tutorials for getting started with SDR development. So far it has focused on demonstrating the basics of getting started with some of the most common SDR hardware currently available on the market, specifically how to get everything installed on a host PC and interfaced with the hardware since software updates continually change that process.
After pulling out my B205mini and RTL-SDR to spend some time getting everything working with the latest version of GNU Radio, I became aware of Digilent's latest release of the Zmod SDR. At first it appeared to just be a single receive-only Zmod peripheral board. Then digging into the reference material a bit deeper showed that in combination with the Eclypse Z7 FPGA development board and Zmod AWG peripheral board, the system became a full transmit and receive capable SDR development platform.
What is the Zmod SDR?Like I mentioned, the Zmod SDR itself is another Zmod peripheral board added to Digilent's line-up for use with any Zmod-equipped FPGA board. It boasts an Analog-to-Digital conversion chip with its two channels routed to SMA connectors.
For those not familiar, Digilent's Zmod is based on the SYZYGY interface standard from Opal Kelly that is a low-cost option for high-speed I/O in a compact footprint. Digilent adopted SYZYGY to build their own protocol on top of to fill the gap between their low-speed I/O Pmod interface and the high-speed, large footprint of FMC.
At first glance, the SDR Zmod peripheral board looks to nearly be a copy of the Zmod Digitizer peripheral board, using the same AD9648 ADC chip. But a few very key details of its analog circuitry make it much more suitable for SDR development.
Starting with the input of the analog signal chain at the SMA connectors, the input impedance is 50Ω to match standard antenna impedance versus 1MΩ on the Digitizer Zmod that is typical in oscilloscope applications. In the same vein of being geared more towards oscilloscope applications, the Zmod Digitizer also has a Low Pass Filter in the analog signal chain with a cutoff frequency of 60MHz.
The Zmod SDR does not have this LPF so that higher input frequencies can be read in without needing to have been mixed down to a lower frequency prior. Finally, the other key difference to note from the Zmod Digitizer, is that the Zmod SDR is AC coupled instead of DC coupled in order to block unwanted DC components of an input RF signal.
When the Eclypse Z7 FPGA board is equipped with a Zmod SDR in one of its Zmod slots and a Zmod AWG in the other, it becomes a full SDR development platform.
As far as how this Zmod SDR setup on the Eclypse Z7 compares to the rest of the SDR market at the moment, it is the most similar to the Red Pitaya in that it consists of an FPGA driving ADC and DAC chips outputting straight to AC-coupled SMA connectors.
There is no on-board IQ mod/demod chip like there is with the RTL-SDR, or like in the case of the B205mini and Adalm Pluto where they use a transceiver chip (AD9364) with the IQ mod/demod built into it. This makes the Zmod SDR/Eclypse a bit more flexible from a hardware perspective because the specific IQ mod/demod chip can be swapped during development.
To get a quick overview of how the Zmod SDR/Zmod AWG/Eclypse (highlighted in yellow) fits into the current market, I threw together the chart above. The SDR Zmod edges out the Red Pitaya a bit with its increased tunable frequency range and bandwidth on the receive side.
I didn't include the max IQ data rate for the Red Pitaya because it is somewhat dependent on the supporting software design and there are quite a few out there with varying numbers. I'm sure the maximum IQ data rate of the SDR Zmod could be higher, but I'll need to spend some more time with it. And since there is only one example software design available for it currently, I'm just including the max IQ data rate of it.
The aforementioned software design for the Zmod SDR/Zmod AWG/Eclypse hardware setup is a custom Alpine Linux image equipped with TCP server applications that handle streaming raw IQ samples to/from host PC software such as GNU Radio, HDSDR, and SDR#. I'm going to be using GNU Radio here since I'm running on a Linux host PC.
The TCP server applications are running on the ARM-core processor of the Eclypse Z7's Zynq-7000 SoC FPGA. Then the bitstream in the programmable logic handles processing the samples from the ADC on the Zmod SDR and DAC on the Zmod AWG. This includes functions such as coverting the ADC/DAC samples into complex format (IQ data) and performing digital down-conversion/digital up-conversion.
Hardware SetupTo get started initially with Zmod SDR on Eclypse Z7, I wanted to test the receive and transmit functionalities on each their own as well as together as a system. So I pulled out a scope and antenna for my test setup as well as the SMA cable for the loopback system testing.
At the moment the example software design expects the SDR and AWG Zmods to be in specific slots on the Eclypse board. Install the Zmod SDR on Zmod Port A of the Eclypse, and the Zmod AWG on Zmod Port B. This is to match the pinout in the sdr_transceiver software design from the supporting repository (will explain in later sections).
Connect the PROG USB port of Eclypse to the host PC to have an interface to the Alpine serial terminal. Then connect the Eclypse's Ethernet port to the same router and the host PC to get the network connection for the TCP application. I tried setting up a direct network connection to my host PC using Internet Sharing like I've done with my Raspberry Pi, but I haven't been able to get that working yet.
For the RF outputs, I connected channel 1 of the Zmod SDR to channel 1 of the Zmod AWG for radio loopback testing.
Channel 2 of the Zmod SDR is connected to my adjustable dipole antenna for testing measuring signals in my environment (mainly picking up local radio stations), and channel 2 of the Zmod AWG is connected to one of my USB oscilloscopes (the ADP2230) to test its output signal.
Software Setup on Host PCThe Alpine Linux image for the Eclypse/Zmod SDR setup is contains drivers for GNU Radio, HDSDR, and SDR#. Like I mentioned, I'm using GNU Radio since I'm using an Ubuntu host PC (specifically Ubuntu 22.04, but the steps below have also been tested on Ubuntu 23.10).
Install GNU Radio if it's not already installed:
~$ sudo apt-get install gnuradio
Then clone Pavel's repo containing the example design for the Eclypse Z7 with Zmods:
~$ git clone https://github.com/pavel-demin/eclypse-z7-notes
Once cloned, change directories into the desired example application. Pavel created examples for both HPSDR and GNU Radio in his repo, the example project in his repo that includes the out-of-tree blocks for the Eclypse Z7 is sdr_transceiver:
~$ cd ./eclypse-z7-notes/projects/sdr_transceiver/gnuradio
Before launching GNU Radio, set the environment variable to specify the location of the out-of-tree blocks for the Eclypse Z7 (which is the current directory at the moment, but you could reference them from elsewhere - just specify that path instead in the command below):
~/zmod_sdr/eclypse-z7-notes/projects/sdr_transceiver/gnuradio$ export GRC_BLOCKS_PATH=.
Then launch GNU Radio and open Pavel's basic FM receiver flowgraph from the GNU Radio GUI or open the flowgraph with the launch of GNU Radio (this is the flowgraph I'll be using for my base testing of the Zmod SDR receive functionality):
~/zmod_sdr/eclypse-z7-notes/projects/sdr_transceiver/gnuradio$ gnuradio-companion fm.grc
Before running the flowgraph in GNU Radio on the host PC, the TCP server application to stream the raw IQ data samples to/from the Zmod SDR needs to be running on the Eclypse Z7.
After booting up the Eclypse with the Alpine image, log in with the username/password of root/changeme (instructions will be displayed of how to change the user password).
Once logged in, verify the local IP address assigned to the Eclypse using a command like ifconfig
(this IP address is what will be specified in the GNU Radio Source/Sink blocks for the Eclypse Z7):
sdr-034729:~# ifconfig
Change directories into the apps directory and the target application that matches the design of the flowgraph on the host.
sdr-034729:~# cd ./apps/sdr_transceiver
sdr-034729:/media/mmcblk0p1/apps/sdr_transceiver# ./start.sh
Again, in my case I am using the sdr_transceiver application that supports both receiver and transmit functionality with the Zmod SDR on Port A and Zmod AWG on port B respectively of the Eclypse Z7.
FM ReceiverAfter getting the TCP server applicaiton running on the Eclypse, we can return to GNU Radio on the host PC. Starting with the example FM receiver flowgraph from Pavel's repo that was opened in the previous step to test the receive functionality (ie - the Zmod SDR hardware itself).
At the time of writing, the latest version of GNU Radio that I am using is version 3.10 and in version 3.8 of GNU Radio all of the reference names of "firdes" were supposed to be removed but some still linger. So when I first opened the FM receiver flowgraph, I got the error Value "firdes.WIN_HAMMING" cannot be evaluated
for the Low Pass Filter block.
This is a super easy fix: just update the name "firdes" to "window" so that firdes.WIN_HAMMING
is window.WIN_HAMMING
in the LPF.
With the flowgraph free of errors, I then took a look at the Eclypse Z7 Source block:
Address: The local IP assigned to the Eclypse on your LAN.
Port: Refers to which channel of the SDR Zmod to receive samples from. Passing values 1001 sets the Eclypse Z7 Source block to receive from SDR Zmod channel 1 and 1002 sets the Eclypse Z7 Source block to receive from SDR Zmod channel 2.
Center Frequency: This is the frequency of the signal coming into the SMA port of the Zmod SDR.
Sample Rate: Sample rate to sample the signal coming into the SMA port of the Zmod SDR.
Freq. Correction ppm: The amount of correction to frequency measurement of the signal coming into the SMA port of the Zmod SDR.
The example FM receiver flowgraph is very barebones with it being centered around the WBFM Receive block and just enough signal processing to downsample the received signal to 48kHz to send into an Audio Sink to output to the host PC's speakers.
So to test, I changed the port in Eclypse Z7 Source to 1002 for channel 2 of the Zmod SDR where I had my dipole antenna connected, and ran the FM receiver flowgraph.
Since the flowgraph has the center frequency set such that it can be adjusted during runtime, I played around setting it to what my local radio station frequencies would be at.
Since there the bare minimum in terms of signal processing, the radio station is covered by quite a bit of static and the songs could not be clearly heard, but it can still be seen as the yellow line in the waterfall graph above.
Testing Out TransmittingWith the receive side of the Eclypse Z7 SDR system tested, I wanted to test the transmit side through the Zmod AWG. My regular method for testing a transmitter for the first time is to have it output a single frequency, referred to as a continuous wave (CW) tone. This lets me verify basic parameters of a transmitter such as center frequency offset, output power, and spurious emissions before attempting to have it output a modulated signal carrying data.
Setting up a flowgraph in GNU Radio for a transmitter to output a CW tone is supper easy. Simply add the Sink block for the target transmitter and connect it to a Constant Source block with the output value set to 1.
I also added a Frequency Sink block for confirmation of the signal being output from GNU Radio.
The Address, Port, Center Frequency, Sample Rate, and Freq. Correction ppm variables are the same as in the Eclypse Z7 Source block, with the Push to Talk variable is the only addition. I found that Push to Talk has two possible setting of 0 or 1, where 1 to enables the RF output from the AWG Zmod and 0 disables it.
While I personally would have labelled this variable "RF Enable" or "Output Enable", I think it's a really handy feature to have control of enabling/disabling the output of the transmitter during runtime. The most straightforward use case of this would be that a button/switch can be placed in the GUI of the flowgraph for the user to toggle while the flowgraph is running.
Like I mentioned in my hardware setup section, channel 2 of the Zmod AWG is connection to a scope channel of my ADP2230 to view the output on spectrum analyzer in WaveForms. This is how I validated that what GNU Radio said the Zmod AWG was outputting was actually being output.
This is how I found that the Push to Talk option needed to be set to 1 before the RF output from the Zmod AWG was actually enabled.
I tested setting the Zmod AWG to output CW tones at a few different center frequencies.
One of the first things I was curious about was what the RF output power of the Zmod AWG was at default settings. So I added a marker at the peak of the measured CW tone on the ADP2230 and found the output power to be 4 dBm:
There were a few spurs and harmonics, but I would expect that at this stage of the RF chain (which is basically coming straight out of the DAC chip) as well as the lack of any DSP in the software (I'm just blasting straight energy out essentially).
FM Audio TransceiverWith the receive and transmit chains of the Eclypse SDR system verified independently, the final step in this "getting started" process is to test the system as a whole.
Because there are a lot of rules for transmitting signals over the air, I personally like to stick to a hardwire for initial testing and prove-in of designs. Thus why I have an SMA cable connecting channel 1 of the Zmod AWG back to channel 1 of the Zmod SDR:
In my recent tutorial explaining the use cases of matched filters in SDR on the Ettus B205mini, I created a loopback design for transmitting audio pulled from my host PC's microphone, transmitting it with FM modulation using the WBFM Transmit block, then receiving/demodulating it with the corresponding WBFM Receive block.
I really like this design as a template to get to know new SDR hardware since the quality of the audio heard on the receive side makes DSP issues in the design readily apparent.
Also depending on the specs of the hardware it's implemented on, the signal processing chain must be modified to match its capabilities in terms of properties such as sample rate.
If you recall my comparison chart from the first section, the B205mini has a max sample rate of 64 Msps with a max IQ data rate of 122.88 Msps. The Zmod SDR in contrast has a max sample rate of 122.88 Msps with a max IQ data rate of 1.536 Msps for this version of its Alpine Linux image.
This means the first element of the flowgraph that needed to be changed was the sample rate, which then causes a chain reaction of changes needed to the interpolation/decimation factors of the data as it passes through the flowgraph to ultimately match the sample rate of the Audio Source/Sink blocks of 48 kHz.
According to Pavel's repo docs, the I/Q data rate is configurable to five available options: 24 ksps, 48 ksps, 96 ksps, 192 ksps, 384 ksps, 768 ksps and 1.536 Msps. I usually like to oversample my data at the source because I've found you usually maintain better single integrity by taking data out (decimating) vs adding it back in (interpolating) so I initially opted to use the 1.536 Msps sample rate for the Eclypse SDR.
I was proven wrong this time however because there is a bottleneck in the system with how many samples can be streamed across the TCP server at once back to the GNU Radio flowgraph for processing. So setting the sample rate to 1.536 Msps resulted in garbled audio coming out from the receive side, along with the constant aUaUaU output in the console of GNU Radio indicating underrun errors. The underrun error indicated GNU Radio wasn't getting enough data in to supply the sound system with the samples it needs for continuous playback in time.
I had been using a 1 Msps sample rate with the B205mini and while I would occasionally get an underrun error, the audio was clear. So that's what lead me to believe the bottleneck was in the TCP server. But I need to try different designs (ie not audio) to be certain.
Overall, I backed the sample rate down to 384 ksps with a quadrature rate of 192 ksps and symbol rate of 96 ksps.
So in the TX chain, I only needed to interpolate the signal by a total factor of 4:
And in the RX chain, I only needed to decimate the signal by a total factor of 6:
And this gave me good clean audio on the loopback test. Which I accomplished without feedback by using my noise-cancelling headphones as the speaker and microphone source.
While reading through the docs of Pavel's repo, I noticed there were instructions for building the bitstream and SD card files for the Alpine Linux image from source. I immediately assumed that this would probably create the Vivado project for the bitstream of the Eclypse somewhere which interests me to two reasons:
1 - Making changes to either retarget a different FPGA development board with Zmod ports, change both ports to be transmit or receive, update it to a later version of Vivado etc.
2 - See the detail of how the complex signal processing was implemented in HDL which I always think is helpful.
So starting by sourcing the Vitis tools to the environment (I opted to stick with the version Pavel originally built the design in - 2023.1, but I will update it soon):
~/zmod_sdr/eclypse-z7-notes$ source /tools/Xilinx/Vitis/2023.1/settings64.sh
Then run the makefile with specified project name to build bitstream for:
~/zmod_sdr/eclypse-z7-notes$ make NAME=sdr_transceiver bit
This creates a tmp
directory in the top level of the cloned repository directory where the Vivado project can be found:
Just keep in mind that every time the makefile is run for that project, it will over-write the Vivado project in this directory. So move the Vivado project if any changes are made that you want to keep.
Opening the Vivado project shows how Pavel implemented the block diagram of his design that he posted in his docs:
I personally find it the most interesting to see how the AXI bus is routed to handle bus width changes and different bits needed to be routed else where that have differing functionalities.
Then to load the new bitstream onto the FPGA from the Alpine Linux image, place the file in the /dev/xdevcfg
directory:
sdr-034729:~# cat sdr_transceiver.bit > /dev/xdevcfg
A command like scp
can be used to transfer the bitstream file from the host PC to Alpine running on the Eclypse.
It's also worth noting that the makefile can also be ran to target the other processor in the Zynq (ps7_cortexa9_0
or ps7_cortexa9_1
) or a different FPGA part (default is the FPGA on the Eclypse board - xc7z020clg484-1
).
~/zmod_sdr/eclypse-z7-notes$ make NAME=sdr_transceiver PART=xc7z020clg484-1 PROC=ps7_cortexa9_0
Just keep in mind that changing these parameters may result in required changes like swapping out the constraints files for the Zmod ports in /eclypse-z7-notes/cfg
if targeting a different FPGA part.
This most likely will also require components of Alpine to be rebuilt such as the device tree, boot binary, server applications, etc. so for major changes like this, it's best to rebuild the entire Alpine Linux image.
Build Alpine Image for SD Card from SourceLooking at the makefile in Pavel's repo, it can be seen how to rebuild components for Alpine Linux image, as well as how to rebuild the whole image. He also provides the commands in his docs:
~/zmod_sdr/eclypse-z7-notes$ source helpers/build-all.sh
In the eclypse-z7-notes
directory, the source files for components such as the TCP server application (./projects/sdr_transceiver/server
), custom device tree (./dts
), and various HDL files (./cores
and ./modules
) are local on the host and customizations can be applied to them as desired before running the makefile to rebuild everything.
The actual Linux kernel, device tree source, Alpine root filesystem source are pulled from their respective repos by the makefile when building. So if a different kernel, device tree, Alpine, Vivado version is desired, the makefile needs to be updated accordingly.
For example, when I come back to update to a newer version of Vivado/Vitis the DTREE_TAG on line 20 needs to be updated to the corresponding version I choose such as 2024.1.
Once, the full image is rebuilt the zip file containing the files to copy to the SD card for the FPGA will appear in the top level of the eclypse-z7-notes
directory:
The eclypse-z7-notes
is super valuable for this setup and makes it very straightforward for expanding the functionality of the Eclypse SDR setup so I'm excited to spend some more time on it!
Comments