






|
 |
Developers
onHand Manual: SED1560 lcd controller
Contents
Introduction
The onHand/Ruputer has an EPSON SED1560 lcd controller. The interface to this
controller is accomplished by two I/O registers: a control register and a data
register. The address of these registers in the onHand/Ruputer address space
are:
Register |
Name |
Address |
Control |
Alcd_c |
0x0010 |
Data |
Alcd_d |
0x0014 |
By writing to the control register we can set some internal variables of the
microcontroller and turn the display on or off. Here are the funtions selected
by the control register:
Function |
Value to write |
Explanation |
LCD on/off |
1010 111x
|
Turns the LCD display ON (x=1) or OFF (x=0) |
Display start line |
01xx xxxx
|
xxxxxx should be 1. Sets the RAM display line for the first line in
LCD |
Page |
1011 xxxx
|
Sets the current page |
Column (high-order 4bit) |
0001 xxxx
|
Sets the higher 4bits (nibble) of current column (see below) |
Column (low-order 4bit) |
0000 xxxx
|
Sets the lower 4bits of current column (see below) |
On the other hand the data register is used to read the contents of the LCD
controller RAM and to write new values in it. Normally we only need to write
into the data register (draw in the LCD). We only write because of performance
reasons, as we will draw the desired contents of the screen into a memory buffer
and then transfer the entire buffer to the LCD so if we needed to read the
screen contents, we would read from memory buffer as it's faster (and easier).
Structure of the LCD memory
The LCD has as video memory some RAM in which every bit maps directly to a
point of the display (magic done by the hardware of the controller).
The way this memory maps into the display is, at least, curious: the display
is divided in "pages" of 8-bit height and 102 columns. Each page is
handled independently and the bits maps to pixels of a page from top to bottom
and then from left to right. This way, each byte represents a column of the
page. The display of the onHand/Ruputer is a dot-matrix of 102x64; as we have a
64 pixels height, the display has 8 pages of 8 pixels height each.
That is:
+----------------------------------------------------+
| Page 0, 102 bytes |
+----------------------------------------------------+
| Page 1, 102 bytes |
+----------------------------------------------------+
| Page 2, 102 bytes |
+----------------------------------------------------+
| Page 3, 102 bytes |
+----------------------------------------------------+
| Page 4, 102 bytes |
+----------------------------------------------------+
| Page 5, 102 bytes |
+----------------------------------------------------+
| Page 6, 102 bytes |
+----------------------------------------------------+
| Page 7, 102 bytes |
+----------------------------------------------------+
Oddly enough, this is exactly the format of Seiko's MMP ignoring the MMP header.
In the page numbers we don't have any problem: thay start with the number 0
and continues thru number 7, the last one. But the column numbers are a little
more tricky. They start with column number 0x40 so the last column is 0xa5. To
translate from the desired x-coodinate to the real lcd column we have to add
0x40 (and remember that we pass the column number with two writes, one for the
high nibble and another for the low nibble).
Writing directly to the LCD
The first thing we have to do is to set the page and the column we are
willing to write. Here a little caveat: we can write only those parts of the
screen that have changed, but to write all the screen we have to output only 816
bytes, so considering the overhead that page/column set implies, and the losing
of some precious machine cycles because of branches, it's a better idea and
often faster to just mantain a "screenfull" image in a buffer and then
fire it up to the display in one shot.
In the most common case we will do:
- Write to the control register the page "n", initially 0, and the
column 0x40
- In a loop write all the columns of the current page to the data register
- if there are more pages, increment "n" and go to (1.).
To speed up this a bit, we will write the data in words rather than bytes,
and the loop to write all columns of the current page should be partially
unrolled.
In the examples I've have found, they unroll the column loop to do 3 times 16
word writes, and then, outside the loop, the last three words (I don't know why
they refuse to do 3 times 17 words writes, as the limits for the "goto"
are not exceeded, but this is the way it's done in signas.tv examples and
in wallcrush sources.)
I've not mentioned that within a page, the column counter in the LCD
controller autoincrements each time we do a writing, so we don't care about it
but when setting a new page. Considering this, tha code is rather simple.
Code example
Here is the example to write a screen directly to the LCD as published in Iwaki's
ruputer page:
# ===============
# LCD_DISPLAY
# ===============
il_lcd_display:
mov il_vram,a0
mov Alcd_c,a1
mov Alcd_d,a2
mov 0x0014,d3
mov Clcd_page,d2
il_lcd_display_01:
movb d2,(0,a1)
mov d3,(a1)
mov 3,d1
il_lcd_display_02:
mov (a0),d0
mov d0,(a2)
mov (2,a0),d0
mov d0,(a2)
mov (4,a0),d0
mov d0,(a2)
mov (6,a0),d0
mov d0,(a2)
mov (8,a0),d0
mov d0,(a2)
mov (10,a0),d0
mov d0,(a2)
mov (12,a0),d0
mov d0,(a2)
mov (14,a0),d0
mov d0,(a2)
mov (16,a0),d0
mov d0,(a2)
mov (18,a0),d0
mov d0,(a2)
mov (20,a0),d0
mov d0,(a2)
mov (22,a0),d0
mov d0,(a2)
mov (24,a0),d0
mov d0,(a2)
mov (26,a0),d0
mov d0,(a2)
mov (28,a0),d0
mov d0,(a2)
mov (30,a0),d0
mov d0,(a2)
add 32,a0
sub 1,d1
bne il_lcd_display_02
mov (a0),d0
mov d0,(a2)
mov (2,a0),d0
mov d0,(a2)
mov (4,a0),d0
mov d0,(a2)
add 6,a0
add 1,d2
cmp Clcd_page+8,d2
bne il_lcd_display_01
rts
il_lcd_display_main_end:
In the code example:
- il_vram is a pointer to the buffer which holds the desired
image contents.
- Alcd_c is the address of the LCD control register, that is
0x0010.
- Alcd_d is the address of the LCD data register, that is
0x0014.
- Clcd_page is a constant with the value 0xb0 used to set the
page
- 0x0014 is a constant used to move to the first column, that
is 0x40
(0x00: set lower nibble to 0; 0x14: set higher nibble to 4)
Reading LCD contents
We have said before that normally we won't want to read the LCD contents, as
we have used a intermediate buffer to write them, so we already have the the
contents of the display. Anyway it's rather simple, so for the sake of
completeness I'll describe it here too ;-).
Reading the LCD contents is very similar to writing to screen, as the first
thing you have to do is setting the page to read and the column using the
control register.
Then you have to do a dummy read from the data port (you read one byte from
the data port and discard the contents). Finally, subsequent read operations
provides us with the contents of the LCD controller memory.
Tips
Synchronizing with the vertical retrace
Well, it doesn't seem to have what I understand for vertical retrace, but
there is something similar. The LCD have 64 lines, named in the documentation as
COM0..COM63. The CPUport4 (?) has a bit that is set when the display is
processing COM63, that is, the last line, cero otherwise. This register is
located in address 0xFFD4, and the bit to look is b6.
Using the internal RAM of the microprocessor
The onHand/Ruputer has the following memory:
Description |
Address |
1kB microprocessor embedded RAM |
0xf000-0xf3ff |
16kB microprocessor embedded ROM |
0x80000-0x83FFF |
128kB external SRAM |
0x1000000-0x11FFFF |
512kB external MROM |
0x200000-0x27FFFF |
Apart of this, of course, it has the external Flash memory that it uses as
secondary storage medium (e.g. hard disk).
Normally, user programs are confinated to the last 64kB of external RAM, but
in practice there is some free space left in the much-faster internal RAM.
The last 384 bytes of the internal RAM are free (0xf280-0xf3ff) and we can
copy a routine to that memory and execute directly from internal RAM. Executing
from internal RAM is very, very fast compared to SRAM; approximately 4 times
faster, so it's the right place to put the sample code explained above that
transfer the buffer to LCD.
Transforming the crisp b/w LCD display into a flashing 4-gray LCD
This is a trick that has been used since the early days of computing... if
you bit-blit some pixel from white to black very fast it appears gray, its
intensity being funtion of the time it was black over the time it was white.
In the wallcrush game this is used to obtain 4 shades of gray. The method is
rather simple, but one have to be careful in the coding.
Basically:
- The 4-shade rendering engine is operating all the time, hooked to the
64-hz interrupt
- Every time a 64-hz interrupt is triggered, it can change the image that is
being displayed in the LCD. The simplest way is two cicles display the high
order image and one cicle display the low order one, then repeat. This way
there are two buffers of the entire screen: high order (its displayed 2/3 of
the time) and low order (it's displayed 1/3 of the time).
- There have to be an API to change simultaneously both images; this can be
done by exchanging pointers to the new images.
Information from SED1560 manual, and various code
examples (wallcrush gamesources, http://sygnas.tv/ruputer.htm). Copyleft by dario@softhome.net
This text is distributed under the GNU FDL. Last updated (dd/mm/yyyy):
21/10/2001
|