Teensy4 SpectrumAnalyzer_Analog curious why it's borked

Hi I was wondering what the exact reason why the Teensy 4.0 doesnt play well with the Spectrum Analyzer code?

I read a bit about the ADC not being sussed out properly, but I thought that was fixed? I saw this discussion and know that with the Teensy 4 and V5 only in OR out i2s is supported.

Since the ADC A2 pin is just being used for input, does it really matter that the ADC itself might not be operating perfectly (optimized for digital vs analog)?

I was able to get my specific 64x64 board working with the V5 shield (Previously was using teensy 3.2 & the shield made for teensy 3.1).

Thanks for any insight.

Just gonna use this thread as a design log I guess.

Current Teensy 4 libraries

Teensy ADC Simple

Teensy 4 ADC same as above without header

Bumblers Teensy 4 ADC Library

Bits and spec

OG code SpectrumAnalyzer_Analog.ino

/*
 * SpectrumAnalyzer Analog Example
 *
 * This version uses an ADC input to receive an Audio signal
 * Tested with Teensy 3
 * Not compatible (as of publishing with the Teensy 4)
 * Not compatible with ESP32
 * 
 * Based on SpectrumAnalyzerBasic by Paul Stoffregen included in the Teensy Audio Library
 * Modified by Jason Coon for the SmartMatrix Library
 * Requires Teensyduino 1.20 or higher and the Teensy Audio Library
 * Also requires FastLED 3.1 or higher
 * If you are having trouble compiling, see
 * the troubleshooting instructions here:
 * https://github.com/pixelmatix/SmartMatrix/#external-libraries
 *
 * Requires the following libraries:
 * Teensy Audio Library: https://github.com/PaulStoffregen/Audio
 * SerialFlash Library (a dependency of the Teensy Audio Library): https://github.com/PaulStoffregen/SerialFlash
 * FastLED v3.1 or higher: https://github.com/FastLED/FastLED/releases
 *
 * Uses line in on pin A2.  For more information, and a recommended analog input circuit, see: http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog
 *
 * You can change the pin used for ADC with the ADC_INPUT_PIN definition below.
 * There are no dedicated ADC pins brought out on the SmartMatrix Shield,
 * but even if you've used all the pins on the SmartMatrix expansion header,
 * you can use solder pins directly to the Teensy to use A14/DAC, A11, or A10
 * 
 * This SmartMatrix example uses just the background layer
 */

// all these libraries are required for the Teensy Audio Library
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// uncomment one line to select your MatrixHardware configuration - configuration header needs to be included before <SmartMatrix.h>
//#include <MatrixHardware_Teensy3_ShieldV4.h>        // SmartLED Shield for Teensy 3 (V4)
//#include <MatrixHardware_Teensy4_ShieldV5.h>        // SmartLED Shield for Teensy 4 (V5)
//#include <MatrixHardware_Teensy3_ShieldV1toV3.h>    // SmartMatrix Shield for Teensy 3 V1-V3
//#include <MatrixHardware_Teensy4_ShieldV4Adapter.h> // Teensy 4 Adapter attached to SmartLED Shield for Teensy 3 (V4)
//#include <MatrixHardware_ESP32_V0.h>                // This file contains multiple ESP32 hardware configurations, edit the file to define GPIOPINOUT (or add #define GPIOPINOUT with a hardcoded number before this #include)
//#include "MatrixHardware_Custom.h"                  // Copy an existing MatrixHardware file to your Sketch directory, rename, customize, and you can include it like this
#include <SmartMatrix.h>
#include <FastLED.h>

#define COLOR_DEPTH 24                  // Choose the color depth used for storing pixels in the layers: 24 or 48 (24 is good for most sketches - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24)
const uint16_t kMatrixWidth = 32;       // Set to the width of your display, must be a multiple of 8
const uint16_t kMatrixHeight = 32;      // Set to the height of your display
const uint8_t kRefreshDepth = 36;       // Tradeoff of color quality vs refresh rate, max brightness, and RAM usage.  36 is typically good, drop down to 24 if you need to.  On Teensy, multiples of 3, up to 48: 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48.  On ESP32: 24, 36, 48
const uint8_t kDmaBufferRows = 4;       // known working: 2-4, use 2 to save RAM, more to keep from dropping frames and automatically lowering refresh rate.  (This isn't used on ESP32, leave as default)
const uint8_t kPanelType = SM_PANELTYPE_HUB75_32ROW_MOD16SCAN;  // Choose the configuration that matches your panels.  See more details in MatrixCommonHub75.h and the docs: https://github.com/pixelmatix/SmartMatrix/wiki
const uint32_t kMatrixOptions = (SM_HUB75_OPTIONS_NONE);        // see docs for options: https://github.com/pixelmatix/SmartMatrix/wiki
const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE);

SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);
SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);

#define ADC_INPUT_PIN   A2

AudioInputAnalog         input(ADC_INPUT_PIN);
AudioAnalyzeFFT256       fft;
AudioConnection          audioConnection(input, 0, fft, 0);

// The scale sets how much sound is needed in each frequency range to
// show all 32 bars.  Higher numbers are more sensitive.
float scale = 256.0;

// An array to hold the 16 frequency bands
float level[16];

// This array holds the on-screen levels.  When the signal drops quickly,
// these are used to lower the on-screen level 1 bar per update, which
// looks more pleasing to corresponds to human sound perception.
int shown[16];

const SM_RGB black = CRGB(0, 0, 0);

byte status = 0;

void setup()
{
    Serial.begin(115200);

    // Initialize Matrix
    matrix.addLayer(&backgroundLayer); 
    matrix.begin();

    matrix.setBrightness(255);

    // Audio requires memory to work.
    AudioMemory(12);
}

void loop()
{
    if (fft.available()) {
        // read the 128 FFT frequencies into 16 levels
        // music is heard in octaves, but the FFT data
        // is linear, so for the higher octaves, read
        // many FFT bins together.

        // I'm skipping the first two bins, as they seem to be unusable
        // they start out at zero, but then climb and don't come back down
        // even after sound input stops
        level[0] = fft.read(2);
        level[1] = fft.read(3);
        level[2] = fft.read(4);
        level[3] = fft.read(5, 6);
        level[4] = fft.read(7, 8);
        level[5] = fft.read(9, 10);
        level[6] = fft.read(11, 14);
        level[7] = fft.read(15, 19);
        level[8] = fft.read(20, 25);
        level[9] = fft.read(26, 32);
        level[10] = fft.read(33, 41);
        level[11] = fft.read(42, 52);
        level[12] = fft.read(53, 65);
        level[13] = fft.read(66, 82);
        level[14] = fft.read(83, 103);
        level[15] = fft.read(104, 127);

        backgroundLayer.fillScreen(black);

        for (int i = 0; i < 16; i++) {
            // TODO: conversion from FFT data to display bars should be
            // exponentially scaled.  But how to keep it a simple example?
            int val = level[i] * scale;

            // trim the bars vertically to fill the matrix height
            if (val >= kMatrixHeight) val = kMatrixHeight - 1;

            if (val >= shown[i]) {
                shown[i] = val;
            }
            else {
                if (shown[i] > 0) shown[i] = shown[i] - 1;
                val = shown[i];
            }

            // color hue based on band
            SM_RGB color = CRGB(CHSV(i * 15, 255, 255));

            // draw the levels on the matrix
            if (shown[i] >= 0) {
                // scale the bars horizontally to fill the matrix width
                for (int j = 0; j < kMatrixWidth / 16; j++) {
                    backgroundLayer.drawPixel(i * 2 + j, (kMatrixHeight - 1) - val, color);
                }
            }
        }

        backgroundLayer.swapBuffers();
    }
}

Tags

display

Platforms

Atmel AVR Espressif 32

Frameworks

Arduino

Authors

Louis Beaudoin (maintainer)

louis@pixelmatix.com

Resources

Homepage

Repository

Downloads

0 in the last day
7 in the last week
32 in the last month

Versions

4.0.3 released a month ago

4.0.2 released a month ago

4.0.0 released a month ago

3.2.0 released over a year ago

3.1.0 released over a year ago

Professional development environment for

When I was working on this the most authoritative note I found on the PJRC forums said that ADC input for the audio library was broken on Teensy 4 and it was something that needed to get fixed. If you go to the Analog input in the audio tool it still says experimental. If you can get it working LMK as it would be nice to include Teensy 4 support in the example.

I was talking to Paul last night about this. He indicated it should work. I built the conditioning circuit, but my audio was not pushing any output through it. I am not quite sure what happened. I was trying the circuit from the previous build I saw, from five years ago, that didnt use smartmatrix (for the conditioning portion), and was still not getting any audio. I will continue to work on this as I want this to work for an installation I am picking away at. I will keep you updated!

Cool, sounds promising. Maybe try a FFT example sketch with a bare Teensy first to rule out any incompatibilities

1 Like

Thats what I was trying with just audio input (~2v) and it was not registering anything.

So trying to run a processing script to serial send data to the Teensy4.

I keep having this issue where the Teensy (COM8, reverted to OG driver), is “in use” somehow when I run the script.

RuntimeException: Error opening serial port COM8: Port busy
RuntimeException: Error opening serial port COM8: Port busy
RuntimeException: Error opening serial port COM8: Port busy

If i stop the processing script, then open serial monitor in arduino IDE, and plug in, then the Teensy shows online.

Hrmn. Pretty close. Got the processing script to do a fft on input audio (from pc) into 8 bars, and sending them as pre scaled INTS over to the Teensy. Teensy is using ‘<’ and ‘>’ sent from script to build an array, then parse through it and push to the led display.

HRMN serial monitor doesnt update UNTIL I reset the teensy via the button, and then the Teensy doesnt return to proper operation and kicks the red light on. HRMN!

If I reset (unplug, replug) the Teensy 4, then start the Processing sketch, it just “hangs” :slight_smile:

If I set the serial assignment to [0] (first comm port) vs [1] (for me , comm 8 where Teensy 4 is at), the processing sketch starts to push to display vs erroring out - but still no serial (obvi):
image

TEENSY INO

    #include <MatrixHardware_Teensy4_ShieldV5.h>        // SmartLED Shield for Teensy 4 (V5)
    #include <SmartMatrix.h>
#include <FastLED.h
#define COLOR_DEPTH 24                  // Choose the color depth used for storing pixels in the layers: 24 or 48 (24 is good for most sketches - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24)
    const uint16_t kMatrixWidth = 64;       // Set to the width of your display, must be a multiple of 8
    const uint16_t kMatrixHeight = 64;      // Set to the height of your display
    const uint8_t kRefreshDepth = 36;       // Tradeoff of color quality vs refresh rate, max brightness, and RAM usage.  36 is typically good, drop down to 24 if you need to.  On Teensy, multiples of 3, up to 48: 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48.  On ESP32: 24, 36, 48
    const uint8_t kDmaBufferRows = 4;       // known working: 2-4, use 2 to save RAM, more to keep from dropping frames and automatically lowering refresh rate.  (This isn't used on ESP32, leave as default)
    
    const uint8_t kPanelType = SM_PANELTYPE_HUB75_64ROW_MOD32SCAN;   // Choose the configuration that matches your panels.  See more details in MatrixCommonHub75.h and the docs: https://github.com/pixelmatix/SmartMatrix/wiki
    
    const uint32_t kMatrixOptions = (SM_HUB75_OPTIONS_NONE);        // see docs for options: https://github.com/pixelmatix/SmartMatrix/wiki
    const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE);
    const uint8_t kScrollingLayerOptions = (SM_SCROLLING_OPTIONS_NONE);
    const uint8_t kIndexedLayerOptions = (SM_INDEXED_OPTIONS_NONE);
    
    SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);
    
    SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);
    
    #ifdef USE_ADAFRUIT_GFX_LAYERS
      // there's not enough allocated memory to hold the long strings used by this sketch by default, this increases the memory, but it may not be large enough
      SMARTMATRIX_ALLOCATE_GFX_MONO_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, 6*1024, 1, COLOR_DEPTH, kScrollingLayerOptions);
    #else
      SMARTMATRIX_ALLOCATE_SCROLLING_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kScrollingLayerOptions);
    #endif
    
    SMARTMATRIX_ALLOCATE_INDEXED_LAYER(indexedLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kIndexedLayerOptions);
    
    
    
    //const int defaultBrightness = (100*255)/100;        // full (100%) brightness
    const int defaultBrightness = (35*255)/100;       // dim: 10% brightness
    const int defaultScrollOffset = 6;
    const rgb24 defaultBackgroundColor = {0x40, 0, 0};
    
    // Teensy 3.0 has the LED on pin 13
    const int ledPin = 13;
    // The scale sets how much sound is needed in each frequency range to
    // show all 32 bars.  Higher numbers are more sensitive.
    float scale = 256.0;
    
    // An array to hold the 8 frequency bands
    float spectrum[8]; 
    
    
    // This array holds the on-screen levels.  When the signal drops quickly,
    // these are used to lower the on-screen level 1 bar per update, which
    // looks more pleasing to corresponds to human sound perception.
    int shown[8];
    
    const SM_RGB black = CRGB(0, 0, 0);
    
    byte status = 0;
    
    
    //serial stuff
    const byte numChars = 9;
    char receivedChars[numChars];   // an array to store the received data
    
    boolean newData = false;
    
    int dataNumber = 0;             // new for this version
    
    
    
    
    // the setup() method runs once, when the sketch starts
    void setup() {
      // initialize the digital pin as an output.
      pinMode(ledPin, OUTPUT);
    
      Serial.begin(115200);
      Serial.println("Ayo we connected");
      
      matrix.addLayer(&backgroundLayer); 
      matrix.addLayer(&scrollingLayer); 
      matrix.addLayer(&indexedLayer); 
      matrix.begin();
    
      matrix.setBrightness(defaultBrightness);
    
      scrollingLayer.setOffsetFromTop(defaultScrollOffset);
    
      backgroundLayer.enableColorCorrection(true);
    }
    
    void loop(){
    
    
    //    float spectrum[] = Serial.read();
         scrollingLayer.setColor({0xff, 0xff, 0xff});
        scrollingLayer.setMode(wrapForward);
        scrollingLayer.setSpeed(40);
        scrollingLayer.setFont(font5x7);
        scrollingLayer.setOffsetFromTop(10);
        backgroundLayer.fillScreen(black);
    
    
        static byte ndx = 0;
        char endMarker = '\n';
        char rc;
    
       
        if (Serial.available() > 0) {
            rc = Serial.read();
    
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                ndx = 0;
                newData = true;
            }
        }
    
    
        
        
    
    
    
    
    
            for (int i = 0; i < 9; i++) {
               // trim the bars vertically to fill the matrix height
               int val = atoi(receivedChars[i]);
               
                if (val >= kMatrixHeight) val = kMatrixHeight - 1;
    
                if (val >= shown[i]) {
                    shown[i] = val;
                }
                else {
                    if (shown[i] > 0) shown[i] = shown[i] - 1;
                    val = shown[i];
                }
    
                // color hue based on band
                SM_RGB color = CRGB(CHSV(i * 15, 255, 255));
              
    
                // draw the levels on the matrix
                if (shown[i] >= 0) {
                    // scale the bars horizontally to fill the matrix width
                    for (int j = 0; j < kMatrixWidth / 8; j++) {
                        backgroundLayer.drawPixel(i * 2 + j, (kMatrixHeight - 1) - val, color);
                    }
                }
            }
    
            backgroundLayer.swapBuffers();
    
    
     
        
    }
    
    
    
    //change serial to this method:
    //https://forum.arduino.cc/index.php?topic=396450.msg2727728#msg2727728

PROCESSING SKETCH PDE

    import processing.sound.*;
    import processing.serial.*;
    
    Serial transfer;  // create object from serial class
    
    FFT fft;
    AudioIn in;
    int bands = 8;
    float[] spectrum = new float[bands];
    float scale = 256.0;
    
    
    
    // This array holds the on-screen levels.  When the signal drops quickly,
    // these are used to lower the on-screen level 1 bar per update, which
    // looks more pleasing to corresponds to human sound perception.
    
    
    void setup() {
        size(512, 360);
        background(255);
        
        String portName = Serial.list()[1];
        transfer = new Serial(this, portName, 115200);
        
        
        //select the device
        Sound s = new Sound(this);
        //Sound.list();
        //for (int q = 0; q < 32; q++){
        
        s.inputDevice(11);
      
      
        // Create an Input stream which is routed into the Amplitude analyzer
        fft = new FFT(this, bands);
        in = new AudioIn(this, 0);
      
      
      
        // start the Audio Input
        in.start();
        
        // patch the AudioIn
        fft.input(in);
        
        loop();
    }      
    void draw() { 
    
        background(255);
        fft.analyze(spectrum);
     
        // do the float to int parsing on this side, and figure out a good way to send the INTS over 
        //https://forum.arduino.cc/index.php?topic=396450.msg2727728#msg2727728
      //  transfer.write(spectrum);
     //   transfer.write('<'); //begin array char send
    
        for(int i = 0; i < bands; i++){
        // The result of the FFT is normalized into an int
          int val = int(spectrum[i] * scale);
       //   transfer.write(val);
          strokeWeight(20);
        line( i*20, height, i*20, height - spectrum[i]*height*5 );
        } 
    
        //transfer.write('<'); // end array char send
       
    }

PROCESSING PDE TO GET SERIAL PORT ASSIGNMENTS AND SOUND ID ASSIGNMENTS

    import processing.sound.*;
    import processing.serial.*;
    
    void setup(){
    //  Serial myPort;
      printArray(Serial.list());
      
      Sound s = new Sound(this);
     Sound.list();
    }

Might try to do ADC again with this library in a bit: https://forum.pjrc.com/threads/25532-ADC-library-with-support-for-Teensy-4-3-x-and-LC?highlight=ADC+library

Trying the example Teensy USBtoSerial.ino blips the LED whenever I hit the serial monitor with any data, so hrmn. Unsure where the pipeline is borking.

With that example sketch and teh SimpleWrite.pde example The Teensy4 shows data, so I think I am closing in on the issue!

found a lot of bugs in my code. Kinda works for like a moment. Updated INO:

        #include <MatrixHardware_Teensy4_ShieldV5.h>        // SmartLED Shield for Teensy 4 (V5)
    #include <SmartMatrix.h>
    #include <FastLED.h>    
#define COLOR_DEPTH 24                  // Choose the color depth used for storing pixels in the layers: 24 or 48 (24 is good for most sketches - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24)
    const uint16_t kMatrixWidth = 64;       // Set to the width of your display, must be a multiple of 8
    const uint16_t kMatrixHeight = 64;      // Set to the height of your display
    const uint8_t kRefreshDepth = 36;       // Tradeoff of color quality vs refresh rate, max brightness, and RAM usage.  36 is typically good, drop down to 24 if you need to.  On Teensy, multiples of 3, up to 48: 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48.  On ESP32: 24, 36, 48
    const uint8_t kDmaBufferRows = 4;       // known working: 2-4, use 2 to save RAM, more to keep from dropping frames and automatically lowering refresh rate.  (This isn't used on ESP32, leave as default)
    
    const uint8_t kPanelType = SM_PANELTYPE_HUB75_64ROW_MOD32SCAN;   // Choose the configuration that matches your panels.  See more details in MatrixCommonHub75.h and the docs: https://github.com/pixelmatix/SmartMatrix/wiki
    
    const uint32_t kMatrixOptions = (SM_HUB75_OPTIONS_NONE);        // see docs for options: https://github.com/pixelmatix/SmartMatrix/wiki
    const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE);
    const uint8_t kScrollingLayerOptions = (SM_SCROLLING_OPTIONS_NONE);
    const uint8_t kIndexedLayerOptions = (SM_INDEXED_OPTIONS_NONE);
    
    SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);
    
    SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);
    
    #ifdef USE_ADAFRUIT_GFX_LAYERS
      // there's not enough allocated memory to hold the long strings used by this sketch by default, this increases the memory, but it may not be large enough
      SMARTMATRIX_ALLOCATE_GFX_MONO_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, 6*1024, 1, COLOR_DEPTH, kScrollingLayerOptions);
    #else
      SMARTMATRIX_ALLOCATE_SCROLLING_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kScrollingLayerOptions);
    #endif
    
    SMARTMATRIX_ALLOCATE_INDEXED_LAYER(indexedLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kIndexedLayerOptions);
    
    
    
    //const int defaultBrightness = (100*255)/100;        // full (100%) brightness
    const int defaultBrightness = (35*255)/100;       // dim: 10% brightness
    const int defaultScrollOffset = 6;
    const rgb24 defaultBackgroundColor = {0x40, 0, 0};
    
    // Teensy 3.0 has the LED on pin 13
    const int ledPin = 13;
    // The scale sets how much sound is needed in each frequency range to
    // show all 32 bars.  Higher numbers are more sensitive.
    float scale = 256.0;
    
    // An array to hold the 8 frequency bands
    float spectrum[8]; 
    
    
    // This array holds the on-screen levels.  When the signal drops quickly,
    // these are used to lower the on-screen level 1 bar per update, which
    // looks more pleasing to corresponds to human sound perception.
    int shown[8];
    
    const SM_RGB black = CRGB(0, 0, 0);
    
    byte status = 0;
    
    
    //serial stuff
    const byte numChars = 8;
    int receivedChars[numChars];   // an array to store the received data
    
    boolean newData = false;
    
    int dataNumber = 0;             // new for this version
    
    
    
    
    // the setup() method runs once, when the sketch starts
    void setup() {
      // initialize the digital pin as an output.
      pinMode(ledPin, OUTPUT);
    
      Serial.begin(9600);
      Serial.println("Ayo we connected");
      
      matrix.addLayer(&backgroundLayer); 
      matrix.addLayer(&scrollingLayer); 
      matrix.addLayer(&indexedLayer); 
      matrix.begin();
    
      matrix.setBrightness(defaultBrightness);
    
      scrollingLayer.setOffsetFromTop(defaultScrollOffset);
    
      backgroundLayer.enableColorCorrection(true);
    }
    
    void loop(){
    
    
    //    float spectrum[] = Serial.read();
         scrollingLayer.setColor({0xff, 0xff, 0xff});
        scrollingLayer.setMode(wrapForward);
        scrollingLayer.setSpeed(40);
        scrollingLayer.setFont(font5x7);
        scrollingLayer.setOffsetFromTop(10);
        backgroundLayer.fillScreen(black);
    
    
        static byte ndx = 0;
        char endMarker = '>';
        char begMarker = '<';
        char rc;
    
       
        if (Serial.available() > 0) {
            rc = Serial.read();
    
            if (rc = begMarker) {
              while (rc != endMarker){
                rc = Serial.read();
                receivedChars[ndx] = atoi(rc);
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
      //      else {
             //  receivedChars[ndx] = '\0'; // terminate the string
                ndx = 0;
                newData = true;
            }
        }
    
    
        
        
    
    
    
    
    
            for (int i = 0; i < 9; i++) {
               // trim the bars vertically to fill the matrix height
               int val = receivedChars[i];
               
                if (val >= kMatrixHeight) val = kMatrixHeight - 1;
    
                if (val >= shown[i]) {
                    shown[i] = val;
                }
                else {
                    if (shown[i] > 0) shown[i] = shown[i] - 1;
                    val = shown[i];
                }
    
                // color hue based on band
                SM_RGB color = CRGB(CHSV(i * 15, 255, 255));
              
    
                // draw the levels on the matrix
                if (shown[i] >= 0) {
                    // scale the bars horizontally to fill the matrix width
                    for (int j = 0; j < kMatrixWidth / 8; j++) {
                        backgroundLayer.drawPixel(i * 2 + j, (kMatrixHeight - 1) - val, color);
                    }
                }
                newData = false;
    
            }
    
            backgroundLayer.swapBuffers();
    
    
     
        
    }