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 -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
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 = 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
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
+2
View File
@@ -35,6 +35,7 @@
#endif
#ifdef HAVE_SPI
# include "hd44780-spi.h"
# include "hd44780-pifacecad.h"
#endif
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
@@ -88,6 +89,7 @@ static const ConnectionMapping connectionMapping[] = {
#endif
#ifdef HAVE_SPI
{ "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi },
{ "pifacecad", HD44780_CT_PIFACECAD, IF_TYPE_SPI, hd_init_pifacecad },
#endif
/* TCP socket connection types */
#ifdef WITH_ETHLCD
+1
View File
@@ -56,6 +56,7 @@
#define HD44780_CT_RASPBERRYPI 22
#define HD44780_CT_PIPLATE 23
#define HD44780_CT_SPI 24
#define HD44780_CT_PIFACECAD 25
/**@}*/
/** \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