LCDproc development and user support list

Text archives Help


[Lcdproc] SED1520 interface PCB and driver


Chronological Thread 
  • From: gerhard_pircher AT gmx.net (Gerhard Pircher)
  • Subject: [Lcdproc] SED1520 interface PCB and driver
  • Date: Wed Feb 13 20:40:02 2008

Hi,

Some time ago I built an interface PCB for a SED1520 compatible LCD
(Electronic Assembly DIP122), based on the schematics which were available
on http://www.usblcd.de/lcdproc (the site is defunct).
Two versions of the interface were available on the site. The first and
older one is compatible with the sed1520 driver that comes with lcdproc.
The last one is able to control the backlight and doesn't work with the
current driver.

Since my board is based on the newer version I had to modify the driver
a little bit to get it working. Unfortunately the driver still doesn't
support control of the backlight and the heartbeat icon is not displayed
correctly.

Would it be possible for the lcdproc developers to update the driver?
(I included my version of the driver). I can also supply a bare PCB
board, if that helps and a developer wants to build a test hardware.

best regards,

Gerhard

--
Ist Ihr Browser Vista-kompatibel? Jetzt die neuesten
Browser-Versionen downloaden: http://www.gmx.net/de/go/browser
//////////////////////////////////////////////////////////////////////////
// This is a driver for 122x32 pixel graphic displays based on the      //
// SED1520 Controller connected to the parallel port. Check             //
// http://www.usblcd.de/lcdproc/ for where to buy                       //
// and how to build the hardware. This Controller has no built in       //
// character generator. Therefore all fonts and pixels are generated    //
// by this driver.                                                      //
//                                                                      //
// This driver is based on drv_base.c and hd44780.c.                    //
// The HD44780 font in sed1520fm.c was shamelessly stolen from          //
// Michael Reinelt / lcd4linux and is (C) 2000 by him.                  //
// The rest of fontmap.c and this driver is                             //
//                                                                      //
// Moved the delay timing code by Charles Steinkuehler to timing.h.     //
// Guillaume Filion <gfk AT logidac.com>, December 2001                    //
//                                                                      //
// (C) 2001 Robin Adams ( robin AT adams-online.de )                       //
//                                                                      //
// This driver is released under the GPL. See file COPYING in this      //
// package for further details.                                         //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <sys/errno.h>
#include <time.h>
#include "port.h"
#include "timing.h"
#define uPause timing_uPause

#include "sed1520fm.h"

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif


#ifndef DEFAULT_PORT
# define DEFAULT_PORT	0x378
#endif

#define CELLWIDTH	6
#define CELLHEIGHT	8

#define PIXELWIDTH	122
#define PIXELHEIGHT	32

#define WIDTH		((int) (PIXELWIDTH / CELLWIDTH))	/* 20 */
#define HEIGHT		((int) (PIXELHEIGHT / CELLHEIGHT))	/*  4 */

			// Parport		// My LCD board
//#define A0 0x08	// SELIN		// A0
//#define CS2 0x04	// INIT	(non-inverted)	// CS2
//#define CS1 0x02	// AUTOFD		// Backlight
//#define WR 0x01	// STROBE		// CS1
#define A0 0x08
#define CS2 0x04
#define CS1 0x01
#define WR 0x02
//#define IODELAY 500
#define IODELAY 200

#include "shared/str.h"
#include "lcd.h"
#include "sed1520.h"
#include "report.h"


typedef struct driver_private_data {
    unsigned int port;

    unsigned char *framebuf;
} PrivateData;


// Vars for the server core
MODULE_EXPORT char *api_version = API_VERSION;
MODULE_EXPORT int stay_in_foreground = 0;
MODULE_EXPORT int supports_multiple = 0;
MODULE_EXPORT char *symbol_prefix = "sed1520_";

/////////////////////////////////////////////////////////////////
// writes command value to one or both sed1520 selected by chip
//
void
writecommand (unsigned int port, int value, int chip)
{
    port_out(port, value);
    // A0 is inverted!
    port_out(port + 2, A0 + CS1);
    port_out(port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2));
    port_out(port + 2, A0 + CS1);
    uPause(IODELAY);
    // Dummy write with same data.
/*  port_out(port + 2, A0 + CS1);
    port_out(port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2));
    port_out(port + 2, A0 + CS1);
    uPause(IODELAY);*/
}

/////////////////////////////////////////////////////////////////
// writes data value to one or both sed 1520 selected by chip
//
void
writedata (unsigned int port, int value, int chip)
{
    port_out(port, value);
    port_out(port + 2, CS1);
    port_out(port + 2, CS1 - (chip & CS1) + (chip & CS2));
    port_out(port + 2, CS1);
    uPause(IODELAY);
/*  port_out(port + 2, CS1 - (chip & CS1) + (chip & CS2));
    port_out(port + 2, CS1);
    uPause(IODELAY); */
}

/////////////////////////////////////////////////////////////////
// selects a page (=row) on both sed1520s
//
void
selectpage (unsigned int port, int page)
{
    writecommand(port, 0xB8 + (page & 0x03), CS1 + CS2);
}

/////////////////////////////////////////////////////////////////
// selects a column on the sed1520s specified by chip
//
void
selectcolumn (unsigned int port, int column, int chip)
{
    writecommand(port, (column & 0x7F), chip);
}

/////////////////////////////////////////////////////////////////
// draws  char z from fontmap to the framebuffer at position
// x,y. These are zero-based textmode positions.
// The Fontmap is stored in rows while the framebuffer is stored
// in columns, so we need a little conversion.
//
void
drawchar2fb (unsigned char *framebuf, int x, int y, unsigned char z)
{
    int i, j;

    if ((x < 0) || (x >= WIDTH) || (y < 0) || (y >= HEIGHT))
	return;

    for (i = CELLWIDTH; i > 0; i--) {
	  int k = 0;

	  for (j = 0; j < CELLHEIGHT; j++)
		k |= ((fontmap[(int) z][j] >> (i-1)) & 0x01) << j;

	  framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + (CELLWIDTH - i)] = k;
      }
}

/////////////////////////////////////////////////////////////////
// This initialises the stuff. We support supplying port as
// a command line argument.
//
MODULE_EXPORT int
sed1520_init (Driver *drvthis)
{
    PrivateData *p;

    /* Allocate and store private data */
    p = (PrivateData *) calloc(1, sizeof(PrivateData));
    if (p == NULL)
	return -1;
    if (drvthis->store_private_ptr(drvthis, p))
	return -1;


    /* Read config file */

    /* What port to use */
    p->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT);

    /* End of config file parsing */

    if (timing_init() == -1) {
	report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno));
	return -1;
    }

    // Allocate our framebuffer
    p->framebuf = (unsigned char *) calloc(PIXELWIDTH * HEIGHT, sizeof(unsigned char));
    if (p->framebuf == NULL) {
	report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
	// sed1520_close ();
	return -1;
      }

    // clear screen
    memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);

    // Initialize the Port and the sed1520s
    if (port_access(p->port) || port_access(p->port+2)) {
	report(RPT_ERR, "%s: unable to access port 0x%03X", drvthis->name, p->port);
	return -1;
    }

//    port_out(p->port,0);
//    port_out(p->port + 2, WR + CS2);
    port_out(p->port + 2, CS1);
    // Software reset.
    writecommand(p->port, 0xE2, CS1 + CS2);
    // Display on.
    writecommand(p->port, 0xAF, CS1 + CS2);
    // Display start line 0.
    writecommand(p->port, 0xC0, CS1 + CS2);
    selectpage(p->port, 3);

    report(RPT_DEBUG, "%s: init() done", drvthis->name);

    return 1;
}

/////////////////////////////////////////////////////////////////
// Frees the frambuffer and exits the driver.
//
MODULE_EXPORT void
sed1520_close (Driver *drvthis)
{
    PrivateData *p = drvthis->private_data;

    if (p != NULL) {
	if (p->framebuf != NULL)
	    free(p->framebuf);

	free(p);
    }
    drvthis->store_private_ptr(drvthis, NULL);
}

/////////////////////////////////////////////////////////////////
// Returns the display width
//
MODULE_EXPORT int
sed1520_width (Driver *drvthis)
{
    //PrivateData *p = drvthis->private_data;
    return WIDTH;
}

/////////////////////////////////////////////////////////////////
// Returns the display height
//
MODULE_EXPORT int
sed1520_height (Driver *drvthis)
{
    //PrivateData *p = drvthis->private_data;
    return HEIGHT;
}

/////////////////////////////////////////////////////////////////
// Returns the display width
//
MODULE_EXPORT int
sed1520_cellwidth (Driver *drvthis)
{
    //PrivateData *p = drvthis->private_data;
    return CELLWIDTH;
}

/////////////////////////////////////////////////////////////////
// Returns the display height
//
MODULE_EXPORT int
sed1520_cellheight (Driver *drvthis)
{
    //PrivateData *p = drvthis->private_data;
    return CELLHEIGHT;
}

/////////////////////////////////////////////////////////////////
// Clears the LCD screen
//
MODULE_EXPORT void
sed1520_clear (Driver *drvthis)
{
    PrivateData *p = drvthis->private_data;

    memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);
}

/////////////////////////////////////////////////////////////////
//
// Flushes all output to the lcd...
//
MODULE_EXPORT void
sed1520_flush (Driver *drvthis)
{
    PrivateData *p = drvthis->private_data;
    int i, j;

    for (i = 0; i < HEIGHT; i++) {
	  selectpage(p->port, i);

	  selectcolumn(p->port, 0, CS1) ;
	  for (j = 0; j < PIXELWIDTH/2; j++)
	      writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS1);

	  selectcolumn(p->port, 0, CS2) ;
	  for (j = PIXELWIDTH/2; j < PIXELWIDTH; j++)
	      writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS2);
      }
}

/////////////////////////////////////////////////////////////////
// Prints a string on the lc display, at position (x,y).  The
// upper-left is (1,1), and the lower right should be (20,4).
//
MODULE_EXPORT void
sed1520_string (Driver *drvthis, int x, int y, const char string[])
{
    PrivateData *p = drvthis->private_data;
    int i;

    x--;			// Convert 1-based coords to 0-based
    y--;

    for (i = 0; string[i] != '\0'; i++)
	drawchar2fb(p->framebuf, x + i, y, string[i]);
}

/////////////////////////////////////////////////////////////////
// Writes  char c at position x,y into the framebuffer.
// x and y are 1-based textmode coordinates.
//
MODULE_EXPORT void
sed1520_chr (Driver *drvthis, int x, int y, char c)
{
    PrivateData *p = drvthis->private_data;

    y--;
    x--;
    drawchar2fb(p->framebuf, x, y, c);
}

/////////////////////////////////////////////////////////////////
// This function draws a number num into the last 3 rows of the
// framebuffer at 1-based position x. It should draw a 4-row font,
// but methinks this would look a little stretched. When
// num=10 a colon is drawn.
// FIXME: make big numbers use less memory
//
MODULE_EXPORT void
sed1520_num (Driver *drvthis, int x, int num)
{
    PrivateData *p = drvthis->private_data;
    int z, c, i, s;
    x--;

    // return on illegal char or illegal position
    if ((x >= WIDTH) || (num < 0) || (num > 10))
	return;

    if (num == 10) {		// colon
	for (z = 0; z < 3; z++) {		// Zeilen a 8 Punkte
	    for (c = 0; c < 6; c++) {		// 6 columns
		s = 0;
		for (i = 0; i < 8; i++) {	// 8 bits aus zeilen
		    s >>= 1;
		    if (*(fontbigdp[(z * 8) + i] + c) == '.')
			s |= 0x80;
		}
		if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH))
		    p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + c] = s;
	    }
	}
    }
    else {			// digits 0 - 9
	for (z = 0; z < 3; z++) {		// Zeilen a 8 Punkte
	    for (c = 0; c < 18; c++) {		// 18 columns
		s = 0;
		for (i = 0; i < 8; i++) {	// 8 bits aus zeilen
		    s >>= 1;
		    if (*(fontbignum[num][z * 8 + i] + c) == '.')
			s |= 0x80;
		}
		if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH))
		    p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + c] = s;
	    }
	}
    }
}


/////////////////////////////////////////////////////////////////
// Changes the font of character n to a pattern given by *dat.
// HD44780 Controllers only posses 8 programmable chars. But
// we store the fontmap completely in RAM, so every character
// can be altered. !Important: Characters have to be redrawn
// by drawchar2fb() to show their new shape. Because we use
// a non-standard 6x8 font a *dat not calculated from
// width and height will fail.
//
MODULE_EXPORT void
sed1520_set_char (Driver *drvthis, int n, char *dat)
{
    //PrivateData *p = drvthis->private_data;
    int row, col;

    if (n < 0 || n > 255)
	return;
    if (!dat)
	return;

    for (row = 0; row < CELLHEIGHT; row++) {
	int i = 0;

	for (col = 0; col < CELLWIDTH; col++)
	    i = (i << 1) | (dat[(row * CELLWIDTH) + col] > 0);

	fontmap[n][row] = i;
    }
}


/////////////////////////////////////////////////////////////////
// Draws a vertical from the bottom up to the last 3 rows of the
// framebuffer at 1-based position x. len is given in pixels.
//
MODULE_EXPORT void
sed1520_old_vbar (Driver *drvthis, int x, int len)
{
    PrivateData *p = drvthis->private_data;
    int i, j, k;

    x--;

    for (j = 0; j < 3; j++) {
	k = 0;
	for (i = 0; i < CELLHEIGHT; i++) {
	    if (len > i)
		k |= (1 << (CELLHEIGHT-1 - i));
	}

	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 0] = 0;
	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 1] = 0;
	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 2] = k;
	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 3] = k;
	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 4] = k;
	p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 5] = 0;
	len -= CELLHEIGHT;
    }
}


/////////////////////////////////////////////////////////////////
// Draws a horizontal bar from left to right at 1-based position
// x,y into the framebuffer. len is given in pixels.
//
MODULE_EXPORT void
sed1520_old_hbar (Driver *drvthis, int x, int y, int len)
{
    PrivateData *p = drvthis->private_data;
    int i;

    x--;
    y--;

    if ((y < 0) || (y >= HEIGHT) || (x < 0) || (len < 0) || ((x + (len / CELLWIDTH)) >= WIDTH))
	return;

    for (i = 0; i < len; i++)
	p->framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + i] = 0x3C;  // set low 6 bits
}

/////////////////////////////////////////////////////////////////
// Reprogrammes character dest to contain an icon given by
// which. Calls set_char() to do this.
//
MODULE_EXPORT int
sed1520_icon (Driver *drvthis, int x, int y, int icon)
{
    //PrivateData *p = drvthis->private_data;
    static char heart_open[] = {
	1, 1, 1, 1, 1,
	1, 0, 1, 0, 1,
	0, 0, 0, 0, 0,
	0, 0, 0, 0, 0,
	0, 0, 0, 0, 0,
	1, 0, 0, 0, 1,
	1, 1, 0, 1, 1,
	1, 1, 1, 1, 1 };

    static char heart_filled[] = {
	1, 1, 1, 1, 1,
	1, 0, 1, 0, 1,
	0, 1, 0, 1, 0,
	0, 1, 1, 1, 0,
	0, 1, 1, 1, 0,
	1, 0, 1, 0, 1,
	1, 1, 0, 1, 1,
	1, 1, 1, 1, 1 };

    switch (icon) {
	case ICON_BLOCK_FILLED:
	    sed1520_chr(drvthis, x, y, 255);
	    break;
	case ICON_HEART_FILLED:
	    sed1520_set_char(drvthis, 0, heart_filled);
	    sed1520_chr(drvthis, x, y, 0);
	    break;
	case ICON_HEART_OPEN:
	    sed1520_set_char(drvthis, 0, heart_open);
	    sed1520_chr(drvthis, x, y, 0);
	    break;
	default:
	    return -1;
    }
    return 0;
}



  • [Lcdproc] SED1520 interface PCB and driver, Gerhard Pircher, 02/13/2008

Archive powered by MHonArc 2.6.18.

Top of page