diff --git a/rtl/test_sincos_serial.vhdl b/rtl/test_sincos_serial.vhdl index b278d47..fa4aac7 100644 --- a/rtl/test_sincos_serial.vhdl +++ b/rtl/test_sincos_serial.vhdl @@ -17,7 +17,7 @@ entity test_sincos_serial is generic ( -- Clock frequency divider from system clock to serial bitrate. -- bitrate = system_clock_frequency / serial_bitrate_divider - serial_bitrate_divider: integer range 10 to 8191; + serial_bitrate_divider: integer range 10 to 8192; -- Select core. -- 1 = 18-bit sin/cos generator; @@ -65,10 +65,21 @@ architecture rtl of test_sincos_serial is signal r_ser_rx_strobe: std_logic; signal r_ser_rx_byte: std_logic_vector(7 downto 0); + signal r_ser_rx_glitch: std_logic_vector(7 downto 0); + signal r_ser_rx_bit: std_logic; + signal r_ser_rx_timer: unsigned(12 downto 0); + signal r_ser_rx_timeout: std_logic; + signal r_ser_rx_state; std_logic_vector(1 downto 0); + signal r_ser_rx_shift: std_logic_vector(8 downto 0); signal r_ser_tx_strobe: std_logic; signal r_ser_tx_busy: std_logic; signal r_ser_tx_byte: std_logic_vector(7 downto 0); + signal r_ser_tx_bit: std_logic; + signal r_ser_tx_timer: unsigned(12 downto 0); + signal r_ser_tx_timeout: std_logic; + signal r_ser_tx_bitcnt: unsigned(3 downto 0); + signal r_ser_tx_shift: std_logic_vector(7 downto 0); begin @@ -169,7 +180,129 @@ begin -- TODO : byte-level protocol --- TODO : serial port RX machine --- TODO : serial port TX machine + -- Synchronous process. + -- Serial port RX machine. + process (clk) is + begin + if rising_edge(clk) then + + -- Default. + r_ser_rx_strobe <= '0'; + + -- Deglitch filter. + r_ser_rx_glitch <= r_ser_rx_glitch(6 downto 0) & ser_rx; + if r_ser_rx_glitch(7 downto 1) = "0000000" then + r_ser_rxbit <= '0'; + elsif r_ser_rx_glitch(7 downto 1) = "1111111" then + r_ser_rxbit <= '1'; + end if; + + -- Bit timer. + r_ser_rx_timer <= r_ser_rx_timer - 1; + if r_ser_rx_timer = 0 then + r_ser_rx_timeout <= '1'; + else + r_ser_rx_timeout <= '0'; + end if; + + -- RX state machine. + if r_ser_rx_state = "00" then + -- Wait for idle level. + if r_ser_rx_bit = '1' then + r_ser_rx_state <= "01"; + end if; + elsif r_ser_rx_state = "01" then + -- Wait for start of byte. + r_ser_rx_shift(7 downto 0) <= (others => '0'); + r_ser_rx_shift(8) <= '1'; + r_ser_rx_timer <= to_unsigned(serial_bitrate_divider / 2 - 2, 13); + r_ser_rx_timeout <= '0'; + if r_ser_rx_bit = '0' then + r_ser_rx_state <= "10"; + end if; + elsif r_ser_rx_state = "10" then + -- Wait for data bit. + if r_ser_rx_timeout = '1' then + r_ser_rx_shift <= r_ser_rx_bit & r_ser_rx_shift(8 downto 1); + if r_ser_rx_shift(0) = '1' then + -- Reached end of byte. + if r_ser_rx_bit = '1' then + -- Got valid stop bit. + r_ser_rx_strobe <= '1'; + r_ser_rx_state <= "01"; + else + -- Got invalid stop bit. + r_ser_rx_state <= "00"; + end if; + r_ser_rx_state <= "11"; + end if; + r_ser_rx_timer <= to_unsigned(serial_bitrate_divider - 2); + end if; + else + -- Invalid state. + r_ser_rx_state <= "00"; + end if; + + -- Synchronous reset. + if rst = '1' then + r_ser_rx_state <= "00"; + r_ser_rx_strobe <= '0'; + end if; + + end if; + end process; + + -- Synchronous process. + -- Serial port TX machine. + process (clk) is + begin + if rising_edge(clk) then + + -- Drive output register. + ser_tx <= r_ser_tx_bit; + + -- Bit timer. + r_ser_tx_timer <= r_ser_tx_timer - 1; + if r_ser_tx_timer = 0 then + r_ser_tx_timeout <= '1'; + else + r_ser_tx_timeout <= '0'; + end if; + + if r_ser_tx_busy = '0' then + + -- Wait for start of byte. + r_ser_tx_timer <= to_unsigned(serial_bitrate_divider - 2, 13); + r_ser_tx_timeout <= '0'; + r_ser_tx_shift <= r_ser_tx_byte; + r_ser_tx_bitcnt <= to_unsigned(9, 4); + if r_ser_tx_strobe = '1' then + -- Start new byte. + r_ser_tx_bit <= '0'; + r_ser_tx_busy <= '1'; + end if; + + elsif r_ser_tx_busy = '1' and r_ser_tx_timout = '1' then + + -- Send next bit. + r_ser_tx_bit <= r_ser_tx_shift(0); + r_ser_tx_shift <= "1" & r_ser_tx_shift(7 downto 1); + r_ser_tx_bitcnt <= r_ser_tx_bitcnt - 1; + r_ser_tx_timer <= to_unsigned(serial_bitrate_divider - 2, 13); + if r_ser_tx_bitcnt = 0 then + -- Just completed stop bit. + r_ser_tx_busy <= '0'; + end if; + + end if; + + -- Synchronous reset. + if rst = '1' then + r_ser_tx_busy <= '0'; + r_ser_tx_bit <= '1'; + end if; + + end if; + end process; end architecture;