From: eLinux.org
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.
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.
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.
The SL11R's memory map:
Int RAM 0000-0BFF (3k)
Ext RAM 0C00-7FFF (29k)
Ext Pg.1/DRAM 8000-9FFF (8k)
Ext Pg.2/DRAM A000-BFFF (8k)
Mem map reg C000-C0FF (256b)
Ext ROM C100-E7FF (9984b)
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.
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).
This is a USB sniffer, logging all tranfers over the USB bus related to particular devices.
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)
Kristoff Bonne has written a PAD extractor. pad_decode and tdc_decode. (url) (add more details)
Controls the Wavefinder's LEDs independently of the Radioscape DLLs.
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.
Extract FIC data from Dabble4 logs, for later processing with FICDEC.
A partial DSP dissasembler for the TI 5402 DSP code has been written, but further work on this is not expected to be fruitful.
(add links to above)
Commands are sent using dwIOControlCode = 0x80002018
Data is retrieved using dwIOControlCode = 0x22000c, 0x220010, 0x2200014
USB Setup Data
bmRequestType = 0x40 - Write
bmRequestType = 0xc0 - Read
bRequest = 1 command/data to DSP_A
wValue = 0x0000
wIndex = 0x0080
wLength = 0x40
*data = <data>
bRequest = 2 command/data to DSP_B
wValue = 0x0000
wIndex = 0x0080
wLength = 0x40
*data = <data>
bRequest = 3 command/data to SR11R
wValue = register address, e.g. red LED = 0xc0f4
wIndex = register value
wLength = 0x04,
*data = <addr> <value>
bRequest = 4 Frequency Synthesiser
wValue = 0x0000
wIndex = 0x0000
wLength = 0x0c
*data = <data>
bRequest = 5 AFC, Symbol Selection
wValue = 0x0000
wIndex = 0x0000
wLength = 0x20
*data = <data>
(skip select_config stuff)
(skip first vendor_device packet, 64 bytes)
; initialise everything to zero
e6 c0 00 00 : 0xc0e6 : PWM control reg
e8 c0 ff 03 : 0xc0e8 : Max counter reg
ea c0 00 00 : 0xc0ea : PWM start ch.0 reg (0)
ec c0 00 00 : 0xc0ec : PWM stop ch.0 reg (0)
ee c0 00 00 : 0xc0ee : PWM start ch.1 reg (0)
f0 c0 00 00 : 0xc0f0 : PWM stop ch.1 reg (0)
fa c0 ff 03 : 0xc0fa : PWM cycle count - 1 (1024)
f2 c0 00 00 : 0xc0f2 : PWM start ch.2 reg (0)
f4 c0 00 00 : 0xc0f4 : PWM stop ch.2 reg (0)
f6 c0 00 00 : 0xc0f6 : PWM start ch.3 reg (0)
f8 c0 00 00 : 0xc0f8 : PWM stop ch.3 reg (0)
; initialise PWM counter registers
ea c0 00 00 : 0xc0ea : PWM start ch.0 reg (0)
ec c0 ff 02 : 0xc0ec : PWM stop ch.0 reg (0x02ff)
f0 c0 ff 02 : 0xc0f0 : PWM stop ch.1 reg (0x02ff)
f4 c0 ff 03 : 0xc0f4 : PWM stop ch.2 reg (0x03ff)
f8 c0 ff 03 : 0xc0f8 : PWM stop ch.3 reg (0x03ff)
f0 c0 ff 03 : 0xc0f0 : PWM stop ch.1 reg (0x03ff)
; initialise PWM control
e6 c0 0f 80 : 0xc0e6 : PWM control register
; initialise frequency synthesiser????
; or these might be the wLength=0x0c ones, as these occur just after dabble prints out "About to tune ..."
28 c0 e0 3d : 0xc028 : I/O control register 1
20 c1 00 00 : ??????
20 c1 ff ff : ??????
24 c0 00 38 : 0xc024 : Output control register 1
1e c0 00 00 : 0xc01e : Output data register 0
24 c0 00 30 : 0xc024 : Output control register 1
24 c0 00 38 : 0xc024 : Output control register 1
14 c1 e0 00 00 00 : ??????
. . .
. . .
. . .
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.
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):
f4 c0 xx 00 (for red)
f8 c0 xx 00 (for green)
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)
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.
e.g.
About to tune radio frequency to 225.648000
req=04, val=0000, idx=0000, len=000c 10 08 10 00 16 00 00 00 00 00 00 10
req=04, val=0000, idx=0000, len=000c 22 63 34 00 16 00 00 00 00 00 00 10
req=04, val=0000, idx=0000, len=000c 10 08 00 00 16 00 00 00 00 00 00 10
req=04, val=0000, idx=0000, len=000c 82 02 20 00 16 00 00 00 00 00 00 10
req=04, val=0000, idx=0000, len=000c 11 80 00 00 10 00 01 00 00 00 00 10
req=04, val=0000, idx=0000, len=000c 04 a2 03 00 13 00 01 00 00 00 00 10
^ ^
\---------/
-> tune(225.648000), x1=1022e, x2=3a204
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).
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.
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).
byte 0 : 0x0c
byte 1 : 0x62
byte 2 : <symbol>
byte 3 : <frame number, 00-1f>
byte 4 : 0xb9 / 0xbd / 0xbe / 0xbf
byte 5 : 0x20 / 0x10
byte 6 : 0x01
byte 7 : 0x00
byte 8 : 0x80
byte 9 : 0x01
byte 10 : 0x00
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...
e.g for the returned data : 0c 62 02 00 b9 20 01 00 80 01 00 00 6e 12 32 ...
<----- 12 byte header -----> <----- symbol data ...
6e 12 - 0 1 1 0 1 0 0 0 0 0 0 1 0 0 1 0
| | | |
| | | \__ real QPSK symbol 0
| | \____ imag QPSK symbol 0
| \______ real QPSK symbol 1
\________ imag QPSK symbol 1
The symbol data must then be processed accroding to EN 300-401. These steps are:
(perhaps we should put together a full list of USB commands and packets and what they do)
Original editor: Matthew Burnham Last updated 31 May 2009 by md84419