精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何從SD卡讀取音頻文件并將其輸出到揚(yáng)聲器上?

OpenFPGA ? 來(lái)源:OpenFPGA ? 2024-01-22 09:23 ? 次閱讀

開篇第一步

在上一篇教程中,創(chuàng)建了一個(gè) I2S 發(fā)送器用來(lái)發(fā)送來(lái)從FPGA內(nèi)部 ROM音頻數(shù)據(jù)。下一步,我們向該 I2S 發(fā)送器添加 AXI-Stream 接口,這樣我們就可以將發(fā)送器與 ZYNQ 的處理系統(tǒng)連接,還可以從 SD 卡讀取音頻數(shù)據(jù)。

為此,創(chuàng)建一個(gè)新的top設(shè)計(jì)。本設(shè)計(jì)應(yīng)具有以下接口:

501d60ec-b8c4-11ee-8b88-92fbcf53809c.png

該塊設(shè)計(jì)產(chǎn)生以下代碼:

entityAXIS_I2Sis
Generic(RATIO:INTEGER:=8;
WIDTH:INTEGER:=16
);
Port(MCLK:inSTD_LOGIC;
nReset:inSTD_LOGIC;
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC;
ACLK:inSTD_LOGIC;
ARESETn:inSTD_LOGIC;
TDATA_RXD:inSTD_LOGIC_VECTOR(31downto0);
TREADY_RXD:outSTD_LOGIC;
TVALID_RXD:inSTD_LOGIC
);
endAXIS_I2S;

SCLK與MCKL的比率通過(guò)RATIO參數(shù)定義,每個(gè)通道的數(shù)據(jù)字寬度通過(guò)WIDTH參數(shù)定義。

PS:此實(shí)現(xiàn)僅支持每個(gè)通道 16 位數(shù)據(jù)字(即立體聲 32 位)。

?設(shè)計(jì)中必須實(shí)現(xiàn)以下組件:

用于為 I2S 發(fā)送器創(chuàng)建輸入時(shí)鐘的時(shí)鐘預(yù)分頻器

AXI-Stream 從接口

I2S發(fā)送器的控制邏輯?

為分頻器創(chuàng)建了一個(gè)過(guò)程,該過(guò)程在MCLK時(shí)鐘上升沿對(duì)計(jì)數(shù)器進(jìn)行計(jì)數(shù),并在半個(gè)周期后切換信號(hào)SCLK_Int。

process
variableCounter:INTEGER:=0;
begin
waituntilrising_edge(MCLK);
if(Counter

下一步是實(shí)現(xiàn) AXI-Stream 接口。為此使用狀態(tài)機(jī):

process
begin
waituntilrising_edge(ACLK);
caseCurrentStateis
whenState_Reset=>
Tx_AXI<=?(others?=>'0');
CurrentState<=?State_WaitForTransmitterReady;

????????when?State_WaitForTransmitterReady?=>
if(Ready_AXI='1')then
TREADY_RXD<=?'1';
????????????????CurrentState?<=?State_WaitForValid;
????????????else
????????????????TREADY_RXD?<=?'0';
????????????????CurrentState?<=?State_WaitForTransmitterReady;
????????????end?if;
????????when?State_WaitForValid?=>
if(TVALID_RXD='1')then
TREADY_RXD<=?'0';
????????????????Tx_AXI?<=?TDATA_RXD;
????????????????CurrentState?<=?State_WaitForTransmitterBusy;
????????????else
????????????????TREADY_RXD?<=?'1';
????????????????CurrentState?<=?State_WaitForValid;
????????????end?if;
????????when?State_WaitForTransmitterBusy?=>
if(Ready_AXI='0')then
CurrentState<=?State_WaitForTransmitterReady;
????????????else
????????????????CurrentState?<=?State_WaitForTransmitterBusy;
????????????end?if;
????end?case;
????if(ARESETn?=?'0')?then
????????????CurrentState?<=?State_Reset;
????end?if;
end?process;

復(fù)位后,機(jī)器從State_Reset狀態(tài)變?yōu)镾tate_WaitForTransmitter等待I2S 發(fā)送器發(fā)出就緒Ready信號(hào)的狀態(tài)。一旦發(fā)送器準(zhǔn)備好,TREADY_RXD就會(huì)設(shè)置 AXI-Stream 接口的信號(hào),通知主機(jī)從機(jī)已準(zhǔn)備好接收數(shù)據(jù)。然后從機(jī)改變?yōu)镾tate_WaitForValid狀態(tài)。

?在此狀態(tài)下,從機(jī)等待主機(jī)置位信號(hào)TVALID_RXD標(biāo)記有效數(shù)據(jù)。一旦置位了信號(hào),數(shù)據(jù)就會(huì)寫入內(nèi)部 FIFO。然后機(jī)器改變到State_WaitForTransmitterBusy狀態(tài)。

?現(xiàn)在狀態(tài)機(jī)等待I2S發(fā)送器開始發(fā)送數(shù)據(jù)并“刪除”就緒信號(hào)。一旦完成,狀態(tài)機(jī)就會(huì)切換回State_WaitForTransmitterReady狀態(tài)并再次等待,直到 I2S 發(fā)送器準(zhǔn)備就緒。

?這樣,理論上 AXI-Stream 接口就完成了。不幸的是,最后變得有點(diǎn)棘手,因?yàn)楫?dāng)前的電路設(shè)計(jì)使用兩個(gè)不同的時(shí)鐘域:

ACLK的時(shí)鐘域

MCLK的時(shí)鐘域

一般來(lái)說(shuō),這兩個(gè)時(shí)鐘信號(hào)不能從時(shí)鐘源生成(例如通過(guò)時(shí)鐘分頻器),因?yàn)?AXI 接口通常以 100 MHz 運(yùn)行,而音頻接口需要可以整齊地分頻至采樣頻率的時(shí)鐘速率,例如 12.288 MHz。因此,由于最差負(fù)裕量 (WNS) 和總負(fù)裕量 (TNS) 過(guò)多,在實(shí)現(xiàn)過(guò)程中會(huì)出現(xiàn)時(shí)序錯(cuò)誤:

502e470e-b8c4-11ee-8b88-92fbcf53809c.png

此外,由于觸發(fā)器在不同時(shí)鐘域中發(fā)生亞穩(wěn)態(tài)而導(dǎo)致數(shù)據(jù)不正確的風(fēng)險(xiǎn)非常高。

因此,各個(gè)時(shí)鐘域所使用的信號(hào)必須在每種情況下經(jīng)由相應(yīng)的電路傳送到另一時(shí)鐘域。Xilinx 在文檔UG953(https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_3/ug953-vivado-7series-libraries.pdf)中描述了可用于此目的的相應(yīng)宏。

xpm_cdc_gray - 該功能塊使用格雷碼將數(shù)據(jù)總線從一個(gè)時(shí)鐘域 (src) 傳輸?shù)搅硪粋€(gè)時(shí)鐘域 (dest)。

xpm_cdc_single - 將單個(gè)信號(hào)從一個(gè)時(shí)鐘域 (src) 轉(zhuǎn)換到另一個(gè)時(shí)鐘域 (dest)。

宏的示例可以直接用于 VHDL 代碼:

xpm_cdc_Data:xpm_cdc_handshakegenericmap(DEST_EXT_HSK=>0,
DEST_SYNC_FF=>4,
INIT_SYNC_FF=>0,
SIM_ASSERT_CHK=>0,
SRC_SYNC_FF=>4,
WIDTH=>(2*WIDTH)
)
portmap(src_clk=>ACLK,
src_in=>Data_Fast,
dest_clk=>MCLK,
dest_out=>Data_Slow,
dest_ack=>'0',
src_send=>src_send,
src_rcv=>src_rcv,
dest_req=>dest_req
);

xpm_cdc_Ready:xpm_cdc_singlegenericmap(DEST_SYNC_FF=>4,
SRC_INPUT_REG=>1
)
portmap(src_clk=>MCLK,
src_in=>Ready_Transmitter,
dest_clk=>ACLK,
dest_out=>Ready_AXI
);

最后,必須插入 I2S 發(fā)送器并傳遞生成的信號(hào)。

Transmitter:I2S_Transmittergenericmap(WIDTH=>WIDTH
)
portmap(Clock=>SCLK_Int,
nReset=>nReset,
Ready=>Ready_Transmitter,
Tx=>Tx_Transmitter,
LRCLK=>LRCLK,
SCLK=>SCLK,
SD=>SD
);

I2S 發(fā)送器的 AXI-Stream 接口現(xiàn)已準(zhǔn)備就緒并可供使用。完整的代碼如下所示:

libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
libraryxpm;
usexpm.vcomponents.all;

entityAXIS_I2Sis
Generic(RATIO:INTEGER:=8;
WIDTH:INTEGER:=16
);
Port(MCLK:inSTD_LOGIC;
nReset:inSTD_LOGIC;
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC;
ACLK:inSTD_LOGIC;
ARESETn:inSTD_LOGIC;
TDATA_RXD:inSTD_LOGIC_VECTOR(31downto0);
TREADY_RXD:outSTD_LOGIC;
TVALID_RXD:inSTD_LOGIC
);
endAXIS_I2S;

architectureAXIS_I2S_ArchofAXIS_I2Sis
typeAXIS_State_tis(State_Reset,State_WaitForTransmitterReady,State_WaitForValid,State_WaitForTransmitterBusy);
signalCurrentState:AXIS_State_t:=State_Reset;
signalTx_AXI:STD_LOGIC_VECTOR(((2*WIDTH)-1)downto0):=(others=>'0');
signalReady_AXI:STD_LOGIC;
signalTx_Transmitter:STD_LOGIC_VECTOR(((2*WIDTH)-1)downto0):=(others=>'0');
signalReady_Transmitter:STD_LOGIC;
signalSCLK_Int:STD_LOGIC:='0';
componentI2S_Transmitteris
Generic(WIDTH:INTEGER:=16
);
Port(Clock:inSTD_LOGIC;
nReset:inSTD_LOGIC;
Ready:outSTD_LOGIC;
Tx:inSTD_LOGIC_VECTOR(((2*WIDTH)-1)downto0);
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC
);
endcomponent;

begin

Transmitter:I2S_Transmittergenericmap(WIDTH=>WIDTH
)
portmap(Clock=>SCLK_Int,
nReset=>nReset,
Ready=>Ready_Transmitter,
Tx=>Tx_Transmitter,
LRCLK=>LRCLK,
SCLK=>SCLK,
SD=>SD
);
xpm_cdc_Data:xpm_cdc_graygenericmap(DEST_SYNC_FF=>4,
SIM_ASSERT_CHK=>0,
SIM_LOSSLESS_GRAY_CHK=>0,
WIDTH=>(2*WIDTH)
)
portmap(src_clk=>ACLK,
src_in_bin=>Tx_AXI,
dest_clk=>MCLK,
dest_out_bin=>Tx_Transmitter
);
xpm_cdc_Ready:xpm_cdc_singlegenericmap(DEST_SYNC_FF=>4,
SRC_INPUT_REG=>1
)
portmap(src_clk=>MCLK,
src_in=>Ready_Transmitter,
dest_clk=>ACLK,
dest_out=>Ready_AXI
);
process
variableCounter:INTEGER:=0;
begin
waituntilrising_edge(MCLK);
if(Counter
Tx_AXI<=?(others?=>'0');
CurrentState<=?State_WaitForTransmitterReady;
????????????when?State_WaitForTransmitterReady?=>
if(Ready_AXI='1')then
TREADY_RXD<=?'1';
????????????????????CurrentState?<=?State_WaitForValid;
????????????????else
????????????????????TREADY_RXD?<=?'0';
????????????????????CurrentState?<=?State_WaitForTransmitterReady;
????????????????end?if;
????????????when?State_WaitForValid?=>
if(TVALID_RXD='1')then
TREADY_RXD<=?'0';
????????????????????Tx_AXI?<=?TDATA_RXD;
????????????????????CurrentState?<=?State_WaitForTransmitterBusy;
????????????????else
????????????????????TREADY_RXD?<=?'1';
????????????????????CurrentState?<=?State_WaitForValid;
????????????????end?if;
????????????when?State_WaitForTransmitterBusy?=>
if(Ready_AXI='0')then
CurrentState<=?State_WaitForTransmitterReady;
????????????????else
????????????????????CurrentState?<=?State_WaitForTransmitterBusy;
????????????????end?if;
????????end?case;
????????if(ARESETn?=?'0')?then
????????????CurrentState?<=?State_Reset;
????????end?if;
????end?process;
end?AXIS_I2S_Arch;

接下來(lái),我們希望使用該接口從 SD 卡讀取波形文件,并使用 CS4344 D/A 轉(zhuǎn)換器通過(guò)連接的揚(yáng)聲器輸出音樂(lè)。

該項(xiàng)目需要以下IP核:

具有 AXI-Stream 接口的 I2S 發(fā)送器

處理系統(tǒng)從 SD 卡讀取數(shù)據(jù)并將其寫入 FIFO

AXI-Stream FIFO

用于生成音頻時(shí)鐘的PLL

5038a082-b8c4-11ee-8b88-92fbcf53809c.png

時(shí)鐘向?qū)蓵r(shí)鐘,然后將其用作 CS4344 的主時(shí)鐘。輸出時(shí)鐘可以通過(guò) AXI-Lite 接口適應(yīng)音頻文件的采樣率。

5049e2b6-b8c4-11ee-8b88-92fbcf53809c.png

AXI-Stream FIFO 充當(dāng)處理系統(tǒng)和 I2S 發(fā)送器之間的鏈接。處理系統(tǒng)通過(guò) AXI-Lite(或 AXI)接口將數(shù)據(jù)寫入 FIFO,然后將數(shù)據(jù)傳輸至 I2S 發(fā)送器。

505b26d4-b8c4-11ee-8b88-92fbcf53809c.png

根據(jù)設(shè)計(jì)創(chuàng)建比特流,然后可以開發(fā)軟件。

讀取 SD 卡需要 Xilinx 的 xilffs FAT 庫(kù),該庫(kù)必須集成到 Vitis 項(xiàng)目的板級(jí)支持包中(不要忘記啟用LFN支持大文件名的選項(xiàng)):

506eb532-b8c4-11ee-8b88-92fbcf53809c.png

第一步,軟件使用該AudioPlayer_Init函數(shù)初始化音頻播放器,從而初始化 FIFO、GIC 和中斷處理程序,以及時(shí)鐘向?qū)Ш?SD 卡。

u32AudioPlayer_Init(void)
{
xil_printf("[INFO]LookingforFIFOconfiguration...
");
_Fifo_ConfigPtr=XLlFfio_LookupConfig(XPAR_FIFO_DEVICE_ID);
if(_Fifo_ConfigPtr==NULL)
{
xil_printf("[ERROR]InvalidFIFOconfiguration!
");
returnXST_FAILURE;
}

xil_printf("[INFO]InitializeFIFO...
");
if(XLlFifo_CfgInitialize(&_Fifo,_Fifo_ConfigPtr,_Fifo_ConfigPtr->BaseAddress)!=XST_SUCCESS)
{
xil_printf("[ERROR]FIFOinitializationfailed!

");
returnXST_FAILURE;
}

xil_printf("[INFO]LookingforGICconfiguration...
");
_GIC_ConfigPtr=XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
if(_GIC_ConfigPtr==NULL)
{
xil_printf("[ERROR]InvalidGICconfiguration!

");
returnXST_FAILURE;
}

xil_printf("[INFO]InitializeGIC...
");
if(XScuGic_CfgInitialize(&_GIC,_GIC_ConfigPtr,_GIC_ConfigPtr->CpuBaseAddress)!=XST_SUCCESS)
{
xil_printf("[ERROR]GICinitializationfailed!

");
returnXST_FAILURE;
}

xil_printf("[INFO]Setupinterrupthandler...
");
XScuGic_SetPriorityTriggerType(&_GIC,XPAR_FABRIC_FIFO_INTERRUPT_INTR,0xA0,0x03);
if(XScuGic_Connect(&_GIC,XPAR_FABRIC_FIFO_INTERRUPT_INTR,(Xil_ExceptionHandler)AudioPlayer_FifoHandler,&_Fifo)!=XST_SUCCESS)
{
xil_printf("[ERROR]Cannotconnectinterrupthandler!

");
returnXST_FAILURE;
}
XScuGic_Enable(&_GIC,XPAR_FABRIC_FIFO_INTERRUPT_INTR);

xil_printf("[INFO]Enableexceptions...
");
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&_GIC);
Xil_ExceptionEnable();

xil_printf("[INFO]EnableFIFOinterrupts...
");
XLlFifo_IntClear(&_Fifo,XLLF_INT_ALL_MASK);

xil_printf("[INFO]InitializeClockingWizard...
");
if((ClockingWizard_Init(&_ClkWiz,XPAR_CLOCKINGWIZARD_BASEADDR)||ClockingWizard_GetOutput(&_ClkWiz,&_AudioClock))!=XST_SUCCESS)
{
xil_printf("[ERROR]ClockingWizardinitializationfailed!

");
returnXST_FAILURE;
}
xil_printf("[INFO]MountSDcard...
");
if(SD_Init())
{
xil_printf("[ERROR]CannotinitializeSDcard!

");
returnXST_FAILURE;
}

returnXST_SUCCESS;
}

一旦初始化完成,就會(huì)調(diào)用AudioPlayer_LoadFile函數(shù)從 SD 卡加載Audio.wav文件 。

if(AudioPlayer_LoadFile("Audio.wav"))
{
xil_printf("[ERROR]CannotopenAudiofile!

");
returnXST_FAILURE;
}

u32AudioPlayer_LoadFile(char*File)
{
if(SD_LoadFileFromCard(File,&_File))
{
xil_printf("[ERROR]CannotopenAudiofile!

");
returnXST_FAILURE;
}

xil_printf("Filesize:%lubytes

",_File.Header.ChunkSize+8);
xil_printf("Fileformat:%lu

",_File.Format.AudioFormat);
xil_printf("Channels:%lu

",_File.Format.NumChannels);
xil_printf("Samplerate:%luHz

",_File.Format.SampleRate);
xil_printf("Bitspersample:%lubits

",_File.Format.BitsPerSample);
xil_printf("Blockalign:%lubytes

",_File.Format.BlockAlign);
xil_printf("Databytes:%lubytes

",_File.Header.ChunkSize/_File.Format.NumChannels);
xil_printf("Samples:%lu

",8*_File.Header.ChunkSize/_File.Format.NumChannels/_File.Format.BitsPerSample);

if((_File.Format.BitsPerSample!=16)||(_File.Format.NumChannels>2))
{
xil_printf("[ERROR]Invalidfileformat!

");
returnXST_FAILURE;
}
AudioPlayer_ChangeFreq(_File.Format.SampleRate);

XLlFifo_TxReset(&_Fifo);
XLlFifo_IntEnable(&_Fifo,XLLF_INT_ALL_MASK);
SD_CopyDataIntoBuffer(_FifoBuffer,256);
AudioPlayer_CopyBuffer();

returnXST_SUCCESS;
}
該函數(shù)AudioPlayer_LoadFile調(diào)用函數(shù)SD_LoadFileFromCard從SD卡加載波形文件。

u32SD_LoadFileFromCard(constchar*FileName,Wave_t*File)
{
xil_printf("[INFO]Openingfile:%s...

",FileName);

if(f_open(&_FileHandle,FileName,FA_READ))
{
xil_printf("[ERROR]Cannotopenaudiofile!

");
returnXST_FAILURE;
}

if(f_read(&_FileHandle,&File->RIFF,sizeof(Wave_RIFF_t),&_BytesRead)||f_read(&_FileHandle,&File->Format,sizeof(Wave_Format_t),&_BytesRead))
{
xil_printf("[ERROR]CannotreadSDcard!

");
returnXST_FAILURE;
}

Wave_Header_tHeader;
uint32_tOffset=sizeof(Wave_RIFF_t)+sizeof(Wave_Format_t);
if(f_read(&_FileHandle,Header.ChunkID,sizeof(Wave_Header_t),&_BytesRead)||f_lseek(&_FileHandle,Offset))
{
xil_printf("[ERROR]CannotreadSDcard!

");
returnXST_FAILURE;
}

if(strncmp("LIST",Header.ChunkID,4)==0)
{
Offset+=Header.ChunkSize+sizeof(Wave_Header_t);
if(f_read(&_FileHandle,&File->ListHeader,sizeof(Wave_Header_t),&_BytesRead)||f_lseek(&_FileHandle,Offset))
{
xil_printf("[ERROR]CannotplaceSDcardpointer!

");
returnXST_FAILURE;
}
}

if(f_read(&_FileHandle,&File->DataHeader,sizeof(Wave_Header_t),&_BytesRead))
{
xil_printf("[ERROR]CannotreadSDcard!

");
returnXST_FAILURE;
}

if(File->Format.AudioFormat!=WAVE_FORMAT_PCM)
{
xil_printf("[ERROR]Audioformatnotsupported!KeepsurethatthefileusethePCMformat!

");
returnXST_FAILURE;
}

_RemainingBytes=File->DataHeader.ChunkSize;

_IsBusy=true;

returnXST_SUCCESS;
}
在下一步中,根據(jù)使用的采樣頻率從波形文件中設(shè)置時(shí)鐘向?qū)У妮敵鲱l率:

staticvoidAudioPlayer_ChangeFreq(constu32SampleRate)
{
if(SampleRate==44100)
{
xil_printf("Useclocksetting1...

");
_ClkWiz.DIVCLK_DIVIDE=5;
_ClkWiz.CLKFBOUT_MULT=42;
_ClkWiz.CLKFBOUT_Frac_Multiply=0;
_AudioClock.DIVIDE=93;
_AudioClock.FRAC_Divide=0;
}
elseif(SampleRate==48000)
{
xil_printf("Useclocksetting2...

");
_ClkWiz.DIVCLK_DIVIDE=3;
_ClkWiz.CLKFBOUT_MULT=23;
_ClkWiz.CLKFBOUT_Frac_Multiply=0;
_AudioClock.DIVIDE=78;
_AudioClock.FRAC_Divide=0;
}
elseif(SampleRate==96000)
{
xil_printf("Useclocksetting3...

");
_ClkWiz.DIVCLK_DIVIDE=3;
_ClkWiz.CLKFBOUT_MULT=23;
_ClkWiz.CLKFBOUT_Frac_Multiply=0;
_AudioClock.DIVIDE=39;
_AudioClock.FRAC_Divide=0;
}

ClockingWizard_SetClockBuffer(&_ClkWiz);
ClockingWizard_SetOutput(&_ClkWiz,&_AudioClock);
}

加載音頻文件并且調(diào)整時(shí)鐘向?qū)У妮敵鲱l率后,將從波形文件中讀取第一個(gè)數(shù)據(jù)塊并將其復(fù)制到 FIFO:

u32SD_CopyDataIntoBuffer(u8*Buffer,constu32Length)
{
if(_RemainingBytes>=Length)
{
if(f_read(&_FileHandle,Buffer,Length,&_BytesRead))
{
returnXST_FAILURE;
}

_RemainingBytes-=_BytesRead;
}
else
{
if(f_read(&_FileHandle,Buffer,_RemainingBytes,&_BytesRead))
{
returnXST_FAILURE;
}

if(f_close(&_FileHandle))
{
xil_printf("[ERROR]Cannotcloseaudiofile!

");
returnXST_FAILURE;
}

_IsBusy=false;
}

returnXST_SUCCESS;
}

程序流程的其余部分在 FIFO 的回調(diào)中進(jìn)行:

staticvoidAudioPlayer_FifoHandler(void*CallbackRef)
{
XLlFifo*InstancePtr=(XLlFifo*)CallbackRef;

u32Pending=XLlFifo_IntPending(InstancePtr);
while(Pending)
{
if(Pending&XLLF_INT_TC_MASK)
{
SD_CopyDataIntoBuffer(_FifoBuffer,AUDIOPLAYER_FIFO_BUFFER_SIZE);

XLlFifo_IntClear(InstancePtr,XLLF_INT_TC_MASK);
}
elseif(Pending&XLLF_INT_TFPE_MASK)
{
AudioPlayer_CopyBuffer();
if(!SD_IsBusy())
{
XLlFifo_IntDisable(&_Fifo,XLLF_INT_ALL_MASK);
}

XLlFifo_IntClear(InstancePtr,XLLF_INT_TFPE_MASK);
}
elseif(Pending&XLLF_INT_ERROR_MASK)
{
xil_printf("Error:%lu!

",Pending);
XLlFifo_IntClear(InstancePtr,XLLF_INT_ERROR_MASK);
}
else
{
XLlFifo_IntClear(InstancePtr,Pending);
}

Pending=XLlFifo_IntPending(InstancePtr);
}
}

一旦 FIFO 觸發(fā)TFPE中斷(發(fā)送 FIFO 可編程空),F(xiàn)IFO 就會(huì)被來(lái)自內(nèi)部緩沖區(qū)的新數(shù)據(jù)填充。當(dāng)從處理系統(tǒng)到 FIFO 的傳輸完成時(shí),會(huì)觸發(fā)TC中斷(傳輸完成),并從 SD 卡讀取下一個(gè)數(shù)據(jù)塊。之后重復(fù)進(jìn)行上面步驟,直到文件完全播放。

staticvoidAudioPlayer_CopyBuffer(void)
{
u32Bytes=0x00;
for(u32i=0x00;i

現(xiàn)在需要一個(gè)波形文件。簡(jiǎn)單的測(cè)試信號(hào)可以wavtones.com上生成(https://www.wavtones.com/functiongenerator.php)。

然后,只需將相應(yīng)的文件以Audio.wav名稱復(fù)制到 SD 卡上,即可開始使用。

-----------I2SAudioplayer-----------

[INFO]LookingforFIFOconfiguration...
[INFO]InitializeFIFO...
[INFO]LookingforGICconfiguration...
[INFO]InitializeGIC...
[INFO]Setupinterrupthandler...
[INFO]Enableexceptions...
[INFO]EnableFIFOinterrupts...
[INFO]InitializeClockingWizard...
[INFO]MountSDcard...
[INFO]Openingfile:Single.wav...
Filesize:264610bytes
Fileformat:1
Channels:1
Samplerate:48000Hz
Bitspersample:16bits
Databytes:264602bytes
Samples:132301
Useclocksetting2...
[INFO]Finished!

或者使用立體聲音頻:

508ecf98-b8c4-11ee-8b88-92fbcf53809c.png

-----------I2SAudioplayer-----------

[INFO]LookingforFIFOconfiguration...
[INFO]InitializeFIFO...
[INFO]LookingforGICconfiguration...
[INFO]InitializeGIC...
[INFO]Setupinterrupthandler...
[INFO]Enableexceptions...
[INFO]EnableFIFOinterrupts...
[INFO]InitializeClockingWizard...
[INFO]MountSDcard...
[INFO]Openingfile:Dual.wav...
Filesize:529208bytes
Fileformat:1
Channels:2
Samplerate:44100Hz
Bitspersample:16bits
Blockalign:4bytes
Databytes:264600bytes
Samples:132300
Useclocksetting1...
[INFO]Finished!
50abb266-b8c4-11ee-8b88-92fbcf53809c.png






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 音頻
    +關(guān)注

    關(guān)注

    29

    文章

    2833

    瀏覽量

    81346
  • 揚(yáng)聲器
    +關(guān)注

    關(guān)注

    29

    文章

    1289

    瀏覽量

    62897
  • SD卡
    +關(guān)注

    關(guān)注

    2

    文章

    559

    瀏覽量

    63798
  • 分頻器
    +關(guān)注

    關(guān)注

    43

    文章

    447

    瀏覽量

    49810
  • fifo
    +關(guān)注

    關(guān)注

    3

    文章

    387

    瀏覽量

    43547
  • 發(fā)送器
    +關(guān)注

    關(guān)注

    1

    文章

    258

    瀏覽量

    26795
  • 時(shí)鐘信號(hào)
    +關(guān)注

    關(guān)注

    4

    文章

    445

    瀏覽量

    28506

原文標(biāo)題:使用 FPGA 播放 SD 卡中的音頻文件

文章出處:【微信號(hào):Open_FPGA,微信公眾號(hào):OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    用stm32f103vet6讀取SD中的音頻文件遇到的疑問(wèn)求解

    各位大佬,請(qǐng)求援助啊。。 最近在做一個(gè)MP3播放,大概做法就是stm32f103vet6讀取SD中的音頻文件,然后在傳入VS1053b
    發(fā)表于 04-23 06:48

    5509A播放音頻文件感覺(jué)全是雜音

    我將音頻文件放到SD中,用DSP5509A將其讀取出來(lái),并發(fā)送給AIC23,但是播放出來(lái)的音樂(lè)感覺(jué)全是雜音,請(qǐng)問(wèn)是對(duì)AIC23的配置不對(duì)嗎
    發(fā)表于 02-12 11:41

    Spat Revolution沉浸式音頻引擎中的自定義揚(yáng)聲器配置

    創(chuàng)建新配置。圖1:揚(yáng)聲器配置窗口顯示預(yù)定義的13.1 Auro 3D揚(yáng)聲器布置管理揚(yáng)聲器配置包括刪除配置,重命名配置,將配置導(dǎo)出到文件
    發(fā)表于 09-21 13:09

    【項(xiàng)目分享】教你用Arduino、Micro SD制作一個(gè)簡(jiǎn)單的音樂(lè)播放

    如何與Arduino結(jié)合我們剛才提到過(guò),這個(gè)Arduino音樂(lè)播放的重要組成成分是SD模塊。音頻文件會(huì)存儲(chǔ)在SD
    發(fā)表于 09-27 17:20

    怎么設(shè)置wavedac參考SD讀取?

    大家好。我想從SD讀取波形聲音放了wavevdac8連接揚(yáng)聲器。我的第一個(gè)問(wèn)題是可能的嗎?2-secound問(wèn)題我不知道怎么設(shè)置wavedac參考
    發(fā)表于 11-04 09:27

    基于MM32F5270開發(fā)板SD讀取音頻文件和界面的設(shè)計(jì)實(shí)現(xiàn)

    1、基于MM32F5270開發(fā)板SD讀取音頻文件和界面的設(shè)計(jì)目前實(shí)現(xiàn)功能如下:實(shí)現(xiàn)從SD
    發(fā)表于 08-29 14:40

    如何利用更高阻抗的揚(yáng)聲器提高汽車音頻質(zhì)量

    需要設(shè)計(jì)汽車外部放大器,可以通過(guò)增加輸出功率、利用更高阻抗的揚(yáng)聲器以及在系統(tǒng)中實(shí)施H類控制來(lái)升級(jí)音頻系統(tǒng)架構(gòu),從而增強(qiáng)用戶體驗(yàn)。本文將詳細(xì)介紹每種方法,包括這些方法對(duì)音頻系統(tǒng)重量和性能
    發(fā)表于 11-03 08:27

    如何本地WLANSD男取出的主機(jī)數(shù)據(jù)?

    中它的插槽。它僅在讀寫期間為 SD 模塊供電。我希望使用 Arduino SD 模塊
    發(fā)表于 06-02 08:17

    制作便攜式揚(yáng)聲器的方法,DIY制作便攜式揚(yáng)聲器的教程

    將兩根電線連接到放大器 ic   的 vcc 5V 和接地引腳,將一個(gè)揚(yáng)聲器連接到一個(gè)通道輸出名稱 +L -L,另一個(gè)連接到 +R -R,這些是輸出到我們的揚(yáng)聲器   將輸入連接到放大
    發(fā)表于 07-31 16:18

    使用M487和NAU88L25在微小SD中解碼并播放AMR音頻文件

    應(yīng)用程序:此示例代碼使用 M487 微控制和外部音頻編碼NAU88L25在微小SD中解碼并播放AMR
    發(fā)表于 08-29 07:28

    消除揚(yáng)聲器音頻雜音的技巧

    消除揚(yáng)聲器音頻雜音的技巧音頻雜音(click and pop)是揚(yáng)聲器或耳機(jī)產(chǎn)生的不良噪聲。它是由注入揚(yáng)聲器線圈的瞬態(tài)電流脈沖引起的,該電流
    發(fā)表于 05-11 16:04 ?107次下載

    JBL揚(yáng)聲器的選擇及應(yīng)用

    JBL揚(yáng)聲器的選擇及應(yīng)用 如何選擇揚(yáng)聲器? 揚(yáng)聲器實(shí)際是一種把可范圍內(nèi)的音頻電功率信號(hào)通過(guò)換能器(
    發(fā)表于 01-14 16:15 ?7442次閱讀

    讀取SDFAT12_16_32文件系統(tǒng)

    讀取SDFAT12_16_32文件系統(tǒng)。
    發(fā)表于 05-20 16:29 ?22次下載

    基于紅牛開發(fā)板的SD讀取文件名在LCD顯示

    文檔內(nèi)容介紹了基于紅牛開發(fā)板的SD讀取文件名在LCD顯示的資料。
    發(fā)表于 09-01 17:09 ?25次下載
    基于紅牛開發(fā)板的<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀取</b><b class='flag-5'>文件</b>名在LCD<b class='flag-5'>上</b>顯示

    stm32程序升級(jí)SD讀取hex文件寫入flash

    stm32程序升級(jí)SD讀取hex文件寫入flash
    發(fā)表于 11-20 12:36 ?57次下載
    stm32程序升級(jí)<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀取</b>hex<b class='flag-5'>文件</b>寫入flash