Загрузка данных
static volatile bool is_switching_audio = false;
static void update_device_pointers(uint8_t change_audio)
{
if(change_audio)
{
if(current_audio_path == AUDIO_PATH_0)
{
current_audio_path = AUDIO_PATH_1;
printf("Switching audio to SAI1 (PATH1) on the fly...\n");
}
else
{
current_audio_path = AUDIO_PATH_0;
printf("Switching audio to SAI3 (PATH0) on the fly...\n");
}
}
if (current_audio_path == AUDIO_PATH_1) {
i2s_dev_rx = DEVICE_DT_GET(DT_NODELABEL(i2s1_rx));
i2s_dev_tx = DEVICE_DT_GET(DT_NODELABEL(i2s1_tx));
codec_dev = DEVICE_DT_GET(DT_NODELABEL(rx_audio_codec));
rx_tx_is_slave = 0;
codec_is_slave = 1;
} else {
i2s_dev_rx = DEVICE_DT_GET(DT_NODELABEL(i2s0_rx));
i2s_dev_tx = DEVICE_DT_GET(DT_NODELABEL(i2s0_tx));
codec_dev = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
rx_tx_is_slave = 0;
codec_is_slave = 1;
}
} while (1)
{
if(!start_stream || is_switching_audio) { // <-- Добавлена проверка флага
k_sleep(K_MSEC(5));
}
else
{
ret = i2s_buf_read(i2s_dev_rx, buf, &block_size);
// ... (остальной код функции без изменений) ... while (1)
{
if(!start_stream || is_switching_audio) { // <-- Добавлена проверка флага
k_sleep(K_MSEC(5));
}
else
{
ret = i2s_buf_write(i2s_dev_tx, buf, i2s_stream->block_size);
// ... (остальной код функции без изменений) ...
void zephyr_change_audio_runtime(void)
{
// Если стрим закрыт, делаем обычную холодную смену указателей
if (close_stream == 1) {
update_device_pointers(1);
return;
}
printf("--- RUNTIME AUDIO SWITCH START ---\n");
// 1. Ставим потоки чтения/записи на паузу
is_switching_audio = true;
k_sleep(K_MSEC(15)); // Даем время потокам завершить текущие операции I2S
// 2. Останавливаем старые аппаратные интерфейсы Zephyr I2S
// Отправляем команду DROP, чтобы сбросить очереди DMA старого устройства
trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_DROP);
// 3. Меняем указатели устройств на противоположный аудио-путь
update_device_pointers(1);
// 4. Проверяем готовность новых девайсов
if (!device_is_ready(i2s_dev_rx) || !device_is_ready(i2s_dev_tx) || !device_is_ready(codec_dev)) {
printf("Runtime Switch Error: New devices are not ready!\n");
is_switching_audio = false; // Возвращаем потоки, чтобы система не зависла окончательно
return;
}
// 5. Конфигурируем новый кодек
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 = codec_is_slave ? (I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE) : I2S_OPT_FRAME_CLK_MASTER;
audio_cfg.dai_cfg.i2s.frame_clk_freq = current_sample_rate;
audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab_tx;
audio_cfg.dai_cfg.i2s.block_size = current_audio_block_size;
audio_cfg.mclk_freq = AUDIO_MCLK_FREQ;
audio_codec_configure(codec_dev, &audio_cfg);
// 6. Конфигурируем новые I2S каналы Zephyr
struct i2s_config config;
config.word_size = SAMPLE_BIT_WIDTH;
config.channels = NUMBER_OF_CHANNELS;
config.format = I2S_FMT_DATA_FORMAT_I2S;
config.options = rx_tx_is_slave ? (I2S_OPT_BIT_CLK_SLAVE | I2S_OPT_FRAME_CLK_SLAVE) : (I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER);
config.frame_clk_freq = current_sample_rate;
config.block_size = current_audio_block_size;
config.timeout = TIMEOUT;
if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &config)) {
printf("Runtime Switch Error: Failed to configure new I2S streams\n");
is_switching_audio = false;
return;
}
// Настраиваем громкость и включаем выход нового кодека
audio_property_value_t vol_val = { .vol = 100 };
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
vol_val.vol = 0;
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
audio_property_value_t mute_val = { .mute = false };
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
audio_codec_start_output(codec_dev);
// 7. Готовим буферы отправки (TX blocks) для нового I2S
prepare_transfer(i2s_dev_tx);
// 8. Физически запускаем новые I2S шины контроллера
trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_START);
// 9. Снимаем потоки чтения/записи с паузы
is_switching_audio = false;
printf("--- RUNTIME AUDIO SWITCH SUCCESSFUL ---\n");
}