Patch adds support for the Adafruit PiPlate
Jonathan Brogdon <[email protected]> Mon, 11 Feb 2013 15:32:25 -0600
| Newsgroups | gmane.comp.sysutils.lcdproc |
|---|---|
| Message-ID | <CANAYU8Y-RCCi+ktF9oMd6x5S21Pp-eE6xBUozgzK89Md5-f=nA@mail.gmail.com> |
Never saw this on the mailing list, or a response. Re-sending. Jon ---------- Forwarded message ---------- From: Jonathan Brogdon <[email protected]> Date: Sat, Feb 9, 2013 at 1:26 AM Subject: [PATCH] Add support for the Adafruit PiPlate To: [email protected] For your consideration, I have attached a v0.5.6 patch which adds a driver for the Adafruit PiPlate (http://adafruit.com/products/1109). The PiPlate includes a HD44780 LCD and 5 button keys which is accessed via a MCP23017 I2C IO expander. The driver was adapted from the HD44780-i2c driver, which uses the PCF8574 I2C IO expander. Jon Brogdon _______________________________________________ LCDproc mailing list [email protected] http://lists.omnipotent.net/mailman/listinfo/lcdproc
lcdproc-piplate.patch
(application/octet-stream, 14.8 KB)
diff -urN ./lcdproc/acinclude.m4 ./lcdproc-piplate/acinclude.m4
--- ./lcdproc/acinclude.m4 2013-01-27 05:44:43.000000000 -0600
+++ ./lcdproc-piplate/acinclude.m4 2013-02-08 23:14:50.000000000 -0600
@@ -227,6 +227,7 @@
fi
if test "$x_ac_have_i2c" = yes; then
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c.o"
+ HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c-piplate.o"
fi
dnl The hd4470-rpi driver only works on a Raspberry Pi,
dnl which is an ARM platform. Require people to compile on
diff -urN ./lcdproc/server/drivers/hd44780-drivers.h ./lcdproc-piplate/server/drivers/hd44780-drivers.h
--- ./lcdproc/server/drivers/hd44780-drivers.h 2013-01-27 05:44:43.000000000 -0600
+++ ./lcdproc-piplate/server/drivers/hd44780-drivers.h 2013-02-08 23:23:16.000000000 -0600
@@ -31,6 +31,7 @@
#endif
#ifdef HAVE_I2C
# include "hd44780-i2c.h"
+# include "hd44780-i2c-piplate.h"
#endif
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
@@ -80,6 +81,7 @@
/* I2C connection types */
#ifdef HAVE_I2C
{ "i2c", HD44780_CT_I2C, IF_TYPE_I2C, hd_init_i2c },
+ { "i2c-piplate", HD44780_CT_I2C_PIPLATE, IF_TYPE_I2C, hd_init_i2c_piplate },
#endif
/* TCP socket connection types */
#ifdef WITH_ETHLCD
diff -urN ./lcdproc/server/drivers/hd44780-i2c-piplate.c ./lcdproc-piplate/server/drivers/hd44780-i2c-piplate.c
--- ./lcdproc/server/drivers/hd44780-i2c-piplate.c 1969-12-31 18:00:00.000000000 -0600
+++ ./lcdproc-piplate/server/drivers/hd44780-i2c-piplate.c 2013-02-09 00:22:12.000000000 -0600
@@ -0,0 +1,412 @@
+/** \file server/drivers/hd44780-i2c-piplate.c
+ * \c i2c (via MCP23017) connection type of \c hd44780 driver for
+ * Hitachi HD44780 based LCD displays connected to the
+ * MCP23017 I2C IO Explander (Adafruit PiPlate LCD).
+ *
+ * This driver implements the
+ * The LCD is operated in its 4 bit-mode to be connected to the 8 bit-port
+ * of a single MCP23017 i2c I/O expander that is accessed by the server via
+ * the i2c bus.
+ */
+
+/* Copyright (c) 2013 Jonathan Brogdon <[email protected]>
+ * 2005 Matthias Goebl <[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:
+ * MCP23017 LCD
+ * GPA8 Blue LCD backlight
+ * GPA7 Green LCD backlight
+ * GPA6 Red LCD backlight
+ * GPA4 Left key
+ * GPA3 Up key
+ * GPA2 Down key
+ * GPA1 Right key
+ * GPA0 Select key
+ * GPB1 D4 (11)
+ * GPB2 D5 (12)
+ * GPB3 D6 (13)
+ * GPB4 D7 (14)
+ * GPB5 EN (6)
+ * GPB6 RW (5)
+ * GPB7 RS (4)
+ *
+ * Configuration:
+ * device=/dev/i2c-1 # the device file of the i2c bus
+ * port=0x20 # the i2c address of the i2c port expander
+ *
+ * Based mostly on the hd44780-i2c module, see there for a complete history.
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+#include "hd44780-i2c-piplate.h"
+#include "hd44780-low.h"
+
+#include "report.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#define DEFAULT_DEVICE "/dev/i2c-0"
+
+void i2c_piplate_HD44780_senddata(PrivateData *p,
+ unsigned char displayID,
+ unsigned char flags,
+ unsigned char ch);
+void i2c_piplate_HD44780_backlight(PrivateData *p, unsigned char state);
+unsigned char i2c_piplate_HD44780_scankeypad(PrivateData *p);
+void i2c_piplate_HD44780_close(PrivateData *p);
+
+/* MCP23017 registers */
+#define MCP23017_IODIRA 0x00
+#define MCP23017_IODIRB 0x01
+#define MCP23017_GPPUA 0x0C
+#define MCP23017_GPPUB 0x0D
+#define MCP23017_GPIOA 0x12
+#define MCP23017_GPIOB 0x13
+#define MCP23017_OLATA 0x14
+#define MCP23017_OLATB 0x15
+
+/* GPIOA BITS */
+#define B_BIT (1 << 8)
+#define G_BIT (1 << 7)
+#define R_BIT (1 << 6)
+#define L_KEY_BIT (1 << 4)
+#define U_KEY_BIT (1 << 3)
+#define D_KEY_BIT (1 << 2)
+#define R_KEY_BIT (1 << 1)
+#define S_KEY_BIT (1 << 0)
+
+/* GPIOB BITS */
+#define RS_BIT (1 << 7)
+#define RW_BIT (1 << 6)
+#define EN_BIT (1 << 5)
+#define D0_BIT (1 << 4)
+#define D1_BIT (1 << 3)
+#define D2_BIT (1 << 2)
+#define D3_BIT (1 << 1)
+
+#define DATA_BIT_START_OFFSET 1
+
+/* Reverses the bits in a 4 bit word */
+#define SWIZZLE_4BITS(x) ((((x) & 0x01) << 3) | (((x) & 0x02) << 1) | (((x) & 0x04) >> 1) | (((x) & 0x08) >> 3))
+
+/* Swizzle and offset bits correctly for the PiPlate wiring */
+#define MAP_TO_DATA_PINS(x) (SWIZZLE_4BITS(x) << DATA_BIT_START_OFFSET)
+
+#define I2C_ADDR_MASK 0x7f
+#define I2C_PCAX_MASK 0x80
+
+/**
+ * Read one of the MCP23017 registers
+ * p Pointer to driver private data.
+ * reg Address of the register to read.
+ * val Pointer to the read buffer.
+ * 0 Success.
+ * -1 Error.
+ */
+static int
+i2c_read_reg(PrivateData *p, unsigned char reg, unsigned char *val)
+{
+ /* Set the address to be read */
+ if (write(p->fd,®,1) != 1) {
+ return -1;
+ }
+
+ /* Read the value */
+ if (read(p->fd,val,1) != 1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Write one of the MCP23017 registers
+ * p Pointer to driver private data.
+ * reg Address of the register to write.
+ * val Value to be written.
+ * 0 Success.
+ * -1 Error.
+ */
+static int
+i2c_write_reg(PrivateData *p, unsigned char reg, unsigned char val)
+{
+ unsigned char buf[2];
+
+ buf[0] = reg;
+ buf[1] = val;
+ if (write(p->fd,buf,sizeof(buf)) != sizeof(buf)) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Low level write to the LCD 4-bit interface.
+ * p Driver private data.
+ * val Value to be written.
+ * rs Register/Data select.
+ * 0 Success.
+ * -1 Error.
+ */
+static int
+i2c_write_4bits(PrivateData *p, unsigned char val, int rs)
+{
+ unsigned char nibble[2];
+ unsigned char write_val;
+ int nibble_idx = 0;
+
+ /* Split the val byte into nibbles */
+ nibble[0] = (val >> 4);
+ nibble[1] = (val & 0x0f);
+
+ for (nibble_idx=0;nibble_idx < 2;nibble_idx++) {
+ /* Adjust for 4-bit data pins */
+ write_val = MAP_TO_DATA_PINS(nibble[nibble_idx]);
+
+ /* Set the RS bit */
+ if (rs) {
+ write_val |= RS_BIT;
+ }
+ else {
+ write_val &= ~RS_BIT;
+ }
+
+ /* Set enable bit */
+ i2c_write_reg(p,MCP23017_GPIOB,write_val | EN_BIT);
+
+ usleep(1);
+
+ /* Clear enable bit */
+ i2c_write_reg(p,MCP23017_GPIOB,write_val & ~EN_BIT);
+
+ } /* for each nibble */
+
+ return 0;
+}
+
+/**
+ * Initialize the driver.
+ * \param drvthis Pointer to driver structure.
+ * \retval 0 Success.
+ * \retval -1 Error.
+ */
+int
+hd_init_i2c_piplate(Driver *drvthis)
+{
+ PrivateData *p = (PrivateData*) drvthis->private_data;
+ HD44780_functions *hd44780_functions = p->hd44780_functions;
+
+ char device[256] = DEFAULT_DEVICE;
+
+ /* READ CONFIG FILE */
+
+ /* Get serial device to use */
+ strncpy(device,
+ drvthis->config_get_string(drvthis->name,
+ "Device",
+ 0,
+ DEFAULT_DEVICE),
+ sizeof(device));
+ device[sizeof(device)-1] = '\0';
+ report(RPT_INFO,
+ "HD44780: I2C piplate: Using device '%s' and address %u for a MCP23017",
+ device,
+ p->port & I2C_ADDR_MASK);
+
+ /* Open the I2C device */
+ p->fd = open(device, O_RDWR);
+ if (p->fd < 0) {
+ report(RPT_ERR,
+ "HD44780: I2C piplate: open i2c device '%s' failed: %s",
+ device,
+ strerror(errno));
+ return(-1);
+ }
+
+ /* Set I2C address */
+ if (ioctl(p->fd,I2C_SLAVE, p->port & I2C_ADDR_MASK) < 0) {
+ report(RPT_ERR,
+ "HD44780: I2C piplate: set address to '%i': %s",
+ p->port & I2C_ADDR_MASK,
+ strerror(errno));
+ return(-1);
+ }
+
+ /* IODIRA - keys as input, all other as output */
+ i2c_write_reg(p, MCP23017_IODIRA,
+ (unsigned char) (L_KEY_BIT | U_KEY_BIT | D_KEY_BIT | R_KEY_BIT | S_KEY_BIT)
+ & ~(B_BIT | G_BIT | R_BIT));
+
+ /* IODIRB - LCD control/data bua signals as outputs */
+ i2c_write_reg(p, MCP23017_IODIRB,
+ (unsigned char) ~(RS_BIT | RW_BIT | EN_BIT | D0_BIT | D1_BIT | D2_BIT | D3_BIT));
+
+ /* GPPUA - Pullups for key switch inputs */
+ i2c_write_reg(p, MCP23017_GPPUA,
+ (unsigned char) (L_KEY_BIT | U_KEY_BIT | D_KEY_BIT | R_KEY_BIT | S_KEY_BIT)
+ & ~(B_BIT | G_BIT | R_BIT));
+
+ /* GPPUB - Pullups disabed */
+ i2c_write_reg(p, MCP23017_GPPUB, (unsigned char) 0x00);
+
+ /* Set driver functions */
+ hd44780_functions->senddata = i2c_piplate_HD44780_senddata;
+ hd44780_functions->backlight = i2c_piplate_HD44780_backlight;
+ hd44780_functions->scankeypad = i2c_piplate_HD44780_scankeypad;
+ hd44780_functions->close = i2c_piplate_HD44780_close;
+
+ /* Init the LCD */
+ i2c_write_4bits(p,0x33,0);
+ if (p->delayBus)
+ hd44780_functions->uPause(p, 1);
+
+ i2c_write_4bits(p,0x32,0);
+ if (p->delayBus)
+ hd44780_functions->uPause(p, 1);
+
+ i2c_write_4bits(p,0x28,0);
+ if (p->delayBus)
+ hd44780_functions->uPause(p, 1);
+
+ i2c_write_4bits(p,0x0C,0);
+ if (p->delayBus)
+ hd44780_functions->uPause(p, 1);
+
+ i2c_write_4bits(p,0x06,0);
+ if (p->delayBus)
+ hd44780_functions->uPause(p, 1);
+
+ /* Set up two-line, small character (5x8) mode */
+ hd44780_functions->senddata(p,
+ 0,
+ RS_INSTR, FUNCSET | IF_4BIT | TWOLINE | SMALLCHAR);
+ hd44780_functions->uPause(p, 40);
+
+ common_init(p, IF_4BIT);
+
+ report(RPT_INFO,"HD44780: I2C piplate: initialized!");
+
+ return 0;
+}
+
+/**
+ * Close the device.
+ * \param p Pointer to driver's private data structure.
+ */
+void
+i2c_piplate_HD44780_close(PrivateData *p) {
+ if (p->fd >= 0) {
+ close(p->fd);
+ }
+}
+
+
+/**
+ * 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
+i2c_piplate_HD44780_senddata(PrivateData *p,
+ unsigned char displayID,
+ unsigned char flags,
+ unsigned char ch)
+{
+ if (flags == RS_INSTR)
+ i2c_write_4bits(p,ch,0);
+ else
+ i2c_write_4bits(p,ch,1);
+
+ if ((p->backlight_bit) && (p->hd44780_functions->backlight)) {
+ p->hd44780_functions->backlight(p,1);
+ }
+ else {
+ p->hd44780_functions->backlight(p,1);
+ }
+}
+
+/**
+ * Turn display backlight on or off.
+ * \param p Pointer to driver's private data structure.
+ * \param state New backlight status.
+ */
+void
+i2c_piplate_HD44780_backlight(PrivateData *p, unsigned char state)
+{
+ unsigned char gpioa=0;
+
+ /* Set the backlit bit */
+ p->backlight_bit = (p->have_backlight ? 0xff : 0) & (state ? 1 : 0);
+
+ /* Read the RGB bits */
+ if (i2c_read_reg(p, MCP23017_GPIOA, &gpioa)) {
+ return;
+ }
+
+ /* Set or clear the RGB bits */
+ if (p->backlight_bit) {
+ gpioa &= ~(R_BIT | G_BIT | B_BIT);
+ }
+ else {
+ gpioa |= (R_BIT | G_BIT | B_BIT);
+ }
+
+ /* Write the RGB bits */
+ i2c_write_reg(p, MCP23017_GPIOA,gpioa);
+}
+
+/**
+ * Scan the LCD keys
+ * \param p Pointer to driver's private data structure.
+ * \retval key Key number
+ */
+unsigned char
+i2c_piplate_HD44780_scankeypad(PrivateData *p)
+{
+ unsigned char gpioa=0;
+
+ /* Read the key bits */
+ if (i2c_read_reg(p,MCP23017_GPIOA,&gpioa)) {
+ return 0;
+ }
+
+ /* Select key */
+ if (0==(gpioa & S_KEY_BIT)) {
+ return 1;
+ }
+
+ /* Up key */
+ if (0==(gpioa & U_KEY_BIT)) {
+ return 2;
+ }
+
+ /* Down key */
+ if (0==(gpioa & D_KEY_BIT)) {
+ return 3;
+ }
+
+ /* Left key */
+ if (0==(gpioa & L_KEY_BIT)) {
+ return 4;
+ }
+
+ /* Right key */
+ if (0==(gpioa & R_KEY_BIT)) {
+ return 5;
+ }
+
+ return 0;
+}
diff -urN ./lcdproc/server/drivers/hd44780-i2c-piplate.h ./lcdproc-piplate/server/drivers/hd44780-i2c-piplate.h
--- ./lcdproc/server/drivers/hd44780-i2c-piplate.h 1969-12-31 18:00:00.000000000 -0600
+++ ./lcdproc-piplate/server/drivers/hd44780-i2c-piplate.h 2013-02-08 23:34:35.000000000 -0600
@@ -0,0 +1,9 @@
+#ifndef HD_I2C_PP_H
+#define HD_I2C_PP_H
+
+#include "lcd.h" /* for Driver */
+
+/* initialise this particular driver */
+int hd_init_i2c_piplate(Driver *drvthis);
+
+#endif
diff -urN ./lcdproc/server/drivers/hd44780-low.h ./lcdproc-piplate/server/drivers/hd44780-low.h
--- ./lcdproc/server/drivers/hd44780-low.h 2013-01-27 05:44:43.000000000 -0600
+++ ./lcdproc-piplate/server/drivers/hd44780-low.h 2013-02-08 23:24:29.000000000 -0600
@@ -54,6 +54,7 @@
#define HD44780_CT_USBTINY 20
#define HD44780_CT_USB4ALL 21
#define HD44780_CT_RASPBERRYPI 22
+#define HD44780_CT_I2C_PIPLATE 23
/**@}*/
/** \name Symbolic names for interface types
diff -urN ./lcdproc/server/drivers/Makefile.am ./lcdproc-piplate/server/drivers/Makefile.am
--- ./lcdproc/server/drivers/Makefile.am 2013-01-27 05:44:43.000000000 -0600
+++ ./lcdproc-piplate/server/drivers/Makefile.am 2013-02-08 23:18:06.000000000 -0600
@@ -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 hd44780-rpi.c hd44780-rpi.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 hd44780-i2c-piplate.c hd44780-i2c-piplate.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