OpenCores
URL https://opencores.org/ocsvn/smbus_controller/smbus_controller/trunk

Subversion Repositories smbus_controller

[/] [smbus_controller/] [trunk/] [hw/] [sources/] [SMBusAnalyzer.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ldalmasso
------------------------------------------------------------------------
2
-- Engineer:    Dalmasso Loic
3
-- Create Date: 30/10/2024
4
-- Module Name: SMBusAnalyzer
5
-- Description:
6
--      SMBus Analyzer in charge to detect:
7
--          - Bus Busy Detection
8
--          - Bus Inactivity
9
--          - Bus Timeout
10
--          - Bus Arbitration
11
--          - Clock Stretching
12
--
13
-- WARNING: /!\ Require Pull-Up on SMBCLK and SMBDAT pins /!\
14
--
15
-- Generics
16
--              INPUT_CLOCK_FREQ: Module Input Clock Frequency
17
--              SMBUS_CLASS: SMBus Class (100kHz, 400kHz, 1MHz)
18
--
19
-- Ports
20
--              Input   -       i_clock: Module Input Clock
21
--              Input   -       i_reset: Module Reset ('0': No Reset, '1': Reset)
22
--              Input   -       i_smbclk_controller: SMBus Serial Clock from Controller
23
--              Input   -       i_smbclk_line: SMBus Serial Clock bus line
24
--              Input   -       i_smbdat_controller: SMBus Serial Data from Controller
25
--              Input   -       i_smbdat_line: SMBus Serial Data bus line
26
--              Output  -       o_smbus_busy: SMBus Busy detection ('0': Not Busy, '1': Busy)
27
--              Output  -       o_smbus_timeout: SMBus Timeout detection ('0': No Timeout, '1': Timeout)
28
--              Output  -       o_smbus_arbitration: SMBus Arbitration detection ('0': Lost Arbitration, '1': Win Arbitration)
29
--              Output  -       o_smbclk_stretching: SMBus Clock Stretching detection ('0': Not Stretching, '1': Stretching)
30
------------------------------------------------------------------------
31
 
32
LIBRARY IEEE;
33
USE IEEE.STD_LOGIC_1164.ALL;
34
USE IEEE.NUMERIC_STD.ALL;
35
USE IEEE.MATH_REAL."ceil";
36
 
37
ENTITY SMBusAnalyzer is
38
 
39
GENERIC(
40
    INPUT_CLOCK_FREQ: INTEGER := 12_000_000;
41
        SMBUS_CLASS: INTEGER := 100_000
42
);
43
 
44
PORT(
45
        i_clock: IN STD_LOGIC;
46
        i_reset: IN STD_LOGIC;
47
    i_smbclk_controller: IN STD_LOGIC;
48
        i_smbclk_line: IN STD_LOGIC;
49
        i_smbdat_controller: IN STD_LOGIC;
50
    i_smbdat_line: IN STD_LOGIC;
51
    o_smbus_busy: OUT STD_LOGIC;
52
    o_smbus_timeout: OUT STD_LOGIC;
53
    o_smbus_arbitration: OUT STD_LOGIC;
54
        o_smbclk_stretching: OUT STD_LOGIC
55
);
56
 
57
END SMBusAnalyzer;
58
 
59
ARCHITECTURE Behavioral of SMBusAnalyzer is
60
 
61
------------------------------------------------------------------------
62
-- Constant Declarations
63
------------------------------------------------------------------------
64
-- SMBus Classes (100kHz, 400kHz, 1MHz)
65
constant SMBUS_100K_CLASS: INTEGER := 100_000;
66
constant SMBUS_400K_CLASS: INTEGER := 400_000;
67
constant SMBUS_1M_CLASS: INTEGER := 1_000_000;
68
 
69
-- SMBus Minimum Free Time (only after Stop condition)
70
-- SMBus 100kHz Class: 4.7 µs
71
-- SMBus 400kHz Class: 1.3 µs
72
-- SMBus 1MHz Class: 0.5 µs
73
constant SMBUS_100K_MIN_FREE_TIME_NS: INTEGER := 4700;
74
constant SMBUS_400K_MIN_FREE_TIME_NS: INTEGER := 1300;
75
constant SMBUS_1M_MIN_FREE_TIME_NS: INTEGER := 500;
76
 
77
-- SMBus Minimum Free Time Cycles ('/1_000_000_000' -> SMBus Minimum Free Time in ns)
78
constant SMBUS_100K_MIN_FREE_TIME_CYCLES: INTEGER := INTEGER(CEIL(REAL(SMBUS_100K_MIN_FREE_TIME_NS * INPUT_CLOCK_FREQ) / REAL(1_000_000_000)));
79
constant SMBUS_400K_MIN_FREE_TIME_CYCLES: INTEGER := INTEGER(CEIL(REAL(SMBUS_400K_MIN_FREE_TIME_NS * INPUT_CLOCK_FREQ) / REAL(1_000_000_000)));
80
constant SMBUS_1M_MIN_FREE_TIME_CYCLES: INTEGER := INTEGER(CEIL(REAL(SMBUS_1M_MIN_FREE_TIME_NS * INPUT_CLOCK_FREQ) / REAL(1_000_000_000)));
81
 
82
-- SMBus Inactivity (50 µs)
83
constant SMBUS_INACTIVITY_US: INTEGER := 50;
84
 
85
-- SMBus Inactivity Cycles ('/1_000_000' -> SMBus Inactivity in µs)
86
constant SMBUS_INACTIVITY_CYCLES: INTEGER := INTEGER(CEIL(REAL(SMBUS_INACTIVITY_US * INPUT_CLOCK_FREQ) / REAL(1_000_000)));
87
 
88
-- SMBus Timeout (35 ms)
89
constant SMBUS_TIMEOUT_MS: INTEGER := 35;
90
 
91
-- SMBus Timeout Cycles ('/1_000' -> SMBus Timeout in ms)
92
constant SMBUS_TIMEOUT_CYCLES: INTEGER := INTEGER(CEIL(REAL(SMBUS_TIMEOUT_MS * INPUT_CLOCK_FREQ) / REAL(1_000)));
93
 
94
------------------------------------------------------------------------
95
-- Signal Declarations
96
------------------------------------------------------------------------
97
-- SMBus SMBCLK / SMBDAT Line Levels
98
signal smbclk_line_level: STD_LOGIC := '0';
99
signal smbdat_line_level: STD_LOGIC := '0';
100
signal smbdat_line_level_reg: STD_LOGIC := '0';
101
 
102
-- SMBus Start & Stop Conditions
103
signal smbus_start_cond: STD_LOGIC := '0';
104
signal smbus_stop_cond: STD_LOGIC := '0';
105
 
106
-- SMBus Busy & Timing Counter
107
signal smbus_busy: STD_LOGIC := '0';
108
signal busy_timing_counter: INTEGER range 0 to SMBUS_INACTIVITY_CYCLES := 0;
109
signal busy_timing_counter_end: STD_LOGIC := '0';
110
 
111
-- SMBus Timeout
112
signal timeout_counter: INTEGER range 0 to SMBUS_TIMEOUT_CYCLES := 0;
113
 
114
-- SMBus Arbitration
115
signal smbus_arbitration: STD_LOGIC := '0';
116
 
117
-- SMBus Clock Stretching
118
signal smbclk_stretching: STD_LOGIC := '0';
119
 
120
------------------------------------------------------------------------
121
-- Module Implementation
122
------------------------------------------------------------------------
123
begin
124
        ---------------------------------------
125
        -- SMBus SMBCLK Line Level Converter --
126
        ---------------------------------------
127
        -- Convert 'Z' into '1' level
128
        smbclk_line_level <= '0' when i_smbclk_line = '0' else '1';
129
 
130
        ---------------------------------------
131
        -- SMBus SMBDAT Line Level Converter --
132
        ---------------------------------------
133
        -- Convert 'Z' into '1' level
134
        smbdat_line_level <= '0' when i_smbdat_line = '0' else '1';
135
 
136
        -- SMBDAT Line Level Register
137
        process(i_clock)
138
        begin
139
                if rising_edge(i_clock) then
140
                        smbdat_line_level_reg <= smbdat_line_level;
141
                end if;
142
        end process;
143
 
144
        -------------------------------------
145
        -- SMBus Start Condition Detection --
146
        -------------------------------------
147
        process(i_clock)
148
        begin
149
                if rising_edge(i_clock) then
150
 
151
                        -- Start Condition (SMBCLK High while SDA High to Low)
152
                        if (smbclk_line_level = '1') and (smbdat_line_level_reg = '1') and (smbdat_line_level = '0') then
153
                                smbus_start_cond <= '1';
154
                        else
155
                                smbus_start_cond <= '0';
156
                        end if;
157
                end if;
158
        end process;
159
 
160
        ------------------------------------
161
        -- SMBus Stop Condition Detection --
162
        ------------------------------------
163
        process(i_clock)
164
        begin
165
                if rising_edge(i_clock) then
166
 
167
                        -- Stop Condition Detection while SMBus Busy
168
                        if (smbus_busy = '1') then
169
 
170
                                -- Stop Condition (SMBCLK High while SDA Low to High)
171
                                if (smbclk_line_level = '1') and (smbdat_line_level_reg = '0') and (smbdat_line_level = '1') then
172
                                        smbus_stop_cond <= '1';
173
                                end if;
174
 
175
                        -- Disable Stop Condition (SMBus NOT Busy)
176
                        else
177
                                smbus_stop_cond <= '0';
178
 
179
                        end if;
180
                end if;
181
        end process;
182
 
183
        -------------------------------
184
        -- SMBus Busy Timing Counter --
185
        -------------------------------
186
        process(i_clock)
187
        begin
188
                if rising_edge(i_clock) then
189
 
190
                        -- Reset Counter when Reset or SMBCLK / SMBDAT toggle
191
                        if (i_reset = '1') or (smbclk_line_level = '0') or (smbdat_line_level = '0') then
192
                                busy_timing_counter <= 0;
193
 
194
                        -- Increment Counter (SMBCLK & SMBDAT High)
195
                        else
196
                                busy_timing_counter <= busy_timing_counter +1;
197
                        end if;
198
                end if;
199
        end process;
200
 
201
        -- Busy Timing Counter End
202
        busy_timing_counter_end <=      '1' when smbus_stop_cond = '1' and busy_timing_counter = SMBUS_100K_MIN_FREE_TIME_CYCLES and SMBUS_CLASS = SMBUS_100K_CLASS else
203
                                                                '1' when smbus_stop_cond = '1' and busy_timing_counter = SMBUS_400K_MIN_FREE_TIME_CYCLES and SMBUS_CLASS = SMBUS_400K_CLASS else
204
                                                                '1' when smbus_stop_cond = '1' and busy_timing_counter = SMBUS_1M_MIN_FREE_TIME_CYCLES and SMBUS_CLASS = SMBUS_1M_CLASS else
205
                                                                '1' when busy_timing_counter = SMBUS_INACTIVITY_CYCLES else
206
                                                                '0';
207
 
208
        --------------------------
209
        -- SMBus Busy Detection --
210
        --------------------------
211
        process(i_clock)
212
        begin
213
                if rising_edge(i_clock) then
214
 
215
                        -- Bus IDLE when Reset / Stop Condition then Minimum Free Time or after Inactivity Period
216
                        if (i_reset = '1') or (busy_timing_counter_end = '1') then
217
                                smbus_busy <= '0';
218
 
219
                        -- Bus BUSY when Start Condition (SMBCLK High while SDA High to Low)
220
                        elsif (smbus_start_cond = '1') then
221
                                smbus_busy <= '1';
222
 
223
                        end if;
224
                end if;
225
        end process;
226
        o_smbus_busy <= smbus_busy;
227
 
228
        ---------------------------
229
        -- SMBus Timeout Counter --
230
        ---------------------------
231
        process(i_clock)
232
        begin
233
                if rising_edge(i_clock) then
234
 
235
                        -- Reset Counter when Reset or SMBCLK is High
236
                        if (i_reset = '1') or (smbclk_line_level = '1') then
237
                                timeout_counter <= 0;
238
 
239
                        -- Increment Counter
240
                        else
241
                                timeout_counter <= timeout_counter +1;
242
                        end if;
243
                end if;
244
        end process;
245
 
246
        -- SMBus Timeout
247
        o_smbus_timeout <=      '1' when timeout_counter = SMBUS_TIMEOUT_CYCLES else '0';
248
 
249
        ---------------------------
250
        -- SMBus Bus Arbitration --
251
        ---------------------------
252
        process(i_clock)
253
        begin
254
                if rising_edge(i_clock) then
255
 
256
                        -- SMBDAT from Controller = SMBDAT Line (when SMBCLK is High)
257
                        if (smbclk_line_level = '1') then
258
                                smbus_arbitration <= i_smbdat_controller xnor smbdat_line_level;
259
                        end if;
260
 
261
                end if;
262
        end process;
263
    o_smbus_arbitration <= smbus_arbitration;
264
 
265
    -----------------------------
266
        -- SMBus SMBCLK Stretching --
267
        -----------------------------
268
        process(i_clock)
269
        begin
270
                if rising_edge(i_clock) then
271
 
272
                        -- SMBus Controller release SMBCLK ('Z') while SMBus Target pull-down SMBCLK
273
                        smbclk_stretching <= i_smbclk_controller and not(smbclk_line_level);
274
 
275
                end if;
276
        end process;
277
        o_smbclk_stretching <= smbclk_stretching;
278
 
279
end Behavioral;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.