Confusion over timers with LEDs and MSGEQ7 [SOLVED]

Hey there!

I’ve been trying to combine an LED strip with an audio sensor and an MSGEQ7 IC to create a music reactive strip. Pretty standard project I know, but I though it would be good for a first attempt at using an arduino with sensors.

To read outputs from the IC it has to be called based on certain timings. To match these timings I have added delay() functions, however I need to change these to timer interrupts. Here’s where the issue lies. As I have to put these delays/interrupts within a for loop, and there is another delay in the loop() function, I dont know how to implement these interrupts without affecting the rest of my code. I could try to use interrupts for the later delay() function instead, but that delay is specific to a certain library that is pretty much necessary. I just cant get my head around this problem. Below is the section of code in question:

void loop()
{

    // Cycle through each frequency band by pulsing the strobe.
    for (int i = 0; i < 7; i++) {
      digitalWrite       (strobePin, LOW);
      delayMicroseconds  (100);                    // Delay necessary due to MSGEQ7 timing diagram
      level[i] =         map(analogRead (outPin),1,1023,1,10);
      digitalWrite       (strobePin, HIGH);
      delayMicroseconds  (100);                    // Delay necessary due to MSGEQ7 timing diagram
    }
   
    for (int i = 0; i < 7; i++) {
      Serial.print       (level[i]);
      Serial.print       ("   ");
    }
   
    Serial.println ();  
  
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
}

MSGEQ7 datasheet: https://www.sparkfun.com/datasheets/Components/General/MSGEQ7.pdf

Thanks for any help you can give!

P.S. Sorry if this topic is in the wrong section. Couldn’t decide if it was LEDs, Sensors or here :stuck_out_tongue:

I'm pretty sure this can be done without using interrupts. Is there some reason you have to use FastLED.delay()?

Also, it might be helpful if you post you entire sketch.

It normally helps to post the whole sketch rather than just a part as it normally makes things much clearer.
Why can you not use a state machine? and as a consequence use millis() rather than delay?

ToddL1962:
I’m pretty sure this can be done without using interrupts. Is there some reason you have to use FastLED.delay()?

Also, it might be helpful if you post you entire sketch.

countrypaul:
It normally helps to post the whole sketch rather than just a part as it normally makes things much clearer.
Why can you not use a state machine? and as a consequence use millis() rather than delay?

Cheers for the responses and sorry about that, thought just the loop would do but will post the whole sketch below. The reason for using FastLED.delay() is that it still calls FastLED.show() and can correctly adjust changes in brightness. Supposedly there are a few other reasons but I’m no expert sadly. I will give it a test with a standard delay() and see how noticeable the effects are to see if I can run without it though! :slight_smile:

In response to using a state machine; as the reactivity portion of this project requires constant input, adding states would cause the LEDs to freeze each time I try and read the input. The result (I’m assuming) would be that the strip wouldn’t be able to react in a visually pleasing fashion if it’s switching states from updating LEDs to reading inputs. I will give this a go however and let you know if it works!

#include <FastLED.h>

#define LED_PIN     6
#define NUM_LEDS    300
#define BRIGHTNESS  10
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100

CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;

//Visualiser IC pins
int strobePin  = 7;    // Strobe Pin on the MSGEQ7
int resetPin   = 8;    // Reset Pin on the MSGEQ7
int outPin     = A5;   // Output Pin on the MSGEQ7
int level[7];          // An array to hold the values from the 7 frequency bands
int mappedValue = 0;   // Sensor values mapped

int period = 100;
unsigned long time_now = 0;

void setup() {

    Serial.begin (9600);
    
    // Define our pin modes
    pinMode      (strobePin, OUTPUT);
    pinMode      (resetPin,  OUTPUT);
    pinMode      (outPin,    INPUT);
 
    // Create an initial state for our pins
    digitalWrite (resetPin,  LOW);
    digitalWrite (strobePin, LOW);
    delay        (1);
 
    // Reset the MSGEQ7 as per the datasheet timing diagram
    digitalWrite (resetPin,  HIGH);
    delay        (1);
    digitalWrite (resetPin,  LOW);
    digitalWrite (strobePin, HIGH);
    delay        (1);
    
    delay( 3000 ); // power-up safety delay
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;
}


void loop()
{

    // Cycle through each frequency band by pulsing the strobe.
    for (int i = 0; i < 7; i++) {
      digitalWrite       (strobePin, LOW);
      delayMicroseconds  (100);                    // Delay necessary due to timing diagram
      level[i] =         map(analogRead (outPin),1,1023,1,10);
      digitalWrite       (strobePin, HIGH);
      delayMicroseconds  (100);                    // Delay necessary due to timing diagram  
    }
   
    for (int i = 0; i < 7; i++) {
      Serial.print       (level[i]);
      Serial.print       ("   ");
    }
   
    Serial.println ();  
  
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
}

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
    uint8_t brightness = 255;
    
    for( int i = 0; i < NUM_LEDS; i++) {
        leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
        colorIndex += 3;
    }
}

void ChangePalettePeriodically()
{
    uint8_t secondHand = (millis() / 1000) % 60;
    static uint8_t lastSecond = 99;
    
    if( lastSecond != secondHand) {
        lastSecond = secondHand;
        if( secondHand ==  0)  { currentPalette = RainbowColors_p;         currentBlending = LINEARBLEND; }
        if( secondHand == 10)  { currentPalette = RainbowStripeColors_p;   currentBlending = NOBLEND;  }
        if( secondHand == 15)  { currentPalette = RainbowStripeColors_p;   currentBlending = LINEARBLEND; }
        if( secondHand == 20)  { SetupPurpleAndGreenPalette();             currentBlending = LINEARBLEND; }
        if( secondHand == 25)  { SetupTotallyRandomPalette();              currentBlending = LINEARBLEND; }
        if( secondHand == 30)  { SetupBlackAndWhiteStripedPalette();       currentBlending = NOBLEND; }
        if( secondHand == 35)  { SetupBlackAndWhiteStripedPalette();       currentBlending = LINEARBLEND; }
        if( secondHand == 40)  { currentPalette = CloudColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 45)  { currentPalette = PartyColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 50)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND;  }
        if( secondHand == 55)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
    }
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
    for( int i = 0; i < 16; i++) {
        currentPalette[i] = CHSV( random8(), 255, random8());
    }
}

void SetupBlackAndWhiteStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::White;
    currentPalette[4] = CRGB::White;
    currentPalette[8] = CRGB::White;
    currentPalette[12] = CRGB::White;
    
}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
    CRGB purple = CHSV( HUE_PURPLE, 255, 255);
    CRGB green  = CHSV( HUE_GREEN, 255, 255);
    CRGB black  = CRGB::Black;
    
    currentPalette = CRGBPalette16(
                                   green,  green,  black,  black,
                                   purple, purple, black,  black,
                                   green,  green,  black,  black,
                                   purple, purple, black,  black );
}

const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
    CRGB::Red,
    CRGB::Gray, // 'white' is too bright compared to red and blue
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Red,
    CRGB::Gray,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Blue,
    CRGB::Black,
    CRGB::Black
};

If I was going to use an interrupt I would do the following:

  1. Since level values are only 1 to 10 define the level array as a volatile array of bytes.
  2. Set up a timer interrupt to trigger every 100us.
  3. Every timer interrupt perform the following:
    if (strobe pin is HIGH)
    toggle strobe pin to LOW
    else
    read the analog and set the current level array element to the mapped value
    increment the level array index
    toggle strobe pin to HIGH

Now you can perform any functionality in your loop() function and you will always have the current levels available.

ToddL1962:
If I was going to use an interrupt I would do the following:

  1. Since level values are only 1 to 10 define the level array as a volatile array of bytes.
  2. Set up a timer interrupt to trigger every 100us.
  3. Every timer interrupt perform the following:
    if (strobe pin is HIGH)
    toggle strobe pin to LOW
    else
    read the analog and set the current level array element to the mapped value
    increment the level array index
    toggle strobe pin to HIGH

Now you can perform any functionality in your loop() function and you will always have the current levels available.

Thanks so much!! Massive help :slight_smile: