printk("start streams\n");
// Шаг 1: Первичное заполнение пула драйвера (накачка очереди TX)
// Выделяем 3-4 блока из slab, заполняем синусоидой и пихаем в i2s_write
for (int i = 0; i < 4; i++) {
void *tx_block;
// Явно берем свободный блок из slab-пула
ret = k_mem_slab_alloc(&mem_slab, &tx_block, K_NO_WAIT);
if (ret < 0) {
printk("Failed to allocate slab block for warm-up\n");
break;
}
// Копируем синусоиду в выделенный блок (следим, чтобы размер не превышал BLOCK_SIZE)
uint32_t bytes_to_copy = (__16kHz16bit_stereo_sine_pcm_len > BLOCK_SIZE) ?
BLOCK_SIZE : __16kHz16bit_stereo_sine_pcm_len;
memcpy(tx_block, &__16kHz16bit_stereo_sine_pcm, bytes_to_copy);
// Отправляем блок в очередь I2S напрямую (БЕЗ i2s_buf_write)
ret = i2s_write(i2s_dev_codec, tx_block, K_NO_WAIT);
if (ret < 0) {
printk("Warm-up i2s_write failed: %d\n", ret);
k_mem_slab_free(&mem_slab, tx_block);
break;
}
}
// Шаг 2: Только ТЕПЕРЬ, когда очередь заполнена, запускаем аппаратную передачу
ret = i2s_trigger(i2s_dev_codec, I2S_DIR_TX, I2S_TRIGGER_START);
if (ret < 0) {
printk("Failed to START I2S TX: %d\n", ret);
return ret;
}
// Шаг 3: Бесконечный цикл непрерывного воспроизведения
while (1) {
void *tx_block;
// Пытаемся взять блок. Так как I2S запущен, по мере воспроизведения
// старые блоки будут автоматически освобождаться драйвером eDMA,
// и эта функция будет успешно проскакивать.
ret = k_mem_slab_alloc(&mem_slab, &tx_block, K_MSEC(100));
if (ret < 0) {
printk("Slab allocation timeout! eDMA TX is STUCK (error -11 prevent)\n");
// Если мы упали сюда — значит eDMA физически стоит и не освобождает блоки
break;
}
// Снова копируем синусоиду в освободившийся блок
uint32_t bytes_to_copy = (__16kHz16bit_stereo_sine_pcm_len > BLOCK_SIZE) ?
BLOCK_SIZE : __16kHz16bit_stereo_sine_pcm_len;
memcpy(tx_block, &__16kHz16bit_stereo_sine_pcm, bytes_to_copy);
// Передаем блок на воспроизведение
ret = i2s_write(i2s_dev_codec, tx_block, K_MSEC(100));
if (ret < 0) {
printk("Continuous i2s_write failed: %d\n", ret);
k_mem_slab_free(&mem_slab, tx_block);
break;
}
}