99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

電子發(fā)燒友App

硬聲App

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

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

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>使用ZYBO從SD卡播放wav文件

使用ZYBO從SD卡播放wav文件

2023-06-15 | zip | 0.00 MB | 次下載 | 免費(fèi)

資料介紹

描述

在上一個(gè)教程中,我們創(chuàng)建了一個(gè) I2S 發(fā)送器來(lái)從內(nèi)部 ROM 輸出一些音頻數(shù)據(jù)。在下一步中,我們?yōu)檫@個(gè) I2S 發(fā)送器添加一個(gè) AXI-Stream 接口,這樣我們就可以將發(fā)送器與 ZYNQ 的處理系統(tǒng)連接起來(lái),從 SD 卡中輸出一些音頻數(shù)據(jù)。

為此,AXIS_I2S創(chuàng)建了一個(gè)名為的新頂部設(shè)計(jì)。這個(gè)設(shè)計(jì)應(yīng)該有如下界面:

pYYBAGNsXIiADptfAAA6hTKWlAI227.png
?

此塊設(shè)計(jì)產(chǎn)生以下實(shí)體:

entity AXIS_I2S is
    Generic (   RATIO   : INTEGER := 8;
                WIDTH   : INTEGER := 16
                );
    Port (  MCLK        : in STD_LOGIC;
            nReset      : in STD_LOGIC;
            LRCLK       : out STD_LOGIC;
            SCLK        : out STD_LOGIC;
            SD          : out STD_LOGIC;
            ACLK        : in STD_LOGIC;
            ARESETn     : in STD_LOGIC;
            TDATA_RXD   : in STD_LOGIC_VECTOR(31 downto 0);
            TREADY_RXD  : out STD_LOGIC;
            TVALID_RXD  : in STD_LOGIC
            );
end AXIS_I2S;

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

此實(shí)現(xiàn)僅支持每個(gè)通道 16 位數(shù)據(jù)字(即立體聲 32 位)。以下代碼必須適用于更大的總線(xiàn)寬度。

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

  • 用于為 I2S 發(fā)送器創(chuàng)建輸入時(shí)鐘的時(shí)鐘預(yù)分頻器
  • AXI-Stream 從接口
  • I2S 發(fā)送器的控制邏輯?

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

process
    variable Counter    : INTEGER := 0;
begin
    wait until rising_edge(MCLK);
    if(Counter < ((RATIO / 2) - 1)) then
        Counter := Counter + 1;
    else
        Counter := 0;
        SCLK_Int <= not SCLK_Int;
    end if;

    if(nReset = '0') then
        Counter := 0;
        SCLK_Int <= '0';
    end if;
end process;

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

process
begin
    wait until rising_edge(ACLK);
    case CurrentState is
        when State_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)?/font>State_WaitForTransmitterReady等待來(lái)自 I2S 發(fā)送器的就緒信號(hào)的狀態(tài)。一旦發(fā)送器準(zhǔn)備就緒,TREADY_RXDAXI-Stream 接口的信號(hào)就會(huì)被設(shè)置,從而通知主機(jī),從機(jī)已準(zhǔn)備好接收數(shù)據(jù)。然后從站更改為State_WaitForValid狀態(tài)。

?在這種狀態(tài)下,從機(jī)等待主機(jī)設(shè)置TVALID_RXD信號(hào)以標(biāo)記有效數(shù)據(jù)。一旦信號(hào)被設(shè)置,數(shù)據(jù)就會(huì)被寫(xiě)入內(nèi)部 FIFO。然后機(jī)器更改為State_WaitForTransmitterBusy狀態(tài)。

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

? 有了這個(gè),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。結(jié)果,由于過(guò)多的最差負(fù)松弛 (WNS) 和總負(fù)松弛 (TNS) 在實(shí)施過(guò)程中發(fā)生時(shí)序錯(cuò)誤:

poYBAGNsXIuAUbW3AABcOkpscO4430.png
?

此外,由于觸發(fā)器的亞穩(wěn)態(tài)發(fā)生在不同的時(shí)鐘域中,導(dǎo)致數(shù)據(jù)不正確的風(fēng)險(xiǎn)非常高。發(fā)生亞穩(wěn)態(tài) a. 然后當(dāng)觸發(fā)器切換并且在那一刻數(shù)據(jù)發(fā)生變化時(shí)。

因此,各個(gè)時(shí)鐘域使用的信號(hào)必須分別通過(guò)相應(yīng)的電路傳輸?shù)搅硪粋€(gè)時(shí)鐘域。Xilinx 在文檔UG953中描述了可用于此目的的相應(yīng)宏。

  • xpm_cdc_gray - 此功能塊使用格雷碼將數(shù)據(jù)總線(xiàn)從一個(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_handshake generic map ( DEST_EXT_HSK => 0,
                                               DEST_SYNC_FF => 4,
                                               INIT_SYNC_FF => 0,
                                               SIM_ASSERT_CHK => 0, 
                                               SRC_SYNC_FF => 4,
                                               WIDTH => (2 * WIDTH)
                                               )
                              port map (  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_single generic map ( DEST_SYNC_FF => 4,
                                             SRC_INPUT_REG => 1
                                             )
                                 port map (  src_clk => MCLK,
                                             src_in => Ready_Transmitter,
                                             dest_clk => ACLK,
                                             dest_out => Ready_AXI
                                             );

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

Transmitter : I2S_Transmitter generic map ( WIDTH => WIDTH
                                            )
                                  port map( 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)備就緒,可供使用。完整的代碼現(xiàn)在應(yīng)該如下所示:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library xpm;
use xpm.vcomponents.all;

entity AXIS_I2S is
    Generic (   RATIO   : INTEGER := 8;
                WIDTH   : INTEGER := 16
                );
    Port (  MCLK        : in STD_LOGIC;
            nReset      : in STD_LOGIC;
            LRCLK       : out STD_LOGIC;
            SCLK        : out STD_LOGIC;
            SD          : out STD_LOGIC;
            ACLK        : in STD_LOGIC;
            ARESETn     : in STD_LOGIC;
            TDATA_RXD   : in STD_LOGIC_VECTOR(31 downto 0);
            TREADY_RXD  : out STD_LOGIC;
            TVALID_RXD  : in STD_LOGIC
            );
end AXIS_I2S;

architecture AXIS_I2S_Arch of AXIS_I2S is
    type AXIS_State_t is (State_Reset, State_WaitForTransmitterReady, State_WaitForValid, State_WaitForTransmitterBusy);
    signal CurrentState : AXIS_State_t    := State_Reset;
    signal Tx_AXI : STD_LOGIC_VECTOR(((2 * WIDTH) - 1) downto 0) := (others => '0');
    signal Ready_AXI : STD_LOGIC;
    signal Tx_Transmitter : STD_LOGIC_VECTOR(((2 * WIDTH) - 1) downto 0) := (others => '0');
    signal Ready_Transmitter    : STD_LOGIC;
    signal SCLK_Int             : STD_LOGIC := '0';
    component I2S_Transmitter is
        Generic (   WIDTH   : INTEGER := 16
                    );
        Port (  Clock   : in STD_LOGIC;
                nReset  : in STD_LOGIC;
                Ready   : out STD_LOGIC;
                Tx      : in STD_LOGIC_VECTOR(((2 * WIDTH) - 1) downto 0);
                LRCLK   : out STD_LOGIC;
                SCLK    : out STD_LOGIC;
                SD      : out STD_LOGIC
                );
    end component;

begin

    Transmitter : I2S_Transmitter generic map ( WIDTH => WIDTH
                                                )
                                  port map(     Clock => SCLK_Int,
                                                nReset => nReset,
                                                Ready => Ready_Transmitter,
                                                Tx => Tx_Transmitter,
                                                LRCLK => LRCLK,
                                                SCLK => SCLK,
                                                SD => SD
                                                );
   xpm_cdc_Data : xpm_cdc_gray generic map (    DEST_SYNC_FF => 4,
                                                SIM_ASSERT_CHK => 0,
                                                SIM_LOSSLESS_GRAY_CHK => 0,
                                                WIDTH => (2 * WIDTH)
                                                )
                                    port map (  src_clk => ACLK,
                                                src_in_bin => Tx_AXI,
                                                dest_clk => MCLK,
                                                dest_out_bin => Tx_Transmitter
                                                );
   xpm_cdc_Ready : xpm_cdc_single generic map ( DEST_SYNC_FF => 4,
                                                SRC_INPUT_REG => 1
                                                )
                                    port map (  src_clk => MCLK,
                                                src_in => Ready_Transmitter,
                                                dest_clk => ACLK,
                                                dest_out => Ready_AXI
                                                );
    process
        variable Counter    : INTEGER := 0;
    begin
        wait until rising_edge(MCLK);
        if(Counter < ((RATIO / 2) - 1)) then
            Counter := Counter + 1;
        else
            Counter := 0;
            SCLK_Int <= not SCLK_Int;
        end if;

        if(nReset = '0') then
            Counter := 0;
            SCLK_Int <= '0';
        end if;
    end process;

    process
    begin
        wait until rising_edge(ACLK);
        case CurrentState is
            when State_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;
end AXIS_I2S_Arch;

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

該項(xiàng)目需要以下 IP 內(nèi)核:

  • 帶有 AXI-Stream 接口的 I2S 發(fā)送器
  • 從 SD 卡讀取數(shù)據(jù)并將其寫(xiě)入 FIFO 的處理系統(tǒng)
  • AXI-Stream FIFO
  • 用于生成音頻時(shí)鐘的時(shí)鐘向?qū)?/font>
poYBAGNsXJWAWQWGAAFzFS9WHfY413.png
?

時(shí)鐘向?qū)蓵r(shí)鐘,然后用作 CS4344 的主時(shí)鐘。輸出時(shí)鐘可以通過(guò) AXI-Lite 接口適應(yīng)音頻文件的采樣率。時(shí)鐘向?qū)褂?12.288 MHz 時(shí)鐘初始化,用于 48 kHz 音頻信號(hào)。

poYBAGNsXJmAdYItAAFECEdnobo694.png
?

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

pYYBAGNsXJuAWK_YAADIkwm0xJo335.png
?

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

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

poYBAGOIIreADpENAAFhBOxMkqY831.png
?

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

u32 AudioPlayer_Init(void)
{
	xil_printf("[INFO] Looking for FIFO configuration...\r\n");
	_Fifo_ConfigPtr = XLlFfio_LookupConfig(XPAR_FIFO_DEVICE_ID);
	if(_Fifo_ConfigPtr == NULL)
	{
		xil_printf("[ERROR] Invalid FIFO configuration!\r\n");
		return XST_FAILURE;
	}

	xil_printf("[INFO] Initialize FIFO...\r\n");
	if(XLlFifo_CfgInitialize(&_Fifo, _Fifo_ConfigPtr, _Fifo_ConfigPtr->BaseAddress) != XST_SUCCESS)
	{
		xil_printf("[ERROR] FIFO initialization failed!\n\r");
		return XST_FAILURE;
	}

	xil_printf("[INFO] Looking for GIC configuration...\r\n");
	_GIC_ConfigPtr = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
	if(_GIC_ConfigPtr == NULL)
	{
		xil_printf("[ERROR] Invalid GIC configuration!\n\r");
		return XST_FAILURE;
	}

	xil_printf("[INFO] Initialize GIC...\r\n");
	if(XScuGic_CfgInitialize(&_GIC, _GIC_ConfigPtr, _GIC_ConfigPtr->CpuBaseAddress) != XST_SUCCESS)
	{
		xil_printf("[ERROR] GIC initialization failed!\n\r");
		return XST_FAILURE;
	}

	xil_printf("[INFO] Setup interrupt handler...\r\n");
	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] Can not connect interrupt handler!\n\r");
		return XST_FAILURE;
	}
	XScuGic_Enable(&_GIC, XPAR_FABRIC_FIFO_INTERRUPT_INTR);

	xil_printf("[INFO] Enable exceptions...\r\n");
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &_GIC);
	Xil_ExceptionEnable();

	xil_printf("[INFO] Enable FIFO interrupts...\r\n");
	XLlFifo_IntClear(&_Fifo, XLLF_INT_ALL_MASK);

	xil_printf("[INFO] Initialize Clocking Wizard...\r\n");
	if((ClockingWizard_Init(&_ClkWiz, XPAR_CLOCKINGWIZARD_BASEADDR) || ClockingWizard_GetOutput(&_ClkWiz, &_AudioClock))!= XST_SUCCESS)
	{
		xil_printf("[ERROR] Clocking Wizard initialization failed!\n\r");
		return XST_FAILURE;
	}
	xil_printf("[INFO] Mount SD card...\r\n");
	if(SD_Init())
	{
		xil_printf("[ERROR] Can not initialize SD card!\n\r");
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}

初始化完成后,立即調(diào)用該函數(shù)從 SD 卡加AudioPlayer_LoadFile載文件Audio.wav 。

if(AudioPlayer_LoadFile("Audio.wav"))
{
	xil_printf("[ERROR] Can not open Audio file!\n\r");
	return XST_FAILURE;
}

u32 AudioPlayer_LoadFile(char* File)
{
	if(SD_LoadFileFromCard(File, &_File))
	{
		xil_printf("[ERROR] Can not open Audio file!\n\r");
		return XST_FAILURE;
	}

	xil_printf("	File size: %lu bytes\n\r", _File.Header.ChunkSize + 8);
	xil_printf("	File format: %lu\n\r", _File.Format.AudioFormat);
	xil_printf("	Channels: %lu\n\r", _File.Format.NumChannels);
	xil_printf("	Sample rate: %lu Hz\n\r", _File.Format.SampleRate);
	xil_printf("	Bits per sample: %lu bits\n\r", _File.Format.BitsPerSample);
	xil_printf("	Block align: %lu bytes\n\r", _File.Format.BlockAlign);
	xil_printf("	Data bytes: %lu bytes\n\r", _File.Header.ChunkSize / _File.Format.NumChannels);
	xil_printf("	Samples: %lu\n\r", 8 * _File.Header.ChunkSize / _File.Format.NumChannels / _File.Format.BitsPerSample);

	if(( _File.Format.BitsPerSample != 16) || (_File.Format.NumChannels > 2))
	{
		xil_printf("[ERROR] Invalid file format!\n\r");
		return XST_FAILURE;
	}
	AudioPlayer_ChangeFreq(_File.Format.SampleRate);

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

	return XST_SUCCESS;
}

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

u32 SD_LoadFileFromCard(const char* FileName, Wave_t* File)
{
	xil_printf("[INFO] Opening file: %s...\n\r", FileName);

	if(f_open(&_FileHandle, FileName, FA_READ))
	{
		xil_printf("[ERROR] Can not open audio file!\n\r");
		return XST_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] Can not read SD card!\n\r");
		return XST_FAILURE;
	}

	Wave_Header_t Header;
	uint32_t Offset = 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] Can not read SD card!\n\r");
		return XST_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] Can not place SD card pointer!\n\r");
			return XST_FAILURE;
		}
	}

	if(f_read(&_FileHandle, &File->DataHeader, sizeof(Wave_Header_t), &_BytesRead))
	{
		xil_printf("[ERROR] Can not read SD card!\n\r");
		return XST_FAILURE;
	}

	if(File->Format.AudioFormat != WAVE_FORMAT_PCM)
	{
		xil_printf("[ERROR] Audio format not supported! Keep sure that the file use the PCM format!\n\r");
		return XST_FAILURE;
	}

	_RemainingBytes = File->DataHeader.ChunkSize;

	_IsBusy = true;

	return XST_SUCCESS;
}

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

static void AudioPlayer_ChangeFreq(const u32 SampleRate)
{
	if(SampleRate == 44100)
	{
		xil_printf("	Use clock setting 1...\n\r");
		_ClkWiz.DIVCLK_DIVIDE = 5;
		_ClkWiz.CLKFBOUT_MULT = 42;
		_ClkWiz.CLKFBOUT_Frac_Multiply = 0;
		_AudioClock.DIVIDE = 93;
		_AudioClock.FRAC_Divide = 0;
	}
	else if(SampleRate == 48000)
	{
		xil_printf("	Use clock setting 2...\n\r");
		_ClkWiz.DIVCLK_DIVIDE = 3;
		_ClkWiz.CLKFBOUT_MULT = 23;
		_ClkWiz.CLKFBOUT_Frac_Multiply = 0;
		_AudioClock.DIVIDE = 78;
		_AudioClock.FRAC_Divide = 0;
	}
	else if(SampleRate == 96000)
	{
		xil_printf("	Use clock setting 3...\n\r");
		_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);
}

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

u32 SD_CopyDataIntoBuffer(u8* Buffer, const u32 Length)
{
	if(_RemainingBytes >= Length)
	{
		if(f_read(&_FileHandle, Buffer, Length, &_BytesRead))
		{
			return XST_FAILURE;
		}

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

		if(f_close(&_FileHandle))
		{
			xil_printf("[ERROR] Can not close audio file!\n\r");
			return XST_FAILURE;
		}

		_IsBusy = false;
	}

	return XST_SUCCESS;
}

然后程序流程的其余部分發(fā)生在 FIFO 的回調(diào)中:

static void AudioPlayer_FifoHandler(void* CallbackRef)
{
	XLlFifo* InstancePtr = (XLlFifo*)CallbackRef;

	u32 Pending = 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);
		}
		else if(Pending & XLLF_INT_TFPE_MASK)
		{
			AudioPlayer_CopyBuffer();
			if(!SD_IsBusy())
			{
				XLlFifo_IntDisable(&_Fifo, XLLF_INT_ALL_MASK);
			}

			XLlFifo_IntClear(InstancePtr, XLLF_INT_TFPE_MASK);
		}
		else if(Pending & XLLF_INT_ERROR_MASK)
		{
			xil_printf("	Error: %lu!\n\r", 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)自?xún)?nèi)部緩沖區(qū)的新數(shù)據(jù)填充。當(dāng)從處理系統(tǒng)到 FIFO 的傳輸完成時(shí),會(huì)觸發(fā)TC中斷(傳輸完成)并從 SD 卡中讀取下一個(gè)數(shù)據(jù)塊。這將重復(fù),直到文件完全播放。

static void AudioPlayer_CopyBuffer(void)
{
	u32 Bytes = 0x00;
	for(u32 i = 0x00; i < AUDIOPLAYER_FIFO_BUFFER_SIZE; i += _File.Format.BlockAlign)
	{
		u32 Word = 0x00;
		for(u8 Byte = 0x00; Byte < _File.Format.BlockAlign; Byte++)
		{
			Word |= _FifoBuffer[i + Byte];
			Word <<= 0x08;
		}

		if(XLlFifo_iTxVacancy(&_Fifo))
		{
			XLlFifo_TxPutWord(&_Fifo, Word);
                        Bytes += sizeof(u32);
		}
	}

	XLlFifo_iTxSetLen(&_Fifo, Bytes);
}

現(xiàn)在需要一個(gè)波形文件。存儲(chǔ)庫(kù)中提供了簡(jiǎn)單的測(cè)試信號(hào),或者可以在例如wavtones.com上生成

然后只需將相應(yīng)的文件復(fù)制到名為Audio.wav的 SD 卡中,您就可以開(kāi)始使用了。

-----------I2S Audio player-----------

[INFO] Looking for FIFO configuration...
[INFO] Initialize FIFO...
[INFO] Looking for GIC configuration...
[INFO] Initialize GIC...
[INFO] Setup interrupt handler...
[INFO] Enable exceptions...
[INFO] Enable FIFO interrupts...
[INFO] Initialize Clocking Wizard...
[INFO] Mount SD card...
[INFO] Opening file: Single.wav...
        File size: 264610 bytes
        File format: 1
        Channels: 1
        Sample rate: 48000 Hz
        Bits per sample: 16 bits
        Data bytes: 264602 bytes
        Samples: 132301
        Use clock setting 2...
[INFO] Finished!
pYYBAGOIIrqAHw9kAADkg8R_eCg272.png
?

或使用立體聲音頻:

-----------I2S Audio player-----------

[INFO] Looking for FIFO configuration...
[INFO] Initialize FIFO...
[INFO] Looking for GIC configuration...
[INFO] Initialize GIC...
[INFO] Setup interrupt handler...
[INFO] Enable exceptions...
[INFO] Enable FIFO interrupts...
[INFO] Initialize Clocking Wizard...
[INFO] Mount SD card...
[INFO] Opening file: Dual.wav...
        File size: 529208 bytes
        File format: 1
        Channels: 2
        Sample rate: 44100 Hz
        Bits per sample: 16 bits
        Block align: 4 bytes
        Data bytes: 264600 bytes
        Samples: 132300
        Use clock setting 1...
[INFO] Finished!
pYYBAGOIIryAf51CAAEVrD4XhNw780.png
?

?


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評(píng)論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
  2. 1.06 MB  |  532次下載  |  免費(fèi)
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費(fèi)
  5. 3TC358743XBG評(píng)估板參考手冊(cè)
  6. 1.36 MB  |  330次下載  |  免費(fèi)
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費(fèi)
  9. 5元宇宙深度解析—未來(lái)的未來(lái)-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費(fèi)
  11. 6迪文DGUS開(kāi)發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費(fèi)
  13. 7元宇宙底層硬件系列報(bào)告
  14. 13.42 MB  |  182次下載  |  免費(fèi)
  15. 8FP5207XR-G1中文應(yīng)用手冊(cè)
  16. 1.09 MB  |  178次下載  |  免費(fèi)

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費(fèi)
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費(fèi)
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費(fèi)
  7. 4開(kāi)關(guān)電源設(shè)計(jì)實(shí)例指南
  8. 未知  |  21549次下載  |  免費(fèi)
  9. 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書(shū))
  10. 0.00 MB  |  15349次下載  |  免費(fèi)
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費(fèi)
  13. 7電子制作實(shí)例集錦 下載
  14. 未知  |  8113次下載  |  免費(fèi)
  15. 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德?tīng)栔?/a>
  16. 0.00 MB  |  6656次下載  |  免費(fèi)

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費(fèi)
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費(fèi)
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費(fèi)
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費(fèi)
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費(fèi)
  11. 6電路仿真軟件multisim 10.0免費(fèi)下載
  12. 340992  |  191187次下載  |  免費(fèi)
  13. 7十天學(xué)會(huì)AVR單片機(jī)與C語(yǔ)言視頻教程 下載
  14. 158M  |  183279次下載  |  免費(fèi)
  15. 8proe5.0野火版下載(中文版免費(fèi)下載)
  16. 未知  |  138040次下載  |  免費(fèi)