24 channels USB to I2S interface (with Source codes, ASIO/VHDL/Schematic)

Hi Now I'm making my USB-I2S interface.
I made stereo and 8channel USB-I2S project 2007 and 2008,
https://sites.google.com/site/koonaudioprojects/usb-to-stereo-i2s
now expanding to 24bit 24 channels.

attached
(1) Board photo, UM232H module / IDT72V FIFO / DLP-HS-FPGA2 / Clock, Power, Buffer
(2) Schematic.
(3) VHDL source, single, about 800 lines. 1300 FFs.
(4) ASIO Host Driver source, about 600 lines. (ver 0.1! I want to tune)
(you need ASIO SDK and free VisualStudio to build)

Hardware
FIFO can be changed to Cypress or faster one, if you want synchronous speed.
FPGA module can be changed. maybe GameDuino, Lattice Brevia, etc will work.
Clock, more can be added to switch 44.1/48/88.2/96.
Isolation, you can add IL711 isoLoop.
Power supply, is your free choice.

Software
by looking into source code, you can find only some lines are specific for FTDI. and 90% of codes are for ASIO. the core is to make data format for the device, then write them to the device. about 40 lines.

VHDL
I only uses very simple VHDL, to understand / to modify. If you can read state-machine, you can read.

Now you have all materials to start your own, don't ask me - please DIY and enjoy:)
 

Attachments

  • Board_Photo.jpg
    Board_Photo.jpg
    112.4 KB · Views: 3,078
  • SCH02.png
    SCH02.png
    176.8 KB · Views: 3,248
  • main.vhd.txt
    36 KB · Views: 586
  • koonasio01.cpp.txt
    17.1 KB · Views: 386
Last edited:
Koon, great post, thank you, you have me thinking about an alternative method of implementing multi-channel bit perfect i2S. I have source code for a virtual sound card driver (MSVAD sample) that could be easily hooked up to the UM232H module, and through implementation of a simple serial protocol the hi-speed of the USB serial interface can easily cater for multi-channel. The virtual soundcard driver would be a nicer way to implement it as any application can use it, and not have to rely on tricks like ASIO4ALL inbetween to connect.

Even though the interface will not be standards based (eg. UAC2) that does not really matter. I also have dug deep into the FTDI modules in a previous project and 40Mbytes/sec is ample for hirez multichannel. Having a quick look at your code, I can't see how you are using the FTDI chip in hi-speed mode as you set the output baud at 115200? Or is this your signalling channel back to the PC (I haven't taken a good look at your code yet).

I'm thinking would it be easier to use a microcontroller like the Pic DSP series instead of the FPGA (use the SPI ports as I2S)?
 
Yes, dsPIC doesn't have the I2S ability although I think you can use either the SPI ports or even bit banging on GPIO pins

I'm not familiar with FPGA, but couldn't you implement the FIFO in the FPGA? ALso it looks like there is a FTDI development card (Maestro) which has both the FTDI hi-speed USB chip and a FPGA on the same card, and it can use an external clock.

ALso, why are you using a separate FIFO? The UM232 has an onboard FIFO as well as 1K buffer. Are you using 512 bytes bulk transfer mode?
 
implementing FIFO in FPGA is possible, but it makes VHDL more long / confusing, and specific for Xilinx.
current design is very 'generic' and as I wanted, easy to understand. complex problem is broken down to ASIO host / FIFO / FPGA.
everything on the generic prototyping board, so anyone can change power / clocks / isolation.

on chip FIFO is too small. 1KB can contain only 13 samples, this is 68usec for 44.1kHz. No program can put next samples in this cycle.
 
Koon,

Can you explain a little more about:
1) How resilient this design is for jitter performance
2) How do you manage the FIFO buffer to avoid over/underruns? I assume the PC sends its data full speed but how do you manage the FIFO buffer control? Its not obvious in your code.
3) Do you have a description of the serial protocol you use between the PC driver and the FPGA. How do you differenciate between the serial samples (header, timing etc?)
4) As I understand it, a FPGA needs to be programmed every time it is switched on. Do you send the program over serial? Wouldn't a CPLD be a better choice (sorry I am FPGA/CPLD newbie).
5) For PC/USB isolation, I assume its best to isolate the 8 data lines out of the FTDI module so that any added jitter is buffered by the FIFO

This is a very interesting approach to USB audio!
 
dean: if you are talking about PC software clock / DAC clock buffering issue, This design is free from that. Only one clock drives everything.

(1) at the end of VHDL, you can see re-clocker. of course you can implement as you like, including power, isolation and buffers, on the outside of FPGA. (this is IL711 / 74HCxxx etc, DIP devices issue)
(2) see VHDL, the state machines run with "Full Flag" and "Empty Flag", and frame sync.
PC to FTDI: only processed when FTDI buffer is not full.
FTDI to FIFO: only processed when FTDI has data and FIFO is not Full.
FIFO to FPGA: only processed when FIFO is not empty and next frame requested.
FPGA to I2S output: MCLK (256fs) drives every bit.
(3) see C code, it adds 7fffff800000 as frame header. and in VHDL, you can see 7f->ff->ff->80->00->00 tracer state machine. If FPGA can not sync, all registers are cleared to 0x000000.
(4) FPGA module has flash memory. so power-on reset will cause reprogramming.
(5) "jitter" buffered to the FIFO? FIFO only has 00-ff data as result of writing operation. there are no information that "this D0 was recorded 15 ps earlier than next D1" all data lines are fixed when write pulse goes 0->1.
 
Thanks Koon for answers.

How do you avoid the state machine from recognizing 7fffff800000 in the audio data stream? I assume you wait for the header and don't look for the header in the stream until you have fully received a frame.

Any reason for this particular bit sequence as a header?

I assume there is no facility for retries, so if a sample is corrupted there is nothing that can done but pass the distortion through to the DAC. You could implement a checksum for each frame and implement a resend? Chance of corruption is pretty low though.

Sorry my last question was about PC isolation, not jitter. I think its pretty clear that putting isolators between each of the FTDI 245 FIFO outputs will be a good method, and with a baud rate of 4Mbps (24 bits x 192Khz for 8 channels) for the 245 FIFO parallel output will be easy for an isolator and allow us to completely separate the FTDI (powered by the USB port) from the rest of the digital logic. Another reason for keeping the external FIFO.

How do you change sample rates? If the PC application changes sample rates then you need some way to adjust the clock rate of the FPGA else you get buffer under/overruns. I assume you could implement in your frame a couple of bits to indicate the frame rate and have the PFGA adjust to suit.

Have you had problems with latency using the D2XX driver? In an earlier project I implemented a RS485 protocol using D2XX and used the DTS/RTS lines as signalling between the MCU and the PC, yet I found I would occassionally see 10 - 30msec latency delays (at random) which caused network errors with my solution (but still OK as protocol recovered) and investigations pretty much pointed to the D2XX drivers. So I was wondering if you have found any irregularities with using the D2XX drivers?

Also, you mentioned in your original post "FIFO can be changed to Cypress or faster one, if you want synchronous speed". Is it that your FIFO cannot handle high sample rates?
 
Last edited:
Hi Dean,
7fffff800000 : this is checked only at the starting of the frame. in the 24ch x 3 = 72 bytes sequence, there are no checking (see VHDL). so State machine always waiting for the header, then check, if OK, process 72 bytes data.

7fffff800000 means +1 (full top height) and -1 (bottom) of PCM. if your wav always contains this pattern, that is not music, should be full volume square wave.
There are another method that 8bit/7bit encoding. But I just want PCM data transfer, not want to implement strict data communication protocol.

retry: when corrupted, the data is cleared to 0x000000. DAC will receive 0.
resending: when FPGA find corrupted frame, then.. send NAK to PC, clear the FIFO, and wait for PC? it will cause some msec silence. I think discarding 1 sample (1/44100) is better.

Isolation point: also it's your free selection where to isolate, .. but including FPGA into DAC area, or Clock / FPGA in same PSU area?

Sample rate: I'm simply thinking to add mechanical switch to change clocks.
you can modify the VHDL/C to include (a) Clock selection byte (b) Clock selecter / buffer.

D2XX: I don't expect much, only writing 512 x 78 = 39936 bytes per host cycle.

FIFO: I had IDT72V so I used it, and it can work up to 15MB/sec > 96k/24bit/24ch.
if someone wants to implement 384k/24bit/24ch, this is 27MB/sec.
 
Dean,
If you want to make "resending" protocol,
(1) PC side have to read ACK/NAK after each communication
(2) you will need USB2.0 HighSpeed MCU, with enough RAM, about 200KB? for 50ms headroom.
(3) MCU check each frame from PC, if OK send ACK and store, if corrupted send NAK and discard.
(4) PC will send again if NAK. (3)-(4) cycle can not exceed the headroom at (2).
This is too much, than I want.
I just need corruption should be recovered within some frames, or DAC will receive all 0x00.
 
Koon, are you having trouble with ASIO? A more flexible alternative to ASIO is to use the MSVAD virtual audio driver, which installs as a soundcard and the Windows DDK sample provides copyFrom & copyTo functions to get/put data into the driver buffer. This way any windows application can be used, not just ASIO clients.

Also, can you talk a little more about how you avoid buffer overruns, I assume as you have posted you are sending the audio to the FTDI hardware at max speed which is much faster than the audio sample rate, so there has to be signalling back to the PC to stop writing to the FTDI buffer else the FIFO will quickly overrun. I can't see that in your PC or VHD code. Previously I used the RTS/CTS FTDI functions for buffer signalling but I found the latency on these lines unreliable with the FTDI USB 1.0 solution I used.

I agree that resending is not needed, and a MCU will not be fast enough for this solution. Thinking about how to handle corrupted packets, the FTDI protocol layers should have mechanisms like checksums and methods to handle corrupted packets, so if we assume the FTDI bits are error free, and we don't have any logic errors and a decent PCB trace layout we can assume the data will be error free. You mention that if you see a sync error you output all 0's, wouldn't it be better to repeat the previous sample, that would be less obvious, assuming the error doesn't last more than a couple of frames?

How does it sound? Do you get any dropouts?
 
Hi Dean,
MSVAD: that is, DDK. ASIO is confusing but far better than DDK.
at 245 FIFO mode FTDI can not accept data when FIFO is full. so my programs just issue FT-W32_WriteFile() and waiting the data are consumed.

0 and hold_previous_value: if stopped with data 0x657834, your speaker will receive high voltage DC signal, continuously.

Sound is just bit perfect, free from buffering / SPDIF clock generator etc.
sync error: I'm watching frame sync error on debug pin out from FPGA but nothing happen.
 
Yes, of course, any logic or system error putting any value other than 0 on the outputs for a period of time is bad.

I understand the D2XX buffer will block, that makes the PC side easy. So basically if the small FIFO on the FTDI chip is full the FTDI framework stops sending, and its up to the user to pull out the data from the FTDI FIFO when it is ready. Very simple.

I am going to order parts to start assembling a prototype. I'd like to use a FPGA with onboard SRAM for the FIFO and modify your code to implement onboard FIFO which should be simple. I need to learn VHD but looking at your code it looks pretty easy (I have Pic micro assembler experience, VHD looks easier!). I will look to implement automatic clock switching for different sample rates.

Do you have any pointers to get started on DIY FPGA? I can see they can be easily programmed through a JTAG port, no need for the expensive DLP-HS-FPGA2 module. I need to find a PLCC FPGA with sufficient SRAM.
 
Thank you Koon, you have been very helpful, and because of your insights (and a little help from FTDI ;)) it looks like a hi-rez async multichannel USB DAC is within relatively easy reach (and much cheaper than similar solutions)!

I'll start working on ordering parts, putting together a schematic and ordering PCBs (I have 2 to make). I'd be happy to share any enhancements and tweaks.