diff --git a/ChangeLog b/ChangeLog index 5f7cee2..c682aa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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! diff --git a/acinclude.m4 b/acinclude.m4 index 6a66dcb..3cc9b6c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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"] ;; diff --git a/docs/lcdproc-user/drivers/hd44780.docbook b/docs/lcdproc-user/drivers/hd44780.docbook index ff3bf8a..21b7535 100644 --- a/docs/lcdproc-user/drivers/hd44780.docbook +++ b/docs/lcdproc-user/drivers/hd44780.docbook @@ -155,6 +155,12 @@ Last but not least, for special purposes, there are even more connection types: ethlcd: Display connected via TCP to PoE powered ethlcd device () + + + raspberrypi: + LCD connected to the GPIO header of a Raspberry Pi + + @@ -2953,6 +2959,161 @@ software adjustable contrast and brightness (backlight). + +Raspberry Pi + +This connection type supports a single LCD connected to the GPIO header P1 +on a Raspberry Pi. + +It supports a switchable backlight connected to pin P1-11 by default. Use +the switch circuit as described in . + + + 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 must + be wired to GND to prevent 5V logic appearing on the GPIO + pins. For the same reason the backlight cicuit from must not be + used. + 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. + + + +HD44780: Default pin mapping for Raspberry Pi + + + + + + + + + Connector + <-> + LCD + + + Pin Name + Pin Number + Name + Pin + + + + + GPIO18 + P1-12 + + D7 + 14 + + + GPIO23 + P1-16 + + D6 + 13 + + + GPIO24 + P1-18 + + D5 + 12 + + + GPIO25 + P1-22 + + D4 + 11 + + + GPIO08 + P1-24 + + EN + 6 + + + GPIO07 + P1-26 + + RS + 4 + + + GND + P1-06 + + RW + 5 + + + GPIO17 + P1-11 + + BL + Backlight (optional) + + + +
+ +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. + + +Special Raspberry Pi configuration options + +This connection driver can be configured to use other pins than the +one described in the table +above. Using the pin_<name> + configuration option, any LCD pin can be assigned +to any GPIO pin. + + + The values for the pin_<name> + 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 RPi Low-level peripherals + description. + + +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. + + +HD44780: Alternate configuration for Raspberry Pi GPIO pins + + + + + + + +
+ + @@ -3008,6 +3169,7 @@ This can be done by specifying or by inclu ConnectionType = { + 4bit | 8bit | winamp | @@ -3018,14 +3180,18 @@ This can be done by specifying or by inclu vdr-lcd | vdr-wakeup | pertelian | - bwctusb | - lcd2usb | - usb4all | lis2 | mplay | - i2c | + usblcd | + bwctusb | + lcd2usb | + usbtiny | + uss720 | + usb4all | ftdi | - usblcd + i2c | + ethlcd | + raspberrypi } @@ -3079,11 +3245,23 @@ This can be done by specifying or by inclu vdr-wakeup VDR-Wakeup module "vdr-wakeup" - pertelian Pertelian X2040 LCD display () + + + lis2 + LIS2 from VLSystem () + + + mplay + MPlay Blast from VLSystem () + + + usblcd + USBLCD adapter from Adams IT Services () + bwctusb BWCT USB device "bwctusb" () @@ -3092,35 +3270,37 @@ This can be done by specifying or by inclu lcd2usb Till Harbaum's LCD2USB () - - USB-4-all - The USB-4-all controller board from Sprut () - usbtiny Dick Streefland's USBtiny () - lis2 - LIS2 from VLSystem () + uss720 + Belkin USS-720 USB-to-IEEE 1284 Bridge - mplay - MPlay Blast from VLSystem () + USB-4-all + The USB-4-all controller board from Sprut () ftdi Display connected to a dual channel FTDI 2232D USB chip - - usblcd - USBLCD adapter from Adams IT Services () - i2c LCD driven by PCF8574(A)/PCA9554(A) connected via I2C + + + ethlcd + ethlcd device () + + + + raspberrypi + LCD connected to the GPIO header of a Raspberry Pi + diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 4022197..6a982cf 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -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 diff --git a/server/drivers/hd44780-drivers.h b/server/drivers/hd44780-drivers.h index 4c58cac..9471dac 100644 --- a/server/drivers/hd44780-drivers.h +++ b/server/drivers/hd44780-drivers.h @@ -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 */ diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h index 448a1a5..7c6bb22 100644 --- a/server/drivers/hd44780-low.h +++ b/server/drivers/hd44780-low.h @@ -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 */ diff --git a/server/drivers/hd44780-rpi.c b/server/drivers/hd44780-rpi.c new file mode 100644 index 0000000..9470a1e --- /dev/null +++ b/server/drivers/hd44780-rpi.c @@ -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 + * 2013 warhog (Conditional ARM test) + * 2013 Serac + * (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 +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/server/drivers/hd44780-rpi.h b/server/drivers/hd44780-rpi.h new file mode 100644 index 0000000..99847eb --- /dev/null +++ b/server/drivers/hd44780-rpi.h @@ -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