• 正文
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

【RT1052】rt-thread 音频驱动增加接收功能

2025/03/03
556
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

本帖基于ok1052进一步完善音频驱动,增加音频接收部分。通过上一贴分析【飞凌RT1052】2、rt-thread 音频驱动分析,主要修改两个文件drv_codec.c和fsl_wm8960.c。

1、wm8960.c主要修改WM8960_Init函数,使能音频wm8960音频输入,代码省略了不需要修改的部分。

void WM8960_Init(wm8960_handle_t *handle, wm8960_config_t *config)
{
...
WM8960_WriteReg(handle, WM8960_POWER1, 0xFE);
...
WM8960_WriteReg(handle, WM8960_POWER3, 0x3C);
...
WM8960_WriteReg(handle, WM8960_LINPATH, 0x1B8);
WM8960_WriteReg(handle, WM8960_RINPATH, 0x138);
...
WM8960_WriteReg(handle, WM8960_INBMIX1, 0x00);
WM8960_WriteReg(handle, WM8960_INBMIX2, 0x00);
...
...
WM8960_WriteReg(handle, WM8960_ADDCTL1, 0x0C0);
...
WM8960_WriteReg(handle, WM8960_LINVOL, 0x117);
WM8960_WriteReg(handle, WM8960_RINVOL, 0x117);
}

2、drv_codec.c修改,这里主要由4部分。

a、增加音频接收需要的数据结构并增加主控音频外设初始化部分

struct imxcodec
{
...
uint8_t rx_started;
sai_edma_handle_t rxHandle;
uint8_t rxbuff[RX_BUFFER_SIZE];
...
edma_handle_t dmaRxHandle;
...
};

static rt_err_t icodec_init(struct rt_audio_device *audio)
{
...
EDMA_CreateHandle(&icodec->dmaRxHandle, EXAMPLE_DMA, EXAMPLE_RX_CHANNEL);
...
DMAMUX_SetSource(DMAMUX0, EXAMPLE_RX_CHANNEL, EXAMPLE_SAI_RX_SOURCE);
DMAMUX_EnableChannel(DMAMUX0, EXAMPLE_RX_CHANNEL);
...
SAI_TransferRxCreateHandleEDMA(icodec->sai, &icodec->rxHandle, saidma_callback, audio, &icodec->dmaRxHandle);
...
SAI_TransferRxSetFormatEDMA(icodec->sai, &icodec->rxHandle, format, mclkSourceClockHz, format->masterClockHz);
...
}

b、音频设备注册时增加读权限,以便上层应用可以读取音频数据

int rt_hw_codec_init(void)
{
...
result = rt_audio_register(audio,"sound0", RT_DEVICE_FLAG_RDWR, &_g_imxcodec);
...
}

c、完善音频接收部分,音频接收函数icodec_transmit和接收完成中断回调saidma_callback

static rt_size_t icodec_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
{
...
else
{
sai_transfer_t xfer;

xfer.data = (uint8_t *)readBuf;
xfer.dataSize = size;
if (size%32 == 0)
icodec->rxHandle.count = 16;
else
icodec->rxHandle.count = 1;

if (SAI_TransferReceiveEDMA(icodec->sai, &icodec->rxHandle, &xfer) != kStatus_Success)
return 0;

return size;
}
...
}

static void saidma_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
{
...
struct rt_audio_device *audio = (struct rt_audio_device *)userData;
struct imxcodec *icodec = audio->parent.user_data;
if(handle == &icodec->txHandle)
{
ind = handle->queueDriver;
saddr = (rt_uint8_t*)handle->saiQueue[ind].data;
rt_audio_tx_complete(userData, saddr);
}
else if(handle == &icodec->rxHandle)
{
rt_audio_rx_done(userData, icodec->rxbuff, RX_BUFFER_SIZE);
if(icodec->rx_started == 1)
{
icodec_transmit(userData, RT_NULL, icodec->rxbuff, RX_BUFFER_SIZE);
}
}
}

d、实现音频接收功能的开始icodec_start与停止icodec_stop功能

rt_err_t icodec_start(struct rt_audio_device *audio,int stream)
{
struct imxcodec *icodec = audio->parent.user_data;
if(stream == AUDIO_STREAM_RECORD)
{
icodec->rx_started = 1;
icodec_transmit(audio, RT_NULL, icodec->rxbuff, RX_BUFFER_SIZE);
}
return RT_EOK;
}

rt_err_t icodec_stop(struct rt_audio_device *audio,int stream)
{
struct imxcodec *icodec = audio->parent.user_data;
if(stream == AUDIO_STREAM_RECORD)
{
icodec->rx_started = 1;
}
return RT_EOK;
}

3、编写测试代码sound_test.c,测方法音频回环测试,将接收到的音频数据发送到音频播放。

while(1)
{
i = rt_device_read(device, 0, read_buffer, BUFF_SIZE);
...
rt_memcpy(write_buffer, read_buffer, BUFF_SIZE);
...
i = rt_device_write(device, 0, write_buffer, BUFF_SIZE);
...
}
4、最后附上代码,用法参考【飞凌RT1052】1、rt-thread移植适配第六部分,覆盖对应文件
代码:  imxrt1052-evk.zip

注:audio.c文件start、stop、suspend、resume的执行判断逻辑都是if (audio->ops->start!= RT_NULL),目前不确定是bug。这里将start改为对应的操作函数判断了

static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args)
{
...
if (audio->ops->start != RT_NULL)
...
if (audio->ops->stop != RT_NULL)
...
if (audio->ops->suspend != RT_NULL)
...
if (audio->ops->resume != RT_NULL)
...
}

相关推荐

电子产业图谱