Go Back   Home > Forums > Blogs > googlyone

Rate this Entry

PIC32MX450F256 as DDS core driving CS4398 DAC

Posted 18th December 2013 at 10:35 AM by googlyone
Updated 18th December 2013 at 10:38 AM by googlyone

Over the last couple of months I have been playing with a PIC32MX450F256H as the DDS core, and using one of the many DAC boards I built for my DSP based crossover as the D/A element.

It has taken a while to get up and running - mainly due to me actually having commitments other than a hobby... (Bugger)

That said, getting this thing up and running also required me to get my head around the microchip XC32 compiler, and the configuration bits in the PIC32MX.

On the compiler, the most serious issue is the schemozzle they call documentation. I imagine if all you wanted to do was simple I/O and stuff you might be OK. As soon as you want to dig into the more detailed registers, the high level library documentation is borderline useless, and spread over a number of directories and the Microchip website. Very frustrating.

The other challenges I had were:
- To set up the PIC I2S interface such that there was no jitter on the LRCLK line.
- To set up multi level interrupts such that the PIC did not go into a permenant state of interrupt on the I2S interface.
- To port my code from the PIC18FXXX to PIC32MX

The key to this DDS working is getting a really REALLY stable LRCLK, and using this as the DDS timing reference. This allows the PIC micro to do the DDS calculations in it's own time, knowing that the data will be clocked out at exactly the next DAC clock interval.

The way the PIC micro generates SPI clocks (which also generate the I2S by re-purposing the interface) is by dividing the internal master clock, and if necessary dithering this to get "exact" clock intervals.

This is no good for this application, as having dither on a DDS is (almost but not quite) the same as having crap amplitude precision.

The SPI interface uses a "integer divider" and a "trim" divider. By using a divider of 4, and ZERO for "trim" you get no dither, and a nice stable SPI clock rate with no jitter.

An additional trick you need to achieve is to convince the compiler to configure the SPI interface to use the "enhanced" SPI mode, which gives you more than a single word in the SPI transmit FIFO. Why? For some insane reason the default setup uses a single word buffer, which if you enable interrupts on the SPI interface asserts the interrupt as soon as the data starts being read. Which means ALWAYS. After much hair pulling I found the documentation on the SPI configuration hidden in a deep dark folder in the microchip directory. Why you would default to this setup is beyond me though.

So with the micro running, and:
- An ISR running to feed the I2S (SPI) interface
- An ISR running to run the user interface

I had the chance to set up the actual DDS code. The initial program I wrote uses:
- a 32 bit phase accumulator (big I know but works)
- A lookup table for the sine wave that has 32 bit amplitude resolution, and 4096 samples (in time)

In between samples the code uses a linear interpolation, which gives at worst 2 odd bits amplitude error. The approach used is:
- Right shift the phase accumulator 20 bits, resulting in a 12 bit lookup for the sine table
- Mask off the bottom 20 bits of the phase accumulator, and use this to calculate a linear interpolation between the Sine lookup value and the "next value" in the sine lookup table.
- Add the sine lookup and the interpolation.

Hey presto - not quite 24 bit precision, but damn close!

The current state of the code is that I have a pair of independent DDS's running in software, one on each of the L and R channels of the DAC.

The PIC micro seems to be about 20% loaded doing this - that said, I do need to convince myself further that the timing flags I am generating in the ISR are accurate.

The HMI also has the following coded in:
- Phase offset between channels. (easy to add in)
- AM - this will use another simple DDS, should be OK to add
- FM - this will use another dimple DDS, and possibly be "either / or" with AM, should be OK to add
- Pulse modulation - this will be a simple "zero crossing count" and is already in the code.
- Frequency Sweep - is a simple linear start / stop sweep, easy to add.

I will be fascinated to try measuring the distortion on this - though about the only choice I will have in my test gear box is either my sound card or the ADC on my crossover. I suspect I will be able to tell if the implementation is grossly wrong, but not if there is a more subtle issue.

So as far as the experiment to see if the PIC can make a decent fist of high fidelity signal generation, as long as you are happy with a slightly odd sample rate on the DAC, the answer is absolutely yes.
Posted in Uncategorized
Views 1085 Comments 0
Total Comments 0



New To Site? Need Help?
Copyright 1999-2017 diyAudio