Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

driving character lcd

Hi all.

I am wondering how to drive the character lcd on the Cyclone III development kit. I can understand as far as driving a seven segment display. I assume it is almost the same concept i.e. some form of mapping to the character codes are required.

I have a written an arithmetic block in verilog and would like to display the answer on the character lcd. Is it just adding another verilog module to do this, or does it involve something else?

I had a look at the fpgaforfun link http://www.fpga4fun.com/textlcdmodule.html

and cannot understand where the 'C' part comes in.

Thanks.

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Usually the LCD is driven by a CPU and some software written in C.

    You could control the LCD from pure HDL instead but you'll have to handle the communication protocol yourself, probably using a state machine.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks. Since I'm focusing on the arithmetic block part, and the text lcd is just for display, I guess it's better for me to do the usual way like you mentioned. But how... is the CPU you mentioned available as a Megafunction to be instantiated?

    Why isn't there any instruction which tells how to do this?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You can use the Sopc builder tool to create a Nios II CPU with a LCD controller.

    There are some tutorials available on the Altera web site about Nios systems design.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello,

    I'm posting my working Verilog state machine for driving the Character LCD. Sorry there are not many comments. This module requires a 5MHz clock for correct LCD timing. The module initializes the LCD according to the some constants that you can modify as you wish.

    Asserting the write input will start an LCD write cycle, which writes the a character on the text bus to the current cursor position. Change the cursor position by asserting the write and addr inputs together, with the new cursor position on the text bus.

    Thomas

     
    module LCD_driver_char (input clk, input wire addr, input wire  text, input wire write, output busy, output reg LCD_RS = 0, output reg LCD_RW = 0, output reg LCD_E = 0, inout  LCD_data); 
     assign LCD_data = LCD_RW ? 8'bzzzzzzzz : data_reg;
     assign busy = ~|state || ~state || state;
     reg  state;
     reg  countclk;
     reg  data_reg;
     reg  text_hold;
     reg addr_hold;
     initial begin
      state <= 0;
      countclk <= 0;
      data_reg <= 0;
      text_hold <= 0;
      addr_hold <= 0;
     end
     always @ (posedge clk) begin
      if (write) begin
       state <= 1'b1;
       text_hold <= text;
       addr_hold <= addr;
      end
      if (state == 2'b00) begin
       if (countclk == 200000) state <= 6'b010000;
       else countclk <= countclk + 1'b1;
      end else if (state == 2'b01) begin
       if (~state) begin
        state <= 2'b10;
        countclk <= 20'h00000;
        LCD_RW <= 0;
        LCD_RS <= 0;
        if (state == 2'b00) begin
         data_reg <= 8'b00111000; // Function Set
         state <= 2'b01;
        end else if (state == 2'b01) begin
         data_reg <= 8'b00001110; // Display Config
         state <= 2'b10;
        end else if (state == 2'b10) begin
         data_reg <= 8'b00000001; // Display Clear
         state <= 2'b11;
        end else if (state == 2'b11) begin
         data_reg <= 8'b00000110; // Memory Mode
         state <= 2'b10;
        end
       end else if (~write) begin
        if (state) begin
         state <= 2'b10;
         state <= 1'b0;
         countclk <= 20'h00000;
         LCD_RW <= 0;
         LCD_RS <= ~addr_hold;
         data_reg <= addr_hold ? (text_hold ? 8'b11000000 : 8'b10000000) + text_hold : text_hold;
        end
       end
      end else if (state == 2'b10) begin
       if (~state) begin
        if (countclk == 4) begin
         LCD_E <= 1;
         countclk <= countclk + 1'b1;
        end else if (countclk == 16) begin
         LCD_E <= 0;
         countclk <= countclk + 1'b1;
        end else if (countclk == 50) begin
         state <= 1;
         countclk <= 0;
         LCD_RW <= 1;
         LCD_RS <= 0;
        end else begin
         countclk <= countclk + 1'b1;
        end
       end else begin
        if (countclk == 4) begin
         LCD_E <= 1;
         countclk <= countclk + 1'b1;
        end else if (countclk == 16) begin
         LCD_E <= 0;
         if (LCD_data == 0) begin
          state <= 2'b11;
          state <= 0;
         end
         countclk <= countclk + 1'b1;
        end else if (countclk == 50) begin
         countclk <= 0;
        end else begin
         countclk <= countclk + 1'b1;
        end
       end
      end else if (state == 2'b11) begin
       if (countclk == 50) state <= 2'b01;
       else countclk <= countclk + 1'b1;
      end
     end
    endmodule
     
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello,

    I'm very new to verilog. Do you have sample top level module for the driver(LCD_driver_char) above to start with?