Загрузка данных
#include <stdio.h>
#include <string.h>
#include <portaudio.h>
#include <audio_dev.h>
#include <pthread.h>
#include <zephyr_i2s_dev.h>
#include <zephyr_audio_dev.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/audio/codec.h>
#if DT_NODE_EXISTS(DT_NODELABEL(i2s_rxtx))
#define I2S_RX_NODE DT_NODELABEL(i2s_rxtx)
#define I2S_TX_NODE I2S_RX_NODE
#else
#define I2S_RX_NODE DT_NODELABEL(i2s0_rx)
#define I2S_TX_NODE DT_NODELABEL(i2s0_tx)
#endif
#define AUDIO_MCLK_FREQ 12288000
#define TIMEOUT 1000
#define I2S_THREAD_PRIORITY 8
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);
typedef enum {
AUDIO_PATH_0 = 0, // SAI3 (i2s0) + SGTL5000
AUDIO_PATH_1 = 1 // SAI1(i2s1) + SGTL5000
} audio_path_t;
static volatile uint8_t current_audio_path = AUDIO_PATH_0;
static const struct device *i2s_dev_rx = NULL;
static const struct device *i2s_dev_tx = NULL;
static const struct device *codec_dev = NULL;
static uint8_t start_stream = 0;
static uint8_t close_stream = 1;
static uint8_t rx_tx_is_slave = 0;
static uint8_t codec_is_slave = 0;
static uint32_t current_sample_rate = MAX_SAMPLE_FREQUENCY;
static uint32_t current_audio_block_size = ((MAX_SAMPLE_FREQUENCY / ZEPHYR_AUDIO_DIV_SIZE) * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE);
enum zephyr_i2s_state {
I2S_STREAM_RUNNING,
I2S_STREAM_CLOSED
};
struct i2s_strm {
uint8_t alloc;
uint8_t devid;
uint8_t *i2s_buf;
pthread_t i2s_thread;
pthread_attr_t threadAttr;
enum zephyr_i2s_state state;
uint32_t block_size;
};
#define MODOPS_I2S_STREAM_COUNT 2
static struct i2s_strm i2s_strm_pool[MODOPS_I2S_STREAM_COUNT] = {0};
static void update_device_pointers(uint8_t change_audio)
{
if(close_stream == 1)
{
if(change_audio)
{
if(current_audio_path == AUDIO_PATH_0)
{
current_audio_path = AUDIO_PATH_1;
printf("Change audio device to SAI1(PATH1)\n");
}
else
{
current_audio_path = AUDIO_PATH_0;
printf("Change audio device to SAI3(PATH0)\n");
}
}
if (current_audio_path == AUDIO_PATH_1) {
printf("USE AUDIO_PATH_1(SAI1)\n");
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 {
printf("USE AUDIO_PATH_0(SAI3)\n");
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;
}
}
else
{
printf("Need stop AUDIO to change devices!!!\n");
}
}
void zephyr_change_audio(void)
{
update_device_pointers(1);
}
static struct i2s_strm *i2s_str_alloc()
{
struct i2s_strm *i2s_strm_ = NULL;
for(uint8_t i=0; i < MODOPS_I2S_STREAM_COUNT; i++)
{
if(i2s_strm_pool[i].alloc == 0)
{
i2s_strm_ = &i2s_strm_pool[i];
i2s_strm_pool[i].alloc = 1;
break;
}
}
return i2s_strm_;
}
static void i2s_str_free(struct i2s_strm *i2s_strm_)
{
if(!i2s_strm_) return;
for(uint8_t i=0; i < MODOPS_I2S_STREAM_COUNT; i++)
{
if(i2s_strm_pool[i].devid == i2s_strm_->devid)
{
i2s_strm_pool[i].alloc = 0;
break;
}
}
}
static void i2s_thread_wakeup(struct i2s_strm *strm, enum zephyr_i2s_state state)
{
if(!strm) return;
strm->state = state;
}
static void *i2s_thread_in(void *arg)
{
struct i2s_strm *i2s_stream = (struct i2s_strm *) arg;
uint32_t block_size;
uint8_t *buf = NULL;
uint8_t half_transfer = 1;
int ret;
buf = i2s_stream->i2s_buf;
while (1)
{
if(!start_stream) {
k_sleep(K_MSEC(10));
}
else
{
ret = i2s_buf_read(i2s_dev_rx, buf, &block_size);
if (ret < 0) {
printf("I2S_IN: Failed to read data: %d\n", ret);
}
else
{
if(half_transfer)
{
BSP_AUDIO_IN_HalfTransfer_CallBack();
buf += i2s_stream->block_size;
half_transfer = 0;
}
else
{
BSP_AUDIO_IN_TransferComplete_CallBack();
buf = i2s_stream->i2s_buf;
half_transfer = 1;
}
}
}
if (i2s_stream->state != I2S_STREAM_RUNNING) {
printf("Exit i2s_in_thread\n");
break;
}
}
return NULL;
}
static void *i2s_thread_out(void *arg)
{
struct i2s_strm *i2s_stream = (struct i2s_strm *) arg;
uint8_t *buf = NULL;
uint8_t half_transfer = 1;
int ret;
buf = i2s_stream->i2s_buf;
while (1)
{
if(!start_stream) {
k_sleep(K_MSEC(10));
}
else
{
ret = i2s_buf_write(i2s_dev_tx, buf, i2s_stream->block_size);
if (ret < 0) {
printf("I2S_OUT: Failed to write data: %d\n", ret);
}
else
{
if(half_transfer)
{
BSP_AUDIO_OUT_HalfTransfer_CallBack();
buf += i2s_stream->block_size;
half_transfer = 0;
}
else
{
BSP_AUDIO_OUT_TransferComplete_CallBack();
buf = i2s_stream->i2s_buf;
half_transfer = 1;
}
}
}
if (i2s_stream->state != I2S_STREAM_RUNNING) {
printf("Exit i2s_out_thread\n");
break;
}
}
return NULL;
}
static bool configure_streams(const struct device *i2s_dev_rx,
const struct device *i2s_dev_tx,
const struct i2s_config *base_config)
{
int ret;
struct i2s_config config = *base_config;
config.mem_slab = &mem_slab_rx;
ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, &config);
if (ret < 0) {
printf("Failed to configure RX: %d\n", ret);
return false;
}
config.mem_slab = &mem_slab_tx;
ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, &config);
if (ret < 0) {
printf("Failed to configure TX: %d\n", ret);
return false;
}
return true;
}