Here is how I synced a LED strip to music using a MSGEq7 and a Adafruit Electret Microphone Amplifier - MAX9814 with Auto Gain Control [ADA1713]. Using a ESP32.
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <Adafruit_NeoPixel.h>
#include "AudioAnalyzer.h"
////
/* define event group and event bits */
EventGroupHandle_t eg;
#define evtDo_AudioReadFreq ( 1 << 0 ) // 1
////
QueueHandle_t xQ_LED_Info;
QueueHandle_t xQ_LstripOn;
QueueHandle_t xQ_LstripMode;
////
const int LED_COUNT = 108; //total number of leds in the strip
////
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel leds = Adafruit_NeoPixel( LED_COUNT, 26, NEO_GRB + NEO_KHZ800 );
//
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
////
void ULP_BLINK_RUN(uint32_t us);
////
void setup()
{
ULP_BLINK_RUN(100000);
eg = xEventGroupCreate();
////
int FreqVal[7]; // used to set queue size
xQ_LED_Info = xQueueCreate ( 1, sizeof(FreqVal) );
xQ_LstripOn = xQueueCreate( 1, sizeof(bool) ); // sends a queue copy of the structure
xQ_LstripMode = xQueueCreate( 1, sizeof(int) );
////
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive( sema_MQTT_KeepAlive );
////
// setting must be set before a mqtt connection is made
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds
connectToWiFi();
connectToMQTT();
//////////////////////////////////////////////////////////////////////////////////////////////
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 7000, NULL, 5, NULL, 1 );
xTaskCreatePinnedToCore( fDo_AudioReadFreq, "fDo_ AudioReadFreq", 30000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fDo_LEDs, "fDo_ LEDs", 30000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fDoLstripMode, "fDoLstripMode", 2000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fDoLstripOn, "fDoLstripOn", 2000, NULL, 3, NULL, 1 );
xEventGroupSetBits( eg, evtDo_AudioReadFreq );
} // setup()
////
void fDoLstripMode( void *pvParameters )
{
int iMode = 0;
for (;;)
{
if (xQueueReceive( xQ_LstripMode, &iMode, portMAX_DELAY) == pdTRUE)
{
log_i( "Mode queue received %d", iMode );
}
//log_i( "memory fDoLstripMode %d", uxTaskGetStackHighWaterMark(NULL) );
}
vTaskDelete ( NULL );
}
////
void fDoLstripOn( void *pvParameters )
{
bool bOn = false;
for (;;)
{
if (xQueueReceive( xQ_LstripOn, &bOn, portMAX_DELAY) == pdTRUE)
{
log_i( "On queue received %d", bOn );
}
//log_i( "memory fDoLstripOn %d", uxTaskGetStackHighWaterMark(NULL) );
}
vTaskDelete ( NULL );
}
////
void loop() {} // void loop
////
void fMQTT_Disconnect( )
{
MQTTclient.disconnect();
}
////
void GetTheTime()
{
char* ntpServer = "2.us.pool.ntp.org";
int gmtOffset_sec = -(3600 * 7 );
int daylightOffset_sec = 3600;
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
}
////
// http://www.cplusplus.com/reference/ctime/strftime/
////
void MQTTkeepalive( void *pvParameters )
{
for (;;)
{
//log_i( " mqtt keep alive run." );
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); //
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
if ( !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
vTaskDelay( 200 );
}
vTaskDelete ( NULL );
}
////
int getHour()
{
struct tm timeinfo;
getLocalTime(&timeinfo);
char _time[ 5 ];
strftime( _time, 80, "%T", &timeinfo );
return String(_time).toInt();
}
////
void printLocalTime() {
struct tm timeinfo;
getLocalTime(&timeinfo);
char _time[ 80 ];
strftime( _time, 80, "%T", &timeinfo );
log_i( "%s", _time);
// }
}
////
void connectToMQTT()
{
log_i( "connect to mqtt" );
while ( !MQTTclient.connected() )
{
MQTTclient.connect( clientID, mqtt_username, mqtt_password );
log_i( "connecting to MQTT" );
vTaskDelay( 250 );
}
log_i("MQTT Connected");
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( mqtt_topic );
}
////
void connectToWiFi()
{
log_i( " Begin Connect to wifi" );
while ( WiFi.status() != WL_CONNECTED )
{
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
log_i(" waiting on wifi connection" );
vTaskDelay( 4000 );
}
log_i( "End connected to WiFi" );
WiFi.onEvent( WiFiEvent );
GetTheTime();
}
////
static void mqttCallback(char* topic, byte * payload, unsigned int length)
{
int i = 0;
String temp = "";
for ( i; i < length; i++) {
temp += ((char)payload[i]);
}
//log_i( " topic %s payload %s", topic, temp );
if ( (String)topic == topicLstripOn )
{
if ( temp == "0" )
{
bool bOn = false;
xQueueOverwrite( xQ_LstripOn, (void *)&bOn );
} else {
bool bOn = true;
xQueueOverwrite( xQ_LstripOn, (void *)&bOn );
}
}
if ( (String)topic == topicLstripMode )
{
int i = temp.toInt();
xQueueOverwrite( xQ_LstripMode, (void *)&i );
}
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
void fDo_LEDs( void *pvParameters )
{
const int Brightness = 200;
const int SEG = 6; // how many parts you want to separate the led strip into
const int ledCount = LED_COUNT; //total number of leds in the strip
int iFreqVal[7];
int j;
leds.begin(); // Call this to start up the LED strip.
clearLEDs( ledCount ); // This function, defined below, de-energizes all LEDs...
leds.show(); // ...but the LEDs don't actually update until you call this.
leds.setBrightness( Brightness ); // 1 = min brightness (off), 255 = max brightness.
for (;;)
{
if (xQueueReceive( xQ_LED_Info, &iFreqVal, portMAX_DELAY) == pdTRUE)
{
j = 0;
//assign different values for different parts of the led strip
for (j = 0; j < ledCount; j++)
{
if ( (0 <= j) && (j < (ledCount / SEG)) )
{
//log_i( "segment 0 %d", iFreqVal[0] );
set( j, iFreqVal[0], ledCount, SEG ); // set the color of led
}
else if ( ((ledCount / SEG) <= j) && (j < (ledCount / SEG * 2)) )
{
set( j, iFreqVal[0], ledCount, SEG );
}
else if ( ((ledCount / SEG * 2) <= j) && (j < (ledCount / SEG * 3)) )
{
set( j, iFreqVal[0], ledCount, SEG );
}
else if ( ((ledCount / SEG * 3) <= j) && (j < (ledCount / SEG * 4)) )
{
set( j, iFreqVal[0], ledCount, SEG );
}
else if ( ((ledCount / SEG * 4) <= j) && (j < (ledCount / SEG * 5)) )
{
set( j, iFreqVal[0], ledCount, SEG );
}
else
{
set( j, iFreqVal[0], ledCount, SEG );
}
}
leds.show();
}
xEventGroupSetBits( eg, evtDo_AudioReadFreq );
}
vTaskDelete( NULL );
} // void fDo_ LEDs( void *pvParameters )
////
void fDo_AudioReadFreq( void *pvParameters )
{
int FreqVal[7];
const int NOISE = 10; // noise that you want to chop off
const int A_D_ConversionBits = 4096; // arduino use 1024, ESP32 use 4096
Analyzer Audio = Analyzer( 5, 15, 36 );//Strobe pin ->15 RST pin ->2 Analog Pin ->36
Audio.Init(); // start the audio analyzer
int64_t EndTime = esp_timer_get_time();
int64_t StartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
for (;;)
{
xEventGroupWaitBits (eg, evtDo_AudioReadFreq, pdTRUE, pdTRUE, portMAX_DELAY);
//EndTime = esp_timer_get_time() - StartTime;
// log_i( "TimeSpentOnTasks: %d", EndTime );
Audio.ReadFreq(FreqVal);
for (int i = 0; i < 7; i++)
{
FreqVal[i] = constrain( FreqVal[i], NOISE, A_D_ConversionBits );
FreqVal[i] = map( FreqVal[i], NOISE, A_D_ConversionBits, 0, 255 );
// log_i( "Freq %d Value: %d", i, FreqVal[i]);//used for debugging and Freq choosing
}
xQueueSend( xQ_LED_Info, ( void * ) &FreqVal, 0 );
//StartTime = esp_timer_get_time();
}
vTaskDelete( NULL );
} // fDo_ AudioReadFreq( void *pvParameters )
////
//the following function set the led color based on its position and freq value
//
void set(byte position, int value, int ledCount, int segment)
{
int valueLowLimit = 20;
// segment 0, red
if ( (0 <= position) && (position < ledCount / segment) ) // segment 0 (bottom to top)
{
if ( value <= valueLowLimit )
{
leds.setPixelColor( position, 0, 0, 0 );
}
else
{
leds.setPixelColor( position, leds.Color( value , 0, 0) );
}
}
else if ( (ledCount / segment <= position) && (position < ledCount / segment * 2) ) // segment 1 yellow
{
if ( value <= valueLowLimit )
{
leds.setPixelColor(position, leds.Color(0, 0, 0));
}
else
{
leds.setPixelColor(position, leds.Color( value, value, 0)); // works better to make yellow
}
}
else if ( (ledCount / segment * 2 <= position) && (position < ledCount / segment * 3) ) // segment 2 pink
{
if ( value <= valueLowLimit )
{
leds.setPixelColor(position, leds.Color(0, 0, 0));
}
else
{
leds.setPixelColor(position, leds.Color( value, 0, value * .91) ); // pink
}
}
else if ( (ledCount / segment * 3 <= position) && (position < ledCount / segment * 4) ) // seg 3, green
{
if ( value <= valueLowLimit )
{
leds.setPixelColor(position, leds.Color( 0, 0, 0));
}
else //
{
leds.setPixelColor( position, leds.Color( 0, value, 0) ); //
}
}
else if ( (ledCount / segment * 4 <= position) && (position < ledCount / segment * 5) ) // segment 4, leds.color( R, G, B ), blue
{
if ( value <= valueLowLimit )
{
leds.setPixelColor(position, leds.Color( 0, 0, 0));
}
else //
{
leds.setPixelColor(position, leds.Color( 0, 0, value) ); // blue
}
}
else // segment 5
{
if ( value <= valueLowLimit )
{
leds.setPixelColor(position, leds.Color( 0, 0, 0));
}
else
{
leds.setPixelColor( position, leds.Color( value, value * .3, 0) ); // orange
}
}
} // void set(byte position, int value)
////
void clearLEDs( int ledCount)
{
for (int i = 0; i < ledCount; i++)
{
leds.setPixelColor(i, 0);
}
} // void clearLEDs()
////
void WiFiEvent(WiFiEvent_t event)
{
// log_i( "[WiFi-event] event: %d\n", event );
switch (event) {
// case SYSTEM_EVENT_WIFI_READY:
// log_i("WiFi interface ready");
// break;
// case SYSTEM_EVENT_SCAN_DONE:
// log_i("Completed scan for access points");
// break;
// case SYSTEM_EVENT_STA_START:
// log_i("WiFi client started");
// break;
// case SYSTEM_EVENT_STA_STOP:
// log_i("WiFi clients stopped");
// break;
case SYSTEM_EVENT_STA_CONNECTED:
log_i("Connected to access point");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
// case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
// log_i("Authentication mode of access point has changed");
// break;
// case SYSTEM_EVENT_STA_GOT_IP:
// log_i ("Obtained IP address: %s", WiFi.localIP() );
// break;
// case SYSTEM_EVENT_STA_LOST_IP:
// log_i("Lost IP address and IP address is reset to 0");
// // vTaskDelay( 5000 );
// // ESP.restart();
// break;
// case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
// log_i("WiFi Protected Setup (WPS): succeeded in enrollee mode");
// break;
// case SYSTEM_EVENT_STA_WPS_ER_FAILED:
// log_i("WiFi Protected Setup (WPS): failed in enrollee mode");
// // ESP.restart();
// break;
// case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
// log_i("WiFi Protected Setup (WPS): timeout in enrollee mode");
// break;
// case SYSTEM_EVENT_STA_WPS_ER_PIN:
// log_i("WiFi Protected Setup (WPS): pin code in enrollee mode");
// break;
// case SYSTEM_EVENT_AP_START:
// log_i("WiFi access point started");
// break;
// case SYSTEM_EVENT_AP_STOP:
// log_i("WiFi access point stopped");
// // WiFi.mode(WIFI_OFF);
// // esp_sleep_enable_timer_wakeup( 1000000 * 2 ); // 1 second times how many seconds wanted
// // esp_deep_sleep_start();
// break;
// case SYSTEM_EVENT_AP_STACONNECTED:
// log_i("Client connected");
// break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
// break;
// case SYSTEM_EVENT_AP_STAIPASSIGNED:
// log_i("Assigned IP address to client");
// break;
// case SYSTEM_EVENT_AP_PROBEREQRECVED:
// log_i("Received probe request");
// break;
// case SYSTEM_EVENT_GOT_IP6:
// log_i("IPv6 is preferred");
// break;
// case SYSTEM_EVENT_ETH_GOT_IP:
// log_i("Obtained IP address");
// break;
default: break;
}
}
//////////////////////////////////////////////
/*
Each I_XXX preprocessor define translates into a single 32-bit instruction. So you can count instructions to learn which memory address are used and where the free mem space starts.
To generate branch instructions, special M_ preprocessor defines are used. M_LABEL define can be used to define a branch target.
Implementation note: these M_ preprocessor defines will be translated into two ulp_insn_t values: one is a token value which contains label number, and the other is the actual instruction.
*/
void ULP_BLINK_RUN(uint32_t us)
{
size_t load_addr = 0;
RTC_SLOW_MEM[12] = 0;
ulp_set_wakeup_period(0, us);
const ulp_insn_t ulp_blink[] =
{
I_MOVI(R3, 12), // #12 -> R3
I_LD(R0, R3, 0), // R0 = RTC_SLOW_MEM[R3(#12)]
M_BL(1, 1), // GOTO M_LABEL(1) IF R0 < 1
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1), // RTC_GPIO2 = 1
I_SUBI(R0, R0, 1), // R0 = R0 - 1, R0 = 1, R0 = 0
I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(#12)] = R0
M_BX(2), // GOTO M_LABEL(2)
M_LABEL(1), // M_LABEL(1)
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
I_ADDI(R0, R0, 1), // R0 = R0 + 1, R0 = 0, R0 = 1
I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(#12)] = R0
M_LABEL(2), // M_LABEL(2)
I_HALT() // HALT COPROCESSOR
};
const gpio_num_t led_gpios[] =
{
GPIO_NUM_2,
// GPIO_NUM_0,
// GPIO_NUM_4
};
for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
rtc_gpio_init(led_gpios[i]);
rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_level(led_gpios[i], 0);
}
size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
ulp_process_macros_and_load( load_addr, ulp_blink, &size);
ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)
//////////////////////////////////////////////
Works real well. Perhaps the code will be useful or not.