Mirics MSi3101 SDR Linux driver

Mirics MSi3101

MSi3101 is name of the reference design that consists of two parts, USB ADC and RF-tuner. Used USB ADC is MSi2500 and RF-tuner is MSi001. That designs was introduced somewhere in 2009 aimed for PCTV marked. It is the first and the only one SDR based PCTV solution, which unfortunately never becomes very popular.

Mirics MSi3101 devices
That solution differs notably from the other PCTV solutions as there is no hardware demodulators, instead signal processing is done by host computer software demodulator. That reduces complexity of hardware but downside is increased complexity of software and needed CPU power.

If we compare traditional DTV USB solution and that software solution, we could see that kind of data paths in higher level:

HW, traditional, solution:
antenna => RF-tuner => HW demodulator => USB-interface => PC => TV-application

SW, SDR, solution:
antenna => RF-tuner => ADC => USB-interface => PC => SW demodulator => TV-application

The very first DTV USB ADC

First of all, Mirics MSi2500 USB ADC is very interesting chip! It is very first plain USB ADC I have ever seen, designed for USB2.0 SDR based digital television. Requirements coming from the DTV terrestrial reception means that there must be sampling rates around 10Msps and sampling resolution 10-bit or more. These are hard requirements to meet as all the bits are transferred over rather slow speed USB2.0, which becomes quickly to bottleneck. To tackle that problem chip offers multiple stream format - for more you need sampling rate the less you has resolution and the other way round.

reverse-engineering USB ADC sampling rate formula

Unfortunately I was not able to get any needed register documentation for that chip, which forces me to jump reverse-engineering mode. Whilst I have done reverse-engineering quite a hell much, I don't like to do it as it is simply a waste of time... Fortunately ADCs are rather simply chips as there is not much moving parts, in a good luck only sampling rate. In that case there were mostly sampling rate and stream format which are needed to find out in order to operate chip somehow meaningful.

I thought some time how I could find out ADC sampling rate calculation formula and eventually ended up developing following method. It is mainly based of register value brute-force with sample rate calculation, but contains mixture of some other steps. I could imagine that same method could be useful later, when new USB ADC chips are arriving to market and documentation how to configure ADC sampling rate is not known.

  1. Prerequisites. You must have somehow working driver skeleton which streams ADC data. RF tuner functionality is not needed, but without the tuner step 2 could be hard to pass.
  2. Learn stream format. Implement some logic to driver which calculates all I/Q samples in given period. After the each period calculate sample rate (by driver) and output it to the debug log. I used 5 second period in my tests - more longer period you use, the more accurate sample rate calculation is.
  3. Find out registers involved to sampling rate setting. Sniffing and diffing... For example tune TV to 8 MHz channel, then 6 MHz and test even radio, depending on what app supports. Should not be very hard.
  4. Add "write_reg" V4L2 private control to your driver and some appropriate implementation for it. You could guess why and how - if not that method is not for you.
  5. Start streaming, eg.
    cat /dev/video0 > /dev/null
  6. Brute force different values to sampling rate registers and see what driver reports as calculated sample rate.
    v4l2-ctl -d /dev/video0 --set-ctrl=
Fractional-N frequency synthesizer
Basic knowledge of Fractional-N based frequency synthesizer functionality is needed in order to succeed with that method,  a lot of patience and a little bit luck too. It is easiest to try found meaning for something that changes a lot output sampling rate - in practise it is output divider (Rout, LO div). After that, integer part "N" of PLL multiplier and finally fractional part, which is most hard.

Sample rates measured

Both devices seems to perform very similarly on sampling rate test made. Sampling rate limits were between 1.21 Msps and 15 Msps. Smallest stable sampling rate is a little bit high what I expected, but not too high.

Sampling resolution & stream format

I found 4 different stream formats, all having different resolution. As a USB2.0 device there is direct relation between stream format and sampling resolution and indirect relation for sampling rate. Stream formats known currently supports 14-bit, 12-bit, 10+2-bit and 8-bit resolutions - at least sample bit count got is that, effective resolution (enob) could be a bit less...

I calculated following ~theoretical maximum sampling rates per stream format using assumption maximum USB2.0 effective throughput is 280 Mbit/s.

format resolution sample rate
252 14 8 613 281
336 12 11 484 375
384 10+2 13 125 000
504 8 17 226 562

These results are very theoretical and not tested.

Btw. that stream format register didn't liked injection of new register values when streaming was ongoing :) Result was typically broken stream and it didn't get fixed until device was physically replugged. There could be still some more formats available and I suspect using own firmware you could implement your own formats. At least these are supported by default firmware.

There was also bits to select USB URB Isochronous micro frame size from one of the 1024/2048/3072. 3072 is maximum what USB2.0 supports and I don't see any idea to use smaller as bus datarate is so high in any case.

MSi2500 advertises on USB interface device descriptor that it has some more alternative settings to offer. That same register is likely place to configure those too.

USB device descriptor


RF tuner used for that design is Mirics MSi001. It supports both Zero-IF and Low-IF, which is very unusual nowadays as most tuners are just Zero-IF only.

Tuner supports multiple bands and wide range frequencies, starting from the 150 kHz and ending up to 2GHz. There is quite big gap between 260 - 410 MHz, but more bigger problem with devices planned for TV usage is unconnected LW/MW/SW and L-Band antennas. These unconnected antennas limits actual frequencies to 50 - 960 MHz. Modding should be possible, but how hard?

testing tuner limits using RF generator

Here is the measured frequency ranges from two different devices I have.

device / mode Mirics MSi3101 SDR Dongle Hauppauge WinTV 133559 LF
VHF_MODE 52 - 132 MHz 49 - 130 MHz
B3_MODE 103 - 263 MHz 98 - 259 MHz
B45_MODE 413 - 960 MHz 391 - 960 MHz

Staging quality

Developing that driver has been relatively big task for me. I started to looking it around one year ago but most of the implementation was done during this summer. There has been numerous new issues to resolve as that is first Linux Kernel USB SDR receiver driver. The fact is that my backgrounds are from the digital television side, DVB API, and that driver is implemented to V4L2 API. I didn't has any existing knowledge from V4L2, which put me position I was forced to learn lot of things. Now I can understand again why some "simple" DVB things could be so hard to implement for firstcomers :)

As there is still multiple unresolved issues that driver could not be mainlined yet. Biggest problem is no less than missing API. So I am putting driver to the Kernel staging which is right place to problematic stuff like that. That is something I will try to kick Mauro to get help as I have so little experience about V4L2 internals. Actually Mauro has already provided some SDR API related patches that are waiting for some discussion and review.

I collected Kernel SDR API requirement specification, which the implementation should follow in the mean it is reasonable possible to implement.

Here is the list of know issues, from critical to less critical. I think resolving API issues is enough to move that driver out from the staging.
  • Kernel SDR API
    • new V4L2 controls
    • do not abuse video-device
    • stream conversions (move to libv4l2?)
    • implementation performance problems are ruled out
  • GNU Radio plugin
    • has performance problems (read => mmap)
    • add more functionality
    • stream conversions with the help of libv4l2
  • separate USB ADC and RF-tuner logic to own drivers
    • USB ADC main driver "msi2500"
    • RF tuner to v4l2 subdev driver "msi001"
  • tons of other changes!
    • feel free to contribute I am open for any help
    • hack hack hack!

Kernel driver development tree

I will keep latest Kernel driver development tree:

GNU Radio use example

Install gr-kernel GNU Radio plugin:

Use LibV4L2 Source it provides.

gr-kernel, LibV4L2 Source, FM radio

v4l2-ctl use example

Whilst LibV4L2 Source in gr-kenel package is recommended application to use device, it is still possible to use it via standard v4l2-ctl tool. These commands will surely change without a any notification when API issues are implemented correctly, but at the time that blog post is written you could capture 94.3 MHz FM radio dump to file using following commands:

$ v4l2-ctl -d /dev/video0 --all
$ v4l2-ctl -d /dev/video0 --set-ctrl=sampling_rate=2000000
$ v4l2-ctl -d /dev/video0 --set-ctrl=tuner_bw=200000
$ v4l2-ctl -d /dev/video0 --set-ctrl=tuner_rf=94300000
$ cat /dev/video0 > ./my_fm_radio_record.bin



Naked hardware #12: USB Audio Transmitter

USB Audio Transmitter teardown

This time I decided to teardown a little bit different hardware as usually - radio transmitter.

unbranded USB Audio Transmitter

USB Audio Transmitter

Key components:

Holtek HT82A821R
Quintic QN8027

General info

It is cheap noname USB audio transmitter, that is supported beginning from the Linux Kernel 3.4. Kernel driver name is radio-keene, done by Norwegian V4L superman Hans Verkuil.

Device has a USB ID 046d:0a0e assigned. That ID seems to belong Logitech, but likely company has nothing to do with device itself. Maybe the ID is just chosen because Logitech uses it on some USB speakers?

Device starts transmitting just after it is plugged on 95.160 MHz. Use of device is very easy as it implements itself as USB speaker - just plug it to the USB port and select proper audio output from volume control. There is some extra controls available via V4L2 interface, like a frequency setting and TX power. Check and tune using v4l2-ctl tool, "v4l2-ctl -d /dev/radio0 --all" lists all settings.

Hardware internals

PCB top side

All components are assembled to that side of the PCB. Bigger chip is HT82A821R and smaller is QN8027.

HT82A821R is USB speaker chip that supports standard USB audio profile.  The other chip, QN8027, is of course FM transmitter. Two similar looking metal tubes are clock sources. Unfortunately I forget to check clock frequencies, but according to datasheets HT82A821R supports 6 & 12 MHz and QN8027 supports 12 & 24 MHz.

Black wire is antenna, which is physically connected to the metal side frame giving physically a little bit more length.

PCB bottom side is almost empty

PCB bottom side

No components on that side, but still something. There seems to be about half of the antenna wired directly to the PCB.

BL-UAT82 V 1.0 ?

USB interface

IDLE current drain without a driver: 38mA