Funpack第11期——基于LPC55S69-EVK的SD卡音乐播放器
完成第十一期指定的任务: 任务一: 读取SD卡(SD卡自备)中的音频文件,使用板卡上的3.5mm音频接口播放音乐。
标签
嵌入式系统
测试
funpack11
小鲨鱼大白牙
更新2021-11-01
1540
  • LPC55S69开发板介绍

Funpack11:基于Arm Cortex -M33 NXP LPC55S69开发板。

      该开发板是基于Arm Cortex -M33的嵌入式应用微控制器。配有320kB的片上SRAM、640kB的片上闪存、高速和全速USB主机与设备接口、一个SD/MMC/SDIO接口、五个通用定时器,一个CTimer/PWM、一个RTC/警报定时器、一个24位多速率定时器(MRT)、一个窗口看门狗定时器(WWDT)、一个高速SPI(50MHz)、八个灵活串行通信外设(每个外设可以是USART、SPI、I2C或I2S接口)、一个16位1.0Msamples/sec ADC、温度传感器。

FkHDrkwZMij48vyo5KLQjwGvNmhe

  • 实验任务

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

  • 构建流程

通过MCUXpresso Config Tools生成SD卡例程。(该工具支持多种编译环境的工程构建,本次实验使用Keil开发)

Fv95AMD4zSgZXT9acSkSTx3YVo0l

之后课根据项目配置引脚,时钟,外设等。配置完成后点击(更新源代码)即可生成相应的配置代码。

FrM_bi7Ic8Xuv4besCFYU3RkqNgE

FuWaYiaqt62qyBxNty13JU0QNWF7

再将WM8904的驱动代码移植到sd卡工程中,就好了

Fns4mr_07bJfFcfu-Mzne8h5UjjD

代码

int main(void)
{
    FRESULT error;
    UINT bytesWritten;
    const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
    volatile bool failedFlag           = false;
    char ch                            = '0';
    BYTE work[FF_MAX_SS];
    uint8_t sd_flag = 1;
    uint32_t port_state = 0;
    uint32_t port_state1 = 0;
    uint32_t port_num = 0;

    /* 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);
    /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
    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);

    const pll_setup_t pll0Setup = {
        .pllctrl = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_SELI(2U) | SYSCON_PLL0CTRL_SELP(31U),
        .pllndec = SYSCON_PLL0NDEC_NDIV(125U),
        .pllpdec = SYSCON_PLL0PDEC_PDIV(8U),
        .pllsscg = {0x0U, (SYSCON_PLL0SSCG1_MDIV_EXT(3072U) | SYSCON_PLL0SSCG1_SEL_EXT_MASK)},
        .pllRate = 24576000U,
        .flags   = PLL_SETUPFLAG_WAITLOCK};
    /*!< Configure PLL to the desired values */
    CLOCK_SetPLL0Freq(&pll0Setup);
    /* Attach PLL clock to MCLK for I2S, no divider */
    CLOCK_AttachClk(kPLL0_to_MCLK);
    SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
    SYSCON->MCLKIO  = 1U;
    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 0U, true);
    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 1U, false);
    /*!< Switch PLL0 clock source selector to XTAL16M */
    /* I2S clocks */
    CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM6);
    CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM7);
    /* reset FLEXCOMM for I2C */
    RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
    /* reset FLEXCOMM for I2S */
    RESET_PeripheralReset(kFC6_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
    NVIC_ClearPendingIRQ(FLEXCOMM6_IRQn);
    NVIC_ClearPendingIRQ(FLEXCOMM7_IRQn);
    /* Enable interrupts for I2S */
    EnableIRQ(FLEXCOMM6_IRQn);
    EnableIRQ(FLEXCOMM7_IRQn);

    /* Initialize the rest */
    BOARD_InitBootPins();
    BOARD_BootClockFROHF96M();
    BOARD_InitDebugConsole();
    BOARD_InitSysctrl();

    PINT_Init(PINT);
    PINT_PinInterruptConfig(PINT, kPINT_PinInt0, kPINT_PinIntEnableFallEdge, pint_intr_callbakc0);
    PINT_EnableCallbackByIndex(PINT, kPINT_PinInt0);
    PINT_PinInterruptConfig(PINT, kPINT_PinInt1, kPINT_PinIntEnableFallEdge, pint_intr_callbakc1);
    PINT_EnableCallbackByIndex(PINT, kPINT_PinInt1);

    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
    PRINTF("\r\nCreate a file in that directory......\r\n");
    error = f_open(&g_fileObject, _T("/3232.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;
        }
    }

    error = f_read(&g_fileObject, tf_Music0, sizeof(tf_Music0), &bytesRead);
    if ((error) || (bytesRead != sizeof(tf_Music0)))
    {
            PRINTF("Read file failed. \r\n");
            failedFlag = true;
    }

    PRINTF("Configure WM8904 codec\r\n");
    /* protocol: i2s
     * sampleRate: 48K
     * bitwidth:16
     */
    if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success)
    {
        PRINTF("WM8904_Init failed!\r\n");
        assert(false);
    }

    /* Initial volume kept low for hearing safety.
     * Adjust it to your needs, 0-100, 0 for mute, 100 for maximum volume.
     */
    if (CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight, 50U) != kStatus_Success)
    {
        assert(false);
    }
    PRINTF("Configure I2S\r\n");

    /*
     * masterSlave = kI2S_MasterSlaveNormalMaster;
     * mode = kI2S_ModeI2sClassic;
     * rightLow = false;
     * leftJust = false;
     * pdmData = false;
     * sckPol = false;
     * wsPol = false;
     * divider = 1;
     * oneChannel = false;
     * dataLength = 16;
     * frameLength = 32;
     * position = 0;
     * watermark = 4;
     * txEmptyZero = true;
     * pack48 = false;
     */
    I2S_TxGetDefaultConfig(&s_TxConfig);
    s_TxConfig.divider     = DEMO_I2S_CLOCK_DIVIDER;
    s_TxConfig.masterSlave = DEMO_I2S_TX_MODE;
    I2S_TxInit(DEMO_I2S_TX, &s_TxConfig);

    StartSoundPlayback();   
    while (true)
    {
        play();
    }
    return 0;
}
  • SD卡简介

      很多单片机系统都需要大容量存储设备,以存储数据。目前常用的有U盘,FLASH芯片,SD卡等。他们各有优点,综合比较,最适合单片机系统的莫过于SD卡了,它不仅容量可以做到很大(32GB以上),支持SPI/SDIO驱动,而且有多种体积的尺寸可供选择(标准的SD卡尺寸,以及TF卡尺寸等),能满足不同应用的要求。

      只需要少数几个IO口即可外扩一个高达32GB以上的外部存储器,容量从几十M到几十G选择尺度很大,更换也很方便,编程也简单,是单片机大容量外部存储器的首选。

FvwpSZkfLyU2JSFdXuAXv5Vmy2zI

  • FATFS简介

      FATFS是一个完全免费开源的FAT文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C语言编写,所以具有良好的硬件平台独立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列单片机上而只需做简单的修改。它支持FATl2、FATl6和FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位

      FATFS的特点有:Windows兼容的FAT文件系统、移植简单(与开发平台无关)、代码量少,效率高、多种配置选项(1.支持多卷2.支持长文件名3.支持多种扇区大小等)

  • WAV简介

      WAV即WAVE文件,WAV是计算机领域最常用的数字化声音文件格式之一,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav"。它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT A LAW 等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几!

Fukj764c7U5u7cTzR1C4yox96yRs

  • WM8904简介

      Cirrus Logic的WM8904是一款高性能、超低功耗立体声编解码器,采用立体声接地参考耳机放大器,且这种放大器采用双模式电荷泵架构,以优化回放过程中的效率和功耗。以地为参考的耳机和线路输出消除了交流耦合电容器,两个输出都通过共模反馈路径来抑制接地噪声。音频路径设置的控制序列可以由集成控制写序列器预加载并执行,以减少软件驱动程序的开发工作,尽可能降低爆裂和咔哒声。模拟输入级可配置为单端或差分输入。最多可连接三个立体声麦克风或线路输入。

FhVCBPrVTb7_TjFTuqfezwtCXYo7

  • I2S简介

      I2S(Inter IC Sound)总线,又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专责于音频设备之间的数据传输,广泛应用于各种多媒体系统。

  • MP3格式转WAV格式

在线转换音频网址:

https://www.aconvert.com/cn/audio/mp3-to-wav/#

FuqnekItEPOlv9b0saXg1d6ILjw2

FuxCgE9uFJ73M_porOBqqoYUc5RG

  • 心的体会

第一次参加Funpack11的活动,在平时的实验项目中接触最多的就是STM32,因为使用过STM32CubeIDE和STM32CubeMX这两个软件,所以对于NXP的这两款软件:MCUXpresso IDE和MCUXpresso Config Tools上手就快很多,在体验之后发现,这两款软件的配置功能比意法半导体的要多,流畅度更好。第一次上手NXP的开发板,不太会使用,找了好久的资料,大部分又是英文(英语小白),只能是一点一点学。遇到的问题就是当初打算播放MP3音频文件,不知道为什么MP3解码库不能放入项目工程中,加进去就报错,不知道为什么。最后还是妥协,换成WAV格式。

附件下载
sdcard_fatfs.rar
团队介绍
一个平时咸鱼的一条大学生,还是在热心网友的帮助下,参加了此次活动,可能是另一面不够咸,所以打算翻一个身,再续盐。。。
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号