2 * Control LCD module hung off parallel port using the
3 * ppi 'geek port' interface.
17 #include <dev/ppbus/ppbconf.h>
18 #include <dev/ppbus/ppi.h>
20 #define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args);
22 static void usage(void);
23 static char *progname
;
25 #define DEFAULT_DEVICE "/dev/ppi0"
27 /* Driver functions */
28 static void hd44780_prepare(char *devname
, char *options
);
29 static void hd44780_finish(void);
30 static void hd44780_command(int cmd
);
31 static void hd44780_putc(int c
);
35 * Note that unrecognised command escapes are passed through with
36 * the command value set to the ASCII value of the escaped character.
45 #define MAX_DRVOPT 10 /* maximum driver-specific options */
51 char *l_options
[MAX_DRVOPT
];
52 void (* l_prepare
)(char *name
, char *options
);
53 void (* l_finish
)(void);
54 void (* l_command
)(int cmd
);
55 void (* l_putc
)(int c
);
58 static struct lcd_driver lcd_drivertab
[] = {
61 "Hitachi HD44780 and compatibles",
64 " 1 1-line display (default 2)",
65 " B Cursor blink enable",
67 " F Large font select",
86 static void do_char(struct lcd_driver
*driver
, char ch
);
92 main(int argc
, char *argv
[])
96 struct lcd_driver
*driver
= &lcd_drivertab
[0];
97 char *drivertype
, *cp
;
98 char *devname
= DEFAULT_DEVICE
;
102 if ((progname
= strrchr(argv
[0], '/'))) {
108 drivertype
= getenv("LCD_TYPE");
110 while ((ch
= getopt(argc
, argv
, "Dd:f:o:v")) != -1) {
134 /* If an LCD type was specified, look it up */
135 if (drivertype
!= NULL
) {
137 for (i
= 0; lcd_drivertab
[i
].l_code
!= NULL
; i
++) {
138 if (!strcmp(drivertype
, lcd_drivertab
[i
].l_code
)) {
139 driver
= &lcd_drivertab
[i
];
143 if (driver
== NULL
) {
144 warnx("LCD driver '%s' not known", drivertype
);
148 debug(1, "Driver selected for %s", driver
->l_name
);
149 driver
->l_prepare(devname
, drvopts
);
150 atexit(driver
->l_finish
);
153 debug(2, "reading input from %d argument%s", argc
, (argc
> 1) ? "s" : "");
154 for (i
= 0; i
< argc
; i
++)
155 for (cp
= argv
[i
]; *cp
; cp
++)
156 do_char(driver
, *cp
);
158 debug(2, "reading input from stdin");
159 setvbuf(stdin
, NULL
, _IONBF
, 0);
160 while ((ch
= fgetc(stdin
)) != EOF
)
161 do_char(driver
, (char)ch
);
171 fprintf(stderr
, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname
);
172 fprintf(stderr
, " -D Increase debugging\n");
173 fprintf(stderr
, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE
);
174 fprintf(stderr
, " -d Specify driver, one of:\n");
175 for (i
= 0; lcd_drivertab
[i
].l_code
!= NULL
; i
++) {
176 fprintf(stderr
, " %-10s (%s)%s\n",
177 lcd_drivertab
[i
].l_code
, lcd_drivertab
[i
].l_name
, (i
== 0) ? " *default*" : "");
178 if (lcd_drivertab
[i
].l_options
[0] != NULL
) {
180 for (j
= 0; lcd_drivertab
[i
].l_options
[j
] != NULL
; j
++)
181 fprintf(stderr
, " %s\n", lcd_drivertab
[i
].l_options
[j
]);
184 fprintf(stderr
, " -o Specify driver option string\n");
185 fprintf(stderr
, " args Message strings. Embedded escapes supported:\n");
186 fprintf(stderr
, " \\b Backspace\n");
187 fprintf(stderr
, " \\f Clear display, home cursor\n");
188 fprintf(stderr
, " \\n Newline\n");
189 fprintf(stderr
, " \\r Carriage return\n");
190 fprintf(stderr
, " \\R Reset display\n");
191 fprintf(stderr
, " \\v Home cursor\n");
192 fprintf(stderr
, " \\\\ Literal \\\n");
193 fprintf(stderr
, " If args not supplied, strings are read from standard input\n");
198 do_char(struct lcd_driver
*driver
, char ch
)
205 driver
->l_command(CMD_BKSP
);
208 driver
->l_command(CMD_CLR
);
211 driver
->l_command(CMD_NL
);
214 driver
->l_command(CMD_CR
);
217 driver
->l_command(CMD_RESET
);
220 driver
->l_command(CMD_HOME
);
223 driver
->l_putc('\\');
226 driver
->l_command(ch
);
234 if (vflag
|| isprint(ch
))
241 /******************************************************************************
242 * Driver for the Hitachi HD44780. This is probably *the* most common driver
243 * to be found on one- and two-line alphanumeric LCDs.
245 * This driver assumes the following connections :
247 * Parallel Port LCD Module
248 * --------------------------------
249 * Strobe (1) Enable (6)
250 * Data (2-9) Data (7-14)
251 * Select In (17) RS (4)
252 * Auto Feed (14) R/W (5)
254 * In addition, power must be supplied to the module, normally with
255 * a circuit similar to this:
257 * VCC (+5V) O------o-------o--------O Module pin 2
262 * \ <-----o--------O Module pin 3
266 * GND O------o----------------O Module pin 1
268 * The ground line should also be connected to the parallel port, on
269 * one of the ground pins (eg. pin 25).
271 * Note that the pinning on some LCD modules has the odd and even pins
272 * arranged as though reversed; check carefully before conecting a module
273 * as it is possible to toast the HD44780 if the power is reversed.
277 static u_int8_t hd_cbits
;
278 static int hd_lines
= 2;
279 static int hd_blink
= 0;
280 static int hd_cursor
= 0;
281 static int hd_font
= 0;
283 #define HD_COMMAND SELECTIN
286 #define HD_WRITE AUTOFEED
288 #define HD_BF 0x80 /* internal busy flag */
289 #define HD_ADDRMASK 0x7f /* DDRAM address mask */
291 #define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);}
292 #define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);}
293 #define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v)
296 hd44780_output(int type
, int data
)
298 debug(3, "%s -> 0x%02x", (type
== HD_COMMAND
) ? "cmd " : "data", data
);
299 hd_sctrl(type
| HD_WRITE
| STROBE
); /* set direction, address */
300 hd_sctrl(type
| HD_WRITE
); /* raise E */
301 hd_sdata((u_int8_t
) data
); /* drive data */
302 hd_sctrl(type
| HD_WRITE
| STROBE
); /* lower E */
306 hd44780_input(int type
)
310 hd_sctrl(type
| HD_READ
| STROBE
); /* set direction, address */
311 hd_sctrl(type
| HD_READ
); /* raise E */
312 hd_gdata(val
); /* read data */
313 hd_sctrl(type
| HD_READ
| STROBE
); /* lower E */
315 debug(3, "0x%02x -> %s", val
, (type
== HD_COMMAND
) ? "cmd " : "data");
320 hd44780_prepare(char *devname
, char *options
)
324 if ((hd_fd
= open(devname
, O_RDWR
, 0)) == -1)
325 err(EX_OSFILE
, "can't open '%s'", devname
);
343 errx(EX_USAGE
, "hd44780: unknown option code '%c'", *(cp
-1));
347 /* Put LCD in idle state */
348 if (ioctl(hd_fd
, PPIGCTRL
, &hd_cbits
)) /* save other control bits */
349 err(EX_IOERR
, "ioctl PPIGCTRL failed (not a ppi device?)");
350 hd_cbits
&= ~(STROBE
| SELECTIN
| AUTOFEED
); /* set strobe, RS, R/W low */
351 debug(2, "static control bits 0x%x", hd_cbits
);
364 hd44780_command(int cmd
)
369 case CMD_RESET
: /* full manual reset and reconfigure as per datasheet */
370 debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor",
371 hd_lines
, hd_font
? "5x10" : "5x7", hd_cursor
? "" : " no", hd_blink
? " blinking" : "");
377 hd44780_output(HD_COMMAND
, val
);
379 hd44780_output(HD_COMMAND
, val
);
381 hd44780_output(HD_COMMAND
, val
);
383 val
= 0x08; /* display off */
384 hd44780_output(HD_COMMAND
, val
);
386 val
|= 0x04; /* display on */
391 hd44780_output(HD_COMMAND
, val
);
393 hd44780_output(HD_COMMAND
, 0x06); /* shift cursor by increment */
398 hd44780_output(HD_COMMAND
, 0x01);
403 hd44780_output(HD_DATA
, 0x10); /* shift cursor left one */
408 hd44780_output(HD_COMMAND
, 0xc0); /* beginning of second line */
412 /* XXX will not work in 4-line mode, or where readback fails */
413 val
= hd44780_input(HD_COMMAND
) & 0x3f; /* mask character position, save line pos */
414 hd44780_output(HD_COMMAND
, 0x80 | val
);
418 hd44780_output(HD_COMMAND
, 0x02);
424 warnx("unknown command %c", cmd
);
426 warnx("unknown command 0x%x", cmd
);
435 hd44780_output(HD_DATA
, c
);