Re: Raspberry Pi as an inexpensive embedded LCDproc server

paul_c <[email protected]> Sun, 19 Aug 2012 14:28:31 +0100
Newsgroups gmane.comp.sysutils.lcdproc
Message-ID <[email protected]>
On Saturday 18 August 2012, Ethan Dicks wrote:
> There would need to be some driver mods to use R-Pi GPIO

Attached, first draft of a patch to drive a 44780 module using the gpio 
on a Raspberry Pi. Connected as a 4bit device to keep the wires down, 
it assumes only a single display is attached. Connections are:

 * header (gpio)  LCD
 * P1-12 (18)     D7 (14)
 * P1-16 (23)     D6 (13)
 * P1-18 (24)     D5 (12)
 * P1-22 (25)     D4 (11)
 * P1-24 (8)      EN (6)
 * P1-26 (7)      RS (4)

See: 
http://www.raspberrypi-spy.co.uk/2012/07/16x2-lcd-module-control-using-python/ 
for further details and a python test program.

As the patch also touches on the configure & makefiles, autotools 
(aclocal, autoconf & automake) need to be installed - pkglib_PROGRAMS 
is now an invalid option, so a small tweak was required in 
server/drivers/Makefile.am to work round the problem.

In use, the ConnectionType under [hd44780] is simply "rpi".


Regards, Paul.

_______________________________________________
LCDproc mailing list
[email protected]
http://lists.omnipotent.net/mailman/listinfo/lcdproc
RaspberryPi.patch (text/x-diff, 12.1 KB)
diff -uprN /tmp/lcdproc-0.5.5/acinclude.m4 ./acinclude.m4
--- /tmp/lcdproc-0.5.5/acinclude.m4	2011-08-14 12:29:14.000000000 +0000
+++ ./acinclude.m4	2012-08-17 22:55:46.306836891 +0000
@@ -196,7 +196,7 @@ dnl			else
 			actdrivers=["$actdrivers glk"]
 			;;
 		hd44780)
-			HD44780_DRIVERS="hd44780-hd44780-serial.o hd44780-hd44780-lis2.o hd44780-hd44780-usblcd.o"
+			HD44780_DRIVERS="hd44780-hd44780-serial.o hd44780-hd44780-lis2.o hd44780-hd44780-usblcd.o hd44780-hd44780-rpi.o"
 			if test "$ac_cv_port_have_lpt" = yes ; then
 				HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-4bit.o hd44780-hd44780-ext8bit.o hd44780-lcd_sem.o hd44780-hd44780-winamp.o hd44780-hd44780-serialLpt.o"
 			fi
diff -uprN /tmp/lcdproc-0.5.5/server/drivers/hd44780-drivers.h ./server/drivers/hd44780-drivers.h
--- /tmp/lcdproc-0.5.5/server/drivers/hd44780-drivers.h	2011-08-14 12:29:16.000000000 +0000
+++ ./server/drivers/hd44780-drivers.h	2012-08-19 11:42:49.499403978 +0000
@@ -34,6 +34,9 @@
 #ifdef WITH_ETHLCD
 # include "hd44780-ethlcd.h"
 #endif
+#ifdef __ARMEL__
+# include "hd44780-rpi.h"
+#endif
 # include "hd44780-usblcd.h"
 /* add new connection type header files to the correct section above or here */
 
@@ -80,6 +83,9 @@ static const ConnectionMapping connectio
 #ifdef WITH_ETHLCD
 	{ "ethlcd",        HD44780_CT_ETHLCD,        IF_TYPE_TCP,     hd_init_ethlcd    },
 #endif
+#ifdef __ARMEL__
+	{ "rpi",           HD44780_CT_4BIT,         IF_TYPE_PARPORT,  hd_init_rpi       },
+#endif
 	/* add new connection types in the correct section above or here */
 
 	/* default, end of structure element (do not delete) */
diff -uprN /tmp/lcdproc-0.5.5/server/drivers/hd44780-rpi.c ./server/drivers/hd44780-rpi.c
--- /tmp/lcdproc-0.5.5/server/drivers/hd44780-rpi.c	1970-01-01 00:00:00.000000000 +0000
+++ ./server/drivers/hd44780-rpi.c	2012-08-19 12:57:11.009325393 +0000
@@ -0,0 +1,258 @@
+/** \file server/drivers/hd44780-4bit.c
+ * \c 4bit connection type of \c hd44780 driver for Hitachi HD44780 based LCD displays.
+ *
+ * The LCD is operated in its 4 bit-mode to be connected to the gpio pins on the Raspberry Pi.
+ */
+
+/* Copyright (c)  2012 Paul Corner <[email protected]>
+ *		  2000, 1999, 1995 Benjamin Tse <[email protected]>
+ *		  2001 Joris Robijn <[email protected]>
+ *		  1999 Andrew McMeikan <[email protected]>
+ *		  1998 Richard Rognlie <[email protected]>
+ *		  1997 Matthias Prinke <[email protected]>
+ *
+ * The connections are:
+ * header (gpio)  LCD
+ * P1-12 (18)	  D7 (14)
+ * P1-16 (23)	  D6 (13)
+ * P1-18 (24)	  D5 (12)
+ * P1-22 (25)	  D4 (11)
+ * P1-24 (8)	  EN (6)
+ * P1-26 (7)	  RS (4)
+*/
+
+#define D7 18
+#define D6 23
+#define D5 24
+#define D4 25
+#define RS 7
+#define EN 8
+
+
+/*
+ *
+ * RW (5) MUST be hard wired low to prevent 5V logic appearing on
+ * the gpio pins.
+ *
+ * Only a single LCD is currently supported - That may change along with
+ * i2c connected devices.
+ *
+ *
+ * Based in part on the hd44780-4bit driver.
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+#include "hd44780-rpi.h"
+#include "hd44780-low.h"
+#include "port.h"
+#include "report.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// Generally, any function that accesses the LCD control lines needs to be
+// implemented separately for each HW design. This is typically (but not
+// restricted to):
+// HD44780_senddata
+// HD44780_readkeypad
+
+void lcdrpi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
+
+// To be implemented at some point if required..
+void lcdrpi_HD44780_backlight(PrivateData *p, unsigned char state);
+unsigned char lcdrpi_HD44780_readkeypad(PrivateData *p, unsigned int YData);
+
+static unsigned char *gpio_mem = NULL;
+static unsigned char  *gpio_map = NULL;
+
+// I/O access
+static volatile unsigned int *gpio = NULL;
+
+// Set up a memory regions to access GPIO
+static int setup_io(Driver *drvthis)
+{
+	int  mem_fd = 0;
+	/* open /dev/mem */
+	if (gpio != NULL) {
+		report(RPT_ERR, "IO already in use.");
+		return -1;
+	}
+	if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
+		report(RPT_ERR, "can not open /dev/mem");
+		return -1;
+	}
+
+	if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
+		report(RPT_ERR, "memory allocation error");
+		return -1;
+	}
+
+	if ((unsigned long)gpio_mem % PAGE_SIZE)
+		gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
+		gpio_map = (unsigned char *)mmap((caddr_t)gpio_mem,
+				BLOCK_SIZE, PROT_READ|PROT_WRITE,
+				MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE);
+
+	if ((long)gpio_map < 0) {
+		report(RPT_ERR, "mmap error %d", (int)gpio_map);
+		return -1;
+	}
+	close(mem_fd); // Done with mem_fd and don't need to use it again.
+
+	// Always use volatile pointer!
+	gpio = (volatile unsigned *)gpio_map;
+	return 0;
+}
+
+
+/**
+ * Initialize the driver.
+ * \param drvthis  Pointer to driver structure.
+ * \retval 0       Success.
+ * \retval -1      Error.
+ */
+int
+hd_init_rpi(Driver *drvthis)
+{
+	PrivateData *p = (PrivateData*) drvthis->private_data;
+
+	if (setup_io(drvthis) < 0) {
+		report(RPT_ERR, "Failed to set up gpio.");
+		return -1;
+	}
+	p->hd44780_functions->senddata = lcdrpi_HD44780_senddata;
+	// Next two are stubbed functions.
+	p->hd44780_functions->backlight = lcdrpi_HD44780_backlight;
+	p->hd44780_functions->readkeypad = lcdrpi_HD44780_readkeypad;
+
+	// Set up pins for output - INP_GPIO must be used before OUT_GPIO
+	// can be used.
+	INP_GPIO(D7);
+	OUT_GPIO(D7);
+	INP_GPIO(D6);
+	OUT_GPIO(D6);
+	INP_GPIO(D5);
+	OUT_GPIO(D5);
+	INP_GPIO(D4);
+	OUT_GPIO(D4);
+
+	INP_GPIO(RS);
+	OUT_GPIO(RS);
+	INP_GPIO(EN);
+	OUT_GPIO(EN);
+
+	// setup the lcd in 4 bit mode
+	p->hd44780_functions->senddata(p, 0, RS_INSTR, /*FUNCSET | IF_8BIT*/ 0x33);
+	p->hd44780_functions->uPause(p, 4100);
+	p->hd44780_functions->senddata(p, 0, RS_INSTR, /*FUNCSET | IF_4BIT*/ 0x32);
+	p->hd44780_functions->uPause(p, 150);
+
+	common_init(p, IF_4BIT);
+
+	return 0;
+}
+
+
+/**
+ * Send data or commands to the display.
+ * \param p          Pointer to driver's private data structure.
+ * \param displayID  ID of the display (or 0 for all) to send data to.
+ * \param flags      Defines whether to end a command or data.
+ * \param ch         The value to send.
+ */
+void
+lcdrpi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
+{
+
+	unsigned int set = 0x0000;
+
+	// Bit pattern to clear gpio pins
+	unsigned int clr = 0x01 << D7 | 0x01 << D6 | 0x01 << D5 | 0x01 << D4;
+
+	if (displayID != 0) {
+		return;
+	}
+
+	if (gpio == NULL) {
+		printf("gpio not set up.\n");
+		return;
+	}
+	// Set EN high while data lines are set up.
+	// Data is latched on the falling edge.
+	p->hd44780_functions->uPause(p, 1);
+	OUT_SET(EN);
+
+	if (flags == RS_INSTR) {
+		clr |= 0x01 << RS;
+	}
+	else { // flags == RS_DATA
+		set |= 0x01 << RS;
+	}
+
+	// Clear data lines ready for nibbles
+	GPIO_CLR = clr;
+
+	// Output upper nibble first
+	if (ch & 0x80) set |= 0x01 << D7;
+	if (ch & 0x40) set |= 0x01 << D6;
+	if (ch & 0x20) set |= 0x01 << D5;
+	if (ch & 0x10) set |= 0x01 << D4;
+	GPIO_SET = set;
+
+	// Data is clocked on the falling edge of EN
+	p->hd44780_functions->uPause(p, 50);
+	OUT_CLR(EN);
+	p->hd44780_functions->uPause(p, 50);
+
+	// Do same for lower nibble
+	p->hd44780_functions->uPause(p, 1);
+	OUT_SET(EN);
+
+	// Clear data lines ready for lower nibble
+	GPIO_CLR = clr;
+	if (ch & 0x08) set |= 0x01 << D7;
+	if (ch & 0x04) set |= 0x01 << D6;
+	if (ch & 0x02) set |= 0x01 << D5;
+	if (ch & 0x01) set |= 0x01 << D4;
+	GPIO_SET = set;
+
+	p->hd44780_functions->uPause(p, 50);
+	OUT_CLR(EN);
+	p->hd44780_functions->uPause(p, 50);
+
+	return;
+}
+
+
+/**
+ * Turn display backlight on or off.
+ * \param p      Pointer to driver's private data structure.
+ * \param state  New backlight status.
+ */
+void lcdrpi_HD44780_backlight(PrivateData *p, unsigned char state)
+{
+	return;
+}
+
+
+/**
+ * Read keypress.
+ * \param p      Pointer to driver's private data structure.
+ * \param YData  Bitmap of rows / lines to enable.
+ * \return       Bitmap of the pressed keys.
+ */
+unsigned char lcdrpi_HD44780_readkeypad(PrivateData *p, unsigned int YData)
+{
+	return 0;
+}
diff -uprN /tmp/lcdproc-0.5.5/server/drivers/hd44780-rpi.h ./server/drivers/hd44780-rpi.h
--- /tmp/lcdproc-0.5.5/server/drivers/hd44780-rpi.h	1970-01-01 00:00:00.000000000 +0000
+++ ./server/drivers/hd44780-rpi.h	2012-08-19 13:04:42.693516174 +0000
@@ -0,0 +1,33 @@
+#ifndef HD_LCDRPI_H
+#define HD_LCDRPI_H
+
+#include "lcd.h"					  /* for Driver */
+
+// initialise this particular driver
+int hd_init_rpi(Driver *drvthis);
+
+//
+//  How to access GPIO registers from C-code on the Raspberry-Pi
+//  Example program
+//  15-January-2012
+//  Dom and Gert
+//
+
+#define BCM2708_PERI_BASE        0x20000000
+#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
+
+#define PAGE_SIZE (4*1024)
+#define BLOCK_SIZE (4*1024)
+
+// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
+#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
+
+#define OUT_SET(pin) (GPIO_SET = 0x01<<pin)
+#define OUT_CLR(pin) (GPIO_CLR = 0x01<<pin)
+
+#endif // HD_LCDRPI_H
diff -uprN /tmp/lcdproc-0.5.5/server/drivers/Makefile.am ./server/drivers/Makefile.am
--- /tmp/lcdproc-0.5.5/server/drivers/Makefile.am	2011-08-14 12:29:16.000000000 +0000
+++ ./server/drivers/Makefile.am	2012-08-17 22:41:18.243866469 +0000
@@ -20,7 +20,8 @@ AM_LDFLAGS = @LDSHARED@
 
 ## Keep the lists sorted!
 
-pkglib_PROGRAMS = @DRIVERS@
+libexecdir = $(pkglibdir)
+libexec_PROGRAMS = @DRIVERS@
 EXTRA_PROGRAMS = bayrad CFontz CFontz633 CFontzPacket curses debug CwLnx ea65 EyeboxOne g15 glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 SureElec svga t6963 text tyan sli ula200 xosd i2500vfd irtrans
 noinst_LIBRARIES = libLCD.a libbignum.a
 
@@ -89,7 +90,7 @@ g15_SOURCES =        lcd.h lcd_lib.h g15
 glcdlib_SOURCES =    lcd.h lcd_lib.h glcdlib.h glcdlib.c report.h
 glk_SOURCES =        lcd.h glk.c glk.h glkproto.c glkproto.h report.h
 hd44780_SOURCES =    lcd.h lcd_lib.h hd44780.h hd44780.c hd44780-drivers.h hd44780-low.h hd44780-charmap.h report.h adv_bignum.h
-EXTRA_hd44780_SOURCES = hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-ext8bit.h lcd_sem.c lcd_sem.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-serial.c hd44780-serial.h hd44780-winamp.c hd44780-winamp.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-lis2.c hd44780-lis2.h hd44780-i2c.c hd44780-i2c.h hd44780-ftdi.c hd44780-ftdi.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-uss720.c hd44780-uss720.h hd44780-usblcd.c hd44780-usblcd.h port.h lpt-port.h timing.h
+EXTRA_hd44780_SOURCES = hd44780-4bit.c hd44780-4bit.h hd44780-ext8bit.c hd44780-ext8bit.h lcd_sem.c lcd_sem.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-serial.c hd44780-serial.h hd44780-winamp.c hd44780-winamp.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-lis2.c hd44780-lis2.h hd44780-i2c.c hd44780-i2c.h hd44780-ftdi.c hd44780-ftdi.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-uss720.c hd44780-uss720.h hd44780-usblcd.c hd44780-usblcd.h port.h lpt-port.h timing.h hd44780-rpi.c hd44780-rpi.h
 i2500vfd_SOURCES =   lcd.h i2500vfd.c i2500vfd.h glcd_font5x8.h report.h
 icp_a106_SOURCES =   lcd.h lcd_lib.h icp_a106.c icp_a106.h report.h
 imon_SOURCES =       lcd.h lcd_lib.h hd44780-charmap.h imon.h imon.c report.h adv_bignum.h