Close

Pi Circle to Teensy Audio Shield and Quad Audio device

PatrickPatrick wrote 06/19/2019 at 03:11 • 9 min read • Like

I added the AudioControlSGTL5000 object to my port of the Teensy Audio Library available at https://bitbucket.org/phorton1/src-circle/src/master/   This is, of course, just part of my ongoing rPi bare metal vGuitar Rig project, but I felt like a “page” would be the best way to present this information.

These classes allows one to connect a Teensy Audio Shield, or other SGTL5000 to a Raspberry Pi within the bare metal Circle environment.

It turned out to be a little more difficult than I originally thought it would be.   The sgtl5000 / teensy shield absolutly requires an input MCLK.  For 44.1khz sound, that clock has to run at 11.289Mhz. Here’s a handy snippet of code to produce an 11.289 Mhz clock in Circle:

LOG("starting MCLK",0);
u32 freq = SAMPLE_RATE * 256;           // 11289600
u32 divi = CLOCK_RATE / freq;            // 44
u32 modi = CLOCK_RATE % freq;           // 3257600
u32 divf = (modi*4096 + freq/2) / freq; // 1182
    // printf("divf=%d should equal 1182\n",divf);
    // the above math overflows 32 bits
divf = 1182;
m_MCLK.Start(divi, divf, 1); 

There is no good way on the Pi to generate 3 synchronized clocks, the other two being needed are the the BCLK (bit clock) and FCLK (frame clock, also known as the LRCLK).   The bcm2835 PCM peripheral can, as a special case, generate a synchronized FCLK for a given BCLK, so it can usually act as a master to i2s devices, but for the sgtl5000, which requires a 256fs master clock, it just cannot reasonably be programmed to act as an i2s master.

So, instead, my code for the rpi generates the 11.289Mhz MCLK on GPIO4, sends it to the sgtl5000 (teensy audio shield), which then acts as the i2s master, generating the BCLK and FCLK signals based on that.  And therefore, in Circle, the AudioControlSGTL5000 is actually not implemented, and you must use the AudioControlSGTL500slave device instead.

It works ok, however, and so is worth checking in.

Below is a diagram showing the pin connections between the Raspberry Pi and the Teensy Audio Shield.  Note that this is *just* the Teensy Audio Shield … there is no Teensy running the codec … it is connected directly to the Pi.

I made a simple breadboard for the Teensy Audio shield by gluing two of the small standard breadboards together (after sanding the joining edges to remove some space), and running jumpers.  This allows me to just use regular wires to connect things.  I HATE DUPONT FEMALE CONNECTORS !!! 

Circle TeensyQuad device

I also added two additional new classes, AudioInputTeensyQuad and AudioOutputTeensyQuad to the library.   These allow the Pi to be connected to a Teensy that is actually running an existing Teensy Audio Library program, so the Pi can act as a (relatively larger, big
brother) audio co-processor to the Teensy.

The teensy MPU has two i2s modules (as opposed to the one on the bm2835) that run synchronously.    Paul has created the AudioI2SQuad input and output devices to allow two teensy sound shields to be stacked for quad io.

These classes allow you to easily use any rPi, including the zero and 3B+, as a DSP co-processor to a teensy audio application.  It *may* even allow you to retrofit such an additional processor into your existing Teensy audio application with a minimal set of changes.

 +-------------------+      teensy       +--------------------+
 |   Teensy Audio    |   quad channels   |       rPi          |
 |    application    |      2 & 3        | acting as an audio |
 |    using quad     | <===============> |    co-processor    |
 |    audio device   |                   |                    |
 +-------------------+                   +--------------------+
      ^        |
      |        |      teensy quad
      |        v     channels 0 & 1
     IN       OUT

The teensy quad device channels 0 and 1 are used for the main audio input and output, from a mic or line input, out to line or the headphones.   The teensy quad device channels 2 and 3 are used to communicate with the rPi. 

From the rpi's perspective, the teensy is simply another i2s IO device (that happens to use a 16 bit channel width instead of 32 bits, as that is the channel frame packing that I see with the default build of the teensy quad libraries in the Arduino IDE).  There is no corresponding "control" object for the streams … it is presumed that control functions will be handled by the native teensy application.

The test program consists simply of a stereo pass through.  The sound comes IN to the teensy shield on quad channels 0 and 1.  It is then sent to the rPi on OUT channels 2 and 3, where it is “processed”.  The Pi then sends it back to the teensy on quad IN channels 2 and 3, and the teensy simply sends the input from those to the main 0 and 1 OUT channels to headphones or the line out.

Here are the pin connections.  Note that we don’t need (disconnected) the MCLK wire from the previous section.

     rPi   gpio   Teensy 3.2_quad  3.6_quad   normal_teensy_i2s

    BCLK    18   <----  9          9            9
    FCLK    19   <----  23         23           23
    RXD     22   ---->  15 tx1     15 tx1       22 tx0      
    TXD     21   <----  30 rx1     38 rx1       13 rx0   

Here is the INO sketch running on the teensy using the native Teensy Audio Library:

#define WITH_SERIAL  0

#include <Audio.h>

#if WITH_SERIAL
    #include "myDebug.h"
#endif


AudioControlSGTL5000    control;
AudioInputI2SQuad       input;           
AudioOutputI2SQuad      output;           
AudioConnection         c0(input, 0, output, 2);
AudioConnection         c1(input, 1, output, 3);
AudioConnection         c2(input, 2, output, 0);
AudioConnection         c3(input, 3, output, 1);


void setup() 
{
    #if WITH_SERIAL
        Serial.begin(115200);
        display(0,"teensyPiQuadTest,ino started ...",0);
    #endif
    
    AudioMemory(12);
    control.enable();
    control.inputSelect(AUDIO_INPUT_LINEIN);
    control.volume(0.7);
    control.lineInLevel(0,7); 

    #if WITH_SERIAL
        display(0,"teensyPiQuadTest.ino running ...",0);
    #endif
}



void loop() 
{
    #if WITH_SERIAL
        static elapsedMillis timer = 0;
        static int counter = 0;
        if (timer > 3000)
        {
            display(0,"counter(%d)",counter++);
            timer = 0;
        }
    #endif
}

 
And here is the Circle program in bare metal running the ported Teensy Audio Library:

#include <audio\Audio.h>

AudioInputTeensyQuad   input;
AudioOutputTeensyQuad  output;

AudioConnection  c0(input, 0, output, 0);
AudioConnection  c1(input, 0, output, 1);


void setup()
{
    printf("02-StereoPassThru::setup()\n");
    AudioMemory(80);
    printf("02-StereoPassThru::setup() finished\n");
}


void loop()
{
}

There are a couple of things to note about the Audio Shield hardware in this configuration

(1) you must remove a small capacitor that is connected to pin 15 on the audio shield.  It’s ok.  Paul added this capacitor to tame signal noise when pin 15 is used with a volume pot, but it’s not really needed.  The teensy native quad device sends out the i2s on pin 15 and it definitely doesn’t work if that capacitor is in place.  You will need to use a different pin besides for the volume control to use the native Teensy Quad Device.

(2) On the teensy 3.2, the second i2s channel RX1 pin is gpio30.   This pin is on the bottom of the teensy 3.2, and so I had to add a jumper and wire to my teensy 3.2 for this test configuration.  The alternative is to use a teensy3.6, which brings the second i2s channel RX1 out to gpio38, which is a “normal” pin on the teensy 3.6.  All my teensy 3.6’s are occupied at the moment, and  It only took a few minutes to solder the jumper on one of my 3.2’s, so the proof of concept is with a teensy 3.2.   I scratched away the connection between the Teensy "program" button and one of the holes on the edge so that I would have someplace to solder a female connector:

Running it on a Pi zero

It’s been a while.   I’ve been using the 3B+ for the last couple of months, but just to prove it works, I broke out an old Pi Zero, and did a clean build of Circle and the test program and kernel with RASPPI=1.  

My breakout breadboard makes it easy to swap a different Pi into the circuit without disconnecting any wires.  It took about 10 minutes to verify that the same program worked on the Pi Zero as had just worked on the rPi 3B+.  That's one nice thing about the Circle environment.  It only takes about 5 mintues to do a clean build, as opposed to what, several hours for a Linux build?  So it was not hard to recompile everything for the zero.

I plugged it in and it worked the first time !!

Gotta Love It!

- Patrick

Like

Discussions