Thông báo

Collapse
No announcement yet.

Srl16 rs-232 rx / tx

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Srl16 rs-232 rx / tx

    RS-232 có lẽ là một trong những bài tập rất thường gặp, và synthesize rất gọn khi sử dụng SRL16 (6 SRL16 và 15 registers).

    Chúng ta sẽ sử dụng 16x clock để sample data.

    Serial data input đến từ clock domain khác với 16x FPGA clock domain, nên chúng ta đưa qua 2 registers trước khi sử dụng.

    Code:
      SYNCHRONIZE_DATA : process(clk)
      begin
        if (rising_edge(clk)) then
          if (rst = '1') then
            data_in_dly01 <= '1';
            data_in_dly02 <= '1';
          else
            data_in_dly01 <= data_serial_i;
            data_in_dly02 <= data_in_dly01;
          end if;
        end if; -- clk
      end process SYNCHRONIZE_DATA;

    Khi ở trạng thái idle và serial data input chuyển từ 1 sang 0, chúng ta bắt đầu sample data.

    Sừ dụng 1 register để delay data input thêm một clock nửa.

    Code:
      DELAY_INPUT_DATA : process(clk)
      begin
        if (rising_edge(clk)) then
          if (rst = '1') then
            data_in_dly03 <= '1';
          else
            data_in_dly03 <= data_in_dly02;
          end if;
        end if; -- clk
      end process DELAY_INPUT_DATA;
    Dùng 1 SRL16 để tạo ra start pulse (tìm falling edge của serial data input khi uart_rx_state = '0'):

    Code:
      SRL16_start_pls_inst : SRL16E
      generic map (
        INIT => x"0002"
      )
      port map (
        Q => start_pls,
        A0 => data_in_dly03,
        A1 => data_in_dly02,
        A2 => uart_rx_state,
        A3 => rst,
        CLK => clk,
        CE => '0',
        D => '0'
      );
    Khi start pulse = '1', chuyển uart_rx_state từ '0' sang '1' (dùng 1 register cho uart_rx_state).

    Code:
      MANAGE_UART_RX_STATE : process(clk)
      begin
        if (rising_edge(clk)) then
          if (rst = '1') then
            uart_rx_state <= '0';
          else
            if (start_pls = '1') then
              uart_rx_state <= '1';
            elsif (data_received_pls = '1') then
              uart_rx_state <= '0';
            end if;
          end if;
        end if; -- clk
      end process MANAGE_UART_RX_STATE;

  • #2
    Dùng 1 SRL16 để delay start pulse vào giữa 16x sampling window (dùng làm sampling pulse).

    Code:
      SRL16_sample_data_pls_srl16_a_inst : SRL16E
      port map (
        Q => sample_data_pls_srl16_a,
        A0 => '1',
        A1 => '1',
        A2 => '1',
        A3 => '0',
        CLK => clk,
        CE => '1',
        D => start_pls
      );
    Dùng 1 SRL16 để loop sampling pulse mỗi 16 clock cycles.

    Code:
      SRL16_sample_data_pls_srl16_b_inst : SRL16E
      port map (
        Q => sample_data_pls_srl16_b,
        A0 => '0',
        A1 => '1',
        A2 => '1',
        A3 => '1',
        CLK => clk,
        CE => '1',
        D => sample_data_pls
      );
    Dùng 1 register để ngừng looping sampling pulse khi đã nhận được stop bit.

    Code:
      SAMPLE_DATA_PLS_REG : process(clk)
      begin
        if (rising_edge(clk)) then
          if (stop_pls = '1') then
            sample_data_pls <= '0';
          else
            if (sample_data_pls_srl16_a = '1') then
              sample_data_pls <= '1';
            else
              sample_data_pls <= sample_data_pls_srl16_b;
            end if;
          end if;
        end if; -- clk
      end process SAMPLE_DATA_PLS_REG;



    Đưa start pulse vào 1 SRL16 để tạo ra parity pulse:
    Code:
      SRL16_parity_pls_inst : SRL16E
      port map (
        Q => parity_pls,
        A0 => parity_pls_srl16_addr(0),
        A1 => parity_pls_srl16_addr(1),
        A2 => parity_pls_srl16_addr(2),
        A3 => parity_pls_srl16_addr(3),
        CLK => clk,
        CE => parity_pls_srl16_clk_en,
        D => start_pls
      );
    Đưa sampling pulse và start pulse qua 1 SRL16 làm clock enable cho SRL16 bên trên. Sau khi đã nhận được số data bit, parity pulse sẽ = '1' ở cổng ra của SRL16 bên trên.

    Code:
      SRL16_start_pls_delay_clk_en_inst : SRL16E
      generic map (
        INIT => x"00fe"
      )
      port map (
        Q => parity_pls_srl16_clk_en,
        A0 => sample_data_pls,
        A1 => start_pls,
        A2 => rst,
        A3 => '0',
        CLK => clk,
        CE => '0',
        D => '0'
      );
    Dùng 1 register cho stop pulse (1 bit trễ so với parity pulse).

    Code:
      STOP_PLS_REG : process(clk)
      begin
        if (rising_edge(clk)) then
          if (start_pls = '1') then
            stop_pls <= '0';
          else
            if (rst = '1') then
              stop_pls <= '1';
            elsif (sample_data_pls = '1') then
              stop_pls <= parity_pls;
            end if;
          end if;
        end if; -- clk
      end process STOP_PLS_REG;

    Comment


    • #3
      Chỉ shift data vào khi không phải là stop / parity bit. Dùng 1 SRL16 cho shift data pulse, và 8 registers cho data shift register.

      Code:
          SRL16_shift_data_pls_inst : SRL16E
          generic map (
            INIT => x"0002"
          )
          port map (
            Q => shift_data_pls,
            A0 => sample_data_pls_srl16_b,
            A1 => stop_pls,
            A2 => parity_pls,
            A3 => rst,
            CLK => clk,
            CE => '0',
            D => '0'
          );
      Code:
        SHIFT_DATA_IN : process(clk)
        begin
          if (rising_edge(clk)) then
            if (rst = '1') then
              data_shift_register <= (others => '1');
            elsif (shift_data_pls = '1') then
              data_shift_register <= data_in_dly02 & data_shift_register(data_shift_register'high downto 1);
            end if;
          end if; -- clk
        end process SHIFT_DATA_IN;

      Tổng cộng là 6 SRL16 và 15 registers:

      Comment


      • #4
        Test bench cho UART receiver này rất đơn giản. Viết một procedure để send serial data, và sau đó gọi procedure để send data đến UART receiver. Chúng ta cũng có thể dùng config parameters để cố ý tạo ra parity bit hoặc là stop bit error (UART receiver bên trên chưa có phần detect errors).

        Code:
          tb_uart_rx : PROCESS
          BEGIN
        
            FPGA_SERIAL1_RX <= '1';
        
            wait for 100 us;
            SendUart(x"55", FPGA_SERIAL1_RX, (true, true, false, true));
            wait for 100 us;
            SendUart(x"1C", FPGA_SERIAL1_RX, uart_rx_config);
            wait for 100 us;
            SendUart(x"1D", FPGA_SERIAL1_RX, uart_rx_config);
            wait for 100 us;
            SendUart(x"1E", FPGA_SERIAL1_RX, uart_rx_config);
        
            wait; -- will wait forever
          END PROCESS;
        Attached Files

        Comment


        • #5
          Nếu dùng baud rate 115200, 16x UART clock bằng khoảng 33MHz / 18. Chúng ta có thể chia 33 MHz / 9, và sau đó (33 MHz / 9) / 2.

          Code:
          SRL16_clk_div9_inst : SRL16E
            generic map (
              INIT => x"000f"
            )
            port map (
              Q => clk33MHz_div8,     -- SRL data output
              A0 => '1',              -- Select[0] input
              A1 => '1',              -- Select[1] input
              A2 => '1',              -- Select[2] input
              A3 => '0',              -- Select[3] input
              CLK => clk_33MHz,       -- Clock input,
              CE => '1',
              D => clk33MHz_div9     -- SRL data input
            );
            clk33MHz_div9 <= clk33MHz_div8 when rising_edge(clk_33MHz);
          
            SRL16_clk_uart_inst : SRL16E
            generic map (
              INIT => x"0001"
            )
            port map (
              Q => clk_uart_srl16,    -- SRL data output
              A0 => '0',              -- Select[0] input
              A1 => '0',              -- Select[1] input
              A2 => '0',              -- Select[2] input
              A3 => '0',              -- Select[3] input
              CLK => clk33MHz_div9,   -- Clock input,
              CE => '1',
              D => clk_uart           -- SRL data input
            );
            clk_uart <= clk_uart_srl16 when rising_edge(clk33MHz_div9);
          Dùng SRL16 LCD controller để viết những ký tự đã nhận được. LCD controller initialize và viết RDY trước khi tiếp nhận data.

          Code:
            lcd_controller_inst : entity work.lcd_controller(rtl_srl16)
            port map (
              clk => clk_uart,
              rst => rst,
              ---
              ready_o => lcd_ready,    
              data_valid_i => data_valid,
              data_i => lcd_data_in,
              type_i => lcd_data_type,
              ---
              lcd_rs_o => lcd_rs,
              lcd_rw_o => lcd_rw,
              lcd_enable_o => lcd_e,
              lcd_data_o => lcd_data,
              ---
              timing_pls_b_i => timing_pls_b,
              timing_pls_c_i => timing_pls_c,
              timing_pls_d_i => timing_pls_d
            );


          Code:
          uart_rx_inst : entity work.uart_rx(rtl_srl16)
            port map (
              clk => clk_uart,
              rst => rst,
              data_serial_i => FPGA_SERIAL1_RX,
              data_o => uart_data_out,
              data_valid_o => uart_data_valid_out
            );
          
            DATA_VALID_REG : process (clk_uart)
            begin
              if (rising_edge(clk_uart)) then
                if ((lcd_ready = '1') and (data_valid = '0')) then
                  if (uart_data_valid_out = '1') then
                    data_valid <= '1';
                    lcd_data_in <= uart_data_out;
                    lcd_data_type <= '1';
                  end if;
                else
                  data_valid <= '0';
                end if;
              end if; -- clk
            end process DATA_VALID_REG;


          Tạm thời đưa serial in (RX) ra serial out (TX) để echo trở lại terminal (Putty).
          Code:
          FPGA_SERIAL1_TX <= FPGA_SERIAL1_RX;
          Attached Files

          Comment

          Về tác giả

          Collapse

          nemesis21 Tìm hiểu thêm về nemesis21

          Bài viết mới nhất

          Collapse

          Đang tải...
          X