forked from ultraembedded/cores
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b348763
commit 3613a4e
Showing
13 changed files
with
923 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,22 @@ | ||
### I2S Master | ||
|
||
Github: [http://github.com/ultraembedded/cores](https://github.com/ultraembedded/cores/tree/master/i2s) | ||
|
||
This is a simple I2S master module written in Verilog. | ||
|
||
The module requires clock source which is used to derive MCLK and BCLK for the I2S interface. | ||
|
||
The audio_clk_i clock rate should be: | ||
* 32KHz - 16.384MHz | ||
* 44.1KHz - 22.5792MHz | ||
* 48KHz - 24.576MHz | ||
|
||
The frequency of clk_i must be more than 2 x audio_clk_i frequency. | ||
|
||
The input interface expects 32-bits (2 x 16-bit audio samples) to be provided to it on 'sample_i' and held until 'sample_req_o' is pulsed (data pop request). | ||
|
||
This allows connection to a simple FIFO for audio samples. | ||
|
||
##### Testing | ||
|
||
The supplied testbench requires the SystemC libraries and Icarus Verilog, both of which are available for free. |
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,172 @@ | ||
//----------------------------------------------------------------- | ||
// I2S Master | ||
// V0.1 | ||
// Ultra-Embedded.com | ||
// Copyright 2012 | ||
// | ||
// Email: [email protected] | ||
// | ||
// License: GPL | ||
// If you would like a version with a more permissive license for | ||
// use in closed source commercial applications please contact me | ||
// for details. | ||
//----------------------------------------------------------------- | ||
// | ||
// This file is open source HDL; you can redistribute it and/or | ||
// modify it under the terms of the GNU General Public License as | ||
// published by the Free Software Foundation; either version 2 of | ||
// the License, or (at your option) any later version. | ||
// | ||
// This file is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public | ||
// License along with this file; if not, write to the Free Software | ||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
// USA | ||
//----------------------------------------------------------------- | ||
module i2s | ||
( | ||
// Main clock (min 2x audio_clk_i) | ||
input clk_i, | ||
input rst_i, | ||
|
||
// Audio clock (MCLK x 2): | ||
// For 44.1KHz: 22.5792MHz | ||
// For 48KHz: 24.576MHz | ||
input audio_clk_i, | ||
input audio_rst_i, | ||
|
||
// I2S DAC Interface | ||
output i2s_mclk_o, | ||
output i2s_bclk_o, | ||
output i2s_ws_o, | ||
output i2s_data_o, | ||
|
||
// Audio interface (16-bit x 2 = RL) | ||
// (synchronous to clk_i) | ||
input [31:0] sample_i, | ||
output sample_req_o | ||
); | ||
|
||
//----------------------------------------------------------------- | ||
// Registers | ||
//----------------------------------------------------------------- | ||
reg [4:0] bit_count_q; | ||
|
||
// Registered audio input data | ||
reg [31:0] sample_q; | ||
|
||
// Xilinx: Place output flop in IOB | ||
//synthesis attribute IOB of mclk_q is "TRUE" | ||
//synthesis attribute IOB of ws_q is "TRUE" | ||
//synthesis attribute IOB of bclk_q is "TRUE" | ||
//synthesis attribute IOB of data_q is "TRUE" | ||
reg mclk_q; | ||
reg bclk_q; | ||
reg ws_q; | ||
reg data_q; | ||
|
||
reg sample_req_q; | ||
reg next_data_q; | ||
|
||
//----------------------------------------------------------------- | ||
// MCLK | ||
//----------------------------------------------------------------- | ||
reg [7:0] clock_div_q; | ||
|
||
always @(posedge audio_clk_i or posedge audio_rst_i) | ||
if (rst_i) | ||
begin | ||
mclk_q <= 1'b0; | ||
clock_div_q <= 8'b0; | ||
end | ||
else | ||
begin | ||
mclk_q <= !mclk_q; | ||
clock_div_q <= clock_div_q + 8'd1; | ||
end | ||
|
||
reg clk_en0_ms_q; | ||
reg clk_en1_q; | ||
reg clk_en2_q; | ||
|
||
// Resync clk enable pulse to clk_i domain | ||
always @(posedge clk_i or posedge rst_i) | ||
if (rst_i) | ||
begin | ||
clk_en0_ms_q <= 1'b0; | ||
clk_en1_q <= 1'b0; | ||
clk_en2_q <= 1'b0; | ||
end | ||
else | ||
begin | ||
clk_en0_ms_q <= (clock_div_q == 8'd0); | ||
clk_en1_q <= clk_en0_ms_q; | ||
clk_en2_q <= clk_en1_q; | ||
end | ||
|
||
// BCLK is div256 of MCLK | ||
wire bclk_en_w = !clk_en2_q && clk_en1_q; | ||
|
||
//----------------------------------------------------------------- | ||
// I2S Output Generator | ||
//----------------------------------------------------------------- | ||
always @(posedge clk_i or posedge rst_i) | ||
begin | ||
if (rst_i == 1'b1) | ||
begin | ||
sample_q <= 32'b0; | ||
bit_count_q <= 5'd0; | ||
data_q <= 1'b0; | ||
ws_q <= 1'b0; | ||
bclk_q <= 1'b0; | ||
next_data_q <= 1'b0; | ||
sample_req_q <= 1'b0; | ||
end | ||
else if (bclk_en_w) | ||
begin | ||
// BCLK 1->0 - Falling Edge | ||
if (bclk_q) | ||
begin | ||
bclk_q <= 1'b0; | ||
|
||
data_q <= next_data_q; | ||
next_data_q <= sample_q[5'd31 - bit_count_q]; | ||
|
||
// Word select | ||
ws_q <= bit_count_q[4]; | ||
|
||
// Increment bit position counter | ||
bit_count_q <= bit_count_q + 5'd1; | ||
end | ||
// BCLK 0->1 - Rising Edge | ||
else | ||
begin | ||
bclk_q <= 1'b1; | ||
|
||
// Last bit in first half, buffer remainder and pop word | ||
if (bit_count_q == 5'd0) | ||
begin | ||
sample_q <= {sample_i[15:0], sample_i[31:16]}; | ||
sample_req_q <= 1'b1; | ||
end | ||
end | ||
end | ||
else | ||
sample_req_q <= 1'b0; | ||
end | ||
|
||
//----------------------------------------------------------------- | ||
// I2S DAC Interface | ||
//----------------------------------------------------------------- | ||
assign i2s_mclk_o = mclk_q; | ||
assign i2s_ws_o = ws_q; | ||
assign i2s_bclk_o = bclk_q; | ||
assign i2s_data_o = data_q; | ||
|
||
assign sample_req_o = sample_req_q; | ||
|
||
endmodule |
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,66 @@ | ||
#include "i2s_decoder.h" | ||
|
||
//----------------------------------------------------------------- | ||
// input: Handle rx data | ||
//----------------------------------------------------------------- | ||
void i2s_decoder::input(void) | ||
{ | ||
do | ||
{ | ||
wait(); | ||
} | ||
while (rst_i.read()); | ||
|
||
bool first = true; | ||
int bit_cnt = 0; | ||
sc_uint <I2S_MAX_BITS> data = 0; | ||
sc_uint <I2S_MAX_BITS> rev_data = 0; | ||
bool ws; | ||
|
||
while (true) | ||
{ | ||
if (!first) | ||
{ | ||
// Left | ||
if (!ws) | ||
{ | ||
sc_assert(bit_cnt < m_bits); | ||
|
||
rev_data[bit_cnt] = i2s_data_i.read(); | ||
|
||
if (++bit_cnt == m_bits) | ||
{ | ||
for (int i=0;i<m_bits;i++) | ||
data[m_bits-i-1] = rev_data[i]; | ||
|
||
m_rx_fifo.write(data); | ||
data = 0; | ||
} | ||
} | ||
// Right | ||
else | ||
{ | ||
sc_assert(bit_cnt >= m_bits); | ||
sc_assert(bit_cnt < (m_bits*2)); | ||
|
||
rev_data[bit_cnt-m_bits] = i2s_data_i.read(); | ||
|
||
if (++bit_cnt == (m_bits*2)) | ||
{ | ||
for (int i=0;i<m_bits;i++) | ||
data[m_bits-i-1] = rev_data[i]; | ||
|
||
m_rx_fifo.write(data); | ||
data = 0; | ||
bit_cnt = 0; | ||
} | ||
} | ||
} | ||
else | ||
first = false; | ||
|
||
ws = i2s_ws_i.read(); | ||
|
||
wait(); | ||
} | ||
} |
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,45 @@ | ||
#ifndef I2S_DECODER_H | ||
#define I2S_DECODER_H | ||
|
||
#include <systemc.h> | ||
|
||
#define I2S_MAX_BITS 24 | ||
|
||
//------------------------------------------------------------- | ||
// i2s_decoder: Decoder for I2S interface | ||
//------------------------------------------------------------- | ||
SC_MODULE (i2s_decoder) | ||
{ | ||
public: | ||
// Clock and Reset | ||
sc_in <bool> clk_i; | ||
sc_in <bool> rst_i; | ||
|
||
// I/O | ||
sc_in <bool> i2s_mclk_i; | ||
sc_in <bool> i2s_bclk_i; | ||
sc_in <bool> i2s_ws_i; | ||
sc_in <bool> i2s_data_i; | ||
|
||
// Constructor | ||
SC_HAS_PROCESS(i2s_decoder); | ||
i2s_decoder(sc_module_name name): sc_module(name), | ||
m_rx_fifo(1024) | ||
{ | ||
m_bits = 16; | ||
SC_CTHREAD(input, i2s_bclk_i.pos()); | ||
} | ||
|
||
public: | ||
sc_uint <I2S_MAX_BITS> read(void) { return m_rx_fifo.read(); } | ||
bool read_ready(void) { return m_rx_fifo.num_available() > 0; } | ||
void set_bit_width(int bits) { m_bits = bits; } | ||
|
||
private: | ||
void input(void); | ||
|
||
sc_fifo < sc_uint<I2S_MAX_BITS> > m_rx_fifo; | ||
int m_bits; | ||
}; | ||
|
||
#endif |
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,20 @@ | ||
#include "i2s_driver.h" | ||
|
||
//----------------------------------------------------------------- | ||
// output: Drive tx data | ||
//----------------------------------------------------------------- | ||
void i2s_driver::output(void) | ||
{ | ||
wait(); | ||
sc_assert(m_tx_fifo.num_available() > 0); | ||
|
||
while (true) | ||
{ | ||
sample_data_o.write(m_tx_fifo.read()); | ||
|
||
wait(); | ||
|
||
while (!sample_req_i.read()) | ||
wait(); | ||
} | ||
} |
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,38 @@ | ||
#ifndef I2S_DRIVER_H | ||
#define I2S_DRIVER_H | ||
|
||
#include <systemc.h> | ||
|
||
//------------------------------------------------------------- | ||
// i2s_driver: | ||
//------------------------------------------------------------- | ||
SC_MODULE (i2s_driver) | ||
{ | ||
public: | ||
// Clock and Reset | ||
sc_in <bool> clk_i; | ||
sc_in <bool> rst_i; | ||
|
||
// I/O | ||
sc_in <bool> sample_req_i; | ||
sc_out <sc_uint<32> > sample_data_o; | ||
|
||
// Constructor | ||
SC_HAS_PROCESS(i2s_driver); | ||
i2s_driver(sc_module_name name): sc_module(name), | ||
m_tx_fifo(2048) | ||
{ | ||
SC_CTHREAD(output, clk_i.pos()); | ||
} | ||
|
||
public: | ||
void write(sc_uint <32> data) { m_tx_fifo.write(data); } | ||
bool write_empty(void) { return m_tx_fifo.num_available() == 0; } | ||
|
||
private: | ||
void output(void); | ||
|
||
sc_fifo < sc_uint<32> > m_tx_fifo; | ||
}; | ||
|
||
#endif |
Oops, something went wrong.