ESP32は Dual Core なので1つのコアを信号処理に専念させて,他の処理を別のコアで処理すればパフォーマンスがよくなる.
setup(), loop() はCore1 で実行される.ここには信号処理のみ記述することにして,Core0で実行するTaskにその他の処理を入れていくことにする.
参考にさせていただいたサイト
mgo-tec電子工作
ESP32でマルチコアを試す
Core0で実行するTaskを追加したコードを下に示す.
// I2S on ESP32-S3 // T.Uebo October 7, 2022 // I2S Master MODE 48kHz/32bit // // Mclk GPIO 39 // Bclk GPIO 42 // LRclk GPIO 2 // Dout GPIO 41 // Din GPIO 1 #include <esp_dsp.h> #include <driver/i2s.h> #define fsample 48000 #define BLOCK_SAMPLES 64 #define MUTE 40 // MUTE control (LOW: Mute) //buffers int rxbuf[BLOCK_SAMPLES*2], txbuf[BLOCK_SAMPLES*2]; float Lch_in[BLOCK_SAMPLES], Rch_in[BLOCK_SAMPLES]; float Lch_out[BLOCK_SAMPLES], Rch_out[BLOCK_SAMPLES]; // for IIR Filter float zL0[2], zR0[2], coeffs0[5]; TaskHandle_t H_Task; //タスクハンドル /*-------------------------------------------------- core 0 で処理するTask Alt_Thread() ---------------------------------------------------*/ void Alt_Thread(void *args) { // // このTask の setup() に相当する処理 // float fc; static int tc; tc=0; while (1) { // // この Task の loop() に相当する処理 // fc = (float)tc/30000.0f; dsps_biquad_gen_lpf_f32(coeffs0, fc, 1.0f); tc++; if(tc>=3000) tc=0; delay(1); // 必須 } } /*----------------------------------------------------------------------------------------------- Setup -------------------------------------------------------------------------------------------------*/ void setup(void) { Serial.begin(115200); delay(50); xTaskCreatePinnedToCore(Alt_Thread, "Alt_Thread", 8192, NULL, 4, &H_Task, 0); // // xTaskCreatePinnedToCore( // [タスク名], "[タスク名]", [スタックメモリサイズ], // NULL, [タスク優先順位](0-24)], // [タスクハンドルのポインタ(&H_Task)], // [Core ID(0 or 1)] // ); //Mute Control pinMode(MUTE, OUTPUT); digitalWrite(MUTE, HIGH); //unmute pinMode(48, OUTPUT); // set IIR Filter Coeffs.(as LPF) dsps_biquad_gen_lpf_f32(coeffs0, 0.1f, 1.0f); // fc = 0.1*fsample[Hz], Q=1.0 // I2S setup (Lables are defined in i2s_types.h, esp_intr_alloc.h)---------------------------------------- i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX), .sample_rate = fsample, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LOWMED, .dma_buf_count = 6, .dma_buf_len = BLOCK_SAMPLES*4, .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = 0, .mclk_multiple = I2S_MCLK_MULTIPLE_256, }; i2s_driver_install( I2S_NUM_0, &i2s_config, 0, NULL); i2s_pin_config_t pin_config = { .mck_io_num = 39, .bck_io_num = 42, .ws_io_num = 2, .data_out_num = 41, .data_in_num = 1 }; i2s_set_pin( I2S_NUM_0, &pin_config); } /*----------------------------------------------------------------------------------------------- Signal Process Loop -------------------------------------------------------------------------------------------------*/ void loop(void) { size_t readsize = 0; //Input from I2S codec esp_err_t rxfb = i2s_read(I2S_NUM_0, &rxbuf[0], BLOCK_SAMPLES*2*4, &readsize, portMAX_DELAY); if (rxfb == ESP_OK && readsize==BLOCK_SAMPLES*2*4) { digitalWrite(48, HIGH); int j=0; for (int i=0; i<BLOCK_SAMPLES; i++) { Lch_in[i] = (float) rxbuf[j]; Rch_in[i] = (float) rxbuf[j+1]; j+=2; } //-------Signal process ------------------------------- //IIR Filter dsps_biquad_f32(Lch_in, Lch_out, BLOCK_SAMPLES, coeffs0, zL0); dsps_biquad_f32(Rch_in, Rch_out, BLOCK_SAMPLES, coeffs0, zR0); //------------------------------------------------------ //Output to I2S codec j=0; for (int i=0; i<BLOCK_SAMPLES; i++) { txbuf[j] = (int) Lch_out[i]; txbuf[j+1] = (int) Rch_out[i]; j+=2; } i2s_write( I2S_NUM_0, &txbuf[0], BLOCK_SAMPLES*2*4, &readsize, portMAX_DELAY); } digitalWrite(48, LOW); }
追加分はハイライト表示している.まとめると,
1.setup() の前にタスクハンドルを定義 TaskHandle_t H_Task;
2.setup() の中にTask 宣言をする一文を入れる.xTaskCreatePinnedToCore
3.宣言したTaskの関数を記述 Alt_Thread()
Alt_Thread() では,一例として IIR LPF のカットオフ周波数をスイープする処理を記述した(動作確認済).