#include #include #include "driver/gpio.h" #include "driver/i2s_std.h" #include "esp_err.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "led_strip.h" #define I2S_BCLK_GPIO GPIO_NUM_3 #define I2S_WS_GPIO GPIO_NUM_4 #define I2S_DATA_GPIO GPIO_NUM_5 #define RGB_LED_GPIO GPIO_NUM_48 #define SAMPLE_RATE_HZ 16000 #define SAMPLES_PER_READ 256 #define GREEN_NOISE_RMS 100000.0f #define RED_NOISE_RMS 1000000.0f #define LED_BRIGHTNESS 64 static const char *TAG = "buzz_detector"; static led_strip_handle_t init_rgb_led(void) { const led_strip_config_t strip_config = { .strip_gpio_num = RGB_LED_GPIO, .max_leds = 1, .led_model = LED_MODEL_WS2812, .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, .flags = { .invert_out = false, }, }; const led_strip_rmt_config_t rmt_config = { .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10 * 1000 * 1000, .mem_block_symbols = 64, .flags = { .with_dma = false, }, }; led_strip_handle_t strip = NULL; ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &strip)); ESP_ERROR_CHECK(led_strip_clear(strip)); return strip; } static void update_rgb_led(led_strip_handle_t strip, float rms) { float red = 0.0f; float green = 0.0f; if (rms < GREEN_NOISE_RMS) { green = LED_BRIGHTNESS * rms / GREEN_NOISE_RMS; } else { float red_fraction = (rms - GREEN_NOISE_RMS) / (RED_NOISE_RMS - GREEN_NOISE_RMS); if (red_fraction > 1.0f) { red_fraction = 1.0f; } red = LED_BRIGHTNESS * red_fraction; green = LED_BRIGHTNESS * (1.0f - red_fraction); } ESP_ERROR_CHECK(led_strip_set_pixel(strip, 0, (uint8_t)red, (uint8_t)green, 0)); ESP_ERROR_CHECK(led_strip_refresh(strip)); } static i2s_chan_handle_t init_microphone(void) { i2s_chan_handle_t rx_channel = NULL; const i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(&channel_config, NULL, &rx_channel)); i2s_std_config_t standard_config = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE_HZ), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG( I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = I2S_BCLK_GPIO, .ws = I2S_WS_GPIO, .dout = I2S_GPIO_UNUSED, .din = I2S_DATA_GPIO, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, }; standard_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT; ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_channel, &standard_config)); ESP_ERROR_CHECK(i2s_channel_enable(rx_channel)); return rx_channel; } void app_main(void) { led_strip_handle_t rgb_led = init_rgb_led(); i2s_chan_handle_t microphone = init_microphone(); int32_t samples[SAMPLES_PER_READ]; float smoothed_rms = 0.0f; uint32_t log_counter = 0; ESP_LOGI(TAG, "INMP441 ready on BCLK=%d, WS=%d, SD=%d; RGB LED on GPIO %d", I2S_BCLK_GPIO, I2S_WS_GPIO, I2S_DATA_GPIO, RGB_LED_GPIO); while (true) { size_t bytes_read = 0; ESP_ERROR_CHECK(i2s_channel_read(microphone, samples, sizeof(samples), &bytes_read, portMAX_DELAY)); const size_t sample_count = bytes_read / sizeof(samples[0]); if (sample_count == 0) { continue; } int64_t sum_squares = 0; for (size_t i = 0; i < sample_count; ++i) { // INMP441 provides 24-bit signed samples in the upper bits of each 32-bit slot. const int32_t sample = samples[i] >> 8; sum_squares += (int64_t)sample * sample; } const float rms = sqrtf((float)sum_squares / sample_count); smoothed_rms += 0.2f * (rms - smoothed_rms); update_rgb_led(rgb_led, smoothed_rms); if (++log_counter == 16) { ESP_LOGI(TAG, "sound RMS: %.0f", smoothed_rms); log_counter = 0; } } }