From: eLinux.org

Wavefinder

Contents

DABUSB Wavefinder Information - Version 0.5

Wavefinder is a software-defined DAB radio designed jointly between
Psion, RadioScape, Roke, Lost Wax and Real Networks; and marketed by
Psion Infomedia circa year 2000. Wavefinder was originally a
Windows-only product - the eventual aim of this project is to develop
Free/Open Source GNU/Linux software, drivers and firmware suitable for
controlling the Wavefinder from an embedded Linux platform such as the
BeagleBoard.

In the future it might even be possible to replace the Wavefinder
hardware with Open
Hardware
that
takes advantage of modern highly integrated ICs (such as the TEMIC
U2731B / Atmel ATR2731 or the Hitachi HD155080 tuner ICs) and using the
DSP onboard the OMAP IC rather than 2x5402s.

Todo

  • Remove any rubbish that’s been superseded (ie. stuff we’ve figured
    out since).

Hardware

Main section (under shielding on USB cable side)

The two TI 5402 DSPs
provide about 200 MIPS of grunt. According to press releases from TI
(link,
link), these perform a
limited amount of demodulation/decoding of the raw RF signal. More
recent designs as used in the ModularTech PCI card, perform much more of
the decoding on-board using a TMS320DRE200 (or TMS320C5416) DSP, and
less on the host PC.

Radio section (large shield on reverse side)

Other bit (small shield on reverse side)

  • 24LC16B
    • 2Kx8 Serial EEPROM (prob interfaced to USB controller)
  • MAX1692 -
    Low-Noise, 5.5V Input, PWM Step-Down Regulator (marked 1692 EUB)
  • Si9424DY -
    P-channel 20V (D-S) mosfet (marked 9424 JZA Y02C)

Power Regulation and Management (Revised 22/11/02)

There is a plethora of power supply devices. It looks like a MAX1692 PWM
regulator (rated 600mA) provides a 3.3V supply from the USB 5V supply.
This almost certainly provides the power for the SL11R and probably the
DSPs and Xilinx chip as well. It also feeds an adjustable linear
regulator set to 1.8V
(LM1117MPX-ADJ - SOT223
package marked ‘NO3A’) which probably forms the core supply for the
TMS320C5402’s. There is also a mosfet (the Si9424) which appears to
switch the unregulated power from the mains unit to a
ZSR800 8V linear regulator
which supplies a ZSR500 5V
linear regulator. This regulator chain looks like it supplies the RF
section (and, of course, the (in)famous LEDs). There is also a
TPS76338 3.3V linear regulator
(the SOT23-5 package marked ‘PBEI’). This is fed directly from the
Si9424 mosfet and here we see a (the?) reason for the Wavefinder’s poor
reliability. The TPS76338 has
a maximum input voltage of 10V according to the data sheet and that is
what the loaded unregulated supply provides - this means that this
regulator is operating at the edge of its specifications and is liable
to fail - or at least it had on mine! The reason whoever designed it
used a 10V PSU is that the
ZSR800 has a minimum input
voltage requirement of 10V. Why the
TPS76338 isn’t fed from either
the ZSR800 or the
ZSR500 I don’t know - they’re
both rated at 200mA.

SL11R microcontroller

The SL11R’s memory map:

  1. Int RAM 0000-0BFF (3k)
  2. Ext RAM 0C00-7FFF (29k)
  3. Ext Pg.1/DRAM 8000-9FFF (8k)
  4. Ext Pg.2/DRAM A000-BFFF (8k)
  5. Mem map reg C000-C0FF (256b)
  6. Ext ROM C100-E7FF (9984b)
  7. Int ROM E800-FFFF (6k)

It seems that the memory mapped registers (0xC000-0xC0FF) are mapped
directly from USB commands such as “e6 c0 00 00”, etc. The processor is
16-bit, and data words are sent LSB first. This holds true for commands
with the first word being in the range (0xC000-0xC0FF). It *may* be
that some of the other commands are writing direct to memory.

General software tools

Psion’s Wavefinder software

The basis for reverse-engineering the Wavefinder, the Psion software
provides the libraries used by any of the Wavefinder control software
(e.g. native Psion software, DABBar, etc.). It also provides an API for
use by custom programs such as Dabble (extrememly useful when combined
with hooking the DLL functions).

Files

  • rsDSP[ab].bin - contain the DSP code. The data from both of
    these files is sent to the Wavefinder at startup.
  • rsCPU*\.dll** - different version of CPU-intensive code for
    different processors
  • ViadabReceiver.dll - lots of stuff, including LED control code

Snoopy/SnoopyPro

This is a USB sniffer, logging all tranfers over the USB bus related to
particular devices.

Custom software tools

Dabble

Dabble uses the Radioscape API to control the Wavefinder while hooking
some DLLs. This allows the behaviour of the supplied Wavefinder software
and what it sends over the USB bus to be studied. (maybe something on
interpreting dabble output)

PAD extraction

Kristoff Bonne has written a PAD extractor. pad_decode and tdc_decode.
(url)
(add more details)

wlights

Controls the Wavefinder’s LEDs independently of the Radioscape DLLs.

wboot

Further development of the wlights code so that now it will bootup the
wavefinder, download the DSP code, tune it to ‘something’, and collect
all the data returned. No real attempt so far to understand the content
of the data streams, other than the semi-obvious.

find_wavefinder() - Now uses some setupapi calls to find the
wavefinder driver, based on its GUID. My PC seems to like both
{96cb3fae-594e-11d3-b317-00e02914a689} and {a5dcbf10-6530-11d2-901f-
00c04fb951ed} - quite where these come from, I’m not sure, but the
{a5dcbf10-… one matches one posted to the list, so it must be
wavefinder specific. Hopefully, this code should now find any wavefinder
driver, on any USB port … init_wavefinder() - Trundles through
the API calls captured by dabble. (see startup, below)

A few threads are kicked off - one to cycle the LEDS, one to control the
frontend, and one to collect the main data: lights_thread() -
updates all 3 LEDS every 100ms - takes a 12 bit value, 0x3ff = dim,
0x001=bright tune_thread() - This is where things get serious… A
few commands are issued, then 0x800 bytes are returned from wavefinder.
This data appears to be the raw output from the ADC in the tuner
frontend - plot it, and you’ll see. The VIADAB code, then performs a
series of DSP functions - applies the Hamming window; fft’s etc. I guess
this is the tuner synchronisation, and feedback from these calculations
gets fed back to keep the tuner locked. It also seems to calulate its
BER from this data. This is what we need to understand more to control
the fine tuning ourselves. data_thread() - This is also quite
serious … This thread is kept in sync with the tuner thread, and
returns blocks of data (0x200 bytes), with a big discontinuity at 0x180
bytes. My guess is that this is the output of the IFFT performed by the
DSP chip. (more detail based on wfic) The whole data stream is not
returned - so the parameters sent each time round the loop by the
tune_thread, must select which what services are being received. Since
no sensible data is being sent back to wavefinder in wboot, the
data_thread is likely to return garbage. But, if you run dabble, you
get the same 2 distinct data streams.

wfic

Extract FIC data from Dabble4 logs, for later processing with FICDEC.

FICDEC

FICDEC

Quick and dirty DSP dissasembler

A partial DSP dissasembler for the TI 5402 DSP code has been written,
but further work on this is not expected to be fruitful.

Specifications

  • ETS 300 401 (AKA “radio broadcasting systems; digital audio
    broadcasting (DAB) to mobile, portable and fixed receivers”).

(add links to above)

USB Protocol

  1. Commands are sent using dwIOControlCode = 0x80002018
  2. Data is retrieved using dwIOControlCode = 0x22000c, 0x220010, 0x2200014
  3. USB Setup Data
  4. bmRequestType = 0x40 - Write
  5. bmRequestType = 0xc0 - Read
  6. bRequest = 1 command/data to DSP_A
  7. wValue = 0x0000
  8. wIndex = 0x0080
  9. wLength = 0x40
  10. *data = <data>
  11. bRequest = 2 command/data to DSP_B
  12. wValue = 0x0000
  13. wIndex = 0x0080
  14. wLength = 0x40
  15. *data = <data>
  16. bRequest = 3 command/data to SR11R
  17. wValue = register address, e.g. red LED = 0xc0f4
  18. wIndex = register value
  19. wLength = 0x04,
  20. *data = <addr> <value>
  21. bRequest = 4 Frequency Synthesiser
  22. wValue = 0x0000
  23. wIndex = 0x0000
  24. wLength = 0x0c
  25. *data = <data>
  26. bRequest = 5 AFC, Symbol Selection
  27. wValue = 0x0000
  28. wIndex = 0x0000
  29. wLength = 0x20
  30. *data = <data>

Startup

  1. (skip select_config stuff)
  2. (skip first vendor_device packet, 64 bytes)
  3. ; initialise everything to zero
  4. e6 c0 00 00 : 0xc0e6 : PWM control reg
  5. e8 c0 ff 03 : 0xc0e8 : Max counter reg
  6. ea c0 00 00 : 0xc0ea : PWM start ch.0 reg (0)
  7. ec c0 00 00 : 0xc0ec : PWM stop ch.0 reg (0)
  8. ee c0 00 00 : 0xc0ee : PWM start ch.1 reg (0)
  9. f0 c0 00 00 : 0xc0f0 : PWM stop ch.1 reg (0)
  10. fa c0 ff 03 : 0xc0fa : PWM cycle count - 1 (1024)
  11. f2 c0 00 00 : 0xc0f2 : PWM start ch.2 reg (0)
  12. f4 c0 00 00 : 0xc0f4 : PWM stop ch.2 reg (0)
  13. f6 c0 00 00 : 0xc0f6 : PWM start ch.3 reg (0)
  14. f8 c0 00 00 : 0xc0f8 : PWM stop ch.3 reg (0)
  15. ; initialise PWM counter registers
  16. ea c0 00 00 : 0xc0ea : PWM start ch.0 reg (0)
  17. ec c0 ff 02 : 0xc0ec : PWM stop ch.0 reg (0x02ff)
  18. f0 c0 ff 02 : 0xc0f0 : PWM stop ch.1 reg (0x02ff)
  19. f4 c0 ff 03 : 0xc0f4 : PWM stop ch.2 reg (0x03ff)
  20. f8 c0 ff 03 : 0xc0f8 : PWM stop ch.3 reg (0x03ff)
  21. f0 c0 ff 03 : 0xc0f0 : PWM stop ch.1 reg (0x03ff)
  22. ; initialise PWM control
  23. e6 c0 0f 80 : 0xc0e6 : PWM control register
  24. ; initialise frequency synthesiser????
  25. ; or these might be the wLength=0x0c ones, as these occur just after dabble prints out "About to tune ..."
  26. 28 c0 e0 3d : 0xc028 : I/O control register 1
  27. 20 c1 00 00 : ??????
  28. 20 c1 ff ff : ??????
  29. 24 c0 00 38 : 0xc024 : Output control register 1
  30. 1e c0 00 00 : 0xc01e : Output data register 0
  31. 24 c0 00 30 : 0xc024 : Output control register 1
  32. 24 c0 00 38 : 0xc024 : Output control register 1
  33. 14 c1 e0 00 00 00 : ??????
  34. . . .
  35. . . .
  36. . . .

PWM Control Register = 0x800f = b1000 0000 0000 1111 which basically
means it’s set to begin operation, at 48MHz, continuous repeat (rather
than one-shot), active low, enabled.

LEDs

The LEDs are controlled via the SL11R’s built-in PWM controlled pins (of
which there are four, though only three are used). The PWM pins are
setup during initialisation (see above).

Colours are sent via the commands (or similar):

  1. f4 c0 xx 00 (for red)
  2. f8 c0 xx 00 (for green)
  3. f0 c0 xx 00 (for blue)

with xx being the intensity (or at least the value passed to the command
line of wlights). (can probably add more here, we know a lot more about
the leds than this now)

Tuning Datastream

The frequency is set by a set of 6 ‘req=4’ commands. The first five
always seem to be the same; the last one varies dependant on the
frequency. The wtune code just calculates the value for the last
command.

  1. e.g.
  2. About to tune radio frequency to 225.648000
  3. req=04, val=0000, idx=0000, len=000c 10 08 10 00 16 00 00 00 00 00 00 10
  4. req=04, val=0000, idx=0000, len=000c 22 63 34 00 16 00 00 00 00 00 00 10
  5. req=04, val=0000, idx=0000, len=000c 10 08 00 00 16 00 00 00 00 00 00 10
  6. req=04, val=0000, idx=0000, len=000c 82 02 20 00 16 00 00 00 00 00 00 10
  7. req=04, val=0000, idx=0000, len=000c 11 80 00 00 10 00 01 00 00 00 00 10
  8. req=04, val=0000, idx=0000, len=000c 04 a2 03 00 13 00 01 00 00 00 00 10
  9. ^ ^
  10. \---------/
  11. -> tune(225.648000), x1=1022e, x2=3a204
  12. the 4 bytes calculated are 0x04, 0xa2, 0x03, 0x00

These values are presumably sent the to frequency synth. PLL (LMX2331U);
but I’ve not tried to figure out the actual meanings of the parameters.


I’ve also been monitoring the ‘req=5’ commands that are sent by the
tune_thread. e.g. cmd=5, value=007f, index=7fff ffff ffff fff8 0000
0000 0000 0000 0000 0000 ff00 056c 0011 0000 000f 0000

The 1st 4 words (0x7fff ffff ffff ffff8) may control which symbols are
transferred, but normally I see these values. Sometimes, if the tuner
cannot lock (bad freq, or no reception), I see something like (1111 1111
1111 1111) which possibly resets the null symbol synchroniser. The last
but few words (056c, 0011) are probably the AFC. If there is no
reception or lock then these values are constant. If it is tuned, then
they vary slowly, presumably causing the AFC circuit to adjust the
frequency to hold the tuner in lock. - onward and upwards …

The wavefinder return a block of 0x20c bytes per symbol received. Not
all symbols per frame are passed accross the USB interface - only those
selected by a ‘req=5’ command (precise format of this command is still
TBD).

Automatic Frequency Control

The biggest missing bit is the AFC control. I figured out how to send
the required frequency to the frequency synthesiser, but to complete the
tuning, the frequency must be phase locked fairly precisely in order to
ensure that each of the carriers end up in the middle of the FFT bin.
This is a 2 stage process. The acquisistion phase achieves a course
lock, by performing a sequence of correlations of the received phase
reference symbol against a locally constructed phase reference symbool.
By sliding the local symbol, and performing a correlation for each
position, a course offset value can be determined. I can do the
correlation, but I don’t yet know how to feed the result back to the
wavefinder. The acquisition phase can reduce the phase offset (too many
phases here …) to within 1 carrier (1 FFT bin). Once this phase offset
has been reduced, the system enters a tracking phase, to provide fine
adjustment. This seems to invlove a further correlation, and then uses a
moving average to further adjust the frequecy. This process should be
able to track any frequency drift, and reduce the phase error to \< 1
carrier - i.e centre the sample point to the middle of the carrier. As
with the acquisition, I do not as yet have a complete understanding of
how the analysis is converted to the value that is sent back to the
wavefinder.

Main datastream - processing data blocks

My current thought is that the DSP may also do the demodulation as well
as the FFT. This is mainly based on the amount of data that is returned.
For each symbol, we get back 1 block of data (0x200) bytes, of which the
last 0x80 bytes is a replica of the first 0x80 bytes of a previous
symbol - this must be the effect of the guard band. That leaves 0x180
bytes per symbol. A symbol is based on 1536 (0x600) carriers; so that
only allows 2 bits per carrier. So, either the data is 2 bits per fft
bin, or the fft output has been further processed. The header for each
data block indicates which symbol it is for. Symbol 0 (the NULL symbol)
seems to be returned for all frames. Sometimes I also get 0x12-0x3d;
somtimes I only get 2,3,4. 2,3,4 are the FIC; higher numbers are the
MSC.

The data returned appears to consist of a 12 byte header that identifies
the symbol number, then 0x180 bytes of ‘useful’ data, then a further
0x80 bytes of ‘useless’ data (which is presumably due to the guard
band).

  1. byte 0 : 0x0c
  2. byte 1 : 0x62
  3. byte 2 : <symbol>
  4. byte 3 : <frame number, 00-1f>
  5. byte 4 : 0xb9 / 0xbd / 0xbe / 0xbf
  6. byte 5 : 0x20 / 0x10
  7. byte 6 : 0x01
  8. byte 7 : 0x00
  9. byte 8 : 0x80
  10. byte 9 : 0x01
  11. byte 10 : 0x00
  12. byte 11 : 0x00 / 0x80

The 0x180 bytes of symbol data is the result of some processing by the
DSPs.
The DSPs take in data from the ADC, perform a 2048 point FFT, then
perform differential demodulation. The data transfered over the USB is
the resulting OFDM complex symbols.
These are transferred as 16 bit words. Care needs to be take to process
this data in the correct order - aren’t big/little endian issues a right
pain…

  1. e.g for the returned data : 0c 62 02 00 b9 20 01 00 80 01 00 00 6e 12 32 ...
  2. <----- 12 byte header -----> <----- symbol data ...
  3. 6e 12 - 0 1 1 0 1 0 0 0 0 0 0 1 0 0 1 0
  4. | | | |
  5. | | | \__ real QPSK symbol 0
  6. | | \____ imag QPSK symbol 0
  7. | \______ real QPSK symbol 1
  8. \________ imag QPSK symbol 1

The symbol data must then be processed accroding to EN 300-401. These
steps are:

  • Frequency Deinterleaving - Each of the 1536 QPSK complex symbols
    is transmitted on a different carrier. Theses are reordered before
    transmission. This process needs to be reversed.
  • Symbol Demapping - The 1536 QPSK symbols are derived from 3072
    OFDM symbols. This process is reversed here.
  • Depuncturing - Extra zero’s are added to the data stream
    according to the puncturing pattern.
  • Viterbi Decoding - The Viterbi decoder attempts to correct any
    errors in the data stream, using the redundancy that was added
    before transmission. Approx. 3 x more data is transmitted than is
    required.
  • Descrambling - The data is scrambled to produce a similar number
    of 1’s and 0’s.

Command list

(perhaps we should put together a full list of USB commands and packets
and what they do)

GNU Radio


Original editor: Matthew Burnham
Last updated 31 May 2009 by md84419

Categories: