<< >>

ADAT Receive

The ADAT receive module comprises a single thread that parses data as it arrives on a one-bit port and that outputs words of data onto a streaming channel end. Each word of data carries 24 bits of sample data and 4 bits of channel information.

This modules depends on the reference clock being exactly 100 Mhz.

THe module has two functions, one that receives adat at 48 KHz, and one that receives ADAT at 44.1 KHz. If the frequency of the input signal is known a priori, the call that function in a non terminating while(1) loop. If the frequency could be either, then call the two functions in succession from a while(1) loop.

Note that the two functions use a normal chanend, but assume that data is read as if it was a streaming channel end. This is historic, and the interface should be changed to use a streaming chanend. This will require any application using this function to be changed (no change is required in the module itself).

API

Compile time defines

ADAT_REF
Define this to 100 to state that the reference clock is exactly 100 MHz (for example when using a 20 or 25 MHz crystal), or 999375 to state that the reference clock is 99.9375 MHz (the result of using a 13 MHz crystal on an L1 or L2). Other values are at present not supported.

Functions

void adatReceiver48000(buffered in port:32 p, chanend oChan)

ADAT Receive Thread (48kHz sample rate).

When a data rame is received, samples will be output onto the streaming channel At first a word 0x000000Z1 will be output, where Z are the user data; after that eight words 0x0ZZZZZZ0 will be output where ZZZZZZ is a 24-bit sample value. The eight words may refer to sample values on eight channels, or on fewer channels if muxing is used.

The function will return if it cannot lock onto a 48,000 Hz signal. Normally the 48000 function is called in a while(1) loop. If both 44,100 and 48,000 need to be supported, they should be called in sequence in a while(1) loop. Note that the functions are large, and that 44,100 should not be called if 44.1 KHz does not need to be supported.

Parameters:
  • p – ADAT port - should be 1-bit and clocked at 100MHz
  • oChan – channel on which decoded samples are output
void adatReceiver44100(buffered in port:32 p, chanend oChan)

ADAT Receive Thread (44.1kHz sample rate).

When a data rame is received, samples will be output onto the streaming channel At first a word 0x000000Z1 will be output, where Z are the user data; after that eight words 0x0ZZZZZZ0 will be output where ZZZZZZ is a 24-bit sample value. The eight words may refer to sample values on eight channels, or on fewer channels if muxing is used.

The function will return if it cannot lock onto a 44,100 Hz signal. Normally the 44,100 function is called in a while(1) loop. If both 44,100 and 48,000 need to be supported, they should be called in sequence in a while(1) loop. Note that the functions are large, and that 48,000 should not be called if 48 Khz does not need to be supported.

Parameters:
  • p – ADAT port - should be 1-bit and clocked at 100MHz
  • oChan – channel on which decoded samples are output

Example

An example program is shown below. The input port needs to be declared as a buffered port:

#include <xs1.h>
#include "adat_rx.h"

buffered in port:32 adat = XS1_PORT_1P;

The receive function should be called from a while(1) loop. The second call in the while loop is optional, and only required if 44,100 Hz data should be received:

void receiveAdat(chanend c) {
    while(1) {
        adatReceiver48000(adat, c);
        adatReceiver44100(adat, c);   // delete this line if only 48000 required.
    }
}

The data handler should inspect received data samples and synchronise with the beginning of each frame. In this case, we expect every 9th value to be marked with a ‘1’ nibble to indicate end-of-frame.

void collectSamples(chanend c) {
    unsigned head, channels[9];
    while(1) {
        for(int i = 0; i < 9; i++) {
            head = inuint(c);         // This will be 24 bits data in each word, shifted up 4 bits.
            if ((head & 0xF) == 1) {
                break;
            }
            channels[i] = head << 4;
        }
        // One whole frame in channels [0..7]
    }
}

The main program simply forks the data handling thread and the receiver in parallel in two threads:

int main(void) {
    chan c;
    par {
        receiveAdat(c);
        collectSamples(c);
    }                                           
    return 0;
}