当前位置:网站首页>[RT thread] NXP rt10xx device driver framework -- Audio construction and use
[RT thread] NXP rt10xx device driver framework -- Audio construction and use
2022-07-03 17:11:00 【L_ seventeen】
Preparation before development
- Hardware platform :nxp rt10xx Single chip microcomputer
- IDE: Keil
1.Kconfig Modifications and menuconfig To configure
stay menuconfig Medium Hardware Drivers Config There may not be SAI The option to , User modification required Kconfig perfect
menuconfig BSP_USING_AUDIO
bool "Enable AUDIO"
select RT_USING_AUDIO
default n
if BSP_USING_AUDIO
config BSP_USING_AUDIO_PLAY
bool "Enable Audio Play"
default y
config BSP_USING_AUDIO_RECORD
bool "Enable AUDIO RECORD"
default n
config BSP_AUDIO_USING_DMA
bool "Enable AUDIO DMA"
default n
endif

stay RT-Thread Components Select from components Using Audio device drivers, So that we can use audio frame

2. add to audio Drive framework and BSP Driver interface
Drive frame :audio.c audio_pipe.c BSP Interface :drv_sai.c fsl_edma.c fsl_sai.c fsl_sai_edma.c

3. Add or modify drv_sai.c
official bsp May not fully support , We need to change bsp, Realization ops Correlation function
audio.h Modify in the header file
struct rt_audio_ops
{
rt_err_t (*getcaps)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*configure)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*init)(struct rt_audio_device *audio);
rt_err_t (*start)(struct rt_audio_device *audio, int stream);
rt_err_t (*stop)(struct rt_audio_device *audio, int stream);
rt_err_t (*control)(struct rt_audio_device *audio, int cmd, void *arg);
rt_size_t (*transmit)(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size);
/* get page size of codec or private buffer's info */
void (*buffer_info)(struct rt_audio_device *audio, struct rt_audio_buf_info *info);
};
from git downloaded rt series bsp There are many problems with the support package , There are many mistakes in some English names. The author also revised them by the way
static struct rt_audio_ops imxrt_payer_ops =
{
.getcaps = imxrt_audio_getcaps,
.configure = imxrt_audio_configure,
.init = imxrt_audio_init,
.start = imxrt_audio_start,
.stop = imxrt_audio_stop,
.transmit = imxrt_audio_transmit,
.buffer_info = imxrt_audio_buffer_info,
.control = imxrt_audio_control,
};
int rt_hw_sound_init(void)
{
rt_uint8_t* tx_fifo = RT_NULL;
rt_uint8_t* rx_fifo = RT_NULL;
sai_tx.base = SAI1;
sai_rx.base = SAI1;
sai_tx.irqn = SAI1_IRQn;
#ifdef BSP_AUDIO_USING_DMA
static struct saidma_tx_config sai_txdma = {
.channel = C052_TX_CHANNEL, .request = kDmaRequestMuxSai1Tx };
sai_tx.dma_tx = &sai_txdma;
sai_tx.dma_flag |= RT_DEVICE_FLAG_DMA_TX;
#if defined (BSP_USING_AUDIO_RECORD)
static struct saidma_rx_config sai_rxdma = {
.channel = C052_RX_CHANNEL, .request = kDmaRequestMuxSai1Rx };
sai_rx.dma_rx = &sai_rxdma;
#endif
#endif
/* Distribute DMA Carry buffer */
tx_fifo = rt_calloc(1, AUD_FIFO_SIZE);
rx_fifo = rt_calloc(1, AUD_FIFO_SIZE);
if(tx_fifo == RT_NULL || rx_fifo == RT_NULL)
{
return -RT_ENOMEM;
}
// Cache initialization
rt_memset(tx_fifo, 0, AUD_FIFO_SIZE);
imxrt_payer_dev.tx_fifo = tx_fifo;
rt_memset(rx_fifo, 0, AUD_FIFO_SIZE);
imxrt_payer_dev.rx_fifo = rx_fifo;
imxrt_payer_dev.audio.ops = &imxrt_payer_ops;
//audio Registration will call init So don't use the front init
rt_audio_register(&imxrt_payer_dev.audio, "sound0", RT_DEVICE_FLAG_RDWR, &imxrt_payer_dev);
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_sound_init);
audio.c In the frame , Register to achieve the following
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
{
rt_err_t result = RT_EOK;
struct rt_device *device;
RT_ASSERT(audio != RT_NULL);
device = &(audio->parent);
device->type = RT_Device_Class_Sound;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &audio_ops;
#else
device->init = _audio_dev_init;
device->open = _audio_dev_open;
device->close = _audio_dev_close;
device->read = _audio_dev_read;
device->write = _audio_dev_write;
device->control = _audio_dev_control;
#endif
device->user_data = data;
/* register a character device */
result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE);
/* initialize audio device */
if (result == RT_EOK)
result = rt_device_init(device);
return result;
}
Registration process , It mainly realizes the registration of equipment linked list and audio Peripheral initialization
1.int rt_hw_sound_init(void)
2.rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
Implement... In function rt_device_register And then execute rt_device_init namely :ops Registered in the structure init
3.rt_err_t rt_device_register(rt_device_t dev,const char *name,rt_uint16_t flags)
4.void rt_object_init(struct rt_object *object,enum rt_object_class_type type,const char *name)
Write the device object information into the linked list
add , The author found that the official audio The English name of the framework is wrong in many places , such as : take audio It's written in aduio, I hope the official components can be improved

Initialization function , Just write according to the bare metal thinking mode
static rt_err_t imxrt_audio_init(struct rt_audio_device* audio)
{
RT_ASSERT(audio != RT_NULL);
CLOCK_EnableClock(kCLOCK_Iomuxc);
CLOCK_EnableClock(kCLOCK_Sai1);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK,0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00,0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00,0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_14_SAI1_TX_BCLK,0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_15_SAI1_TX_SYNC,0x10B0u);
CLOCK_InitAudioPll(&audioPllConfig);
CLOCK_SetMux(kCLOCK_Sai1Mux, DEMO_SAI1_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_Sai1PreDiv, DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER);
CLOCK_SetDiv(kCLOCK_Sai1Div, DEMO_SAI1_CLOCK_SOURCE_DIVIDER);
BOARD_EnableSaiMclkOutput(RT_TRUE);
EDMA_CreateHandle(&sai_tx.dma_tx->edma, DMA0, sai_tx.dma_tx->channel);
DMAMUX_SetSource(DMAMUX, sai_tx.dma_tx->channel, (rt_uint8_t)sai_tx.dma_tx->request);
DMAMUX_EnableChannel(DMAMUX, sai_tx.dma_tx->channel);
SAI_TxGetDefaultConfig(&config);
config.masterSlave = kSAI_Master;
config.protocol = kSAI_BusI2S;
SAI_TxInit(sai_tx.base, &config);
#if defined (BSP_USING_AUDIO_RECORD)
EDMA_CreateHandle(&sai_rx.dma_rx->edma, DMA0, sai_rx.dma_rx->channel);
DMAMUX_SetSource(DMAMUX, sai_rx.dma_rx->channel, (rt_uint8_t)sai_rx.dma_rx->request);
DMAMUX_EnableChannel(DMAMUX, sai_rx.dma_rx->channel);
SAI_RxGetDefaultConfig(&config);
config.masterSlave = kSAI_Slave;
config.protocol = kSAI_BusI2S;
SAI_RxInit(sai_rx.base, &config);
#endif
//dma Interrupt priority setting
NVIC_SetPriority(C052_SAIDMA_IRQ,SAI_ISR_PRE);
format.bitWidth = kSAI_WordWidth32bits;
format.channel = 0U;
format.sampleRate_Hz = kSAI_SampleRate44100Hz;
format.protocol = config.protocol;
format.stereo = kSAI_Stereo;
format.isFrameSyncCompact = false;
format.watermark = FSL_FEATURE_SAI_FIFO_COUNT / 2U;
SAI_TransferTxCreateHandleEDMA(sai_tx.base, &sai_tx.dma_tx->txHandle, sai_TxDmaCallback, NULL, &sai_tx.dma_tx->edma);
SAI_TransferTxSetFormatEDMA(sai_tx.base, &sai_tx.dma_tx->txHandle, &format, DEMO_SAI_CLK_FREQ, DEMO_SAI_CLK_FREQ);
#if defined (BSP_USING_AUDIO_RECORD)
SAI_TransferRxCreateHandleEDMA(sai_rx.base, &sai_rx.dma_rx->rxHandle, sai_RxDmaCallback, NULL, &sai_rx.dma_rx->edma);
SAI_TransferRxSetFormatEDMA(sai_rx.base, &sai_rx.dma_rx->rxHandle, &format, DEMO_SAI_CLK_FREQ, DEMO_SAI_CLK_FREQ);
#endif
return RT_EOK;
}
#define AUD_BLOCK_CNT 2
#define AUD_BLOCK_SIZE 512
#define AUD_FIFO_SIZE (AUD_BLOCK_SIZE * AUD_BLOCK_CNT)
static void sai_TxDmaCallback(I2S_Type* base, sai_edma_handle_t* handle, rt_int32_t status, void* userData)
{
rt_audio_tx_complete(&imxrt_payer_dev.audio);
}
#if defined (BSP_USING_AUDIO_RECORD)
static void sai_RxDmaCallback(I2S_Type* base, sai_edma_handle_t* handle, rt_int32_t status, void* userData)
{
rt_audio_rx_done(&imxrt_payer_dev.audio, &imxrt_payer_dev.rx_fifo[0], AUD_BLOCK_SIZE);
}
#endif
// Start dma transmission
static rt_err_t imxrt_audio_start(struct rt_audio_device* audio, int stream)
{
RT_ASSERT(audio != RT_NULL);
xfer.data = imxrt_payer_dev.rx_fifo;
xfer.dataSize = AUD_BLOCK_SIZE;
#if defined (BSP_USING_AUDIO_RECORD)
SAI_TransferReceiveEDMA(sai_rx.base, &sai_rx.dma_rx->rxHandle, &xfer);
#endif
xfer.data = imxrt_payer_dev.tx_fifo;
xfer.dataSize = AUD_BLOCK_SIZE;
SAI_TransferSendEDMA(sai_tx.base, &sai_tx.dma_tx->txHandle, &xfer);
return RT_EOK;
}
static rt_err_t imxrt_audio_control (struct rt_audio_device *audio, int cmd, void *args)
{
rt_err_t result = RT_EOK;
switch (cmd)
{
case AUDIO_CTL_START:
imxrt_audio_start(audio,AUDIO_STREAM_REPLAY);
break;
case AUDIO_CTL_STOP:
imxrt_audio_stop(audio,AUDIO_STREAM_REPLAY);
break;
default:
result = -RT_ERROR;
break;
}
return result;
}
4. Build application layer demo
For the use of the application layer, please refer to the official link , If the function is abnormal, you need to see bsp Is the layer not built well :AUDIO equipment (rt-thread.org)
/**************************************************START OF FILE*****************************************************/
/*------------------------------------------------------------------------------------------------------------------ Includes */
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
/*------------------------------------------------------------------------------------------------------------------ Macros */
#define SOUND_DEVICE_NAME "sound0"
#define MIC_DEVICE_NAME "record"
#define THREAD_PRIORITY 12
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 2
#define FIFO_SIZE 512
/*------------------------------------------------------------------------------------------------------------------ Variables */
static rt_device_t h_dev_speaker;
static rt_device_t h_dev_mic;
static rt_thread_t h_thread_audio = RT_NULL;
int32_t micBuf[FIFO_SIZE/4],speBuf[FIFO_SIZE/4];
/*------------------------------------------------------------------------------------------------------------------ Functions */
static void thread_audio(void *parameter)
{
int i;
int length;
rt_kprintf("thread audio start\n");
#if 0 //bypass
while(1)
{
length = rt_device_read(h_dev_mic, 0, micBuf, FIFO_SIZE);
if(length)
{
memcpy(speBuf,micBuf,length);
rt_device_write(h_dev_speaker, 0, speBuf, length);
}
}
#else // Short the output to the input
for(i=0;i<FIFO_SIZE/4;i++)
{
speBuf[i] = i*0x100;
}
rt_device_write(h_dev_speaker, 0, speBuf, FIFO_SIZE);
while(1)
{
length = rt_device_read(h_dev_mic, 0, micBuf, FIFO_SIZE);
if(length)
{
rt_device_write(h_dev_speaker, 0, speBuf, length);
}
}
#endif
}
int xAPP_AudioInit(void)
{
rt_err_t ret = RT_EOK;
/* Find by device name Audio equipment , Get device handle */
h_dev_speaker = rt_device_find(SOUND_DEVICE_NAME);
if (!h_dev_speaker)
{
rt_kprintf("find %s failed!\n", SOUND_DEVICE_NAME);
return RT_ERROR;
}
ret = rt_device_open(h_dev_speaker, RT_DEVICE_OFLAG_WRONLY);
if (ret != RT_EOK)
{
rt_kprintf("open %s failed!\n", SOUND_DEVICE_NAME);
return RT_ERROR;
}
h_dev_mic = rt_device_find(MIC_DEVICE_NAME);
if (!h_dev_mic)
{
rt_kprintf("find %s failed!\n", MIC_DEVICE_NAME);
return RT_ERROR;
}
ret = rt_device_open(h_dev_mic, RT_DEVICE_OFLAG_WRONLY);
if (ret != RT_EOK)
{
rt_kprintf("open %s failed!\n", MIC_DEVICE_NAME);
return RT_ERROR;
}
ret = rt_device_control(h_dev_speaker, AUDIO_CTL_START, RT_NULL);
if (ret != RT_EOK)
{
rt_kprintf("start %s failed!\n", SOUND_DEVICE_NAME);
return RT_ERROR;
}
// establish Audio Threads
h_thread_audio = rt_thread_create("t_audio",thread_audio,RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE);
if (h_thread_audio != RT_NULL)
{
rt_thread_startup(h_thread_audio);
}
return 0;
}
/* Export to msh In the command list */
//MSH_CMD_EXPORT(audioInit, audio init);
/****************************************************END OF FILE*****************************************************/
Test input and output ,SAI RT and TX Short circuit


边栏推荐
- 大变局!全国房价,跌破万元大关
- Talk about several methods of interface optimization
- 建立自己的网站(23)
- One brush 145 force deduction hot question-2 sum of two numbers (m)
- 27. 输入3个整数,按从大到小的次序输出。要求用指针方法实现。
- [combinatorics] recursive equation (general solution structure of recursive equation with multiple roots | linear independent solution | general solution with multiple roots | solution example of recu
- Design e-commerce spike
- 一位普通程序员一天工作清单
- 數據分析必備的能力
- How to delete a specific line from a text file using the SED command?
猜你喜欢

静态程序分析(一)—— 大纲思维导图与内容介绍

PHP online confusion encryption tutorial sharing + basically no solution

The most complete postman interface test tutorial in the whole network, API interface test

【RT-Thread】nxp rt10xx 设备驱动框架之--hwtimer搭建和使用

图之深度优先搜索

Bcvp developer community 2022 exclusive peripheral first bullet

建立自己的网站(23)

Meituan side: why does thread crash not cause JVM crash

设计电商秒杀

C语言按行修改文件
随机推荐
New library online | cnopendata complete data of Chinese insurance institution outlets
Great changes! National housing prices fell below the 10000 yuan mark
Design e-commerce spike
[combinatorics] recursive equation (definition of general solution | structure theorem of general solution of recursive equation without multiple roots)
图之深度优先搜索
Depth first search of graph
Leetcode13. Roman numeral to integer (three solutions)
Execute script unrecognized \r
IL Runtime
Javescript variable declaration -- VaR, let, const
Kindeditor editor upload image ultra wide automatic compression -php code
SVN如何查看修改的文件记录
[combinatorial mathematics] counting model, common combinatorial numbers and combinatorial identities**
What is your income level in the country?
C语言按行修改文件
PHP production website active push (website)
Svn full backup svnadmin hotcopy
[combinatorics] recursive equation (outline of recursive equation content | definition of recursive equation | example description of recursive equation | Fibonacci Series)
One brush 146 force buckle hot question-3 longest substring without repeated characters (m)
Redis:关于列表List类型数据的操作命令