Nios II-based LCD1602 Driver Example
This article demonstrates how to drive an LCD1602 display using a Nios II soft-core processor on the DE2-115 development board.
Experimental Setup
- Platform: DE2-115
- Sofwtare: Quartus II 15.1
The Qsys system configuration is shown below (assembly details omitted for brevity).

SDRAM configuration on the DE2-115 board is illustrated below:

Hardware Code
The hardware design is implemneted in Verilog. The top-level module instantiates a PLL and the Nios II system (my_cpu). The PLL generates a main clock (c0) and the SDRAM clock (sdram_clk). A simple counter (vl_cnt) controls the LCD backlight via lcd1602_vl.
module LCD1602 (
clk,
rst_n,
led,
lcd1602_RS,
lcd1602_RW,
lcd1602_data,
lcd1602_E,
sdram_addr,
sdram_ba,
sdram_cas_n,
sdram_cke,
sdram_cs_n,
sdram_dq,
sdram_dqm,
sdram_ras_n,
sdram_we_n,
sdram_clk,
lcd1602_vl,
lcd1602_on
);
input clk;
output lcd1602_RS;
output lcd1602_RW;
inout [7:0] lcd1602_data;
output lcd1602_E;
output lcd1602_vl;
output lcd1602_on;
input rst_n;
output [12:0] sdram_addr;
output [1:0] sdram_ba;
output sdram_cas_n;
output sdram_cke;
output sdram_cs_n;
inout [31:0] sdram_dq;
output [3:0] sdram_dqm;
output sdram_ras_n;
output sdram_we_n;
output sdram_clk;
output [3:0] led;
wire c0;
reg [3:0] vl_cnt;
always @(posedge clk or negedge rst_n)
if (!rst_n)
vl_cnt <= 4'd0;
else
vl_cnt <= vl_cnt + 4'd1;
assign lcd1602_vl = (vl_cnt > 9);
assign lcd1602_on = 1;
PLL PLL_inst (
.inclk0 ( clk ),
.c0 ( c0 ),
.c1 ( sdram_clk )
);
my_cpu u0 (
.clk_clk (c0),
.lcd1602_RS (lcd1602_RS),
.lcd1602_RW (lcd1602_RW),
.lcd1602_data (lcd1602_data),
.lcd1602_E (lcd1602_E),
.reset_reset_n (rst_n),
.sdram_addr (sdram_addr),
.sdram_ba (sdram_ba),
.sdram_cas_n (sdram_cas_n),
.sdram_cke (sdram_cke),
.sdram_cs_n (sdram_cs_n),
.sdram_dq (sdram_dq),
.sdram_dqm (sdram_dqm),
.sdram_ras_n (sdram_ras_n),
.sdram_we_n (sdram_we_n),
.pio_led_export(led)
);
endmodule
Software Code
The software driver is written in C and runs on the Nios II processor. It provides macros for LCD command and data read/write operations, and functions to initialize the LCD, display text, and move the cursor to the second line.
Header File (lcd1602.h)
#ifndef LCD1602_H_
#define LCD1602_H_
#define lcd_write_cmd(base, data) IOWR(base, 0, data)
#define lcd_read_cmd(base) IORD(base, 1)
#define lcd_write_data(base, data) IOWR(base, 2, data)
#define lcd_read_data(base) IORD(base, 3)
void LCD_Init(void);
void LCD_Show_Text(char* Text);
void LCD_Line2(void);
#endif /* LCD1602_H_ */
Source File (lcd1602.c)
#include <stdio.h>
#include <altera_avalon_pio_regs.h>
#include <alt_types.h>
#include <unistd.h>
#include <system.h>
#include <string.h>
#include <io.h>
#include <sys/alt_irq.h>
#include "../inc/lcd1602.h"
void LCD_Init(void)
{
lcd_write_cmd(LCD1602_BASE, 0x38); // Initialize LCD
usleep(2000);
lcd_write_cmd(LCD1602_BASE, 0x0c); // Display on, cursor off
usleep(2000);
lcd_write_cmd(LCD1602_BASE, 0x01); // Clear display
usleep(2000);
lcd_write_cmd(LCD1602_BASE, 0x06); // Cursor move direction, no shift
usleep(2000);
lcd_write_cmd(LCD1602_BASE, 0x80); // Set cursor to home position
usleep(2000);
}
void LCD_Show_Text(char* Text)
{
int i;
for (i = 0; i < strlen(Text); i++)
{
lcd_write_data(LCD1602_BASE, Text[i]);
usleep(2000);
}
}
void LCD_Line2(void)
{
lcd_write_cmd(LCD1602_BASE, 0xc0); // Move cursor to start of second line
usleep(2000);
}
int main(void)
{
char Text1[16] = " Hello DE2-115 ";
char Text2[16] = " Legend of NCU ";
LCD_Init();
LCD_Show_Text(Text1);
LCD_Line2();
LCD_Show_Text(Text2);
return 0;
}
Results
The LCD correctly displays the configured text as shown below:

Notes
- The PLL generates a 50 MHz clock for the Nios II system and a separate clock for the SDRAM controller.
- The LCD backlight is controlled by a simple counter; it turns on when
vl_cntexceeds 9. - The software includes appropriate delays (
usleep) to meet the LCD timing requirements.