Audio DACs and some odd frequency goings on. - Page 1
Forum section: electronics / projects

author: hamster_nz
author_rank: Super Contributor
timestamp: November 30, 2019, 09:44:01 am
content: As a learning project I've got four inexpensive 24-bit I2S ADC feeding into four equally inexpensive 24-bit I2S DAC (CS4344), via an FPGA. The design is currently running at 48KS/s. Components and layout follow the reference implementation in the datasheet. The ADC seems to work really well - a good input generates the same output spectrum as a lookup table in the FPGA.However, regardless of if I use the ADC, or generate the samples from a lookup table I have some unwanted aliases appearing in the output.The aliases are always Fin + n*(8 kHz), and of course 'fold back' at 0Hz and 24kHz (as you would expect aliases to). So if I put 10kHz in I get the largest spikes at 2kHz and 18khz, and then a smaller one at -6kHz and 22kHz, So looks like a small amount of non-linear something is going on, involving an 8kHz signal. The odd thing is I don't have a 8kHz signal anywhere.So I found the worst possible case, and looked at it on the scope (see image). Sample rate is 48kHz, F_in is a smidge under 16kHz, most likely due to the signal generator having a different reference to the ADC/DACs. That gives three samples per cycle going into the DAC.It looks like the DAC generates 12 'steps' for the cycle, so to me it looks like it up-samples internally to 192kHz. And 8kHz is 1/24th of the 192kHz - and I'm using it in 24-bit mode. Is it somehow related? Could it be that one step in 24 is somehow 'bigger' than the others causing the unwanted modulation?Anybody got any ideas what is going on, or is it just that the CS4344 is an inexpensive audio DAC and I am expecting too much from such a cheap part?

author: hamster_nz
author_rank: Super Contributor
timestamp: November 30, 2019, 10:45:04 am
content: Oh, I switched my AD2 sampling into 'average' rather than 'decimate' mode, so now the spectrum looks a lot better for the noise floor, with it matching that expected from a audio DAC.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 01, 2019, 10:09:38 am
content: Got the data from the scope trace, and wrote some code to extract the desired 16kHz signal and the undesired 8kHz signal from the noise and print what is left over.Threw it into a spreadsheet and this is the first graph. The 8kHz signal (yellow) is so low that it looks like a straight line (as the numbers suggest).The second graph has the 8kHz signal on the secondary axis, so it is at least visible and the relative phase can be seen.Seems the signal is coming out of the DAC - no idea what or why though. Oh well....

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 01, 2019, 05:42:35 pm
content: Quote from: hamster_nz on November 30, 2019, 10:45:04 amWhat is AD2?For the noise floor yes, but otherwise it looks pretty poor compared to even an average 24-bit audio DAC as far as THD is concerned. You definitely have some issue there. Not sure what it is without more info.What is your MCLK frequency, and are you 100% sure of your I2S transmit block?

author: bson
author_rank: Unknown
timestamp: December 01, 2019, 07:17:41 pm
content: Do you have both ends set to single channel? Looks like the MSB is flipping, which could possibly be the case if the ADC is sending stereo while the DAC expects mono.I'd stick my MSO probe on there and check timing, waveform shapes (ringing, overshoot, runts, crosstalk, etc), and that it all looks like it should.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 01, 2019, 08:24:03 pm
content: Quote from: SiliconWizard on December 01, 2019, 05:42:35 pmAD2 => Digilent Analog Discovery 2, just using it a test bench for this, as both the input and outputs are 14-bit ADC, 100MS/sThe DAC being used is a Cirrus Logic CS4344 -https://statics.cirrus.com/pubs/proDatasheet/CS4344-45-48_F2.pdfMCLK is as smidgen off of 36.864MHz (like 0.01% off), due to not being able to nail it with the valid FPGA's PLL multipler/divider combinations. Maybe I should try clocking directly from the 12MHz oscillator?Tonight I will snoop the I2S bus while sending a test tone from a lookup table in the FPGA, and check that the values seen match those in the table.Quote from: bson on December 01, 2019, 07:17:41 pmBoth ends are set to stereo, and can have test signal down one channel at 1V p-p while the other channel remains quite, so it doesn't look like the are getting messed up on either the digital or analog side of the DAC.All I2S waveforms look great (well, given the limitations of a 100MHz scope looking at the 36MHz clock) - but the slower LRCK BCLK and SDAT signals are all nice and square. But just in case I've got a Rev2 board in the works that will have series resistors on the digital signals in case it is needed.I was listening to the whole ADC->FPGA->SRAM->FPGA->DAC chain, at "moderate" volume and it sounds fine to my aged ears. No dogs in the neighbourhood started howlingOh, I've just realized that I could use my PMOD I2S (https://reference.digilentinc.com/reference/pmod/pmodi2s/reference-manual) as a comparison to see if it is just my design. It uses the same part, but the forgot the output filtering caps (or more likely left them off because optimal values depends on the sample rate). I'll add that too to the todo list for tonight...

author: BrianHG
author_rank: Super Contributor
timestamp: December 01, 2019, 09:44:03 pm
content: Hint why the ADC may be fine and the DAC isn't (if the problem is leakage high frequency noise in the dac output):Place series resistors as close to the IO pins of the FPGA as possible on ALL signals going into the DAC. Tune the resistor values so you you get smooth, not so rounded, but no spike edges on the DAC clock input. Measure with a J-Fet amplified probe as you don't want probe capacitance to smear your reading.The outputs on the ADC may be a really low current drive, by design, so that their drive won't add noise into the sample due to bounce and spikes during transition.An ultra fast FPGA output may leak through the DAC's inputs to the analog section due to internal capacitance inside the DAC. Series resistors right at the FPGA IOs will prevent this current in the steep rise and fall of the FPGA to probigate throughout you analog system.Also to clean up you FPGA IO, I personally second D-Flipflop clock my outputs and set 'Fast Output Registers' on those FPGA output pins so that the fitter forces those final D-Flipflops to be located right at the IO pins. Make a huge difference plus every time you re-compile your FPGA, you don't need to worry about those IO characteristics will ever change.

author: jbb
author_rank: Super Contributor
timestamp: December 01, 2019, 11:38:42 pm
content: Yes! Definitely push the output flip flops into the IO pins. It makes a big difference. If you get timing closure problems because of it, you can add a 1 clock delay register (who cares about 1 clock at these oversample rates provided its consistent). For quick results, check the FPGA IO documentation and just use the vendor specific Verilig/VHDL module for how you want your IO pin. (Some IO pins can also take a few bits in parallel and serialise them for you, which might be helpful.)Depending on the FPGA, you might have some nice IO pin options built right in, such as different slew rate settings or even real series resistance settings. This can make a big difference. They can be managed by the same file that you use to specify where the IO pins come out.If you’re concerned about clocking, maybe you could get a crystal oscillator on one of the ‘oddbal’ frequencies that turn out to multiply up (or down or sideways) to just the right frequency.Have you checked that the clock and data lines to the DACs are appropriately aligned? If you’re on the edge of a setup or hold limit then you could get weird behaviour. A quick test is to heat or cool the DAC a bit and see if it behaves differently.I also hear that FPGA internal PLLs aren’t great for things like phase noise, especially if the divider numerator and denominator are quite large (which means that the phase detector frequency is low and the loop has to ‘coast’ for longer between updates). Using an ‘oddball’ crystal oscillator frequency might help get more friendly divider values. You could even look at an external PLL chip with better performance (note: I know basically nothing about PLL specs and could be totally wrong).For basic debugging work, I suggest you only use 1 clock frequency for the whole FPGA, because transitions between clock domains are a bit tricky and you’ve already got a problem to worry about.Are you outputting an ADC or DAC clock from the FPGA? If so, I hear it can be helpful to use a two clock system (same frequency, with 0 degree clock and 180 degree clock) for the output drivers, a DDR output driver, and a fixed output of “10” to provide a very even 50% duty cycle clock with low jitter.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 01, 2019, 11:51:03 pm
content: Quote from: BrianHG on December 01, 2019, 09:44:03 pmYes, as soon as new boards are here I'll be doing this.QuoteYes, I am pretty 99% sure it is already set up this way - will double-check.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 02, 2019, 12:15:54 am
content: Quote from: jbb on December 01, 2019, 11:38:42 pmI've got some 4 pin oscillators of the right frequencies in my parts stash.. hopefully it won't get to that, because then I have all the joy of getting the clock cleanly into the FPGA.QuoteClock and data lines look to be correctly aligned as per datasheet timing requirements - will try heating/cooling anyway to check. My understanding is the MCLK needs to be the same ppm as the LRCLK and BCLK, but there is no specific phase alignment requirements - from 4.1 of the datasheet "Please note there is no required phase relationship, but MCLK, LRCK and SCLK must be synchronous."QuoteGoing to try looking into this too - rather then attempting the perfect 36.864 MHz clock through weird multiply/divide ratios.QuoteThe whole FPGA design is one clock domain - the same clock is used for the MCLK of the ADCs & DACs and the minimal FPGA logic. All clocks generated in the FPGAs. Starting out simple.QuoteYes, I am using a clock forwarding using a DDR register for those very reasons. On the FPGA I'm using the DDR primitive can work with just one clock.I'm thinking of knocking up a very simple I2S test case - outputs 0, 7207992, -7207992, which should be a perfect sine at Fs/3, and will be easy to verify with a logic analyzer.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 02, 2019, 12:21:32 am
content: Oh, I've just seen in the data sheet, that the specs are quoted at"Full-Scale Output Sine Wave, 997 Hz"Humm, might try at that frequency, and see if it is then within spec... maybe it is once again a case of dodgy DAC specifications.

author: fcb
author_rank: Super Contributor
timestamp: December 02, 2019, 01:31:46 am
content: Could these be idle-tones? Level does seem quite high for idle tones? How clean is your PSU?

author: BrianHG
author_rank: Super Contributor
timestamp: December 02, 2019, 02:08:56 am
content: Quote from: hamster_nz on December 02, 2019, 12:15:54 amDDR outputs are noisy. Especially when it comes to trying to get that jitter and edge noise down.Even a compiler PC internal timing simulation reveals the slight inconsistencies of a DDR output.Example, in my soft serializer simulation, if you look here:Image #1 shows the hookup.Image #5 shows the pin-pin timing with a 100ps grid.Image #7 shows a reconnect to an SDR output with DFF driving the IO.Image #9 shows a closeup of the IO skew timing with a 100pf grid.https://www.eevblog.com/forum/fpga/fpga-soft-serializer/msg2804118/#msg2804118Now, if you want to see the difference of using normal outputs and 'fast output register' outputs,Image #3 here without 'Fast output Registers', YES that's 1ns per division.Image #4 is where the output group has the 'Fast Output Register' assignment enabled. (1ns / division )https://www.eevblog.com/forum/fpga/fpga-soft-serializer/msg2803150/#msg2803150

author: hamster_nz
author_rank: Super Contributor
timestamp: December 02, 2019, 02:09:28 am
content: Quote from: fcb on December 02, 2019, 01:31:46 amUnsure of what idle-tones are, but the PSU is now quite clean (had some issues early on, but that was due to my stuff-up).When I bypass the filtering inductor on the path to the DACs Vcc I do get to see some PSU noise. The PSU noise remains pretty consistent when I change the test signal's frequency and amplitude.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 02, 2019, 02:40:05 am
content: Have you tried something very simple: sending all zeroes to the DAC and look at the output?

author: hamster_nz
author_rank: Super Contributor
timestamp: December 02, 2019, 04:06:16 am
content: Quote from: SiliconWizard on December 02, 2019, 02:40:05 amYes, all zeros will give just a flat spectrum of the background noise.When fed from the ADCs with the signal generator switched off (which should be randomly flapping around somewhere near +/- 0) gives about the same level of noise on the outputs.

author: magic
author_rank: Super Contributor
timestamp: December 02, 2019, 08:47:20 am
content: I wonder if a constant 8kHz jitter component could intermodulate with your signal to produce similar output?

author: hamster_nz
author_rank: Super Contributor
timestamp: December 03, 2019, 10:17:50 am
content: It took a while to do some testing... Tested using a 12MHz clock, and now running at ~96kS/s, then had to add logic to turn things off and on, and mute channels.The problem is 99% between the chair and keyboard.The biggest problem is that my signal generator is a 14-bit DDS - so when connected direct to the input I get the fundamental and then an harmonic at -72db or so. Not really good enough for testing audio. Image 1 is the frequency of the test signal.With the test PCB in the loop, but powered off I get image 2.With just the signal generator turned on (and everything else turned off) I get Image 3 - which is crosstalk in the testing setup - it was much worse until I moved things around on the bench. This also explains why I thought I had really poor channel separation or bits were somehow leaking between channels - it was external crosstalk.With the FPGA, ADCs and DACs turn on, but the FPGA sending zeros to the DAC (and the signal generator off) I get Image 4. I think this is pretty good - about -100db, just inside what I can measure.With the ADCs in the loop, but receiving no signal I get image 5. The noise on one channel is a PCB issue, I can change the level of noise by moving my finger around (but not touching) the ADC. Still, it is about -96db so perfectly adequate for my first hack. Be interesting to see how it looks when I build the next PCB that is better laid out.And finally with the signal generator turned on, I get image 6. I get some unexpected signal at 15kHz (-72 db) and 16.25kHz (-78 db). The spike at 20 kHz is present in the input from signal generator.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 03, 2019, 03:21:47 pm
content: For testing audio circuits, I would suggest using a good sound card instead of a typical lab signal gen (unless it's extremely good.)

author: macboy
author_rank: Super Contributor
timestamp: December 03, 2019, 05:36:20 pm
content: Quote from: hamster_nz on December 01, 2019, 08:24:03 pmActual precise frequency of MCLK doesn't matter. But make sure that it is exactly 768x (in your case) the sample rate (LRCLK). They must be synchronous. Close isn't close enough. You said about 0.01% off... well that's in the single digit kHz territory so it would explain your spurious sidebands if you are using asynchronous clocks. Page 12 of datasheet: "MCLK/LRCK must be an integer ratio".

author: jbb
author_rank: Super Contributor
timestamp: December 03, 2019, 07:09:41 pm
content: Quote from: hamster_nz on December 03, 2019, 10:17:50 amEveryone loves a test equipment surprise! Or something like that...Direct Digital Synthesis (DDS) instruments are great because they can give really consistent performance at a good price point (i.e. without a truckload of special analog components). DDS instruments are terrible because they generate artifacts in non-obvious fashion with stuff like aliasing and spurs, instead of good old fashioned harmonics and drift.The good news is that you've got an FPGA with logic resources inside. That means you can build your ownhigh resolutionDDS core to provide a well-known all-digital test waveform with lots of bits. I got very good use out ofthis magazine articlewhen design a DDS in the past.Let's see what we can do:Set output widthM=16 bitsExpect SNR = −6.02M−1.76dB = -95 dBSet phase resolutionP=M+ 1 = 17 bitsFor sine LUT, only store 1/4 of the full wave; save 2 bits of length. LUT length = 2^(P-2) = 32768 entriesFor sine LUT, only store sine(phi)-2 phi / pi; save 2 bits of word size. LUT word size =M-2 = 14 bits.Note: the word size tweak may be pointless given the properties of your FPGA block RAMs...The LUT will be quite large (further compression methods are available if you feel keen, see the magazine article), but should still fit into many cheap FPGAs. What FPGA are you using?Given that the output rate is going to be much less than the FPGA clock rate, you can (with suitable address/data multiplexing) re-use the LUT for multiple DDS generators. So you could generate multiple independent tones for things like IMD testing.

author: hamster_nz
author_rank: Super Contributor
timestamp: December 03, 2019, 08:10:46 pm
content: Quote from: jbb on December 03, 2019, 07:09:41 pmExactly - which is what I am building this board for, it's a platform for mucking around with DSP. I also have used CORDIC before, so generating next-to-perfect 24-bit samples is a piece of cake... (well, maybe '24 successive better approximations' would be a bit closer to the truth than a 'piece of cake').

author: hamster_nz
author_rank: Super Contributor
timestamp: December 03, 2019, 08:35:33 pm
content: Quote from: macboy on December 03, 2019, 05:36:20 pmWhen using the PLL, the MCLK I'm using is 36.86311 MHz (rather than the "on spec" 36.864), and the SCLK and LRCLK generated by dividing that down (2.303 MHz and 47,999.1 S/s, and twice that when running at ~96kS/s), so everything is derived from the same reference clock.I've also been using just 36.0MHz (to avoid fractional multiply/divide in the FPGA's MMCM) which is 46,875 S/s, to see if that makes a difference.

author: bson
author_rank: Unknown
timestamp: December 05, 2019, 08:25:15 pm
content: Quote from: hamster_nz on December 03, 2019, 08:35:33 pmIs that an integer-N synthesizer? If so, there's another potential source of spurs.

author: capt bullshot
author_rank: Super Contributor
timestamp: December 05, 2019, 09:04:39 pm
content: Quite an interesting topic.Having read all the posts, IMO the side frequencies are a result of some non-exactly matching frequencies (MCLK to SCLK/LRCLK ratio or phase noise), maybe even internal to the DAC chip. Looks like this chip has some kind of internal "magic" re-sampling capabilities that might play a tricky game on you. So my only advice would be to avoid any kind of FPGA specific clock generator circuitry, feed the FPGA directly from e.g. a 36MHz oscillator and derive all frequencies by using your own (simple) dividers to ensure exact integer ratios of these frequencies. I wouldn't expect side tones like the ones you shown from even the cheapest audio DAC.As others said, for the ADC/DAC to operate properly in an isolated setup like yours, it isn't necessary to hit the exact 36.864MHz MCLK, anything within some MHz around will do as long as the other criteria (integer and synchronous ratio MCLK to SCLK) are met.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 05, 2019, 09:13:44 pm
content: Quote from: hamster_nz on December 03, 2019, 08:35:33 pmFor generating the bit clock (SCLK?) it's fine IMO, but I don't think it's a good idea for generating LRCLK. I usually generate both the data output bits AND LRCLK from SCLK in a process.

author: hamster_nz
author_rank: Super Contributor
timestamp: January 06, 2020, 06:13:05 pm
content: A very late update. The next revision of the board was much better - improved grounding (well, half-decent grounding) got rid of a lot of noise, and the output is looking much cleaner.Next up I want to replace the electros with equivalent MLCCs on one side of one channel and see if it makes a measurable difference...Pictures are top-to-botom:- New board- Old board- Signal generator direct to input.