/////////////////////////////////////////////////////////////////////////////////////////////
/*
* Driver module for Hitachi HD44780 based LCD displays.
* The LCD is operated in it's 8 bit-mode to be connected to the ts7200 LCD Port
*
* Copyright (c) 1999, 1995 Benjamin Tse <>
* 2001 Joris Robijn <>
*
* Created modular driver Dec 1999, Benjamin Tse <>
*
* Modified for Technologix Systems TS-72xx ARM CPU series by Kym B Newbery
*
* Based on the code in the lcdtime package which uses the LCD
* controller in its 8-bit mode.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-ts7200.h"
#include "hd44780-low.h"
#include "report.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#define GPIOBASE 0x80840000
#define PADR 0
#define PADDR (0x10 / sizeof(unsigned int))
#define PAMASK 0x7F
#define PHDR (0x40 / sizeof(unsigned int))
#define PHDDR (0x44 / sizeof(unsigned int))
#define LCD_EN 0x08
#define LCD_RS 0x10
#define LCD_WR 0x20
volatile unsigned int *gpio;
volatile unsigned int *phdr;
volatile unsigned int *phddr;
volatile unsigned int *padr;
volatile unsigned int *paddr;
#define DEFAULT_KEYPAD_DEVICE "/dev/ttyTS2"
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically (but not
// restricted to):
// HD44780_senddata
// HD44780_readkeypad
void ts7200_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
void ts7200_HD44780_backlight (PrivateData *p, unsigned char state);
unsigned char ts7200_HD44780_scankeypad (PrivateData *p);
// initialise the driver
int hd_init_ts7200 (Driver *drvthis)
{
int memfd;
PrivateData *p = (PrivateData*) drvthis->private_data;
struct termios portset;
char keypad_device[256] = DEFAULT_KEYPAD_DEVICE;
HD44780_functions *hd44780_functions = p->hd44780_functions;
// Read config file
/****************************************************************/
strncpy(keypad_device,
drvthis->config_get_string(drvthis->name, "Keypad_Device", 0, DEFAULT_KEYPAD_DEVICE),
sizeof(keypad_device));
keypad_device[sizeof(keypad_device)-1] = '\0';
report(RPT_INFO, "HD44780: TS7200 KEYPAD : using device %s", keypad_device);
// setup port and open it
p->fd = open(keypad_device, O_RDWR | O_NOCTTY);
if (p->fd == -1)
{
report(RPT_ERR, "HD44780 : TS7200 : Could not open device %s (%s)",
keypad_device, strerror(errno));
return -1;
}
tcgetattr(p->fd, &portset);
portset.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
portset.c_iflag &= ~OPOST;
portset.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN );
portset.c_cflag &= ~(CSIZE | PARENB | CRTSCTS);
portset.c_cflag |= (CS8 | CREAD | CLOCAL);
portset.c_cc[VMIN] = 1;
portset.c_cc[VTIME] = 3;
// input port speed 9600
cfsetispeed(&portset, B9600);
// Force settings now
tcsetattr(p->fd, TCSANOW, &portset);
/**************************************************************/
report(RPT_INFO, "HD44780: TS7200 LCD : initialising lcd port");
// Get I/O Access
memfd = open("/dev/mem", O_RDWR | O_SYNC);
gpio = (unsigned int *)mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, memfd, GPIOBASE);
phdr = &gpio[PHDR];
phddr = &gpio[PHDDR];
padr = &gpio[PADR];
paddr = &gpio[PADDR];
// Port H - Bit 3 = LCD_EN, output
// Bit 4 = LCD_RS, output
// Bit 5 = LCD_WR, output
*phddr |= (LCD_EN | LCD_RS | LCD_WR);
// de-assert EN, deassert RS
*phdr &= ~(LCD_EN | LCD_RS);
// Set port A (databus) to inputs
*paddr = 0x00;
report(RPT_INFO, "HD44780: TS7200 LCD : Done Initialising..");
hd44780_functions->senddata = ts7200_HD44780_senddata;
hd44780_functions->backlight = ts7200_HD44780_backlight;
hd44780_functions->scankeypad = ts7200_HD44780_scankeypad;
// setup the lcd in 8 bit mode
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (p, 4100);
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (p, 100);
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT | TWOLINE | SMALLCHAR);
hd44780_functions->uPause (p, 40);
common_init (p, IF_8BIT);
if (p->have_keypad) {
// Remember which input lines are stuck
p->stuckinputs = ts7200_HD44780_scankeypad (p);
}
return 0;
}
// ts7200_HD44780_senddata
void ts7200_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
{
//
// NOTE : May want to optimise the timing in this section
//
// set LCD_RS
if (flags == RS_INSTR)
*phdr &= ~(LCD_RS); // RS = low for control registers
else if (flags == RS_DATA)
*phdr |= LCD_RS; // RS = high for data ram
// set LCD_RW low for write cycle
*phdr &= ~(LCD_WR);
// Set port A all outputs to write data
*paddr = 0xFF;
// Put value to write on port A
*padr = ch;
// pause for min 100ns
p->hd44780_functions->uPause(p, 1);
// Set LCD_EN
*phdr |= LCD_EN;
// Pause for min 500ns
p->hd44780_functions->uPause(p, 1);
// clear LCD_EN. Data latched on falling edge
*phdr &= ~(LCD_EN);
// pause for minimum
// p->hd44780_functions->uPause(p, 1);
}
void ts7200_HD44780_backlight (PrivateData *p, unsigned char state)
{
/* No Backlight Control - Yet */
}
unsigned char ts7200_HD44780_scankeypad (PrivateData *p)
{
char in = 0;
unsigned char keycode = 0;
struct pollfd fds[1];
fds[0].fd = p->fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
poll(fds,1,0);
if (fds[0].revents == 0)
return (unsigned char)NULL;
read(p->fd, &in, 1);
if (in == '\0')
return (unsigned char)NULL;
else
{
switch(in)
{
// Mapping for RT Nollett serial 4 x 4 keypad
// row 1
case '1' : keycode = 0x11; break;
case '2' : keycode = 0x12; break;
case '3' : keycode = 0x13; break;
case 'A' : keycode = 0x14; break;
// row 2
case '4' : keycode = 0x21; break;
case '5' : keycode = 0x22; break;
case '6' : keycode = 0x23; break;
case 'B' : keycode = 0x24; break;
// row 3
case '7' : keycode = 0x31; break;
case '8' : keycode = 0x32; break;
case '9' : keycode = 0x33; break;
case 'C' : keycode = 0x34; break;
// row 4
case 0x08 : keycode = 0x41; break;
case '0' : keycode = 0x42; break;
case 0x0D : keycode = 0x43; break;
case 'D' : keycode = 0x44; break;
default : keycode = 0; break;
}
return keycode;
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/*
* Driver module for Hitachi HD44780 based LCD displays.
* The LCD is operated in it's 8 bit-mode to be connected to the ts7200 LCD Port
*
* Copyright (c) 1999, 1995 Benjamin Tse <>
* 2001 Joris Robijn <>
*
* Created modular driver Dec 1999, Benjamin Tse <>
*
* Modified for Technologix Systems TS-72xx ARM CPU series by Kym B Newbery
*
* Based on the code in the lcdtime package which uses the LCD
* controller in its 8-bit mode.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*/
#include "hd44780-ts7200.h"
#include "hd44780-low.h"
#include "report.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#define GPIOBASE 0x80840000
#define PADR 0
#define PADDR (0x10 / sizeof(unsigned int))
#define PAMASK 0x7F
#define PHDR (0x40 / sizeof(unsigned int))
#define PHDDR (0x44 / sizeof(unsigned int))
//Port C
#define PCDR (0x08 / sizeof(unsigned int))
#define PCDDR (0x18 / sizeof(unsigned int))
#define PCMASK 0x01
#define LCD_EN 0x08
#define LCD_RS 0x10
#define LCD_WR 0x20
//GPIO KEYPAD
// Use 0 for busy-wait
#define POLL_FREQ 30
// Use 0 for busy-wait
#define DEBOUNCE_POLL_FREQ 256
#define DEBOUNCE_STABLE_MS 10
#define REPEAT_FREQ 30
#define REPEAT_DELAY_MS 500
// struct timeval utility macros
#define TV_ADD_US(x, y) { \
(x).tv_usec += (y); \
(x).tv_sec += (x).tv_usec / 1000000; \
(x).tv_usec = (x).tv_usec % 1000000; \
}
#define TV_GTE(x, y) ((x).tv_sec > (y).tv_sec || ((x).tv_sec == (y).tv_sec && \
(x).tv_usec >= (y).tv_usec))
#define TV_ELAPSED_US(x, y) (((x).tv_sec - (y).tv_sec) * 1000000 + \
((x).tv_usec - (y).tv_usec))
volatile unsigned int *dir, *dat;
unsigned int lastkey = -1;
struct timeval repeat_time;
volatile unsigned int *gpio;
volatile unsigned int *phdr;
volatile unsigned int *phddr;
volatile unsigned int *padr;
volatile unsigned int *paddr;
volatile unsigned int *pcdr;
volatile unsigned int *pcddr;
unsigned int changed_key;
#define DEFAULT_KEYPAD_DEVICE "/dev/mem"
// Generally, any function that accesses the LCD control lines needs to be
// implemented separately for each HW design. This is typically (but not
// restricted to):
// HD44780_senddata
// HD44780_readkeypad
void ts7200_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
void ts7200_HD44780_backlight (PrivateData *p, unsigned char state);
unsigned char ts7200_HD44780_scankeypad (PrivateData *p);
// GPIO keypad routines
unsigned int get_keys(void);
unsigned int debounce(unsigned int);
void keypad_event(unsigned int, unsigned int);
// initialise the driver
int hd_init_ts7200 (Driver *drvthis)
{
int memfd;
PrivateData *p = (PrivateData*) drvthis->private_data;
struct termios portset;
char keypad_device[256] = DEFAULT_KEYPAD_DEVICE;
HD44780_functions *hd44780_functions = p->hd44780_functions;
// Read config file
/****************************************************************/
strncpy(keypad_device,
drvthis->config_get_string(drvthis->name, "Keypad_Device", 0, DEFAULT_KEYPAD_DEVICE),
sizeof(keypad_device));
keypad_device[sizeof(keypad_device)-1] = '\0';
report(RPT_INFO, "HD44780: TS7200 KEYPAD : using device %s", keypad_device);
// setup port and open it
p->fd = open(keypad_device, O_RDWR | O_SYNC);
if (p->fd == -1)
{
report(RPT_ERR, "HD44780 : TS7200 : Could not open device %s (%s)",
keypad_device, strerror(errno));
return -1;
}
unsigned char *start;
start = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0x80840000);
dat = (unsigned int *)(start + 0x4);
dir = (unsigned int *)(start + 0x14);
*dir = 0xf;
/**************************************************************/
report(RPT_INFO, "HD44780: TS7200 LCD : initialising lcd port");
// Get I/O Access
memfd = open("/dev/mem", O_RDWR | O_SYNC);
gpio = (unsigned int *)mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, memfd, GPIOBASE);
phdr = &gpio[PHDR];
padr = &gpio[PADR];
paddr = &gpio[PADDR];
pcdr = &gpio[PCDR]; //C Portu için yapýlan..
pcddr = &gpio[PCDDR];
phddr = &gpio[PHDDR];
// Port H - Bit 3 = LCD_EN, output
// Bit 4 = LCD_RS, output
// Bit 5 = LCD_WR, output
//*phddr |= (LCD_EN | LCD_RS | LCD_WR);
*phddr |= 0x38; // bits 3:5 of port H to outputs
// de-assert EN, deassert RS
//*phdr &= ~(LCD_EN | LCD_RS);
*phdr &= ~0x18; // de-assert EN, de-assert RS
// Set port A (databus) to inputs
//*paddr = 0x00;
*paddr & ~PAMASK; // port A to inputs
*pcddr & ~PCMASK; // port C to inputs
hd44780_functions->senddata = ts7200_HD44780_senddata;
//hd44780_functions->backlight = ts7200_HD44780_backlight;
hd44780_functions->scankeypad = ts7200_HD44780_scankeypad;
/*
// setup the lcd in 8 bit mode
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (p, 4100);
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT);
hd44780_functions->uPause (p, 100);
hd44780_functions->senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT | TWOLINE | SMALLCHAR);
hd44780_functions->uPause (p, 40);
common_init (p, IF_8BIT);
*/
if (p->have_keypad) {
// Remember which input lines are stuck
p->stuckinputs = ts7200_HD44780_scankeypad (p);
}
return 0;
}
// ts7200_HD44780_senddata
void ts7200_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
{
//
// NOTE : May want to optimise the timing in this section
//
// set LCD_RS
if (flags == RS_INSTR)
*phdr &= ~(LCD_RS); // RS = low for control registers
else if (flags == RS_DATA)
*phdr |= LCD_RS; // RS = high for data ram
// set LCD_RW low for write cycle
*phdr &= ~(LCD_WR);
// Set port A all outputs to write data
//*paddr = 0xFF;
// Put value to write on port A and C
//*padr = ch;
*paddr = *paddr | PAMASK; //set port A to outputs
*pcddr = *pcddr | PCMASK; //set port C to outputs
*padr = *padr & ~PAMASK;
*pcdr = *pcdr & ~PCMASK;
*padr = *padr | (ch & PAMASK);
*pcdr = *pcdr | ((ch >> 7) & PCMASK);
// pause for min 100ns
p->hd44780_functions->uPause(p, 1);
// Set LCD_EN
*phdr |= LCD_EN;
// Pause for min 500ns
p->hd44780_functions->uPause(p, 1);
// clear LCD_EN. Data latched on falling edge
*phdr &= ~(LCD_EN);
// pause for minimum
// p->hd44780_functions->uPause(p, 1);
}
void ts7200_HD44780_backlight (PrivateData *p, unsigned char state)
{
/* No Backlight Control - Yet */
}
unsigned char ts7200_HD44780_scankeypad (PrivateData *p)
{
char in = 0;
unsigned char keycode = 0;
unsigned int k = 0, pressed = 0;
k = get_keys();
changed_key = pressed ^ k;
if (changed_key) {
k = debounce(changed_key);
changed_key &= pressed ^ k;
}
if (changed_key) {
keypad_event(changed_key & k, changed_key & pressed);
pressed &= ~(changed_key & pressed);
pressed |= changed_key & k;
} else {
return 0;
}
in = lastkey;
printf("%c", lastkey);
fflush(stdout);
// report(RPT_INFO, "HD44780: TS7200 KEYPAD : keypress : %c", lastkey);
if (in == '\0')
return (unsigned char)0;
else
{
switch(in)
{
// Mapping for RT Nollett serial 4 x 4 keypad
// row 1
case '1' : keycode = 0x11; break;
case '2' : keycode = 0x12; break;
case '3' : keycode = 0x13; break;
case 'A' : keycode = 0x14; break;
// row 2
case '4' : keycode = 0x21; break;
case '5' : keycode = 0x22; break;
case '6' : keycode = 0x23; break;
case 'B' : keycode = 0x24; break;
// row 3
case '7' : keycode = 0x31; break;
case '8' : keycode = 0x32; break;
case '9' : keycode = 0x33; break;
case 'C' : keycode = 0x34; break;
// row 4
case 0x08 : keycode = 0x41; break;
case '0' : keycode = 0x42; break;
case 0x0D : keycode = 0x43; break;
case 'D' : keycode = 0x44; break;
default : keycode = 0; break;
}
return keycode;
}
return NULL;
}
void keypad_event(unsigned int on, unsigned int off) {
unsigned int i;
unsigned char keys[] = {
'1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
};
lastkey = -1;
for(i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
if (on & (1 << i)) {
printf("%c", keys[i]);
lastkey = keys[i];
}
}
if (REPEAT_DELAY_MS && lastkey != -1) {
gettimeofday(&repeat_time, NULL);
TV_ADD_US(repeat_time, REPEAT_DELAY_MS * 1000);
}
}
unsigned int get_keys(void) {
unsigned int pos, on = 0;
for(pos = 0; pos < 4; pos++) {
*dat = ~(1 << pos);
on |= (~(*dat >> 4) & 0xf) << (4 * pos);
}
return on;
}
// debounce will return when masked keys have been stable for DEBOUNCE_STABLE_MS
unsigned int debounce(unsigned int mask) {
struct timeval verystart, start, now;
unsigned int last_val, val;
last_val = get_keys();
gettimeofday(&verystart, NULL);
memcpy(&start, &verystart, sizeof(struct timeval));
do {
val = get_keys();
gettimeofday(&now, NULL);
if ((val ^ last_val) & mask)
memcpy(&start, &now, sizeof(struct timeval));
last_val = val;
if (DEBOUNCE_POLL_FREQ) usleep(1000000 / DEBOUNCE_POLL_FREQ);
} while (TV_ELAPSED_US(now, start) <= (DEBOUNCE_STABLE_MS * 1000));
return val;
}
//////////////////////////////////////////////////////////////////////////////////
Subject: Re: [ts-7000] Re: ts 7300 LCD drıver problem for HD44780