Repository navigation
Expand file tree
/
Copy pathtdm8_in.vhd
More file actions
183 lines (158 loc) · 5.7 KB
/
Copy pathtdm8_in.vhd
File metadata and controls
183 lines (158 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
---------------------------------------------------------------------------------
-- Engineer: Based on i2s_in by Klimann Wendelin
--
-- Create Date: 2026
-- Design Name: tdm8_in
--
-- Description:
--
-- This module provides a bridge between a TDM-8 serial device (audio ADC) and
-- a parallel device (FPGA logic, ringbuffer).
--
-- TDM-8 format: 8 channels time-multiplexed on a single data line.
-- FSYNC indicates frame start (active high for one BCLK cycle or first slot).
-- Each slot is 32 bits wide, total frame = 256 BCLK cycles.
-- Data is MSB-first, left-justified within each 32-bit slot.
-- Only the first 'width' bits of each slot are captured.
--
-- Input takes:
-- -DIN TDM serial data
-- -BIT_CLK Bit clock (256*fs for 8 channels x 32 bits)
-- -FSYNC Frame sync (rising edge marks start of channel 0)
-- -SYS_CLK System Clock for CDC
-- -RESET Asynchronous Reset (Active Low)
--
-- Output provides:
-- -DATA_CH0..DATA_CH7 parallel audio words (on SYS_CLK domain)
-- -DATA_RDY pulse when all 8 channels have been captured (on SYS_CLK domain)
--
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tdm8_in is
generic (width : integer := 24);
port (
-- TDM ports
FSYNC : in std_logic; -- Frame sync (rising edge = start of frame)
BIT_CLK : in std_logic; -- Bit clock (256*fs)
DIN : in std_logic; -- Serial data input
-- Control ports
RESET : in std_logic; -- Asynchronous Reset (Active Low)
SYS_CLK : in std_logic; -- System Clock for CDC
-- Parallel output ports
data_out : out STD_LOGIC_VECTOR(width * 8 - 1 downto 0);
-- Output status
DATA_RDY : out std_logic -- Pulse when frame is complete
);
end tdm8_in;
architecture rtl of tdm8_in is
-- BIT_CLK domain signals
signal shift_reg : std_logic_vector(width - 1 downto 0);
signal bit_count : integer range 0 to 31;
signal slot_count : integer range 0 to 7;
signal fsync_prev : std_logic;
signal frame_active : std_logic;
-- Channel data registers (BIT_CLK domain)
type channel_array_t is array (0 to 7) of std_logic_vector(width - 1 downto 0);
signal ch_data : channel_array_t;
signal data_rdy_int : std_logic;
-- CDC synchronizer signals
signal data_rdy_sync1 : std_logic;
signal data_rdy_sync2 : std_logic;
signal data_rdy_prev : std_logic;
-- SYS_CLK domain latched data
signal ch_data_sys : channel_array_t;
begin
-------------------------------------------------------------------------
-- TDM Serial to Parallel (BIT_CLK Domain)
-- FSYNC rising edge marks the start of slot 0.
-- Data is sampled on rising edge of BIT_CLK, MSB first.
-- Each slot is 32 BCLK wide; only first 'width' bits are captured.
-------------------------------------------------------------------------
tdm_in_proc : process (RESET, BIT_CLK)
begin
if (RESET = '0') then
shift_reg <= (others => '0');
bit_count <= 0;
slot_count <= 0;
fsync_prev <= '0';
frame_active <= '0';
data_rdy_int <= '0';
for i in 0 to 7 loop
ch_data(i) <= (others => '0');
end loop;
elsif rising_edge(BIT_CLK) then
-- Default: clear ready pulse
data_rdy_int <= '0';
-- Detect FSYNC rising edge
fsync_prev <= FSYNC;
if (FSYNC = '1' and fsync_prev = '0') then
-- Frame start: sample first bit (MSB of channel 0) on this edge
frame_active <= '1';
slot_count <= 0;
bit_count <= 1;
shift_reg <= (others => '0');
shift_reg(0) <= DIN;
elsif (frame_active = '1') then
-- Shift in data
if (bit_count < width) then
shift_reg(width - 1 downto 1) <= shift_reg(width - 2 downto 0);
shift_reg(0) <= DIN;
end if;
if (bit_count = 31) then
-- End of slot: store captured data and advance
ch_data(slot_count) <= shift_reg;
bit_count <= 0;
shift_reg <= (others => '0');
if (slot_count < 7) then
slot_count <= slot_count + 1;
else
-- Slot 7 just captured: full frame complete
data_rdy_int <= '1';
frame_active <= '0';
end if;
else
bit_count <= bit_count + 1;
end if;
end if;
end if;
end process tdm_in_proc;
-------------------------------------------------------------------------
-- 2-Flip-Flop Synchronizer: BIT_CLK -> SYS_CLK
-------------------------------------------------------------------------
sync_rdy : process (RESET, SYS_CLK)
begin
if (RESET = '0') then
data_rdy_sync1 <= '0';
data_rdy_sync2 <= '0';
elsif rising_edge(SYS_CLK) then
data_rdy_sync1 <= data_rdy_int;
data_rdy_sync2 <= data_rdy_sync1;
end if;
end process sync_rdy;
-------------------------------------------------------------------------
-- Data Transfer to SYS_CLK Domain
-------------------------------------------------------------------------
data_transfer : process (RESET, SYS_CLK)
begin
if (RESET = '0') then
for i in 0 to 7 loop
ch_data_sys(i) <= (others => '0');
end loop;
data_rdy_prev <= '0';
DATA_RDY <= '0';
elsif rising_edge(SYS_CLK) then
data_rdy_prev <= data_rdy_sync2;
if (data_rdy_sync2 = '1' and data_rdy_prev = '0') then
-- Rising edge: latch all channels
for i in 0 to 7 loop
data_out((i+1) * width - 1 downto i*width) <= ch_data(i);
end loop;
DATA_RDY <= '1';
elsif (data_rdy_sync2 = '0' and data_rdy_prev = '1') then
DATA_RDY <= '0';
end if;
end if;
end process data_transfer;
end rtl;