Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 18 of 18

Thread: Using Teensy 3.6 two DACs with Audio library

  1. #1
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6

    Using Teensy 3.6 two DACs with Audio library

    Hello everybody,

    I'm working on a project that requires stereo output, that's why I bought a 3.6.
    Is there only one DAC accessible through the audio library ?
    How can this be modified ?
    I'm definitely not an expert, I had a quick look at the libraries files and prefered asking here

    Cheers !

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,991

    Cool

    Quote Originally Posted by terdjman View Post
    Hello everybody,

    I'm working on a project that requires stereo output, that's why I bought a 3.6.
    Is there only one DAC accessible through the audio library ?
    How can this be modified ?
    I'm definitely not an expert, I had a quick look at the libraries files and prefered asking here

    Cheers !
    I believe Paul has said he has plans to enhance the audio library to support the second DAC. I don't know how important this is compared to the other things on his plate. Though if somebody were to step up and pitch in, it might be helpful.

    Briefly looking at the library, the DAC support is in just 2 files: output_dac.h and output_dac.cpp in the teensy/hardware/teensy/avr/libraries/Audio directory. I could imagine two ways to add the second DAC:
    • Clone the files to add second class (AudioOutputAnalog2?) that does the same thing as the original files, but for the second DAC;
    • Add secondary a AudioOutputAnalog constructor and begin function that takes an integer argument that says whether you are dealing with the first or second DAC.


    The second is simpler if the two DAC's are mostly the same.

    Obviously after the code is done, you have to add options to the GUI to create the second DAC.

    Assuming the second method is used, you would do something like:

    Code:
    AudioSynthWaveformSine   sine1;
    AudioSynthWaveformSine   sine2;
    AudioOutputAnalog               dac1(0);
    AudioOutputAnalog               dac2(1);
    AudioConnection                  patchCord1(sine1, dac1);
    AudioConnection                  patchCord1(sine2, dac2);
    
    void setup (void) {
      AudioMemory(12);
      sine1.amplitude(1.0);
      sine1.frequency(100);
      sine2.amplitude(2.0);
      sine2.frequency(200);
    }
    
    void loop (void) {
    }
    [/code]

  3. #3
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6
    Hi MichaelMeissner,

    I checked these two files already... I don't get anything. Any code with capitals and underscores is frightening me too much
    And I don't get why there are three AudioOutputAnalog already.
    Last edited by terdjman; 10-25-2016 at 02:52 PM.

  4. #4
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,991
    Quote Originally Posted by terdjman View Post
    Hi MichaelMeissner,

    I checked these two files already... I don't get anything. Any code with capitals and underscores is frightening me too much
    Then unfortunately, you will have to wait for somebody who can understand the datasheets, and has the time and desire to write code to add the second DAC support.

    Quote Originally Posted by terdjman View Post
    And I don't get why there are three AudioOutputAnalog already.
    I'm not sure I understand this comment. In the Audio library there is only one AudioOutputAnalog device, and that is the DAC on the Teensy 3.1/3.2 and DAC0 on the Teensy 3.5/3.6. There are other Audio Output devices, such as the speakers and/or I2S that you can plug into.

    If you mean why is there output_dac.h and output_dac.cpp, that is a C/C++ convention. The .h file is the header that defines the interface, and it is included in any sketch that wants to use that interface. The .cpp file is the implementation of the interface, and it provides the code to actually write to the DAC.
    Last edited by MichaelMeissner; 10-25-2016 at 03:02 PM.

  5. #5
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6
    Quote Originally Posted by MichaelMeissner View Post
    I'm not sure I understand this comment. In the Audio library there is only one AudioOutputAnalog device, and that is the DAC on the Teensy 3.1/3.2 and DAC0 on the Teensy 3.5/3.6. There are other Audio Output devices, such as the speakers and/or I2S that you can plug into.
    I meant "void AudioOutputAnalog::begin(void)" inside output_dac.cpp

  6. #6
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,880
    If it were me, I would probably try the first approach that Michael mentioned, it is probably easier.

    And clone the two files.

    In these files change all AudioOutputAnalog to AudioOutputAnalog2
    Change all: DAC0_ to DAC1_
    Change: SIM_SCGC2_DAC0 to SIM_SCGC2_DAC1
    Change #if statement to only allow for T3.5/3.6 and remove Teensy LC code.
    change which header file is included and #if statements.
    Add a reference to output_dac2.h to Audio.h

    I have done the above and at least one of the Audio examples still compiles, but I have not tried it... But if anyone wishes to take a look, I included the files in the below zip file.
    Note: I have the current Beta2 of Teensyduino.

    If anyone tries it and it works, can issue pull request or maybe Paul likes the 2nd approach...
    Attached Files Attached Files

  7. #7
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,991
    Quote Originally Posted by KurtE View Post
    If it were me, I would probably try the first approach that Michael mentioned, it is probably easier.

    And clone the two files.
    I tend to like the second alternative for two reasons.

    1) In theory, it can simplify updates, in that you only have to modify 1 file, not 2. I've had a number of cases, where I had similar code, and I would edit one but not the other, or not do all of the transformations;

    2) Having separate types gives you the Serial1, Serial2, Serial3 problem where you cannot take the address of one of the Serial types simply. You have to convert the pointer to underlying base type.

    But, it isn't my call. Which ever Paul picks is fine.

  8. #8
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6
    Hi KurtE,

    wow ! thanks a lot for the infos. I downloaded and replaced the files.
    Everything compiles fine. But the problem stays the same. A gigantic VERY loud buzz on one channel, and nothing on the other.

    Here is the very simple code I'm using to test it :
    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include "SdFat.h"
    
    
    AudioSynthWaveform       waveform0;
    AudioSynthWaveform       waveform1;
    AudioOutputAnalog        dac1;
    AudioOutputAnalog        dac2;
    AudioConnection          patchCord1(waveform0, dac1);
    AudioConnection          patchCord2(waveform1, dac2);
    
    void setup(){
    
      Serial.begin(57600);
      
      AudioMemory(16);
      analogReference(INTERNAL);
      
      waveform0.begin(0.2, 110, WAVEFORM_SINE);
      waveform1.begin(0.2, 120, WAVEFORM_SINE);
    
    }
    
    void loop(){
      
    }

  9. #9
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,880
    In your Example here, try changing: AudioOutputAnalog dac2;

    to: AudioOutputAnalog2 dac2;

  10. #10
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6
    Quote Originally Posted by KurtE View Post
    In your Example here, try changing: AudioOutputAnalog dac2;

    to: AudioOutputAnalog2 dac2;
    Thank you ! It is working ! The sound is pretty distorted though. Closer to a square than a sine wave. It tried with an increased AudioMemory and also adding a mixer with .1 gain, still the same distortion.

  11. #11
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,880
    If it were me, I would then try just the dac2 channel and see how it sounds by itself.

    It may be that there is another shared resource between the two units like the PDB0, which need to be worked out.

  12. #12
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,169
    Quote Originally Posted by MichaelMeissner View Post
    I believe Paul has said he has plans to enhance the audio library to support the second DAC. I don't know how important this is compared to the other things on his plate.
    I seriously considered doing this as a last-minute addition before publishing 1.31-beta2. It's really not very difficult, but as the conversation below shows, the devil is in the details.

    At this moment I'm doing documentation stuff (hopefully you can see a few web pages now have 3.5 & 3.6 info) and recovering from a cold. I'll be back to software in a couple days. DAC1 support and fixing the complex USB types for Windows 10 are my top priorities. My hope is to get a beta3 installer done by the end of this week, and finalize 1.31 (not beta) sometime next week.

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,169
    I've added stereo DAC support to the audio library.

    https://github.com/PaulStoffregen/Au...08cec1cf202ef6

    A single object supports both DACs. This is done to keep them perfectly in sync using a single DMA channel. There isn't any way to use only DAC1 without DAC0.

    Here's the sketch I've been using for testing.

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    AudioPlaySdWav           playWav1;
    AudioOutputAnalogStereo  audioOutput;
    //AudioOutputAnalog        audioOutput;
    AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
    AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
    
    void setup() {
      Serial.begin(9600);
      while (!Serial && millis() < 2500) ; // wait
      Serial.println("Stereo DAC test");
    
      // Audio connections require memory to work.  For more
      // detailed information, see the MemoryAndCpuUsage example
      AudioMemory(12);
      
      if (!(SD.begin(BUILTIN_SDCARD))) {
        // 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);
    
      // Start playing the file.  This sketch continues to
      // run while the file plays.
      playWav1.play(filename);
    
      // A brief delay for the library read WAV info
      delay(5);
    
      // Simply wait for the file to finish playing.
      while (playWav1.isPlaying()) {
      }
    }
    
    
    void loop() {
      playFile("SDTEST1.WAV");  // filenames are always uppercase 8.3 format
      delay(500);
      playFile("SDTEST2.WAV");
      delay(500);
      playFile("SDTEST3.WAV");
      delay(500);
      playFile("SDTEST4.WAV");
      delay(1500);
    }

  14. #14
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,880
    Hi Paul,

    Looks good.

    My version was working for either DAC0 or DAC1 but as soon as you defined both, they failed (garbage sound). Bright side was it was helping me learn some new stuff about the processor/libraries, like some of the interactions between DAC and PDB and DMA... May play a little longer, try to understand more. Like it sounded like in the PDB that there are two triggers for DAC0 and DAC1, but was not clear yet to me, if that would imply PDB0_CH0C1 would have different values or if it would be something like PDB0_CH1C1 ... But again yours is the better approach as the user probably wanted both for Stereo.

    Now back to my normal interrupts

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,169
    I believe the only problem was using the PDB to trigger 2 different DMA channels. To make that work, you'd need to have the PDB trigger 1 channel, then using the channel linking to have that channel trigger the other one. It could suffer from "strange" startup timing issues if the first channel starts running before the 2nd channel is fully set up.

  16. #16
    Junior Member
    Join Date
    Oct 2016
    Location
    Copenhagen
    Posts
    6
    Thanks a lot Paul !

  17. #17
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,880
    Quote Originally Posted by PaulStoffregen View Post
    I believe the only problem was using the PDB to trigger 2 different DMA channels. To make that work, you'd need to have the PDB trigger 1 channel, then using the channel linking to have that channel trigger the other one. It could suffer from "strange" startup timing issues if the first channel starts running before the 2nd channel is fully set up.
    Yep - That makes sense as it shows the dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB); in both cases. As you said trying to get them both to work independent may be problematic. So I punt!

  18. #18
    Junior Member
    Join Date
    Oct 2016
    Posts
    11
    What is the logic of 2 dac output?
    Is it like the 2 channel line-out of the audio board so it can play 2 channel audio file?
    Or it simply outputs the same signal on both dac 0&1?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •