Re-worked sed1520 driver:
- Add 68-familiy style interface support and make it configurable. - Make delay configurable. - Correct swapped display halves. - Resurrect vBar / hBar functions. - Fix icon definitions and modify set_char for common data format.
This commit is contained in:
@@ -19,6 +19,7 @@ v.0.5dev (ongoing development)
|
|||||||
* All drivers: sync functions with prototypes
|
* All drivers: sync functions with prototypes
|
||||||
* Port remaining drivers to 0.5 API (glk, lcdm001, stv5730)
|
* Port remaining drivers to 0.5 API (glk, lcdm001, stv5730)
|
||||||
* Pyramid: Only send LED state changes, doxygen-ize
|
* Pyramid: Only send LED state changes, doxygen-ize
|
||||||
|
* sed1520: Make it work with 68-family style interface, convert to 0.5 API
|
||||||
|
|
||||||
v0.5.4
|
v0.5.4
|
||||||
* Update driver includes and LDFLAGS (fixed glk and bayrad binding error)
|
* Update driver includes and LDFLAGS (fixed glk and bayrad binding error)
|
||||||
|
|||||||
@@ -3,14 +3,229 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
This section talks about using LCDproc with LCD displays that use the
|
This section talks about using LCDproc with LCD displays that use the
|
||||||
sed1520 chipset.
|
SED1520 chipset.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>Currently the driver supports 122x32 pixel graphic displays based on
|
<para>Currently the driver supports 122x32 pixel graphic displays based on
|
||||||
the SED1520 Controller connected to the parallel port.</para>
|
the SED1520 controller connected to the parallel port.</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>Those SED1520 displays are the most troublesome I have ever used. You
|
||||||
|
should probably avoid using them and get a 20x4 text display instead.</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<sect2 id="sed1520-connections">
|
||||||
|
<title>Connections</title>
|
||||||
<!-- Insert schematic here -->
|
<!-- Insert schematic here -->
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>Displays using SED1520 come in a wide variety of configurations. It is
|
||||||
|
possible to cause harm to your display (e.g. connecting negative voltage
|
||||||
|
incorrectly. Be sure to check your datasheet! Do not try to use a display
|
||||||
|
without having a datasheet to check against!</para>
|
||||||
|
<para>Here here some of the options I encountered:</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para>Negative voltage: The chip requires negative voltage for
|
||||||
|
driving the display. Some display modules have a negative voltage converter
|
||||||
|
on-board. On those that don't you have to supply about -7 V (will not
|
||||||
|
show how to do this).</para></listitem>
|
||||||
|
<listitem><para>Reset circuit: Some display modules have an R/C-combination
|
||||||
|
on-board selecting an MCU interface if the pin is not connected.</para></listitem>
|
||||||
|
<listitem><para>Frequency generator: The SED1520 is manufactured in several
|
||||||
|
versions. Some contain an on-chip frequency generator, others require an external
|
||||||
|
clock of 2 kHz (won't show this here). Note that display modules with an
|
||||||
|
on-chip generator do not have a /CS (chip select) line.</para></listitem>
|
||||||
|
<listitem><para>Incorrect datasheets: I have seen display datasheets
|
||||||
|
incorrectly naming pins, missing some of the commands, missing pages from the
|
||||||
|
chip description and other odds. Be warned!</para></listitem>
|
||||||
|
<listitem><para>No pin numbers are given in the tables below. You have to
|
||||||
|
figure out those yourself from the datasheet for your display!</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</warning>
|
||||||
|
|
||||||
|
<para>That said here some wirings:</para>
|
||||||
|
|
||||||
|
<sect3 id="sed1520-80">
|
||||||
|
<title>80-style connection style</title>
|
||||||
|
|
||||||
|
<para>This mode of operation is selected if the RESET line is wired to ground.
|
||||||
|
The wiring used by this driver in 80-style mode requires the use of an external
|
||||||
|
74HC04 inverter and assumes you have /CS1 and /CS2 lines available (thus you
|
||||||
|
must have an external clock generator) and toggles the /RW line. This is the
|
||||||
|
original wiring by Robin Adams.</para>
|
||||||
|
|
||||||
|
<table id="sed1520-connections-80-mapping">
|
||||||
|
<title>SED1520 80-style wiring schematic</title>
|
||||||
|
<tgroup cols="5" align="left">
|
||||||
|
<colspec colname="lpt1"/>
|
||||||
|
<colspec colname="lpt2" align="right"/>
|
||||||
|
<colspec colname="base" align="center"/>
|
||||||
|
<colspec colname="lcd1"/>
|
||||||
|
<colspec colname="lcd2"/>
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry namest="lpt1" nameend="lpt2" align="center">Parallel port</entry>
|
||||||
|
<entry morerows="1"><-></entry>
|
||||||
|
<entry namest="lcd1" nameend="lcd2" align="center">LCD</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>name</entry>
|
||||||
|
<entry>pin</entry>
|
||||||
|
<entry>name</entry>
|
||||||
|
<entry>pin</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>D0-D7</entry>
|
||||||
|
<entry>2-9</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>DB0-DB7</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nSTRB</entry>
|
||||||
|
<entry>1</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>/WR</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nLF</entry>
|
||||||
|
<entry>14</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>/CS1</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>INIT</entry>
|
||||||
|
<entry>16</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>/CS2</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nSEL</entry>
|
||||||
|
<entry>17</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>A0</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>VDD</entry>
|
||||||
|
<entry>/RD</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>GND</entry>
|
||||||
|
<entry>RESET/IF</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>2 kHz clock</entry>
|
||||||
|
<entry>CL</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</sect3>
|
||||||
|
|
||||||
|
<sect3 id="sed1520-68">
|
||||||
|
<title>68-style connection style</title>
|
||||||
|
|
||||||
|
<para>This mode of operation is selected if the RESET line is wired to VDD.
|
||||||
|
For this wiring the display is required to have an on-board frequency generator
|
||||||
|
(something you really want to have) and the display module has an E1 and E2
|
||||||
|
line. Writing is controlled by toggling the E1 and E2 line while /RW is low.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table id="sed1520-connections-68-mapping">
|
||||||
|
<title>SED1520 68-style wiring schematic</title>
|
||||||
|
<tgroup cols="5" align="left">
|
||||||
|
<colspec colname="lpt1"/>
|
||||||
|
<colspec colname="lpt2" align="right"/>
|
||||||
|
<colspec colname="base" align="center"/>
|
||||||
|
<colspec colname="lcd1"/>
|
||||||
|
<colspec colname="lcd2"/>
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry namest="lpt1" nameend="lpt2" align="center">Parallel port</entry>
|
||||||
|
<entry morerows="1"><-></entry>
|
||||||
|
<entry namest="lcd1" nameend="lcd2" align="center">LCD</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>name</entry>
|
||||||
|
<entry>pin</entry>
|
||||||
|
<entry>name</entry>
|
||||||
|
<entry>pin</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>D0-D7</entry>
|
||||||
|
<entry>2-9</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>DB0-DB7</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nSTRB</entry>
|
||||||
|
<entry>1</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>R/-W</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nLF</entry>
|
||||||
|
<entry>14</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>E1</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>INIT</entry>
|
||||||
|
<entry>16</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>E2</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>nSEL</entry>
|
||||||
|
<entry>17</entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>A0</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>VDD</entry>
|
||||||
|
<entry>RESET/IF</entry>
|
||||||
|
<entry>*</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>This is the only wiring I was able to test. My display (Crystalfontz
|
||||||
|
CFAG12232J-TFH-TA) has E1 and E2 lines. Trying to use it with 80-style wiring
|
||||||
|
was not successful. I suspect that (as the E# line is used as /RD line in
|
||||||
|
80-style mode) the wiring resulted in reading from one chip while writing to
|
||||||
|
the other at the same time and the data bus got fuzzed.</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</sect3>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<!-- ## Seiko Epson 1520 driver ## -->
|
<!-- ## Seiko Epson 1520 driver ## -->
|
||||||
<sect2 id="sed1520-config">
|
<sect2 id="sed1520-config">
|
||||||
<title>Configuration in LCDd.conf</title>
|
<title>Configuration in LCDd.conf</title>
|
||||||
@@ -31,6 +246,36 @@ the SED1520 Controller connected to the parallel port.</para>
|
|||||||
The default value is <literal>0x378</literal>.
|
The default value is <literal>0x378</literal>.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<property>InterfaceType</property> =
|
||||||
|
<parameter><replaceable>INTERFACE</replaceable></parameter>
|
||||||
|
</term>
|
||||||
|
<listitem><para>
|
||||||
|
The SED1520 chip can be driven with one of two interface types selected by
|
||||||
|
the level of the RESET line: 68-style MCU interface (high level) or
|
||||||
|
80-style MCU interface (low level).
|
||||||
|
</para><para>
|
||||||
|
Use value <literal>68</literal> if your display is connected 68-style
|
||||||
|
style. In this mode the E1 and E2 lines are cycled to write the data. If
|
||||||
|
you use <literal>80</literal> (the default), 80-style style is selected
|
||||||
|
and the /WR line is cycled and /CS1 and /CS2 lines are required.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<property>DelayMult</property> =
|
||||||
|
<parameter><replaceable>DELAY</replaceable></parameter>
|
||||||
|
</term>
|
||||||
|
<listitem><para>
|
||||||
|
This value adds an additional delay to each write, in microseconds. For
|
||||||
|
the 80-style connection type actual two delays are added each. The
|
||||||
|
default value of <literal>1</literal> already slows down communication a
|
||||||
|
lot, larger value should likely be avoided.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</sect3>
|
</sect3>
|
||||||
|
|||||||
+155
-101
@@ -2,19 +2,14 @@
|
|||||||
* LCDd \c sed1520 driver for graphic displays based on the SED1520.
|
* LCDd \c sed1520 driver for graphic displays based on the SED1520.
|
||||||
*
|
*
|
||||||
* This is a driver for 122x32 pixel graphic displays based on the SED1520
|
* 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/
|
* controller connected to the parallel port. This Controller has no
|
||||||
* 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
|
* built in character generator. Therefore all fonts and pixels are generated
|
||||||
* by this driver.
|
* by this driver.
|
||||||
*
|
|
||||||
* \todo Convert to 0.5 style hbar / vbar API.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* (C) 2001 Robin Adams ( robin@adams-online.de )
|
* Copyright (C) 2001 Robin Adams <robin@adams-online.de>
|
||||||
*
|
* 2011 Markus Dolze <bsdfan@nurfuerspam.de>
|
||||||
* The HD44780 font in sed1520fm.c was shamelessly stolen from
|
|
||||||
* Michael Reinelt / lcd4linux and is (C) 2000 by him.
|
|
||||||
*
|
*
|
||||||
* This file is released under the GNU General Public License. Refer to the
|
* This file is released under the GNU General Public License. Refer to the
|
||||||
* COPYING file distributed with this package.
|
* COPYING file distributed with this package.
|
||||||
@@ -22,8 +17,14 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Driver history:
|
* Driver history:
|
||||||
* Moved the delay timing code by Charles Steinkuehler to timing.h.
|
* 2001, Guillaume Filion <gfk@logidac.com>:
|
||||||
* Guillaume Filion <gfk@logidac.com>, December 2001
|
* - Moved the delay timing code by Charles Steinkuehler to timing.h.
|
||||||
|
* 2011, Markus Dolze:
|
||||||
|
* - Add 68-familiy style interface support and make it configurable
|
||||||
|
* - Make delay configurable
|
||||||
|
* - Correct swapped display halves
|
||||||
|
* - Resurrect vBar / hBar functions
|
||||||
|
* - Fix icon definitions and modify set_char for common data format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@@ -45,9 +46,9 @@
|
|||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include "sed1520fm.h"
|
#include "sed1520fm.h"
|
||||||
|
#include "lpt-port.h"
|
||||||
|
|
||||||
#define uPause timing_uPause
|
#define uPause timing_uPause
|
||||||
#define IODELAY 500
|
|
||||||
|
|
||||||
#ifndef DEFAULT_PORT
|
#ifndef DEFAULT_PORT
|
||||||
# define DEFAULT_PORT 0x378
|
# define DEFAULT_PORT 0x378
|
||||||
@@ -62,14 +63,16 @@
|
|||||||
#define WIDTH ((int) (PIXELWIDTH / CELLWIDTH)) /* 20 */
|
#define WIDTH ((int) (PIXELWIDTH / CELLWIDTH)) /* 20 */
|
||||||
#define HEIGHT ((int) (PIXELHEIGHT / CELLHEIGHT)) /* 4 */
|
#define HEIGHT ((int) (PIXELHEIGHT / CELLHEIGHT)) /* 4 */
|
||||||
|
|
||||||
#define A0 0x08 /* nSEL */
|
#define A0 nSEL /* pin 17 */
|
||||||
#define CS2 0x04 /* INIT */
|
#define CS1 nLF /* pin 14 */
|
||||||
#define CS1 0x02 /* nLF */
|
#define CS2 INIT /* pin 16 */
|
||||||
#define WR 0x01 /* nSTRB */
|
#define WR nSTRB /* pin 1 */
|
||||||
|
|
||||||
/** private data for the \c sed1520 driver */
|
/** private data for the \c sed1520 driver */
|
||||||
typedef struct sed1520_private_data {
|
typedef struct sed1520_private_data {
|
||||||
unsigned int port;
|
unsigned short port;
|
||||||
|
int interface;
|
||||||
|
int delayMult;
|
||||||
|
|
||||||
unsigned char *framebuf;
|
unsigned char *framebuf;
|
||||||
} PrivateData;
|
} PrivateData;
|
||||||
@@ -83,71 +86,106 @@ MODULE_EXPORT char *symbol_prefix = "sed1520_";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes command value to one or both sed1520 selected by chip.
|
* Writes command value to one or both sed1520 selected by chip.
|
||||||
* \param port Output port base address
|
* \param p Pointer to private data structure
|
||||||
* \param value Command byte to write
|
* \param value Command byte to write
|
||||||
* \param chip Bitmap of controllers to send value to
|
* \param chip Bitmap of controllers to send value to
|
||||||
|
*
|
||||||
|
* \note It is a little code duplication having writecommand and writedata
|
||||||
|
* both, but I leave it that way.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
writecommand(unsigned int port, int value, int chip)
|
writecommand(PrivateData *p, int value, int chip)
|
||||||
{
|
{
|
||||||
port_out(port, value);
|
if (p->interface == 68) {
|
||||||
|
port_out(p->port + 2, 0 ^ OUTMASK);
|
||||||
|
port_out(p->port, value);
|
||||||
|
/* cycle E */
|
||||||
|
port_out(p->port + 2, ((chip & CS1) + (chip & CS2)) ^ OUTMASK);
|
||||||
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
|
port_out(p->port + 2, 0 ^ OUTMASK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
port_out(p->port, value);
|
||||||
/*
|
/*
|
||||||
* lower WR, rise A0 and CS1 and/or CS2. Take bit inversion of parallel
|
* lower WR, rise A0 and CS1 and/or CS2. Take bit inversion of parallel
|
||||||
* port into account.
|
* port into account. External inverter required!
|
||||||
*/
|
*/
|
||||||
port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
|
port_out(p->port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
|
||||||
/* rise WR */
|
/* rise WR */
|
||||||
port_out(port + 2, CS1 - (chip & CS1) + (chip & CS2));
|
port_out(p->port + 2, CS1 - (chip & CS1) + (chip & CS2));
|
||||||
uPause(IODELAY);
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
/* lower WR again */
|
/* lower WR again */
|
||||||
port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
|
port_out(p->port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
|
||||||
uPause(IODELAY);
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes data value to one or both sed 1520 selected by chip.
|
* Writes data value to one or both sed 1520 selected by chip.
|
||||||
* \param port Output port base address
|
* \param p Pointer to private data structure
|
||||||
* \param value Data byte to write
|
* \param value Data byte to write
|
||||||
* \param chip Bitmap of controllers to send value to
|
* \param chip Bitmap of controllers to send value to
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
writedata(unsigned int port, int value, int chip)
|
writedata(PrivateData *p, int value, int chip)
|
||||||
{
|
{
|
||||||
port_out(port, value);
|
if (p->interface == 68) {
|
||||||
/*
|
port_out(p->port + 2, (A0) ^ OUTMASK);
|
||||||
* lower WR and A0, rise CS1 and/or CS2. Take bit inversion of parallel
|
port_out(p->port, value);
|
||||||
* port into account.
|
/* cycle E */
|
||||||
*/
|
port_out(p->port + 2, (A0 + (chip & CS1) + (chip & CS2)) ^ OUTMASK);
|
||||||
port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
port_out(port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2));
|
port_out(p->port + 2, (A0) ^ OUTMASK);
|
||||||
uPause(IODELAY);
|
}
|
||||||
port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
|
else {
|
||||||
uPause(IODELAY);
|
port_out(p->port, value);
|
||||||
|
/* lower WR and A0, rise CS1 and/or CS2. See also writecommand. */
|
||||||
|
port_out(p->port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
|
||||||
|
port_out(p->port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2));
|
||||||
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
|
port_out(p->port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
|
||||||
|
if (p->delayMult) uPause(p->delayMult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects a page (=row) on both sed1520s.
|
* Selects a page (=row) on both sed1520s.
|
||||||
* \param port Output port base address
|
* \param p Pointer to private data structure
|
||||||
* \param page Page (=row) number (0-3)
|
* \param page Page (=row) number (0-3)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
selectpage(unsigned int port, int page)
|
selectpage(PrivateData *p, int page)
|
||||||
{
|
{
|
||||||
writecommand(port, 0xB8 + (page & 0x03), CS1 + CS2);
|
writecommand(p, PAGE_ADR + (page & 0x03), CS1 + CS2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects a column on the sed1520s specified by chip.
|
* Selects a column on the sed1520 specified by chip.
|
||||||
* \param port Output port base address
|
* \param p Pointer to private data structure
|
||||||
* \param column Select column (segment) in controller (0-79)
|
* \param column Select column (segment) in controller (0-60)
|
||||||
* \param chip Bitmap of controllers to send value to
|
* \param chip Bitmap of controllers to send value to
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
selectcolumn(unsigned int port, int column, int chip)
|
selectcolumn(PrivateData *p, int column, int chip)
|
||||||
{
|
{
|
||||||
writecommand(port, (column & 0x7F), chip);
|
writecommand(p, COLUMN_ADR + (column & 0x7F), chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Display memory layout information:
|
||||||
|
*
|
||||||
|
* The SED1520 does not use a linear display data memory but a paged memory
|
||||||
|
* with four pages (0-3) corresponding to rows 0-7, 8-15, 16-23, and 24-31.
|
||||||
|
* Within each page, one bytes represents 8 pixels of one column (from 0-60)
|
||||||
|
* with bit 0 (LSB) being the top and bit 7 (MSB) the bottom pixel within
|
||||||
|
* that page.
|
||||||
|
*
|
||||||
|
* To write data to display memory one selects the page and column and then
|
||||||
|
* writes bytes of pixel data to the display. The column counter is increased
|
||||||
|
* by each write so the display fills from left ro right (the SED1520 can
|
||||||
|
* also be configured to write from right to left).
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws character z from fontmap to the framebuffer at position x,y.
|
* Draws character z from fontmap to the framebuffer at position x,y.
|
||||||
* The Fontmap is stored in rows while the framebuffer is stored in columns,
|
* The Fontmap is stored in rows while the framebuffer is stored in columns,
|
||||||
@@ -202,6 +240,13 @@ sed1520_init(Driver * drvthis)
|
|||||||
report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno));
|
report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
p->delayMult = drvthis->config_get_int(drvthis->name, "delaymult", 0, 1);
|
||||||
|
if (p->delayMult < 0 || p->delayMult > 1000) {
|
||||||
|
report(RPT_WARNING, "%s: DelayMult value invalid, using default (1)", drvthis->name);
|
||||||
|
p->delayMult = 1;
|
||||||
|
}
|
||||||
|
if (p->delayMult == 0)
|
||||||
|
report(RPT_INFO, "%s: Delay is disabled", drvthis->name);
|
||||||
|
|
||||||
/* Allocate our framebuffer */
|
/* Allocate our framebuffer */
|
||||||
p->framebuf = (unsigned char *) calloc(PIXELWIDTH * HEIGHT, sizeof(unsigned char));
|
p->framebuf = (unsigned char *) calloc(PIXELWIDTH * HEIGHT, sizeof(unsigned char));
|
||||||
@@ -214,18 +259,23 @@ sed1520_init(Driver * drvthis)
|
|||||||
memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);
|
memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);
|
||||||
|
|
||||||
/* Open port */
|
/* Open port */
|
||||||
if (port_access(p->port) || port_access(p->port + 2)) {
|
if (port_access_multiple(p->port, 3)) {
|
||||||
report(RPT_ERR, "%s: unable to access port 0x%03X", drvthis->name, p->port);
|
report(RPT_ERR, "%s: unable to access port 0x%03X", drvthis->name, p->port);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get interface style (68-family or 80-family) */
|
||||||
|
p->interface = drvthis->config_get_int(drvthis->name, "InterfaceType", 0, 80);
|
||||||
|
if (p->interface != 68 && p->interface != 80) {
|
||||||
|
report(RPT_WARNING, "%s: Invalid interface configured, using type 80", drvthis->name);
|
||||||
|
p->interface = 80;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize display */
|
/* Initialize display */
|
||||||
port_out(p->port, 0);
|
writecommand(p, SOFT_RESET, CS1 + CS2);
|
||||||
port_out(p->port + 2, WR + CS2);
|
writecommand(p, DISP_ON, CS1 + CS2);
|
||||||
writecommand(p->port, 0xE2, CS1 + CS2); /* software reset */
|
writecommand(p, DISP_START_LINE, CS1 + CS2);
|
||||||
writecommand(p->port, 0xAF, CS1 + CS2); /* display on */
|
selectpage(p, 3);
|
||||||
writecommand(p->port, 0xC0, CS1 + CS2); /* display start address */
|
|
||||||
selectpage(p->port, 3);
|
|
||||||
|
|
||||||
report(RPT_DEBUG, "%s: init() done", drvthis->name);
|
report(RPT_DEBUG, "%s: init() done", drvthis->name);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -306,18 +356,18 @@ sed1520_flush(Driver * drvthis)
|
|||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < HEIGHT; i++) {
|
for (i = 0; i < HEIGHT; i++) {
|
||||||
/* select line */
|
/* select line/page */
|
||||||
selectpage(p->port, i);
|
selectpage(p, i);
|
||||||
|
|
||||||
/* update left half of display */
|
/* update left half of display */
|
||||||
selectcolumn(p->port, 0, CS2);
|
selectcolumn(p, 0, CS1);
|
||||||
for (j = 0; j < PIXELWIDTH / 2; j++)
|
for (j = 0; j < PIXELWIDTH / 2; j++)
|
||||||
writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS2);
|
writedata(p, p->framebuf[j + (i * PIXELWIDTH)], CS1);
|
||||||
|
|
||||||
/* update right half of display */
|
/* update right half of display */
|
||||||
selectcolumn(p->port, 0, CS1);
|
selectcolumn(p, 0, CS2);
|
||||||
for (j = PIXELWIDTH / 2; j < PIXELWIDTH; j++)
|
for (j = PIXELWIDTH / 2; j < PIXELWIDTH; j++)
|
||||||
writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS1);
|
writedata(p, p->framebuf[j + (i * PIXELWIDTH)], CS2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +456,7 @@ sed1520_num(Driver * drvthis, int x, int num)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* API: Changes the font of character n to a pattern given by *dat.
|
* API: Changes the font of character n to a pattern given by *dat.
|
||||||
* HD44780 Controllers only posses 8 programmable chars. But we store the
|
* HD44780 controllers only posses 8 programmable chars. But we store the
|
||||||
* fontmap completely in RAM, so every character can be altered.
|
* fontmap completely in RAM, so every character can be altered.
|
||||||
*
|
*
|
||||||
* Important: Characters have to be redrawn by drawchar2fb() to show their
|
* Important: Characters have to be redrawn by drawchar2fb() to show their
|
||||||
@@ -416,76 +466,80 @@ sed1520_num(Driver * drvthis, int x, int num)
|
|||||||
MODULE_EXPORT void
|
MODULE_EXPORT void
|
||||||
sed1520_set_char(Driver * drvthis, int n, char *dat)
|
sed1520_set_char(Driver * drvthis, int n, char *dat)
|
||||||
{
|
{
|
||||||
int row, col;
|
int row;
|
||||||
|
unsigned char mask = (1 << CELLWIDTH) - 1;
|
||||||
|
|
||||||
if (n < 0 || n > 255)
|
if (n < 0 || n > 255)
|
||||||
return;
|
return;
|
||||||
if (!dat)
|
if (!dat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (row = 0; row < CELLHEIGHT; row++) {
|
for (row = 0; row < CELLHEIGHT; row++)
|
||||||
int i = 0;
|
fontmap[n][row] = dat[row] & mask;
|
||||||
|
|
||||||
for (col = 0; col < CELLWIDTH; col++)
|
|
||||||
i = (i << 1) | (dat[(row * CELLWIDTH) + col] > 0);
|
|
||||||
|
|
||||||
fontmap[n][row] = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* API: Draws a vertical from the bottom up at 1-based position x.
|
||||||
* 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
|
MODULE_EXPORT void
|
||||||
sed1520_old_vbar(Driver * drvthis, int x, int len)
|
sed1520_vbar(Driver *drvthis, int x, int y, int len, int promille, int options)
|
||||||
{
|
{
|
||||||
PrivateData *p = drvthis->private_data;
|
PrivateData *p = drvthis->private_data;
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
|
int pixels;
|
||||||
|
|
||||||
x--;
|
x--;
|
||||||
|
|
||||||
|
if (x < 0 || y < 1 || x >= WIDTH || y > HEIGHT || len > HEIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pixels = len * CELLHEIGHT * promille / 1000;
|
||||||
|
|
||||||
for (j = 0; j < 3; j++) {
|
for (j = 0; j < 3; j++) {
|
||||||
k = 0;
|
k = 0;
|
||||||
/* Set height of block. Bottom is leftmost bit */
|
/* Set height of block. Bottom is leftmost bit */
|
||||||
for (i = 0; i < CELLHEIGHT; i++) {
|
for (i = 0; i < CELLHEIGHT; i++) {
|
||||||
if (len > i)
|
if (pixels > i)
|
||||||
k |= (1 << (CELLHEIGHT - 1 - i));
|
k |= (1 << (CELLHEIGHT - 1 - i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw directly into framebuffer starting from bottom */
|
/* Draw directly into framebuffer starting from bottom */
|
||||||
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 0] = 0;
|
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) + 1] = k;
|
||||||
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 2] = k;
|
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) + 3] = k;
|
||||||
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 4] = k;
|
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 4] = k;
|
||||||
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 5] = 0;
|
p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 5] = 0;
|
||||||
|
|
||||||
len -= CELLHEIGHT;
|
pixels -= CELLHEIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* API: Draws a horizontal bar from left to right at 1-based position x,y into
|
||||||
* Draws a horizontal bar from left to right at 1-based position x,y into the
|
* the framebuffer.
|
||||||
* framebuffer. len is given in pixels.
|
|
||||||
*/
|
*/
|
||||||
MODULE_EXPORT void
|
MODULE_EXPORT void
|
||||||
sed1520_old_hbar(Driver * drvthis, int x, int y, int len)
|
sed1520_hbar(Driver *drvthis, int x, int y, int len, int promille, int options)
|
||||||
{
|
{
|
||||||
PrivateData *p = drvthis->private_data;
|
PrivateData *p = drvthis->private_data;
|
||||||
int i;
|
int i;
|
||||||
|
int pixels;
|
||||||
|
|
||||||
x--;
|
x--;
|
||||||
y--;
|
y--;
|
||||||
|
|
||||||
if ((y < 0) || (y >= HEIGHT) || (x < 0) || (len < 0) || ((x + (len / CELLWIDTH)) >= WIDTH))
|
if ((y < 0) || (y >= HEIGHT) || (x < 0) || (len < 0) || (x + len > WIDTH))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Draw directly into framebuffer. Use 4 dots in the middle (0x3C). */
|
pixels = len * CELLWIDTH * promille / 1000;
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
p->framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + i] = 0x3C;
|
/*
|
||||||
|
* Draw directly into framebuffer. Drawing is easy, as one byte is one
|
||||||
|
* column in a page. Use 5 dots in the middle (0x3E).
|
||||||
|
*/
|
||||||
|
for (i = 0; i < pixels; i++)
|
||||||
|
p->framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + i] = 0x3E;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -496,26 +550,26 @@ sed1520_icon(Driver * drvthis, int x, int y, int icon)
|
|||||||
{
|
{
|
||||||
static char heart_open[] =
|
static char heart_open[] =
|
||||||
{
|
{
|
||||||
1, 1, 1, 1, 1,
|
b_OOOOO,
|
||||||
1, 0, 1, 0, 1,
|
b_O_O_O,
|
||||||
0, 0, 0, 0, 0,
|
b______,
|
||||||
0, 0, 0, 0, 0,
|
b______,
|
||||||
0, 0, 0, 0, 0,
|
b______,
|
||||||
1, 0, 0, 0, 1,
|
b_O___O,
|
||||||
1, 1, 0, 1, 1,
|
b_OO_OO,
|
||||||
1, 1, 1, 1, 1
|
b_OOOOO
|
||||||
};
|
};
|
||||||
|
|
||||||
static char heart_filled[] =
|
static char heart_filled[] =
|
||||||
{
|
{
|
||||||
1, 1, 1, 1, 1,
|
b_OOOOO,
|
||||||
1, 0, 1, 0, 1,
|
b_O_O_O,
|
||||||
0, 1, 0, 1, 0,
|
b__O_O_,
|
||||||
0, 1, 1, 1, 0,
|
b__OOO_,
|
||||||
0, 1, 1, 1, 0,
|
b__OOO_,
|
||||||
1, 0, 1, 0, 1,
|
b_O_O_O,
|
||||||
1, 1, 0, 1, 1,
|
b_OO_OO,
|
||||||
1, 1, 1, 1, 1
|
b_OOOOO
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (icon) {
|
switch (icon) {
|
||||||
|
|||||||
@@ -3,6 +3,20 @@
|
|||||||
|
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
|
||||||
|
/* Commands for SED1520 */
|
||||||
|
#define DISP_OFF 0xAE
|
||||||
|
#define DISP_ON 0xAF
|
||||||
|
#define DISP_START_LINE 0xC0
|
||||||
|
#define PAGE_ADR 0xB8
|
||||||
|
#define COLUMN_ADR 0x00
|
||||||
|
#define ADC_NORM 0xA0 /* left-to-right */
|
||||||
|
#define ADC_INV 0xA1 /* right-to-left */
|
||||||
|
#define STATIC_DR_OFF 0xA4 /* normal operation */
|
||||||
|
#define STATIC_DR_ON 0xA5 /* power safe */
|
||||||
|
#define DUTY_1_16 0xA8
|
||||||
|
#define DUTY_1_32 0xA9
|
||||||
|
#define SOFT_RESET 0xE2
|
||||||
|
|
||||||
MODULE_EXPORT int sed1520_init (Driver *drvthis);
|
MODULE_EXPORT int sed1520_init (Driver *drvthis);
|
||||||
MODULE_EXPORT void sed1520_close (Driver *drvthis);
|
MODULE_EXPORT void sed1520_close (Driver *drvthis);
|
||||||
MODULE_EXPORT int sed1520_width (Driver *drvthis);
|
MODULE_EXPORT int sed1520_width (Driver *drvthis);
|
||||||
|
|||||||
@@ -11,42 +11,9 @@
|
|||||||
// package for further details. //
|
// package for further details. //
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define b______ 0x00
|
#include "sed1520fm.h"
|
||||||
#define b_____O 0x01
|
|
||||||
#define b____O_ 0x02
|
|
||||||
#define b____OO 0x03
|
|
||||||
#define b___O__ 0x04
|
|
||||||
#define b___O_O 0x05
|
|
||||||
#define b___OO_ 0x06
|
|
||||||
#define b___OOO 0x07
|
|
||||||
#define b__O___ 0x08
|
|
||||||
#define b__O__O 0x09
|
|
||||||
#define b__O_O_ 0x0a
|
|
||||||
#define b__O_OO 0x0b
|
|
||||||
#define b__OO__ 0x0c
|
|
||||||
#define b__OO_O 0x0d
|
|
||||||
#define b__OOO_ 0x0e
|
|
||||||
#define b__OOOO 0x0f
|
|
||||||
#define b_O____ 0x10
|
|
||||||
#define b_O___O 0x11
|
|
||||||
#define b_O__O_ 0x12
|
|
||||||
#define b_O__OO 0x13
|
|
||||||
#define b_O_O__ 0x14
|
|
||||||
#define b_O_O_O 0x15
|
|
||||||
#define b_O_OO_ 0x16
|
|
||||||
#define b_O_OOO 0x17
|
|
||||||
#define b_OO___ 0x18
|
|
||||||
#define b_OO__O 0x19
|
|
||||||
#define b_OO_O_ 0x1a
|
|
||||||
#define b_OO_OO 0x1b
|
|
||||||
#define b_OOO__ 0x1c
|
|
||||||
#define b_OOO_O 0x1d
|
|
||||||
#define b_OOOO_ 0x1e
|
|
||||||
#define b_OOOOO 0x1f
|
|
||||||
#define b_OOOOO 0x1f
|
|
||||||
#define bOOOOOO 0x3f
|
|
||||||
|
|
||||||
unsigned char fontmap[256][8] = {
|
char fontmap[256][8] = {
|
||||||
[0x20] {b______,
|
[0x20] {b______,
|
||||||
b______,
|
b______,
|
||||||
b______,
|
b______,
|
||||||
|
|||||||
@@ -1,8 +1,43 @@
|
|||||||
#ifndef SED1520FM_H
|
#ifndef SED1520FM_H
|
||||||
#define SED1520FM_H
|
#define SED1520FM_H
|
||||||
|
|
||||||
unsigned char fontmap[256][8];
|
#define b______ 0x00
|
||||||
unsigned char *fontbignum[10][24];
|
#define b_____O 0x01
|
||||||
unsigned char *fontbigdp[24];
|
#define b____O_ 0x02
|
||||||
|
#define b____OO 0x03
|
||||||
|
#define b___O__ 0x04
|
||||||
|
#define b___O_O 0x05
|
||||||
|
#define b___OO_ 0x06
|
||||||
|
#define b___OOO 0x07
|
||||||
|
#define b__O___ 0x08
|
||||||
|
#define b__O__O 0x09
|
||||||
|
#define b__O_O_ 0x0a
|
||||||
|
#define b__O_OO 0x0b
|
||||||
|
#define b__OO__ 0x0c
|
||||||
|
#define b__OO_O 0x0d
|
||||||
|
#define b__OOO_ 0x0e
|
||||||
|
#define b__OOOO 0x0f
|
||||||
|
#define b_O____ 0x10
|
||||||
|
#define b_O___O 0x11
|
||||||
|
#define b_O__O_ 0x12
|
||||||
|
#define b_O__OO 0x13
|
||||||
|
#define b_O_O__ 0x14
|
||||||
|
#define b_O_O_O 0x15
|
||||||
|
#define b_O_OO_ 0x16
|
||||||
|
#define b_O_OOO 0x17
|
||||||
|
#define b_OO___ 0x18
|
||||||
|
#define b_OO__O 0x19
|
||||||
|
#define b_OO_O_ 0x1a
|
||||||
|
#define b_OO_OO 0x1b
|
||||||
|
#define b_OOO__ 0x1c
|
||||||
|
#define b_OOO_O 0x1d
|
||||||
|
#define b_OOOO_ 0x1e
|
||||||
|
#define b_OOOOO 0x1f
|
||||||
|
#define b_OOOOO 0x1f
|
||||||
|
#define bOOOOOO 0x3f
|
||||||
|
|
||||||
|
char fontmap[256][8];
|
||||||
|
char *fontbignum[10][24];
|
||||||
|
char *fontbigdp[24];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user