Add 'raspberrypi' connection type to HD44780 driver (by P. Corner).

This commit is contained in:
mmdolze
2013-01-27 11:44:42 +00:00
parent 48b1c1ee40
commit 96502bcfdf
8 changed files with 715 additions and 21 deletions
+1
View File
@@ -10,6 +10,7 @@ v0.5dev (ongoing development)
* sed1520: Add an option for inverted segment mapping (idea by R. Buchert)
* Fix build if compiled with --enable-permissive-menu-goto (#3599609)
* glcd driver: Add direct support for framebuffer with paged memory layout
+ hd44780: Added 'raspberrypi' connection type (P. Corner)
v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
+9
View File
@@ -228,6 +228,15 @@ dnl else
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. Require people to compile on
dnl (or for) ARM to get it.
case $host in
arm*-*-linux*)
HD44780_DRIVERS="$HD44780_DRIVERS hd44780-hd44780-rpi.o"
AC_DEFINE([WITH_RASPBERRYPI],[1],[Define if you are using a Raspberry Pi.])
;;
esac
DRIVERS="$DRIVERS hd44780${SO}"
actdrivers=["$actdrivers hd44780"]
;;
+198 -18
View File
@@ -155,6 +155,12 @@ Last but not least, for special purposes, there are even more connection types:
<link linkend="hd44780-ethlcd">ethlcd</link>:
Display connected via TCP to PoE powered ethlcd device (<ulink url="http://manio.skyboo.net/ethlcd/"></ulink>)
</para></listitem>
<listitem><para>
<link linkend="hd44780-raspberrypi">raspberrypi</link>:
LCD connected to the GPIO header of a Raspberry Pi
</para></listitem>
</itemizedlist>
@@ -2953,6 +2959,161 @@ software adjustable contrast and brightness (backlight).
</sect3>
<sect3 id="hd44780-raspberrypi">
<title>Raspberry Pi</title>
<para>This connection type supports a single LCD connected to the GPIO header P1
on a Raspberry Pi.</para>
<para>It supports a switchable backlight connected to pin P1-11 by default. Use
the switch circuit as described in <xref linkend="hd44780-ftdi-backlight"/>.</para>
<warning>
<para>The signal level on the GPIO pins is 3.3 V and they are said not to
be 5 V tolerant. Therefore the R/W pin of the display <emphasis>must
</emphasis> be wired to GND to prevent 5V logic appearing on the GPIO
pins. For the same reason the backlight cicuit from <xref linkend=
"hd44780-connections-backlight.circuit"/> <emphasis>must not</emphasis> be
used.</para>
<para>Powering a LCD that uses 5 V from pin P1-02 will work. Powering a
LCD from 3.3 V (pin P1-01) will only work if it is designed for 3.3 V
operation.</para>
</warning>
<table id="hd44780-raspberrypi.pin-mapping">
<title>HD44780: Default pin mapping for Raspberry Pi</title>
<tgroup cols="5" align="left">
<colspec colname="rp1"/>
<colspec colname="rpi2" align="right"/>
<colspec colname="base" align="center"/>
<colspec colname="lcd1"/>
<colspec colname="lcd2"/>
<thead>
<row>
<entry namest="rpi1" nameend="rpi2" align="center">Connector</entry>
<entry morerows="1">&lt;-&gt;</entry>
<entry namest="lcd1" nameend="lcd2" align="center">LCD</entry>
</row>
<row>
<entry>Pin Name</entry>
<entry>Pin Number</entry>
<entry>Name</entry>
<entry>Pin</entry>
</row>
</thead>
<tbody>
<row>
<entry>GPIO18</entry>
<entry>P1-12</entry>
<entry></entry>
<entry>D7</entry>
<entry>14</entry>
</row>
<row>
<entry>GPIO23</entry>
<entry>P1-16</entry>
<entry></entry>
<entry>D6</entry>
<entry>13</entry>
</row>
<row>
<entry>GPIO24</entry>
<entry>P1-18</entry>
<entry></entry>
<entry>D5</entry>
<entry>12</entry>
</row>
<row>
<entry>GPIO25</entry>
<entry>P1-22</entry>
<entry></entry>
<entry>D4</entry>
<entry>11</entry>
</row>
<row>
<entry>GPIO08</entry>
<entry>P1-24</entry>
<entry></entry>
<entry>EN</entry>
<entry>6</entry>
</row>
<row>
<entry>GPIO07</entry>
<entry>P1-26</entry>
<entry></entry>
<entry>RS</entry>
<entry>4</entry>
</row>
<row>
<entry>GND</entry>
<entry>P1-06</entry>
<entry></entry>
<entry>RW</entry>
<entry>5</entry>
</row>
<row>
<entry>GPIO17</entry>
<entry>P1-11</entry>
<entry></entry>
<entry>BL</entry>
<entry>Backlight (optional)</entry>
</row>
</tbody>
</tgroup>
</table>
<para>GPIO07 and GPIO08 used for RS and EN signal are also used by the SPI
bus. If you loaded the SPI driver you will need to assign them to a different
GPIO, e.g. GPIO04 and GPIO22.</para>
<sect4 id="hd44780-raspberrypi-config">
<title>Special Raspberry Pi configuration options</title>
<para>This connection driver can be configured to use other pins than the
one described in <link linkend="hd44780-raspberrypi.pin-mapping">the table
above</link>. Using the <literal> pin_<replaceable>&lt;name&gt;
</replaceable></literal> configuration option, any LCD pin can be assigned
to any GPIO pin.</para>
<important>
<para>The values for the <literal>pin_<replaceable>&lt;name&gt;
</replaceable></literal> configuration option are the number part from the
GPIO signal name, not the pin number from the header connector! To find
out which signal is routed to which connector pin refer to the <ulink url=
"http://elinux.org/RPi_Low-level_peripherals">RPi Low-level peripherals</ulink>
description.</para>
</important>
<para>The connection driver contains a check for possible signal names. You
will receive an error message if you try to assign a pin to a signal that is
not available on connector P1 or P5.</para>
<example id="hd44780-raspberrypi-config.example">
<title>HD44780: Alternate configuration for Raspberry Pi GPIO pins</title>
<screen>
<![CDATA[
[hd44780]
ConnectionType=raspberrypi
Backlight=yes
Size=16x2
pin_D4=25
pin_D5=24
pin_D6=23
pin_D7=18
pin_EN=8
pin_RS=7
pin_BL=17
]]>
</screen>
</example>
</sect4>
</sect3>
</sect2>
@@ -3008,6 +3169,7 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<term>
<property>ConnectionType</property> =
{
<!-- 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> |
@@ -3018,14 +3180,18 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<parameter><literal>vdr-lcd</literal></parameter> |
<parameter><literal>vdr-wakeup</literal></parameter> |
<parameter><literal>pertelian</literal></parameter> |
<parameter><literal>bwctusb</literal></parameter> |
<parameter><literal>lcd2usb</literal></parameter> |
<parameter><literal>usb4all</literal></parameter> |
<parameter><literal>lis2</literal></parameter> |
<parameter><literal>mplay</literal></parameter> |
<parameter><literal>i2c</literal></parameter> |
<parameter><literal>usblcd</literal></parameter> |
<parameter><literal>bwctusb</literal></parameter> |
<parameter><literal>lcd2usb</literal></parameter> |
<parameter><literal>usbtiny</literal></parameter> |
<parameter><literal>uss720</literal></parameter> |
<parameter><literal>usb4all</literal></parameter> |
<parameter><literal>ftdi</literal></parameter> |
<parameter><literal>usblcd</literal></parameter>
<parameter><literal>i2c</literal></parameter> |
<parameter><literal>ethlcd</literal></parameter> |
<parameter><literal>raspberrypi</literal></parameter>
}
</term>
<listitem>
@@ -3079,11 +3245,23 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<entry><literal><link linkend="hd44780-vdr-wakeup">vdr-wakeup</link></literal></entry>
<entry>VDR-Wakeup module "vdr-wakeup"</entry>
</row>
<!-- USB -->
<row>
<entry><literal><link linkend="hd44780-pertelian">pertelian</link></literal></entry>
<entry>Pertelian X2040 LCD display (<ulink url="http://pertelian.com/joomla/index.php?option=com_content&amp;task=view&amp;id=43&amp;Itemid=48"></ulink>)</entry>
</row>
<!-- USB -->
<row>
<entry><literal><link linkend="hd44780-lis2">lis2</link></literal></entry>
<entry>LIS2 from VLSystem (<ulink url="http://www.vlsys.co.kr"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-mplay">mplay</link></literal></entry>
<entry>MPlay Blast from VLSystem (<ulink url="http://www.vlsys.co.kr"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-usblcd">usblcd</link></literal></entry>
<entry>USBLCD adapter from Adams IT Services (<ulink url="http://www.usblcd.de/"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-bwctusb">bwctusb</link></literal></entry>
<entry>BWCT USB device "bwctusb" (<ulink url="http://www.bwct.de/lcd.html"></ulink>)</entry>
@@ -3092,35 +3270,37 @@ This can be done by specifying <option>--enable-drivers=all</option> or by inclu
<entry><literal><link linkend="hd44780-lcd2usb">lcd2usb</link></literal></entry>
<entry>Till Harbaum's LCD2USB (<ulink url="http://www.harbaum.org/till/lcd2usb/"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-usb4all">USB-4-all</link></literal></entry>
<entry>The USB-4-all controller board from Sprut (<ulink url="http://www.sprut.de/electronic/pic/projekte/usb4all/usb4all.htm"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-usbtiny">usbtiny</link></literal></entry>
<entry>Dick Streefland's USBtiny (<ulink url="http://www.xs4all.nl/~dicks/avr/usbtiny/"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-lis2">lis2</link></literal></entry>
<entry>LIS2 from VLSystem (<ulink url="http://www.vlsys.co.kr"></ulink>)</entry>
<entry><literal><link linkend="hd44780-uss720">uss720</link></literal></entry>
<entry>Belkin USS-720 USB-to-IEEE 1284 Bridge</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-mplay">mplay</link></literal></entry>
<entry>MPlay Blast from VLSystem (<ulink url="http://www.vlsys.co.kr"></ulink>)</entry>
<entry><literal><link linkend="hd44780-usb4all">USB-4-all</link></literal></entry>
<entry>The USB-4-all controller board from Sprut (<ulink url="http://www.sprut.de/electronic/pic/projekte/usb4all/usb4all.htm"></ulink>)</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-ftdi">ftdi</link></literal></entry>
<entry>Display connected to a dual channel FTDI 2232D USB chip</entry>
</row>
<row>
<entry><literal><link linkend="hd44780-usblcd">usblcd</link></literal></entry>
<entry>USBLCD adapter from Adams IT Services (<ulink url="http://www.usblcd.de/"></ulink>)</entry>
</row>
<!-- I2C -->
<row>
<entry><literal><link linkend="hd44780-i2c">i2c</link></literal></entry>
<entry>LCD driven by PCF8574(A)/PCA9554(A) connected via I<superscript>2</superscript>C</entry>
</row>
<!-- Ethernet -->
<row>
<entry><literal><link linkend="hd44780-ethlcd">ethlcd</link></literal></entry>
<entry>ethlcd device (<ulink url="http://manio.skyboo.net/ethlcd/"></ulink>)</entry>
</row>
<!-- Other -->
<row>
<entry><literal><link linkend="hd44780-raspberrypi">raspberrypi</link></literal></entry>
<entry>LCD connected to the GPIO header of a Raspberry Pi</entry>
</row>
</tbody>
</tgroup>
</informaltable>
+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 = 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
+7 -1
View File
@@ -35,7 +35,10 @@
#ifdef WITH_ETHLCD
# include "hd44780-ethlcd.h"
#endif
# include "hd44780-usblcd.h"
#include "hd44780-usblcd.h"
#ifdef WITH_RASPBERRYPI
# include "hd44780-rpi.h"
#endif
/* add new connection type header files to the correct section above or here */
@@ -81,6 +84,9 @@ static const ConnectionMapping connectionMapping[] = {
/* TCP socket connection types */
#ifdef WITH_ETHLCD
{ "ethlcd", HD44780_CT_ETHLCD, IF_TYPE_TCP, hd_init_ethlcd },
#endif
#ifdef WITH_RASPBERRYPI
{ "raspberrypi", HD44780_CT_RASPBERRYPI, IF_TYPE_PARPORT, hd_init_rpi },
#endif
/* add new connection types in the correct section above or here */
+5 -1
View File
@@ -53,6 +53,7 @@
#define HD44780_CT_USBLCD 19
#define HD44780_CT_USBTINY 20
#define HD44780_CT_USB4ALL 21
#define HD44780_CT_RASPBERRYPI 22
/**@}*/
/** \name Symbolic names for interface types
@@ -104,7 +105,7 @@ typedef struct ConnectionMapping {
int if_type;
/** Pointer to connection type's initialization function */
int (*init_fn) (Driver *drvthis);
} ConnectionMapping;
} ConnectionMapping;
/**
@@ -153,6 +154,9 @@ typedef struct hd44780_private_data {
#ifdef WITH_ETHLCD
int sock; /**< socket for TCP devices */
#endif
#ifdef WITH_RASPBERRYPI
struct rpi_gpio_map *rpi_gpio; /**< GPIO pin mapping for Raspberry Pi */
#endif
int charmap; /**< index of currently used charmap */
+458
View File
@@ -0,0 +1,458 @@
/** \file server/drivers/hd44780-rpi.c
* \c rpi connection type of \c hd44780 driver for Hitachi HD44780 based LCD
* displays connected to the GPIO pins on the Raspberry Pi.
*
* The LCD is operated in its 4 bit-mode. R/W (5) on the LCD MUST be hard wired
* low to prevent 5V logic appearing on the GPIO pins.
*
* 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)
* GND R/W (5)
* P1-26 (7) RS (4)
* P1-11 (17) BL (backlight optional)
*
* Mappings can be set in the config file using the key-words:
* pin_EN, pin_RS, pin_D7, pin_D6, pin_D5, pin_D4, pin_BL
* in the [HD44780] section.
*
* Only a single LCD is currently supported.
*/
/*-
* Copyright (c) 2012-2013 Paul Corner <paul_c@users.sourceforge.net>
* 2013 warhog <warhog@gmx.de> (Conditional ARM test)
* 2013 Serac <Raspberry Pi forum>
* (Backlight & Rev2 board support)
*
* The code to access the GPIO on a Raspberry Pi draws on an example program
* by Dom and Gert van Loo from:
* http://elinux.org/Rpi_Low-level_peripherals#GPIO_Driving_Example_.28C.29
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
/* Default GPIO pin assignment */
#define RPI_DEF_D7 18
#define RPI_DEF_D6 23
#define RPI_DEF_D5 24
#define RPI_DEF_D4 25
#define RPI_DEF_RS 7
#define RPI_DEF_EN 8
#define RPI_DEF_BL 17
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include "hd44780-rpi.h"
#include "hd44780-low.h"
#include "report.h"
void lcdrpi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
void lcdrpi_HD44780_backlight(PrivateData *p, unsigned char state);
void lcdrpi_HD44780_close(PrivateData *p);
/**
* Pointer to the memory mapped GPIO registers. Note the pointer type is
* (unsigned int) not (char). This is important when calculating offset
* adresses!
*
* This pointer is outside PrivataData as it needs to be volatile!
*/
static volatile unsigned int *gpio_map = NULL;
/*
* Two different board revisions are currently in widespread use. The
* GPIO mappings differ slightly - Not enough to kill a system yet.
* Future models *may* have extra pins added or reassigned to other
* functions. Having a revision dependent mapping gives the user fair
* warning if they mess up.
*/
static const int gpio_pins_R1[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,
24, 25, -1, -1, -1, -1, -1, -1
};
static const int gpio_pins_R2[GPIO_PINS] = {
-1, -1, -1, 3, 4, -1, -1, 7,
8, 9, 10, 11, -1, -1, 14, 15,
-1, 17, 18, -1, -1, -1, 22, 23,
/* 28-31 accessible via P5 */
24, 25, -1, 27, 28, 29, 30, 31
};
/**
* Maps a memory region to the address space of the BM2835 GPIO controller.
* \param drvthis Pointer to driver structure.
* \return 0 on success, -1 on error.
*/
static int
setup_io(Driver *drvthis)
{
int mem_fd = 0;
if (gpio_map != NULL) {
report(RPT_ERR, "setup_io: IO already in use");
return -1;
}
if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
report(RPT_ERR, "setup_io: can not open /dev/mem");
return -1;
}
gpio_map = (unsigned int *) mmap(NULL,
GPIO_BLOCK_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
mem_fd,
GPIO_BASE);
if ((long) gpio_map < 0) {
report(RPT_ERR, "setup_io: mmap error %s", strerror(errno));
close(mem_fd);
return -1;
}
close(mem_fd);
debug(RPT_INFO, "setup_io: finished");
return 0;
}
/**
* Check if LCDd runs on a Raspberry Pi board and which revision (Rev 1 or
* Rev 2) it is.
* \param drvthis Pointer to driver structure.
* \return Pointer to a GPIO mapping table or NULL on error.
*/
static int const *
check_board_rev(Driver *drvthis)
{
FILE *fp;
char buf[80];
char hw[8];
unsigned int rev = 0;
if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) {
report(RPT_ERR, "check_board_rev: Can not open /proc/cpuinfo");
return NULL;
}
while (!feof(fp)) {
fgets(buf, sizeof(buf), fp);
sscanf(buf, "Hardware : %7s", hw);
sscanf(buf, "Revision : %x", &rev);
}
fclose(fp);
/* On boards that have been overvolted, the MSB will be set */
rev &= 0x00ff;
if (strcmp(hw, "BCM2708") != 0 || rev == 0) {
report(RPT_ERR, "check_board_rev: This board is not recognized as a Raspberry Pi!");
return NULL;
}
/* Rev 1 boards will be 0x002 or 0x003 (not sure if 0x001 ever existed
* in the wild). */
if (rev < 4) {
report(RPT_INFO, "check_board_rev: Revision 1 board detected");
return gpio_pins_R1;
}
/* Currently, Rev 2 boards are 0x004, 0x005, or 0x006. This will need
* updating as new revisions are released, but it is unlikely that P1
* will change. */
if (rev > 3) {
report(RPT_INFO, "check_board_rev: Revision 2 board detected");
return gpio_pins_R2;
}
return NULL;
}
/**
* Check user provided GPIO pin configuration.
* \param drvthis Pointer to driver structure.
* \param pin Number of the GPIO pin to use.
* \param allowed_pins Pointer to array of allowed GPIO pins (depends on
* board revision).
* \param used_pins Pointer to array of pin usage status.
* \return 0 on success, -1 on error.
*/
static int
check_pin(Driver *drvthis, int pin, const int *allowed_pins, int *used_pins)
{
/* Check for errors */
if (pin >= GPIO_PINS || pin < 0) {
report(RPT_ERR, "check_pin: GPIO pin %i out of range", pin);
return -1;
}
if (allowed_pins[pin] < 0) {
report(RPT_ERR, "check_pin: Use of GPIO pin %i not allowed", pin, allowed_pins[pin]);
return -1;
}
if (used_pins[pin] == 1) {
report(RPT_ERR, "check_pin: GPIO pin %i already used", pin);
return -1;
}
/* Mark used */
used_pins[pin] = 1;
return 0;
}
/**
* Configures a GPIO pin: Disable pull-up/down and set it up as output.
* \param drvthis Pointer to driver structure.
* \param gpio Number of the GPIO pin to use.
*/
static void
setup_gpio(Driver *drvthis, int gpio)
{
volatile int i;
#define GPPUP gpio_map + 37
#define GPPUDCLK gpio_map + 38
/* Disable pull-up/down */
*(GPPUP) &= ~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 optimize loop out.
*/
i = 30;
while (--i);
/* Enable Pull-up/down clock register for the pin */
*(GPPUDCLK + (gpio / 32)) = 1 << (gpio % 32);
/* Another 150 cycle wait required after a write to GPPUDCLK */
i = 30;
while (--i);
/* Write again to GPPUD and disable clock */
*(GPPUP) &= ~3;
*(GPPUDCLK + (gpio / 32)) = 0;
/*
* Now configure the pin as output: This reads the complete GPSELx
* register, clears all bits for the selected pin, enables it as
* output, and writes back the register.
*/
*(gpio_map + (gpio / 10)) =
(*(gpio_map + (gpio / 10)) & ~(7 << ((gpio % 10) * 3))) | (1 << ((gpio % 10) * 3));
}
/**
* Free resources used by this connection type.
* \param p Pointer to driver's PrivateData structure.
*/
void
lcdrpi_HD44780_close(PrivateData *p)
{
/* Configure all pins as input */
INP_GPIO(p->rpi_gpio->en);
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);
if (p->have_backlight)
INP_GPIO(p->backlight_bit);
/* Unmap and free memory */
if (gpio_map != NULL)
munmap((caddr_t) gpio_map, GPIO_BLOCK_SIZE);
if (p->rpi_gpio != NULL)
free(p->rpi_gpio);
p->rpi_gpio = NULL;
}
/**
* 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;
const int *allowed_gpio_pins = NULL;
int used_pins[GPIO_PINS] = {};
if ((allowed_gpio_pins = check_board_rev(drvthis)) == NULL)
return -1;
/* Get GPIO configuration */
p->rpi_gpio = malloc(sizeof(struct rpi_gpio_map));
if (p->rpi_gpio == NULL) {
report(RPT_ERR, "hd_init_rpi: unable to allocate memory");
return -1;
}
p->rpi_gpio->en = drvthis->config_get_int(drvthis->name, "pin_EN", 0, RPI_DEF_EN);
p->rpi_gpio->rs = drvthis->config_get_int(drvthis->name, "pin_RS", 0, RPI_DEF_RS);
p->rpi_gpio->d7 = drvthis->config_get_int(drvthis->name, "pin_D7", 0, RPI_DEF_D7);
p->rpi_gpio->d6 = drvthis->config_get_int(drvthis->name, "pin_D6", 0, RPI_DEF_D6);
p->rpi_gpio->d5 = drvthis->config_get_int(drvthis->name, "pin_D5", 0, RPI_DEF_D5);
p->rpi_gpio->d4 = drvthis->config_get_int(drvthis->name, "pin_D4", 0, RPI_DEF_D4);
debug(RPT_INFO, "hd_init_rpi: Pin EN mapped to GPIO%d", p->rpi_gpio->en);
debug(RPT_INFO, "hd_init_rpi: Pin RS mapped to GPIO%d", p->rpi_gpio->rs);
debug(RPT_INFO, "hd_init_rpi: Pin D4 mapped to GPIO%d", p->rpi_gpio->d4);
debug(RPT_INFO, "hd_init_rpi: Pin D5 mapped to GPIO%d", p->rpi_gpio->d5);
debug(RPT_INFO, "hd_init_rpi: Pin D6 mapped to GPIO%d", p->rpi_gpio->d6);
debug(RPT_INFO, "hd_init_rpi: Pin D7 mapped to GPIO%d", p->rpi_gpio->d7);
if (check_pin(drvthis, p->rpi_gpio->en, allowed_gpio_pins, used_pins) ||
check_pin(drvthis, p->rpi_gpio->rs, allowed_gpio_pins, used_pins) ||
check_pin(drvthis, p->rpi_gpio->d7, allowed_gpio_pins, used_pins) ||
check_pin(drvthis, p->rpi_gpio->d6, allowed_gpio_pins, used_pins) ||
check_pin(drvthis, p->rpi_gpio->d5, allowed_gpio_pins, used_pins) ||
check_pin(drvthis, p->rpi_gpio->d4, allowed_gpio_pins, used_pins)) {
free(p->rpi_gpio);
return -1;
}
if (p->have_backlight) { /* Backlight setup is optional */
p->backlight_bit = drvthis->config_get_int(drvthis->name, "pin_BL", 0, RPI_DEF_BL);
debug(RPT_INFO, "hd_init_rpi: Backlight mapped to GPIO%d", p->backlight_bit);
if (check_pin(drvthis, p->backlight_bit, allowed_gpio_pins, used_pins) != 0) {
report(RPT_WARNING, "hd_init_rpi: Invalid backlight configuration - disabling backlight");
p->have_backlight = 0;
}
}
/* Now that configuration should be correct, set up the GPIO pins */
if (setup_io(drvthis) < 0) {
report(RPT_ERR, "hd_init_rpi: Failed to set up GPIO");
free(p->rpi_gpio);
return -1;
}
setup_gpio(drvthis, p->rpi_gpio->en);
setup_gpio(drvthis, p->rpi_gpio->rs);
setup_gpio(drvthis, p->rpi_gpio->d7);
setup_gpio(drvthis, p->rpi_gpio->d6);
setup_gpio(drvthis, p->rpi_gpio->d5);
setup_gpio(drvthis, p->rpi_gpio->d4);
p->hd44780_functions->senddata = lcdrpi_HD44780_senddata;
p->hd44780_functions->close = lcdrpi_HD44780_close;
if (p->have_backlight) {
setup_gpio(drvthis, p->backlight_bit);
p->hd44780_functions->backlight = lcdrpi_HD44780_backlight;
}
/* Setup the lcd in 4 bit mode: Send (FUNCSET | IF_8BIT) three times
* followed by (FUNCSET | IF_4BIT) using four nibbles. Timing is not
* exactly what is required by HD44780. */
p->hd44780_functions->senddata(p, 0, RS_INSTR, 0x33);
p->hd44780_functions->uPause(p, 4100);
p->hd44780_functions->senddata(p, 0, RS_INSTR, 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)
{
/* Only one display is (currently) supported */
if (displayID > 1) {
return;
}
/* Safeguard: This should never happen */
if (gpio_map == NULL) {
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->en, 1);
p->hd44780_functions->uPause(p, 50);
SET_GPIO(p->rpi_gpio->en, 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->en, 1);
p->hd44780_functions->uPause(p, 50);
SET_GPIO(p->rpi_gpio->en, 0);
p->hd44780_functions->uPause(p, 50);
}
/**
* 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)
{
if (p->backlight_bit > -1 && p->backlight_bit < 32)
SET_GPIO(p->backlight_bit, (state == BACKLIGHT_ON) ? 1 : 0);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef HD_LCDRPI_H
#define HD_LCDRPI_H
#include "lcd.h" /* for Driver */
/* initialize this particular driver */
int hd_init_rpi(Driver *drvthis);
/**
* rpi_gpio_map is addressed through the hd44780_private_data struct. Data
* stored here is used for mapping physical GPIO pins to BCM2835 gpio. */
struct rpi_gpio_map {
int en;
int rs;
int d7;
int d6;
int d5;
int d4;
};
/** Peripheral base address of the BCM2835 */
#define BCM2835_PERI_BASE 0x20000000
/** GPIO register start address */
#define GPIO_BASE BCM2835_PERI_BASE + 0x200000
/** Length of register space */
#define GPIO_BLOCK_SIZE 180
/** The Pi has 32 GPIO pins */
#define GPIO_PINS 32
/** Setup a GPIO pin as input */
#define INP_GPIO(g) *(gpio_map+((g)/10)) &= ~(7<<(((g)%10)*3))
/** Sets or clears a GPIO pin */
#define SET_GPIO(g,a) *(gpio_map+((a)?7:10))=1<<((g)%32);
#endif // HD_LCDRPI_H