Stereo Software Page

Designing the stereo generator code.

The software is loaded from an external non-volatile memory at start-up to run entirely in DSP memory. There is a watchdog that causes the software to re-load should the core software decide to fault.

The Software Design

The software core runs asynchronously to the hardware. A run to process a sample pair is triggered by an ADC generated interrupt on the frame clock transistion. The incoming sample pair is processed to produce 4 MPX samples that are stored in a ring buffer until such time as the DAC retrieves the data. In this way the processing time can and does vary according to the level of processing required(with/without compression etc). The only requirement is that the processing is less than the time between sample pairs.

In essence:

The ADC frame clock triggers reading of a sample pair.
The DSP processes the data.
The resultant MPX samples are placed on the opposite sides of the Ring Buffer to the side flagged for reading.
        

A 4 way Ring Buffer holding 16 MPX samples is used.. Since thread write is done in blocks of four sample in a ring of 16 two pointers are employed spaced 8 addresses apart.

The ADC data stream structure

When the data comes from an AES3/EBU receiver the self same data format is used. Only the DSP SPORT port changes.. Inorder to choose which data source is used one of the DSP GPIO ports can be used to flag the SPORT port to be used.

The software is split into two parts: the startup code written in C and the core processing loop written in assembler for speed.

It is possible to write all the code in C using special C constructs to inform the compiler that a DSP optimised construct is used. How ever pure assembler beats a compiler anyday. Expert progammers can make many global short cuts that current compilers do not understand. Besides the Sharc assembler is really really simple.

The Filters Required

Several filters are required for correct processing of the incoming signals, some of which have to be choosen at start up.

The pilot filter, this is required because with a sampling frequency of 48KHz, the maximum sampled frequency is 24KHz. This is a linear phase FIR low pass filter with a cut off frequency of 15KHz designed to rmove any frequency components above 15KHz with especial attention to any signal at the pilot frequency of 19KHz This ensures that the pilot inserted by the stereo generator cannot be affected in any way by any external 19KHz signal and any possible alias of the 48KHz sampling are removed.

The pre-emphasis filter, used to condition the broadcast in order to improve the signal to noise ratio at reception. The assumtion is that in any normal audio stream for broadcast the high frequencies (3KHz and up) are at a lower level then the lower bands, so can be boosted to higer level and reduced on reception. There are several possible standards with different time constants. In Europe 50μSec is used, in North America it is 75μSec and in South Americ 125μSec is common. Thus four set of filter coefficients are stored as constants in memory, then at startup the correct array of coefficients is read into a dynamic array.

The optional signal processing that incorporates the possibiliy of signal expansion, signal compression and signal limiting work on three seperate bands. Thus 4 filters are required to split the signal into the low, middle and upper bands. See the Stereo Generator block diagram description for mor details.

There are two further important filters that can be defined seperately or combined, the 1:4 interpolation and the MPX correction filter. If a DAC with sinc/x correction is employed only the Analoue MPX filter needs to be response corrected. If the generator is operated in the mono mode only the interpolation filter is needed.

Varios FIR Filters

Varios IIR Filters

Configuration From Switch Settings

On start up various parameters have to be configured, the input level, pre-emphasis etc. This is achieved in the design under consideration by the DSP reading a bank of switches at start up. This obviously a one time initial state read. Since this read is memory bank read and very fast (one system cycle) the switch state is read every watchdog cycle. If the state changes the software is rebooted.

Standard C code bit arithmetic is used to decode the switch settings

Partial Code for Switch Decoding

Configuration ADC and DAC

Both the ADC and DAC have to be programmed via the DSP SPI port. For example: the gain of the ADC driver amplifier has to be set, the DSP data stream format or activate of sinc/x correction. The DSP is placed in the master SPI mode to configure the ADC and DAC before starting the core processing loop.

In the case of a DSP like the ADSP21488 the can be changed to a slave allowing DMA access to the memory. In this way frequently changing variables like the RDS data can be written without effecting the core loop. Likewise the the DSP memory can be interrogated for the audio processing information for a real time graphical display.

Partial Code for SPI actions

SPORT Setup

Up to three SPORT ports are used for the possible two inputs and one output data streams. The input ports have a simple configuration, just lecture of a pair of samples on the trigger of the frame clock flank and DMA write to the defined buffers. On detection of the write the core loop will trigger a calculation pass stating with lecture of the input buffer pair.

The output configuration is somewhat more complicated since a rotation of the lecture group (4 sample pairs per group) is required to read the Ring Buffer under control of the DAC frame flank. The first of the buffer pairs is the MPX signal and the second the pilot reference as read from a pre-calculated sample array.

Some of the code for the output SPORT

Defining The Pilot and Sub-carrier

The 19KHz pilot and 38KHz sub-carrier samples are pre-calculated and stored in an array to save computation time. Using a 192KHz sample rate, which is the sample rate at the point where we add on the pilot and sub-carrier modulation to the MPX signal, the common boundary is 1mSec. That is we store 192 samples of each waveform, this being 19 cycles of the pilot and 38 cycles of the sub-carrier. If we want we can vary the phase relation ship between the pilot and subcarrier. This phase feature is more usefull when the 57 cycles of the RDS carries are introduced.

As stated this is done to save computation time and easy to implement since the Analog Sharc has more than suffient data memory for this task. Computation of trigometric functions is very time elaborate since (depending upon the accuracy required), iteration of a series is required until the accuracy required is reached. By pre-calculating the values into an array the time involved is of no consequence and can be as accurate as required.

Usage only requires recovery of data from an array organised as a ring buffer and increment a pointer to the next array element. For the DSP this is a single cycle operation. Carry round of the pointer from last to first position of the array is automatic.

The pilot and sub-carrier arrays

The Core Machine

Written in assembler for speed, this is loop that processes each incoming sample pair. All the essential information of what is in the loop has already been given. Depending upon the equipment design the loop can be put together with the required component parts. There are a number of scaling parameters that have to one time set up when the prototype is operational since the parameters depend up the hardware.

Worthy of mention is the starting of the SPORT DMA by loading the first DMA script element:

                
//	Kick off DAC DMA
r1=8;
r0=_tx1_tcb0a;
r2=r0+r1;
dm(CP2A)=r2;
//	Kick off ADC DMA
r0=_rx3_tcb0;
r2=r0+r1;

            

Also there is the trigger of the loop when data enters. The DSP waits in an idle instruction until an event occurs:

                
to_idle:r12=0x40000;		// address offset
idle;
//		nop;
r5=dm(GP2A);		// next address of sport2 buffer
r1=r5 or r12;
dm(_ptr_buf)=r1;
//	Get data to the buffer audio for processing as floating values
i2=_rx3_buf;
i4=_audio;
r2=dm(i2,m6);

            

On completion of processing the loop returns to the flag to_idle. On the frame clock trigger the data pair is retrieved into the data pair array audio. Note: processing is in the SIMD mode.