No audio output Teensy 3.2 using either onboard DAC or USB passthrough

Status
Not open for further replies.
[SOLVED] No audio output Teensy 3.2 using either onboard DAC or USB passthrough

Hello,

I'm working on my final project for my music degree (the idea is exploring alternative input methods for interacting with electronic instruments) and I'm putting together a touch screen based synth using the Adafruit STMPE610. I had originally planned on going with a hardware based setup but after fighting with different circuits, I've decided to go with software which I'm much more comfortable with.

The issue I'm having is that I can't seem to get any audio to play through either the onboard DAC or through the digital USB interface that's passed through to the computer. I can see that the program is getting through to where the audio should be played but nothing seems to want to work.

After adding dac1.begin(), the program hangs and only prints out the initial project title. I don't think that function is required but after looking at the source code for the library, I found it so I thought I'd give it a go.

I'm not sure if I'm missing something in my setup function or if I specifically have to output audio in the loop function. I've watched the workshop for the audio library but I can't find much documentation for the library other than the included examples.

Here's a copy of the output to the serial monitor without dac1.begin() with me randomly pressing on the touch screen (code is under):

Code:
=======================
Touch Synth
<name> - 2017
Music Major Project
=======================
Note on 
Touch location (x,y,z) -> 1884 2371 49 
Touch location (x,y,z) -> 1896 2365 37 
Touch location (x,y,z) -> 1892 2365 34  
Touch location (x,y,z) -> 1428 2152 37 
Note off 
Note on 
Touch location (x,y,z) -> 1985 2440 55 
Touch location (x,y,z) -> 1987 2420 39 
Touch location (x,y,z) -> 2010 2381 36 
Touch location (x,y,z) -> 2023 2327 34 
Touch location (x,y,z) -> 2277 2552 34 
Touch location (x,y,z) -> 2074 2648 40 
Note off 
Note on 
Touch location (x,y,z) -> 2006 2575 35 
Touch location (x,y,z) -> 2024 2568 35 
Note off 
Note on 
Touch location (x,y,z) -> 1992 2522 34 
Touch location (x,y,z) -> 2005 2525 31 
Touch location (x,y,z) -> 2004 2523 31 
Touch location (x,y,z) -> 2007 2514 33 
Note off 
Note on 
Touch location (x,y,z) -> 2047 2409 36 
Touch location (x,y,z) -> 2036 2410 32 
Touch location (x,y,z) -> 2039 2405 31 
Touch location (x,y,z) -> 2066 2399 37 
Note off 
Note on 
Touch location (x,y,z) -> 2058 2367 36 
Touch location (x,y,z) -> 2062 2372 34 
Note off 
Note on 
Touch location (x,y,z) -> 2013 2398 34 
Touch location (x,y,z) -> 2029 2399 32 
Note off

And the code:

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
#include "Adafruit_STMPE610.h"
    
// ===== Audio GUI Tool code =====
// GUItool: begin automatically generated code
AudioSynthWaveform       waveform1;      //xy=97,100
AudioSynthWaveform       waveform2;      //xy=97,137
AudioMixer4              mixer1;         //xy=349,119
AudioEffectEnvelope      envelope1;      //xy=514,104
AudioMixer4              mixer2;         //xy=676,123
AudioOutputAnalog        dac1;           //xy=841,110
AudioConnection          patchCord1(waveform1, 0, mixer1, 0);
AudioConnection          patchCord2(waveform2, 0, mixer1, 1);
AudioConnection          patchCord3(mixer1, envelope1);
AudioConnection          patchCord4(envelope1, 0, mixer2, 0);
AudioConnection          patchCord5(mixer2, 0, dac1, 0);
// GUItool: end automatically generated code
    
// ===== Pinout setup =====
const byte PWR_LED = 13;
const byte GATE_OUT = 6;
const byte SPI_SCK = 14;
const byte SPI_MOSI = 11;
const byte SPI_MISO = 12;
const byte STMPE_CS = 15; // Touch Screen Controller Chip Select
const byte aPot = 16;
const byte rPot = 17;
    
// ===== Touch Screen Object Declaration =====
// SDI to MOSI, SDO to MISO, and SCL to SPI CLOCK
// Tie MODE to 3.3V and POWER CYCLE the STMPE610 (there is no reset pin)
Adafruit_STMPE610 touch = Adafruit_STMPE610(STMPE_CS, SPI_MOSI, SPI_MISO, SPI_SCK);
    
// ===== Function Declarations =====
void error(int);
    
// ===== Global variables =====
int gTouchOn = 0;
int gNoteOn = 0;
    
void setup() {
  Serial.begin(9600);                       // Setup serial
  Serial.println("=======================");  // ============================
  Serial.println("Touch Synth");              // 
  Serial.println("Callum Blackmore - 2017");  // Print faux splash screen to
  Serial.println("Music Major Project");      // serial output
  Serial.println("=======================");  //
  //Serial.flush();                           // ============================
    
  pinMode(PWR_LED, OUTPUT); //Setup power LED
  digitalWrite(PWR_LED, HIGH);
    
  if (! touch.begin()) {
    Serial.println("STMPE not found!");
    error(1000);
  }
    
      
  AudioMemory(50);
  //dac1.begin();    // <--- Code will hang here if uncommented
  dac1.analogReference(INTERNAL);
  waveform1.begin(WAVEFORM_SINE);
  waveform2.begin(WAVEFORM_TRIANGLE);
  mixer1.gain(0, 0.5);
  mixer1.gain(1, 0.5);
  mixer2.gain(0, 0.75);
  envelope1.delay(0);
  envelope1.attack(100);
  envelope1.hold(0);
  envelope1.decay(15);
  envelope1.sustain(0.7);
  envelope1.release(200);
}
    
void loop() {
  // put your main code here, to run repeatedly:
  uint16_t analogVal; // temp value for analog reads
  uint16_t x, y;  // Touch coordinates
  uint8_t z;      // ''
    
  analogVal = analogRead(aPot);      // =====
  //Serial.print(analogVal); Serial.print(' ');
  envelope1.attack(analogVal/10);   // Read pots and update attack and release values
  analogVal = analogRead(rPot);      //
  //Serial.print(analogVal); Serial.println(' ');
  envelope1.release(analogVal/10);  // =====
      
  if(touch.touched())
  {
    gTouchOn = 1; 
    while (! touch.bufferEmpty())
    {
      touch.readData(&x, &y, &z);
      waveform1.frequency((y*2)+100);
      waveform2.frequency((y*2)+100);
      Serial.print("Touch location (x,y,z) -> ");
      Serial.print(x); Serial.print(' ');
      Serial.print(y); Serial.print(' ');
      Serial.print(z); Serial.println(' ');
    }
    touch.writeRegister8(STMPE_INT_STA, 0xFF); // reset all ints
    if(gNoteOn == 0)
    {
      Serial.print("Note on"); Serial.println(' ');
      gNoteOn = 1;
      envelope1.noteOn();
    }
  }
  else if(!touch.touched() && gNoteOn == 1)
  {
    Serial.print("Note off"); Serial.println(' ');
    envelope1.noteOff();
    gNoteOn = 0;
    gTouchOn = 0;
  }
}
    
void error(int len){
  while(1) {
      digitalWrite(PWR_LED, HIGH);
      delay(len);
      digitalWrite(PWR_LED, LOW);
      delay(len);
    }
}
 
Last edited:
The DAC doesn't have the power (1 ma) to drive a speaker, so is your DAC output going to an amp (like on the propshield?). maybe post a photo of your setup? Try this simple sine wave tone generator through the DAC ...
Code:
// prop shield need pin 5
// start monitor to hear sound,  hit key to increase freq
#include <Audio.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=180,469
AudioOutputAnalog        dac1;           //xy=380,468
AudioConnection          patchCord1(sine1, dac1);
// GUItool: end automatically generated code

int freq = 1100;

void setup() {
	Serial.begin(9600);
	while (!Serial);
	Serial.println("Setting up");
  //dac1.analogReference(EXTERNAL);   // louder, default is 1.2v INTERNAL
	pinMode(5, OUTPUT);
	digitalWrite(5, 1);//Enable Amplified.
	AudioMemory(12);
	sine1.amplitude(1.0);
	sine1.frequency(1000);
	Serial.println("Send Serial Char to increase freq");
}

void loop()
{
	if (Serial.available()) {
		Serial.read();
		sine1.frequency(freq);
		Serial.println(freq);
		freq += 100;
	}
}
You need to open the serial monitor for sound to begin.

EDIT: In your sketch to get DAC output, in setup() you need to add
waveform1.amplitude(1.0);
waveform2.amplitude(1.0);

You probably don't need mixer2, just patch envelope1 to dac1

DAC output and FFT of 1khz and 440hz sine waves through mixer
mixerfft.png
 
Last edited:
The DAC doesn't have the power (1 ma) to drive a speaker, so is your DAC output going to an amp (like on the propshield?). maybe post a photo of your setup?
I've been running the teensy into some powered speakers so I shouldn't need an amp for that. While running your example and even after uncommenting dac1.analogReference(EXTERNAL);, I still had no audio.

For good measure, I tried plugging the teensy into a small mixer to see if it was because of any DC offset that the speakers may not have liked but there's still no sound. I even changed the line AudioOutputAnalog dac1; to AudioOutputUSB dac1; and after checking the input levels for the teensy on my Win10 machine, the level meter showed nothing.

EDIT: In your sketch to get DAC output, in setup() you need to add
waveform1.amplitude(1.0);
waveform2.amplitude(1.0);

You probably don't need mixer2, just patch envelope1 to dac1

I've changed my *.begin() statements to include the amplitude and starting frequency but that doesn't seem to have changed anything.

The modified statements:
Code:
waveform1.begin(1.0, 440, WAVEFORM_SINE);
waveform2.begin(1.0, 440, WAVEFORM_TRIANGLE);

I probably don't need mixer 2 but I'll be adding a volume pot to control the gain for mixer 2 once I get this all working.

Do you think I may have an old version of the audio library? Or is it not compatible with the teensy 3.2? I'll take a look at the github repo and try the latest versions of the libraries to see if that makes any difference.

My end goal is to have the audio being sent over USB so I can route it through Ableton Live (music production software).

Here's a picture of the setup (please excuse the messy desk):
fVNMGIr.jpg
 
Last edited:
UPDATE: I think my teensy was faulty or I've damaged it somehow. I've swapped the original teensy that was having issues with a second one that I had and now my program is working perfectly.
 
If my simple DAC sketch produced no sound (I can't really see the DAC/A14 wiring in your photo), maybe do some simple tests on the DAC output with a scope or digital meter. analogWrite(A14, n); in setup() and measure the voltage on A14 for different values of n. Or I use this sketch to test DAC, jumpering A14 to A0.
Code:
// DAC out T3.2 A14  (A12 LC) to ADC A0 in   pin 12 for hi/lo  K66 A21 or A22
#define DACPIN A14
#define VREF 3.3

void setup() {
  Serial.begin(9600);
  analogWriteResolution(12);
  analogReadResolution(16);
  analogReadAveraging(32);
  pinMode(12, INPUT); // voltage threshold
}
void loop() {
  int i, sensorValue, k;
  float v;
  char str[80];

  for (i = 0; i < 4096; i += 40) {
    analogWrite(DACPIN, i);
    //  ? should we wait for DAC to settle 2-15us, datasheet
    delayMicroseconds(10);
    sensorValue = analogRead(A0);
    v = VREF * sensorValue / 65536.;
    k = sensorValue >> 4;
    sprintf(str, "%d  %d %d   %d ", i, k, sensorValue, digitalRead(12));
    Serial.print(str);
    Serial.println(v, 3);
    delay(1000);
  }
  for (i = 4096 - 40; i >= 0; i -= 40) {
    analogWrite(DACPIN, i);
    delayMicroseconds(10);
    sensorValue = analogRead(A0);
    v = VREF * sensorValue / 65536.;
    k = sensorValue >> 4;
    sprintf(str, "%d  %d %d   %d ", i, k, sensorValue, digitalRead(12));
    Serial.print(str);
    Serial.println(v, 3);
    delay(1000);
  }
}

Since USB is not working either, try the following "version" of your sketch. It works for me on DAC and USB to audacity on Windows 10. I don't have the touch-screen and pots, but it can change the 2nd waveform frequency from Serial input (set USB in IDE to USB+Serial+Midi)
Code:
#include <Audio.h>

// ===== Audio GUI Tool code =====
// GUItool: begin automatically generated code
AudioSynthWaveform       waveform1;      //xy=97,100
AudioSynthWaveform       waveform2;      //xy=97,137
AudioMixer4              mixer1;         //xy=349,119
AudioEffectEnvelope      envelope1;      //xy=514,104
AudioOutputAnalog        dac1;           //xy=841,110
AudioConnection          patchCord1(waveform1, 0, mixer1, 0);
AudioConnection          patchCord2(waveform2, 0, mixer1, 1);
AudioConnection          patchCord3(mixer1, envelope1);
AudioConnection          patchCord4(envelope1, 0, dac1, 0);
// GUItool: end automatically generated code
//if using USB output, need IDE with USB in Audio mode
AudioOutputUSB    usb1;
AudioConnection          patchCord5(mixer1, usb1);

// ===== Pinout setup =====
const byte PWR_LED = 13;


void setup() {
  Serial.begin(9600);                       // Setup serial
  pinMode(PWR_LED, OUTPUT); //Setup power LED
  digitalWrite(PWR_LED, HIGH);

  AudioMemory(50);

  waveform1.begin(WAVEFORM_SINE);
  waveform2.begin(WAVEFORM_SINE);
  waveform1.frequency(1000);
  waveform1.amplitude(1.0);
  waveform2.amplitude(1.0);
  waveform2.frequency(440);
  mixer1.gain(0, 0.5);
  mixer1.gain(1, 0.5);
  envelope1.delay(5);
  envelope1.attack(30);
  envelope1.hold(10);
  envelope1.decay(15);
  envelope1.sustain(0.7);
  envelope1.release(20);
}

void loop() {
  static int freq = 440;
  envelope1.noteOn();
  delay(800);
  envelope1.noteOff();
  delay(60);
  if (Serial.available()) {
    uint8_t c = Serial.read();
    if (c == '+') freq += 100;
    else freq -= 100;
    waveform2.frequency(freq);
  }
  Serial.println(freq);
}
This is the sketch I was running for the scope test image in my earlier post. Tests were run on standalone T3.2 (no prop shield or audio adaptor) running 1.8.3/1.37
 
Last edited:
UPDATE: I think my teensy was faulty or I've damaged it somehow. I've swapped the original teensy that was having issues with a second one that I had and now my program is working perfectly.

Ah, simultaneous posts. ;) glad it's working now.
 
So after soldering a header pin to the second teensy to the DAC output, I'm now not getting any audio output again. Are there particularly sensitive components around that pin that are sensitive to heat?

I tested the continuity between the micro (pin 18) and the DAC pin where headers are soldered and there's continuity so I'm not sure what's happening.

I'm tempted to buy a Teensy 3.5 or 3.6 and give it a go with one of those because I kinda just need it to work at the moment.
 
Last edited:
As a quick sanity check, you could try a program like this:

Code:
void setup() {
  analogWrite(A14, 128);
}
void loop() {
}

Just use a DC voltmeter, and try different values. 255 should cause 3.3V output. 128 should give approx 1.65V. Since it's stable DC voltage, you can easily measure and see the stable reading on your multimeter.

This can at least give you an idea if the pin still works and your hardware is connected properly, without all the complexity of the audio lib.
 
That little program outputs the correct voltages to pin A14 at 128 and 255. I gave the blink example a go using pin 13 but it doesn't light up so I have a feeling that I'm damaging the Teensy whole I'm working on it.

It looks like that soldering to pin A14/dac upsets something near that pin. I can't see any damage in the area and while I'm not the best at soldering, I'm far from the worst.
 
Okay no it works. I'm home now and I have access to a mixer that I'm assuming has DC coupling and I'm getting a signal.

Earlier I was trying it with a small powered speaker (I only had access to that at the time) which obviously doesn't have DC coupling so the DC offset must have been messing with it.
 
I'm kind of late to the party, but the most valuable tool you can have for troublshooting would be a oscilloscope. I ran into some problems with my first Teensy 3.2 and I stuck a probe on there and saw a beautiful 440hz sine wave (even those pocket oscopes will be able to easily measure audio frequencies). I realized at that point that it was a module further on. One thing I learned in the Navy is to look at everything like a box. You have inputs and you have outputs. If the inputs are good, but the outputs are bad you found the bad box. You can further narrow down the box at that point to smaller and smaller "boxes" until you found your component (or components in some cases). In the Navy they termed it "top down troubleshooting" which is differentiated by "bottom up" in the sense that you start with an unknown and narrow down until you find the culprit. The alternative (bottom up) is you start with a suspected component and troubleshoot based on that. The former is obviously more effecient - you could be guessing all day which component is bad - unless it's a piece of gear that fails often in the same manner. For example, there was an altitude alarm indicator on the H3 that would always fail because Q3 was underpowered - poor design - and so when that box came in to AIMD with the same failure indication (light fails to light and alarm fails to sound at target altitude) my first guess was Q3 and I was right 99.9% of the time. That's an edge case though as other types of gear would come in that would require a series of measurements to determine the faulting sub-system before you even got to the component level.

Anyway tldr; oscopes are your friends
 
Status
Not open for further replies.
Back
Top