Teensy LC, audio library support?

Ok, great!
Glad that it works now.

You can further reduce the memory by using a lower number for AudioMemory(12);
Apparently it still works with AudioMemory(1); Does that make sense?

In this simple case with a sine only, yes, its correct.
When the PT8211, releases the used block, it is used by sine immedeately which then sends it to output again..
Note, on all other Teensys, 1 will not work, due to the double buffering of blocks.
The double buffering design, in hindsight, was a mistake on my part. Eventually it should get removed from all the output objects.

In the earliest days of the audio library, back in late 2013, I was overly cautious about so many things. Double buffering seemed like a good idea. And back then, so many other aspects of the system weren't stable, so some mistakes I made with other things seemed at the time to confirm the need for double buffering.

In fact, double buffering isn't needed at all. Usually isn't never even used. Typically the 2nd pointer always remains null. So AudioMemory(1) might work on Teensy 3.x & 4.x too.

I have known about this for years, but the only harm is a few extra bytes of memory and some unnecessary code, so it's been pretty much at the very bottom of my long list of issues. The only case where double buffering does come into play is when something anomalous happens (exactly what, I haven't investigated... remember, low priority issue) and the 2nd pointer ends up getting an allocated block. From that point forward, the interrupt always end up using data from the 2nd pointer. So the net result is an extra 2.9ms output latency is added forever (until reboot). If that anomalous thing happens again, you get an audio dropout or repeat, because there's no 3rd buffer pointer.

So if anyone cares about this, I would love to merge any well tested pull requests which remove the 2nd buffer. But please don't send a PR which hasn't been tested on real hardware. The last round of changes for cache management added bugs which made their way to users, because not all were tested. I want to avoid that when/if the buffering is changed.

@Frank - if you need any hardware for testing, just email me and we'll get you whatever you need. (I might have new CS42448 boards in the works....)
So AudioMemory(1) might work on Teensy 3.x & 4.x too.

Oh, I must have read the code wrong.
Next I try I2S slave mode on the Teensy LC. If nobody else does it, I'll add a pullrequest re: the 2nd buffer, later, too.

And I want to make a list of supported audio chips and microphones in the WIKI. Or does such a list exist?

Paul, I'll send you a mail.
While checking the output signals on the oscilloscope I noticed that the left channel [yellow] is trailing behind by 1 BCLK period when sending out a mono 10kHz sine on both channels:


By the way, on a Teensy 3.2. [at 4x oversampling], the left channel is also trailing behind by 1 BCLK period:


Is this a property of the PT8211? Or is this perhaps code related?

I think this is due to the inner working of the PT8211. It has no MCLK that other chips may use for this purpose?
It is a cheap, cost optimized product, as well as the Teensy LC CPU. Freescales calls it "ultra low-end microcontroller" in the reference manual :)
I wonder how they would call the ATMEL 8-Bit products.

The PT8211 datasheet is here: https://www.futurlec.com/Datasheet/Others/PT8211.pdf
On the scope, for me, the timining looks like as required. Or, maybe you want to look at it? YOu can cheat a bit and comment-out "interleave" in the ISRs and replace the memsets at the beginning with a loop that fills both channels with 0x01. This way its more easy to verify the timing.
Thanks for your reply.
By the way, there is newer datasheet on the PJRC website.
I may hookup the logic analyzer and check the I2S frames [I'm not sure what I'm exactly doing when I start modifying that particular ISR code...]

Hm I think the only bits remaining that can have an influence is the Bit Clock Polarity (BCP) and the Frame Sync Polarity(FSP).
I modified both, but the result is always the same on my scope.
Yeah, it's the DAC that causes the 1 BLCK period shift of the left channel.
Here is what the logic analyzer shows:


Identical data for right & left 16 bit sample, 0x00008540.
Timing of the I2S frame is according to the datasheet of the PT8211:


Data is sampled on the rising edge of BCLK.

From the paragraph below the figures: "The buffered DIN data then feeding to the DAC after both input register are all settled down, this can eliminated the phase shift happened between two channel output."
Well, the phase shift is unfortunately not eliminated - it's off by 1 BLCK period.


so..next step... make the LC work with the Audio Shield.
The LC can output 16MHZ on MCLK, which is perfect for the SGTL-5000:

The datasheet says:
Clocking for the SGTL5000 is provided by a system master clock input (SYS_MCLK). SYS_MCLK should be synchronous to the sampling rate (Fs) of the I2S port. Alternatively any clock between 8.0 and 27MHz can be provided on SYS_MCLK and the SGTL5000 can use an internal PLL to derive all internal and I2S clocks. This allows the system to use an available clock such as 12MHz (common USB clock) for SYS_MCLK to reduce overall system costs.

So, as first step, I'll try to modify the SGTL-5000 code and enable its "I2S Master mode". If that works, I'll add the I2S-Slave code for the LC.
So, as first step, I'll try to modify the SGTL-5000 code and enable its "I2S Master mode".
That works good. I see 44100Hz, with corresponding bitclock, created by the SGTL PLL. But I was unsuccessful to create 441117.6 with it.

To be continued soon
Last edited:
Managed to kill my last LC by unintentional, brute force applied to the poor usb connector.... ordered a new one.
If that was one of the purple prototypes - yeah, it was weak because I hand soldered it without any way to solder the underneath pads (I don't use a reflow oven)
So, I have time now, and so I played a bit with excel.
SampleFrequency = PLL_FREQ / 4096

To create the PLL Frequency we have a "div" and a "frac" field. "Frac" ist float, and gets multiplied by 2048 for fixed point representation.
We can archieve 44116,9739 Hz with (int)div=11, (int)frac = 602 (gives 16MHz * (div + frac / 2048) = 180703125Hz. this / 4096 gives 44116,9739 Hz )
(could not measure it - that's my math result)

My question: What is better? 44100Hz, or 44116,9739Hz? The latter would be more close to the rest of the library.
I would want 44100, like Sony & Phillips...

Very glad to hear that the 2 dma channel / 2 irq code for LC is already done. I looked at the reference manual for the mkl26 yesterday and it seemed to me that would be our solution.
If you want to connect a PCM5102 DAC board to a Teensy LC, you have to change output_pt8211.cpp, line 606, from:
I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF [COLOR="#FF0000"]/*| I2S_TCR4_FSE*/[/COLOR] | I2S_TCR4_FSP | I2S_TCR4_FSD;
I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | [COLOR="#FF0000"]I2S_TCR4_FSE[/COLOR] | I2S_TCR4_FSP | I2S_TCR4_FSD;

Yes, I hope I can make it work with the Audio Shield (SGTL-5000 in I2S-master-mode), too.

I can :) The new Teensy LC arrived.

SGTL-5000 sine (44116,9739Hz sample frequency):


However, I need to find a way, NOT to initialize the SGTL-5000 after a reset. Otherwise it stays silent...
Tomorrow is another day.
Last edited:
I have created some PR, hoping that Paul will merge them.

- Code for the PT8211 (tested and working)
- Audio-Lib fixes for the LC, so that it does not come to errors when compiling.
- AudioControlSGTL5000 now supports master mode.
There is a new variant of enable() for this:
bool AudioControlSGTL5000::enable(extMCLK, pllFreq)
For the LC this is called automatically - so enable() still works here too. In your Sketch is no change needed.

- AudioOutputI2S: Is now in, but completely untested. Maybe someone wants to test this with the PCM1502?
- AudioOutputI2Sslave: tested with the SGTL-5000

To get the sampleplayer working with the Audioshield only two changes are necessary.
- In the sample player code AudioOutputI2S has to be replaced by AudioOutputI2Sslave.
- In AudioStream.h change the blocksize to 128.

Note: I2S-Input is TBD. Not sure when I have time for this. Maybe tomorrow, maybe next week.
Last edited: