Add the pifacecad connection type to hd44780 driver (by Thomas Preston). This

is for the PiFace Contral And Display device from http://www.piface.org.uk/.
This commit is contained in:
mmdolze
2014-02-10 07:04:01 +00:00
parent a8d9504a3c
commit 417ce0555f
9 changed files with 432 additions and 3 deletions
+1
View File
@@ -20,6 +20,7 @@ v0.5dev (ongoing development)
* picolcd: Improvements to IR processing (M. Jones) * picolcd: Improvements to IR processing (M. Jones)
+ hd44780: Added 'spi' connection type (S. Dawson) + hd44780: Added 'spi' connection type (S. Dawson)
* hd55780/serial: Change data escape handling (G. Smith) * hd55780/serial: Change data escape handling (G. Smith)
+ hd44780: New connection type 'pifacecad' (T. Preston)
v0.5.6 v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead! - Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
+1 -1
View File
@@ -233,7 +233,7 @@ dnl else
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-piplate.o" HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-piplate.o"
fi fi
if test "$x_ac_have_spi" = yes; then if test "$x_ac_have_spi" = yes; then
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-spi.o" HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-spi.o hd44780-hd44780-pifacecad.o"
fi fi
dnl The hd4470-rpi driver only works on a Raspberry Pi, dnl The hd4470-rpi driver only works on a Raspberry Pi,
dnl which is an ARM platform. Require people to compile on dnl which is an ARM platform. Require people to compile on
+4 -1
View File
@@ -1,4 +1,4 @@
.TH LCDd 8 "24 March 2011" LCDproc "LCDproc suite" .TH LCDd 8 "February 10, 2014" LCDproc "LCDproc suite"
.SH NAME .SH NAME
LCDd - LCDproc server daemon LCDd - LCDproc server daemon
@@ -185,6 +185,9 @@ LCD in 4-bit mode driven by PCF8574(A) / PCA9554(A), connected via I2C bus
.B spi .B spi
LCD with KS0073 or equivalent in serial mode, connected via SPI bus LCD with KS0073 or equivalent in serial mode, connected via SPI bus
.TP .TP
.B pifacecad
PiFace Control and Display for the Raspberry Pi (http://www.piface.org.uk/)
.TP
.B ftdi .B ftdi
USB connection via a FTDI FT2232D chip in bitbang mode USB connection via a FTDI FT2232D chip in bitbang mode
.TP .TP
+48
View File
@@ -163,6 +163,10 @@ of connection (parallel port, serial port, USB, I2C, SPI or others).
<entry><literal><link linkend="hd44780-spi">spi</link></literal></entry> <entry><literal><link linkend="hd44780-spi">spi</link></literal></entry>
<entry>Display using a KS0073 or similar in serial mode accessed via Linux SPI device</entry> <entry>Display using a KS0073 or similar in serial mode accessed via Linux SPI device</entry>
</row> </row>
<row>
<entry><literal><link linkend="hd44780-pifacecad">pifacecad</link></literal></entry>
<entry>PiFace Control and Display for Raspberry Pi</entry>
</row>
<!-- Other --> <!-- Other -->
<row> <row>
<entry spanname="fullwidth">Other connection types:</entry> <entry spanname="fullwidth">Other connection types:</entry>
@@ -3090,6 +3094,49 @@ KeyDirect_5=Right
</sect3> </sect3>
<sect3 id="hd44780-pifacecad">
<title>PiFace Control and Display</title>
<para>
The <ulink url="http://www.piface.org.uk/products/piface_control_and_display/">PiFace Control and Display for Raspberry Pi</ulink>
from OpenLX SP Ltd combines a 16x2 Character LCD and navigation buttons using
the SPI bus on the Rasperry Pi.
</para>
<note>
<para>
The PiFace Control and Display features a IR receiver, which LCDproc does not
make use of. You have to setup and use LIRC for that. See
<ulink url="http://www.piface.org.uk/guides/setting_up_pifacecad/setting_up_PiFace_CAD_to_use_a_remote/">
Setting up PiFace Control And Display to use a remote</ulink>.
</para>
</note>
<example id="hd44780-pifacecad-config.example">
<title>HD44780: Configuration example for PiFace Control and Display connection type</title>
<screen>
<![CDATA[
[hd44780]
ConnectionType=pifacecad
Device=/dev/spidev0.1
Size=16x2
Backlight=yes
Keypad=yes
KeyMatrix_1_1=Left
KeyMatrix_1_2=Down
KeyMatrix_1_3=Up
KeyMatrix_1_4=Right
KeyMatrix_1_5=Escape
KeyMatrix_1_6=Enter
KeyMatrix_1_7=Left
KeyMatrix_1_8=Right
]]>
</screen>
</example>
</sect3>
</sect2> </sect2>
@@ -3171,6 +3218,7 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<parameter><literal>i2c</literal></parameter> | <parameter><literal>i2c</literal></parameter> |
<parameter><literal>piplate</literal></parameter> | <parameter><literal>piplate</literal></parameter> |
<parameter><literal>spi</literal></parameter> | <parameter><literal>spi</literal></parameter> |
<parameter><literal>pifacecad</literal></parameter> |
<parameter><literal>ethlcd</literal></parameter> | <parameter><literal>ethlcd</literal></parameter> |
<parameter><literal>raspberrypi</literal></parameter> <parameter><literal>raspberrypi</literal></parameter>
} }
+1 -1
View File
@@ -95,7 +95,7 @@ EXTRA_glcd_SOURCES = glcd-t6963.c t6963_low.c t6963_low.h glcd-png.c glcd-serdis
glcdlib_SOURCES = lcd.h lcd_lib.h glcdlib.h glcdlib.c report.h 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 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 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 = port.h lpt-port.h timing.h lcd_sem.c lcd_sem.h hd44780-4bit.c hd44780-4bit.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-ext8bit.c hd44780-ext8bit.h hd44780-ftdi.c hd44780-ftdi.h hd44780-i2c.c hd44780-i2c.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-lis2.c hd44780-lis2.h hd44780-piplate.c hd44780-piplate.h hd44780-rpi.c hd44780-rpi.h hd44780-serial.c hd44780-serial.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-spi.c hd44780-spi.h hd44780-usb4all.c hd44780-usb4all.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-uss720.c hd44780-uss720.h hd44780-winamp.c hd44780-winamp.h EXTRA_hd44780_SOURCES = port.h lpt-port.h timing.h lcd_sem.c lcd_sem.h hd44780-4bit.c hd44780-4bit.h hd44780-bwct-usb.c hd44780-bwct-usb.h hd44780-ethlcd.c hd44780-ethlcd.h hd44780-ext8bit.c hd44780-ext8bit.h hd44780-ftdi.c hd44780-ftdi.h hd44780-i2c.c hd44780-i2c.h hd44780-lcd2usb.c hd44780-lcd2usb.h hd44780-lis2.c hd44780-lis2.h hd44780-pifacecad.c hd44780-pifacecad.h hd44780-piplate.c hd44780-piplate.h hd44780-rpi.c hd44780-rpi.h hd44780-serial.c hd44780-serial.h hd44780-serialLpt.c hd44780-serialLpt.h hd44780-spi.c hd44780-spi.h hd44780-usb4all.c hd44780-usb4all.h hd44780-usblcd.c hd44780-usblcd.h hd44780-usbtiny.c hd44780-usbtiny.h hd44780-uss720.c hd44780-uss720.h hd44780-winamp.c hd44780-winamp.h
i2500vfd_SOURCES = lcd.h i2500vfd.c i2500vfd.h glcd_font5x8.h report.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 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 imon_SOURCES = lcd.h lcd_lib.h hd44780-charmap.h imon.h imon.c report.h adv_bignum.h
+2
View File
@@ -35,6 +35,7 @@
#endif #endif
#ifdef HAVE_SPI #ifdef HAVE_SPI
# include "hd44780-spi.h" # include "hd44780-spi.h"
# include "hd44780-pifacecad.h"
#endif #endif
#ifdef WITH_ETHLCD #ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h" # include "hd44780-ethlcd.h"
@@ -88,6 +89,7 @@ static const ConnectionMapping connectionMapping[] = {
#endif #endif
#ifdef HAVE_SPI #ifdef HAVE_SPI
{ "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi }, { "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi },
{ "pifacecad", HD44780_CT_PIFACECAD, IF_TYPE_SPI, hd_init_pifacecad },
#endif #endif
/* TCP socket connection types */ /* TCP socket connection types */
#ifdef WITH_ETHLCD #ifdef WITH_ETHLCD
+1
View File
@@ -56,6 +56,7 @@
#define HD44780_CT_RASPBERRYPI 22 #define HD44780_CT_RASPBERRYPI 22
#define HD44780_CT_PIPLATE 23 #define HD44780_CT_PIPLATE 23
#define HD44780_CT_SPI 24 #define HD44780_CT_SPI 24
#define HD44780_CT_PIFACECAD 25
/**@}*/ /**@}*/
/** \name Symbolic names for interface types /** \name Symbolic names for interface types
+365
View File
@@ -0,0 +1,365 @@
/** \file server/drivers/hd44780-pifacecad.c
* \c PiFace Control and Display connection type (SPI) of \c hd44780 driver for
* Hitachi HD44780 based LCD displays.
*
* The LCD is operated in its 4 bit-mode to be connected to the 8 bit Port B
* of a single MCP23S17 that is accessed by the server via the SPI bus.
*/
/*-
* Copyright (c) 2013 Thomas Preston <thomas.preston@openlx.org.uk>
*
* 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.
*/
/*-
* The connections are (MCP23S17):
* Port A Pin 0 Switch 0 (Left)
* Port A Pin 1 Switch 1 (Down)
* Port A Pin 2 Switch 2 (Up)
* Port A Pin 3 Switch 3 (Right)
* Port A Pin 4 Switch 4 (Enter)
* Port A Pin 5 Switch 5 (Nav push)
* Port A Pin 6 Switch 6 (Nav left)
* Port A Pin 6 Switch 7 (Nav right)
* Port B Pin 0 D4
* Port B Pin 1 D5
* Port B Pin 2 D6
* Port B Pin 3 D7
* Port B Pin 4 EN
* Port B Pin 5 RW
* Port B Pin 6 RS
*
* Backlight
* Port B Pin 7 Backlight (optional, active-high)
*
* Configuration:
* device=/dev/spidev0.1 # the device file of the SPI bus
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "hd44780-pifacecad.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 <stdint.h>
#include <linux/spi/spidev.h>
void pifacecad_HD44780_senddata(PrivateData *p,
unsigned char displayID, unsigned char flags, unsigned char ch);
void pifacecad_HD44780_backlight(PrivateData *p, unsigned char state);
void pifacecad_HD44780_close(PrivateData *p);
unsigned char pifacecad_HD44780_scankeypad(PrivateData *p);
/** \name SPI bus configuration
*@{*/
#define DEFAULT_DEVICE "/dev/spidev0.1"
#define SPI_HW_ADDR 0 /**< Hardware address set by pins A0:2 */
const unsigned char spi_mode = 0; /**< Set SPI mode to CPOL = 0 (leading edge is rising)
* and CPHA = 0 (sample on leading edge) */
const unsigned char spi_bpw = 8; /**< Set SPI to 8 bits per word */
const unsigned long spi_speed = 10000000L; /**< Set SPI speed to 10MHz */
const unsigned char spi_delay = 0;
/**@}*/
/** \name MCP23S17 commands
*@{*/
#define WRITE_CMD 0
#define READ_CMD 1
/**@}*/
/** \name MCP23S17 Register addresses
*@{*/
#define IODIRA 0x00 /**< I/O direction A */
#define IODIRB 0x01 /**< I/O direction B */
#define IPOLA 0x02 /**< Input polarity A */
#define IPOLB 0x03 /**< Input polarity B */
#define IOCON 0x0A /**< I/O config (also 0x0B) */
#define GPPUA 0x0C /**< Port A pull-ups when input */
#define GPPUB 0x0D /**< Port B pull-ups when input */
#define GPIOA 0x12 /**< Port A */
#define GPIOB 0x13 /**< Port B */
/**@}*/
/* Ports */
#define SWITCH_PORT GPIOA /**< Switches are connected to port A */
#define LCD_PORT GPIOB /**< LCD and backlight are connected to port B */
/* LCD timing delays */
#define DELAY_PULSE_US 1 /**< 1us hold time for EN */
#define DELAY_SETTLE_US 40 /**< 40us delay for executing LCD command */
/** \name LCD control pins
* LCD control pins are connected to upper nibble of Port B on the MCP23S17
*@{*/
#define EN 0x10
#define RW 0x20
#define RS 0x40
#define BL 0x80
/**@}*/
/**
* Writes to a register on the MCP23S17.
*
* \param p Pointer to PrivateData structure.
* \param reg Register address to write to.
* \param data Data to write
*/
static void
mcp23s17_write_reg(PrivateData *p, unsigned char reg, unsigned char data)
{
unsigned char tx_buf[3] = { 0x40 | SPI_HW_ADDR | WRITE_CMD, reg, data };
unsigned char rx_buf[3];
struct spi_ioc_transfer spi;
spi.tx_buf = (unsigned long) tx_buf;
spi.rx_buf = (unsigned long) rx_buf;
spi.len = sizeof(tx_buf);
spi.delay_usecs = spi_delay;
spi.speed_hz = spi_speed;
spi.bits_per_word = spi_bpw;
/* do the SPI transaction */
if (ioctl(p->fd, SPI_IOC_MESSAGE(1), &spi) < 0) {
p->hd44780_functions->drv_report(RPT_ERR,
"HD44780: PiFaceCAD: mcp23s17_write_reg: There was "
"a error during the SPI transaction: %s",
strerror(errno));
}
}
/**
* Reads from a register on the MCP23S17.
*
* \param p Pointer to PrivateData structure.
* \param reg Register address to read from.
* \retval Value of the register. Returns zero (0) on error, too.
*/
static unsigned char
mcp23s17_read_reg(PrivateData *p, unsigned char reg)
{
unsigned char tx_buf[3] = { 0x40 | SPI_HW_ADDR | READ_CMD, reg, 0 };
unsigned char rx_buf[3] = { 0, 0, 0 };
struct spi_ioc_transfer spi;
spi.tx_buf = (unsigned long) tx_buf;
spi.rx_buf = (unsigned long) rx_buf;
spi.len = sizeof(tx_buf);
spi.delay_usecs = spi_delay;
spi.speed_hz = spi_speed;
spi.bits_per_word = spi_bpw;
/* do the SPI transaction */
if (ioctl(p->fd, SPI_IOC_MESSAGE(1), &spi) < 0) {
p->hd44780_functions->drv_report(RPT_ERR,
"HD44780: PiFaceCAD: mcp23s17_read_reg: There was"
"a error during the SPI transaction: %s",
strerror(errno));
return 0;
}
return rx_buf[2];
}
/**
* Writes control and data to HD44780 through Port B on MCP23S17.
*
* \param p Pointer to the PrivateData structure.
* \param data The data to write.
*/
static void
write_and_pulse(PrivateData *p, unsigned char data)
{
/* Enable: Off/On/Off - Doesn't seem to work any other way. */
mcp23s17_write_reg(p, LCD_PORT, data);
if (p->delayBus)
p->hd44780_functions->uPause(p, DELAY_PULSE_US);
mcp23s17_write_reg(p, LCD_PORT, data | EN);
if (p->delayBus)
p->hd44780_functions->uPause(p, DELAY_PULSE_US);
mcp23s17_write_reg(p, LCD_PORT, data);
p->hd44780_functions->uPause(p, DELAY_SETTLE_US);
}
/**
* Initialize the driver.
*
* \param drvthis Pointer to driver structure.
* \retval 0 Success.
* \retval -1 Error.
*/
int
hd_init_pifacecad(Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
HD44780_functions *hd44780_functions = p->hd44780_functions;
char device[256] = DEFAULT_DEVICE;
p->backlight_bit = BL; /* Backlight on during init */
/* 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: PiFaceCAD: Using device '%s'", device);
/* Open the SPI device */
if ((p->fd = open(device, O_RDWR)) < 0) {
report(RPT_ERR,
"HD44780: PiFaceCAD: open SPI device '%s' failed: %s",
device, strerror(errno));
return -1;
}
/* configure SPI device */
if (ioctl(p->fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
report(RPT_ERR, "HD44780: PiFaceCAD: Could not set SPI mode.");
return -1;
}
if (ioctl(p->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bpw) < 0) {
report(RPT_ERR, "HD44780: PiFaceCAD Could not set SPI bits per word.");
return -1;
}
if (ioctl(p->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) < 0) {
report(RPT_ERR, "HD44780: PiFaceCAD: Could not set SPI speed.");
return -1;
}
/* Set IO config */
mcp23s17_write_reg(p, IOCON, 0x08); /* Hardware Address Enable */
mcp23s17_write_reg(p, IODIRB, 0x00); /* Set GPIOB (LCD port) to output */
mcp23s17_write_reg(p, IODIRA, 0xff); /* Set GPIOA (switches) to input */
mcp23s17_write_reg(p, GPPUA, 0xff); /* enable pull-ups on input */
mcp23s17_write_reg(p, IPOLA, 0xff); /* invert inputs */
hd44780_functions->senddata = pifacecad_HD44780_senddata;
hd44780_functions->backlight = pifacecad_HD44780_backlight;
hd44780_functions->close = pifacecad_HD44780_close;
hd44780_functions->scankeypad = pifacecad_HD44780_scankeypad;
/* Send 0x03 a couple of times, which is ((FUNCSET | IF_8BIT) >> 4) */
write_and_pulse(p, 0x03);
hd44780_functions->uPause(p, 15000);
write_and_pulse(p, 0x03);
hd44780_functions->uPause(p, 5000);
write_and_pulse(p, 0x03);
hd44780_functions->uPause(p, 1000);
/* Now switch to IF_4BIT */
write_and_pulse(p, 0x02);
hd44780_functions->uPause(p, DELAY_SETTLE_US);
common_init(p, IF_4BIT);
report(RPT_INFO, "HD44780: PiFaceCAD: initialized");
return 0;
}
/**
* Closes the file descriptor of the HD44780 (SPI bus to MCP23S17).
*
* \param p Pointer to driver's private data structure.
*/
void
pifacecad_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
pifacecad_HD44780_senddata(PrivateData *p,
unsigned char displayID, unsigned char flags, unsigned char ch)
{
unsigned char portControl = 0;
unsigned char h = (ch >> 4) & 0x0f; /* high nibble */
unsigned char l = ch & 0x0f; /* low nibble */
if (flags == RS_INSTR)
portControl = 0;
else
portControl = RS;
portControl |= p->backlight_bit;
write_and_pulse(p, portControl | h);
write_and_pulse(p, portControl | l);
}
/**
* Turn display backlight on or off.
*
* \param p Pointer to driver's private data structure.
* \param state New backlight status.
*/
void
pifacecad_HD44780_backlight(PrivateData *p, unsigned char state)
{
unsigned char port_state = mcp23s17_read_reg(p, LCD_PORT);
p->backlight_bit = (state == BACKLIGHT_ON) ? BL : 0;
if (p->backlight_bit)
port_state |= BL; /* set */
else
port_state &= 0xff ^ BL; /* clear */
mcp23s17_write_reg(p, LCD_PORT, port_state);
}
/**
* Scan the LCD keys. Each button is connected to a pin on Port A. As the
* hd44780 driver only supports 5 direct keys return the pressed key as a
* matrix key code instead.
*
* \param p Pointer to driver's private data structure.
* \retval key Key code as matrix code (1,1) to (1,8).
*/
unsigned char
pifacecad_HD44780_scankeypad(PrivateData *p)
{
unsigned char keycode = 0;
unsigned char switch_state;
int i;
if ((switch_state = mcp23s17_read_reg(p, SWITCH_PORT)) == 0)
return 0;
/* detect which key is pressed (which bit is set) */
for (i = 0; i < 8; i++) {
if (switch_state & (1 << i)) {
/* convert to matrix code */
keycode = ((i + 1) << 4 | 1);
break;
}
}
return keycode;
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef HD_PIFACECAD_H
#define HD_PIFACECAD_H
#include "lcd.h" /* for Driver */
/* initialise this particular driver */
int hd_init_pifacecad(Driver *drvthis);
#endif