Teensy 4.0, I2S, AudioPlayQueue, Timer interrupts & more

Status
Not open for further replies.
Cheers people, hope everyone is okay!

I've been working on an audio project with T3.6, recently migrated my code to T4.0 and I'm facing several issues/problems that I don't really know how to solve. I'm bumping my head against the wall. Just hope somebody can help, it's a long shot but I have to try :)

General description
I'm using an 44.100Hz timer interrupt (basically a uint16 counter that wraps around every 1.486s) to generate and process the audio signal. Processed audio is (or it should be) stored into an 128-word int16 buffer array, which is then fed to AudioPlayQueue 512 times in one counter cycle (~345 times per second). AudioPlayQueue is connected to the I2S output in Audio System Design Tool and processed by PCM1681 DAC (or SGTL5000 Audio Shield).

Code:
#include <Audio.h>
AudioPlayQueue           audio;
AudioOutputI2S           i2s1;
AudioConnection          patchCord1(audio, 0, i2s1, 0);

#define SAMPLE_RATE 44100
#define BLOCK_SIZE 128
static uint16_t cycle=0;
static int16_t waveform[BLOCK_SIZE];
static int16_t input;
extern const int16_t wavetable[2048];

void audioInt()
{
  uint8_t cbX=cycle%(BLOCK_SIZE);
  input=wavetable[cycle>>5];
  // do some audio processing
  waveform[cbX]=input;
  if (cbX==(BLOCK_SIZE-1))
  {
    int16_t *p1 = audio.getBuffer();
    memcpy(p1, waveform, BLOCK_SIZE<<1);
    audio.playBuffer();
  {
  cycle++; // automatically reset at 65536
}
void setup()
{
  noInterrupts();
  AudioMemory(128);
  IntervalTimer *t1 = new IntervalTimer();
  t1->begin(audioInt, 1000000.0f / (float)SAMPLE_RATE);
  interrupts();
}
void loop()
{  
  //read some inputs
}

1. AudioPlayQueue and speed
Description of AudioPlayQueue.getBuffer() states "This buffer is within the audio library memory pool, providing the most efficient way to input data to the audio system", but I'm not really sure I'm doing this the most efficient way. Couldn't find any meaningful instructions about AudioPlayQueue anywhere, very poorly documented stuff. It's rolling in an audio rate interrupt, gets executed 345 times per second together with other greedy math-crunching stuff going on in the rest of the cycles, and I wonder is there any faster/better way to do this? Especially because I'm using more than one channel of audio :rolleyes:
Code:
    int16_t *p1 = audio.getBuffer();
    memcpy(p1, waveform, BLOCK_SIZE<<1);
    audio.playBuffer();
Do I absolutely have to get a new *p pointer for every new transfer? Is there a better/faster/more efficient way to transfer the array to AudioPlayQueue.getBuffer() pointer than memcpy? Is there a way to write directly to I2S DMA buffers without using AudioPlayQueue? I've stumbled upon class AudioOutputI2S : public AudioStream in <output_i2s.h>, but I have no idea can that be used or how to use it :confused:

2. T4.0 vs. T3.6 issue
This code worked without a problem on T3.6 for hours, but now on T4.0 it works for maybe 3 minutes and then my Teensy freezes. I checked AudioProcessorUsage and AudioMemoryUsage, CPU stays under 0.5% but AudioMemory consumption increases every few seconds until it exhausts completely. Doesn't matter even if I declare AudioMemory(512) in Setup, it will freeze somewhere around 160 - maybe it's not even related, I have no way to tell. I can only speculate that AudioPlayQueue.getBuffer() doesn't release memory after AudioPlayQueue.playBuffer() is executed :eek: Maybe the problem that isn't normally obvious happens because of the interrupt routine and the speed? Is this a bug or am I doing something wrong? Like I said, it worked like a charm on T3.6 :confused:

3. I2S issue
I solved this one in the meantime, turns out the problem was between the monitor and the chair :D

P.S. two more bits at the end: Is it better to use 44.117 instead of 44.100 sample rate for I2S on T3.6/T4.0? Also can I make I2S on T4.0 work at 22.050Hz and how?
Thanks in advance for your kind answers, stay safe. And a big thank you to Paul and everybody else involved in Teensy development :cool:
 
follow up

Hi,
Were you able to solve these issues?

Thank you


Cheers people, hope everyone is okay!

I've been working on an audio project with T3.6, recently migrated my code to T4.0 and I'm facing several issues/problems that I don't really know how to solve. I'm bumping my head against the wall. Just hope somebody can help, it's a long shot but I have to try :)

General description
I'm using an 44.100Hz timer interrupt (basically a uint16 counter that wraps around every 1.486s) to generate and process the audio signal. Processed audio is (or it should be) stored into an 128-word int16 buffer array, which is then fed to AudioPlayQueue 512 times in one counter cycle (~345 times per second). AudioPlayQueue is connected to the I2S output in Audio System Design Tool and processed by PCM1681 DAC (or SGTL5000 Audio Shield).

Code:
#include <Audio.h>
AudioPlayQueue           audio;
AudioOutputI2S           i2s1;
AudioConnection          patchCord1(audio, 0, i2s1, 0);

#define SAMPLE_RATE 44100
#define BLOCK_SIZE 128
static uint16_t cycle=0;
static int16_t waveform[BLOCK_SIZE];
static int16_t input;
extern const int16_t wavetable[2048];

void audioInt()
{
  uint8_t cbX=cycle%(BLOCK_SIZE);
  input=wavetable[cycle>>5];
  // do some audio processing
  waveform[cbX]=input;
  if (cbX==(BLOCK_SIZE-1))
  {
    int16_t *p1 = audio.getBuffer();
    memcpy(p1, waveform, BLOCK_SIZE<<1);
    audio.playBuffer();
  {
  cycle++; // automatically reset at 65536
}
void setup()
{
  noInterrupts();
  AudioMemory(128);
  IntervalTimer *t1 = new IntervalTimer();
  t1->begin(audioInt, 1000000.0f / (float)SAMPLE_RATE);
  interrupts();
}
void loop()
{  
  //read some inputs
}

1. AudioPlayQueue and speed
Description of AudioPlayQueue.getBuffer() states "This buffer is within the audio library memory pool, providing the most efficient way to input data to the audio system", but I'm not really sure I'm doing this the most efficient way. Couldn't find any meaningful instructions about AudioPlayQueue anywhere, very poorly documented stuff. It's rolling in an audio rate interrupt, gets executed 345 times per second together with other greedy math-crunching stuff going on in the rest of the cycles, and I wonder is there any faster/better way to do this? Especially because I'm using more than one channel of audio :rolleyes:
Code:
    int16_t *p1 = audio.getBuffer();
    memcpy(p1, waveform, BLOCK_SIZE<<1);
    audio.playBuffer();
Do I absolutely have to get a new *p pointer for every new transfer? Is there a better/faster/more efficient way to transfer the array to AudioPlayQueue.getBuffer() pointer than memcpy? Is there a way to write directly to I2S DMA buffers without using AudioPlayQueue? I've stumbled upon class AudioOutputI2S : public AudioStream in <output_i2s.h>, but I have no idea can that be used or how to use it :confused:

2. T4.0 vs. T3.6 issue
This code worked without a problem on T3.6 for hours, but now on T4.0 it works for maybe 3 minutes and then my Teensy freezes. I checked AudioProcessorUsage and AudioMemoryUsage, CPU stays under 0.5% but AudioMemory consumption increases every few seconds until it exhausts completely. Doesn't matter even if I declare AudioMemory(512) in Setup, it will freeze somewhere around 160 - maybe it's not even related, I have no way to tell. I can only speculate that AudioPlayQueue.getBuffer() doesn't release memory after AudioPlayQueue.playBuffer() is executed :eek: Maybe the problem that isn't normally obvious happens because of the interrupt routine and the speed? Is this a bug or am I doing something wrong? Like I said, it worked like a charm on T3.6 :confused:

3. I2S issue
I solved this one in the meantime, turns out the problem was between the monitor and the chair :D

P.S. two more bits at the end: Is it better to use 44.117 instead of 44.100 sample rate for I2S on T3.6/T4.0? Also can I make I2S on T4.0 work at 22.050Hz and how?
Thanks in advance for your kind answers, stay safe. And a big thank you to Paul and everybody else involved in Teensy development :cool:
 
Were you able to solve these issues?

Hi, alfa66. Nope, I tried a zillion workarounds and nothing worked as it should :(
It took me a looong time to convert everything into AudioLibrary objects, but finally I have a code base that works flawlessly. Built an 8-ch synth around it, no problems whatsoever!
 
Hey there, sorry to revive your old thread, I was just curious about your DAC setup. Are you using the PCM1681, did it work straight away in I2S mode? Could you share any more code/info about it? Thanks.
 
Hey there, sorry to revive your old thread, I was just curious about your DAC setup. Are you using the PCM1681, did it work straight away in I2S mode? Could you share any more code/info about it? Thanks.
Hey there, no need to apologize :) Yes, PCM1681-Q1 is my workhorse and it worked straight away with T4 in both I2S and TDM mode. I'm using it in hardware config because it requires no pins or code from Teensy.

PCM1681 hardware config:
MSEL (pin 14) - 220k resistor to Vdd
FMT1 (pin 2) to Gnd, FMT0 (pin 1) to Vdd - I2S mode
DEMP (pin 3) to Gnd
MUTE (pin 4) to Gnd

Connection to T4:
SCK (pin 5) to T4 SCK (pin 13)
DATA1 (pin 6) to T4 OUT1A (pin 7)
BCK (pin 7) to T4 BCLK1 (pin 21)
LRCK (pin 8) to T4 LRCLK1 (pin 20)

If you need any more info, feel free to ask.
Cheers!
 
Thanks a ton, I will give this chip a try :) It's the cheapest way I've seen thus far to get this many channels.
 
Status
Not open for further replies.
Back
Top