📄 smbus_control.vhd
字号:
men_bit_reset <= RESET_ACTIVE;
next_watchdog_state <= WATCHDOG_IDLE;
end case;
end process;
scl_watchdog_regs: process (sys_clk, reset)
begin
if reset = RESET_ACTIVE then
watchdog_state <= WATCHDOG_IDLE;
elsif sys_clk'event and sys_clk='1' then
watchdog_state <= next_watchdog_state;
end if;
end process;
-- ************************ SCL_Generator Process ************************
-- This process generates SCL and SDA when in Master mode. It generates the START
-- and STOP conditions. If arbitration is lost, SCL will be generated until the
-- end of the byte transfer.
scl_generator_comb: process (scl_state, arb_lost, sm_stop, gen_stop, rep_start,
bus_busy, gen_start, master_slave, stop_scl_reg,
clk_cnt, bit_cnt, scl_in, state, sda_out,
sda_out_reg, master_sda, rep_start_det_reg)
begin
-- state machine defaults
scl_out <= '1';
sda_out <= sda_out_reg;
stop_scl <= stop_scl_reg;
clk_cnt_en <= '0';
clk_cnt_rst <= '1';
next_scl_state <= scl_state;
rep_start_det <= rep_start_det_reg;
rsta_rst <= not (RESET_ACTIVE);
case scl_state is
when SCL_IDLE =>
sda_out <= '1';
stop_scl <= '0';
-- leave IDLE state when master, bus is idle, and gen_start
if master_slave = '1' and bus_busy = '0' and gen_start = '1' then
next_scl_state <= START;
end if;
when START =>
-- generate start condition
clk_cnt_en <= '1';
clk_cnt_rst <= '0';
sda_out <= '0';
stop_scl <= '0';
if clk_cnt = START_HOLD then
next_scl_state <= SCL_LOW_EDGE;
if rep_start = '1' then
rsta_rst <= RESET_ACTIVE;
rep_start_det <= '0';
end if;
else
next_scl_state <= START;
end if;
when SCL_LOW_EDGE =>
clk_cnt_rst <= '1';
scl_out <= '0';
next_scl_state <= SCL_LOW;
stop_scl <= '0';
when SCL_LOW =>
clk_cnt_en <= '1';
clk_cnt_rst <= '0';
scl_out <= '0';
-- set SDA_OUT based on control signals
if arb_lost = '1' then
stop_scl <= '0';
elsif ((sm_stop = '1' or gen_stop = '1') and
(state /= ACK_DATA and state /= ACK_HEADER and state /= WAIT_ACK)) then
sda_out <= '0';
stop_scl <= '1';
elsif rep_start_det_reg = '1' then
sda_out <= '1';
stop_scl <= '0';
elsif clk_cnt = DATA_HOLD then
sda_out <= master_sda;
stop_scl <= '0';
else
stop_scl <= '0';
end if;
-- determine next state
if clk_cnt = LOW_CNT then
if bit_cnt = CNT_DONE and arb_lost = '1' then
next_scl_state <= SCL_IDLE;
else
next_scl_state <= SCL_HIGH_EDGE;
end if;
else
next_scl_state <= SCL_LOW;
end if;
when SCL_HIGH_EDGE =>
clk_cnt_rst <= '1';
scl_out <= '1';
if ((sm_stop = '1' or gen_stop = '1') and
(state /= ACK_DATA and state /= ACK_HEADER and state /= WAIT_ACK)) then
stop_scl <= '1';
else
stop_scl <= '0';
end if;
-- this state sets SCL high
-- stay in this state until SCL_IN = 1
-- this will hold the counter in reset until all SCL drivers
-- have released SCL to 1
if scl_in = '0' then
next_scl_state <= SCL_HIGH_EDGE;
else
next_scl_state <= SCL_HIGH;
end if;
when SCL_HIGH =>
-- now all SCL drivers have set SCL to '1'
-- begin count for high time
clk_cnt_en <= '1';
clk_cnt_rst <= '0';
scl_out <= '1';
-- check to see if a repeated start or a stop needs to be
-- generated. If so, only hold SCL high for half of the high time
if clk_cnt = STOP_REP_START_SU then
if rep_start = '1' then
if rep_start_det_reg = '0' then
rep_start_det <= '1';
next_scl_state <= SCL_HIGH;
elsif rep_start_det_reg = '1' then
clk_cnt_rst <= '1';
next_scl_state <= START;
end if;
elsif stop_scl_reg = '1' then
clk_cnt_rst <= '1';
next_scl_state <= STOP_WAIT;
end if;
elsif clk_cnt = HIGH_CNT then
next_scl_state <= SCL_LOW_EDGE;
else
next_scl_state <= SCL_HIGH;
end if;
when STOP_WAIT =>
--this state gives the required free time between stop and start
--conditions
clk_cnt_en <='1';
clk_cnt_rst <= '0';
sda_out <= '1';
stop_scl <= '0';
if clk_cnt = TBUF then
-- clk_cnt_rst <= '1';
-- clk_cnt_en <= '0';
next_scl_state <= SCL_IDLE;
else
next_scl_state <= STOP_WAIT;
end if;
end case;
end process;
scl_generator_regs: process (sys_clk, reset)
begin
if reset = RESET_ACTIVE then
scl_state <= SCL_IDLE;
sda_out_reg <= '1';
scl_out_reg <= '1';
stop_scl_reg <= '0';
rep_start_det_reg <= '0';
elsif sys_clk'event and sys_clk='1' then
scl_state <= next_scl_state;
sda_out_reg <= sda_out;
scl_out_reg <= scl_out;
stop_scl_reg <= stop_scl;
rep_start_det_reg <= rep_start_det;
end if;
end process;
-- ************************ Clock Counter Implementation ************************
-- The following code implements the counter that divides the sys_clock for
-- creation of SCL. Control lines for this counter are set in SCL state machine
CLKCNT : UPCNT9
port map( data => cnt_zero,
cnt_en => clk_cnt_en,
load => clk_cnt_rst,
clr => reset,
clk => sys_clk,
qout => clk_cnt );
-- ************************ Timout Counter Implementation ************************
-- The following code implements the counter that divides the sys_clock for
-- timout testing of SCL. Control lines for this counter are set in the scl_watchdog
-- process.
WATCHDOGCNT : UPCNT21
port map( data => timeout_cnt_zero,
cnt_en => timeout_cnt_en,
load => timeout_cnt_rst,
clr => reset,
clk => sys_clk,
qout => timeout_cnt );
-- ************************ Input Registers Process ************************
-- This process samples the incoming SDA and SCL with the system clock
input_regs: process(sys_clk,reset)
begin
if reset = RESET_ACTIVE then
sda_in <= '1';
scl_in <= '1';
msta_d1 <= '0';
sda_out_reg_d1 <= '1';
-- sda_out_reg_d2 <= '1';
elsif sys_clk'event and sys_clk = '1' then
-- the following if, then, else clauses are used
-- because scl may equal 'H' or '1'
if scl = '0' then
scl_in <= '0';
else
scl_in <= '1';
end if;
if sda = '0' then
sda_in <= '0';
else
sda_in <= '1';
end if;
sda_out_reg_d1 <= sda_out_reg;
-- sda_out_reg_d2 <= sda_out_reg_d1;
msta_d1 <= msta;
end if;
end process;
-- ************************ START/STOP Detect Process ************************
-- This process detects the start and stop conditions.
-- by using SDA as a clock.
start_det: process(sda, reset, state)
begin
if reset = RESET_ACTIVE or state = HEADER then
detect_start <= '0';
elsif sda'event and sda = '0' then
if scl /= '0' then
detect_start <= '1';
else
detect_start <= '0';
end if;
end if;
end process;
stop_det: process(sda, reset, detect_start)
begin
if reset = RESET_ACTIVE or detect_start = '1' then
detect_stop <= '0';
elsif sda'event and sda /= '0' then
if scl /= '0' then
detect_stop <= '1';
else
detect_stop <= '0';
end if;
end if;
end process;
-- ************************ Bus Busy Process ************************
-- This process detects the start and stop conditions and sets the bus busy bit
-- It also describes a delayed version of the bus busy bit which is used to determine
-- MAL. MAL should be set if a start is detected while the bus is busy, however, the code below
-- sets bus_busy as soon as START is detected which would always set MAL. Therefore, a delayed
-- version of bus_busy is generated and used to determine MAL.
set_bus_busy: process(sys_clk,reset)
begin
if reset = RESET_ACTIVE then
bus_busy <= '0';
bus_busy_d1 <= '0';
elsif sys_clk'event and sys_clk = '1' then
bus_busy_d1 <= bus_busy;
if detect_start = '1' then
bus_busy <= '1';
end if;
if detect_stop = '1' then
bus_busy <= '0';
end if;
end if;
end process;
-- ************************ uP Control Bits Process ************************
-- This process detects the rising and falling edges of MSTA and sets signals to
-- control generation of start and stop conditions
-- This process also sets the master slave bit based on MSTA if and only if it is not
-- in the middle of a cycle, i.e. bus_busy = '0'
control_bits: process (sys_clk,reset)
begin
if reset = RESET_ACTIVE then
gen_start <= '0';
gen_stop <= '0';
master_slave <= '0';
elsif sys_clk'event and sys_clk = '1' then
if msta_d1 = '0' and msta = '1' then
-- rising edge of MSTA - generate start condition
gen_start <= '1';
elsif detect_start = '1' then
gen_start <= '0';
end if;
if arb_lost = '0' and msta_d1 = '1' and msta = '0' then
-- falling edge of MSTA - generate stop condition only
-- if arbitration has not been lost
gen_stop <= '1';
elsif detect_stop = '1' then
gen_stop <= '0';
end if;
if bus_busy = '0' then
master_slave <= msta;
else
master_slave <= master_slave;
end if;
end if;
end process;
rep_start <= rsta; -- repeat start signal is RSTA control bit
-- ************************ uP Status Register Bits Processes ************************
-- The following processes and assignments set the bits of the MBUS status register MBSR
--
-- MCF - Data transferring bit
-- While one byte of data is being transferred, this bit is cleared. It is set by the falling edge
-- of the 9th clock of a byte transfer and is not cleared at reset
mcf_bit: process(scl, reset)
begin
if reset = RESET_ACTIVE then
mcf <= '0';
elsif scl'event and scl = '0' then
if bit_cnt = CNT_DONE then
mcf <= '1';
else
mcf <= '0';
end if;
end if;
end process;
-- MAAS - Addressed As Slave Bit
-- When its own specific address (MADR) matches the SMBUS Address, this bit is set. The CPU is
-- interrupted provided the MIEN is set. Then the CPU needs to check the SRW bit and set its
-- TX-RX mode accordingly. Writing to the MBCR clears this bit
maas_bit: process(sys_clk, reset)
begin
if reset = RESET_ACTIVE then
maas <= '0';
elsif sys_clk'event and sys_clk = '1' then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -