2 * Control LCD module hung off parallel port using the
3 * ppi 'geek port' interface.
5 * $FreeBSD: src/share/examples/ppi/ppilcd.c,v 1.2.2.1 2003/01/05 19:45:29 semenu Exp $
6 * $DragonFly: src/share/examples/ppi/ppilcd.c,v 1.2 2003/06/17 04:36:57 dillon Exp $
18 #include <dev/ppbus/ppbconf.h>
19 #include <dev/ppbus/ppi.h>
21 #define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args);
23 static void usage(void);
24 static char *progname
;
26 #define DEFAULT_DEVICE "/dev/ppi0"
28 /* Driver functions */
29 static void hd44780_prepare(char *devname
, char *options
);
30 static void hd44780_finish(void);
31 static void hd44780_command(int cmd
);
32 static void hd44780_putc(int c
);
36 * Note that unrecognised command escapes are passed through with
37 * the command value set to the ASCII value of the escaped character.
46 #define MAX_DRVOPT 10 /* maximum driver-specific options */
52 char *l_options
[MAX_DRVOPT
];
53 void (* l_prepare
)(char *name
, char *options
);
54 void (* l_finish
)(void);
55 void (* l_command
)(int cmd
);
56 void (* l_putc
)(int c
);
59 static struct lcd_driver lcd_drivertab
[] = {
62 "Hitachi HD44780 and compatibles",
65 " 1 1-line display (default 2)",
66 " B Cursor blink enable",
68 " F Large font select",
87 static void do_char(struct lcd_driver
*driver
, char ch
);
93 main(int argc
, char *argv
[])
97 struct lcd_driver
*driver
= &lcd_drivertab
[0];
98 char *drivertype
, *cp
;
99 char *devname
= DEFAULT_DEVICE
;
100 char *drvopts
= NULL
;
103 if ((progname
= strrchr(argv
[0], '/'))) {
109 drivertype
= getenv("LCD_TYPE");
111 while ((ch
= getopt(argc
, argv
, "Dd:f:o:v")) != EOF
) {
135 /* If an LCD type was specified, look it up */
136 if (drivertype
!= NULL
) {
138 for (i
= 0; lcd_drivertab
[i
].l_code
!= NULL
; i
++) {
139 if (!strcmp(drivertype
, lcd_drivertab
[i
].l_code
)) {
140 driver
= &lcd_drivertab
[i
];
144 if (driver
== NULL
) {
145 warnx("LCD driver '%s' not known", drivertype
);
149 debug(1, "Driver selected for %s", driver
->l_name
);
150 driver
->l_prepare(devname
, drvopts
);
151 atexit(driver
->l_finish
);
154 debug(2, "reading input from %d argument%s", argc
, (argc
> 1) ? "s" : "");
155 for (i
= 0; i
< argc
; i
++)
156 for (cp
= argv
[i
]; *cp
; cp
++)
157 do_char(driver
, *cp
);
159 debug(2, "reading input from stdin");
160 setvbuf(stdin
, NULL
, _IONBF
, 0);
161 while ((ch
= fgetc(stdin
)) != EOF
)
162 do_char(driver
, (char)ch
);
172 fprintf(stderr
, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname
);
173 fprintf(stderr
, " -D Increase debugging\n");
174 fprintf(stderr
, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE
);
175 fprintf(stderr
, " -d Specify driver, one of:\n");
176 for (i
= 0; lcd_drivertab
[i
].l_code
!= NULL
; i
++) {
177 fprintf(stderr
, " %-10s (%s)%s\n",
178 lcd_drivertab
[i
].l_code
, lcd_drivertab
[i
].l_name
, (i
== 0) ? " *default*" : "");
179 if (lcd_drivertab
[i
].l_options
[0] != NULL
) {
181 for (j
= 0; lcd_drivertab
[i
].l_options
[j
] != NULL
; j
++)
182 fprintf(stderr
, " %s\n", lcd_drivertab
[i
].l_options
[j
]);
185 fprintf(stderr
, " -o Specify driver option string\n");
186 fprintf(stderr
, " args Message strings. Embedded escapes supported:\n");
187 fprintf(stderr
, " \\b Backspace\n");
188 fprintf(stderr
, " \\f Clear display, home cursor\n");
189 fprintf(stderr
, " \\n Newline\n");
190 fprintf(stderr
, " \\r Carriage return\n");
191 fprintf(stderr
, " \\R Reset display\n");
192 fprintf(stderr
, " \\v Home cursor\n");
193 fprintf(stderr
, " \\\\ Literal \\\n");
194 fprintf(stderr
, " If args not supplied, strings are read from standard input\n");
199 do_char(struct lcd_driver
*driver
, char ch
)
206 driver
->l_command(CMD_BKSP
);
209 driver
->l_command(CMD_CLR
);
212 driver
->l_command(CMD_NL
);
215 driver
->l_command(CMD_CR
);
218 driver
->l_command(CMD_RESET
);
221 driver
->l_command(CMD_HOME
);
224 driver
->l_putc('\\');
227 driver
->l_command(ch
);
235 if (vflag
|| isprint(ch
))
242 /******************************************************************************
243 * Driver for the Hitachi HD44780. This is probably *the* most common driver
244 * to be found on one- and two-line alphanumeric LCDs.
246 * This driver assumes the following connections :
248 * Parallel Port LCD Module
249 * --------------------------------
250 * Strobe (1) Enable (6)
251 * Data (2-9) Data (7-14)
253 * Auto Feed (14) R/W (5)
255 * In addition, power must be supplied to the module, normally with
256 * a circuit similar to this:
258 * VCC (+5V) O------o-------o--------O Module pin 2
263 * \ <-----o--------O Module pin 3
267 * GND O------o----------------O Module pin 1
269 * The ground line should also be connected to the parallel port, on
270 * one of the ground pins (eg. pin 25).
272 * Note that the pinning on some LCD modules has the odd and even pins
273 * arranged as though reversed; check carefully before conecting a module
274 * as it is possible to toast the HD44780 if the power is reversed.
278 static u_int8_t hd_cbits
;
279 static int hd_lines
= 2;
280 static int hd_blink
= 0;
281 static int hd_cursor
= 0;
282 static int hd_font
= 0;
284 #define HD_COMMAND SELECTIN
287 #define HD_WRITE AUTOFEED
289 #define HD_BF 0x80 /* internal busy flag */
290 #define HD_ADDRMASK 0x7f /* DDRAM address mask */
292 #define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);}
293 #define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);}
294 #define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v)
297 hd44780_output(int type
, int data
)
299 debug(3, "%s -> 0x%02x", (type
== HD_COMMAND
) ? "cmd " : "data", data
);
300 hd_sctrl(type
| HD_WRITE
| STROBE
); /* set direction, address */
301 hd_sctrl(type
| HD_WRITE
); /* raise E */
302 hd_sdata((u_int8_t
) data
); /* drive data */
303 hd_sctrl(type
| HD_WRITE
| STROBE
); /* lower E */
307 hd44780_input(int type
)
311 hd_sctrl(type
| HD_READ
| STROBE
); /* set direction, address */
312 hd_sctrl(type
| HD_READ
); /* raise E */
313 hd_gdata(val
); /* read data */
314 hd_sctrl(type
| HD_READ
| STROBE
); /* lower E */
316 debug(3, "0x%02x -> %s", val
, (type
== HD_COMMAND
) ? "cmd " : "data");
321 hd44780_prepare(char *devname
, char *options
)
325 if ((hd_fd
= open(devname
, O_RDWR
, 0)) == -1)
326 err(EX_OSFILE
, "can't open '%s'", devname
);
344 errx(EX_USAGE
, "hd44780: unknown option code '%c'", *(cp
-1));
348 /* Put LCD in idle state */
349 if (ioctl(hd_fd
, PPIGCTRL
, &hd_cbits
)) /* save other control bits */
350 err(EX_IOERR
, "ioctl PPIGCTRL failed (not a ppi device?)");
351 hd_cbits
&= ~(STROBE
| SELECTIN
| AUTOFEED
); /* set strobe, RS, R/W low */
352 debug(2, "static control bits 0x%x", hd_cbits
);
365 hd44780_command(int cmd
)
370 case CMD_RESET
: /* full manual reset and reconfigure as per datasheet */
371 debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor",
372 hd_lines
, hd_font
? "5x10" : "5x7", hd_cursor
? "" : " no", hd_blink
? " blinking" : "");
378 hd44780_output(HD_COMMAND
, val
);
380 hd44780_output(HD_COMMAND
, val
);
382 hd44780_output(HD_COMMAND
, val
);
384 val
= 0x08; /* display off */
385 hd44780_output(HD_COMMAND
, val
);
387 val
|= 0x04; /* display on */
392 hd44780_output(HD_COMMAND
, val
);
394 hd44780_output(HD_COMMAND
, 0x06); /* shift cursor by increment */
399 hd44780_output(HD_COMMAND
, 0x01);
404 hd44780_output(HD_DATA
, 0x10); /* shift cursor left one */
409 hd44780_output(HD_COMMAND
, 0xc0); /* beginning of second line */
413 /* XXX will not work in 4-line mode, or where readback fails */
414 val
= hd44780_input(HD_COMMAND
) & 0x3f; /* mask character position, save line pos */
415 hd44780_output(HD_COMMAND
, 0x80 | val
);
419 hd44780_output(HD_COMMAND
, 0x02);
425 warnx("unknown command %c", cmd
);
427 warnx("unknown command 0x%x", cmd
);
436 hd44780_output(HD_DATA
, c
);