Preparing 16bits for 24bit playback methods
T Chap
Posts: 4,223
I have hacked together various objects to create an I2S SD wav player engine. It is an SD card file reading method to get stereo 16bit wav files into a dual buffer, then drive a DAC engine in PASM that transfers the 16 bits out in a 24bit I2S format(MSB first) to the DAC that wants signed data. The test is a 5 second simple sine wave that is 16 bits stereo in a wav file. The buffer is transferring the entire file, but what I hear is cyclical white noise with a hint of tone to it.
I adapted a PASM method of transferring the 24 bits with the MSB output shown below:
I think the distortion of data may be a result of the method I have tried to use that does the Rotate and Carry Left.
RCL info: If the WC effect is specified, at the end of the operation, the C flag is set equal to Value’s original bit 31.
But, I am not working with 32 bits, I am working with 16 bits shifted left to 24 to allow the sign bit of 16 bits to sit at bit 24 so that the output is 24bit signed.
LeftData long 0
RightData long 0
Since LeftData and RightData are longs( originally filled with a 16bit word, then bitshifted left), I am thinking the RCL is not doing what it did in the original version that Mark T posted.
Bottom line is, can anyone suggest a method to take signed 16 bits, move it to 24 bit format maintaining the sign, then allow the each of the 24 bits to be prepared for output one at a time based on my bitclock as the timing?
I do not want to convert the individual outputs to a loop concept, as the LSB requires a LR clock to toggle before it is sent, and I found that injecting code to insert it in a loop was affecting the timing, so it is best to keep the 24 x 2 = 48 sections as it is easier and less headaches since the timing is already pushed to far on the Prop.
I adapted a PASM method of transferring the 24 bits with the MSB output shown below:
:bit23 rcl LeftData, #1 WC muxc OutPutMask, DataOutPinMask ' SETUP Data bit MSB WAITPEQ HIGH, bclkMSK WAITPEQ LOW, bclkMSK ' Must Wait for Bitclock LOW to change output mov OUTA, OutPutMask ' DRIVE Data
I think the distortion of data may be a result of the method I have tried to use that does the Rotate and Carry Left.
RCL info: If the WC effect is specified, at the end of the operation, the C flag is set equal to Value’s original bit 31.
But, I am not working with 32 bits, I am working with 16 bits shifted left to 24 to allow the sign bit of 16 bits to sit at bit 24 so that the output is 24bit signed.
LeftData long 0
RightData long 0
Since LeftData and RightData are longs( originally filled with a 16bit word, then bitshifted left), I am thinking the RCL is not doing what it did in the original version that Mark T posted.
Bottom line is, can anyone suggest a method to take signed 16 bits, move it to 24 bit format maintaining the sign, then allow the each of the 24 bits to be prepared for output one at a time based on my bitclock as the timing?
I do not want to convert the individual outputs to a loop concept, as the LSB requires a LR clock to toggle before it is sent, and I found that injecting code to insert it in a loop was affecting the timing, so it is best to keep the 24 x 2 = 48 sections as it is easier and less headaches since the timing is already pushed to far on the Prop.
Comments
So I think all you need to do is change the #8 to #16 in this section:
I would try to change the code for the single bits to: Because this spares one instruction you can now output the bits in a loop. Here is a draft of an alternative output loop, that also minimizes hub access. It does not handle the buffers.
Andy
The idea to go direct with muxc to outa is still distorted. I will work on your new loop idea instead and other suggestions to see what happens.
left-justified and right-justified modes.
So one does: synchronize to BCLK falling edge and set LRCLK, synchronize to next BCLK falling edge and output MSB, etc etc.
Inputs are sampled on the rising edge of BCLK.
On one channel, I am getting tons of distortion but can clearly hear the sample. The other side is much clearer but still clipping. I wonder if there is any gain being introduced by moving the data left the equivalent of 8 bits(16 bits moved to align to MSB of long)
Do you have a Scope to watch the signals?
Andy
Ariba, I don't have the bitclock set perfect yet, I have it is a cycle length of .5uS. It should be slightly less than that to be perfect. I have added a PLL1708 master clock that feeds the dac at 768*44100 and feeds the Prop at 384*44100. The Prop has a counter dividing it down and syncing the start of the bitclock to 48 clocks per sample(2 * 24 bits).
The flags show the start of the bitclock at the MSB. There are 25 bits per LR clock, one clock is padding at the end of the data.
I have a Propeller board with a Wolfson Audio DAC here (WM8762) but had not yet the time to play with it.
Andy
Very interested in audio & my main first project will be to use this board as a test board to evaluate various DAC chips, some of which will be non-audio chips.
So looking for an easy to program/configure solution which can deal with the various chip communication interfaces I2S, RJ, LJ (and all the variants of these), parallel, etc.
T Chap - this looks like a good starting point & look forward to seeing your finished code
BTW, you might be getting away with using a non-synchronous clock because it is the ES9023 chip you are using which can work with an asynch or synch clock. Sounds better with a synch clock, though.
What are you using as a signal analyser, btw - I'm looking for a good cheap solution?
I have the Saleae Logic analyzer that Parallax has on their site, it has built in options to examine various formats including I2S. I also have the PropScope for simple and portable uses. Now that the idea is flushed out for the I2S data flow, connecting other devices is easy. I have an external master clock that the Prop derives it's bitclock and word clock from, but on the 9023, I am not sure that the Prop couldn't generate all the clocks needed for simple audio playback needs depending on the xtal.
These files are a mess, most of this is my first real effort to start learning PASM, so there is room for improvement. I included the ariba starting point but it needs a good deal of work still.
Audio_SDPlayer launches the external master clock, then the bitclock engine, dac engine, and manages the SD reader FSRW.
The code is derived from Raymans QMP player which uses a double buffer handled in SPIN using FSRW. The DAC engine was derived from Mark T's Wolfson I2S DAC code, although his original code was left justified and I have modified it to I2S which is slightly different.
I did study Kye's FAT engine, V2 player etc, but it was too far over my head to dissect it and convert. Although, at this point with a working DAC output, it would be much easier to adapt to any other buffer method. For me, the hardest part is getting a clear mental picture of all of the elements that must work together: 1. Reading the SD into a dual buffer with empty flags(level meters as Jonny Mac says). 2. Putting the data into a format that can be sent to the DAC chip. 3. Determining the bitclock and LR clock timing. 4. The DAC pcb.
For my own purposes I intend to create a simple graphic for future reference of the elements to make it work.
As I said, I'm looking into this prop board for evaluating various DAC chips so I want to ensure optimum operation to be able to achieve this (or as optimum as I know how).
My concept for the eventual config for this design is two external audio clocks - one for each speed family. One of which is enabled depending on what the samplerate of the audio file being played. This can be determined when the start of the file is read & an enable signal sent out through one of 2 prop pins. The enabled clock signal being fed back to the prop & all clocking is then synchronous. Does this make sense & how feasible is it to implement?
If you see this datasheet, notice that is shows quite a few more bitclocks than actual data bits, so it is ignoring anything past the LSB bit 0.
To be honest, I am very new to figuring this out, these are just my perceptions and discoveries so far, which can easily be wrong.
And if my idea is feasible of using 2 independent external audio clocks (only one being enabled to suit the speed family of the audio signal)?
I thought I read somewhere that the prop can be run solely from an external clock but this may have been with the Teensy board which I'm also looking into?
If you can possibly use a single crystal clock source for all parts then do so. Otherwise you have to pay extra close attention to data synchronisation.
But, I'm new to this can the Prop use an external clock for it's timing?
Yes, look up _CLKMODE in the Prop manual