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

Thread: Using I2S causes Teensy 4.1 to not boot, no setup(), no serial, no debug.

  1. #1

    Using I2S causes Teensy 4.1 to not boot, no setup(), no serial, no debug.

    tl,dr: When I declare an `AudioInputI2S` or `AudioOutputI2S` object and upload the code, my Teensy 4.1 won't boot: no USB devices (host computer doesn't even see it), no GPIO activity, nothing. It doesn't even get to `setup()`. Comment out the `AudioInputI2S` declaration, and it boots right up. Because I have no serial console, I'm not sure how to debug this.

    Details:
    * It happens with either Input or Output I2S objects.
    * It does NOT happen with other `AudioStream` objects, like `AudioInputUSB` or `AudioSynthWaveformSine`
    * It happens even if the instantiation COULD happen, but doesn't. If I wrap the `new AudioInputI2S()` with a conditional the compiler can't optimize out (eg: `if (digitalRead(PIN_TIED_TO_GROUND) == HIGH)`), it won't boot. Even though the `new AudioInputI2S()` never gets called.

    The fact that it happens even when the `new AudioInputI2S()` never gets called, and the fact that it's happening before `setup()` runs, tells me that it's something that's happening with `static` code/constructors. The fact that it's NOT happening with other `AudioStream` objects, tells me it's not in `AudioStream` parent-class code, it's in the `AudioInputI2S` child-class code.

    So looking in `class AudioInputI2S` for static code, I see:
    Code:
    protected:
    	static bool update_responsibility;
    	static DMAChannel dma;
    	static void isr(void);
    private:
    	static audio_block_t *block_left;
    	static audio_block_t *block_right;
    	static uint16_t block_offset;
    I'm willing to bet that defining some static variables, all set to 0 or NULL, isn't doing this, nor is defining (but not calling) a static function (ISR.) So the most likely candidate is `static DMAChannel dma;` which will have a constructor

    It's initialized as:
    Code:
    DMAChannel AudioInputI2S::dma(false);
    Which will call this constructor:
    Code:
    	DMAChannel(bool allocate) {
    		if (allocate) begin();
    	}
    Which doesn't even do anything!

    `DMAChannel` is a child of `DMABaseClass`, which only has this constructor:
    Code:
    	DMABaseClass() {}
    Again, does nothing.

    Going back to `DMAChannel()` constructor: If for some reason it DID get to the point where it called `begin()`, then there's some code in `DMAChannel::begin()` that looks like it might be problematic, but looks good:
    Code:
    void DMAChannel::begin(bool force_initialization)
    {
    	uint32_t ch = 0;
    
    	__disable_irq();
    	if (!force_initialization && TCD && channel < DMA_MAX_CHANNELS
    	  && (dma_channel_allocated_mask & (1 << channel))
    	  && (uint32_t)TCD == (uint32_t)(0x400E9000 + channel * 32)) {
    		// DMA channel already allocated
    		__enable_irq();
    		return;
    	}
    	while (1) {
    		if (!(dma_channel_allocated_mask & (1 << ch))) {
    			dma_channel_allocated_mask |= (1 << ch);
    			__enable_irq();
    			break;
    		}
    		if (++ch >= DMA_MAX_CHANNELS) {
    			__enable_irq();
    			TCD = (TCD_t *)0;
    			channel = DMA_MAX_CHANNELS;
    			return; // no more channels available
    			// attempts to use this object will hardfault
    		}
    	}
    	channel = ch;
    [...other stuff...]
    I see a `while(1)` and messing with IRQs. Those are the kinds of things that could lead to lock-ups, but in my brief review of the code, I don't see any obvious problems. Never mind the fact that it doesn't look like it gets called.

    So, I'm stumped. Any ideas? Am I even looking in the right place?

    Here's the real kick-to-the-shins: While writing up this post, I pulled out all my Audio code to put in a dummy program to reproduce the problem AND THE SILLY THING WORKS. IT DOESN'T FAIL. I'm happy to accept that this is a problem in my code, but I can't for the life of me figure out what I'm doing that would conflict with any of this static code in `AudioInputI2S` or `DMAChannel`. Where to even look for that?

    Here's my dummy code anyway. This is from Platform.IO. `SOARAudio.h` and `.cpp` are copied directly from my larger project, `main.cpp` just does what it needs to call it. Hopefully someone will see something in my code that's a race condition? Or a resource consumption that when stripped down has plenty of resources? Or something...

    I appreciate any help you can provide, or suggests on where to look next. Thank you!

    73 de N6MTS
    -Mark

    main.cpp:
    Code:
    #include <Arduino.h>
    #include "SOARAudio.h"
    
    SOARAudio *audio;
    
    void setup() {
        Serial.begin(115200);
        while (!Serial) delay(500);
        Serial.println("Getting started, waiting 2 seconds for console.");
        delay(2000);
        pinMode(31, INPUT_PULLUP);
    
        if (digitalRead(31) == LOW) {
            audio = new SOARAudio();
        }
    }
    
    void loop() {
        Serial.println("Loop top");
        delay(1000);
    }
    SOARAudio.h:
    Code:
    #ifndef SOAR_AUDIO_H
    #define SOAR_AUDIO_H
    #include <Audio.h>
    #include <Wire.h>
    #include <map>
    
    class SOARAudio {
    public:
        SOARAudio();
    
        const static uint8_t num_audio_buffers = 12;
    
        std::map<String, AudioStream *> Streams;
        std::map<String, AudioConnection *> Connections;
        std::map<String, AudioControl *> Controllers;
        // Needs to be public so the Audio library can see it.
        static DMAMEM audio_block_t data[num_audio_buffers];
    
    protected:
        void begin_v2_2b();
    
    };
    
    
    #endif // SOAR_AUDIO_H
    SOARAudio.cpp:
    Code:
    #include "SOARAudio.h"
    
    
    DMAMEM audio_block_t SOARAudio::data[num_audio_buffers];
    
    SOARAudio::SOARAudio() {
        Serial.printf("Setting up audio for v2.2b hardrware.");
        begin_v2_2b();
    }
    
    void SOARAudio::begin_v2_2b() {
        /*
        AudioSynthWaveformSine   TestTone440Hz;          //xy=621,364
        AudioInputUSB            USB_in;           //xy=643,416
        AudioInputI2S            CODEC_in;           //xy=702,555
        AudioMixer4              mixer2;         //xy=814,457
        AudioMixer4              mixer1;         //xy=815,381
        AudioOutputUSB           USB_out;           //xy=903,554
        AudioOutputI2S           CODEC_out;           //xy=957,420
        AudioConnection          patchCord1(TestTone440Hz, 0, mixer1, 0);
        AudioConnection          patchCord2(TestTone440Hz, 0, mixer2, 3);
        AudioConnection          patchCord3(USB_in, 0, mixer1, 3);
        AudioConnection          patchCord4(USB_in, 1, mixer2, 0);
        AudioConnection          patchCord5(CODEC_in, 0, USB_out, 0);
        AudioConnection          patchCord6(CODEC_in, 1, USB_out, 1);
        AudioConnection          patchCord7(mixer2, 0, CODEC_out, 1);
        AudioConnection          patchCord8(mixer1, 0, CODEC_out, 0);
        AudioControlWM8731       wm8731;       //xy=825,645
        */
    
        bool ret;
    
        // Streams
        AudioSynthWaveformSine *testTone = new AudioSynthWaveformSine();
        testTone->amplitude(0.0);
        testTone->frequency(440.0);
        testTone->phase(0.0);
        Streams["TestTone440Hz"] = testTone;
    
        Streams["USB_in"] = new AudioInputUSB();
        Streams["USB_out"] = new AudioOutputUSB();
        Serial.println("Allocated USB Streams.");
        Streams["I2S_in"] = new AudioInputI2S();
        Streams["I2S_out"] = new AudioOutputI2S();
        Serial.println("Allocated I2S Streams.");
        Streams["MixerUplink"] = new AudioMixer4();
        Streams["MixerDownlink"] = new AudioMixer4();
        Serial.println("Allocated Mixers.");
    
        // Connections
        Connections["TestToneToUplink"] = new AudioConnection(*Streams["TestTone440Hz"], 0, *Streams["MixerUplink"], 0);
        Connections["TestToneToDownlink"] = new AudioConnection(*Streams["TestTone440Hz"], 0, *Streams["MixerDownlink"], 0);
        Connections["USBToUplink"] = new AudioConnection(*Streams["USB_in"], 0, *Streams["MixerUplink"], 1);
        Connections["USBToDownlink"] = new AudioConnection(*Streams["USB_in"], 1, *Streams["MixerDownlink"], 1);
        Connections["I2SToUSBUp"] = new AudioConnection(*Streams["I2S_in"], 0, *Streams["USB_out"], 0);
        Connections["I2SToUSBDown"] = new AudioConnection(*Streams["I2S_in"], 1, *Streams["USB_out"], 1);
        Connections["MixerUplinkToI2S"] = new AudioConnection(*Streams["MixerUplink"], 0, *Streams["I2S_out"], 0);
        Connections["MixerDownlinkToI2S"] = new AudioConnection(*Streams["MixerDownlink"], 1, *Streams["I2S_out"], 1);
    
        // Controllers
        AudioControlWM8731 *wm8731 = new AudioControlWM8731();
        ret = wm8731->enable();
        Serial.printf("wm8731.enable(): %s\n", ret ? "True" : "False");
        ret = wm8731->volume(0.0);       // This is the headphone amp, which we aren't using.
        Serial.printf("wm8731.volume(): %s\n", ret ? "True" : "False");
        ret = wm8731->inputLevel(1.0);
        Serial.printf("wm8731.inputLevel(): %s\n", ret ? "True" : "False");
        ret = wm8731->inputSelect(AUDIO_INPUT_LINEIN);
        Serial.printf("wm8731.inputSelect(): %s\n", ret ? "True" : "False");
        Controllers["CODEC"] = wm8731;
    
        // This is a #define that expects to be run outside of a class.  We have to do this 
        // differently to make sure `data` doesn't leave scope.
        //AudioMemory(12);
        // expands to:
        //{ static DMAMEM audio_block_t data[12]; AudioStream::initialize_memory(data, 12); }
        AudioStream::initialize_memory(data, num_audio_buffers);
    }

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,876
    If reading right ... the working code has this explicit call in setup(): audio = new SOARAudio();

    Where the failing code has the same code done in the constructor called implicitly when the static element is created?

    That could point to the problem - the constructor is being called too early before the system is ready.

    Other posts have noted calling for 'stuff' to happen in constructors can cause such troubles.

    That might be in > DMAChannel::begin

    That should just init values to show it is ready for an explicit .begin() call in setup.

  3. #3
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,748
    When begin_v2_b2() returns all the audio objects have their destructors called and cease to exist. This won't be useful, and won't
    work at all because audio objects that do I/O set up DMA and interrupts which are not tidied up in the destructor, there is no
    explicit destructor in fact... So the DMA or interrupts are then running after the memory they are using has been de-allocated,
    hence immediate crash. [ I think they are actually spraying stuff all over the stack in fact ]

    The audio library is intended to be used as per the audio lib design tool, declared globally and statically. There are some threads
    here about more dynamic use of the audio library with some other branches of it. If you do go down this route you will have to
    use explicit pointers to audio objects in your SOARAudio class.

  4. #4
    Quote Originally Posted by defragster View Post
    If reading right ... the working code has this explicit call in setup(): audio = new SOARAudio();

    Where the failing code has the same code done in the constructor called implicitly when the static element is created?
    The failing code is also calling `new SOARAudio()` in `setup()`. But it's wrapped in a conditional that will never be true, so it never actually gets called. The compiler can't optimize the code out, which forces the `static` code elements of `AudioInputI2S` to be run on boot. At least, that's my theory of what's happening.

    That could point to the problem - the constructor is being called too early before the system is ready.

    Other posts have noted calling for 'stuff' to happen in constructors can cause such troubles.

    That might be in > DMAChannel::begin

    That should just init values to show it is ready for an explicit .begin() call in setup.
    `DMAChannel::begin(true)` might be a problem, but it's being called with `false` which just short circuits and returns.

    Hence my confusion. Argh.

    Quote Originally Posted by MarkT View Post
    When begin_v2_b2() returns all the audio objects have their destructors called and cease to exist. This won't be useful, and won't
    work at all because audio objects that do I/O set up DMA and interrupts which are not tidied up in the destructor, there is no
    explicit destructor in fact... So the DMA or interrupts are then running after the memory they are using has been de-allocated,
    hence immediate crash. [ I think they are actually spraying stuff all over the stack in fact ]
    The Audio objects are being `new`'d and stored in a std::map in an object who's pointer is at global scope. So, several pointer levels removed from global scope, but they are not being destructed by going out of scope.

    The audio library is intended to be used as per the audio lib design tool, declared globally and statically. There are some threads
    here about more dynamic use of the audio library with some other branches of it. If you do go down this route you will have to
    use explicit pointers to audio objects in your SOARAudio class.
    This has me thinking that the audio stuff may not like the fact that my Audio objects AREN'T created yet. The `static` code may be assuming that the objects also exist in the `global` context and already exist when the `static` code runs. This would be a bit of a bummer from an Object Oriented stand point; it makes it impossible for me to write code that responds to the actual hardware its deployed to and change its configuration in response to a hardware-version detection.

    But at the very least, this is easy to test. I'll give it a shot to remove all the object-ness and go back to global objects, see if that fixes the problem.

  5. #5
    Quote Originally Posted by SmittyHalibut View Post
    But at the very least, this is easy to test. I'll give it a shot to remove all the object-ness and go back to global objects, see if that fixes the problem.
    Alas, it didn't work. It still fails when all the Audio objects are defined at global scope. :-(

  6. #6
    Quote Originally Posted by MarkT View Post
    When begin_v2_b2() returns all the audio objects have their destructors called and cease to exist.
    Sorry, I think I see the confusion here. The block that displays first is the block from the Audio tool that's comment out. I just used that as a reference when connecting together the objects below it. That CODE block is scrolling, look below the first page where the objects are actually being created.

    Having said that, moving everything back to the global scope objects as defined by the Audio tool, didn't fix the problem. :-(

  7. #7
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    338
    Works fine for me here, having transposed it to the Arduino IDE. I had to
    • enable instantiation of the SOARaudio class in setup()
    • change from WM8731 to SGTL5000 because that's what I've got
    • set the volume and test tone amplitudes to non-zero
    • fix Connections["MixerDownlinkToI2S"] = new AudioConnection(*Streams["MixerDownlink"], 0, *Streams["I2S_out"], 1);, as AudioMixer4 only has one output

    None of which would appear to have a direct bearing on your issue... I tried with both the current static Audio library and my revised dynamic one, both seem equally happy. I didn't test USB.

    Then ... on closer reading, I think you've said you posted a "dummy" program which doesn't reproduce the issue ... which is a bit of an odd question, "why does this code work?": not very usual for the forum. Can you post a minimal example that actually has a problem?

  8. #8
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Then ... on closer reading, I think you've said you posted a "dummy" program which doesn't reproduce the issue ... which is a bit of an odd question, "why does this code work?": not very usual for the forum. Can you post a minimal example that actually has a problem?
    I agree that none of your changes should impact this, and thanks for catching the AudioConnection bug, I'll fix that in my code. :-)

    I agree that my post was .. awkward.. What I'm actually asking is, how should I even proceed debugging this problem? The normal path of "strip everything away to minimal code to reproduce the problem" led to a program that did NOT reproduce the problem. So, it's likely something in the rest of my code; unfortunately, there's a lot of intertwined "rest of" code, that won't be easy to start stripping away. But that's my only next step, so I'll get started on this today.

    Usually I'd start debugging with Serial.println(), or finally take the time to get some experience with GDB, but neither of those are possible because of where it's failing: before any outside communication starts up.

    Seriously, thank you everyone for your help. Any frustration leaking through my words is with my situation, not at all with anyone here or the advice you've given.

  9. #9
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    338
    Ah, OK, I understand. I don't use PlatformIO myself, so if that's anything to do with your problem I can't help...

    As far as I can tell from other semi-related work, there are no problems caused by having the static elements of Audio library objects compiled in, followed by using 'new' to instantiate them later. This is true even if the objects are mutually-incompatible, for instance AudioOutputI2S and AudioOutputSPDIF (which use the same hardware). However, deleting objects (without using my dynamic audio library) or instantiating multiple copies of incompatible objects definitely causes problems.

    As you say, about the only thing to do is to methodically strip stuff out until you have a single change that provokes the observed failure - it's either then blindingly obvious what you've done, or you have something we can look at! I would recommend trying to do this using the Arduino IDE and Teensyduino, simply because it's the most widely-used platform. I tend to use conditional compilation and / or stub functions to strip down functionality; for a really huge project doing that under version control can be useful, just because it makes it easier to see what changes you've made if it takes more than a few hours' work.

    The only other thing I can suggest is to look at the startup hooks - I don't know much about these so you'll have to search this forum or the PJRC website. As I understand them they let you inject code fragments at key points of the startup process, and might let you show an LED pattern or trigger a scope to help narrow things down a bit.

  10. #10
    I’m out running errands now so I’ll hopefully have more time to bang on this later tonight. But the “look at start up hooks” is a good pointer. Thank you.

    Before I left, I did the easy part of commenting out all of the intertwined code and it’s still failing. So I’ve got an easier situation to debug now. It would have been worse if commending out the big blob of intertwined code made the problem go away. :-)

  11. #11
    Oh wow, I found it. It's TeensyDebug. Let me clean up everything I've just been hacking at, get it back to a state that doesn't resemble a Rube Goldberg device and verify.

  12. #12
    Ok, yes, confirmed: It's TeensyDebug [1]. I don't know the mechanism; once I confirmed that was the conflict, I didn't dig any deeper. I've included what my platformio.ini file looked like that wasn't working, in case this helps anyone in the future. Again, I don't know what of this is breaking it, but I completely removed (well, commented out) all the debugging stuff (including from lib_deps) and the problem went away.

    No more GDB for me I guess.

    Thank you again everyone for your help. I consider this issue closed for me. Hopefully this will help some person from the future who's having similar issues.

    [1] https://github.com/ftrias/TeensyDebug

    Code:
    [env:teensy41]
    platform = teensy
    board = teensy41
    framework = arduino
    lib_deps = 
    	adafruit/Adafruit GFX Library@^1.10.12
    	adafruit/Adafruit BusIO@^1.9.6
    	mikalhart/TinyGPSPlus@^1.0.2
    	bblanchon/ArduinoJson@^6.18.5
    	git@github.com:ftrias/TeensyDebug.git
     	git@github.com:SmittyHalibut/MTP_t4.git
            git@github.com:SmittyHalibut/arduino-dra818.git
            git@github.com:dl9sec/AioP13.git
            git@github.com:Halibut-Electronics/ILI9341_t3.git
    monitor_port = /dev/ttyACM0
    build_flags = -D USB_MIDI_AUDIO_SERIAL
    test_filter = test_*
    test_build_project_src = yes
    
    
    ; Tryin GDB debuggin
    build_type = debug
    ; See https://github.com/platformio/platform-teensy/issues/65
    ; build_unflags = -DUSB_SERIAL
    ; build_flags = -DUSB_DUAL_SERIAL
    ;debug_port = /dev/cu.usbmodem61684903 
    debug_port = /dev/ttyACM0
    debug_tool = custom
    debug_load_mode = manual
    debug_server = 
    debug_init_cmds =
      target extended-remote $DEBUG_PORT
      $INIT_BREAK
      define pio_reset_run_target
      interrupt
      tbreak loop
      continue
      end
      define pio_restart_target
      echo Restart is undefined for now.
      end
    
    debug_init_break =

  13. #13
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    338
    Repeat disclaimer: I Am Not A PlatformIO User! However...

    Looking at the line "; See https://github.com/platformio/platform-teensy/issues/65", I did, and it may be you have to put back the "build_unflags = -DUSB_SERIAL". That should leave USB_MIDI_AUDIO_SERIAL defined but not the conflicting USB_SERIAL. I'd expect it to give you serial but no debug (because you only have one serial port). Or possibly debug but no serial?

    Somewhere in this forum is a set of edits to give you a USB_MIDI_AUDIO_DUAL_SERIAL option, which may help to make your debug work again.

  14. #14
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Repeat disclaimer: I Am Not A PlatformIO User! However...

    Looking at the line "; See https://github.com/platformio/platform-teensy/issues/65", I did, and it may be you have to put back the "build_unflags = -DUSB_SERIAL". That should leave USB_MIDI_AUDIO_SERIAL defined but not the conflicting USB_SERIAL. I'd expect it to give you serial but no debug (because you only have one serial port). Or possibly debug but no serial?

    Somewhere in this forum is a set of edits to give you a USB_MIDI_AUDIO_DUAL_SERIAL option, which may help to make your debug work again.
    That's there as an easier way to say "remove the -D USB_SERIAL above" In reality, I've created my own profile that includes Audio, Serial, and MTP. But I backed off from the MTP features and tested with the provided MIDI_AUDIO_SERIAL to verify I didn't screw up my custom USB profile. If I ended up making heavy use of the GDB stuff (never did), I'd have added a second serial port to my custom USB profile.

    This is all by way of saying that wasn't the problem. The way these -D's are used (A large "#if defined() - #elif defined()" chain; see https://github.com/PaulStoffregen/co...sy4/usb_desc.h) only one will apply anyway. If USB_SERIAL was accidentally still defined, it would take precedence over the MIDI_AUDIO_SERIAL. They wouldn't both clobber each other.

  15. #15
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    338
    True, but if USB_SERIAL "wins" then you don't have an audio interface, which will clobber stuff!

    Just out of interest I had another play with the TeensyDebug add-on, having failed to get it to work ages ago and given up with it. I did manage to get it working this time, both with USB_MIDI_AUDIO_SERIAL and "Take over Serial" mode and a custom USB_MIDI_AUDIO_DUAL_SERIAL and "Manual device selection". Example code, apologies for any incorrect/irrelevant comments, I just grabbed my minimal Blink code to start from:
    Code:
    // Derived from Blink example
    // make it possible to compile for different hardware 
    //#define PRO_MINI
    #define TEENSY
    #if defined(PRO_MINI)
      #define LED 13
      #define ON HIGH
      #define OFF LOW
      #define TXLED0
      #define TXLED1
      #define RXLED0
      #define RXLED1
    #elif defined(TEENSY)
      #define LED 13
      #define ON HIGH
      #define OFF LOW
      #define TXLED0
      #define TXLED1
      #define RXLED0
      #define RXLED1
    #else // Pro Micro/Leonardo (USB)
      #define LED 17 // aka RXLED
      #define OFF HIGH
      #define ON LOW
    #endif
    
    #include "TeensyDebug.h"
    #include "Audio.h"
    
    // GUItool: begin automatically generated code
    AudioSynthWaveform       wav1;      //xy=642,262
    AudioOutputI2S           i2s1;           //xy=851,263
    AudioConnection          patchCord1(wav1, 0, i2s1, 0);
    AudioConnection          patchCord2(wav1, 0, i2s1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=853,305
    // GUItool: end automatically generated code
    
    
    // the setup function runs once when you press reset or power the board
    void setup() 
    {
      debug.begin(SerialUSB1);
      halt_cpu();
    
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.05);
    
      wav1.begin(0.5,220.0,WAVEFORM_SINE);
      
      AudioMemory(10);
      
      // initialize digital pin 13 as an output.
      pinMode(LED, OUTPUT);
      Serial.begin(38400);
      TXLED0;
    
    }
    
    // Gives a pulse of variable length when called
    // followed by a fixed-length off time
    #define LONG 300
    #define SHORT 100
    #define OFF_TIME 200
    void blink(int length, int led=LED)
    {
      digitalWrite(led, ON);     // turn the LED on 
      delay(length);             // wait for time given by parameter
      digitalWrite(led, OFF);    // turn the LED off 
      delay(OFF_TIME);           // wait for fixed time
    }
    
    // the loop function runs over and over again forever
    void loop() {
      blink(LONG);
      blink(LONG);
      blink(SHORT);
      RXLED1;
      delay(SHORT);
      RXLED0;
      Serial.println("Blop!");
      delay(700);              // wait for a second
    }
    This is a mild torture test as the audio blocks are initialised after the I2S output and waveform are started - this seems fine. Apart from audio stopping when the processor is halted at a breakpoint (the claim is that interrupts continue), everything worked as expected. My worst issue was that TeensyDebug seems really poor at identifying the correct debug COM port, though I did give it a pretty hostile environment: COM5 and COM7 are separate non-Teensy ports, single serial was coming up as COM3, and dual as COM4+COM6!

    So my experience is that you can get Teensy 4.1 to run I2S audio, serial and debug all at once, and there must be something else going on with your application.

Posting Permissions

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