#define SAMPLE_FREQUENCY 16000
#define NUMBER_OF_CHANNELS 1
#define SAMPLE_BIT_WIDTH 16
#define BYTES_PER_SAMPLE 2
/* 20 ms - оптимальный интервал для VoIP (16000 * 0.02 = 320 семплов) */
#define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 50) * NUMBER_OF_CHANNELS)
#define ZEPHYR_AUDIO_BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
/* 6 блоков по 20мс = 120мс буферизации на каждое направление */
#define ZEPHYR_AUDIO_BLOCK_COUNT 6
typedef void I2S_Stream;
/* Создаем раздельные пулы памяти для RX и TX в быстрой секции DTCM */
K_MEM_SLAB_DEFINE_IN_SECT_STATIC(mem_slab_rx, __dtcm_noinit_section,
ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
K_MEM_SLAB_DEFINE_IN_SECT_STATIC(mem_slab_tx, __dtcm_noinit_section,
ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
int zephyr_i2s_audio_init(void)
{
struct i2s_config config_rx;
struct i2s_config config_tx;
#if DT_NODE_HAS_STATUS(DT_NODELABEL(audio_codec), okay)
const struct device *const codec_dev = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
struct audio_codec_cfg audio_cfg;
audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK_CAPTURE;
audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
audio_cfg.dai_cfg.i2s.channels = NUMBER_OF_CHANNELS;
audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_MASTER;
audio_cfg.dai_cfg.i2s.frame_clk_freq = SAMPLE_FREQUENCY;
/* Кодеку отдаем любой, он использует его для общих параметров DAI */
audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab_tx;
audio_cfg.dai_cfg.i2s.block_size = ZEPHYR_AUDIO_BLOCK_SIZE;
audio_codec_configure(codec_dev, &audio_cfg);
k_msleep(100); // 1000мс многовато, 100мс обычно хватает для стабилизации
#else
printk("Error: No audio_codec in DTS!\n");
return -1;
#endif
if (!device_is_ready(i2s_dev_rx) || !device_is_ready(i2s_dev_tx)) {
printk("I2S devices not ready\n");
return -1;
}
/* Настройка RX (Capture) */
config_rx.word_size = SAMPLE_BIT_WIDTH;
config_rx.channels = NUMBER_OF_CHANNELS;
config_rx.format = I2S_FMT_DATA_FORMAT_I2S;
config_rx.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
config_rx.frame_clk_freq = SAMPLE_FREQUENCY;
config_rx.mem_slab = &mem_slab_rx; // Свой пул
config_rx.block_size = ZEPHYR_AUDIO_BLOCK_SIZE;
config_rx.timeout = TIMEOUT;
/* Настройка TX (Playback) */
config_tx = config_rx;
config_tx.mem_slab = &mem_slab_tx; // Свой пул
if (i2s_configure(i2s_dev_rx, I2S_DIR_RX, &config_rx) < 0) {
printk("Failed to configure RX stream\n");
return -1;
}
if (i2s_configure(i2s_dev_tx, I2S_DIR_TX, &config_tx) < 0) {
printk("Failed to configure TX stream\n");
return -1;
}
return 0;
}