Add 'spi' connection type by S. Dawson to the hd44780 driver.

This commit is contained in:
mmdolze
2014-01-29 21:48:03 +00:00
parent 8230c0ace1
commit dca261e98a
12 changed files with 287 additions and 5 deletions
+2 -1
View File
@@ -17,7 +17,8 @@ v0.5dev (ongoing development)
* lcdproc client: Add option to turn off title on OldTime screen
+ glcd driver: Connection type 'x11' that draws to a X window (S. Meharg)
+ glcd driver: 'picolcdgfx' for picoLCD 256x64 from Mini-Box.com (S. Meharg)
* picolcd: Improvements to IR processing (M. Jones).
* picolcd: Improvements to IR processing (M. Jones)
+ hd44780: Added 'spi' connection type (S. Dawson)
v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
+1 -1
View File
@@ -538,7 +538,7 @@ ConnectionType=4bit
# For I2C connections this sets the slave address (usually 0x20).
Port=0x378
# Device of the serial or I2C interface [default: /dev/lcd]
# Device of the serial, I2C, or SPI interface [default: /dev/lcd]
Device=/dev/ttyS0
# Bitrate of the serial port (0 for interface default)
+3
View File
@@ -232,6 +232,9 @@ dnl else
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-i2c.o"
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-piplate.o"
fi
if test "$x_ac_have_spi" = yes; then
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-spi.o"
fi
dnl The hd4470-rpi driver only works on a Raspberry Pi,
dnl which is an ARM platform. Require people to compile on
dnl (or for) ARM to get it.
+6
View File
@@ -167,6 +167,12 @@ if test "$x_ac_have_i2c" = yes; then
AC_DEFINE(HAVE_I2C,[1],[Define to 1 if you have the i2c headers])
fi
x_ac_have_spi=no
AC_CHECK_HEADERS([linux/spi/spidev.h], [x_ac_have_spi=yes])
if test "$x_ac_have_spi" = yes; then
AC_DEFINE(HAVE_SPI,[1],[Define to 1 if you have the spi headers])
fi
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
+3
View File
@@ -182,6 +182,9 @@ USS-720 USB-to-IEEE 1284 Bridge (Belkin F5U002 USB Parallel Printer Adapters)
.B i2c
LCD in 4-bit mode driven by PCF8574(A) / PCA9554(A), connected via I2C bus
.TP
.B spi
LCD with KS0073 or equivalent in serial mode, connected via SPI bus
.TP
.B ftdi
USB connection via a FTDI FT2232D chip in bitbang mode
.TP
+32 -2
View File
@@ -37,7 +37,7 @@ various special features.
<para>
The following table lists the available connection types, sorted by the kind
of connection (parallel port, serial port, USB, I2C or others).
of connection (parallel port, serial port, USB, I2C, SPI or others).
</para>
<para>
@@ -155,6 +155,14 @@ of connection (parallel port, serial port, USB, I2C or others).
<entry><literal><link linkend="hd44780-piplate">piplate</link></literal></entry>
<entry>Adafruit RGB Positive 16x2 LCD+Keypad for Raspberry Pi</entry>
</row>
<!-- SPI -->
<row>
<entry spanname="fullwidth">SPI (Serial Peripheral Interface):</entry>
</row>
<row>
<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>
</row>
<!-- Other -->
<row>
<entry spanname="fullwidth">Other connection types:</entry>
@@ -1757,6 +1765,27 @@ that. The BL output below should be connected to the BL input in the
</sect3>
<sect3 id="hd44780-spi">
<title>spi</title>
<para>
This connection type drives a LCD in serial mode (supported on Hitachi HD66712,
Samsung KS0073 and KS0074 (and clones) controllers) connected to some Linux
SPI device.
</para>
<para>
This connection type is currently only supported on Linux. It is strongly
recommended to use a SPI implementation with hardware support, e.g. on the
Raspberry Pi.
</para>
<para>
As the SPI communication to the display cannot drive a backlight switch, this
connection type features a <replaceable>BacklightDevice</replaceable> option
that can use a GPIO pin exposed via sysfs (see <ulink url="http://elinux.org/GPIO">eLinux GPIO</ulink>).
</para>
</sect3>
<sect3 id="hd44780-ftdi">
<title>FTDI FT2232D USB chip "ftdi"</title>
@@ -3122,8 +3151,8 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<!-- Keep this list sorted according to the table in hd44780-drivers.h -->
<emphasis><parameter><literal>4bit</literal></parameter></emphasis> |
<parameter><literal>8bit</literal></parameter> |
<parameter><literal>winamp</literal></parameter> |
<parameter><literal>serialLpt</literal></parameter> |
<parameter><literal>winamp</literal></parameter> |
<parameter><literal>picanlcd</literal></parameter> |
<parameter><literal>lcdserializer</literal></parameter> |
<parameter><literal>los-panel</literal></parameter> |
@@ -3141,6 +3170,7 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<parameter><literal>ftdi</literal></parameter> |
<parameter><literal>i2c</literal></parameter> |
<parameter><literal>piplate</literal></parameter> |
<parameter><literal>spi</literal></parameter> |
<parameter><literal>ethlcd</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
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-ext8bit.c hd44780-ext8bit.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-rpi.c hd44780-rpi.h hd44780-piplate.c hd44780-piplate.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
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
+6
View File
@@ -33,6 +33,9 @@
# include "hd44780-i2c.h"
# include "hd44780-piplate.h"
#endif
#ifdef HAVE_SPI
# include "hd44780-spi.h"
#endif
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
#endif
@@ -82,6 +85,9 @@ static const ConnectionMapping connectionMapping[] = {
#ifdef HAVE_I2C
{ "i2c", HD44780_CT_I2C, IF_TYPE_I2C, hd_init_i2c },
{ "piplate", HD44780_CT_PIPLATE, IF_TYPE_I2C, hd_init_i2c_piplate },
#endif
#ifdef HAVE_SPI
{ "spi", HD44780_CT_SPI, IF_TYPE_SPI, hd_init_spi },
#endif
/* TCP socket connection types */
#ifdef WITH_ETHLCD
+2
View File
@@ -55,6 +55,7 @@
#define HD44780_CT_USB4ALL 21
#define HD44780_CT_RASPBERRYPI 22
#define HD44780_CT_PIPLATE 23
#define HD44780_CT_SPI 24
/**@}*/
/** \name Symbolic names for interface types
@@ -65,6 +66,7 @@
#define IF_TYPE_USB 3
#define IF_TYPE_I2C 4
#define IF_TYPE_TCP 5
#define IF_TYPE_SPI 6
/**@}*/
/** \name Symbolic default values
+215
View File
@@ -0,0 +1,215 @@
/** \file server/drivers/hd44780-spi.c
* \c SPI connection type of \c hd44780 driver for Hitachi HD44780 based LCD displays.
*
* The LCD is operated in its serial mode to be connected via the SPI bus
* using the Linux kernel spidev interface. The LCD SPI device should be
* declared in your board setup code.
*/
/*-
* Copyright (C) 2013 Simon Dawson <spdawson@gmail.com>
*
* 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.
*
* Configuration:
* Device=/dev/spidev0.0 # the device file of the spi bus (spi 0, chipselect 0)
* BacklightDevice=(undef) # the device file for the backlight (1 = on, 0 = off)
*/
#include "hd44780-spi.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 spi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
void spi_HD44780_backlight(PrivateData *p, unsigned char state);
#define DEFAULT_DEVICE "/dev/spidev0.0"
/** KS0073 5-bit sync lead-in on SPI interface */
#define SYNC 0xF8u
/** KS0073 Read Write bit: 1 = read selected data/register, 0 = write to selected data/register */
#define RW 0x04u
/** KS0073 Register Select bit: 0 = instruction register follows, 1 = data register follows */
#define RS 0x02u
/**
* Reverses the bits of \a u8.
* \param u8 byte of which to reverse the bits.
* \return Value resulting from \a u8 with reversed bits.
*/
static inline uint8_t
bit_reverse8(uint8_t u8)
{
/*
* See
* http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
* for how this works and. This code snippet is in the public domain.
*/
return (uint8_t) (((u8 * 0x0802LU & 0x22110LU) | (u8 * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
}
/**
* Do a SPI transfer by sending \c length bytes of \c outbuf and read the same
* number of bytes into \c inbuf.
* \param p Pointer to driver's private data structure.
* \param outbuf Buffer holding data to send.
* \param inbuf Buffer to store incoming data (or NULL).
* \param length Length of buffers (both).
* \return Status from ioctl.
*/
static int
spi_transfer(PrivateData *p, const unsigned char *outbuf, unsigned char *inbuf, unsigned length)
{
struct spi_ioc_transfer xfer;
int status;
static unsigned char no_more_errormsgs = 0;
memset(&xfer, 0, sizeof(xfer));
xfer.tx_buf = (unsigned long) outbuf;
xfer.rx_buf = (unsigned long) inbuf;
xfer.len = length;
p->hd44780_functions->drv_debug(RPT_DEBUG, "SPI sending %02x %02x %02x",
outbuf[0], outbuf[1], length > 2 ? outbuf[2] : 0xFFu);
status = ioctl(p->fd, SPI_IOC_MESSAGE(1), &xfer);
if (status < 0) {
p->hd44780_functions->drv_report(no_more_errormsgs ? RPT_DEBUG : RPT_ERR,
"HD44780: SPI: spidev write data %u failed: %s",
status, strerror(errno));
no_more_errormsgs = 1;
}
#ifdef DEBUG
if (inbuf)
p->hd44780_functions->drv_debug(RPT_DEBUG, "SPI returned data %02x %02x %02x",
inbuf[0], inbuf[1], length > 2 ? inbuf[2] : 0xFFu);
#endif
return status;
}
/**
* Initialize the driver.
* \param drvthis Pointer to driver structure.
* \retval 0 Success.
* \retval -1 Error.
*/
int
hd_init_spi(Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
HD44780_functions *hd44780_functions = p->hd44780_functions;
char device[256] = DEFAULT_DEVICE;
char backlight_device[256] = "";
/* READ CONFIG FILE */
/* Get and open SPI 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: SPI: Using device '%s'", device);
p->fd = open(device, O_RDWR);
if (p->fd < 0) {
report(RPT_ERR, "HD44780: SPI: open spidev device '%s' failed: %s", device,
strerror(errno));
return -1;
}
/* Get and open the backlight device */
p->backlight_bit = -1;
strncpy(backlight_device,
drvthis->config_get_string(drvthis->name, "BacklightDevice", 0, ""),
sizeof(backlight_device));
backlight_device[sizeof(backlight_device) - 1] = '\0';
if (strlen(backlight_device) > 0) {
report(RPT_INFO, "HD44780: SPI: Using backlight_device '%s'", backlight_device);
p->backlight_bit = open(backlight_device, O_RDWR);
if (p->backlight_bit < 0) {
report(RPT_ERR, "HD44780: SPI: open backlight_device '%s' failed: %s",
backlight_device, strerror(errno));
}
else {
hd44780_functions->backlight = spi_HD44780_backlight;
}
}
hd44780_functions->senddata = spi_HD44780_senddata;
common_init(p, IF_8BIT);
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
spi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
{
unsigned char buf[3];
unsigned char reverse;
p->hd44780_functions->drv_report(RPT_DEBUG, "HD44780: SPI: sending %s %02x",
RS_INSTR == flags ? "CMD" : "DATA", ch);
if (flags == RS_INSTR)
buf[0] = SYNC;
else
buf[0] = SYNC | RS;
/* KS0073 wants Least Significant Bit first, with the added twist of
* peculiar splitting of a byte across 4 nibbles. If we ever need to
* read from the device, remember to bit_reverse8() each byte (note
* that replies aren't split into nibbles). */
reverse = bit_reverse8(ch);
buf[1] = reverse & 0xF0;
buf[2] = (reverse & 0x0F) << 4;
spi_transfer(p, buf, NULL, sizeof(buf));
}
/**
* Turn display backlight on or off.
* \param p Pointer to driver's private data structure.
* \param state New backlight status.
*
* KS0073 in SPI mode does not have a backlight control function. We
* assume instead that there is some device mapped to a file which we can
* write to.
*/
void
spi_HD44780_backlight(PrivateData *p, unsigned char state)
{
if (p->backlight_bit != -1) {
unsigned char byte = (state == BACKLIGHT_ON) ? '1' : '0';
if (write(p->backlight_bit, &byte, sizeof(byte)) < 0)
p->hd44780_functions->drv_report(RPT_ERR,
"HD44780: SPI: Cannot write to backlight device: %d (%s)",
errno, strerror(errno));
}
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef HD_SPI_H
#define HD_SPI_H
#include "lcd.h" /* for Driver */
/* initialise this particular driver */
int hd_init_spi(Driver *drvthis);
#endif
+7
View File
@@ -427,6 +427,13 @@ HD44780_init(Driver *drvthis)
(p->have_output?" out":"")
);
break;
case IF_TYPE_SPI:
sprintf(buf, "SPI %s%s%s",
(p->have_backlight?" bl":""),
(p->have_keypad?" key":""),
(p->have_output?" out":"")
);
break;
case IF_TYPE_TCP:
sprintf(buf, "TCP %s%s%s",
(p->have_backlight?" bl":""),