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

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

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

使用FPGA播放音頻文件

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

9b3d3e8c-b4d0-11ee-8b88-92fbcf53809c.png

讓我們看一下I2S規(guī)范,并嘗試用FPGA播放音頻文件。

開(kāi)篇第一步

Inter-IC Sound Interface(簡(jiǎn)稱I2S)是由飛利浦公司開(kāi)發(fā),用于通過(guò)不同IC之間的串行接口(例如從處理器DAC)傳輸數(shù)字音頻數(shù)據(jù)。該接口使用以下信號(hào)進(jìn)行數(shù)據(jù)傳輸:

SCK (串行時(shí)鐘)——用于數(shù)據(jù)傳輸?shù)臅r(shí)鐘。

SD (串行數(shù)據(jù))- 每個(gè)數(shù)據(jù)字的各個(gè)位通過(guò)該線傳輸。

WS (字選擇)- 定義傳輸數(shù)據(jù)字的長(zhǎng)度。它用于標(biāo)記右或左音頻通道。

僅音頻數(shù)據(jù)通過(guò) I2S 傳輸。附加數(shù)據(jù)(例如各個(gè)總線用戶的配置)通過(guò)其他接口傳輸。數(shù)據(jù)傳輸總是在兩個(gè)總線之間沿一個(gè)方向進(jìn)行,其中一路總線必須充當(dāng)主機(jī)并負(fù)責(zé)生成時(shí)鐘信號(hào)。在由多個(gè)發(fā)送器和接收器組成的復(fù)雜系統(tǒng)中,時(shí)鐘信號(hào)由外部總線主控器生成,并且相應(yīng)的發(fā)送器生成數(shù)據(jù)。

9b4c1128-b4d0-11ee-8b88-92fbcf53809c.png

所有數(shù)據(jù)均以二進(jìn)制補(bǔ)碼和 MSB 優(yōu)先的方式傳輸。如果接收方和發(fā)送方的字寬存在正差(即一方的字寬小于另一方的字寬),則剩余位填充0。根據(jù)規(guī)范,數(shù)據(jù)可以同步于正時(shí)鐘沿或負(fù)時(shí)鐘沿,從而數(shù)據(jù)總是在負(fù)時(shí)鐘沿讀入。

WS信號(hào)選擇活動(dòng)通道,并將低或高相位內(nèi)的所有數(shù)據(jù)分配給相應(yīng)的通道:

WS = 0 – 通道 1(左)

WS = 1 – 通道 2(右)

?WS信號(hào)必須在下一個(gè)數(shù)據(jù)字的 MSB 之前的一個(gè)時(shí)鐘周期發(fā)生變化,以便接收器可以將數(shù)據(jù)讀入正確的通道。WS信號(hào)的時(shí)鐘頻率通常對(duì)應(yīng)于音頻信號(hào)的采樣頻率。

9b593894-b4d0-11ee-8b88-92fbcf53809c.png

在這篇文章中,展示如何設(shè)計(jì)一個(gè)簡(jiǎn)單的 I2S 發(fā)射器,并使用 CS4344 立體聲 D/A 轉(zhuǎn)換器通過(guò)揚(yáng)聲器輸出恒定的聲音。

要輸出的聲音將存儲(chǔ)在 FPGA 的block memory中,并由發(fā)送器讀出,并將數(shù)據(jù)發(fā)送到 D/A 轉(zhuǎn)換器。整個(gè)項(xiàng)目分為三個(gè)部分,將逐步討論:

集成系統(tǒng)時(shí)鐘和I2S模塊的Top設(shè)計(jì)

集成ROM和I2S發(fā)送器的I2S模塊

I2S發(fā)送器

I2S發(fā)送器

設(shè)計(jì)的最底層應(yīng)該是 I2S 發(fā)送器,其任務(wù)是通過(guò) I2S 接口發(fā)送各個(gè)數(shù)據(jù)字。

9b739d56-b4d0-11ee-8b88-92fbcf53809c.png

該框圖產(chǎn)生了以下發(fā)送器:

entityI2S_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
);
endI2S_Transmitter;

數(shù)據(jù)字的大小通過(guò)WIDTH參數(shù)定義。

三級(jí)狀態(tài)機(jī)控制發(fā)送器,描述如下:

architectureI2S_Transmitter_ArchofI2S_Transmitteris

typeState_tis(State_Reset,State_LoadWord,State_TransmitWord);

signalCurrentState:State_t:=State_Reset;

signalTx_Int:STD_LOGIC_VECTOR(((2*WIDTH)-1)downto0):=(others=>'0');
signalReady_Int:STD_LOGIC:='0';
signalLRCLK_Int:STD_LOGIC:='1';
signalSD_Int:STD_LOGIC:='0';
signalEnable:STD_LOGIC:='0';

begin

process
variableBitCounter:INTEGER:=0;
begin
waituntilfalling_edge(Clock);

caseCurrentStateis
whenState_Reset=>
Ready_Int<=?'0';
????????????????LRCLK_Int?<=?'1';
????????????????Enable?<=?'1';
????????????????SD_Int?<=?'0';
????????????????Tx_Int?<=?(others?=>'0');
CurrentState<=?State_LoadWord;
????????????when?State_LoadWord?=>
BitCounter:=0;
Tx_Int<=?Tx;
????????????????LRCLK_Int?<=?'0';
????????????????CurrentState?<=?State_TransmitWord;
????????????when?State_TransmitWord?=>
BitCounter:=BitCounter+1;
if(BitCounter>(WIDTH-1))then
LRCLK_Int<=?'1';
????????????????end?if;
????????????????if(BitCounter?

復(fù)位期間,輸出信號(hào)被置位,SCLK時(shí)鐘被停用。復(fù)位后,機(jī)器從State_Reset狀態(tài)變?yōu)镾tate_TransmitWord狀態(tài)。在此狀態(tài)下,機(jī)器Tx_Int通過(guò) I2S 接口傳輸緩沖區(qū)的內(nèi)容。

一旦開(kāi)始傳輸最后一個(gè)數(shù)據(jù)位,Ready就設(shè)置為表示傳輸結(jié)束并準(zhǔn)備好接受新數(shù)據(jù)。然后機(jī)器更改為 stateState_LoadWord狀態(tài),其中發(fā)送緩沖區(qū)填充有新的數(shù)據(jù)字并開(kāi)始新的傳輸。

I2S模塊

I2S 模塊使用 I2S 發(fā)送器將數(shù)據(jù)從 ROM 傳輸?shù)?D/A 轉(zhuǎn)換器。

9b7cc9c6-b4d0-11ee-8b88-92fbcf53809c.png

具有以下代碼:

entityI2Sis
Generic(RATIO:INTEGER:=8;
WIDTH:INTEGER:=16
);
Port(MCLK:inSTD_LOGIC;
nReset:inSTD_LOGIC;
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC
);
endI2S;

參數(shù)RATIO 定義了SCLK與MCLK WIDTH的比率以及每個(gè)通道的數(shù)據(jù)字的寬度。

除了 I2S 發(fā)送器之外,該模塊還使用 ROM,該 ROM 可以通過(guò)block memory生成器創(chuàng)建并填充數(shù)據(jù)。兩者都可以使用 Vivado 的 IP 來(lái)完成。

9b875b48-b4d0-11ee-8b88-92fbcf53809c.png

最后,通過(guò)其他選項(xiàng)使用正弦信號(hào) coe 文件(參見(jiàn)附件)對(duì) ROM 進(jìn)行初始化。

I2S 模塊使用狀態(tài)機(jī)從 ROM 讀取數(shù)據(jù)并將其傳輸?shù)?I2S 發(fā)送器。

architectureI2S_ArchofI2Sis

typeState_tis(State_Reset,State_WaitForReady,State_IncreaseAddress,State_WaitForStart);

signalCurrentState:State_t:=State_Reset;

signalTx:STD_LOGIC_VECTOR(((2*WIDTH)-1)downto0):=(others=>'0');
signalROM_Data:STD_LOGIC_VECTOR((WIDTH-1)downto0):=(others=>'0');
signalROM_Address:STD_LOGIC_VECTOR(6downto0):=(others=>'0');

signalReady: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;

componentSineROMis
Port(Address:inSTD_LOGIC_VECTOR(6downto0);
Clock:inSTD_LOGIC;
DataOut:outSTD_LOGIC_VECTOR(15downto0)
);
endcomponentSineROM;

begin

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

ROM:SineROMportmap(Clock=>MCLK,
Address=>ROM_Address,
DataOut=>ROM_Data
);

process
variableCounter:INTEGER:=0;
begin
waituntilrising_edge(MCLK);
if(Counter
WordCounter:=0;
CurrentState<=?State_WaitForReady;
????????????when?State_WaitForReady?=>
if(Ready='1')then
CurrentState<=?State_WaitForStart;
????????????????else
????????????????????CurrentState?<=?State_WaitForReady;
????????????????end?if;
????????????when?State_WaitForStart?=>
ROM_Address<=?STD_LOGIC_VECTOR(to_unsigned(WordCounter,?ROM_Address'length));
????????????????Tx?<=?x"0000"?&?ROM_Data;
????????????????if(Ready?=?'0')?then
????????????????????CurrentState?<=?State_IncreaseAddress;
????????????????else
????????????????????CurrentState?<=?State_WaitForStart;
????????????????end?if;
????????????when?State_IncreaseAddress?=>
if(WordCounter

第一個(gè)過(guò)程用于從MCLK生成發(fā)送器所需的時(shí)鐘信號(hào)SCLK 。

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

第二個(gè)進(jìn)程負(fù)責(zé)狀態(tài)機(jī)的處理。離開(kāi)State_Reset狀態(tài)后,機(jī)器在該State_WaitForReady狀態(tài)下等待,直到發(fā)送器發(fā)出就緒信號(hào)Ready 。??

一旦發(fā)送器準(zhǔn)備就緒,機(jī)器就會(huì)更改State_WaitForStart狀態(tài)。在此狀態(tài)下,從 ROM 讀取當(dāng)前數(shù)據(jù)字并將其傳輸?shù)桨l(fā)送器。

PS:此處顯示的 ROM 僅包含一個(gè)通道的信息。第二個(gè)通道的數(shù)據(jù)需進(jìn)行擴(kuò)展。

一旦發(fā)送器清除就緒信號(hào)并開(kāi)始發(fā)送數(shù)據(jù),狀態(tài)機(jī)就會(huì)更改為State_IncreaseAddress狀態(tài)。該狀態(tài)下ROM地址加1,然后切換回State_WaitForReady狀態(tài)

top模塊

最后一個(gè)組件是頂層設(shè)計(jì),包括 I2S 模塊和時(shí)鐘PLL。

本示例使用以下參數(shù)來(lái)控制 CS4344:

MCLK:12.288MHz

SCLK:1.536 MHz

LRCLK:48kHz

比率:8

寬度:16

時(shí)鐘PLL生成 12.288 MHz 時(shí)鐘,并與之前代碼中完成的 I2S 模塊一起實(shí)例化。

9b96a652-b4d0-11ee-8b88-92fbcf53809c.png

entityTopis
Generic(RATIO:INTEGER:=8;
WIDTH:INTEGER:=16
);
Port(Clock:inSTD_LOGIC;
nReset:inSTD_LOGIC;
MCLK:outSTD_LOGIC;
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC;
LED:outSTD_LOGIC_VECTOR(3downto0)
);
endTop;

architectureTop_ArchofTopis

signalnSystemReset:STD_LOGIC:='0';
signalMCLK_DCM:STD_LOGIC:='0';
signalLocked:STD_LOGIC:='0';

componentI2Sis
Generic(RATIO:INTEGER:=8;
WIDTH:INTEGER:=16
);
Port(MCLK:inSTD_LOGIC;
nReset:inSTD_LOGIC;
LRCLK:outSTD_LOGIC;
SCLK:outSTD_LOGIC;
SD:outSTD_LOGIC
);
endcomponent;

componentAudioClockis
Port(ClockIn:inSTD_LOGIC;
Locked:outSTD_LOGIC;
MCLK:outSTD_LOGIC;
nReset:inSTD_LOGIC
);
endcomponent;

begin

InputClock:AudioClockportmap(ClockIn=>Clock,
nReset=>nReset,
MCLK=>MCLK_DCM,
Locked=>Locked
);

I2S_Module:I2Sgenericmap(RATIO=>RATIO,
WIDTH=>WIDTH
)
portmap(MCLK=>MCLK_DCM,
nReset=>nSystemReset,
LRCLK=>LRCLK,
SCLK=>SCLK,
SD=>SD
);

nSystemReset<=?nReset?and?Locked;
????LED(0)?<=?nReset;
????LED(1)?<=?Locked;
????LED(2)?<=?nSystemReset;
????MCLK?<=?MCLK_DCM;

end?Top_Arch;

最后就可以進(jìn)行測(cè)試。理想情況下,D/A 轉(zhuǎn)換器輸出 480 Hz 正弦信號(hào)。因?yàn)閬?lái)自 ROM 的信號(hào)模式的長(zhǎng)度為 100 個(gè)樣本,采樣頻率為 48 kHz??梢杂?a href="http://wenjunhu.com/v/tag/577/" target="_blank">示波器檢查總線和信號(hào):

9ba75fd8-b4d0-11ee-8b88-92fbcf53809c.png

此外,還可以檢查音頻信號(hào)(示波器的 FFT 功能是實(shí)現(xiàn)此目的的最佳工具)。

9bb38236-b4d0-11ee-8b88-92fbcf53809c.png

附件-Coe

memory_initialization_radix=16;
memory_initialization_vector=
0000,
0809,
100A,
17FB,
1FD4,
278D,
2F1E,
367F,
3DA9,
4495,
4B3B,
5196,
579E,
5D4E,
629F,
678D,
6C12,
7029,
73D0,
7701,
79BB,
7BF9,
7DBA,
7EFC,
7FBE,
7FFF,
7FBE,
7EFC,
7DBA,
7BF9,
79BB,
7701,
73D0,
7029,
6C12,
678D,
629F,
5D4E,
579E,
5196,
4B3B,
4495,
3DA9,
367F,
2F1E,
278D,
1FD4,
17FB,
100A,
0809,
0000,
F7F7,
EFF6,
E805,
E02C,
D873,
D0E2,
C981,
C257,
BB6B,
B4C5,
AE6A,
A862,
A2B2,
9D61,
9873,
93EE,
8FD7,
8C30,
88FF,
8645,
8407,
8246,
8104,
8042,
8001,
8042,
8104,
8246,
8407,
8645,
88FF,
8C30,
8FD7,
93EE,
9873,
9D61,
A2B2,
A862,
AE6A,
B4C5,
BB6B,
C257,
C981,
D0E2,
D873,
E02C,
E805,
EFF6,
F7F7,

下一篇文章,將向 I2S 發(fā)送器添加 AXI-Stream 接口,并將其與 ZYNQ 的處理系統(tǒng)連接,播放 SD 卡中的音頻文件。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(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)注

    68

    文章

    19286

    瀏覽量

    229852
  • FPGA
    +關(guān)注

    關(guān)注

    1629

    文章

    21736

    瀏覽量

    603419
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8598

    瀏覽量

    151163
  • 音頻
    +關(guān)注

    關(guān)注

    29

    文章

    2877

    瀏覽量

    81553

原文標(biāo)題:使用 FPGA 播放音頻(一)

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

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    請(qǐng)問(wèn)如何使用PSoC4播放音頻文件

    如何使用 PSoC4 播放音頻文件
    發(fā)表于 07-02 07:19

    音頻文件(WAV)特技播放的原理及實(shí)現(xiàn)

    本帖最后由 eehome 于 2013-1-5 10:08 編輯 音頻文件播放是開(kāi)發(fā)多媒體軟件中的一個(gè)重要內(nèi)容,但有時(shí)需要對(duì)它進(jìn)行特技播放,如快速播放,慢速
    發(fā)表于 03-12 00:42

    LabVIEW 播放音頻文件-

    LabVIEW 播放音頻文件-
    發(fā)表于 01-20 17:30

    labview 數(shù)組轉(zhuǎn)換成數(shù)組波形并寫(xiě)入音頻文件重新播放

    我先對(duì)一個(gè)音頻文件進(jìn)行處理 將左右聲道的波形分別進(jìn)行量化編碼調(diào)制解調(diào)解碼了 請(qǐng)問(wèn) 各位大神解碼后 如果我想把一個(gè)數(shù)組轉(zhuǎn)換回?cái)?shù)組波形 并寫(xiě)入一個(gè)音頻文件 重新播放 怎么實(shí)現(xiàn)?
    發(fā)表于 05-12 20:30

    FPGA+VS1003+flash方案,播放音頻文件耳機(jī)沒(méi)有任何聲音

    大家好,公司項(xiàng)目采用的是FPGA+VS1003+flash方案,flash用于保存音頻文件。目前播放遇到問(wèn)題了,描述如下:首先我確認(rèn)了以下幾點(diǎn):1.首先是硬件方面,目前已經(jīng)完成了寄存器配置的測(cè)試
    發(fā)表于 01-16 23:10

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

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

    Matlab處理音頻文件

    文章目錄Matlab處理音頻文件DAC播放DAC配置Tim配置開(kāi)始應(yīng)用層數(shù)據(jù)流向Matlab處理音頻文件Audio_filename = 'Audio.wav';% 獲取原音頻數(shù)據(jù)[A
    發(fā)表于 08-17 06:36

    如何用STM32F103xx單片機(jī)通過(guò)外部I2S音頻編解碼器來(lái)播放音頻文件

    如何用高密度STM32F103xx單片機(jī)通過(guò)外部 I2S音頻編解碼器來(lái)播放音頻文件,本手冊(cè)僅適用于STM32F103系列,可以實(shí)現(xiàn)音頻播放功能
    發(fā)表于 12-01 07:42

    103xx通過(guò)外部I2S音頻解碼器播放音頻文件

    103xx通過(guò)外部I2S音頻解碼器播放音頻文件。
    發(fā)表于 01-12 18:26 ?56次下載

    基于ESP32構(gòu)建的音頻播放

    在這里,我們將使用LM386 和一個(gè)帶有 ESP32 的揚(yáng)聲器來(lái)播放音樂(lè)文件。音頻輸出可能不大,但此應(yīng)用程序顯示了 ESP32 板播放音頻文件的能力。
    發(fā)表于 08-08 15:37 ?2.3w次閱讀
    基于ESP32構(gòu)建的<b class='flag-5'>音頻</b><b class='flag-5'>播放</b>器

    AN4309_將STM32L1xx微控制器與外部I2S音頻編解碼器連接起來(lái)播放音頻文件

    AN4309_將STM32L1xx微控制器與外部I2S音頻編解碼器連接起來(lái)播放音頻文件
    發(fā)表于 11-21 08:11 ?0次下載
    AN4309_將STM32L1xx微控制器與外部I2S<b class='flag-5'>音頻</b>編解碼器連接起來(lái)<b class='flag-5'>播放音頻文件</b>

    AN2739 如何用高密度STM32F103xx單片機(jī)來(lái)播放音頻文件

    AN2739 如何用高密度STM32F103xx單片機(jī)來(lái)播放音頻文件
    發(fā)表于 11-24 08:30 ?4次下載
    AN2739 如何用高密度STM32F103xx單片機(jī)來(lái)<b class='flag-5'>播放音頻文件</b>

    在Arduino中播放音頻

    電子發(fā)燒友網(wǎng)站提供《在Arduino中播放音頻.zip》資料免費(fèi)下載
    發(fā)表于 06-25 15:16 ?0次下載
    在Arduino中<b class='flag-5'>播放音頻</b>

    使用STM32L1xx微控制器與外部I2S音頻編解碼器播放音頻文件

    電子發(fā)燒友網(wǎng)站提供《使用STM32L1xx微控制器與外部I2S音頻編解碼器播放音頻文件.pdf》資料免費(fèi)下載
    發(fā)表于 09-21 11:30 ?3次下載
    使用STM32L1xx微控制器與外部I2S<b class='flag-5'>音頻</b>編解碼器<b class='flag-5'>播放音頻文件</b>

    如何使用音頻接口播放音頻文件

    ZDP1440是一款基于開(kāi)源GUI引擎的圖像顯示專用驅(qū)動(dòng)芯片,內(nèi)部集成16MB顯示內(nèi)存、2D圖形加速器、音頻解碼器等豐富多媒體功能,本文將介紹如何使用音頻接口播放音頻文件。
    的頭像 發(fā)表于 08-06 16:12 ?650次閱讀
    如何使用<b class='flag-5'>音頻</b>接口<b class='flag-5'>播放音頻文件</b>