Teensy LC, audio library support?

- AudioOutputI2S: Is now in, but completely untested. Maybe someone wants to test this with the PCM1802?

Hi Frank, just tested this a few minutes ago. Copied both output_is2.cpp & output_is2.h from PR #377 to C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Audio\.
Using this sketch...
Code:
// PCM5102 bd   Teensy LC
// VCC          5V
// GND          GND
// LRCLK        23
// DIN          22
// BCK          9

#include <Audio.h>

AudioSynthWaveformSine   sine1;
AudioOutputI2S           i2s1;
AudioConnection          patchCord1(sine1, 0, i2s1, 0);
AudioConnection          patchCord2(sine1, 0, i2s1, 1);

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  AudioMemory(1);
  sine1.frequency(10000);
  sine1.amplitude(0.5);
}

void loop() {
}
...shows this on the scope:

SDS00015.png

Expected sine frequency 10kHz, generated freq 1.666kHz.

Gruesse,
Paul
 
Hi Pauls,

hm.. can you try to edit line 609 in OutputI2s and change it to this:
I2S0_MCR = I2S_MCR_MICS(0) | I2S_MCR_MOE;

Dank je wel!
Frank
 
Found the LRCK to be 7.353kHz:

SDS00016.png

And the BCK to be 470.59kHz:

SDS00017.png

Paul

Edit: this reply belongs to message #51, is not a response to #52
 
hm.. can you try to edit line 609 in OutputI2s and change it to this:
I2S0_MCR = I2S_MCR_MICS(0) | I2S_MCR_MOE;

Just did.
Output freq is now 5 kHz, LRCK is 22.059 kHz, BCK is 1.411 MHz.

Paul
 
Looks like we need a I2S_TCR2_DIV(x); where x = 8.5 which is not possible.
Or I must go back to 16 bit I2S

Hm... i think I'll do that.
 
Or I must go back to 16 bit
Yes, that worked fine when I modified your output_pt8211.cpp to support the PCM5102. The DAC will do 8x interpolation anyway, so the analog signal is looking OK.

Danke,
Paul

edit: I will be out for a few hours now, back later this afternoon
 
Hallo Frank,

That worked! 10 kHz sine, LRCK 44.118 kHz, BCK 1.41178 MHz.

Danke,
Paul
 
LOL

I tried to modify the PLL of the SGTL-5000 at runtime, with the help of the potentiometer on the Audio Shield and the WavFilePlayer.
HAHA.. Well..
THE LC CAN DO PITCH-SHIFTING.
Totally random... it jumps between x-times faster (have to test HOW fast.. i guess it skips some blocks) and ultra slow.
Unfortunately absolutely unusable.
But the effect is very funny!
 
Last edited:
If I do it right, it works right.

Voilá, pitch shifting on LC (okay, it just changes the samplerate on the fly)
You'll need a potentiometer on your Audio Shield or Pin 15.

Modified WavPlayer example for Teensy LC and Teensy 3.x:

Code:
// Simple WAV file player example with pitch shifting
// This example code is in the public domain.
// (c) Jan 2021 Frank B

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioPlaySdWav           playWav1;
AudioOutputI2Sslave      audioOutput;
AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
AudioControlSGTL5000     sgtl5000_1;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// Use these with the Teensy 3.5 & 3.6 SD card
//#define SDCARD_CS_PIN    BUILTIN_SDCARD

#if defined(KINETISL) //Teensy LC
const unsigned extMCLK = 16000000;
const unsigned maxSpeed = 51000;
#else
const unsigned extMCLK = 11294118;
const unsigned maxSpeed = 71000;
#endif

void initSGTLasMaster(void);
void SGTLsetSampleFreq(const float freq);

void setup() {
  AudioMemory(4);
  initSGTLasMaster();
  Serial.begin(9600);
  sgtl5000_1.volume(0.5);

#if defined(SDCARD_SCK_PIN)
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
#endif  

  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  
}

void playFile(const char *filename)
{
  Serial.print("Playing file: ");
  Serial.println(filename);

  playWav1.play(filename);
  delay(25);

  while (playWav1.isPlaying()) {
    float speed = analogRead(15);
    float freq = maxSpeed * speed / 1024.0f;
    if (freq < extMCLK / 1024) freq = extMCLK / 1024;
    SGTLsetSampleFreq(freq);
    Serial.println(freq);
    delay(200);
  }
}


void loop() {
  playFile("SDTEST2.WAV");  // filenames are always uppercase 8.3 format
  delay(500);
  playFile("SDTEST3.WAV");
  delay(500);
  playFile("SDTEST4.WAV");
  delay(500);
  playFile("SDTEST1.WAV");
  delay(1500);
}

//SGTL-5000 registers
#define CHIP_PLL_CTRL      0x0032

bool writeSgtl(unsigned int reg, unsigned int val)
{
  Wire.beginTransmission(0x0A);
  Wire.write(reg >> 8);
  Wire.write(reg);
  Wire.write(val >> 8);
  Wire.write(val);
  if (Wire.endTransmission() == 0) return true;
  return false;
}

void SGTLsetSampleFreq(const float freq) {
  float pllFreq = 4096.0f * freq;
  uint32_t int_divisor = ((uint32_t)(pllFreq / extMCLK)) & 0x1f;
  uint32_t frac_divisor = (uint32_t)(((pllFreq / extMCLK) - int_divisor) * 2048.0) & 0x7ff;
  writeSgtl(CHIP_PLL_CTRL, (int_divisor << 11) | frac_divisor);
}

void initSGTLasMaster()
{

#if defined(KINETISL) //Teensy LC  

  sgtl5000_1.enable(); //Uses SGTL I2S Master Mode automatically

#else   //enable MCLK-Output

#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
  // PLL is at 96 MHz in these modes
#define MCLK_MULT 2
#define MCLK_DIV  17
#elif F_CPU == 72000000
#define MCLK_MULT 8
#define MCLK_DIV  51
#elif F_CPU == 120000000
#define MCLK_MULT 8
#define MCLK_DIV  85
#elif F_CPU == 144000000
#define MCLK_MULT 4
#define MCLK_DIV  51
#elif F_CPU == 168000000
#define MCLK_MULT 8
#define MCLK_DIV  119
#elif F_CPU == 180000000
#define MCLK_MULT 16
#define MCLK_DIV  255
#define MCLK_SRC  0
#elif F_CPU == 192000000
#define MCLK_MULT 1
#define MCLK_DIV  17
#elif F_CPU == 216000000
#define MCLK_MULT 12
#define MCLK_DIV  17
#define MCLK_SRC  1
#elif F_CPU == 240000000
#define MCLK_MULT 2
#define MCLK_DIV  85
#define MCLK_SRC  0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV  17
#define MCLK_SRC  1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV  17
#else
#error "This CPU Clock Speed is not supported by the Audio library";
#endif

#ifndef MCLK_SRC
#if F_CPU >= 20000000
#define MCLK_SRC  3  // the PLL
#else
#define MCLK_SRC  0  // system clock
#endif
#endif

  I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
  while (I2S0_MCR & I2S_MCR_DUF);
  I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT - 1)) | I2S_MDR_DIVIDE((MCLK_DIV - 1));
  CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK  
  sgtl5000_1.enable(extMCLK, AUDIO_SAMPLE_RATE_EXACT * 4096.0L); //Use SGTL I2S Master Mode
#endif
}

MP3:
 

Attachments

  • LCSHIFT_mp3.zip
    1 MB · Views: 75
Last edited:
Hey, good stuff, Frank!

I also have an audio shield working with the TeensyLC at 44100 Hz sample rate. I coded a little kick drum using the synth_simple_drum class from Bryan Jacquot at SparkFun. I can trigger via midi (USB_MIDI_SERIAL) or a serial debug command at this point.

It instantiates the synth_simple_drum, output_i2s, control_sgtl5000 classes.

The only tweaks to control_sgtl5000 were to ifdef out a bunch of EQ, surround sound, and volume ramping code I wasn't using (and add some debug hello messaging in the enable() method).

I used a single i2s tx buffer, and the two dma channels simply use the first or second half of that buffer.

I had to code a couple of functions in dspinst.h for KINETISL, but the performance is fine - not overloading the CPU at all.

I use the arm-none-eabi-gcc 9.2.1 toolchain from Ubuntu packaging.

It looks good on the 'scope, I haven't wired it up to an amplifier yet.

Take care, folks
 
The only tweaks to control_sgtl5000 were to ifdef out a bunch of EQ, surround sound, and volume ramping code I wasn't using (and add some debug hello messaging in the enable() method).

Why were these tweaks needed? Does it not work without? Do I have to take that into account somehow? I did not test EQ, surround and volume ramping (and at the moment I can see no reason why they should'nt work)
 
Hi Frank,
Thanks for all your work on this! I tried compiling your sketch for T4 from T4SGTLPitchShift Github and am running into issues trying to pass 2 variables to the SGTL.enable function. In control_sgtl5000.h the enable function declaration has no args (void). I see that in contro_sgtl5000.cpp there are two functions for enable - the void one and the one you wrote - is there something I need to do to get the compiler to send the args to the correct function definition?
I've modified the code in #60 to work with TeensyLC and Teensy3.x
Or is it not actually working for Teensy4.0 yet?

I've tried compiling on PlatformIO with vsCode and also through the Teensyduino IDE. Here is the error I'm getting:

Code:
src\main.cpp: In function 'void initSGTLasMaster()':
src\main.cpp:143:63: error: no matching function for call to 'AudioControlSGTL5000::enable(const unsigned int&, long double)'
   sgtl5000_1.enable(extMCLK, AUDIO_SAMPLE_RATE_EXACT * 4096.0L); //Use SGTL I2S Master Mode
                                                               ^
In file included from C:\Users\deevo\.platformio\packages\framework-arduinoteensy\libraries\Audio/Audio.h:69:0,
                 from src\main.cpp:14:
C:\Users\deevo\.platformio\packages\framework-arduinoteensy\libraries\Audio/control_sgtl5000.h:37:7: note: candidate: virtual bool AudioControlSGTL5000::enable()
  bool enable(void);
       ^
C:\Users\deev\.platformio\packages\framework-arduinoteensy\libraries\Audio/control_sgtl5000.h:37:7: note:   candidate expects 0 arguments, 2 provided  
*** [.pio\build\teensy40\src\main.cpp.o] Error 1
============================================================== [FAILED] Took 2.32 seconds =============================================================
 
Why were these tweaks needed? Does it not work without? Do I have to take that into account somehow? I did not test EQ, surround and volume ramping (and at the moment I can see no reason why they should'nt work)

Um... a year later... time flies... Sorry Frank.

I was out of code space and decided these features could go. They brought in some floating point code from the library, which put me over the edge on my little project.

Tim
 
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:

View attachment 23171

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

View attachment 23172


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

Regards,
Paul

The solution to this issue is to write L before R channel, as the chip seems to sync the two channels after the R channel is written. See here
 
Back
Top