Thông báo

Collapse
No announcement yet.

SRL16 LCD Controller

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

  • SRL16 LCD Controller

    SRL(16) là shift-register look-up table trong các dòng chip của Xilinx. SRL16 rất hữu ích, và rất phù hợp với một project nhỏ như LCD Controller dùng trong các Xilinx kit.

    Một ứng dụng của SRL16 là dùng để chia clock. Một SRL16 có thể chia clock xuống 16 lần. Một SRL16 + 1 register có thể chia xuống 17 lần, như thí dụ sau đây (SRL16 primitive với clock enable được instantiate):

    Code:
      SRL16_clk_div16_inst : SRL16E
      generic map (
        INIT => x"00ff"
      )
      port map (
        Q => clk33MHz_div16,    
        A0 => '1',              
        A1 => '1',              
        A2 => '1',              
        A3 => '1',              
        CLK => clk_33MHz,
        CE => '1',
        D => clk33MHz_div17
      );
      clk33MHz_div17 <= clk33MHz_div16 when rising_edge(clk_33MHz);
    Mấu chốt ở đây là phần INIT = x"00ff", và address A0/1/2/3.


    Dưới đây là một thí dụ để chia clock xuống 13 lần chỉ dùng 1 SRL16.
    Code:
      SRL16_clk_div13_inst : SRL16E
      generic map (
        INIT => x"003f"
      )
      port map (
        Q => clk33MHz_div13,    
        A0 => '0',              
        A1 => '0',              
        A2 => '1',              
        A3 => '1',              
        CLK => clk_33MHz,       
        CE => '1',
        D => clk33MHz_div13     
      );



    Phương thức này và chân clock enable (CE) có thể được kết hợp để tạo xung. Với 4 SRL16 và 1 register, chúng ta có thể tạo pulses cách nhau ~8ms (clock đầu vào = 33MHz/17).

    Attached Files

  • #2
    Trong các LCD datasheet khác nhau cho cùng một dòng controller, các bước initialization không được đồng nhất, có một số xem ra hơi rườm rà. Phần initialization dưới đây gần như là giản lược nhất (1.53ms bị in nhầm thành 1.53us):




    Bước đầu tiên là chờ ~40 ms. Dùng 1 SRL16 với timing pulse D ở phần trên là clock enable, sau 8 x 7.8ms, init_wait sẽ chuyển từ 1 --> 0, và ready sẽ có thể chuyển sang 1 để tiếp nhận data input.

    Code:
      SRL16_init_wait_inst : SRL16E
      generic map (
        INIT => x"ff00"
      )
      port map (
        Q => init_wait,       
        A0 => '1',            
        A1 => '1',            
        A2 => '1',            
        A3 => '1',            
        CLK => clk,           
        CE => timing_pls_d_i,
        D => '0'              
      );
    Code:
     
      READY_REG : process (clk)
      begin
        if (rising_edge(clk)) then
          if (init_wait = '1') then
            ready <= '0';
          else
           if (ready_pls = '1') then
              ready <= '1';
            elsif (data_valid_i = '1') then
              ready <= '0';
            end if;
          end if;
        end if; -- clk
      end process READY_REG;
    Lưu ý là khi viết đoạn code như bên trên, chúng ta tận dụng cả 3 cổng RESET (init_wait), SET (ready_pls), và CLOCK_ENABLE (data_valid_i) của flip-flop.




    Nếu viết lại đoạn code trên ngắn gọn hơn một chút, thì chúng ta lại phải cần nhiều resources hơn.

    Code:
      READY_REG : process (clk)
      begin
        if (rising_edge(clk)) then
          if (init_wait = '1' or data_valid_i = '1') then
            ready <= '0';
          elsif (ready_pls = '1') then
            ready <= '1';
          end if;
        end if; -- clk
      end process READY_REG;
    Last edited by nemesis21; 03-05-2009, 07:12.

    Comment


    • #3
      LCD instruction và data có 8-bit, nhưng chúng ta chỉ có thể sử dụng 4-bit interface để viết ra LCD. Chúng ta cần phải viết hai lần 4-bit, và phải enable hai lần. Nếu chúng ta có một data valid pulse ở đầu vào (để báo là có 8-bit cần được viết ra LCD), một SRL16 và một register là một lựa chọn tối ưu trong trường hợp này để tạo ra hai 2 enable pulses. Data valid pulse được gán với đầu vào của SRL16, và sau 4 clock cycles, data valid pulse trễ 4 clock sẽ hiện ra ở output của SRL16, gọn hơn so với việc dùng bộ đếm.

      Code:
        SRL16_enable_delay_inst : SRL16E
        port map (
          Q => enable_delayed,
          A0 => '1',            
          A1 => '1',            
          A2 => '0',            
          A3 => '0',            
          CLK => clk,           
          CE => '1',
          D => masked_data_valid
        );
      
        LCD_ENABLE_REG : process (clk)
        begin
          if (rising_edge(clk)) then
            if (masked_data_valid = '1') then
              lcd_enable <= '1';
            else
              lcd_enable <= enable_delayed;
            end if;
          end if; -- clk
        end process LCD_ENABLE_REG;

      Nếu có lúc chúng ta chỉ muốn tạo ra 1 pulse thay vì hai, address a0 và a1 nên được reset thành 0.


      Code:
        
        
        srl_addr <= '0';
      
        SRL16_enable_delay2_inst : SRL16E
        port map (
          Q => enable_delayed2,
          A0 => srl_addr,            
          A1 => srl_addr,            
          A2 => '0',            
          A3 => '0',            
          CLK => clk,           
          CE => '1',
          D => masked_data_valid
        );
      
        LCD_ENABLE2_REG : process (clk)
        begin
          if (rising_edge(clk)) then
            if (masked_data_valid = '1') then
              lcd_enable2 <= '1';
            else
              lcd_enable2 <= enable_delayed2;
            end if;
          end if; -- clk
        end process LCD_ENABLE2_REG;

      Last edited by nemesis21; 03-05-2009, 07:13.

      Comment


      • #4
        Phần việc của LCD controller rất đơn giản. Tiếp nhận 8-bit data/instruction và viết 4-bit data ra LCD.

        Khi ready = '1' thì LCD controller có thể tiếp nhận data. Khi có data vào (được báo bời data_valid = '1') thì ready được reset thành '0'. Theo datasheet, một số data và instruction cần phải đợi ít nhất là 40us, một số instruction phải đợi ít nhất là 1.5ms. Đơn giản nhất là chúng ta có thể đợi ~1.5ms cho tất cả data và instruction.

        Khi data_valid = '1', chúng ta đưa vào cổng input của SRL16 (cũng dùng data_valid là clock enable). Chúng ta cũng dùng timing_pls_c (~.9 ms period) làm clock enable. Sau khi timing_pls_c được assert 2 lần (~1.8 ms), chúng ta sẽ có được ready pulse ở đầu ra.

        Code:
          SRL16_ready_inst : SRL16E
          port map (
            Q => ready_pls,       
            A0 => '1',              
            A1 => '1',              
            A2 => '0',              
            A3 => '0'           
            CLK => clk,             
            CE => ready_pls_ce,
            D => data_valid_i        
          );
        
          ready_pls_ce <= data_valid_i or timing_pls_c_i;
        Khi ready = '1' trở lại, chúng ta có thể tiếp nhận thêm data để viết ra LCD. Rất đơn giản.
        Attached Files

        Comment


        • #5
          Các module ở trên tổng hợp lại như trong đoạn code bên dưới. Khi LCD controller ready, chúng ta đẩy data (type = '0') hoặc instruction (type = '1') vào để viết ra LCD.

          Code:
            
          --------------------------------------------------------------------------------
            --   
            --------------------------------------------------------------------------------
          timing_pls_gen_inst : entity work.timing_pls_gen(rtl)
            port map (
              clk => clk33MHz_div17,
              timing_pls_a_o => timing_pls_a,
              timing_pls_b_o => timing_pls_b,
              timing_pls_c_o => timing_pls_c,
              timing_pls_d_o => timing_pls_d            
            );
          
            lcd_controller_inst : entity work.lcd_write(rtl_srl16)
            port map (
              clk => clk33MHz_div17,
              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        
            );
          
            --------------------------------------------------------------------------------
            --   
            --------------------------------------------------------------------------------
            DATA_VALID_REG : process (clk33MHz_div17)
            begin
              if (rising_edge(clk33MHz_div17)) then
                if ((lcd_ready = '1') and (data_valid = '0') and (data_index < display_string'high)) then
                  data_valid <= '1';
                  lcd_data_in <= std_logic_vector(to_unsigned(character'pos(display_string(data_index)), lcd_data_in'length));
                  lcd_data_type <= type_string(data_index);      
                  data_index <= data_index + 1;
                else
                  data_valid <= '0';
                end if;
              end if; -- clk
            end process DATA_VALID_REG;

          Phần data ROM cũng đơn giản, chúng ta có thể dùng STRING tương tự như khi viết software. (Character " " đầu tiên trong STRING là cần thiết để Modelsim không phàn nàn ... khi synthesized sẽ không được viết ra LCD)

          Code:
            -- 4-bit, 2 lines, 5x8
            constant function_set   : character := '('; --character'val(40); -- 0x28 = 40
            constant display_on     : character := SI;  --character'val(15); -- 0x0f = 15  
            constant clear_display  : character := SOH; --character'val(1); -- 0x01 = 1
            constant goto_line_2    : character := 'À'; --character'val(192); -- 0xC0 = 192
            
            constant display_string : STRING(1 to 30) :=
              " " &
              function_set &
              display_on &
              clear_display &
              "ML506 LCD Demo" &
              goto_line_2 &
              "using SRL16";
          
            constant type_string : std_logic_vector(1 to 30) := -- '1' = data, '0' = instruction
              "1" &
              "0" &
              "0" &
              "0" &            
              "11111111111111" &
              "0" &
              "11111111111"
              ;
          
            signal data_index : natural range 0 to display_string'high := 1;
            signal lcd_data_in : std_logic_vector(7 downto 0) := (others => '0');
            signal lcd_data_type : std_logic := '0';

          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