-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added i2s peripheral * Update README.md
- Loading branch information
1 parent
31f4244
commit 925ea7e
Showing
37 changed files
with
3,643 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Protocolo de comunicação I2S | ||
|
||
O protocolo I²S (ou I2S, como também é conhecido) é uma interface serial utilizada para transmitir áudio digital de dois canais em formato de modulação por código de pulso (PCM) entre componentes de circuitos integrados em dispositivos eletrônicos. | ||
|
||
### O que é o I²S? | ||
|
||
- O I²S (Inter-Integrated Circuit Sound) é um protocolo de comunicação serial síncrono. Ele foi introduzido em 1986 pela Philips Semiconductor (agora conhecida como NXP Semiconductors) e tem sido amplamente utilizado em dispositivos de áudio e sistemas embarcados. | ||
- A principal finalidade do I²S é transmitir dados de áudio digital entre componentes, como microcontroladores, processadores de sinal digital (DSPs), conversores analógico-digital (ADCs) e conversores digital-analógico (DACs). | ||
|
||
### Como funciona o I²S? | ||
O barramento I²S utiliza três linhas principais: | ||
- Serial Clock (SCK): Também conhecido como bit clock (BCLK), é responsável por sincronizar a transmissão dos dados. | ||
- Word Select (WS): Também chamado de left-right clock (LRCLK) ou frame sync (FS), indica qual canal (esquerdo ou direito) está sendo transmitido. O WS tem uma frequência igual à taxa de amostragem. | ||
- Serial Data (SD): Transmite os dados de áudio. | ||
|
||
 | ||
|
||
### Funcionamento | ||
|
||
Para o funcionamento do periférico deve se atentar que: | ||
- O I2S desenvolvido possui uma resolução de 32 bits e como o microfone usado nos testes era de 24 bits foi necessário ajuste na leitura (processo ready em i2s.vhd), então ele deve ser ajustado conforme o mic usado para garantir a leitura correta. | ||
|
||
- A taxa de amostragem é definida por $ clk/64 $, nos testes foi usado um clk de 1Mhz resultando em uma taxa de amostragem de 15625Hz. Caso for utilizar um clk menor, o áudio captado poderá ser prejudicado, visto que devemos ter uma taxa de amostragem de pelo menos o dobro da maior frequência que será captada para garantir a integridade do sinal. | ||
|
||
- Para o funcionamento também é necessário ter nível lógico alto no pino de enable. | ||
|
||
- O áudio captado é escrito na memória desenvolvidada, ela escreve de maneira circular, ou seja, sempre o dado será escrito sob o antigo, ela suporta 16384 palavras de 32 bits, logo é salvo aproximamente 1 segundo. Também deve ser resaltado que é gravado somente o dado do microfone direito, pois somente ele esta transmitindo nos testes. | ||
|
||
### Gravando um áudio | ||
|
||
Foi utilizado kit DE10-Lite, baseado na FPGA MAX10 para gravar um áudio, deve-se conectar o mic do seguinte modo: | ||
|
||
ARDUINO_IO(0) <= sck; | ||
ARDUINO_IO(2) <= ws; | ||
ARDUINO_IO(4) <= sd; | ||
|
||
Com a hardware já em funcionamento use o In-System Memory Contet Editor para ler a memória e exportar o áudio, verá algo semelhate a isso: | ||
|
||
 | ||
|
||
Como o áudio é exportado em .hex e a parte significativa do áudio são os 24 bits menos significativos, iremos converter à inteiro sinalizado com um ganho, dessa forma podemos ouvir o áudio gravado. Para isso foi usado um script python para fazer a conversão. | ||
|
||
# Lê o arquivo original | ||
with open('audio.hex', 'r') as arquivo_original: | ||
linhas = arquivo_original.readlines() | ||
|
||
# Extrai os caracteres de cada linha | ||
ultimos_caracteres = [linha.strip()[-10:-2] for linha in linhas] | ||
|
||
# Cria um novo arquivo para salvar os caracteres | ||
with open('audio.txt', 'w') as novo_arquivo: | ||
for caracteres in ultimos_caracteres: | ||
inteiro = int(caracteres,16) | ||
if inteiro &(1 << (31)): | ||
inteiro -= 1 << 32 | ||
novo_arquivo.write(str(inteiro*256) + '\n') | ||
|
||
Para a análise da gravação foi utilizado o Ocenaudio. | ||
Abaixo tem o espectro do áudio gravado quando é emitido um som na frequência de 1KHz. | ||
|
||
 | ||
|
||
Testando o microfone com voz se tem o seguinte resultado: | ||
|
||
 | ||
|
||
### Pendências | ||
|
||
- Integrar com o softcore; | ||
- Ajustar os timings do sinal de WS e gravação na memória. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
------------------------------------------------------------------- | ||
-- Name : i2s.vhd | ||
-- Author : Emmanuel Reitz Guesser | ||
-- Version : 0.1 | ||
-- Copyright : Departamento de Eletrônica, Florianópolis, IFSC | ||
-- Description : Este projeto descreve o funcionamento da comunicação i2s entre a FPGA e um microfone. | ||
------------------------------------------------------------------- | ||
library IEEE; | ||
use IEEE.STD_LOGIC_1164.ALL; | ||
|
||
entity I2S is | ||
|
||
Port ( | ||
clk : in std_logic; | ||
sck : out std_logic; | ||
rst : in std_logic; | ||
ws : out std_logic; | ||
sd : in std_logic; | ||
enable : in std_logic; | ||
left_channel : out std_logic_vector(31 downto 0) := (others => '0'); | ||
right_channel : out std_logic_vector(31 downto 0) := (others => '0') | ||
); | ||
end I2S; | ||
|
||
architecture RTL of I2S is | ||
type state_type is (IDLE, LEFT, RIGHT); | ||
signal state : state_type := IDLE; | ||
signal bit_count : integer range 0 to 31 := 0; | ||
signal right_data : std_logic_vector(31 downto 0); | ||
signal left_data : std_logic_vector(31 downto 0); | ||
|
||
begin | ||
|
||
-- Processo que realiza a transição de estados da maquina e um contador que sera usado | ||
-- para direcionar os bits de entrada no bufer, ele é sincronizado por borda | ||
-- de descida porque envio do dado do mic é em borda de descida. | ||
state_transition : process(clk, rst) | ||
begin | ||
if rst = '1' then | ||
state <= IDLE; | ||
bit_count <= 31; | ||
|
||
elsif falling_edge(clk) then | ||
case state is | ||
when IDLE => | ||
if enable = '1' then | ||
state <= LEFT; | ||
end if; | ||
|
||
when LEFT => | ||
if enable = '0' then | ||
state <= IDLE; | ||
elsif bit_count = 0 then | ||
bit_count <= 31; | ||
state <= RIGHT; | ||
else | ||
bit_count <= bit_count - 1; | ||
end if; | ||
|
||
when RIGHT => | ||
if enable = '0' then | ||
state <= IDLE; | ||
elsif bit_count = 0 then | ||
bit_count <= 31; | ||
state <= LEFT; | ||
else | ||
bit_count <= bit_count - 1; | ||
end if; | ||
end case; | ||
end if; | ||
end process state_transition; | ||
|
||
-- Processo que envia a sinal de "word select" e o clock que sincroniza o envio de dados do mic. | ||
outs : process(state, clk) is | ||
begin | ||
case state is | ||
when IDLE => | ||
ws <= '0'; | ||
sck <= '1'; | ||
when LEFT => | ||
ws <= '0'; | ||
sck <= clk; | ||
when RIGHT => | ||
ws <= '1'; | ||
sck <= clk; | ||
end case; | ||
end process outs; | ||
|
||
-- Processo que armazena o dado enviado pelo mic em um bufer. Rescebendo os 32 bits, ele armazena os dados do bufer, como a resolução | ||
-- do mic usado é 24 bits os ultimos 8 bits enviados são lixo, então ele descarta e completa o registrador de 32 bits com o MSB enviado | ||
-- para manter a sinalização do dado. Devido ao atraso do envio de 1 ciclo apos o sinal de ws ignorasse o primeiro bit do buffer. | ||
-- A leitura é sincroniza por borda de subida, para que haja menos interferencia da transição de bit. | ||
ready : process (clk, rst) is | ||
begin | ||
if rst = '1' then | ||
right_data <= (others => '0'); | ||
left_data <= (others => '0'); | ||
left_channel <= (others => '0'); | ||
right_channel <= (others => '0'); | ||
|
||
elsif rising_edge(clk) then | ||
case state is | ||
when IDLE => | ||
left_data <= (others => '0'); | ||
right_data <= (others => '0'); | ||
|
||
when LEFT => | ||
left_data(bit_count) <= sd; | ||
if bit_count = 0 then | ||
left_channel(23 downto 0) <= left_data(30 downto 7); | ||
if left_data(30) = '1' then | ||
left_channel(31 downto 24) <= (others => '1'); | ||
else | ||
left_channel(31 downto 24) <= (others => '0'); | ||
end if; | ||
right_data <= (others => '0'); | ||
end if; | ||
|
||
when RIGHT => | ||
right_data(bit_count) <= sd; | ||
if bit_count = 0 then | ||
right_channel(23 downto 0) <= right_data(30 downto 7); | ||
if right_data(30) = '1' then | ||
right_channel(31 downto 24) <= (others => '1'); | ||
else | ||
right_channel(31 downto 24) <= (others => '0'); | ||
end if; | ||
left_data <= (others => '0'); | ||
end if; | ||
end case; | ||
end if; | ||
end process ready; | ||
|
||
end RTL; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
entity test_bench is | ||
end test_bench; | ||
|
||
architecture Test of test_bench is | ||
signal clk_tb : std_logic; | ||
signal sck_tb : std_logic; | ||
signal rst_tb : std_logic; | ||
signal ws_tb : std_logic; | ||
signal sd_tb : std_logic; | ||
signal enable_tb : std_logic; | ||
signal left_channel_tb : std_logic_vector(31 downto 0); | ||
signal right_channel_tb : std_logic_vector(31 downto 0); | ||
signal q_tb: std_logic_vector(31 downto 0); | ||
|
||
|
||
begin | ||
I2S_inst : entity work.I2S | ||
port map( | ||
clk => clk_tb, | ||
sck => sck_tb, | ||
rst => rst_tb, | ||
ws => ws_tb, | ||
sd => sd_tb, | ||
enable => enable_tb, | ||
left_channel => left_channel_tb, | ||
right_channel => right_channel_tb | ||
); | ||
|
||
men_cycle_inst : entity work.men_cycle | ||
port map( | ||
clk => clk_tb, | ||
rst => rst_tb, | ||
data => right_channel_tb, | ||
wren => ws_tb, | ||
q => q_tb | ||
); | ||
|
||
clock_driver : process | ||
constant period : time := 10 ns; | ||
begin | ||
clk_tb <= '1'; | ||
wait for period / 2; | ||
clk_tb <= '0'; | ||
wait for period / 2; | ||
end process clock_driver; | ||
|
||
rst : process is | ||
begin | ||
rst_tb <= '1'; | ||
wait for 2 ns; | ||
rst_tb <= '0'; | ||
wait; | ||
end process rst; | ||
|
||
sign : process is ------- | ||
constant data_1 : std_logic_vector(31 downto 0) := "00110001010010101100100110011010"; | ||
constant data_2 : std_logic_vector(31 downto 0) := "01000100011100001111001000101101"; | ||
variable i : integer; | ||
|
||
begin | ||
enable_tb <= '1'; | ||
sd_tb <= '0'; | ||
|
||
i := 31; | ||
while i /= -1 loop | ||
wait until sck_tb = '0'; | ||
sd_tb <= data_1(i); | ||
i := i - 1; | ||
end loop; | ||
|
||
i := 31; | ||
while i /= -1 loop | ||
wait until sck_tb = '0'; | ||
sd_tb <= data_2(i); | ||
i := i - 1; | ||
end loop; | ||
|
||
i := 31; | ||
while i /= -1 loop | ||
wait until sck_tb = '0'; | ||
sd_tb <= data_1(i); | ||
i := i - 1; | ||
end loop; | ||
|
||
|
||
end process sign; | ||
|
||
end architecture Test; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
library ieee; | ||
use ieee.std_logic_1164.all; | ||
use ieee.numeric_std.all; | ||
|
||
entity men_cycle is | ||
port( | ||
clk : in std_logic; | ||
rst : in std_logic; | ||
data : in std_logic_vector(31 downto 0); | ||
wren : in std_logic; | ||
q : out std_logic_vector(31 downto 0) | ||
); | ||
end entity men_cycle; | ||
|
||
architecture RTL of men_cycle is | ||
|
||
signal address : unsigned(13 downto 0) := (others => '0'); | ||
|
||
component ram | ||
PORT | ||
( | ||
address : IN STD_LOGIC_VECTOR (13 DOWNTO 0); | ||
clock : IN STD_LOGIC := '1'; | ||
data : IN STD_LOGIC_VECTOR (31 DOWNTO 0); | ||
wren : IN STD_LOGIC ; | ||
q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0) | ||
); | ||
end component; | ||
begin | ||
ram_inst : component ram | ||
port map( | ||
address => std_logic_vector(address), | ||
clock => clk, | ||
data => data, | ||
wren => wren, | ||
q => q | ||
); | ||
|
||
addr_cycle : process (wren, rst) is | ||
begin | ||
if rst = '1' then | ||
address <= (others => '0'); | ||
elsif rising_edge(wren) then | ||
address <= address + 1; | ||
end if; | ||
end process addr_cycle; | ||
|
||
end architecture RTL; | ||
|
Oops, something went wrong.