此次活动我选择使用LPC55S69开发板实现SD卡内音频文件的播放,主要用到的设备有有线音箱、LPC55S69开发板、SD卡、个人电脑、安卓线。
一 硬件介绍
LPC55S69是一款ARM Cortex M33内核的单片机,运行频率可高达100MHz,内部包括TrustZone安全空间,保证代码的安全性。该芯片内部由主核心与辅助核心双核心结构构成,大大提高了处理器的性能与灵活性。320KB的SRAM以及高达640KB的闪存。高速与全速USB接口、五个通用定时器、高速SPI以及八个灵活串行通信外设等等工具,可大大方便开发者的设计难度。
LPC55S69开发板是作为LPC55S69微处理器的开发学习用板,该开发板为了方便用户快速了解使用LPC55S69芯片,配置了大量的外围电路,并将相关例程发布在NXP官网上,以供初学者与相关开发人员下载。下图为LPC55S69开发板的外部展示图与功能说明。
LPC55S69开发板外部展示与功能框图
由图中可以看出,LPC55S69开发板外部电路装配有1个USB供电口,两个USB通信接口,以及一个板载调试器,用于程序下载以及在线调试。四个USB接口均可与安卓线相连,方便学习人员的调试。除此之外,开发板还包括SD卡槽,音频输入输出接口,以及RGB灯珠,并提供相应的例程,使开发者可以轻松实现SD卡的读取,音频信号的输入与输出,RGB三色光的调整,进而学习LPC55S69的相关功能。LPC扩展口可轻松连接外部硬件系统,与其他系统进行互动,mikroBUS接口可轻松连接上位机等信息通讯系统,实现互联,PMOD接头可以连接相应的外设。
二 设计思路
针对这次Funpack十一期的任务要求,我选择了利用SD卡播放音乐的任务。由于开发板上自带SD卡槽以及音频输出接口,以及丰富的例程包,使得任务完成的难度降低很多。
实现该功能的设计思路如下图所示。首先完成该芯片相关功能的初始化,其中包括时钟配置,串口初始化,I2C通信初始化,I2S通信初始化,用于与板载WM8904解码芯片通信,FATFS系统初始化,用于读取SD内存卡中的相关信息。在初始化任务结束后,我们首先检测SD卡是否插入到卡槽之中,检测到卡插入之后,向上位机反馈相应的信息,对SD卡进行挂载,随后寻找卡内指定的音频文件,打开文件,并读取相应的文件信息。这里我设置了双缓存区,用于加载音频内容,每个缓存区大小为20KB,首先将一部分内容加载到缓存区1,同时启动音频播放,在音频播放的同时,将下一部分的音频内容加载到缓存区2中,等待音频播放完毕,继续播放缓存区2中的音频信息,再将下一部分信息加载到缓存区1中,依此类推,直到整首歌播放完毕,关闭播放。
程序运行流程图
本次代码编译环境选择KEIL5软件,指定音乐格式为wav格式,该格式音频文件内部信息为未经加密处理的音频信号,播放较为简单,其他几种格式需要进行解密处理,操作复杂,在这里没有进行相关研究。以下为程序片段。
/* set BOD VBAT level to 1.65V */
POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
CLOCK_EnableClock(kCLOCK_InputMux);
CLOCK_EnableClock(kCLOCK_Iocon);
CLOCK_EnableClock(kCLOCK_Gpio0);
CLOCK_EnableClock(kCLOCK_Gpio1);
/* USART0 clock */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* I2C clock */
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_XTAL32M_MASK; /*!< Ensure XTAL16M is on */
PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK; /*!< Ensure XTAL16M is on */
SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /*!< Ensure CLK_IN is on */
ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK;
CLOCK_AttachClk(kEXT_CLK_to_PLL0);
系统初始化
PRINTF("\r\nFATFS example to demonstrate how to use FATFS with SD card.\r\n");
PRINTF("\r\nPlease insert a card into board.\r\n");
if (sdcardWaitCardInsert() != kStatus_Success)
{
return -1;
}
if (f_mount(&g_fileSystem, driverNumberBuffer, 0U))
{
PRINTF("Mount volume failed.\r\n");
return -1;
}
#if (FF_FS_RPATH >= 2U)
error = f_chdrive((char const *)&driverNumberBuffer[0U]);
if (error)
{
PRINTF("Change drive failed.\r\n");
return -1;
}
#endif
SD卡配置程序
error = f_open(&g_fileObject, _T("/song.wav"), (FA_READ | FA_OPEN_EXISTING));
if (error)
{
if (error == FR_EXIST)
{
PRINTF("File exists.\r\n");
}
else
{
PRINTF("Open file failed.\r\n");
return -1;
}
}
error = f_read(&g_fileObject, music1, sizeof(music1), &bytesRead);
if ((error) || (bytesRead != sizeof(music1)))
{
PRINTF("Read file failed. \r\n");
failedFlag = true;
}
musicflag=1;
s_TxTransfer.data = &music1[0];
s_TxTransfer.dataSize = sizeof(music1);
I2S_TxTransferCreateHandle(DEMO_I2S_TX, &s_TxHandle, TxCallback, (void*)&s_TxTransfer);
I2S_TxTransferNonBlocking(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer);
文件读取与音乐播放
for(;;)
{
if(musicflag2!=musicflag)
{
if(musicflag==0)
{
error = f_read(&g_fileObject, music1, sizeof(music1), &bytesRead);
if ((error) || (bytesRead != sizeof(music1)))
{
PRINTF("Read file failed. \r\n");
failedFlag = true;
break;
}
}
else
{
error = f_read(&g_fileObject, music2, sizeof(music2), &bytesRead);
if ((error) || (bytesRead != sizeof(music2)))
{
PRINTF("Read file failed. \r\n");
failedFlag = true;
break;
}
}
musicflag2=musicflag;
}
}
双缓存填充
static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData)
{
if((musicflag==0)&&(music_close==0))
{
musicflag=1;
s_TxTransfer.data = &music1[0];
s_TxTransfer.dataSize = sizeof(music1);
I2S_TxTransferNonBlocking(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer);
}
else if((musicflag==1)&&(music_close==0))
{
musicflag=0;
s_TxTransfer.data = &music2[0];
s_TxTransfer.dataSize = sizeof(music2);
I2S_TxTransferNonBlocking(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer);
}
if(bytesRead<0x5000)//
{
music_close=1;
}
}
音乐播放
三、功能展示
将相关程序下载到开发板芯片中,随后将存好音频文件的SD卡插入到开发板中,将音频线分别连接桌面音箱和开发板音频输出接口,随后给音箱和开发板上电,观察开发板的运行效果。能够听到,在上电结束后,音箱可以正常播放SD卡内预设置的音乐文件,并在开发板复位之后也可以从头运行。具体演示可看视频。注意,串口上位机波特率设置为115200,SD卡中请放入wav文件,文件名设置为“song”。
硬件连接图
串口接收信息
四、心得体会
感谢电子森林,硬禾学堂,提供这些非常难得的体验机会!该活动促使我学习了LPC55S69芯片的开发流程,并对音频开发的I2S,SD卡读取所借用的FATFS系统软件进行了相应的学习,是一次很好了解软件的机会,也体会到程序语言对嵌入式开发的重要性。在这里非常感谢硬禾学堂提供的这次机会。