ADAT SMUX with FPGA

GroupDIY Audio Forum

Help Support GroupDIY Audio Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.

chilidawg

Well-known member
Joined
Nov 27, 2013
Messages
184
Nevermind, I got it working! 8)
The correct way is as described in the PDF file ADAT 96K Optical Addendum which you can get from Wavefront.

I finally get to the point in my FPGA ADAT receiver development where I want to add SMUX capability.

Let say, I have these 8 logic vectors which contain the 24 bit channel data.


signal audio0 : std_logic_vector(23 downto 0);
signal audio1 : std_logic_vector(23 downto 0);
signal audio2 : std_logic_vector(23 downto 0);
signal audio3 : std_logic_vector(23 downto 0);
signal audio4 : std_logic_vector(23 downto 0);
signal audio5 : std_logic_vector(23 downto 0);
signal audio6 : std_logic_vector(23 downto 0);
signal audio7 : std_logic_vector(23 downto 0);


From what I can understand about S/MUX, I will get 4 channel, which are:

audio0 + audio1 = channel0
audio2 + audio3 = channel1
audio4 + audio5 = channel2
audio6 + audio7 = channel3

And I will also have to generate the 88.2/96 KHz rate for I2S master clock (MCLK), I2S bit (serial) clock (BCLK/SCLK), and I2S word clock (LRCLK/WCLK) that I transmit together with the new channel data.

So, my question in regards to combining the bits; is it by arranging them in an odd-even interleaving manner?
Something like:


signal channel0 : std_logic_vector(46 downto 0);

channel0 <= audio0(23) & audio1(23)...
, and continue down to 0.


Can someone here please help me clarify? Thanks.
 
I've noticed that using the ADA8000 for example connected to a master device expecting and transmitting SMUX you see both input signals "multiplexed" (of the pair of channels) in the waveform at 96KHz and the analog outputs works both but of course at 48KHz, so that is logic to be as described in wavefront.

Could you publish your project, I'm interested in doing so and wish to know which FPGA did you used and if it's not much to ask the code and PCB/Schem you used.

Thanks!

JS
 
I was wrong, I got it messed up. As for the code, it's from OpenCores, courtesy of DannyW.
Originally written for Altera Cyclone II, and I converted it for Xilinx Spartan 3A.

It decodes the ADAT bitstream perfectly, and recovers the system clock SCLK at 256 fs, with a period jitter of 10 ns (100MHz FPGA clock). I added the BCLK and LRCLK in sync with the SCLK for a complete I2S transmitter.

For 44.1/48KHz, the channel data is:

L = channel 1
R = channel 2
L = channel 3
R = channel 4
L = channel 5
R = channel 6
L = channel 7
R = channel 8

recovered SCLK is nominal 256 x 44.1KHz (11.2896MHz) or 256 x 48KHz (12.288MHz)
IS2 transmitter SCLK is nominal 256 x 44.1KHz (11.2896MHz) or 256 x 48KHz (12.288MHz)

no problem! :)

For SMUX 88.2/96KHz, the channel data is:

L0 = channel 1
L0 = channel 1
R0 = channel 2
R0 = channel 2
L1 = channel 3
L1 = channel 3
R1 = channel 4
R1 = channel 4

recovered SCLK is nominal 256 x 44.1KHz (11.2896MHz) or 256 x 48KHz (12.288MHz)
I2S transmitter SCLK is nominal 256 x 88.2KHz (22.5792MHz) or 256 x 96KHz (24.576MHz)

Here's my problem. I don't know how to multiply the recovered SCLK by 2 :'(
 
I know that I can use DCM, but I don't know how to do it properly.

For an example, on the top level code, I have this:

Code:
    smux_mclk_gen : dcm_sp
    generic map (
        CLKFX_MULTIPLY  => 2
    )
    port map (
        CLKIN           => rmclk,  -- recovered system clock
        CLKFX           => clkfx
    );

I get errors in the simulation.
 
That jitter seems pretty high, do you know why is that? maybe using the clock from to slink instead of WorldClock.  I don't have any experience on FPGA, I'm looking at this thread since I'm interested in building this but I'm not ready to design it.

A good thing you may know, I did my experience connecting a well known ADA8000 into my sound card, making it to expect and transmit SMUX. Clock as toslink slave on the ADA8000, master on sound card.
So what I get was the following: inputs, from the ADA to PC, in the DAW, I was able to see both input signals (CH1&2 from ADA) in Channel one of the sound card, multiplexed, samples alternated, so one sample of channel one, one of channel two, and again. At the output from PC to ADA I get the signal of a single channel in the PC in both channels of the ADA, I guess interchanged, so first sample to channel one, second sample to channel two, and keeps going.

So from there I conclude that just taking the samples from one 96kHz ADC and send it at a single I2C input would make it look like channel one SMUX, it didn't seems to need anything else, so I'd use an FPGA to do that task, take the strings from one I2C of a two channels ADC and route it into 2 I2C strings with single channel 96kHz samples to each string, that to the conventional ADAT Encoder format and then to toslink. Same in the other way, take two strings from the ADAT decoder and make it one single string to a 2 channels DAC, putting a sample of each channel one by one. I don't know how is that, I would make the code for that part but I don't know how to set up a working FPGA and I don't have any demo boards close to try it out, I don't have the converters or nothing of that nor time to start to working on this right now. I don't know if it's just what I said or I'm missing something, also I think the FPGA could replace the encoder, decoder inside of it reducing a couple of things outside, which are hard to find here, I can get an FPGA without much trouble but I can't get wavefront chips. Then the clocking, I plan to use the master clock from my saffire which seems to be pretty nice, the same FPGA could make the necessary task on it to do all the synchronization I guess. Do all that on a single FPGA would require a big one instead of a smaller one and a lot of things around, but seems proper since we already need an FPGA use it for everything it could be useful.

JS
 
I have thought about doing what you described, which is to work on the serial audio data from AL1402G instead, but one receiver solution (without Wavefront ICs) implemented on a single FPGA is what I'm after.

I suppose I can reduce the recovered SCLK jitter by sending it out to an external PLL clock jitter-multiplier cleaner, then feed the PLL outputs back to the FPGA. A bit of an overkill? :/
 
SMUX support for Wavefront AL1402G.

1 cycle period of 10.416 ns is approximately 96KHz.
 

Attachments

  • smux96k.png
    smux96k.png
    133.2 KB
chilidawg said:
I know that I can use DCM, but I don't know how to do it properly.

For an example, on the top level code, I have this:

Code:
    smux_mclk_gen : dcm_sp
    generic map (
        CLKFX_MULTIPLY  => 2
    )
    port map (
        CLKIN           => rmclk,  -- recovered system clock
        CLKFX           => clkfx
    );

I get errors in the simulation.

It would help if you told me what errors your simulation was throwing.  ::) The clock names on your DCM instance aren't in the simulation waveform you show.

Oh, wait, I see the problem. You simply can't run the word clock (at the sample frequency) into the DCM; it's frequency is waaaaay too slow (RTFDS).  That's why you're getting the period errors.

You probably need to rethink your approach. One way to do it would be to use high-frequency clock (maybe 100 MHz, whatever) to oversample the incoming data line and decode it. Then write the incoming samples to a small FIFO, and read them out on the appropriate MCLK (24.576 or 22.5792 MHz) domain.

See http://ackspace.nl/wiki/ADAT_project, for example.

-a
 
joaquins said:
That jitter seems pretty high, do you know why is that? maybe using the clock from to slink instead of WorldClock.

What jitter?

So from there I conclude that just taking the samples from one 96kHz ADC and send it at a single I2C I2S input would make it look like channel one SMUX, it didn't seems to need anything else, so I'd use an FPGA to do that task, take the strings from one I2C I2S of a two channels ADC and route it into 2 I2C I2S strings with single channel 96kHz samples to each string, that to the conventional ADAT Encoder format and then to toslink.

I think you're a bit confused. What do you mean by "single I2S input?" Remember that I2S is a two-channel protocol (which channel is being shifted is determined by the state of LRCLK).

I'm also confused .. what are you trying to do?

-a
 
Oh, wait, I see the problem. You simply can't run the word clock (at the sample frequency) into the DCM; it's frequency is waaaaay too slow (RTFDS).  That's why you're getting the period errors.

You probably need to rethink your approach. One way to do it would be to use high-frequency clock (maybe 100 MHz, whatever) to oversample the incoming data line and decode it. Then write the incoming samples to a small FIFO, and read them out on the appropriate MCLK (24.576 or 22.5792 MHz) domain.

Nope. I'm not using DCM to multiply the word clock. The next few screenshots will tell the story.
 
and the signal "clkfx" which is the DCM output for doubling "rmclk".
 

Attachments

  • isim3.png
    isim3.png
    123.9 KB
My eyes might be playing tricks on me... but it looks like rmclk is not periodic. This seems to be what the error message is indicating as well.

It looks to me like it is changing between 80ns and 90ns on the fly. Thus the reason for no lock.

You might want to probe the locked and status signals out of the DCM.

Also, there is a clock wizard 'core' to help you set up the DCM if you want. It's a nice little GUI and it spits out the instantiation with all the proper attributes.
 
Also, I'd be a little leery of your duty cycle on your input clock. See table 58 in the datasheet:
http://www.xilinx.com/support/documentation/data_sheets/ds099.pdf

It specifies a 60/40 duty cycle requirement for clkin when using the DLL or phase shifter. However, the datasheet doesn't seem to specify any requirement for clkin when using the DFS only. Just something to keep in mind during debug.
 
guitarguy12387 said:
It looks to me like it is changing between 80ns and 90ns on the fly. Thus the reason for no lock.

You might want to probe the locked and status signals out of the DCM.

oh, yes, good point -- the DCM should be held in reset until the input clock stabilizes, and only then release the reset and let it lock.

I did a Virtex-4 design which handled source-synchronous data from an image sensor whose operating frequency (and hence its data clock) was set according to a a register. (It had an internal PLL/clock multiplier.)  The operating frequency ranged from something like 160 MHz to 300 MHz. Whenever the user wanted to change the operating frequency, a command was sent to the camera's microcontroller, which would put the DCM into reset, change the register, and then take the DCM out of reset.

Oh, bonus if you know about the V-4's DCM. Note the input clock frequency range. Well, it turns out that the DCM has a restriction on the input frequency range; below 240 MHz the DCM frequency mode has to be set to "LOW" (a build-time constant, can't be changed after configuration) and above it must be set to "HIGH." A condundrum -- solved by storing two configurations in an EPROM and having the microcontroller manage the configuration process.
 
Sorry, I was confused then and now again, too many tests at the university going on this days, I'll follow this when I'm done with all of them...

JS
 
Andy Peters said:
guitarguy12387 said:
It looks to me like it is changing between 80ns and 90ns on the fly. Thus the reason for no lock.

You might want to probe the locked and status signals out of the DCM.

oh, yes, good point -- the DCM should be held in reset until the input clock stabilizes, and only then release the reset and let it lock.

I did a Virtex-4 design which handled source-synchronous data from an image sensor whose operating frequency (and hence its data clock) was set according to a a register. (It had an internal PLL/clock multiplier.)  The operating frequency ranged from something like 160 MHz to 300 MHz. Whenever the user wanted to change the operating frequency, a command was sent to the camera's microcontroller, which would put the DCM into reset, change the register, and then take the DCM out of reset.

Oh, bonus if you know about the V-4's DCM. Note the input clock frequency range. Well, it turns out that the DCM has a restriction on the input frequency range; below 240 MHz the DCM frequency mode has to be set to "LOW" (a build-time constant, can't be changed after configuration) and above it must be set to "HIGH." A condundrum -- solved by storing two configurations in an EPROM and having the microcontroller manage the configuration process.

Haha yeah... good 'ol Virtex-4.

So you had to re-config the device every time you wanted to change that clock?! Ouch... I didn't know about that particular "feature."  :eek: Didn't the DRP ports didn't let you change the frequency mode? I can't quite recall. Or maybe a spare DCM and a bufgmux to switch between them?
 
guitarguy12387 said:
So you had to re-config the device every time you wanted to change that clock?! Ouch... I didn't know about that particular "feature."  :eek: Didn't the DRP ports didn't let you change the frequency mode? I can't quite recall. Or maybe a spare DCM and a bufgmux to switch between them?

Nope, DRP lets you set the CLKFX' M and N values and the phase shift, but not the frequency range.

And I didn't have a spare DCM.

-a
 
Back
Top