• 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

【RT1052】rt-thread 音頻驅(qū)動增加接收功能

03/03 14:49
469
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

本帖基于ok1052進一步完善音頻驅(qū)動,增加音頻接收部分。通過上一貼分析【飛凌RT1052】2、rt-thread 音頻驅(qū)動分析,主要修改兩個文件drv_codec.c和fsl_wm8960.c。

1、wm8960.c主要修改WM8960_Init函數(shù),使能音頻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、增加音頻接收需要的數(shù)據(jù)結(jié)構(gòu)并增加主控音頻外設(shè)初始化部分

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、音頻設(shè)備注冊時增加讀權(quán)限,以便上層應(yīng)用可以讀取音頻數(shù)據(jù)

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

c、完善音頻接收部分,音頻接收函數(shù)icodec_transmit和接收完成中斷回調(diào)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、實現(xiàn)音頻接收功能的開始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,測方法音頻回環(huán)測試,將接收到的音頻數(shù)據(jù)發(fā)送到音頻播放。

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移植適配第六部分,覆蓋對應(yīng)文件
代碼:??imxrt1052-evk.zip

注:audio.c文件start、stop、suspend、resume的執(zhí)行判斷邏輯都是if (audio->ops->start!= RT_NULL),目前不確定是bug。這里將start改為對應(yīng)的操作函數(shù)判斷了

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)
...
}

相關(guān)推薦

電子產(chǎn)業(yè)圖譜