Raspberry Pi direct connection patch for 0.5.6

warhog <[email protected]> Sat, 29 Dec 2012 11:51:33 +0100
Newsgroups gmane.comp.sysutils.lcdproc
Message-ID <[email protected]>
hi all,
i ported paul_c's raspberry pi hd44780 direct connection patch to 
lcdproc-0.5.6. i also added a simple check for arm host in acinclude.

as this works like a charm for a few months now, is this stuff going to 
be officially included some day?

greetings

_______________________________________________
LCDproc mailing list
[email protected]
http://lists.omnipotent.net/mailman/listinfo/lcdproc
lcdproc-0.5.6-lcd-hd44780-rpi-gpio_0.3.patch (text/x-patch, 15.1 KB)
diff -Naur lcdproc-0.5.6/acinclude.m4 lcdproc-0.5.6-patched/acinclude.m4
--- lcdproc-0.5.6/acinclude.m4	2012-09-01 23:34:24.000000000 +0200
+++ lcdproc-0.5.6-patched/acinclude.m4	2012-11-24 10:20:56.340518665 +0100
@@ -228,6 +228,13 @@
 			if test "$x_ac_have_i2c" = yes; then
 				HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c.o"
 			fi
+dnl			The hd4470-rpi driver only works on a Raspberry Pi,
+dnl			which is an ARM platform.
+			case $host in
+			arm*-*-linux*)
+				HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-rpi.o"
+			    ;;
+			esac
 			DRIVERS="$DRIVERS hd44780${SO}"
 			actdrivers=["$actdrivers hd44780"]
 			;;
diff -Naur lcdproc-0.5.6/server/drivers/hd44780-drivers.h lcdproc-0.5.6-patched/server/drivers/hd44780-drivers.h
--- lcdproc-0.5.6/server/drivers/hd44780-drivers.h	2012-08-19 16:29:08.000000000 +0200
+++ lcdproc-0.5.6-patched/server/drivers/hd44780-drivers.h	2012-11-24 10:22:19.616520977 +0100
@@ -17,6 +17,9 @@
 # include "hd44780-serialLpt.h"
 # include "hd44780-winamp.h"
 #endif
+#ifdef __ARMEL__
+# include "hd44780-rpi.h"
+#endif
 #include "hd44780-serial.h"
 #include "hd44780-lis2.h"
 #ifdef HAVE_LIBUSB
@@ -82,6 +85,9 @@
 #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 -Naur lcdproc-0.5.6/server/drivers/hd44780-low.h lcdproc-0.5.6-patched/server/drivers/hd44780-low.h
--- lcdproc-0.5.6/server/drivers/hd44780-low.h	2012-08-19 16:29:08.000000000 +0200
+++ lcdproc-0.5.6-patched/server/drivers/hd44780-low.h	2012-11-24 10:23:32.896523011 +0100
@@ -28,6 +28,9 @@
 #ifdef HAVE_LIBFTDI
 # include <ftdi.h>
 #endif
+#ifdef __ARMEL__
+#  include "hd44780-rpi.h"
+#endif
 
 /** \name Symbolic names for connection types
  *@{*/
@@ -153,6 +156,9 @@
 #ifdef WITH_ETHLCD
 	int sock;		/**< socket for TCP devices */
 #endif
+#ifdef __ARMEL__
+	struct rpi_gpio_map *rpi_gpio;
+#endif
 
 	int charmap;		/**< index of currently used charmap */
 
diff -Naur lcdproc-0.5.6/server/drivers/hd44780-rpi.c lcdproc-0.5.6-patched/server/drivers/hd44780-rpi.c
--- lcdproc-0.5.6/server/drivers/hd44780-rpi.c	1970-01-01 01:00:00.000000000 +0100
+++ lcdproc-0.5.6-patched/server/drivers/hd44780-rpi.c	2012-08-28 21:25:24.000000000 +0200
@@ -0,0 +1,336 @@
+/** \file server/drivers/hd44780-rpi.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]>
+ *
+ * Based in part on the hd44780-4bit driver and comments/notes/code provided
+ * by Serac (RaspberryPi forum user)
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+/**
+ * The code to access the gpio on a Raspberry Pi draws on an
+ * example program dated 15-January-2012 by Dom and Gert van Loo:
+ * How to access GPIO registers from C-code on the Raspberry-Pi
+
+ * The default 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)
+ *
+ * Mappings can be set in the config file using the key-words:
+ * ENABLE, RS, D7, D6, D5, D4 in the [HD44780] section.
+*/
+
+#define D7 18
+#define D6 23
+#define D5 24
+#define D4 25
+#define RS 7
+#define EN 8
+
+/**
+ *
+ * RW (5) on the LCD 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.
+ */
+
+
+#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 volatile unsigned int *gpio_map = NULL;
+
+static int setup_io(Driver *drvthis)
+{
+	void *gpio_mem;
+	int  mem_fd = 0;
+	/* open /dev/mem */
+	if (gpio_map != 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 int)gpio_mem % PAGE_SIZE)
+		gpio_mem += PAGE_SIZE - ((unsigned int)gpio_mem % PAGE_SIZE);
+
+	gpio_map = (unsigned int *)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.
+
+    return 0;
+}
+
+		/* gpio pins 3, 5, 27 available on S5 */
+static const int gpio_pins[] = {  0,  1, -1, -1,  4, -1, -1,  7,
+				  8,  9, 10, 11, -1, -1, 14, 15,
+				 -1, 17, 18, -1, -1, 21, 22, 23,
+		/* 8-31 accessible via board-id resistors R3-R10 */
+				 24, 25, -1, -1, -28, -29, -30, -31 };
+
+static int setup_gpio(int gpio)
+{
+	volatile int i;
+
+	if (gpio > 31 || gpio_pins[gpio] < 0) {
+		printf("%s: Invalid gpio pin %i - Mapped to %i\n",
+				__FUNCTION__, gpio, gpio_pins[gpio]);
+		return -1;
+	}
+
+		printf("%s: gpio pin %i - Mapped to %i\n", __FUNCTION__, gpio, gpio_pins[gpio]);
+
+
+	*(gpio_map+0x0025) &= ~3;
+	/*  After writing to the GPPUD register, need to wait
+	    150 cycles as per p101 BCM2835.pdf. The following
+	    while loop uses approx five instructions plus another
+	    two to load the counter.
+	    Note: the int must be volatile or gcc will optimise
+	    loop out. */
+	i=30; while (--i); // need a 150 cycle min wait
+	*(gpio_map+0x0026+(gpio/32)) = 1<<(gpio%32);
+	// Another 150 cycle wait required after a write to GPPUDCLK
+	i=30; while (--i);
+	*(gpio_map+0x0025) &= ~3;
+	*(gpio_map+0x0026+(gpio/32)) = 0;
+	*(gpio_map+(gpio/10)) = (*(gpio_map+(gpio/10))&~(7<<((gpio%10)*3)))|(1<<((gpio%10)*3));
+	return 0;
+}
+
+static void cleanup_io(PrivateData *p)
+{
+
+	INP_GPIO(p->rpi_gpio->enable);
+	INP_GPIO(p->rpi_gpio->rs);
+	INP_GPIO(p->rpi_gpio->d7);
+	INP_GPIO(p->rpi_gpio->d6);
+	INP_GPIO(p->rpi_gpio->d5);
+	INP_GPIO(p->rpi_gpio->d4);
+	munmap((caddr_t)gpio_map, BLOCK_SIZE);
+	free(p->rpi_gpio);
+	return;
+}
+
+/**
+ * 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->rpi_gpio = malloc(sizeof(struct rpi_gpio_map));
+	if (p->rpi_gpio == NULL) {
+		report(RPT_ERR, "%s: unable to allocate memory", drvthis->name);
+		return -1;
+	}
+
+	p->rpi_gpio->enable = drvthis->config_get_int(drvthis->name, "EN", 0, EN);
+	p->rpi_gpio->rs = drvthis->config_get_int(drvthis->name, "RS", 0, RS);
+	p->rpi_gpio->d7 = drvthis->config_get_int(drvthis->name, "D7", 0, D7);
+	p->rpi_gpio->d6 = drvthis->config_get_int(drvthis->name, "D6", 0, D6);
+	p->rpi_gpio->d5 = drvthis->config_get_int(drvthis->name, "D5", 0, D5);
+	p->rpi_gpio->d4 = drvthis->config_get_int(drvthis->name, "D4", 0, D4);
+
+	if (p->rpi_gpio->enable == p->rpi_gpio->rs ||
+			p->rpi_gpio->enable == p->rpi_gpio->d7 ||
+			p->rpi_gpio->enable == p->rpi_gpio->d6 ||
+			p->rpi_gpio->enable == p->rpi_gpio->d5 ||
+			p->rpi_gpio->enable == p->rpi_gpio->d4 ||
+			p->rpi_gpio->rs == p->rpi_gpio->d7 ||
+			p->rpi_gpio->rs == p->rpi_gpio->d6 ||
+			p->rpi_gpio->rs == p->rpi_gpio->d5 ||
+			p->rpi_gpio->rs == p->rpi_gpio->d4 ||
+			p->rpi_gpio->d7 == p->rpi_gpio->d6 ||
+			p->rpi_gpio->d7 == p->rpi_gpio->d5 ||
+			p->rpi_gpio->d7 == p->rpi_gpio->d4 ||
+			p->rpi_gpio->d6 == p->rpi_gpio->d5 ||
+			p->rpi_gpio->d6 == p->rpi_gpio->d4 ||
+			p->rpi_gpio->d5 == p->rpi_gpio->d4) {
+		report(RPT_ERR, "Can not use the same GPIO pin twice\n");
+		return -1;
+	}
+
+	if (setup_gpio(p->rpi_gpio->enable) ||
+			setup_gpio(p->rpi_gpio->rs) ||
+			setup_gpio(p->rpi_gpio->d7) ||
+			setup_gpio(p->rpi_gpio->d6) ||
+			setup_gpio(p->rpi_gpio->d5) ||
+			setup_gpio(p->rpi_gpio->d4)) {
+		report(RPT_ERR, "Invalid GPIO specified\n");
+		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;
+	p->hd44780_functions->close = cleanup_io;
+
+	// 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)
+{
+
+	if (displayID > 1) {
+		return;
+	}
+	if (gpio_map == NULL) {
+		printf("gpio not set up.\n");
+		return;
+	}
+	if (flags == RS_INSTR) {
+                SET_GPIO(p->rpi_gpio->rs, 0);
+	}
+	else { // flags == RS_DATA
+                SET_GPIO(p->rpi_gpio->rs, 1);
+	}
+	// Clear data lines ready for nibbles
+	SET_GPIO(p->rpi_gpio->d7, 0);
+	SET_GPIO(p->rpi_gpio->d6, 0);
+	SET_GPIO(p->rpi_gpio->d5, 0);
+	SET_GPIO(p->rpi_gpio->d4, 0);
+
+	p->hd44780_functions->uPause(p, 50);
+
+	// Output upper nibble first
+	SET_GPIO(p->rpi_gpio->d7, (ch & 0x80));
+	SET_GPIO(p->rpi_gpio->d6, (ch & 0x40));
+	SET_GPIO(p->rpi_gpio->d5, (ch & 0x20));
+	SET_GPIO(p->rpi_gpio->d4, (ch & 0x10));
+
+	p->hd44780_functions->uPause(p, 50);
+
+	// Data is clocked on the falling edge of EN
+	SET_GPIO(p->rpi_gpio->enable, 1);
+	p->hd44780_functions->uPause(p, 50);
+	SET_GPIO(p->rpi_gpio->enable, 0);
+	p->hd44780_functions->uPause(p, 50);
+
+	// Do same for lower nibble
+	SET_GPIO(p->rpi_gpio->d7, 0);
+	SET_GPIO(p->rpi_gpio->d6, 0);
+	SET_GPIO(p->rpi_gpio->d5, 0);
+	SET_GPIO(p->rpi_gpio->d4, 0);
+	p->hd44780_functions->uPause(p, 50);
+	SET_GPIO(p->rpi_gpio->d7, (ch & 0x08));
+	SET_GPIO(p->rpi_gpio->d6, (ch & 0x04));
+	SET_GPIO(p->rpi_gpio->d5, (ch & 0x02));
+	SET_GPIO(p->rpi_gpio->d4, (ch & 0x01));
+	p->hd44780_functions->uPause(p, 50);
+
+	SET_GPIO(p->rpi_gpio->enable, 1);
+	p->hd44780_functions->uPause(p, 50);
+	SET_GPIO(p->rpi_gpio->enable, 0);
+	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 -Naur lcdproc-0.5.6/server/drivers/hd44780-rpi.h lcdproc-0.5.6-patched/server/drivers/hd44780-rpi.h
--- lcdproc-0.5.6/server/drivers/hd44780-rpi.h	1970-01-01 01:00:00.000000000 +0100
+++ lcdproc-0.5.6-patched/server/drivers/hd44780-rpi.h	2012-08-28 21:26:51.000000000 +0200
@@ -0,0 +1,31 @@
+#ifndef HD_LCDRPI_H
+#define HD_LCDRPI_H
+
+#include "lcd.h"					  /* for Driver */
+
+// initialise this particular driver
+int hd_init_rpi(Driver *drvthis);
+
+/* rpi_map is addcessed through the hd44780_private_data struct.
+    Data stored here is used for mapping physical GPIO pins to
+    BCM2835 gpio */
+struct rpi_gpio_map {
+	int enable;
+	int rs;
+	int d7;
+	int d6;
+	int d5;
+	int d4;
+};
+
+
+#define BCM2708_PERI_BASE        0x20000000
+#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
+
+#define PAGE_SIZE (4*1024)
+#define BLOCK_SIZE (4*1024)
+
+#define INP_GPIO(g) *(gpio_map+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define SET_GPIO(g,a) *(gpio_map+(a?7:10))=1<<(g%32);
+
+#endif // HD_LCDRPI_H
diff -Naur lcdproc-0.5.6/server/drivers/Makefile.am lcdproc-0.5.6-patched/server/drivers/Makefile.am
--- lcdproc-0.5.6/server/drivers/Makefile.am	2012-08-19 16:29:08.000000000 +0200
+++ lcdproc-0.5.6-patched/server/drivers/Makefile.am	2012-11-24 10:24:30.616524613 +0100
@@ -95,7 +95,7 @@
 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 hd44780-usb4all.c hd44780-usb4all.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 hd44780-usb4all.c hd44780-usb4all.h port.h hd44780-rpi.c hd44780-rpi.h lpt-port.h timing.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