S/PDIF Receive

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

This module requires the reference clock to be exactly 100 MHz.

Symbolic constants

  • FRAME_X

    This constant defines the four least-significant bits of the first sample of a frame (typically a sample from the left channel).

  • FRAME_Y

    This constant defines the four least-significant bits of the second or later sample of a frame (typically a sample from the right channel, unless there are more than two channels).

  • FRAME_Z

    This constant defines the four least-significant bits of the first sample of the first frame of a block (typically a sample from the left channel).

API

  • void SpdifReceive(in buffered port:4 p, streaming chanend c, int initial_divider, clock clk)

    S/PDIF receive function.

    This function needs 1 thread and no memory other than ~2800 bytes of program code. It can do 11025, 12000, 22050, 24000, 44100, 48000, 88200, 96000, and 192000 Hz. When the decoder encounters a long series of zeros it will lower the divider; when it encounters a short series of 0-1 transitions it will increase the divider.

    Output: the received 24-bit sample values are output as a word on the streaming channel end. Each value is shifted up by 4-bits with the bottom four bits being one of FRAME_X, FRAME_Y, or FRAME_Z. The bottom four bits should be removed whereupon the sample value should be sign extended.

    The function does not return unless compiled with TEST defined in which case it returns any time that it loses synchronisation.

    This function has the following parameters:
    • p

      S/PDIF input port. This port must be 4-bit buffered, declared as in buffered port:4

    • c

      channel to output samples to

    • initial_divider

      initial divide for initial estimate of sample rate For a 100Mhz reference clock, use an initial divider of 1 for 192000, 2 for 96000/88200, and 4 for 48000/44100.

    • clk

      clock block sourced from the 100 MHz reference clock.

Example

An example program is shown below. An input port and a clock block must be declared. Neither should be configured:

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

buffered in port:4 oneBitPort = XS1_PORT_1F;
clock clockblock = XS1_CLKBLK_1;

All data samples are being received on a streaming channel, after being parsed by the receive process. After reading a sample value from the channel, it must be converted to a signed sample value whilst removing the tag identifying the channel information. In this example, we perform this operation by masking off the bottom four bits and shifting the sample-data into the most significant 24-bits, ready to be used on, for example, I2S:

void handleSamples(streaming chanend c) {
    int v, left, right;
    while(1) {
        c :> v;
        if((v & 0xF) == FRAME_Y) {
            right = (v & ~0xf) << 4;
            // operate on left and right
        } else {
            left = (v & ~0xf) << 4;
        }
    }
}

The main program in this example simply starts the S/PDIF receive thread, and the data handling thread in parallel:

int main(void) {
    streaming chan c;
    par {
        SpdifReceive(oneBitPort, c, 1, clockblock);
        handleSamples(c);
    }
    return 0;
}