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