Funpack11期于10月31日截止后,到現在已審核完畢,相信審核通過的小伙伴都已經收到祝賀郵件了,那就靜等返款吧。
本期的任務也是很有用意思,四選一,難度中等。這款來自NXP的強大的LPC55S69-EVK在群友們和各種開源資料的幫助下被大家玩的非常深入,輕松完成這期的幾個任務。
下面就來看看vic網友如何使用本期板卡實現音頻播放器的吧。以下項目已開源在電子森林:https://www.eetree.cn/project/detail/626,大家感興趣的可以來一起學習。
1. 實現功能說明本次使用LCP55S69-EVK開發板顯示的功能是,任務一:讀取SD卡中的音頻文件,使用板卡上的3.5mm音頻接口播放音樂。2. 功能代碼展示2.1. 主函數在主函數中主要是對需要用到的外設進行初始化,例如:USART、I2C、I2S、Codec等,最后創兩個任務分別用于完成SD卡管理以及通過USART0提供shell接口。
2.2. SD卡管理任務SD卡任務的代碼如下所示,其主要的作用是:SD在插入時會觸發中斷,最終觸發到當前任務,用于完成SD卡的掛載操作。int main(void)
{
int ret;
/* 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;
/*!< Switch PLL0 clock source selector to XTAL16M */
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);
CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 0U, true);
CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 1U, false);
/* I2S clocks */
CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM6);
CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM7);
/* Attach PLL clock to MCLK for I2S, no divider */
CLOCK_AttachClk(kPLL0_to_MCLK);
SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
SYSCON->MCLKIO = 1U;
/* reset FLEXCOMM for I2C */
RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
/* reset FLEXCOMM for DMA0 */
RESET_PeripheralReset(kDMA0_RST_SHIFT_RSTn);
/* reset FLEXCOMM for I2S */
RESET_PeripheralReset(kFC6_RST_SHIFT_RSTn);
RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
/* reset NVIC for FLEXCOMM6 and FLEXCOMM7 */
NVIC_ClearPendingIRQ(FLEXCOMM6_IRQn);
NVIC_ClearPendingIRQ(FLEXCOMM7_IRQn);
/* Enable interrupts for I2S */
EnableIRQ(FLEXCOMM6_IRQn);
EnableIRQ(FLEXCOMM7_IRQn);
/* Initialize the rest */
BOARD_InitPins();
BOARD_BootClockPLL1_150M();
BOARD_InitDebugConsole();
BOARD_InitSysctrl();
PRINTF(" ");
PRINTF("********************************** ");
PRINTF("Maestro audio solutions demo start ");
PRINTF("********************************** ");
PRINTF(" ");
ret = BOARD_CODEC_Init();
if (ret)
{
PRINTF("CODEC_Init failed ");
return -1;
}
if (xTaskCreate(APP_SDCARD_Task, "SDCard Task", SDCARD_TASK_STACK_SIZE, &app, configMAX_PRIORITIES - 4, NULL) !=
pdPASS)
{
PRINTF(" Failed to create application task ");
while (1)
;
}
/* Set shell command task priority = 1 */
if (xTaskCreate(APP_Shell_Task, "Shell Task", SHELL_TASK_STACK_SIZE, &app, configMAX_PRIORITIES - 5,
&app.shell_task_handle) != pdPASS)
{
PRINTF(" Failed to create application task ");
while (1)
;
}
/* Run RTOS */
vTaskStartScheduler();
/* Should not reach this statement */
return 0;
}
2.3. shell任務shell任務的主要目的通過USART0(與Link2的虛擬串口鏈接),為用戶提供一個可以控制播放器的操作接口,主要處理函數如下所示:void APP_SDCARD_Task(void *param)
{
const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
FRESULT error;
app_handle_t *app = (app_handle_t *)param;
app->sdcardSem = xSemaphoreCreateBinary();
BOARD_SD_Config(&g_sd, APP_SDCARD_DetectCallBack, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, app);
PRINTF("[APP_SDCARD_Task] start ");
/* SD host init function */
if (SD_HostInit(&g_sd) != kStatus_Success)
{
PRINTF("[APP_SDCARD_Task] SD host init failed. ");
vTaskSuspend(NULL);
}
/* Small delay for SD card detection logic to process */
vTaskDelay(100 / portTICK_PERIOD_MS);
while (1)
{
/* Block waiting for SDcard detect interrupt */
xSemaphoreTake(app->sdcardSem, portMAX_DELAY);
if (app->sdcardInserted != app->sdcardInsertedPrev)
{
app->sdcardInsertedPrev = app->sdcardInserted;
SD_SetCardPower(&g_sd, false);
if (app->sdcardInserted)
{
/* power on the card */
SD_SetCardPower(&g_sd, true);
if (f_mount(&app->fileSystem, driverNumberBuffer, 0U))
{
PRINTF("[APP_SDCARD_Task] Mount volume failed. ");
continue;
}
#if (FF_FS_RPATH >= 2U)
error = f_chdrive((char const *)&driverNumberBuffer[0U]);
if (error)
{
PRINTF("[APP_SDCARD_Task] Change drive failed. ");
continue;
}
#endif
PRINTF("[APP_SDCARD_Task] SD card drive mounted ");
xSemaphoreGive(app->sdcardSem);
}
}
}
}
uint32_t ulTaskGenericNotifyTake( UBaseType_t uxIndexToWait,
BaseType_t xClearCountOnExit,
TickType_t xTicksToWait )
{
uint32_t ulReturn;
configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES );
taskENTER_CRITICAL();
{
/* Only block if the notification count is not already non-zero. */
if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] == 0UL )
{
/* Mark this task as waiting for a notification. */
pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION;
if( xTicksToWait > ( TickType_t ) 0 )
{
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWait );
/* All ports are written to allow a yield in a critical
* section (some will yield immediately, others wait until the
* critical section exits) - but it is not something that
* application code should ever do. */
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
taskENTER_CRITICAL();
{
traceTASK_NOTIFY_TAKE( uxIndexToWait );
ulReturn = pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ];
if( ulReturn != 0UL )
{
if( xClearCountOnExit != pdFALSE )
{
pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = 0UL;
}
else
{
pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = ulReturn - ( uint32_t ) 1;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION;
}
taskEXIT_CRITICAL();
return ulReturn;
}
2.4. codec初始化codec使用的是板載的wm8904,初始化代碼如下所示。
3. 功能配置功能配置使用的NXP提供的MCUXpresso Config Tools,各個配置項如下所示。 3.1. 管腳配置主要是對用到的USART、I2C、SDIF等外設管腳進行初始化。 3.2. 時鐘配置時鐘配置如下所示,只配置了基本的時鐘以及使用到的外設時鐘。int BOARD_CODEC_Init(void)
{
CODEC_Init(&codecHandle, &boardCodecConfig);
/* Invert the DAC data in order to output signal with correct polarity - set DACL_DATINV and DACR_DATINV = 1 */
WM8904_WriteRegister((wm8904_handle_t *)codecHandle.codecDevHandle, WM8904_AUDIO_IF_0, 0x1850);
/* Initial volume kept low for hearing safety. */
CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight, 75);
return 0;
}

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
播放器
+關注
關注
5文章
411瀏覽量
38049 -
音頻
+關注
關注
30文章
3041瀏覽量
83429
原文標題:基于LPC55S69-EVK的音頻播放器 - Funpack11項目分享一
文章出處:【微信號:xiaojiaoyafpga,微信公眾號:電子森林】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
新品|Unit AudioPlayer,支持 MP3/WAV 播放的音頻播放單元
UnitAudioPlayer是一款自帶MP3解碼功能的音頻播放單元,內置高性能音頻解碼芯片N9301,自帶microSD卡座。該產品采用UART通信接口,用戶可通過配置指令實現

Made with KiCad:Tangara 便攜式音樂播放器
不同,Tangara 還配備了全彩顯示屏、內置電池以及單手觸控交互界面,為開發者提供更完整的硬件支持。
現代技術加持的高品質音頻體驗
Tangara 首先是一款音頻播放器,其核心功能設計均圍繞這一本質展開
發表于 04-16 14:01
圣邦微電子SGM56101Q 車規級110dB、192kHz、32 位、8 通道音頻數模轉換器
圣邦微電子推出 SGM56101Q,一款車規級 110dB、192kHz、32 位、8 通道音頻數模轉換器。 該器件可應用于汽車音響系統、CD 播放器、耳機、網絡音頻播放器、RCA 接

海貝HiBy R1播放器體驗
之前分享過用接入便攜耳放來提升音質,讓手機端也能享受HiFi級的聽感體驗。這個方案對于沒有數碼播放器的初燒用戶來說,確實是種非常高效的方法。 但缺點也是有的,比如歌曲存放需要占用手機存儲空間,手機

畢業設計競賽選題推薦 | 嵌入式Linux應用之音樂播放器項目實戰(含文檔及源碼)
01引言隨著數字化娛樂日益普及,音樂播放器作為人們生活中不可或缺的一部分,扮演著重要的角色。無論是通勤途中、健身鍛煉還是工作學習,一個好用的音樂播放器都能為用戶提供愉悅的音頻體驗,豐富生活的同時也

海貝R1便攜音樂播放器開箱
作為一個愛聽音樂打發時間的玩家,我已經習慣隨身攜帶一款小巧輕便的音樂播放器,從早期的CD播放器到現在的數碼播放器,它總能在不經意間中給我帶來簡單的快樂。不管是逛街等人的時候,還是工作壓力大的時候

如何在音頻播放時插播音頻
ZDP14x0系列芯片是內置開源GUI引擎的圖像顯示專用驅動芯片,內部集成16MB/64MB顯示內存、2D圖形加速器、音視頻解碼器等豐富多媒體功能。不僅支持音視頻播放,還支持在音視頻播放

藍牙耳機項目用到功放TPA6112A2,打開音頻播放器從點擊到音頻播出大概有3秒的延時,為什么?
藍牙耳機項目用到功放TPA6112A2,但是在使用中遇到問題:
1.藍牙連接手機,打開音頻播放器,點擊開始,但是從點擊到音頻播出大概有3秒的延時!
音頻輸出為CSR BC5
請問
發表于 10-24 06:20
變速播放器1和2的區別
的區別。 變速播放器通常允許用戶調整播放速度,以適應不同的觀看或學習需求。這類播放器可能具備以下功能: 變速播放 :用戶可以根據需要加快或減慢播放
為什么好的播放器還要配解碼器
好的播放器之所以需要配備解碼器,是因為音頻和視頻文件的編碼和解碼是一個復雜的過程,涉及到多種技術和標準。解碼器的作用是將壓縮的音頻和視頻數據
【飛凌嵌入式OK527N-C開發板體驗】3.鼠標+硬件編解碼+音頻播放器
有偶而的報錯,且運行一段時間 會有明顯卡頓,懷疑是加載一段,解碼一段。
測試音頻播放,啟動后可以 顯示 出播放器畫面,但我沒鼠標無法播放,但神奇的地方是我這個屏幕有觸摸,點按時會導致
發表于 07-25 23:47
評論