【HC32F4A0开发板测评】+I2S语音播放测试
[复制链接]
本帖最后由 jinglixixi 于 2023-2-22 09:20 编辑
在HC32F4A0开发板上,为进行音频播放配置了I2S音频电路,所用的芯片为WM8731SEDS和BL6281。
此外,还配置MIC、3.5mm耳机接口、Line in接口及扬声器接口,以便进行录音、音频输入和输出测试。
具体的接口电路见图1和图2所示。
图1 AUDIO PA电路
图2 AUDIO CODEC电路
为学习其语音播放功能,对所提供的例程进行了测试。
在下载程序后,需将拨码开关J36拨到MCK一侧,并将耳机插入HPHONE端口J42。
在按下K2键后,即可听到“测试通过”的声音。
该语音的数据存放在数组中,其格式如下:
__ALIGN_BEGIN const uint8_t u8SoundBuf[121590] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
...
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
对I2S的初始化函数为:
int32_t BSP_I2S_Init(uint32_t u32AudioFreq)
{
stc_i2s_init_t stcI2sInit;
int32_t i32Ret;
GPIO_SetFunc(BSP_WM8731_I2S_CK_PORT, BSP_WM8731_I2S_CK_PIN, BSP_WM8731_I2S_CK_FUNC);
GPIO_SetFunc(BSP_WM8731_I2S_WS_PORT, BSP_WM8731_I2S_WS_PIN, BSP_WM8731_I2S_WS_FUNC);
GPIO_SetFunc(BSP_WM8731_I2S_SD_PORT, BSP_WM8731_I2S_SD_PIN, BSP_WM8731_I2S_SD_FUNC);
GPIO_SetFunc(BSP_WM8731_I2S_SDIN_PORT, BSP_WM8731_I2S_SDIN_PIN, BSP_WM8731_I2S_SDIN_FUNC);
GPIO_SetFunc(BSP_WM8731_I2S_MCK_PORT, BSP_WM8731_I2S_MCK_PIN, BSP_WM8731_I2S_MCK_FUNC);
FCG_Fcg1PeriphClockCmd(BSP_WM8731_I2S_CLK, ENABLE);
CLK_SetI2SClockSrc(BSP_WM8731_I2S_CLK_CH, BSP_WM8731_I2S_CLK_SRC);
(void)I2S_StructInit(&stcI2sInit);
stcI2sInit.u32ClockSrc = I2S_CLK_SRC_PLL;
stcI2sInit.u32Mode = I2S_MD_MASTER;
stcI2sInit.u32Protocol = I2S_PROTOCOL_PHILLIPS;
stcI2sInit.u32TransMode = I2S_TRANS_MD_HALF_DUPLEX_TX;
stcI2sInit.u32AudioFreq = u32AudioFreq;
stcI2sInit.u32ChWidth = I2S_CH_LEN_16BIT;
stcI2sInit.u32DataWidth = I2S_DATA_LEN_16BIT;
stcI2sInit.u32MCKOutput = I2S_MCK_OUTPUT_ENABLE;
i32Ret = I2S_Init(BSP_WM8731_I2S_UNIT, &stcI2sInit);
I2S_FuncCmd(BSP_WM8731_I2S_UNIT, I2S_FUNC_TX, ENABLE);
return i32Ret;
}
实现语音播放的函数为:
static void I2S_PlayAudio(void)
{
uint32_t u32DataLen;
const uint16_t *pu16Sound;
pu16Sound = (const uint16_t *)(uint32_t)(&u8SoundBuf[0]);
u32DataLen = sizeof(u8SoundBuf);
(void)I2S_Trans(BSP_WM8731_I2S_UNIT, pu16Sound, u32DataLen / 2U, 100U);
}
实现键控播放语音的主程序为:
int32_t main(void)
{
LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
BSP_CLK_Init();
BSP_IO_Init();
BSP_LED_Init();
BSP_KEY_Init();
(void)BSP_WM8731_Init(WM8731_INPUT_DEVICE_NONE, WM8731_OUTPUT_DEVICE_BOTH,
80U, WM8731_AUDIO_FREQ_32K, WM8731_DATA_WIDTH_16BIT);
LL_PERIPH_WP(EXAMPLE_PERIPH_WP);
for (;;) {
if (SET == BSP_KEY_GetStatus(BSP_KEY_2)) {
I2S_PlayAudio();
}
}
}
除了语音播放播放功能外,它还提供了及时录放功能。在完成程序下载后,
需将拨码开关J36拨到XTI一侧,并将耳机插入HPHONE端口J42。
当按下按键K2时,蓝色LED灯会被亮起,此时通过MIC1即可录制声音并加以播放音乐。若按下按键K3,则蓝色LED灯会熄灭,耳机也不再进行播放。
该处理过程看通过其主程序获得,其程序如下:
int32_t main(void)
{
/* Peripheral registers write unprotected */
LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
/* Configure BSP */
BSP_CLK_Init();
BSP_IO_Init();
BSP_LED_Init();
BSP_KEY_Init();
/* Configure WM8731 */
(void)BSP_WM8731_Init(WM8731_INPUT_DEVICE_MICROPHONE, WM8731_OUTPUT_DEVICE_BOTH,
80U, WM8731_AUDIO_FREQ_32K, WM8731_DATA_WIDTH_32BIT);
/* Peripheral registers write protected */
LL_PERIPH_WP(EXAMPLE_PERIPH_WP);
for (;;) {
if (RESET != BSP_KEY_GetStatus(BSP_KEY_2)) {
BSP_LED_On(LED_BLUE);
u8TransCompleteFlag = 0U;
u8ReceiveCompleteFlag = 0U;
BSP_WM8731_Record(&u32ReceiveBuf[0][0], BSP_WM8731_DMA_BLK_LEN);
BSP_WM8731_Play(&u32TransBuf[0][0], BSP_WM8731_DMA_BLK_LEN);
}
if (RESET != BSP_KEY_GetStatus(BSP_KEY_3)) {
BSP_WM8731_Stop();
BSP_LED_Off(LED_BLUE);
}
}
}
那它然后来实现的呢?
它主要定义了2个512存储单元的数组来进行记录和发送,其定义如下:
static uint32_t u32TransBuf[2][BSP_WM8731_DMA_BLK_LEN];
static uint32_t u32ReceiveBuf[2][BSP_WM8731_DMA_BLK_LEN];
#define BSP_WM8731_DMA_BLK_LEN (512U)
由于录制的声音通常都很大,所以每个数组都分为2部分,当一个进行工作时,另一个则进行数据补充,这样就实现了无缝的衔接。
此外,为了加快数据的处理速度,它采用了DMA的处理方式。
这里的声音录放操作是靠芯片WM8731来处理的,为其配置的辅助函数有4个,即:BSP_WM8731_Init 、BSP_WM8731_Record 、BSP_WM8731_Play及BSP_WM8731_Stop。
其中负责录制的函数为:
void BSP_WM8731_Record(uint32_t *pu32ReadBuf, uint16_t u16Size)
{
(void)DMA_SetDestAddr(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SDIN_CH, (uint32_t)pu32ReadBuf);
(void)DMA_SetTransCount(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SDIN_CH, u16Size);
(void)DMA_ChCmd(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SDIN_CH, ENABLE);
DMA_TransCompleteIntCmd(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SDIN_INT_CH, ENABLE);
if (RESET != I2S_GetStatus(BSP_WM8731_I2S_UNIT, I2S_FLAG_RX_ERR)) {
I2S_ClearStatus(BSP_WM8731_I2S_UNIT, I2S_FLAG_RX_ERR);
}
I2S_SetReceiveFIFOLevel(BSP_WM8731_I2S_UNIT, I2S_RECEIVE_LVL3);
I2S_FuncCmd(BSP_WM8731_I2S_UNIT, I2S_FUNC_RX, ENABLE);
}
负责播放的函数为:
void BSP_WM8731_Play(uint32_t *pu32WriteBuf, uint16_t u16Size)
{
(void)DMA_SetSrcAddr(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SD_CH, (uint32_t)pu32WriteBuf);
(void)DMA_SetTransCount(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SD_CH, u16Size);
(void)DMA_ChCmd(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SD_CH, ENABLE);
DMA_TransCompleteIntCmd(BSP_WM8731_DMA_UNIT, BSP_WM8731_DMA_SD_INT_CH, ENABLE);
if (RESET != I2S_GetStatus(BSP_WM8731_I2S_UNIT, I2S_FLAG_TX_ERR)) {
I2S_ClearStatus(BSP_WM8731_I2S_UNIT, I2S_FLAG_TX_ERR);
}
I2S_SetTransFIFOLevel(BSP_WM8731_I2S_UNIT, I2S_TRANS_LVL3);
I2S_FuncCmd(BSP_WM8731_I2S_UNIT, I2S_FUNC_TX, ENABLE);
}
如果在此基础上能将录制的语音片段存到FLASH存储器,并构建语音库则可实现一个电子留言板。
|