📄 uart.vhd
字号:
-- assumes that shift happens at the rollovers if tf1_16'event and tf1_16 = 0 then case i is when 0 => txd_wr <= '0'; -- start bit when 9 => txd_wr <= tb8; -- 9th bit when 10 => txd_wr <= '1'; -- stop bit ti_set <= '1'; when 11 => to_send := '0'; -- time to stop when others => txd_wr <= sbuf_dup(i-1); -- shift the byte out end case; i := i+1; end if; when others => null; end case;end if;end process;-- process to receive data from outside-- reception start conditions:-- for mode 0 the condition is ri = '0' and ren = '1'-- for other modes the condition is ren = '1' and falling edge of rxdprocess (sm_r(2 downto 1), cycle_state, rf1_16, p2clk_16, rxd)variable i : integer := 0; -- iteration countervariable samp1, samp2, samp3, rcvd_bit : std_logic;variable sbuf_dup : byte; -- internal buffer for sbuf-- indicate whether reception is in sessionvariable rcv_in_session : std_logic := '0';begin-- if sm_r(2 downto 1) is changed, clear the current processif sm_r(2 downto 1)'event then rcv_in_session := '0'; end if;case sm_r(2 downto 1) is when "00" => -- mode 0, 8-bit shift register, Fxtal1/12 -- shift clock is output through txd -- shift clock is low during s3, s4, s5, high during s6, s1, s2 -- actual data is sampled in through rxd during s5p2 if cycle_state'event and ri = '0' and ren = '1' then if rcv_in_session = '0' then -- initiate reception rcv_in_session := '1'; i := 0; ri_set <= '0'; -- lower ri_set signal to create an edge later else -- already in reception case cycle_state is when s1p1 => if i = 9 then -- time to stop sbuf_rd <= sbuf_dup; ri_set <= '1'; -- set ri rcv_in_session := '0'; end if; when s3p1 => if i /= 0 then txd_rd <= '0'; end if; -- assume that ri is cleared after s5p2 in the cycle when s5p2 => if i /= 0 then sbuf_dup(i-1) := rxd; end if; i := i + 1; when s6p1 => if i /= 0 then txd_rd <= '1'; end if; when others => null; end case; end if; end if; when "01" => -- mode 1, 8-bit UART, baud rate set by timer 1 -- we can change this falling edge detection into sampling if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then rcv_in_session := '1'; rf1_16_reset <= '1'; -- reset the counter immediately i := 0; rb8_set <= '0'; rb8_reset <= '0'; ri_set <= '0'; end if; if rf1_16'event and (rcv_in_session = '1') then case rf1_16 is when 7 => samp1 := rxd; -- first sample when 8 => samp2 := rxd; -- second sample when 9 => samp3 := rxd; -- third sample -- take the value which appears at least twice, for noise rejection if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2; else rcvd_bit := samp1; end if; if i = 0 then -- start bit if rcvd_bit /= '0' then -- false start bit, start over rcv_in_session := '0'; rf1_16_reset <= '0'; end if; elsif i = 9 then -- stop bit -- two conditions to meet for successful reception completion if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then sbuf_rd <= sbuf_dup; -- save rcvd_bit in rb8 if rcvd_bit = '1' then rb8_set <= '1'; else rb8_reset <= '1'; end if; ri_set <= '1'; end if; rcv_in_session := '0'; rf1_16_reset <= '0'; else sbuf_dup(i-1) := rcvd_bit; -- data bits end if; i := i + 1; when others => null; end case; end if; when "10" => -- mode 2, 9-bit UART, Fxtal1/64 or Fxtal1/32 -- we can change this falling edge detection into sampling if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then rcv_in_session := '1'; p2clk_16_reset <= '1'; -- reset the counter i := 0; rb8_set <= '0'; rb8_reset <= '0'; ri_set <= '0'; end if; if p2clk_16'event and (rcv_in_session = '1') then case p2clk_16 is when 7 => samp1 := rxd; -- first sample when 8 => samp2 := rxd; -- second sample when 9 => samp3 := rxd; -- third sample -- take the value which appears at least twice, for noise rejection if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2; else rcvd_bit := samp1; end if; if i = 0 then -- start bit if rcvd_bit /= '0' then -- false start bit, start over rcv_in_session := '0'; p2clk_16_reset <= '0'; end if; elsif i = 9 then -- stop bit -- two conditions to meet for successful reception completion if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then sbuf_rd <= sbuf_dup; -- save rcvd_bit in rb8 if rcvd_bit = '1' then rb8_set <= '1'; else rb8_reset <= '1'; end if; ri_set <= '1'; end if; rcv_in_session := '0'; p2clk_16_reset <= '0'; else sbuf_dup(i-1) := rcvd_bit; -- data bits end if; i := i + 1; when others => null; end case; end if; when "11" => -- mode 3, 9-bit UART, baud rate set by timer 1 -- we can change this falling edge detection into sampling if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then rcv_in_session := '1'; rf1_16_reset <= '1'; -- reset the counter i := 0; rb8_set <= '0'; rb8_reset <= '0'; ri_set <= '0'; end if; if rf1_16'event and (rcv_in_session = '1') then case rf1_16 is when 7 => samp1 := rxd; -- first sample when 8 => samp2 := rxd; -- second sample when 9 => samp3 := rxd; -- third sample -- take the value which appears at least twice, for noise rejection if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2; else rcvd_bit := samp1; end if; if i = 0 then -- start bit if rcvd_bit /= '0' then -- false start bit, start over rcv_in_session := '0'; rf1_16_reset <= '0'; end if; elsif i = 9 then -- stop bit -- two conditions to meet for successful reception completion if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then sbuf_rd <= sbuf_dup; -- save rcvd_bit in rb8 if rcvd_bit = '1' then rb8_set <= '1'; else rb8_reset <= '1'; end if; ri_set <= '1'; end if; rcv_in_session := '0'; rf1_16_reset <= '0'; else sbuf_dup(i-1) := rcvd_bit; -- data bits end if; i := i + 1; when others => null; end case; end if; when others => null;end case;end process;-- the rxd signal has got two drivers: outside and transmitter-- in mode 0 both can drive rxd-- in other modes only outside drives rxd-- when transmitter is not driving it outputs 'H'-- process to resolve the txd signal-- it's got two drivers: transmitter and receiver-- in mode 0 both transmitter and receiver can drive txd-- in other modes only transmitter drives txd-- when one is not driving txd, it outputs '1'txd <= txd_wr and txd_rd;-- process to generate the divide-by-16 counter of timer 1 overflow signal-- the clock of this counter is 16 times slower than the timer 1 overflow signal-- we don't know in which cycle_state tf1 will be set-- so have to synchronize it with s1p1process (tf1, cycle_state, tf1_16_reset, rf1_16_reset)variable tf1_flag : bit := '0';variable tf1_half : bit := '0';begin-- rising edge of tf1_16_reset clears the counter-- could be level-triggeredif rising_edge(tf1_16_reset) then tf1_16 <= 0; end if;if rising_edge(rf1_16_reset) then rf1_16 <= 0; end if;--if rising_edge(tf1) then tf1_flag := '1'; end if;--if cycle_state'event and cycle_state = s1p1 and tf1_flag = '1' thenif rising_edge(tf1) then if smod = '0' then -- cut the frequency in half tf1_half := not tf1_half; end if; if not (smod = '0' and tf1_half = '1') then -- increment the counter tf1_16 <= (tf1_16 + 1) mod 16; rf1_16 <= (rf1_16 + 1) mod 16; --tf1_flag := '0'; end if;end if;end process;-- process to generate the divide-by-16 counter of the phase 2 clock-- phase 2 clock is twice as slow as the xtal1 clockprocess (p2clk, p2clk_16_reset)variable p2clk_half : bit := '0';begin-- rising edge of p2clk_16_reset clears the counter-- could be level-triggeredif rising_edge(p2clk_16_reset) then p2clk_16 <= 0; end if;-- it could be rising edge depending on how it aligns with cycle_stateif falling_edge(p2clk) then if smod = '0' then -- cut the frequency in half p2clk_half := not p2clk_half; end if; if not (smod = '0' and p2clk_half = '1') then -- increment the counter p2clk_16 <= (p2clk_16 + 1) mod 16; end if;end if;end process;end behave;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -