269 lines
7.6 KiB
C
269 lines
7.6 KiB
C
/* SPDX - FileCopyrightText : 2025 Asaril
|
|
** SPDX - License - Identifier : CC0 - 1.0
|
|
*/
|
|
|
|
#include "esp_system.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "sdkconfig.h"
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
|
|
#include "driver/i2s_std.h"
|
|
#include "driver/uart.h"
|
|
#include "esp_dsp.h"
|
|
|
|
static const char *TAG = "main";
|
|
|
|
/*
|
|
|
|
24000 hz sample rate
|
|
16bit per channel
|
|
2 channel i2s input, second zeros
|
|
|
|
complex format: buf[0]=re[0], buf[1]=im[0]
|
|
|
|
*/
|
|
|
|
#define I2S_MIC_SCLK_PIN GPIO_NUM_4
|
|
#define I2S_MIC_SD_PIN GPIO_NUM_5
|
|
#define I2S_MIC_WS_PIN GPIO_NUM_6
|
|
|
|
#define SAMPLE_RATE 24000
|
|
#define SAMPLE_COUNT 512
|
|
#define SAMPLE_CHANNELS 2
|
|
#define SAMPLE_TYPE int16_t
|
|
|
|
#define BUF_COUNT 4
|
|
|
|
#define BANDS_COUNT 3
|
|
|
|
// ----------------------------------------------------------------
|
|
/*
|
|
|
|
512:
|
|
bass: 1-4
|
|
mid: 5-42
|
|
treb: 43-255
|
|
|
|
*/
|
|
|
|
|
|
#define SAMPLE_BYTES (sizeof(SAMPLE_TYPE))
|
|
#define BUF_SIZE_SAMPLES (SAMPLE_COUNT * SAMPLE_CHANNELS)
|
|
#define BUF_SIZE_BYTES (BUF_SIZE_SAMPLES * SAMPLE_BYTES)
|
|
|
|
#define FALLOFF(OLD_V, NEW_V) ((OLD_V >> 1) + (OLD_V >> 2) + (NEW_V >> 2))
|
|
#define ABS(T, V) ((v < 0 ? (((T)0) - v) : v))
|
|
#define MAX(a, b) ((b > a) ? (b) : (a))
|
|
|
|
i2s_chan_handle_t rx_handle = NULL;
|
|
TaskHandle_t proc_task = NULL;
|
|
TaskHandle_t output_task = NULL;
|
|
|
|
SemaphoreHandle_t output_mutex;
|
|
|
|
__attribute__((aligned(16))) static SAMPLE_TYPE i2s_readraw_buff[BUF_SIZE_BYTES * BUF_COUNT];
|
|
|
|
uint32_t current_powers[BANDS_COUNT];
|
|
uint32_t avg_powers[BANDS_COUNT];
|
|
|
|
int16_t floating_max;
|
|
|
|
void app_init_mic(void)
|
|
{
|
|
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
|
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
|
|
|
i2s_std_config_t i2s_rx_cfg = {
|
|
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
|
/* The default mono slot is the left slot (whose 'select pin' of the PDM microphone is pulled down) */
|
|
.slot_cfg =
|
|
{
|
|
.data_bit_width = 8 * SAMPLE_BYTES,
|
|
.slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT,
|
|
.slot_mode = I2S_SLOT_MODE_MONO,
|
|
.slot_mask = I2S_STD_SLOT_BOTH,
|
|
.ws_width = 32,
|
|
.ws_pol = false,
|
|
.bit_shift = true,
|
|
.left_align = true,
|
|
.big_endian = false,
|
|
.bit_order_lsb = false,
|
|
},
|
|
.gpio_cfg =
|
|
{
|
|
.mclk = I2S_GPIO_UNUSED,
|
|
.bclk = I2S_MIC_SCLK_PIN,
|
|
.din = I2S_MIC_SD_PIN,
|
|
.ws = I2S_MIC_WS_PIN,
|
|
.invert_flags =
|
|
{
|
|
.bclk_inv = false,
|
|
.mclk_inv = false,
|
|
.ws_inv = false,
|
|
},
|
|
},
|
|
};
|
|
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &i2s_rx_cfg));
|
|
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
|
|
}
|
|
|
|
static void app_process_task(void *args)
|
|
{
|
|
uint32_t notify_value;
|
|
|
|
while (1)
|
|
{
|
|
xTaskNotifyWait(0, 0, ¬ify_value, portMAX_DELAY);
|
|
if (notify_value >= BUF_COUNT)
|
|
{
|
|
printf("process buf count wrong: %ld", notify_value);
|
|
continue;
|
|
}
|
|
|
|
SAMPLE_TYPE *buf = i2s_readraw_buff + notify_value * BUF_SIZE_SAMPLES;
|
|
// printf("%08lx - %08lx - %08lx\n", (uint32_t)i2s_readraw_buff, (uint32_t)buf,
|
|
// (uint32_t)(buf - i2s_readraw_buff));
|
|
|
|
int16_t max = 0;
|
|
for (int i = 0; i < SAMPLE_COUNT; i++)
|
|
{
|
|
max = MAX(max, buf[i * 2]);
|
|
}
|
|
|
|
floating_max = (max > floating_max) ? max : FALLOFF(floating_max, FALLOFF(floating_max,max));
|
|
|
|
// int16_t scale = 0x7fff / floating_max;
|
|
|
|
int16_t scale = 8;
|
|
|
|
// for (int16_t max_tmp = floating_max; scale < 15 && ((max_tmp & 0x8000) == 0); scale++, max_tmp <<= 1)
|
|
// ;
|
|
|
|
for (int i = 0; i < SAMPLE_COUNT; i++)
|
|
{
|
|
buf[i * 2] <<= scale-1;
|
|
}
|
|
|
|
// dsps_mulc_s16_ae32(buf,buf,SAMPLE_COUNT,scale,1,1);
|
|
|
|
// dsps_fft2r_sc16(buf, SAMPLE_COUNT);
|
|
// dsps_bit_rev_sc16_ansi(buf, SAMPLE_COUNT);
|
|
// dsps_cplx2real_sc16_ansi(buf, SAMPLE_COUNT);
|
|
|
|
xSemaphoreTake(output_mutex, portMAX_DELAY);
|
|
|
|
// current_powers[band] = 0;
|
|
// for (int band=START;band<END;band++){
|
|
// current_powers[band] = ;
|
|
// }
|
|
|
|
// for (int band = 0; band < BANDS_COUNT; band++)
|
|
// {
|
|
// current_powers[band] = 0;
|
|
// for (int freq = 0; freq < FREQS_PER_BAND; freq++)
|
|
// {
|
|
// // current_powers[band] += abs(buf[band * FREQS_PER_BAND + freq]);
|
|
// SAMPLE_TYPE v = buf[band * FREQS_PER_BAND + freq];
|
|
// if (v < 0)
|
|
// {
|
|
// current_powers[band] -= v;
|
|
// }
|
|
// else
|
|
// {
|
|
// current_powers[band] += v;
|
|
// }
|
|
// if(band==0 && freq<BANDS_COUNT){
|
|
// avg_powers[freq] = v; //current_powers[band];
|
|
// }
|
|
// }
|
|
|
|
// uint32_t old_band_avg_power = avg_powers[band];
|
|
|
|
// // avg_powers[band] = 0; // (old_band_avg_power >> 1) + (old_band_avg_power >> 2) + (current_powers[band]
|
|
// >> 2);
|
|
// }
|
|
|
|
xSemaphoreGive(output_mutex);
|
|
|
|
xTaskNotify(output_task, notify_value, eSetValueWithOverwrite);
|
|
|
|
// printf("[0] %08x [1] %08x [2] %08x [3]%08x ...\n", (buf[0]), (buf[1]), (buf[2]), (buf[3]));
|
|
}
|
|
}
|
|
|
|
static void app_output_task(void *args)
|
|
{
|
|
uint32_t notify_value;
|
|
|
|
const uint8_t sync_word[] = {0x00,0x11,0x80,0x00,0x7f,0xff,0x11,0x00};
|
|
|
|
while (1)
|
|
{
|
|
xTaskNotifyWait(0, 0, ¬ify_value, portMAX_DELAY);
|
|
if (notify_value >= BUF_COUNT)
|
|
{
|
|
printf("output buf count wrong: %ld", notify_value);
|
|
continue;
|
|
}
|
|
|
|
SAMPLE_TYPE *buf = i2s_readraw_buff + notify_value * BUF_SIZE_SAMPLES;
|
|
|
|
buf[SAMPLE_COUNT - 1] = floating_max;
|
|
|
|
uart_write_bytes(UART_NUM_0, sync_word, sizeof(sync_word));
|
|
|
|
uart_write_bytes(UART_NUM_0, buf, BUF_SIZE_BYTES);
|
|
|
|
// xSemaphoreTake(output_mutex, portMAX_DELAY);
|
|
// uart_write_bytes(UART_NUM_0, avg_powers, sizeof(avg_powers));
|
|
// uart_write_bytes(UART_NUM_0, current_powers, sizeof(current_powers));
|
|
// xSemaphoreGive(output_mutex);
|
|
}
|
|
}
|
|
|
|
void app_main(void)
|
|
{
|
|
size_t bytes_read = 0;
|
|
uint32_t next_rx = 0;
|
|
esp_err_t ret;
|
|
|
|
app_init_mic();
|
|
|
|
uart_config_t uart_cfg = {
|
|
.baud_rate = 1000000,
|
|
.data_bits = UART_DATA_8_BITS,
|
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
.parity = UART_PARITY_DISABLE,
|
|
.stop_bits = UART_STOP_BITS_1,
|
|
};
|
|
uart_param_config(UART_NUM_0, &uart_cfg);
|
|
uart_set_pin(UART_NUM_0, 17, 18, -1, -1);
|
|
|
|
uart_driver_install(UART_NUM_0, 256, 256, 0, NULL, 0);
|
|
|
|
ret = dsps_fft2r_init_sc16(NULL, SAMPLE_COUNT);
|
|
if (ret != ESP_OK)
|
|
{
|
|
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
|
|
return;
|
|
}
|
|
|
|
output_mutex = xSemaphoreCreateMutex();
|
|
|
|
xTaskCreate(&app_output_task, "app_output_task", 4096, NULL, 5, &output_task);
|
|
xTaskCreate(&app_process_task, "app_process_task", 4096, NULL, 5, &proc_task);
|
|
|
|
while (1)
|
|
{
|
|
if (i2s_channel_read(rx_handle, (char *)i2s_readraw_buff + (BUF_SIZE_BYTES * next_rx), BUF_SIZE_BYTES,
|
|
&bytes_read, 1000) == ESP_OK)
|
|
{
|
|
xTaskNotify(proc_task, next_rx, eSetValueWithOverwrite);
|
|
next_rx = (next_rx + 1) & (BUF_COUNT - 1);
|
|
// printf("main buf next %ld\n", next_rx);
|
|
taskYIELD();
|
|
}
|
|
}
|
|
}
|