Teensy 4 audio ticking with audio board and Neopixels

Status
Not open for further replies.

jgoldader

Member
Hello-
First post here. I have a problem with rapid ticking on top of a WAV being played, listening with earbuds through the audio plug of a Teensy soundboard. Equipment: Teensy 4, Audio Board Rev. D, I2C OLED screen, Neopixel 8x5 matrix (with 74AHCT125 level shifter). The Teensy is powered by USB from a dock, Neopixels are powered by an Adafruit 5V power supply. Grounds are tied together.

The project is a light board like at the end of Close Encounters. The Teensy reads a WAV off the micro-SD, plays the audio through the earphone jack on the audio board, calculates the FFT of the sound, displays the FFT on a 1.3" OLED monitor, and maps the FFT onto the Neopixel matrix. Though I'm pretty new with Arduinos and brand new with Teensy, the code works, with one little problem.

When I was building the code, up through computing and displaying the FFT on the OLED, the sound through the earphones was perfect. However, a problem with the audio showed up when I introduced the Neopixels. When I'm using the Neopixels, there's a rapid ticking that I think is connected to the Neopixel updating; putting in a delay after the updating (delaying the next run through the loop that assigns brightnesses and updates the OLED) results in a change to the ticking frequency (greater delay means more time between ticks). Ticking is there with a small powered speaker as well, so it's not just the earphones.

I'd like to be able to get rid of the ticking. Not sure what I'm doing wrong, if the problem is in the code or if I'm missing some component in the circuit. I don't have any resistors or capacitors in the circuit (except for one in the power supply line) and maybe I need to put some somewhere, but I don't know where to start on that.

Thank you for whatever ideas you have.

Code:
// 
//Based mainly on:
// Advanced Microcontroller-based Audio Workshop
//
// http://www.pjrc.com/store/audio_tutorial_kit.html
// https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015
// 
//


#include <Adafruit_NeoPixel.h>  //For the Neopixels

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

// OLED routines here
#include <Adafruit_GFX.h>                             // graphics library for display
#include <Adafruit_SSD1306.h>                         // SSD1306 OLED display library
#define OLED_RESET 5                                  // OLED library likes to see this but it isn't used here with I2C, changed to deconflict with sound board
#define OLED_ADDR 0x3D                                // OLED I2C address
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);                 // create instance of OLED display
byte ylim = 60;                                       //sets vertical pixel limit of histogram

//below, do Neopixel setup, to CE3K light board colors
#define PIN 6  // Which pin on the Arduino is connected to the NeoPixels?
#define NUMPIXELS 40  //There are 40 Neopixels on the board
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//set up color mapping for the Neopixels
int redc[] ={255,255,175,50,0,96,168,218,255,255,150,25,0,128,178,228,255,255,125,0,0,138,288,238,255,230,100,0,32,148,198,248,255,200,75,0,64,158,208,255};
int greenc[]={128,218,255,255,102,0,0,0,146,236,255,255,51,0,0,0,164,255,255,255,0,0,0,0,182,255,255,204,0,0,0,0,200,255,255,153,0,0,0,0};
int bluec[]={0,0,0,0,153,255,155,55,0,0,0,0,202,255,135,35,0,0,0,0,255,235,115,15,0,0,0,51,255,205,95,0,0,0,0,102,255,185,75,0};
int MAXBRIGHT=10;
//for storing the Neopixel brightnesses
int reds[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int greens[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int blues[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//

//next code initializes many things, taken from the graphical audio configurator
AudioPlaySdWav           playWav1;
AudioMixer4              mixer1;
AudioOutputI2S           audioOutput; //plays through 3.5mm jack
AudioControlSGTL5000     sgtl5000_1;
AudioAnalyzeFFT1024      fft1024_1;      //xy=562,298
AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
AudioConnection          patchCord3(playWav1, 0, mixer1, 0);
AudioConnection          patchCord4(playWav1, 1, mixer1, 1);
AudioConnection          patchCord5(mixer1, fft1024_1);

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7  //changing these from their defaults to deconflict with the I2C display
#define SDCARD_SCK_PIN   14 //changing these from their defaults to deconflict with the I2C display


void setup() {

  //OLED setup information
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);     // initialize OLED display
  display.clearDisplay();                             // blank the display
  display.setTextSize(1);                             // configure text properties
  display.setTextColor(WHITE);

  //Neopixel setup information
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.clear(); // Set all pixel colors to 'off'
  
  Serial.begin(9600);
  AudioMemory(100);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.2);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
    if (!(SD.begin(SDCARD_CS_PIN))) {
     while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
      }
    }
 
  mixer1.gain(0, 2.0);
  mixer1.gain(1, 2.0);
  mixer1.gain(2, 0.0);
  mixer1.gain(3, 0.0);
  // Uncomment one these to try other window functions
  fft1024_1.windowFunction(AudioWindowHanning1024);
  // fft1024_1.windowFunction(NULL);
  // fft1024_1.windowFunction(AudioWindowBartlett1024);
  // fft1024_1.windowFunction(AudioWindowFlattop1024);
  delay(1000);
//  playWav1.play("DIALOGUE.WAV");
  Serial.print("Finishing setup");
  Serial.println();
  
}



void loop() {                                              // begin the master loop
  pixels.clear(); // Set all Neopixels to 'off'
  playWav1.play("DIALOGUE.WAV");                           // "Play the five tones..."
  display.clearDisplay();                                  // clear the OLED display
  display.display();                                       // send the data to the OLED display
  delay(10);                                               // give time for the music to start
  while (playWav1.isPlaying()) {  //while the music is playing, compute and display the FFT
    // uncomment these lines if you audio shield
    // has the optional volume pot soldered
    //float vol = analogRead(15);
    //vol = vol / 1024;
    // sgtl5000_1.volume(vol)
    
  
    // print Fourier Transform data to the Arduino Serial Monitor and OLED
    if (fft1024_1.available()) {
       display.clearDisplay();                             // clear the OLED display
       display.setCursor(0, 0);                            // set cursor to top left corner of the display
       display.print("Audio Spectrum");                    // print a header on the top row of the display
    
 //      Serial.print("FFT: ");
       for (int i=0; i<40; i++) {  // 0-60  -->  DC to 23409 Hz at 39 Hz/bin
       float n = fft1024_1.read(i);
 //      printNumber((n));
       display.drawLine(i*2, ylim, i*2, ylim - (512*n), WHITE);
       // calculate the brightnesses of the pixels
          reds[i]=redc[i]*((512*n)/64)*MAXBRIGHT/255;
          greens[i]=greenc[i]*((512*n)/64)*MAXBRIGHT/255;
          blues[i]=bluec[i]*((512*n)/64)*MAXBRIGHT/255;
          //below are sanity checks for LED brightness
          if(reds[i]>=250) {
              reds[i]=250;
             }
                    if(greens[i]>=250) {
              greens[i]=250;
             }
                    if(blues[i]>=250) {
              blues[i]=250;
             }
          pixels.setPixelColor(i, pixels.Color(reds[i], greens[i], blues[i]));
          }
          
       }
//    Serial.println();
    display.display();      //send the FFT data to the OLED display
    pixels.show();          // Send the updated pixel colors to the Neopixels

   
  
 } //This loop finishes when the music stops; then the master loop repeats, restarting the music

}

void printNumber(float n) {                               //this function sets up the format for printing output to the serial line
  
  if (n >= 0.003) {
    Serial.print(n, 3);
    Serial.print(" ");
  } else {
    Serial.print("   -  "); // don't print "0.00"
  }
 
}
 
I was able to change the code to use the FastLED library, and everything basically works, but I still have the ticking. I tried adding in #define FASTLED_ALLOW_INTERRUPTS 0 before #include <FastLED.h> and the code refused to compile. If I replace that interrupt line with #define FASTLED_INTERRUPT_RETRY_COUNT 1, the code works (with ticking noise), but it's not very stable, there are LED and audio glitches.

Any other ideas? If I have to live with it as-is, it's good enough for the immediate purpose, but I would like to figure out the ticking at some point.

Thanks again.
 
I'm fairly sure the neopixels are ws2811s (rather than ws2812s)

The OctoWS2811.h lib is another of Paul's non-blocking libs that you can use with FastLED as in #5
 
I'm fairly sure the neopixels are ws2811s (rather than ws2812s)

The OctoWS2811.h lib is another of Paul's non-blocking libs that you can use with FastLED as in #5

I believe the original Adafruit neopixels used the WS2812's, then moved to the WS2812B's, and now they generally use SK6812's.

Here are two pages that I've seen that compare them:

IIRC, the WS2812B's were the ones that needed at least 4.5v power, and needed the high speed level shifting to go from a 3.3v data signal to 5v. I've run SK6812's on lipo batteries (i.e. 3.7v) and even off of 3.3v from the Teensy (providing I'm careful not to exceed the 250ma power for the Teensy + LEDs).
 
Maybe I’m doing this the hard way... Could I get a 3.5 mm male to 2x (L/R) RCA cord, strip the RCA ends and solder them to the line-in on the audio board? And plug the 3.5mm plug into any old source for the audio input, rather than reading/playing a WAV from the SD card? I can use a splitter to send the audio to a portable speaker at the same time. Then the Teensy won’t have to play the sound, just “listen.”

Should that work? No capacitors or whatever needed?
 
M...Could I get a 3.5 mm male to 2x (L/R) RCA cord, strip the RCA ends and solder them to the line-in on the audio board? And plug the 3.5mm plug into any old source for the audio input, rather than reading/playing a WAV from the SD card? I can use a splitter to send the audio to a portable speaker at the same time. Then the Teensy won’t have to play the sound, just “listen.” ...

Yes you could do that.
You could use your audio board as the splitter if you setup the mixers.
I know thats what I did rather than looking into an issues I was having with sdcard playback octows2811 code.
It's something else to help you diagnose your issue anyway.
 
Well, this was an adventure, but it ended well!

I got the line in to work, no trouble at all. FastLED worked well in "demo" mode, just to set the pixel colors. However, it absolutely refused to address more than about 26 of the Neopixels in the array, no matter what I did, when it was "active". (EDIT: I think it was a timing error.) So, I resurrected the version I wrote using the Neopixel library, modifying it to work with the line in. I'm very happy with the end result.

I'm grateful for the suggestions! Here's the code, in case someone else wants to try this project.

Code:
// 
//Based mainly on:
// Advanced Microcontroller-based Audio Workshop
//
// http://www.pjrc.com/store/audio_tutorial_kit.html
// https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015
//  OLED display routines from learnelectronics:      https://www.youtube.com/watch?v=5RmQJtE61zE
// 
//


#include <Adafruit_NeoPixel.h>  //For the Neopixels

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

// OLED routines here
#include <Adafruit_GFX.h>                             // graphics library for display
#include <Adafruit_SSD1306.h>                         // SSD1306 OLED display library
#define OLED_RESET 5                                  // OLED library likes to see this but it isn't used here with I2C, changed to deconflict with sound board
#define OLED_ADDR 0x3D                                // OLED I2C address
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);                 // create instance of OLED display
byte ylim = 60;                                       //sets vertical pixel limit of histogram

//below, do Neopixel setup, to CE3K light board colors
#define PIN 1  // Which pin on the Arduino is connected to the NeoPixels?
#define NUMPIXELS 40  //There are 40 Neopixels on the board
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//set up color mapping for the Neopixels
int redc[] ={255,255,175,50,0,96,168,218,255,255,150,25,0,128,178,228,255,255,125,0,0,138,288,238,255,230,100,0,32,148,198,248,255,200,75,0,64,158,208,255};
int greenc[]={128,218,255,255,102,0,0,0,146,236,255,255,51,0,0,0,164,255,255,255,0,0,0,0,182,255,255,204,0,0,0,0,200,255,255,153,0,0,0,0};
int bluec[]={0,0,0,0,153,255,155,55,0,0,0,0,202,255,135,35,0,0,0,0,255,235,115,15,0,0,0,51,255,205,95,0,0,0,0,102,255,185,75,0};
int MAXBRIGHT=25;
//for storing the Neopixel brightnesses
int reds[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int greens[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int blues[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
float scalfac[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//

//next code initializes many things, taken from the graphical audio configurator
AudioInputI2S            i2s1;           //xy=180,280
AudioMixer4              mixer1;         //xy=392,202
AudioAnalyzeFFT1024      fft1024_1;      //xy=570,196
AudioConnection          patchCord1(i2s1, 0, mixer1, 0);
AudioConnection          patchCord3(i2s1, 1, mixer1, 1);
AudioConnection          patchCord5(mixer1, fft1024_1);
AudioControlSGTL5000     sgtl5000_1;     //xy=302,184

const int myInput = AUDIO_INPUT_LINEIN;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7  //changing these from their defaults to deconflict with the I2C display
#define SDCARD_SCK_PIN   14 //changing these from their defaults to deconflict with the I2C display


void setup() {

  //OLED setup information
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);     // initialize OLED display
  display.clearDisplay();                             // blank the display
  display.setTextSize(1);                             // configure text properties
  display.setTextColor(WHITE);

  //Neopixel setup information
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
  pixels.clear(); // Set all pixel colors to 'off'
  
  for(int i=0;i<40;i++) {
    scalfac[i]=3./39.*(float(i))+1; //scaling factor qualitatively accounts for the fact that higher frequencies sound louder

  }
  
  // Enable the audio shield, select input, and enable output
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.5);
  //  
  Serial.begin(9600);
  AudioMemory(100);

 
  mixer1.gain(0, 4);
  mixer1.gain(1, 4);
  mixer1.gain(2, 0.0);
  mixer1.gain(3, 0.0);

  fft1024_1.windowFunction(AudioWindowHanning1024);
  
} //end Setup



void loop() {               // begin the master loop
  
  pixels.clear();           // Set all Neopixels to 'off'
  display.clearDisplay();   // clear the OLED display

  
    // in the loop below, take, scale, and print Fourier Transform data to the Neopixels and OLED
    
    if (fft1024_1.available()) {
       display.clearDisplay();                             // clear the OLED display
       display.setCursor(0, 0);                            // set cursor to top left corner of the display
       display.print("Audio Spectrum");                    // print a header on the top row of the display
    

       for (int i=0; i<40; i++) {  // 0-39 there are 40 pixels in the array, and 43 Hz per bin
//Decided to add 3 consecutive bins together; squeezing FFT to cover up to 5220 Hz
          float n=scalfac[i]*((fft1024_1.read(3*i)+fft1024_1.read(3*i+1)+fft1024_1.read(3*i+2))/3.0);
                
          if((i<1)) {  //low-frequency noise suppression in the first couple of bins
             if(n>=0.05){
              n=n-0.05;
             }
          }
          
       // draw the line for this bin on the OLED; the 512 was found from experimentation
       display.drawLine(i*2, ylim, i*2, ylim - (512*n), WHITE);
       
       // calculate the brightnesses of the pixels; coefficient 32 found from experimentation

          reds[i]=redc[i]*(n/32)*MAXBRIGHT;
          greens[i]=greenc[i]*(n/32)*MAXBRIGHT;
          blues[i]=bluec[i]*(n/32)*MAXBRIGHT;

          //below are sanity checks for LED brightness, keep them below 250 no matter what
          //
          if(reds[i]>=250) {
              reds[i]=250;
             }
          if(greens[i]>=250) {
              greens[i]=250;
             }
          if(blues[i]>=250) {
              blues[i]=250;
             }

          pixels.setPixelColor(i, pixels.Color(reds[i], greens[i], blues[i])); //build the Neopixel data array
          } //finish the pixel-by-pixel calculations
          
       }  //finish the FFT analysis loop

    display.display();      // send the FFT data to the OLED display
    pixels.show();          // send the updated pixel data to the Neopixels

}

void printNumber(float n) {     //this function sets up the format for printing output to the serial line, for debugging
  
  if (n >= 0.003) {
    Serial.print(n, 3);
    Serial.print(" ");
  } else {
    Serial.print("   -  "); // don't print "0.00"
  }
 
}
 
Last edited:
Status
Not open for further replies.
Back
Top