Funpack11:基于LPC55S69开发板的音乐播放器
任务一: 读取SD卡(SD卡自备)中的音频文件,使用板卡上的3.5mm音频接口播放音乐 视频中音乐音量较低
标签
嵌入式系统
lxb
更新2021-11-04
1288

完成任务一:

读取SD卡(SD卡自备)中的音频文件,使用板卡上的3.5mm音频接口播放音乐。

LPCXpresso55S69 开发板为评估和开发基于 Arm ® Cortex ® -M33 架构的 LPC55S6x MCU 提供了理想的平台。该板包括高性能板载调试探针、音频子系统和加速度计,并提供多种选项,用于添加用于网络、传感器、显示器和其他接口的现成附加板。

MCUXpresso 工具套件完全支持 LPCXpresso55S69,该套件提供设备驱动程序、中间件和示例以允许快速开发,以及配置工具和可选的免费 IDE。MCUXpresso 软件与开源 MCU 操作系统 FreeRTOS、来自 Arm 和 IAR 等流行工具供应商的工具兼容,并且 LPCXpresso55S69 还可与 SEGGER 和 P&E Micro 提供的流行调试探针一起使用。

芯片功能图

FjhwNi0yfkLcWWW1cxn0zzPqH2I0

  • LPC55S6x MCU家族是全球首款基于通用Cortex-M33的微控制器。
  • 该高效率MCU家族采用Armv8-M架构,性能和高级安全功能达到新水平,包括TrustZone-M和协处理器扩展。LPC55S6x家族利用协处理器扩展型号,大幅提高信号处理效率,采用专有DSP加速器,使计算的时钟周期减少了10倍。还可选择使用第二个Cortex-M33内核,支持灵活地平衡高性能与功率效率。
  • 此外,LPC55S6x MCU家族依托基于40nm NVM的处理技术,具备成本效益优势,提供广泛的可扩展封装和存储器选项,并提供强大的支持,包括MCUXpresso软件和工具生态系统及低成本开发板。

以上是凑字数的,下面开始正式开始:

首先是一个入门教程的推荐:https://blog.csdn.net/k331922164/category_9640818.html

因为本次任务,我参考的是其中的LPC55S69之FatFs_SDCard这篇文章,当然其实不太严谨,因为这篇博客其实是参考的是官方SDK,既然提到这里了,(软件的安装与LPC55s69的SDK下载参考直播教程即可)

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2szMzE5MjIxNjQ=,size_16,color_FFFFFF,t_70

需要提一下,上图中可能因为IDE版本的变迁发生了一些变化,安照下图即可:

FhGRdQaLty2gDdHr_OPcebjuGwfp

下面是先点Add Folder

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2szMzE5MjIxNjQ=,size_16,color_FFFFFF,t_70

下面这步貌似可以跳过

FgOEXJ-HuHShP8P-U-JCdHp5cDVr

之后就是新建fatfs_sdcard.h和fatfs_sdcard.c加入工程:

1、fatfs_sdcard.h

#ifndef FATFS_SDCARD_H_
#define FATFS_SDCARD_H_
 
#include <stdio.h>
#include <string.h>
#include "fsl_sd.h"
#include "fsl_debug_console.h"
#include "ff.h"
#include "diskio.h"
#include "fsl_sd_disk.h"
#include "board.h"
 
#include "pin_mux.h"
#include <stdbool.h>
#include "fsl_iocon.h"
 
/* buffer size (in byte) for read/write operations */
#define BUFFER_SIZE (100U)
 
extern FATFS g_fileSystem; /* File system object */
extern FIL g_fileObject;   /* File object */
 
extern SDK_ALIGN(uint8_t g_bufferWrite[SDK_SIZEALIGN(BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)],
          MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN));
extern SDK_ALIGN(uint8_t g_bufferRead[SDK_SIZEALIGN(BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)],
          MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN));
 
extern const sdmmchost_detect_card_t s_sdCardDetect;
 
extern FRESULT error;
extern UINT bytesWritten;
extern UINT bytesRead;
extern const TCHAR driverNumberBuffer[];
extern TCHAR * fileName;
 
void fatfs_sdcard_init(void);
void fatfs_sdcard_read(void);
void fatfs_sdcard_write(void);
 
status_t sdcardWaitCardInsert(void);
 
#endif /* FATFS_SDCARD_H_ */

2、fatfs_sdcard.c

#include "fatfs_sdcard.h"
 
FATFS g_fileSystem; /* File system object */
FIL g_fileObject;   /* File object */
 
SDK_ALIGN(uint8_t g_bufferWrite[SDK_SIZEALIGN(BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)],
          MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN));
SDK_ALIGN(uint8_t g_bufferRead[SDK_SIZEALIGN(BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CACHE)],
          MAX(SDMMC_DATA_BUFFER_ALIGN_CACHE, SDMMCHOST_DMA_BUFFER_ADDR_ALIGN));
 
const sdmmchost_detect_card_t s_sdCardDetect = {
    .cdType = BOARD_SD_DETECT_TYPE,
    .cdTimeOut_ms = (~0U),
};
 
FRESULT error;
UINT bytesWritten;
UINT bytesRead;
const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
 
TCHAR * fileName = "/config.txt";
 
void fatfs_sdcard_init(void) {
	static uint8_t initFlag = 0;
	if(initFlag == 0)  {
		CLOCK_EnableClock(kCLOCK_InputMux);
		CLOCK_AttachClk(BOARD_SDIF_CLK_ATTACH);
		CLOCK_SetClkDiv(kCLOCK_DivSdioClk, (uint32_t)(SystemCoreClock / FSL_FEATURE_SDIF_MAX_SOURCE_CLOCK + 1U), true);
		initFlag = 1;
	}
 
    if (sdcardWaitCardInsert() != kStatus_Success) {
    	PRINTF("\r\nPlease insert a card into board.\r\n");
    }
    if (f_mount(&g_fileSystem, driverNumberBuffer, 0U)) {
        PRINTF("Mount volume failed.\r\n");
    }
#if (FF_FS_RPATH >= 2U)
    error = f_chdrive((char const *)&driverNumberBuffer[0U]);
    if (error) {
        PRINTF("Change drive failed.\r\n");
    }
#endif
}
 
void fatfs_sdcard_write(void) {
	uint8_t i;
 
	PRINTF("Write.\r\n");
    error = f_open(&g_fileObject, (const TCHAR*)fileName, (FA_WRITE | FA_CREATE_ALWAYS));
    if (error) {
        if (error == FR_EXIST) {
            PRINTF("File exists.\r\n");
        } else {
            PRINTF("Open file failed.\r\n");
        }
        fatfs_sdcard_init();
        error = f_open(&g_fileObject, (const TCHAR*)fileName, (FA_WRITE | FA_CREATE_ALWAYS));
    }
 
    for(i=0;i<8;i++) { // Writting Bytes
    	g_bufferWrite[i] = '0' +i;
    }
 
    error = f_write(&g_fileObject, g_bufferWrite, sizeof(g_bufferWrite), &bytesWritten);
    if ((error) || (bytesWritten != sizeof(g_bufferWrite))) {
    	PRINTF("Write file failed. \r\n");
    }
 
    if (f_close(&g_fileObject)) {
        PRINTF("\r\nClose file failed.\r\n");
    }
}
 
void fatfs_sdcard_read(void) {
	uint8_t i;
 
	PRINTF("Read.\r\n");
    error = f_open(&g_fileObject, (const TCHAR*)fileName, FA_READ);
    if (error) {
        if (error == FR_EXIST) {
            PRINTF("File exists.\r\n");
        } else {
            PRINTF("Open file failed.\r\n");
        }
        fatfs_sdcard_init();
        error = f_open(&g_fileObject, (const TCHAR*)fileName, FA_READ);
    }
    if (f_lseek(&g_fileObject, 0U)) {
    	PRINTF("Set file pointer position failed. \r\n");
    }
 
    memset(g_bufferRead, 0U, sizeof(g_bufferRead));
    error = f_read(&g_fileObject, g_bufferRead, sizeof(g_bufferRead), &bytesRead);
    if ((error) || (bytesRead != sizeof(g_bufferRead))) {
    	PRINTF("Read file failed. \r\n");
    }
 
    for(i=0;i<8;i++) { // Read Bytes
    	PRINTF("%c",g_bufferRead[i]);
    }
 
    if (f_close(&g_fileObject)) {
        PRINTF("\r\nClose file failed.\r\n");
    }
}
 
status_t sdcardWaitCardInsert(void) {
    g_sd.host.base           = SD_HOST_BASEADDR;
    g_sd.host.sourceClock_Hz = SD_HOST_CLK_FREQ;
    g_sd.usrParam.cd = &s_sdCardDetect;
    if (SD_HostInit(&g_sd) != kStatus_Success) {
        PRINTF("\r\nSD host init fail\r\n");
        return kStatus_Fail;
    }
    SD_PowerOffCard(g_sd.host.base, g_sd.usrParam.pwr);
    if (SD_WaitCardDetectStatus(SD_HOST_BASEADDR, &s_sdCardDetect, true) == kStatus_Success) {
        PRINTF("\r\nCard inserted.\r\n");
        SD_PowerOnCard(g_sd.host.base, g_sd.usrParam.pwr);
    } else {
        PRINTF("\r\nCard detect fail.\r\n");
        return kStatus_Fail;
    }
    return kStatus_Success;
}

SD卡部分就结束了,记得配置管脚文件。

之后就是I2S部分播放音乐,首先是将.flac文件(下载自网易云)转化为.wav文件(https://convertio.co/zh/download/b78091f7b2f336c7bc270b0f94747145e7fb1b/),下载时选择文件时最好选择一般音质(文件小),因为文件过大的话读取时总会出现问题。

I2S的对应芯片WM8904参考下面这篇文章:https://www.nxp.com.cn/docs/zh/application-note/AN12644.pdf

wm8904配置文件

wm8904_config_t wm8904Config = {
    .i2cConfig    = {.codecI2CInstance = BOARD_CODEC_I2C_INSTANCE, .codecI2CSourceClock = BOARD_CODEC_I2C_CLOCK_FREQ},
    .recordSource = kWM8904_RecordSourceLineInput,
    .recordChannelLeft  = kWM8904_RecordChannelLeft2,
    .recordChannelRight = kWM8904_RecordChannelRight2,
    .playSource         = kWM8904_PlaySourceDAC,
    .slaveAddress       = WM8904_I2C_ADDRESS,
    .protocol           = kWM8904_ProtocolI2S,
    .format             = {.sampleRate = kWM8904_SampleRate11025Hz, .bitWidth = kWM8904_BitWidth16},
    .mclk_HZ            = DEMO_I2S_MASTER_CLOCK_FREQUENCY,
    .master             = false,
};

之后就是阅读官方SDK的代码。I2S播放按照官方代码即可。

打开文件并播放,换文件的话记得改名:

error = f_open(&g_fileObject, _T("/m1.wav"), (FA_READ | FA_OPEN_ALWAYS));
	if (error)
	{
		if (error == FR_EXIST)
		{
			PRINTF("File exists.\r\n");
		}
		else
		{
			PRINTF("Open file failed.\r\n");
			return -1;
		}
        }
StartSoundPlayback();
	uint8_t sd_flag = 1;
	int flag = 1;
	GPIO_PortToggle(GPIO, BOARD_LED_PORT, 1u << BOARD_LED_PIN);
	while (flag == 1)
	{
		if (Music_flag != sd_flag)
		{
			sd_flag = Music_flag;
			if (Music_flag == 0)
			{
				error = f_read(&g_fileObject, tf_Music1, sizeof(tf_Music1),
						&bytesRead);
				if ((error) || (bytesRead != sizeof(tf_Music1)))
				{
					PRINTF(" That's all. \r\n");
					break;
				}
			}
			else if (Music_flag == sd_flag)
			{
				error = f_read(&g_fileObject, tf_Music0, sizeof(tf_Music0),
						&bytesRead);
				if ((error) || (bytesRead != sizeof(tf_Music0)))
				{
					PRINTF(" That's all. \r\n");
					break;
				}
			}
		}
	}

	f_open(&g_fileObject, _T("/m2.wav"), (FA_READ | FA_OPEN_ALWAYS));
	while (flag == 1)
		{
			if (Music_flag != sd_flag)
			{
				sd_flag = Music_flag;
				if (Music_flag == 0)
				{
					error = f_read(&g_fileObject, tf_Music1, sizeof(tf_Music1),
							&bytesRead);
					if ((error) || (bytesRead != sizeof(tf_Music1)))
					{
						PRINTF(" That's all. \r\n");
						break;
					}
				}
				else if (Music_flag == sd_flag)
				{
					error = f_read(&g_fileObject, tf_Music0, sizeof(tf_Music0),
							&bytesRead);
					if ((error) || (bytesRead != sizeof(tf_Music0)))
					{
						PRINTF(" That's all. \r\n");
						break;
					}
				}
			}
		}

 

不足是播放时声音有点小。

 

心得体会:

      这是我第一次接触LPC系列的芯片,首先不得不说的NXP的IDE做得很不错,简洁明了易上手,官方SDK也很完整,缺点就是中文资料相对较少有待完善,不过官方文档也不是那么难以阅读。这次的任务也不复杂(如果只是为了完成目标的话)。

      LPC55s69官方SDK中有Arzue IOT的Demo,有Arduino和microbus规格的接口,我想它会是一款不错的物联网开发板,我会好好利用的,它的高性能和安全模式也都引起了我的兴趣,值得我日后慢慢研究。

      不足是期间是大三期中考试,有点忙,所以完成的其实不是很理想,有待慢慢改进。

 

      总而言之这起的开发板非常值。

 

 

附件下载
m1.wav
young and beautiful
funpack.7z
因为MCUXpresso只支持.zip文件打开,所以需要解压才能打开工程
m2.wav
revolution
团队介绍
哈工大电信大三信息对抗
团队成员
lxb
哈尔滨工业大学电信学院信息对抗专业
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号