HiFiBerry follow up

11.06.2017 20:59

Back in December I was writing about problems with a HiFiBerry audio interface for Raspberry Pi. The audio board was apparently emitting interference on the 2.4 GHz frequency band and made the wireless LAN connection on the Raspberry Pi unreliable. I got in contact with their support and they acknowledged that the oscillators on that version of their hardware had an EMI problem. They promised to get back when they've fixed the issue and indeed in April they offered to replace the old board free of charge or sell me a new one for half the price. I opted for the latter option, since I was curious what changes they made to the design and wanted to compare the boards side-by-side.

HiFiBerry DAC+ HW 2.2

This is the old board, marked HiFiBerry DAC+ HW 2.2. The components marked with X44 and X48 are Fox Electronics Xpresso-series hybrid oscillator modules. Each of these contains an integrated circuit and a quartz crystal resonator. Unfortunately they are unmarked and I didn't bother to measure their frequency. From their designations I'm guessing one provides the clock for the 44100 kHz sampling rate and the other for 48000 kHz. Datasheet for the PCM5122 ADC suggests that the oscillators themselves are in the 10 MHz range and the clocks are then divided down inside the ADC chip.

HiFiBerry DAC+ HW 2.6

This is the new board I got. It's marked HW 2.6. The gold hybrids have been replaced with similar looking components in black plastic packages. Xpresso-series has apparently been discontinued. The new oscillators are marked only with letters BOHXA and after a brief web search I didn't manage to find their manufacturer. The new board also omits the push-button. I'm not sure what its original function was anyway.

Here are the two photographs superimposed to highlight the differences:

Comparison of HiFiBerry DAC+ HW 2.2 and 2.6

Apart from the new oscillator hybrids the most obvious change is the removal of two large copper fills on the top layer of the PCB. These large areas of copper on the top layer are all connected to the 3.3V supply. The bottom layer of the board remains one big ground plane.

Copper fill stub near the oscillators on HW 2.2.

The copper fill near the oscillators looks especially suspicious. It was only connected to the 3.3V supply with a narrow bridge between the pins of P4 on the right. It provided supply voltage to U4 and nothing else further down to the left side. It seems like it could accidentally form a quarter-wave stub antenna. It's approximately 25 mm in length, so the resonance could well be somewhere in the GHz range. This is near enough to the 2.4 GHz band that I think it would be feasible for it transmit some oscillator harmonics out from the board.

It would be interesting to see if this stub was indeed causing the problems. It should be easy to drill a hole through and decouple the left end of it with a SMD capacitor to the ground plane on the bottom layer. I could then repeat the near-field measurements I did last year to confirm. I'm not sure if I will bother though. The new board does indeed fix the problem with the Raspberry Pi built-in Wi-Fi radio and I currently don't have any particular use for another audio board.

Posted by Tomaž | Categories: Analog | Comments »

Repairing what wasn't broken

04.06.2017 21:10

Last time when I was tinkering with the insides of my portable CRT TV (UTV 6007) I happened to notice one more odd thing. One of the smaller through-hole resistors near the high-voltage transformer looked charred from heat. Ever since this TV was new it had a little bit of that characteristic smell of overheated electronics. However it worked fine, so I didn't worry too much about it and it's not unusual for cheap plastic to smell a bit when heated. But this here looked serious enough to look into it even though from the outside there were still no apparent problems.

Blackened R75 near the high-voltage transformer.

The size of the resistor suggested a 1/8 W rating. The body was too blackened to read out the colors. The position is marked with R75 and the silkscreen print underneath helpfully says it should be 1 kΩ. However I've seen that other resistors on this board sometimes don't match the values printed for their positions. Out of the circuit, the resistor measured around 900 Ω, which seemed consistent with a slightly damaged 1 kΩ. Just to be sure, I traced the circuit around it to see what its function was.

The following is the relevant part of the circuit on the main board around the HVT. Only the low-voltage secondary winding providing a few 100 V for the first anode is shown here.

Circuit around the HVT in UTV 6007.

I also traced the small circular board that sits directly on top of the electron gun pins and is connected to the main board with a (very flimsy looking) 4-wire flat cable.

Small circuitboard on top of the electron gun.

I didn't find the exact pin-out for this tube, so take the pin markings with a grain of salt. However this pin-out seems consistent with how the typical cathode ray tube is connected. For reference I used the one shown in the KA2915 datasheet and a few old TV schematics my father found in his library.

The small circuit on top of CRT pins.

The cathode K has a positive bias relative to the ground. The bias can be adjusted with the Brightness knob. The first grid G1 is grounded and is hence negative relative to the cathode. First anode A1 is on a higher positive bias relative to the ground and is hence positive relative to the cathode. The second grid G2 either isn't present in this tube or is grounded as well. There is no apparent focus adjustment. The video signal is connected to the cathode. It varies cathode potential relative to the first grid and so controls the intensity of the electron beam and thus the brightness of the spot on the phosphor.

The capacitor and diode arrangement between A1, G1 and ground is interesting. Something similar is present on all CRT circuits I've seen (see D3 here for example, from this project). Its purpose might be to put a high negative bias on G1 to stop the electron beam when the device is turned off and A1 goes low. I know that a lingering electron beam in old TV sets sometimes burned out a spot in the screen if the beam didn't shut down before the deflection. This may be there to prevent that.

In any case, the R75 is in circuit that provides the anode voltage. Only the small anode current should flow through it, and the charging current for the 2.2 μF capacitor for a short time after the TV is turned on. It's not apparent what caused it to heat up so much. The capacitor seems fine, so perhaps something arced over at one point or the TV was turned on and off several times in short succession.

Replacement R75 resistor in UTV 6007.

Since the circuit seemed to be consistent with the suggested 1 kΩ value, I replaced the resistor with a new one. I used a standard 1/4 W carbon resistor I had at hand and left it on longer leads for better cooling if something similar happened again. As expected, the TV runs just as well with the new resistor in place as it did with the old burned up one. There's currently no sign of it overheating, but perhaps I'll check again after some time.

I love playing with this old stuff. Analog TV was one of the pinnacles of consumer analog technology and it's fascinating to see how optimized and well thought out it was at the end of its era. This particular specimen is surprisingly repairable for a device that I got new in the store for 20 €. Components are well marked on the silk screen print and most have their values printed out as well (even if those don't always match reality). The only thing more I could wish for is that I could run it with the case opened without a special contraption for holding the CRT.

Posted by Tomaž | Categories: Analog | Comments »

Disabling TV audio squelch circuit

21.05.2017 14:33

I just don't have any luck with Maker Faires it seems. I had everything packed and prepared for the event last week and then spent the weekend in bed with a fever. Sincere appologies to anyone who wanted to see the Galaksija. I'm sure there were more than enough other interesting exhibitions to make the visit worth your time.

Galaksija screenshot

In the weeks leading to the Maker Faire I came across an old problem with the small analog TV (United UTV 6007) that I use with vintage computers. Ever since I first played with Galaksija's audio capabilities I noticed that sound gets very distorted when played through the TV speaker. I never really looked into it. I just assumed that perhaps voltage levels were wrong for line input or the high-frequency components of 1 bit music were interfering with something. Since I had Galaksija already setup on my bench, I decided to investigate this time. It turned out that a clean sine wave from a signal generator also sounded very choppy and distorted. On the other hand, audio from a DVD player sounded perfectly fine. This made me curious and I took the TV apart.

United UTV 6007 TV circuit board.

UTV 6007 is built around the CD5151CP integrated circuit. It's very similar to the camping set TV described in this post about adding a composite video input to it. The post on Bidouille.org also has links to a bunch of useful datasheets. UTV 6007 already has a composite video and an audio line input out of the box, which was one of the reasons I originally bought it.

Part of the UTV 6007 circuit board marked "hbb".

I traced the audio path on the board to this curious circuit near the volume knob. I'm not sure what "hbb" stands for, but the circuit has a squelch function. It mutes the speaker when there's no picture displayed. This makes the TV silent when it's not tuned to a channel instead of playing the characteristic white noise. It actually takes a surprising amount of real estate on the small PCB.

Audio amplifier and squelch circuit in UTV 6007

This is the relevant part of the circuit traced out. The squelch takes input from the sync. sep. output on the CD5151CP. This is probably a signal that contains only synchronization impulses separated out from the video. R1, C1, R2 and C2 form an impulse filter. Positive impulses between 150 μs and 5 ms will open Q1. This discharges C3. If no impulses are present, R3 will in about 14 ms charge C3 to the point that Q2 opens. Q2 shorts the audio amplifier input to ground, making the output silent.

Q2 seems somewhat odd, since its collector doesn't have any bias current. So at first glance it appears that it would not be able to ground negative half waves of the audio signal. However, D386 amplifier has a bipolar differential input stage that sources base current. Apparently that provides sufficient collector current for Q2. In fact, the audio circuit (without the squelch) is identical to one of the D386 reference designs.

These timings suggest that the circuit detects vertical video synchronization. Unfortunately, the compact design of the TV makes it non-trivial to power it up while the circuit board is accessible. I didn't want to bother with any special setup, so I don't have any actual measurements. Sound distortion suggested that Galaksija's video signal was making this circuit erroneously trigger for a short time once every frame, which made for a choppy sound. Galaksija's video is in fact somewhat out-of-spec (for instance, it's progressive scan instead of interlaced).

Since I was not sure which timing exactly was the culprit, I opted to simply disable the circuit. I guess in the age of digital TV some untuned television noise just adds to the retro style of the whole setup. To disable the squelch I removed the R3 resistor. Without it, Q2 can't get any base current and hence always remains closed. A quick test confirmed that with that modification in place Galaksija sounds as it should on the TV speakers.

Posted by Tomaž | Categories: Analog | Comments »

Closer look at the original Galaksija

09.05.2017 20:34

A few weeks ago I met with Mr. Vojislav Ivetić in Maribor. He entrusted me with an old Galaksija computer circuit board. Several years ago he obtained it from Janez Stergar at the Faculty of Electrical Engineering and Computer Science, University of Maribor. He told me that the historical computer was in an unknown condition, very likely not working, and was interested in restoring it back to usable state. This post is the result of my visual inspection of the circuit to estimate the extent of the restoration that would be necessary.

Galaksija is a small home microcomputer that was designed in Belgrade by Voja Antonić around the Z80 microprocessor. The designs were openly published in a magazine in 1984 with the intention that readers would build their own computers from scratch. Do-it-yourself kits could be ordered by mail and eventually also complete, factory made computers. Galaksija was often easier to obtain than similar foreign computers due to heavy import restrictions in the former Yugoslavia. It is generally considered the most successful of several attempts at a domestic home microcomputer.

At the first glance, Mr. Ivetić' Galaksija appears to be built from one of the kits. It has a white mechanical keyboard and a factory made single-layer printed circuit board with the green solder mask and white silk screen print on top. The integrated circuits and other components were most likely gathered from various sources and soldered manually (not all are in sockets). All original Galaksija computers I've seen looked very similar to this. Some had black keyboards, but they all shared the same PCB design.

Galaksija circuit board from Mr. Ivetić.

The circuit board has the basic Galaksija configuration. Only the 4 kB ROM A is installed. This ROM contains the BASIC interpreter, video driver and the rest of Galaksija's minimalistic operating system (here marked Master EPROM). The ROM B socket is empty.

The quartz windows on UV-erasable EPROMs are only covered with a white paper sticker. If the board was stored for a long time exposed to light, it might be that the EPROMs have lost their charge due to ambient UV light and will have to reprogrammed.

Iskra EMS6116 static RAM on a Galaksija computer.

There is a single 2 kB static RAM chip installed. Interestingly, the logo suggests this is an Iskra EMS6116, a domestic integrated circuit. I was not aware that RAM was produced by Iskra. In fact, the original magazine article that gives instructions for Galaksija builders suggests ordering RAM and other chips by mail from abroad (with suggested distributors that will ship to Yugoslavia and tips on getting the shipments through customs). Sockets for additional two 2 kB RAM chips are empty.

All other chips are foreign made. The Z80 CPU and EPROMs are all from SGS (former Italian semiconductor company, later merged into STMicroelectronics). These also have the most recent date codes among the identifiable components on the board: first week of 1986. Original Galaksija design was published in January 1984, so this board was built at least 2 years later. Other logic chips I could identify are from TI and SGS. The oldest chip is the 74LS38 from 1979.

Improvised circuit on shift/load line.

There is a small bundle of components wrapped in sticky tape hanging off the PCB on four wires. It looks like it contains an IC in a DIP package and some capacitors. The circuit sits in front of the shift/load input to the 74LS166 shift register that generates the video signal. It's also connected to the ground and the power supply. Since the extra circuit is not connected to any other digital lines, I'm guessing it is most likely a delay to fix some timing problem.

Location of the improvised circuit on the schematic.

Normally, the shift/load input is driven directly by a circuit that detects when the CPU is in the M1 (opcode fetch) cycle. See full schematic here. I know from my previous research that M1 detection circuit on the original Galaksija is unreliable, since it depends on signal timings that are not guaranteed by the design of the Z80 CPU. It's possible that this was an attempt to work around this issue.

Two potentiometers for setting sync pulse lengths.

There is no RF modulator installed. The circuit has been modified so that composite video signal is directly present on a pair of improvised screw terminals. I'm guessing this Galaksija was used with a monitor or a TV with composite input. Those were quite rare at the time, but it was not uncommon for people to modify their TV sets to add a composite input.

Two potentiometers are wired in series with R12 and R13. They have been glued down, but are now hanging loose on wires. Potentiometers seem to have been installed to adjust horizontal and vertical sync pulse widths. They are not part of the original design. They affect the time constants of 74LS123 monostable multivibrators that generate synchronization impulses in the composite video signal.

Missing space key on the Galaksija.

The space keycap is missing, but the key itself is present. I guess even if a suitable replacement can't be found, one could be drawn in a CAD program and 3D-printed.

Example of a lifted track on Galaksija PCB.

A look at the bottom side reveals that the condition of the copper laminate is quite bad. Many tracks and annular rings have broken or lifted off the substrate. The PCB shows signs of old repairs to some of the damaged tracks, so at least part of this damage is not due to age. Maybe soldering was done at a too high temperature or the quality of the laminate was not particularly good. This Galaksija shows no signs that it was ever mounted in a case, so the damage might also be due to mechanical stress. Many tracks around EPROM sockets are broken, suggesting that the stress of inserting and removing the EPROMs was at least partially responsible.

Ruined annular rings under a transistor on Galaksija.

I've counted around 40 points on the PCB that would need repair. Some are hairline breaks in traces that seem easy to reliably bridge with solder. Other parts would require replacements of copper areas using foil and epoxy glue to bring them back to original condition. Fortunately this PCB has relatively large features compared to modern SMD boards. However, this extent of repair still seems like a lot of delicate work. I'm also not certain that other areas of the laminate that look fine now would not start failing during repair.

If all else fails, another possibility would be to have a whole replacement PCB made and re-solder the keyboard and other original components. This would obviously decrease the historical authenticity. While the scans of original PCB masks are available on the web, those are not precise enough to make a usable replacement board. They would need to be redrawn before they can be sent to a fab.

In conclusion, all basic components are there and look fairly well preserved. At the moment I have no reason to believe that any chips are bad. However the PCB should be repaired before attempting to power up this board. The extent of damage and the amount of fine work with the copper foil would make this repair quite time consuming. It would be nice to somehow check the state of the most critical chips before proceeding on that path. Fixing the PCB would be a big waste of time if the CPU or RAM chip will eventually turn out to be bad. On the other hand, replacements for 74LSxx series logic still seem to be relatively easy to come by.

Posted by Tomaž | Categories: Digital | Comments »

Galaksija retrospective and some news

29.04.2017 8:59

This year my Galaksija replica is a decade old. Back in January 2007 I first brought to life enough of the circuit in my father's workshop to display some faint, mirrored characters on the TV screen. It has been the culmination of 6 intensive months of reverse engineering and documenting the original design, ironing out the odd corners and designing a compatible computer around it. In September that year I've successfully defended my diploma thesis on Galaksija at the Faculty of Electrical Engineering.

In the following five years, I've mostly focused on the software. With the help of the working replica, I've been able to document a large portion of its ROM. I found convincing clues that Galaksija's BASIC was derived from Tandy TRS-80, not Microsoft BASIC as it is commonly believed. I explored old software and wrote some new demos. Along the way I confirmed the myth that high-resolution graphics were possible on that hardware. Finally, I've summed up most of my work in the Ultimate Galaksija talk in front of fellow hackers at the 29C3.

Applebloom simulation on Galaksija at 29C3 retro-gaming assembly.

I can't believe it's been ten years already. It feels like I've written all those articles two life times ago. In the mean time, I've been employed in vastly different fields and I guess I shouldn't be surprised that a lot has faded from my memory. The Hamburg talk was certainly the crowning moment and after the pretty exhausting preparations for it, I hardly returned to anything Galaksija-related. My replica still works, but while I once knew by heart minute timing details of every signal, the circuit diagram now only stirs up general ideas behind its operation. Still, the &2BA8 register address for horizontal sync adjustment immediately popped up from muscle memory upon touching the keyboard.

Anyway, I promised some news. There will be a Mini Maker Faire in Ljubljana in two weeks. I've always been intrigued by reports from Maker Faires and on a couple of occasions I've been very close to going to the one in Brighton. However, each time something else intervened. Hence I immediately jumped to the opportunity to participate in the first Maker Faire in our country. Also, a few people encouraged me to put my Galaksija on display once again. So, if you would like to play some Inspektor Spiridon on real hardware, or puzzle over why your BASIC program results in the WHAT? response, find my table at the Poligon Creative Centre on 13 May.

Galaksija circuit board from Mr. Ivetić.

The other news is that I was recently contacted by Mr. Vojislav Ivetić. As a fan of old computers, he acquired an old, original Galaksija from one of his colleagues and was interested in the possibility of renovating it and bringing it back to life. The exact state of the board is unknown, but supposedly it is not in a working condition. From the first glance it appears to be a mostly complete article, built from one of the original kits, albeit with some crude home brew modifications. Inspired by the recent series on Xerox Alto restoration by Ken Shirriff, I offered to have a look and at least do a quick checkup and a list of things that would need to be done to get it working.

I'll post my first findings from a more detailed look at this Galaksija in another blog post here in the near future. I would love to restore this computer back to its former glory and document the process. But that really depends on how much time I'll be able to dedicate to it and how other things in my life turn out in the following months.

Posted by Tomaž | Categories: Life | Comments »

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.

Update: This Mikrotik manual suggests that such repeated multicast packets are expected on wireless access points that are aware of multicast addresses. So it still might be that the problem is somewhere on the client side. I did find out that enabling Client Isolation on the Archer C20 fixes this problem (with the obvious side effect that wireless clients can no longer talk to each other). dad-timeout NetworkManager option is not supported on Debian Jessie.

Update: Client Isolation doesn't actually help. After a few days I'm again getting the dadfailed flag.

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 »