Search This Blog

Saturday, July 28, 2018

Project Swiftlet - Audio playback

Projects / Project Swiftlet  Original post date: 09/20/2015

AK4386 DAC requires a MCLK for its internal clock that is a multiple of the sampling frequency fs. It is an inexpensive simple DAC that requires no I2C programming. There are no internal fancy resampling PLL, so all its clock signals have to come from the I2S master.


One possible setting is MCLK is 8192 x 512 = 4.194304MHz Now that sounds innocent enough until you read the buried fine prints aka the "Chip Configuration" chapter in the KL16 reference manual. That chapter is Freescale's lazy way of telling you how they wired the individual peripheral blocks together instead of them maintaining the information in the actual chapters.

"That's right Al -- you lost. And let me tell what you didn't win" - Weird Al, "I Lost On Jeopardy"

Have you ever wonder why they show features that are not available in the peripherals chapter?

Lesson of the day: Read that chapter and errata when you are designing your hardware.

Not sure what they are thinking as not having a programmable MCLK. Sometimes, you cut too much corners to make a cheap part only to makes the feature not usable. ¯\_(ツ)_/¯

Note: Even though you can set the values of the MDR in the debugger, scope probing test shows MDR has no effects on the output frequency IRL.

Clock dividers are cheap and Freescale even use the more fancy fractional dividers for other on-chip peripherals except here for MCLK generation. Normally if you use a high frequency crystal, you can just pick one that matches the MCLK and hope you ever need to deal with fixed I2S speed. In the case of using the 32kHz clock and FLL, you are SOL as there are very limited fixed multiplier ratios available nor the crystal frequency is fast enough for MCLK. Or you can use a more expensive DAC that can source MCL, but Freescale isn't the one making money on the DAC.

I was reading this just before I went to bed. I couldn't sleep as I was trying to find a way around it. I then realized that the "System Clock" has a programmable divider, so as long as I am willing to live with the consequences of changing it on the fly.


FLL frequency = 32768Hz x 640 = 20.97152MHz. Divide it by 5 yields 4.194304MHz so setting DIV1 to div by 5 would do the trick. Scope probing shows that Freescale didn't cut corners on the divider as it shows 50% duty cycle for even a odd number divider.

The BICK is set to either x32 or >= x48, so I pick 8192Hz x 32 = 262.144kHz. The higher numbers are for higher than 16-bit resolution.


Telling the ARM that "Sync Width = 0x0f ", "Word 0 Width = 0x0f " and "Word N Width = 0x0f " seems to set the right frequency for Frame Sync signal fs = 8192Hz.

The digital waveforms like excellent - perfect square waves even for the MCLK that is on the opposite side of the chip. Very short traces, good ground returns helps.

FYI: Currently there are no known open source working code for the audio playback as of the original posting of this. There are no I2S support for Teensy LC nor ChibiOS.

Got much closer last night. DMA is now working and the playing back take about the right amount of time. No idea where the data is going as there is no audio. Probably something very simple that I overlooked. Got to get the dreaded video done today to meet the contest requirement. Going to be a boring video.

Seen AN4486 "MPC5604E Serial Audio Interface" a few times, but I wasn't really reading it. Interesting tidbits concerning the register settings for I2S setting in Chapter 5.2. The register bits are named differently, but the important parts are in the comment field.

While I more or less had most of these set correctly, it is still worth while to know what I don't need to change.

• The maximum supported frame size depends on SAI implementation. I2S requires two words per frame. Frame sync width – configures the length of the frame sync in number of bitclocks. The sync width cannot be longer than the first word of the frame. I2S requires frame sync asserted for first word.
SAI0.STCR4.B.FRSZ = 1; /* Configures number of words in each frame. The value written should be one less than the number of words in the frame. */
SAI0.STCR4.B.SYWD =31; /* Configures length of the frame sync. Example for I2S and 32-bit words are transmitted. The value written should be one less than the number of bitclocks. */
SAI0.STCR4.B.MF = 1; /* MSB is transmitted first */
SAI0.STCR4.B.FSE=1; /* Frame sync asserted one bit before the first bit of the frame */
SAI0.STCR4.B.FSP=1; /* Frame sync is active low */
SAI0.STCR4.B.FSD = 1; /* Frame sync is generated internally (Master mode) */
• Configure the Word 0 and next word sizes and first bit shifted. W0W – defines number of bits in the first word in each frame. The maximum supported bits in the first word in each frame are 32 bits. Words of fewer than 8 bits wide are not supported if there is only one word per frame. WNW – defines number of bits in each word for each word except the first in the frame. The maximum supported bits in the first word in each frame are 32 bits. Words of fewer than 8 bits wide are not supported.
SAI0.STCR5.B.WNW = 31; /* Number of bits in each word in each frame except the first word. Example for I2S and 32-bit words are transmitted. */
SAI0.STCR5.B.W0W =31; /* Number of bits in first word in each frame. Example for I2S and 32-bit words are transmitted. */
SAI0.STCR5.B.FBT = 0; /* Configures the bit index for the first bit transmitted for each word in the frame. */
• Clear the Transmit and Receive Mask registers.

SAI0.STMR0.R=0; /* Enable or mask word N in the frame. */
I have been playing with Processor Expert (PE) and it insists on not letting me select 8-bit data as the MSB for I2S playback. The reference manual leads me to believe that's possible. May be PE is right.

Anyway, I came up with the idea of first copying a 8-bit value to the MSB of a 16-bit variable by DMA and then link a 2nd DMA to copy the 16-bit word to the I2S peripheral thus doing a cheap conversion on the fly.

I also found out that I swapped the LRCLK and the BICK signal at the DAC. I fixed that by cutting traces and connecting the right signals together with fine magnetic wires. Now both the converted 16-bit sample and my old 8-bit code from yesterday sort of works.

I managed to get some noise from the speaker. It is a bit distorted. I think it is a matter of getting the right bits set and scaling the signal level down. At least now the bits seems to be going in the right place on the chips. The 1.5V boost converter is too noisy, so just have to use Li-ion battery until that's fixed.


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.