IPv6 problems on TP-Link Archer C20

26.04.2017 12:44

Recently I replaced an old 2.4 GHz-only Linksys WRT54GL wireless router with a shiny new, dual band TP-Link Archer C20 (hardware version V1). Unfortunately, the new router brought some unusual problems. It turns out some devices are now unable to get a global IPv6 address when connected over Wi-Fi. For example, my Android 5.1 smartphone and my work laptop with Debian Jessie and Network Manager don't get IPv6 connectivity. They worked just fine when connected through the old router. At the same time, a different phone with Android 6.0 seems to have no problems with the new Archer C20 router.

First a brief note on the network setup: Archer C20 is used here as a wireless access point only. Some other host on the network acts as a gateway to the Internet. That host also provides a DHCP service for IPv4 and runs the route advertisement daemon (radvd) for IPv6 SLAAC. The setup has been quite well tested and works flawlessly on the wired Ethernet. The old WRT54GL has also been used in this way, which is why IPv6 connectivity on the Wi-Fi worked fine even though the old router's firmware had no explicit IPv6 support.

As the TP-Link FAQ entry explains, the WAN port on the C20 is unused, the network is connected to one of the LAN ports and the DHCP server on the C20 is disabled. IPv6 status tab in the configuration interface shows the following:

IPv6 status tab in Archer C20 configuration interface.

The IPv6 problem is somewhat frustrating to diagnose, since it only appears some time after the router has been restarted. For instance, I've usually seen that IPv6 stops working the next day after a reboot. Similarly, changing some unrelated settings, like the wireless SSID, also appears to temporarily fix the issue, only for it to reappear after a while.

Searching the web I can find some discussions about similar problems with TP-Link routers, with no clear conclusion. The firmware changelog does say in a vague way that the latest version fixes an IPv6 problem. However, I've tried the V1_160427 and V1_151120 firmwares and they both behave in the same (broken) way.

Modifications in Archer C20 firmware.

After much head scratching I found out that the base cause why my laptop does not get an IPv6 address over Wi-Fi is IPv6 duplicate address detection. This is apparent from the dadfailed flag on the link local address:

$ ip addr show dev wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether a0:88:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.xx.xx/24 brd 192.168.xx.255 scope global dynamic wlan0
       valid_lft 484sec preferred_lft 484sec
    inet6 fe80::a288:xxxx:xxxx:xxxx/64 scope link tentative dadfailed
       valid_lft forever preferred_lft forever

Also, when you know what to look for, this error appears in the logs:

$ dmesg|grep duplicate
IPv6: wlan0: IPv6 duplicate address fe80::a288:xxxx:xxxx:xxxx detected!

So it seems that my laptop thinks that there is another device on the network with the same link-local (and hence Ethernet MAC) address. This is of course not true. In fact, if I disable the duplicate address detection, IPv6 starts working properly:

# sysctl net.ipv6.conf.wlan0.accept_dad=0

Investigating things a bit further, Wireshark shows the following curious packet capture immediately after the laptop connects to the wireless network:

Packet capture during IPv6 neighbor solicitation.

This appears to be the progress of a normal attempt at a IPv6 autoconfiguration from the laptop's side. The laptop (with the MAC address a0:88:...) sends some packets to a IPv6 multicast address (33:33:...). However, all these packets seem to be immediately reflected back to the laptop by Archer C20. The incoming packets highlighted in yellow are byte-by-byte identical to the preceding outgoing packets, with only the destination address in the Ethernet header changed from the multicast to the laptop's MAC address. These incoming packets are not present when the laptop is connected to one of the wired LAN ports, or when using the old wireless router.

These reflected packets trigger the duplicate address detection in the laptop's network stack and the autoconfiguration is interrupted. It seems that at some point in the Archer C20 uptime, IPv6 multicast groups stop working correctly. In fact I don't understand why it even tries to do anything special with those. WRT54GL had no concept of IPv6 and it worked fine. I've experimented with other options that looked related to multicast (like IGMP settings), but with no success. So unfortunately at the moment I don't have a good network-side solution. Any suggestions would be most welcome. Changing the stock firmware might work, but support in OpenWRT for this hardware currently seems experimental at best.

The device-side work-around is to disable DAD like I show above, but this is somewhat ugly. There might be a way to disable it on a per-network basis with Network Manager (see dad-timeout), but I have not tried this yet. It is also still not clear why some devices appear to work. It might be that Android simply disabled duplicate address detection in 6.0.

Posted by Tomaž | Categories: Code | Comments »

Phase noise in microcontroller ADCs

17.04.2017 19:44

In the past few years I designed a series of small VHF/UHF receivers. They are all based on TV tuner chips from NXP semiconductors and the STM32 series of Cortex-M3 microcontrollers. The receivers were originally intended for experiments with TV whitespaces, such as detecting the presence of wireless microphones. However, European projects come and go, and so recently my work at the Institute has shifted towards ultra-narrowband technology. I keep using my old hardware though. Partly because it is convenient and partly because it's interesting to find where its limitations are.

With ultra-narrowband, phase noise is often the defining characteristic of a system. Phase noise of a receiver is a measure of the short-term stability of its frequency reference. One of its effects is blooming of narrowband signals in the frequency domain. A common way to specify phase noise is in decibels relative to the carrier (dBc), at 1 Hz equivalent bandwidth at a certain offset from the carrier. This slide deck from Agilent nicely explains the concept.

Not surprisingly, my design has quite a lot of phase noise. This was not a concern when receiving wide band FM microphone signals. However, it turns out that it's not the RF part that is the culprit. Most of the phase noise in the system comes from the analog-to-digital converter in the ARM microcontroller that I use to sample the baseband signal. I investigated this using the same setup I used for my ADC undersampling measurement - in the following measurements, no RF circuits were involved.

This is how the spectrum of a 500 kHz CW signal looks like after being sampled at 2 Msample/s (using the interleaved dual mode of the ADC). The spectrum is calculated using FFT from 2048 samples. Ideally, there should only be a narrow spike representing one frequency component, however the phase noise causes it to smear into a broad peak:

Measured spectrum of a CW signal.

From this, I drew the phase noise plot. This shows half of the dual sideband power, calculated at 1 Hz equivalent bandwidth and relative to the total signal power:

Measured phase noise of the ADC.

At 10 kHz offset, this gives:

\mathcal{L}_{ADC}(10\mathrm{kHz}) = -77 \mathrm{dBc @ 1 Hz}

On the other hand, typical phase noise from the datasheet of the tuner chip I'm using is:

\mathcal{L}_{tuner}(10\mathrm{kHz}) = -93 \mathrm{dBc @ 1 Hz}

For comparison, the National Instruments USRP N210, another device I use daily, is only 3 dB better at 10 kHz (according to this knowledge base page):

\mathcal{L}_{USRP}(10\mathrm{kHz}) = -80 \mathrm{dBc @ 1 Hz}

Proper lab equipment of course is significantly better. The Rohde & Schwarz SMBV signal generator I used in the measurement only has -148 dBc of phase noise specified at 20 kHz offset.

What causes this phase noise? The ADC in the microcontroller is driven by the system clock. The accuracy of this clock determines the accuracy of the signal sampling and in turn the phase noise in the digital signal on the output of the ADC. In my case, the system clock is derived from the high speed internal (HSI) oscillator using the integrated PLL. The datasheet doesn't say anything about the oscillator, but it does say that the PLL cycle-to-cycle jitter is at most 300 ps.

Using a Monte Carlo simulation, I simulated the phase noise of a system where signal sampling has a random ±150 ps jitter with a uniform distribution. The results nicely fit the measurement. The shaded area below shows the range of 𝓛(f) observed in 5000 runs:

Simulated phase noise compared to measurement.

So it seems that the PLL is responsible for most of the phase noise. Unfortunately, it appears that I can't avoid using it. There is no way to run the integrated ADC from a separate external clock. I could run the whole system from a low-jitter high-speed external (HSE) clock without the PLL, however HSE is limited to 25 MHz. This is quite low compared to my current system clock of 56 MHz and would only be feasible for significantly lower sample rates (which would require different analog anti-aliasing filters). External ADC triggering also wouldn't help here since even with an external trigger, the sample-and-hold circuit appears to be still driven by the ADC clock.

For some further reading on the topic, I recommend Effect of Clock Jitter on High Speed ADCs design note from Linear, which talks about phase noise from the perspective of serious ADCs, and Phase Locked Loop section in STMicroelectronics AN2352.

Posted by Tomaž | Categories: Analog | Comments »

ESP8266 humidity monitoring

27.02.2017 20:11

Last year my flat developed a bit of a mold problem, or maybe I just found out about it then. It's possible the fungus already lived a long, fulfilling life before being discovered. It wouldn't be surprising for a building from an era when thermal- and hydro-isolation were pretty far down on the priority list. In any case, it made me want to monitor the relative air humidity and dew point levels a bit more closely. I had the apartment pretty well covered with sensors already, but the room with the mold in particular lacked a hygrometer.

Wireless humidity monitor based on the ESP8266 module.

Not to re-invent too much hot water, I more or less replicated the nicely documented temperature and humidity web server project from Adafruit. It was doubly appealing because I still had a full bag of old ESP8266 modules that I bought for pennies back when they were the exciting new thing. The only problem was the fact that the humidity sensors supported out-of-the-box by that project were only available from their shop, which is relatively expensive for small items with oversea shipping. Since I was in a hurry, I bought a few DHT11 modules anyway (which turned out to be a mistake).

There's not much to say about the hardware. It's the minimalistic Adafruit's circuit soldered on a perforated board. For the power supply I used a small 3.3V switch-mode converter module I had left over from another project. I was nicely surprised by how easy ESP8266 support was to install into the Arduino IDE. Another pleasant discovery was that ESP8266 with the Arduino-based firmware seems to consume much less power than with the stock AT-command firmware.

The Arduino IDE got updated since Adafruit's tutorial was written, so I had to experiment a bit with the firmware upload settings. Following values seemed to work with my particular modules. Another thing I discovered was that the RST line on ESP8266 has to be left floating for the firmware upload to work reliably. On my previous ESP8266 project I tied it to VCC.

Arduino firmware upload settings for ESP8266 modules.

Unfortunately, the DHT11 modules are pretty bad as far as accuracy is concerned. I only discovered Robert's wonderfully in-depth comparison of hygrometer modules after the fact. I played a bit with power supply filtering, but that doesn't seem to be the source of the noise in the data. I ended up modifying Adafruit's firmware so that it reads the sensor every 5 seconds and returns the average of last 8 readings. This alleviates somewhat the problem, but I definitely recommend using some other sensor to anyone wanting to build this.

For comparison, here is the daily humidity graph recorded using DHT11 with averaging:

DHT11 example daily humidity record.

And here is humidity recorded at the same time (albeit in a different room) by a TEMPerHUM USB dongle with no extra averaging applied:

TEMPerHUM example daily humidity record.

After several months of running, the Arduino-based ESP8266 turned out to be pretty reliable. I haven't seen any big outages in the log of sensor readings. This is a nice improvement over the stock firmware that I used in my Munin display, which still regularly gets lost to the point that it requires a power cycle.

Posted by Tomaž | Categories: Digital | Comments »

GIMP onion layers plug-in

21.02.2017 20:48

Some time ago I was playing with animation making applications on a (non-pro) iPad. I found the whole ecosystem very closed and I had to jump through some hoops to get my drawings back onto a Linux computer. However the fact that you can draw directly on the screen does make some things easier compared to a standalone Wacom tablet, even if the accuracy is significantly worse.

One other thing in particular stood out compared to my old GIMP setup. These applications make it very easy to jump frame by frame through the animation. In one touch you can display the next frame and do some quick edits and then move back with another touch. You can browse up and down the stack as a quick way to preview the animation. They also do something they call onion layering which simply means that they overlay the next and previous frames with reduced opacity so that it's easier to see how things are moving around.

This is all obviously useful. I was doing similar things in GIMP, except that changing frames there took some more effort. GIMP as such doesn't have a concept of frames. Instead you use image layers (or layer groups) as frames. You have to click to select a layer and then a few more clicks to adjust the visibility and opacity for neighboring layers if you want to have the onion layer effect. This quickly amounts to a lot of clicking around if you work on more than a handful of frames.

GIMP does offer a Python plug-in interface however, so automating quick frame jumps is relatively simple. Relatively, because GIMP Python Documentation turns out to be somewhat rudimentary if you're not already familiar with GIMP internals. I found it best to learn from the Python-Fu samples and explore the interface using the built-in interactive console.

Screenshot of the GIMP onion layers plug-in

The end result of this exercise was the GIMP onion layers plug-in, which you can now find on GitHub together with installation and usage instructions. The plug-in doesn't have much in terms of an user interface - it merely registers a handful of python-fu-onion- actions for stepping to previous or next frame, with or without the onion layer effect. The idea is that you then assign keyboard (or tablet button) shortcuts to these actions. You will have to define the shortcuts yourself though, since the plug-in can't define them for you. I like to use dot and comma keys since they don't conflict with other GIMP shortcuts and match the typical frame step buttons on video players.

If you follow the layer structure suggested by the Export layers plug-in, this all works quite nicely, including handling of background layers. The only real problem I encountered was the fact that the layer visibility and opacity operations clutter the undo history. Unfortunately, that seems to be the limitation of the plug-in API. Other plug-ins work around this by doing operations on a duplicate of the image, but obviously I can't do that here.

I should note that I was using GIMP 2.8.14 from Debian Jessie, so the code might be somewhat outdated compared to latest GIMP 2.8.20. Feedback in that regard is welcome, as always.

Posted by Tomaž | Categories: Code | Comments »

Python applications in a .zip

08.02.2017 10:20

Poking around youtube-dl I found this interesting recipe on how to package a self-contained Python application. Youtube-dl ships as a single executable file you can run immediately, or put somewhere into your PATH. This makes it very convenient to use even when you don't want to do the usual pip install dance. Of course, it comes at the cost of not resolving any dependencies for you.

I was expecting the file to be a huge, monolithic Python source file, but in fact it's a ZIP with a prepended hash-bang and nicely structured Python package inside. Simplified a bit, here is the gist of the Makefile part that builds it:

hello:
	cd src && zip ../hello hello/*.py __main__.py
	echo '#!/usr/bin/python' > hello
	cat hello.zip >> hello
	rm hello.zip
	chmod a+x hello

Now, if src/__main__.py contains:

import hello
hello.greet()

And src/hello/__init__.py contains:

def greet():
	print("Hello, World!")

Building the executable and running hello from the command-line should result in the standard greeting:

$ make
cd src && zip ../hello hello/*.py __main__.py
  adding: hello/__init__.py (stored 0%)
  adding: __main__.py (stored 0%)
echo '#!/usr/bin/python' > hello
cat hello.zip >> hello
rm hello.zip
chmod a+x hello
$ ./hello
Hello, World!

How does this work? Apparently it's quite an old trick with some added refinement. Already since version 2.3 Python knows how to import modules directly from ZIP files in the same way as from the usual directories. Python also allows executing modules from the command-line.

It sounds very much like Java JARs, doesn't it? The only missing part is the #!... line that makes the Linux kernel use the Python interpreter when executing the file. Since ZIP format ignores any junk that precedes the compressed data, the line can simply be prepended as if the whole file was a simple Bash script.

Posted by Tomaž | Categories: Code | Comments »

Jahresrückblick

29.01.2017 18:56

So this has been 2016. Another year that went by all too fast. It has made the world a bit more broken and a whole lot more selfish and incomprehensible.

I haven't traveled much. Except for one project meeting I've hardly left the country. In part because other colleagues took the burden of attending meetings where the Institute had to have a presence. The other part must have been the effect of attacks around Europe and the newly erected borders and barbed wires. I haven't been to any foreign conference, I've skipped 33C3 and I had to cancel my visit to GalaCon at the last moment.

On the other hand, it feels like the local tech meetups have mostly devolved into TED-style talks. I miss the old grassroots events where people would discuss technologies they found interesting or fascinating projects that grew in their basements. It seems the only valid reason to be excited about something these days is if you want to be hired or want to hire someone.

Ljubljana

Last year more than before I found myself in situations where people were willing to talk collaboration up to the point where they got what they wanted - and then walked away without as much as a thank you. The charge more mantra is now being taught to every STEM student as a solution to this, and I find it increasingly depressing. Must you really state an hourly rate before even saying hello?

Social events now have codes of conduct, but seem more hostile than ever. Then again, maybe that tells more about myself than those events. Sometimes I feel like I don't understand people and these communities anymore.

All this obviously affected my motivation to work on projects in my free time. Existing Free software I maintain has mostly been on life support last year. Some things I would usually took the effort to clean and publish as open source were left on my disk. I've done very little electronics work outside of my duties at the Institute. In general I stepped away a lot from the usual technical stuff. I rather spent evenings reading, and at a drawing class in the National Gallery.

All we are

I'm now in my 6th year employed as a research assistant at the Institute. My project work last year has been mostly related to ultra-narrowband technology. I have 26 publications listed in the national bibliographic database and political games in academia still manage to catch me completely by surprise. With the start of the new academic year I've made a decision to finish my PhD and set a deadline to wrap things up by October.

Most of my time after that have been dedicated to concluding my research work, and writing journal papers. My doctoral topic application has been accepted, but I'm still short of the publication quota. A paper I've been trying to publish since April 2014 has since then accumulated more than 200 commits to the LaTeX source and is currently under yet another peer review.

I don't want to make any big plans for 2017. I have plenty of ideas for interesting projects and a backlog of (non-academic) things I would like to write about. However, given how much work I still have ahead of me before my viva voce, I doubt much of that will happen this year.

Posted by Tomaž | Categories: Life | Comments »

Moving Dovecot indexes and control files

23.12.2016 22:06

Dovecot IMAP server can use a standard Maildir for storage of messages inside user's home directories. The default in that case is to store search indexes and control files in the same directory structure, alongside mail files. That can be convenient, since no special setup is needed and everything is stored in the same place.

However, this doesn't work very well if you have disk quotas enabled on the filesystem that stores Maildirs. In case a user reaches their quota, Dovecot will not be able to write to its own files, which can lead to problems. Hence, documentation recommends that you configure a separate location for Dovecot's files in that case. This is done with INDEX and CONTROL options to the mail_location specification.

For example, after setting up appropriate directory structure and permissions under /var/lib/dovecot:

mail_location = maildir:%h/Maildir:INDEX=/var/lib/dovecot/index/%u:CONTROL=/var/lib/dovecot/control/%u

You can just set this up and leave old index and control files in place. In that case, Dovecot will automatically regenerate them. However, this is not ideal. It can take significant time to regenerate indexes if you have a lot of mail. You also lose some IMAP-related metadata, like message flags and unique IDs, which will confuse IMAP clients. It would be better to move existing files to the new location, however the documentation doesn't say how to do that.

I found that the following script works with Dovecot 2.2.13 on Debian Jessie. As always, be careful when dealing with other people's mail and double check that the script does what you want. I had my share of problems when coming up with this. Make backups.

#!/bin/bash

set -ue

# Run as "migrate_dovecot.sh user path-to-users-maildir" for each user.

# Make sure that Dovecot isn't running or that this specific IMAP user isn't
# connected (and can't connect) while this script runs!
USERNAME=$1
MAILDIR=$2

DOVECOTDIR=/var/lib/dovecot

# Correct after double-checking that this script does what you want.
MV="echo mv -i"

cd $MAILDIR

# Index files like dovecot.index, dovecot.index.cache, etc. go under the 
# INDEX directory. The directory structure should be preserved. For example,
# ~/Maildir/.Foo/dovecot.index should go to index/.Foo/dovecot.index.

# Exception are index files in the root of Maildir. Those should go under 
# .INBOX
b=$DOVECOTDIR/index/$USERNAME/.INBOX
mkdir -p "$b"
$MV *index* "$b"

find . -name "*index*"|while read a; do
	b=$DOVECOTDIR/index/$USERNAME/`dirname "$a"`
	mkdir -p "$b"
	$MV "$a" "$b"
done

# dovecot-uidlist and dovecot-keywords files should go under CONTROL, in a
# similar way to indexes. There is the same exception for .INBOX.
b=$DOVECOTDIR/control/$USERNAME/.INBOX
mkdir -p "$b"
$MV dovecot-uidlist dovecot-keywords "$b"

find . -name "*dovecot*"|while read a; do
	b=$DOVECOTDIR/control/$USERNAME/`dirname "$a"`
	mkdir -p "$b"
	$MV "$a" "$b"
done

# subscriptions file should go to the root of the control directory.

# Note that commands above also move some dovecot-* files into the root of
# the control directory. This seems to be fine.
$MV "subscriptions" "$DOVECOTDIR/control/$USERNAME"
Posted by Tomaž | Categories: Code | Comments »

About the Wire loop probe

15.12.2016 21:08

Recently I was writing about how my father and I were checking a HiFiBerry board for a source of Wi-Fi interference. For want of better equipment we used a crude near-field probe that consisted of a loop of stripped coaxial cable and a trimmer capacitor. We attempted to tune this probe to around 2.4 GHz using the trimmer to get more sensitivity. However we didn't see any effect of capacitance changes on the response in that band.

The probe was made very much by gut feeling, so it wasn't that surprising that it didn't work as expected. We got some interesting results nonetheless. Still, I thought I might do some follow-up calculations to see how far off we were in our estimates of the resonance frequency.

Our probe looked approximately like the following schematic (photograph). The loop diameter was around 25 mm and the wire diameter was around 1 mm. Trimmer capacitor was around 10 pF:

Wire loop at the end of a coaxial cable.

Inductance of a single, circular loop of wire in air is:

L = \mu_0 \frac{D}{2} \left( \ln \frac{8D}{d} - 2 \right) \approx 50 \mathrm{nH}

The wire loop and the capacitor form a series LC circuit. If we ignore the effect of the coaxial cable connection, the resonant frequency of this circuit is:

f = \frac{1}{2 \pi \sqrt{LC}} \approx 200 \mathrm{MHz}

So it appears that we were off by an order of magnitude. In fact, this result is close to the low frequency peak we saw on the spectrum analyzer at around 360 MHz:

Emissions from the HiFiBerry board from DC to 5 GHz.

Working backwards from the equations above, we would need capacitance below 1 pF or loop diameter on the order of millimeters to get resonance at 2.4 GHz. These are very small values. Below 1 pF, stray capacitance of the loop itself would start to become significant and a millimeter-sized loop seems too small to be approximated with lumped elements.

Posted by Tomaž | Categories: Analog | Comments »

HiFiBerry and Wi-Fi interference

01.12.2016 11:43

HiFiBerry is a series of audio output cards designed to sit on the Raspberry Pi 40-pin GPIO connector. I've recently bought the DAC+ pro version for my father to use with a Raspberry Pi 3. He is making a custom box to use as an Internet radio and music player. I picked HiFiBerry because it seemed the simplest, with fewest things that could go wrong (the Cirrus Logic board for instance has many other features in addition to an audio output). It's also well supported out-of-the-box in various Raspberry Pi Linux distributions.

Unfortunately, my father soon found out that the internal wireless LAN adapter on the Raspberry Pi 3 stopped working when HiFiBerry was plugged in. Apparently other people have noticed that as well, as there is an open ticket about it at the Raspberry Pi fork of the Linux kernel.

Several possible causes were discussed on the thread on GitHub, from hardware issues to kernel driver bugs. From those, I found electromagnetic interference the most likely explanation - reports say that the issue isn't always there and depends on the DAC sampling rate and the Wi-Fi channel and signal strength. I thought I might help resolving the issue by offering to make a few measurements with a spectrum analyzer (also, when you have RF equipment on the desk, everything looks like EMI).

HiFiBerry board with a near-field probe over the resonators.

I don't have any near-field probes handy, so we used an ad-hoc probe made from a small wire loop on an end of a coaxial cable. We attempted to tune the loop using a trimmer capacitor to get better sensitivity around 2.4 GHz, but the capacitor didn't have any noticeable effect. We swept this loop around the surface of the HiFiBerry board as well as the Raspberry Pi 3 board underneath.

During these tests, the wireless LAN and Bluetooth interfaces on-board Raspberry Pi were disabled by blacklisting brcmfmac, brcmutil, btbcm and hci_uart kernel modules in /etc/modprobe.d. Apart from this, the Raspberry Pi was booted from an unmodified Volumio SD card image. Unfortunately we don't know what kind of ALSA device settings the Volumio music player used.

What we noticed is that the HiFiBerry board seemed to radiate a lot of RF energy all over the spectrum. The most worrying are spikes approximately 22.6 MHz apart in the 2.4 GHz band that is used by IEEE 802.11 wireless LAN. Note that the peaks on the screenshot below almost perfectly match the center frequencies of channels 1 (2.412 GHz) and 6 (2.437 GHz). The peaks continue to higher frequencies beyond the right edge of the screen and the two next ones match channels 11 and 14. This seems to approximately match the report from Hyperjett about which channels seems to be most affected.

Emissions from the HiFiBerry board in the 2.4 GHz band.

The spikes were highest when the probe was centered around the crystal resonators. This position is shown on the photograph above. This suggests that the oscillators on HiFiBerry are the source of this interference. Phil Elwell mentions some possible I2S bus harmonics, but frequencies we saw don't seem to match those.

Emissions from the HiFiBerry board down to 1 GHz.

Scanning lower frequencies shows that the highest peak is around 360 MHz, but that is likely because of the sensitivity of our probe and not due to something related to the HiFiBerry board.

Emissions from the HiFiBerry board from DC to 5 GHz.

I'm pretty sure these emissions are indeed connected with the HiFiBerry itself. With the probe on Raspberry Pi board underneath HiFiBerry, the spectrum analyzer barely registered any activity. Unfortunately, I forgot to take some measurements with a 2.4 GHz antenna to see how much of this is radiated out into the far-field. I'm guessing not much, since it doesn't seem to affect nearby wireless devices.

Related to that, another experiment points towards the fact that this is an EMI issue. If you connect a Wi-Fi dongle via a USB cable to the Raspberry Pi, it will work reliably as long as the dongle is kept away from the HiFiBerry board. However if you put it a centimeter above the HiFiBerry board, it will lose the connection to the access point.

In conclusion, everything I saw seems to suggest that this is a hardware issue. Unfortunately the design of the HiFiBerry board is not open, so it's hard to be more specific or suggest a possible solution. The obvious workaround is to use an external wireless adapter on an USB extension cable, located as far as feasible from the board.

I should stress though that the measurements we did here are limited by our probe, which was very crude, even compared to a proper home-made one. While frequencies of the peaks are surely correct, the measured amplitudes don't have much meaning. Real EMI testing is done with proper tools in a anechoic chamber, but that is somewhat out of my league at the moment.

Posted by Tomaž | Categories: Analog | Comments »

AFG-2005 noise generation bug

09.10.2016 13:49

The noise output function in the GW Instek AFG-2005 arbitrary function generator appears to have a bug. If you set up the generator to output a sine wave at 10 kHz, and then switch to noise output using the FUNC key, you get output like this:

Noise output in frequency domain.

Noise output in time domain.

The red trace shows the spectrum of the signal from the signal generator using the FFT function of the oscilloscope. The yellow trace shows the signal in the time domain.

The noise spectrum looks flat and starts to roll off somewhere beyond 10 MHz. This is what you would expect for an instrument that is supposed to have a 20 MHz DAC. However, if you set the output to a sine wave at 1 kHz before switching to noise output, the signal looks significantly different:

Noise output in frequency domain, low sampling rate.

Noise output in time domain, low sampling rate.

These two later oscilloscope screenshots have been made using the same settings as the pair above.

This is obviously an error on the part of the signal generator. The setting for the sine wave output shouldn't affect the noise output. It looks like the DAC is now only set to around 4 MHz sampling rate. Probably it has been switched to a lower sampling rate for the low-frequency sine wave output and the code forgot to switch it back for the noise function.

This behavior is perfectly reproducible. If you switch back to sine wave output, increase the frequency to 10 kHz or more and switch to noise output, the DAC sampling rate is increased again. Similarly, if you set a 100 Hz sine wave, the DAC sampling rate is set to 400 kHz. As far as I can see there is no mention of this in the manual and you cannot set the sampling rate manually. The FREQ button is disabled in Noise mode and there is no indication on the front panel about which sampling rate is currently used.

I've been writing about the AFG-2005 before. It's an useful instrument, but things like this make it absolutely necessary to always have an oscilloscope at hand to verify that the generator is actually doing what you think it should be doing.

Posted by Tomaž | Categories: Life | Comments »