Skip to content

Commit fcd3413

Browse files
author
brabo
authored
Merge pull request #5 from mrnuke/stellaris-lcd
examples/lm4f/stellaris: Add LCD printf example
2 parents f560bc2 + 61114b6 commit fcd3413

File tree

8 files changed

+765
-0
lines changed

8 files changed

+765
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
##
2+
## This file is part of the libopencm3 project.
3+
##
4+
## Copyright (C) 2016 Alexandru Gagniuc <[email protected]>
5+
##
6+
## This library is free software: you can redistribute it and/or modify
7+
## it under the terms of the GNU Lesser General Public License as published by
8+
## the Free Software Foundation, either version 3 of the License, or
9+
## (at your option) any later version.
10+
##
11+
## This library is distributed in the hope that it will be useful,
12+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
## GNU Lesser General Public License for more details.
15+
##
16+
## You should have received a copy of the GNU Lesser General Public License
17+
## along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
##
19+
20+
BINARY = lcd-hd44780-printf
21+
22+
LDSCRIPT = ../ek-lm4f120xl.ld
23+
24+
OBJS += hd44780-gpio.o stellaris_vfd.o uart.o
25+
26+
include ../../Makefile.include
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# README
2+
3+
This example demonstrates interfacing the Stellaris board to any HD44780 style
4+
LCD display, using an 8-bit data bus. It demonstrates the use of LCDs or VFDs
5+
(Vacuum Fluorescent Displays) driven by a HD44780 controller. It also
6+
demonstrates the use of printf-like functionality to print data to the display.
7+
8+
While this example has been split up in component parts, it is complex, and
9+
contains many parts. If you're only looking for an example on how to use the
10+
UART, see uart_echo_simple, and uart_echo_interrupt examples instead.
11+
12+
## HD44780 diplay control
13+
14+
The HD44780 interface is split into two parts:
15+
16+
### hd44780-gpio.[ch]
17+
18+
These files provide a generic, object-oriented interface to talk to HD44780
19+
display controllers. It abstracts the communication interface into several easy
20+
to use functions, ranging from low-level control of the communication lines, to
21+
high-level control of the data to be displayed. The driver is named
22+
hd44780-gpio because the communication is driven via GPIO (as opposed to using
23+
an external bus).
24+
25+
Hardware-specific details, such as driving the GPIO lines are not implemented
26+
here, but are instead outsourced to hardware-specific drivers. A
27+
hardware-specific driver can be provided by filling up a hd44870_lcd structure.
28+
This structure is also the context for every function in the generic display
29+
code.
30+
31+
The hd44780-gpio aims to be a minimalistic driver, and does not aim to impement
32+
all the bells and whistles of the HD44780 controller, nor is it guaranteed to
33+
work on all display geometries (but it's pretty easy to adapt).
34+
35+
### stellaris_vfd.c
36+
37+
This file implements the hardware-specific part of the display driver. It
38+
provides initialization of the GPIO lines, and controls the communication lines
39+
leading to the display. It also implements other hardware details, such as
40+
delays, and details about the geometry of the display.
41+
42+
## UART control
43+
44+
This example uses UART0 send and receive data. It also echoes back any data
45+
received. The echo happens within the UART interrupt routine. See
46+
uart_echo_interrupt for a simpler example on using UART interrupts.
47+
48+
The uart.c file also keeps tracks of the numbers of received and sent bytes,
49+
and provides a way to report them to the application, as well as reset the
50+
counters.
51+
52+
## Main application
53+
54+
the application prints the "libopencm3" text on the first line of the display,
55+
followed by two special characters. The number of bytes sent and received over
56+
UART0 are displayed on the second line. The display is updated whenever one of
57+
the counters changes.
58+
59+
The main application demonstrates how to use printf-like functionality to send
60+
data over the UART. It then demonstrates how to put simple strings on the
61+
display, and use the CGRAM (character generation RAM) of the HD44780 to create
62+
custom characters.
63+
The program's event loop demonstrates how to partition the display into
64+
subsections for displaying different information, using lcd_nprintf(), and
65+
lcd_printf(). With lcd_nprintf(), it is possible to print text to the LCD and
66+
confine it to a specified number of characters.
67+
68+
## UART
69+
70+
PA0 is the Rx pin, and PA1 is the Tx pin (from the LM4F perspective). These
71+
pins are connected to the CDCACM interface on the debug chip, so no hardware is
72+
necessary to test this example. Just connect the debug USB cable and use a
73+
terminal program to open the ACM port with 921600-8N1.
74+
75+
For example:
76+
picocom /dev/ttyACM0 -b921600
77+
78+
## Connections
79+
display data[0-7] <-> PB[0-7]
80+
display FNC -> PD4 (unused)
81+
display RS -> PD5
82+
display RW -> PD6
83+
display E -> PD7
84+
UART0 TX -> PA0
85+
UART0 RX <- PA1
86+
87+
These connections were chosen such that writing to the data bus can be done
88+
with a single GPIO write. This is, however, not required, and GPIOs from
89+
different ports may be mixed to create the 8-bit data bus. Such changes should
90+
be reflected in the hardware-specific driver in stellaris_vfd.c .
91+
92+
## Hardware
93+
94+
This example was developed using a Noritake CU20025ECPB-U1J 2x20 vacuum
95+
fluorescent display.
96+
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* This file is part of the libopencm3 project.
3+
*
4+
* Copyright (C) 2016 Alexandru Gagniuc <[email protected]>
5+
*
6+
* This library is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "hd44780-gpio.h"
21+
22+
#include <stdarg.h>
23+
#include <stdio.h>
24+
25+
#define MIN(x, y) ((x) < (y) ? (x) : (y))
26+
27+
static void set_data_lines(struct hd44780_lcd *ctx, uint8_t data)
28+
{
29+
ctx->set_data_lines(ctx, data);
30+
}
31+
32+
static void set_handshake_lines(struct hd44780_lcd *ctx,
33+
enum lcd_ctl_lines lines)
34+
{
35+
ctx->set_handshake_lines(ctx, lines);
36+
}
37+
38+
static void ndelay(struct hd44780_lcd *ctx, unsigned int nano_sec)
39+
{
40+
ctx->ndelay(ctx, nano_sec);
41+
}
42+
43+
void lcd_init(struct hd44780_lcd *ctx)
44+
{
45+
uint8_t function_bits;
46+
47+
ctx->hardware_init(ctx);
48+
49+
function_bits = HD44780_FUNCTION_8BIT;
50+
if (ctx->num_lines > 1)
51+
function_bits |= HD44780_FUNCTION_2LINES;
52+
53+
lcd_send_command(ctx, HD44780_CMD_FUNCTION_SET | function_bits);
54+
/* VFD-specific: set brightness after sending FUNCTION_SET command */
55+
lcd_send_data(ctx, 0x02);
56+
/* Enable display. Disable cursor and blinker. */
57+
lcd_send_command(ctx, HD44780_CMD_DISPLAY_ON_OFF |
58+
HD44780_DISP_ONOFF_DISPLAY);
59+
lcd_send_command(ctx, HD44780_CMD_ENTRY_MODE_SET |
60+
HD44780_MODE_INCREMENT);
61+
}
62+
63+
void lcd_clear_display(struct hd44780_lcd *ctx)
64+
{
65+
lcd_send_command(ctx, HD44780_CMD_CLEAR_DISPLAY);
66+
ndelay(ctx, 2300000);
67+
}
68+
69+
void lcd_send_command(struct hd44780_lcd *ctx, uint8_t cmd)
70+
{
71+
set_handshake_lines(ctx, LINE_E);
72+
ndelay(ctx, 1000);
73+
set_data_lines(ctx, cmd);
74+
ndelay(ctx, 1000);
75+
set_handshake_lines(ctx, LINE_NONE);
76+
ndelay(ctx, 1000);
77+
}
78+
79+
void lcd_send_data(struct hd44780_lcd *ctx, uint8_t data)
80+
{
81+
set_handshake_lines(ctx, LINE_E | LINE_RS);
82+
ndelay(ctx, 1000);
83+
set_data_lines(ctx, data);
84+
ndelay(ctx, 1000);
85+
set_handshake_lines(ctx, LINE_RS);
86+
ndelay(ctx, 1000);
87+
88+
}
89+
90+
void lcd_write_ddram(struct hd44780_lcd *ctx, uint8_t addr, uint8_t val)
91+
{
92+
lcd_send_command(ctx, HD44780_CMD_SET_DDRAM_ADDR | addr);
93+
lcd_send_data(ctx, val);
94+
}
95+
96+
static void set_cgram_addr(struct hd44780_lcd *ctx, uint8_t addr)
97+
{
98+
addr &= HD44780_CMD_MASK(HD44780_CMD_SET_CGRAM_ADDR);
99+
lcd_send_command(ctx, HD44780_CMD_SET_CGRAM_ADDR | addr);
100+
}
101+
102+
void lcd_write_cgram(struct hd44780_lcd *ctx, uint8_t addr, uint8_t val)
103+
{
104+
set_cgram_addr(ctx, addr);
105+
lcd_send_data(ctx, val);
106+
}
107+
108+
void lcd_put_string(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
109+
const char *str)
110+
{
111+
unsigned int i;
112+
uint8_t addr;
113+
114+
if (start_char >= ctx->line_len)
115+
return;
116+
117+
addr = ctx->mem_line_stride * line + start_char;
118+
119+
lcd_send_command(ctx, HD44780_CMD_SET_DDRAM_ADDR | addr);
120+
for (i = 0; i < (ctx->line_len - start_char); i++) {
121+
if (str[i] == '\0')
122+
break;
123+
lcd_send_data(ctx, str[i]);
124+
}
125+
}
126+
127+
static void lcd_print_variadic(struct hd44780_lcd *ctx, uint8_t line,
128+
uint8_t start_char, uint8_t num_chars,
129+
const char *format, va_list args)
130+
{
131+
char buffer[64];
132+
int len;
133+
134+
if (start_char >= ctx->line_len)
135+
return;
136+
137+
len = MIN(ctx->line_len - start_char, num_chars);
138+
len = vsnprintf(buffer, len, format, args);
139+
140+
lcd_put_string(ctx, line, start_char, buffer);
141+
}
142+
143+
void lcd_printf(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
144+
const char *format, ...)
145+
{
146+
va_list args;
147+
148+
va_start(args, format);
149+
lcd_print_variadic(ctx, line, start_char, ctx->line_len, format, args);
150+
va_end(args);
151+
}
152+
153+
void lcd_nprintf(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
154+
uint8_t num_chars, const char *format, ...)
155+
{
156+
va_list args;
157+
158+
va_start(args, format);
159+
lcd_print_variadic(ctx, line, start_char, num_chars, format, args);
160+
va_end(args);
161+
}
162+
163+
void lcd_fill_cgram_character(struct hd44780_lcd *ctx, uint8_t char_idx,
164+
const uint8_t bitmap[8])
165+
{
166+
int i;
167+
168+
if (char_idx > 7)
169+
return;
170+
171+
set_cgram_addr(ctx, char_idx * 8);
172+
for (i = 0; i < 8; i++)
173+
lcd_send_data(ctx, bitmap[i]);
174+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* This file is part of the libopencm3 project.
3+
*
4+
* Copyright (C) 2016 Alexandru Gagniuc <[email protected]>
5+
*
6+
* This library is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef _HD44780_GPIO_H_
21+
#define _HD44780_GPIO_H_
22+
23+
#include <stdint.h>
24+
#include <string.h>
25+
26+
enum lcd_ctl_lines {
27+
LINE_NONE = 0,
28+
LINE_E = 1 << 0,
29+
LINE_RS = 1 << 1,
30+
LINE_WR = 1 << 2,
31+
};
32+
33+
enum hd44780_commands {
34+
HD44780_CMD_CLEAR_DISPLAY = 1 << 0,
35+
HD44780_CMD_RETURN_HOME = 1 << 1,
36+
HD44780_CMD_ENTRY_MODE_SET = 1 << 2,
37+
HD44780_CMD_DISPLAY_ON_OFF = 1 << 3,
38+
HD44780_CMD_CURSOR_SHIFT = 1 << 4,
39+
HD44780_CMD_FUNCTION_SET = 1 << 5,
40+
HD44780_CMD_SET_CGRAM_ADDR = 1 << 6,
41+
HD44780_CMD_SET_DDRAM_ADDR = 1 << 7,
42+
};
43+
44+
enum hd44780_function {
45+
HD44780_FUNCTION_8BIT = 1 << 4,
46+
HD44780_FUNCTION_2LINES = 1 << 3,
47+
HD44780_FUNCTION_FONT_5x8 = 1 << 2,
48+
};
49+
50+
enum hd44780_disp_onoff {
51+
HD44780_DISP_ONOFF_DISPLAY = 1 << 2,
52+
HD44780_DISP_ONOFF_CURSOR = 1 << 1,
53+
HD44780_DISP_ONOFF_BLINKER = 1 << 0,
54+
};
55+
56+
enum hd44780_entry_mode {
57+
HD44780_MODE_INCREMENT = 1 << 1,
58+
HD44780_MODE_SHIFT = 1 << 0,
59+
};
60+
61+
#define HD44780_CMD_MASK(cmd) ((cmd) - 1)
62+
63+
struct hd44780_lcd {
64+
void (*hardware_init)(struct hd44780_lcd *);
65+
void (*set_data_lines)(struct hd44780_lcd *, uint8_t data);
66+
void (*set_handshake_lines)(struct hd44780_lcd *, enum lcd_ctl_lines);
67+
void (*change_data_lines_mode_in)(struct hd44780_lcd *);
68+
void (*change_data_lines_mode_out)(struct hd44780_lcd *);
69+
void (*ndelay)(struct hd44780_lcd *, unsigned int nano_sec);
70+
void *priv;
71+
unsigned int num_lines;
72+
unsigned int line_len;
73+
unsigned int mem_line_stride;
74+
};
75+
76+
void lcd_init(struct hd44780_lcd *ctx);
77+
void lcd_clear_display(struct hd44780_lcd *ctx);
78+
void lcd_write_ddram(struct hd44780_lcd *ctx, uint8_t addr, uint8_t val);
79+
void lcd_write_cgram(struct hd44780_lcd *ctx, uint8_t addr, uint8_t val);
80+
void lcd_send_command(struct hd44780_lcd *ctx, uint8_t cmd);
81+
void lcd_send_data(struct hd44780_lcd *ctx, uint8_t data);
82+
void lcd_put_string(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
83+
const char *str);
84+
void lcd_printf(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
85+
const char *format, ...);
86+
void lcd_nprintf(struct hd44780_lcd *ctx, uint8_t line, uint8_t start_char,
87+
uint8_t num_chars, const char *format, ...);
88+
void lcd_fill_cgram_character(struct hd44780_lcd *ctx, uint8_t char_idx,
89+
const uint8_t bitmap[8]);
90+
91+
#endif /* _HD44780_GPIO_H_ */

0 commit comments

Comments
 (0)