84PCSE:LCD Controller
Contents
- 1 Quick Specs
- 2 Overview
- 3 Register List
- 3.1 00: Driver Code
- 3.2 01: Driver Output Control 1
- 3.3 02: LCD Driving Control
- 3.4 03: Entry Mode
- 3.5 05: 16-bit Data Format Selection
- 3.6 07: Display Control 1
- 3.7 08: Display Control 2
- 3.8 09: Display Control 3
- 3.9 0A: Display Control 4
- 3.10 0C: RGB Display Interface Control 1
- 3.11 0D: Frame Maker Position
- 3.12 0F: RGB Display Interface Control 2
- 3.13 10: Power Control 1
- 3.14 11: Power Control 2
- 3.15 12: Power Control 3
- 3.16 13: Power Control 4
- 3.17 20: Cursor Row
- 3.18 21: Cursor Column
- 3.19 22: GRAM
- 3.20 29: Power Control 7
- 3.21 2B: Frame Rate and Color Control
- 3.22 30-3D: Gamma Control
- 3.23 50: Window Horizontal Address Start
- 3.24 51: Window Horizontal Address End
- 3.25 52: Window Vertical Address Start
- 3.26 53: Window Vertical Address End
- 3.27 60: Gate Scan Control
- 3.28 61: Base Image Display Control
- 3.29 6A: Vertical Scroll Control
- 3.30 80: Partial Image 1 Display Position
- 3.31 81: Partial Image 1 Start Line
- 3.32 82: Partial Image 1 End Line
- 3.33 83: Partial Image 2 Display Position
- 3.34 84: Partial Image 2 Start Line
- 3.35 85: Partial Image 2 End Line
- 3.36 90: Panel Interface Control 1
- 3.37 92: Panel Interface Control 2
- 3.38 95: Panel Interface Control 4
- 3.39 97: Panel Interface Control 5
Quick Specs
- ILI9335
- TFT color LCD
- Supports 8 and 16-bit interfaces
- 172,800 bytes internal RAM
- 76,800 pixels
- Power-saving 8-color mode
- 262,144 = 2^18 = 6x6x6 colors
- Data sheet: http://www.displayfuture.com/Display/datasheet/controller/ILI9335.pdf
Overview
Like the old LCD controller, the new color controller is controlled by ports 10h and 11h. The LCD controller wants 16- or 18-bit data, but the Z80 only does 8-bit I/O, so each read or write takes TWO operations. The controller expects them to be in big-endian order, i.e. to output 1234h, you write 12h first, then write 34h to the SAME port. Writes to port 10h set the current "register". You need to send 16-bits to 10h at a time, even though there are no registers above 0FFh; every time you set the current register, send a dummy zero first, or alternatively, send the same byte twice. Reading 10h probably returns some kind of status information (more information needed). Reading and writing to 11h reads or writes to or from a register.
Therefore, to send the LCD a command, you first send two bytes to port 10h to set the current register. Then, you send two bytes to write the data. Similarly, to read, write the register number to 10h, and then read twice from 11h. You should be able to read-modify-write without resending the register number.
To send graphics to the LCD, set the column and row address registers, and then send the data serially to register #22h. You do not need to write 00 22h to port 10h after every byte.
NOTA BENE: IMPORTANT TERMINOLOGY:
In this document, the word "cursor" refers to the LCD controller's current reading or writing location on the screen; that is, the current row and column set by registers 20h and 21h.
(For those following along with the data sheet: Like before, the X/Y plane is flipped in the data sheet documentation. Specifically, the the screen is rotated 90 degrees from the way the manufacturer expects, so "horizontal" and "vertical" refer to the OTHER, i.e. horizontal means up and down on the screen. Also, "up" and "down" are switched with "left" and "right". Also, the auto-increment behavior in hardware is rotated 90 degrees clockwise from the register 0x03 diagram. It also suggests that the manufacturer expects the screen to be in landscape mode, which is wrong.)
To resolve potential CONFUSION about the meaning of the words "horizontal", "vertical", "up", "down", "left", "right", "X", and "Y", (see above paragraph) this document will use the terms "row" and "Y" to refer to the up/down direction positioning of the cursor on the actual calculator; similarly, "column" and "X" refer to the left/right axis. Additionally, as is standard for computer screens, the X=0 position is at the left side, and X+ is pointing to the right; and moreover, Y=0 is at the top, and Y+ points DOWN.
READ THE ABOVE OR YOU WILL HAVE BUGS!
Like the old B&W LCD controller, this one has an internal cursor (the data sheet calls it the GRAM address) that determines where data written or read goes. Unlike the old controller, setting the row register will cause the column pointer to reset to the last value written, and vice versa. For example, if you set the row to 1, the column to 2, write a pixel so the column is now 3, and then set the row to 5, the column will not remain at 3, but revert to 2. (If you then set the column to 10, the row remains at 5, because 5 is the last value you wrote.)
So, port 10h:
- Writing sets the index for the IR register
- Reading reads an internal status code
- Write four zeros to sync for multibyte transfers
Port 11h:
- Writing sets a control register value or writes to GRAM (auto-buffered to WRD)
- Reading reads from GRAM through the buffered RDR register (so a dummy read (16-bits!) is required before the data are valid, just like before)
TI always uses the 16-bit color mode. They also always seem to set BGR color order, even though the color data actually has red as the high bits, and blue as the low bits. (Perhaps it's "BGR" going form low-to-high bits, even though we write bits high-to-low.)
If you read the data sheet, the interface mode is the I80 8-bit mode.
Windows
To make life a little less terrible, the LCD controller supports setting a "window" into which the cursor is confined. In this window, if moving to the next pixel---whichever direction that may be---would move the cursor outside the bounds of the window, the cursor will instead move to the start of the next appropriate row or column, as determined by the entry mode, eventually wrapping back to the start of the window. This makes it easier to write sprites and do tiny animations. Windowing is always active, so it's something you must keep track of. Furthermore, you must set the cursor to inside the window when you change it, or else the screen will go totally wonky and display garbage when you try to write pixels to it.
Partial Image Mode
This has the potential to be quite useful. In particular, it allows a hacked 160x240 mode in which each pixel is twice as wide as normal. Somebody should probably add more information on this.
Panic Mode
If you do something the LCD controller finds particularly adverse (like set the cursor to be outside of the window bounds and try to write pixels), the LCD controller will display garbage lines everywhere. It will not operate normally again until you perform the power-off and power-on sequences.
Power Control
The B&W screen can be initialized with just half-a-dozen writes. The color screen is much more complicated. Power-on and power-off both require many writes with minimum wait times.
Be aware! The LCD controller is not connected to the LCD backlight controller. They are separate hardware, and operate independently. The LCD controller can be on without the backlight being on (you can't see anything except if you shine a very, very bright light directly on the screen), and the backlight can be on with LCD controller off. Port 3A controls the LCD backlight (among other things).
Power On
Key: shows the specific values TI gives to fields, check the documentation for detail. Binary: (- means zero & field is not defined) 54321098 76543210 Port Value Purpose On hard boot: 07 0000 Reset Disp.Ctrl.1: LCD scanning, command processing off 10 07F1 Reset Pwr.Ctrl.1: Start RC oscillator, set voltages ---0-111 1111--01 Device soft-power on: 54321098 76543210 01 0000 Reset Out.Ctrl.1: Ensure scan directions are not reversed 02 0200 LCD Driving Control: Sets inversion mode=line inversion and ------10 -------- disables it 03 1038 Init. Entry Mode: Cursor moves up/down, down, left, disable 00-1---- 0-111--- auto-origin set for windows, BGR order, 16-bit color 08 0202 Set front & back porches: 2 blank lines top & bottom ----0010 ----0010 09 0000 Reset Disp.Ctrl.3: Resets scanning stuff and off-screen voltage 0A 0000 Disp.Ctrl.4: No FMARK 0C 0000 RGB Disp.: Off 0D 0000 FMARK position: Off 60 2700 Driver Output Ctrl. 2 ??100111 00000000 61 0001 Base Image Display Ctrl: Use color inversion, no vertical scroll, reset voltage in non-display level 6A 0000 Reset Vertical Scroll Ctrl. WAIT A WHILE (40 ms is good) 10 1190 Init Pwr.Ctrl.1: Exit standby, fiddle with voltages, enable ---1-001 1001--00 voltage booster 11 0227 Pwr.Ctrl.2: Configure voltages -----010 -010-111 WAIT A WHILE 12 008C Pwr.Ctrl.3: More voltages -------- 1--01100 WAIT A WHILE 13 1800 Pwr.Ctrl.4: Take a wild guess ---11000 -------- 29 0030 Pwr.Ctrl.7: I'm not an LCD engineer, don't ask me. -------- --110000 2B 000B Set frame rate to 70 -------- ----1011 WAIT A WHILE 30 0000 Gamma Control 1: I really have idea about these. Touching them may or may not make things explode. 31 0305 Gamma Control 2 32 0002 Gamma Control 3 35 0301 Gamma Control 4 36 0004 Gamma Control 5 37 0507 Gamma Control 6 38 0204 Gamma Control 7 39 0707 Gamma Control 8 3C 0103 Gamma Control 9 3D 0004 Gamma Control 10 50 0000 Horiz.Win.Start: 0 51 00EF Horiz.Win.End: 239 = 240-1 52 0000 Vert.Win.Start: 0 53 013F Vert.Win.End: 319 = 320-1 WAIT A WHILE 07 0133 Disp.Ctrl.1: LCD scan & light on, ready to enter standby --00---1 --110-11 No partial image
Power Off
Powering down the LCD controller is a lot easier. Just follow this sequence.
- Write 0 to register 7 (lrDispCtrl1)
- Wait
- Write 07F0 to 10h (lrPwrCtrl)
- Wait
- Write 07F1 to 10h
Register List
This is a list of all the LCD's registers, what each bit does (if anything), and the values the OS expects for normal operation, so you can hopefully return the screen to normal after you're done screwing things up.
You should probably not screw with the power and scanning control registers. The screen might catch on fire, or cause the screen to fade over time, or just stop working. Remember, some of said registers directly control the internal voltages used in the controller.
00: Driver Code
Reads 9335h
01: Driver Output Control 1
Default: 0000h
Bit | Default | Description |
8 | 0 | Set to reverse row scan direction (i.e. upside-down mode) |
10 | 0 | Set for interlaced output |
02: LCD Driving Control
Default: 0200h
Bit | Default | Description |
8 | 0 | EOR: Set with B/C = 1 to set line inversion |
9 | 1 | B/C: 0 = Frame/Field inversion, 1 = lin inversion |
Comments: This seems to have no effect?
03: Entry Mode
Default: 1038h
Bit | Default | Description |
3 | 1 | AM: Cursor direction. Set = L/R, reset = U/D. After every pixel, the cursor moves either U/D or L/R.
If set to L/R (1), after every pixel the cursor moves left (bit 5=0) or right (b5=1). At the end of the row, the cursor moves up (b4=0) or down (b4=1). If AM is set to U/D, after every pixel, the cursor moves up (b4=0) or down (b4=1). At the end of each column, the cursor moves left (b5=0) or right (b5=1). At the end of every row or column, the cursor resets to the start of the next line, where ever the current window setting puts it. |
4 | 1 | Vertical increment/decrement: Set = increment |
5 | 1 | Horizontal increment/decrement: Set = increment |
7 | 0 | ORG: The controller's wording suggests that if this is set, then the cursor seeks to the corner of the window when the window is set, but this appears to be wrong? |
12 | 1 | BGR: If this is set, the "red" and "blue" channels are swapped both when writing pixels to GRAM, and when reading pixels from GRAM. Note that this doesn't affect the appearance of existing pixels. |
14 | 0 | TRI: If set, 3 writes are required for every pixel (of which 18 bits are used, allowing up to 218 distinct colors to be displayed.) Note that unlike the BGR bit, TRI only affects output operations, not input operations. |
15 | 0 | DFM: If reset, the 3 writes are packed.
If set, the 3 writes are unpacked. (That is, write 1 byte red, 1 byte green, and finally 1 byte blue, or reverse for BGR.) |
The display has three color modes:
TRI | DFM | Transfer Mode |
0 | any | 16-bit color, packed values, MSB first (big endian) |
1 | 0 | 18-bit color, packed values, R[5:4] low bits of first transfer |
1 | 1 | 18-bit color, unpacked values, uses high 6 bits, low two bits
ignored |
For example, to draw an orange pixel (R=100%, G=50%, B=0%) in TRI=0/BGR=1 mode, you would write 11111011b, 11100000b. In TRI=1/DFM=0/BGR=1 mode, you would write 00000011b, 11110111b, 11000000b. In TRI=1/DFM=1/BGR=1 mode, you would write 11111100b, 01111100b, 00000000b.
05: 16-bit Data Format Selection
The ILI9335 documentation is wrong about this register. It claims that it controls how the least-significant bits of the red and blue channels are determined when TRI=0. Experiments, however, have shown that the mode described as "EPF=10" is always used, regardless of the value of R05. In this mode, the most significant bit is copied into the least significant bit - or in other words, the input values are multiplied by 63/31 and rounded to the nearest integer.
(For reference, the documentation claims that mode 00 sets the least significant bits to 0; mode 01 sets the least significant bits to 1; mode 10 does as described above; and mode 11 does something not-completely-explained based on whether the red and blue values are equal.)
If this register has any effect, it's unknown.
07: Display Control 1
Default: 0133h
Bit | Default | Description |
0 | 1 | D0: Turn off scanning?? |
1 | 1 | D1: Turn off LCD?? |
3 | 0 | CL: Set for 8-colors mode |
4 | 1 | DTE: Set for normal operation |
5 | 1 | GON: Set for normal operation |
8 | 1 | BASEE: Set to keep LCD controller active even in standby/sleep |
12 | 0 | PTDE0: Set to enable partial image 1 |
13 | 0 | PTDE1: Set to enable partial image 2 |
08: Display Control 2
Default: 0202h
You probably shouldn't muck with this field.
Bit | Default | Description |
3:0 | 2 | BP: Number of lines to skip after after VSYNC |
11:8 | 2 | FP: Number of lines to skip after finishing LCD scan |
Neither may be set to 0, 1, or more than 128, and must total less than or equal to 256.
09: Display Control 3
Default: 0000h
You probably shouldn't muck with this field.
Bit | Default | Description |
3:0 | 0 | ISC: Scan cycle period = ISC*2-1 frames |
4 | 0 | PTG0: Do not set this bit |
5 | 0 | PTG1: Set for interval scan |
10:8 | 0 | PTS: Output voltage when scanning in non-display area |
0A: Display Control 4
Default: 0000h
Probably useless to us
Bit | Default | Description |
2:0 | 0 | FMARK interval, valid values are 0, 1, 3, 5 |
3 | 0 | MKARKOE: Enables FMARK |
0C: RGB Display Interface Control 1
Default: 0000h
Probably useless to us
Bit | Default | Description |
1:0 | 0 | RIM |
5:4 | 0 | DM |
8 | 0 | RM |
14:12 | 0 | ENC |
0D: Frame Maker Position
Default: 0000h
Probably useless to us
Bit | Default | Description |
8:0 | 0 | FMP: Sets when the FMARK pulse is output |
0F: RGB Display Interface Control 2
Default: 0000h
Probably useless to us, TI doesn't initalize it
Bit | Default | Description |
0 | DPL | |
1 | EPL | |
3 | HSPL | |
4 | VSPL |
10: Power Control 1
Default: 1190h
You probably shouldn't muck with this field.
Bit | Default | Description |
0 | 0 | STB: Set=sleep mode (RC oscillator still active) |
1 | 0 | SLP: Set=standby mode (GRAM preserved)
In STB or SLP, no commands except exit STB or SLP are accepted |
6:4 | 1 | AP: OP amp adjust |
7 | 1 | APE: Set to enable power supply startup |
10:8 | 1 | BT: Voltage step-up adjust |
12 | 1 | SAP: Set=source driver enabled, boot with this=0 then set to 1
after LCD power supply is active |
11: Power Control 2
Default: 0227h
You probably shouldn't muck with this field.
Bit | Default | Description |
2:0 | VC | |
6:4 | DC0 | |
10:8 | DC1 |
12: Power Control 3
Default: 008Ch
You probably shouldn't muck with this field.
Bit | Default | Description |
3:0 | VRH | |
4 | PON | |
7 | VCIRE |
13: Power Control 4
Default: 1800h
You probably shouldn't muck with this field.
Bit | Default | Description |
12:8 | VDV |
20: Cursor Row
The datasheet calls this the "Horizontal GRAM Address" , but it sets the up/down position of the cursor because the display is on its side.
21: Cursor Column
Sets the left/right position of the cursor. NOTA BENE: Setting one register will cause the other to revert to its previous value; see Overview, above.
22: GRAM
This is the register that you use to actually send and read pixels.
When reading, a dummy read is required before a cursor change takes effect; i.e., after writing 20 and 21, do a 16-bit dummy read before saving the actual data.
Reading does not appear to update the cursor, so you can do a read-modify-write type operation, which might be useful for masking or implementing gratuitous transparency effects.
29: Power Control 7
Default: 0030h
You probably shouldn't muck with this field.
Bit | Default | Description |
5:0 | VCM |
2B: Frame Rate and Color Control
Default: 0000Bh
Bit | Default | Description |
3:0 | 0Bh | Frame rates, 0-15: 31, 33, 34, 36, 39, 41, 44, 48, 52, 57, 62,
69, 78, 89, undefined, undefined |
30-3D: Gamma Control
You probably shouldn't muck with these fields.
Default values:
Register | Value | Description |
30 | 0000 | Gamma Control 1 |
31 | 0305 | Gamma Control 2 |
32 | 0002 | Gamma Control 3 |
35 | 0301 | Gamma Control 4 |
36 | 0004 | Gamma Control 5 |
37 | 0507 | Gamma Control 6 |
38 | 0204 | Gamma Control 7 |
39 | 0707 | Gamma Control 8 |
3C | 0103 | Gamma Control 9 |
3D | 0004 | Gamma Control 10 |
50: Window Horizontal Address Start
Default: 0000h
Defines leftmost position of window, inclusive. Remember that it's the actually the top of the window on the calculator.
51: Window Horizontal Address End
Default: 00EFh
Exactly what you think. This is inclusive, like port 50, so if your sprite starts on column 0 and is 10 pixels wide, do not add 10 to 0 to get 10. The number you want is 9.
52: Window Vertical Address Start
Default: 0000h
53: Window Vertical Address End
Default: 013Fh
60: Gate Scan Control
Default: 2700
Bit | Default | Description |
5:0 | 0 | SCN: Sets the gate line from which the gate driver starts to scan. |
13:8 | 27h | NL: Sets the number of lines to drive the LCD at an interval of 8 lines. In other words, it tells the LCD controller how big the screen really is. |
15 | 0 | GS: Gate scan direction. Setting this will cause left/right mirroring. |
61: Base Image Display Control
Default: 0001h
Bit | Default | Description |
0 | 1 | REV: Set=enable grayscale inversion |
1 | 0 | VLE: Vertical scroll enable. |
2 | 0 | NDL: Sets the output level in the non-display area |
6A: Vertical Scroll Control
Default: 0000
Because the LCD is rotated, this actually scrolls horizontally.
Partial image display is not affected by this.
Bit | Default | Description |
8:0 | 0000 | Sets the line to start displaying from. |
80: Partial Image 1 Display Position
81: Partial Image 1 Start Line
82: Partial Image 1 End Line
83: Partial Image 2 Display Position
84: Partial Image 2 Start Line
85: Partial Image 2 End Line
90: Panel Interface Control 1
Default: 0000
92: Panel Interface Control 2
Default: 0600h
No, I don't know what happened to Panel Interface Control 3. It's totally missing from the datasheet.
95: Panel Interface Control 4
Default: 0200
97: Panel Interface Control 5
Default: 0C00