I2S Audio Device
The audio driver includes two layers: a hardware access layer (HAL) for I2S and an adapter layer for RT-Thread. The hardware access layer provides basic APIs for accessing I2S peripheral registers. Detailed information is available in the I2S API documentation. The adapter layer supports the RT-Thread driver framework, enabling audio programming via RT-Thread POSIX driver interfaces. Refer to the RT-Thread driver API documentation for details. Main functionalities include:
i2s samplerate
i2s channel
i2s sample bitwidth
i2s slave/master select
Driver Configuration
Select the desired I2S device in the {menuselection} On-Chip Peripheral RTOS Drivers --> Enable I2S Audio Driver menu.
#define BSP_USING_DMA 1
#define RT_USING_AUDIO 1
#define BSP_USING_I2S 1
#define BSP_ENABLE_I2S_MIC 1
#define BSP_ENABLE_I2S_CODEC 1
Device Names
i2s<x>, where x is the device number, such asi2s1,i2s2, corresponding to the peripheral number. Refer to the definitions in audio_config.h. You can see that the device name is i2s2, but it actually corresponds to the hardware i2s1 (hwp_i2s1). For chips with only one I2S, or if I2s1 is actually used, note that hwp_i2s2 should be changed to hwp_i2s1. If configuring BF0_MIC_CONFIG, the I2S used as a mic will use drv_i2s_mic.c. If using BSP_ENABLE_I2S_CODEC, drv_i2s_audio.c is generally used for playback data. Note that rt_device_find(“i2s1”) or rt_device_find(“i2s2”) should match the .name below. You need to specifically check which one is used in the configuration below.
struct i2s_audio_cfg_t bf0_i2s_audio_obj[] = { … }
#ifdef BSP_USING_I2S
#ifdef BSP_ENABLE_I2S_MIC
#ifndef BF0_MIC_CONFIG
#define BF0_MIC_CONFIG \
{ \
.name = "i2s1", \
.dma_handle = MIC_DMA_INSTANCE, \
.dma_request = I2S1_RX_DMA_REQUEST, \
.is_record = 1, \
.i2s_handle = hwp_i2s1, \
.reqdma_tx = I2S1_TX_DMA_REQUEST, \
.hdma_tx = MIC_TX_DMA_INSTANCE, \
}
#endif /* BF0_MIC_CONFIG */
#endif /* BSP_ENABLE_I2S_MIC */
#ifdef BSP_ENABLE_I2S_CODEC
#ifndef BF0_I2S2_CONFIG
#define BF0_I2S2_CONFIG \
{ \
.name = "i2s2", \
.dma_handle = I2S_RX_DMA_INSTANCE, \
.dma_request = I2S2_RX_DMA_REQUEST, \
.is_record = 1, \
.i2s_handle = hwp_i2s2, \
.reqdma_tx = I2S2_TX_DMA_REQUEST, \
.hdma_tx = I2S_TX_DMA_INSTANCE, \
}
#endif /* BF0_I2S2_CONFIG */
#endif /* BSP_ENABLE_I2S_CODEC */
Usage Process
1. Open the I2S Device
/* Choose i2s2 or i2s1 based on the configuration in audio_config.h */
rt_device_t i2s = rt_device_find("i2s2");
if (i2s)
{
rt_device_open(i2s, RT_DEVICE_FLAG_RDWR);}
2. Configure Parameters
struct rt_audio_caps caps;
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_PARAM;
/* 1 for mono, 2 for stereo */
caps.udata.config.channels = 2;
/* Number of bits per sample */
caps.udata.config.samplefmt = 16;
/* Sample rate */
caps.udata.config.samplerate = 44100;
rt_device_control(i2s, AUDIO_CTL_CONFIGURE, &caps);
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_MODE;
/* Mode setting, 0 --- master mode; 1 --- slave mode */
caps.udata.value = 0;
rt_device_control(i2s, AUDIO_CTL_CONFIGURE, &caps);
By default, I2S outputs directly to peripherals. There is also an advanced usage where I2S inputs from audprc module. This is not commonly used. If needed, configure it as follows: if you don’t know what is audprc->i2s, skip this
/* i2s input from audprc*/
rt_uint32_t inter = 1;
rt_device_control(i2s, AUDIO_CTL_SETINPUT, (void *)inter);
3. Set Callback Functions for Receiving or Sending
static rt_err_t audio_rx_ind(rt_device_t dev, rt_size_t size)
{
LOG_I("audio_rx_ind %d\n", size);
/*
here can notify read thread to use rt_device_read(i2s) to read i2s
*/
return RT_EOK;
}
rt_err_t audio_tx_done(rt_device_t dev, void *buffer)
{
LOG_I("audio_tx_done \n");
return RT_EOK;
}
rt_device_set_rx_indicate(i2s, audio_rx_ind);
rt_device_set_tx_complete(i2s, audio_tx_done);
4. I2S Start
int stream = 0;
//select one for stream
#if playback_only
stream = AUDIO_STREAM_REPLAY; /*playback only*/
#else if capture_only
stream = AUDIO_STREAM_RECORD; /*record only*/
#else if capture_and_playback
stream = AUDIO_STREAM_RXandTX; /*record & playback*/
#endif
rt_device_control(i2s, AUDIO_CTL_START, &stream);
rt_thread_mdelay(xxxx);
rt_device_close(i2s);
5. config size of dma ping-pong buffer
#define AUDIO_DATA_SIZE 640
ALIGN(4) static uint8_t audio_data[AUDIO_DATA_SIZE];
ALIGN(4) static uint8_t audio_tx_data[AUDIO_DATA_SIZE];
AUDIO_DATA_SIZE is size of DMA ping-pong buffer,one DMA frame size is (AUDIO_DATA_SIZE / 2), when read or write,data size should be (AUDIO_DATA_SIZE / 2).
Using the Audio Driver
The adapter layer registers hardware support functions for RT-Thread and implements these functions using the I2S HAL. The I2S HAL API is detailed in the I2S documentation.
Example Code for Audio Capture Using RT-Thread Microphone Device:
uint8_t g_pipe_data[512];
// Find and open device
rt_device_t g_mic = rt_device_find("i2s1");
rt_err_t err = rt_device_open(g_mic, RT_DEVICE_FLAG_RDONLY);
// Configure Microphone device, sample rate 16000
struct rt_audio_caps caps;
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_SAMPLERATE;
caps.udata.value = 16000;
rt_device_control(g_mic, AUDIO_CTL_CONFIGURE, &caps);
// Start capture
int stream = 1; // record = 1, playback = 0
rt_device_set_rx_indicate(g_mic, audio_rx_ind);
rt_device_control(g_mic, AUDIO_CTL_START, &stream);
...
Example Code for Audio Playback Using RT-Thread Speaker/Headphone Device:
uint8_t g_pipe_data[512];
// Find and open device
rt_device_t g_i2s = rt_device_find("i2s2");
rt_err_t err = rt_device_open(g_i2s, RT_DEVICE_FLAG_RDWR);
// Configure speaker device, sample rate 16000
struct rt_audio_caps caps;
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_SAMPLERATE;
caps.udata.value = 16000;
rt_device_control(g_i2s, AUDIO_CTL_CONFIGURE, &caps);
// Start playback
int stream = 0; // record = 1, playback = 0
rt_device_set_tx_complete(g_i2s, audio_tx_done);
rt_device_control(g_i2s, AUDIO_CTL_START, &stream);
...
other exmaple for i2s
$(sdk_root)\example\rt_device\i2s
shell cmd example
There are command lines at the end of the drv_i2s_audio.c and drv_i2s_mic.c files, which can also be used as a reference.