Dave's STM32 Page
Notes on using a 128 x 64 LCD
The
Blog for this project
After choosing a 128x64 LCD display, there
were several challenges. I couldn't find STM32 code for the KS0108
so decided to roll my own. As a starting point I used a combination
of AVR code I found on-line, a 5x7 font, also found, and my old
Bresneham's line and circle functions.. It is important to totally
understand the GPIO controls for the processor first, so I wrote a
handful of tests to set bits, set the port data direction, etc. I do
like the STM32 I/O registers and the fact that they can still use
the "PORTC->REG = 0x42" coding style This approach gives you full
access to all the ports and all the registers for each port. It is
very powerful and never got in the way at all. It allows you to
easily define which ports and bits you are using, making changes
simple.
I'm using the Newhaven NHD-12864WG-BTFH-V#N
LCD. I like the .43mm dot pitch: not too big, not too small. And
that it is 5V but operates with 3.3V logic (see below). I also like
the $25 qty. 1 price.
Most challenges were met by RTFM (Reading The Manual). You really
need to read and understand the KS0108 data sheet and the registers
of the STM32.
Chip Select Polarity
These 128 x 64 displays mostly use the KS0108 / KS0107 controllers.
But the KS0108 can only control 64x64 dots, so 2 controllers are
used. The panels typically bring out one chip select (CS) for each
controller. The KS0108 has both active high and active low chip
selects, so the CS polarity is a function of the panel, not the
chip: the LCD panel manufacturer makes the decision. Unfortunately
there is no standard here. Some manufacturers don't specify the
polarity on their sparse data sheets. Newhaven specified it but got
it wrong for the panel I chose. The data sheet says CS 1 and 2 are
active high to select the chip. They are active low. That cost me a
few debug hours.
Newhaven didn't specify the RST polarity either. The KS0108 data
sheet says it is low for reset. Unless the LCD manufacturer has
logic to invert RST it will be reset low, operate high. I found that
just tying RST high was fine. But I haven't exhaustively tested this
under varying power supply conditions, partial brownout, etc. the
real test for a reset circuit.
5V CMOS vs TTL levels
This issues is critical when you use 3.3V logic to drive a 5V LCD.
In order to do this the LCD Vih must tolerate 3.3V levels. On read
cycles, the processor data pins must tolerate 5V logic inputs. The
KS0108B chip has TTL input levels and 5V CMOS output levels on the
data bus pins. Again, some LCDs that use this chip have ambiguous
specs. They say ViH must be 0.7 * VDD or 3.5V at 5V VDD (higher at
5.25V). 3.3V logic can't meet this. But the KS0108B has Vih = 2.0V
min, so no problem driving the LCD with 3.3V logic.
Data Reads
During reads, the KS0108 drives the processor input pins with 5V
CMOS logic. Some 3.3V processors cannot tolerate 5V. but the STM32
can, so long as you don't have the pull-up or pull-down resistors
enabled. With a non-5V tolerant part, you either need to level
translate or limit the voltage with eight resistor and schottky
diodes, eight FETs... Or find a 3.3V compatible LCD.
From the KS0108 data sheet:
" 3. Output register
Output register stores the data temporarily from display data RAM
when CS1B, CS2B, CS3 is in active mode and R/W and RS=H, stored data
in display data RAM is latched in output register. When CS1B to CS3
is in active mode and R/W=H, RS=L, status data (busy check) can read
out.To read the contents of display data RAM, twice access of read
instruction is needed. In first access, data in display data RAM is
latched into output register. In second access, MPU can read data
which is latched. That is, to read the data in display data RAM, it
needs dummy read. But status read is not needed dummy read."
putpix()
The ability to set a single pixel on the display is fundamental to
doing graphics. With the KS0108, this operation is quite cumbersome,
meaning complicated and time consuming. Good thing I have lots of
fast processor cycles. putpix(x,y,val) sets one pixel. Sounds
simple, but the pseudo-code to write one pixel on the KS0108 is
something like this:
Set X address (x & 0x3F)
Set
bus direction OUT
Set
RW, RS, both CS
Set
data
Pulse
E
E= 1
Delay 500nS
E = 0
Delay(5)
Set
Y page (y >> 3)
Set
data
Pulse
E
Delay(3us)
Pixel
mask
(1 >> y%7)
Read
dummy
data
Set
bus direction IN
Set
RW, RS
Select
L or R chip based on X>63
Pulse
E
Delay(5)
Read
real
data
E
= 1
Delay(1)
Input
data
E
= 0
Delay(3us)
Re-set
X
address (x & 0x3F) since the last read incremented it
Set
bus direction OUT
Set
RW, RS, both CS
Set
data
Pulse
E
Delay(3us)
Merge
the
mask and the read data (mask | data)
Write
data
Set
bus direction OUT
Set
RW, RS
Select
L or R chip based on X>63
Pulse
E
Delay(3us)
Whew! The Delay(3us) are there to avoid needing a wait for
the busy flag. The Delay in the Pulse E is to time the E pulses to
.5uS.
Another approach is to manage graphics in a block of CPU memory and
then transfer the block of CPU memory to the LCD after the drawing
is complete. This is more efficient but adds a bit of complexity. It
is much faster to set a single pixel in CPU RAM. The data transfer
uses writes only and can take advantage of the auto-increment of the
LCD X address register. A full screen takes only 128 X 64 / 8 = 1KB
of RAM. My processor has 8KB which is reasonable. One reason I don't
like this approach is that it is not as convenient for larger LCD's
and I'd like my code to be scalable to larger displays where
possible. This processor only has 8K of RAM, not enough for one
buffer of a 320x240 monochrome display (9.4 KB), never mind a color
TFT or higher res LCD. As far as the software differences between
managing a display in RAM vs in the controller, it wouldn't be that
hard to insert an lcd_update() to move the data from RAM to the LCD
every so often.
Other KS0108 Gotchas
The Samsung data sheet calls the horizontal axis Y and the vertical
axis X. This is backwards for me and for most of the world.
Data reads require a 'dummy' read first. That adds another slow
cycle to every read.
Data reads and writes cause the X (their Y) register to increment.
This is handy in some cases but it interferes with read-modify-write
cycles (Like PutPix). Also if you are incrementing between pixel 63
and 64, you need to set the Y register anyway. So a software test is
needed for this. But it is faster to do this test in software than
to set the X register every single time.
Pros and Cons
The pros and cons of 128x64 LCDs:
- + Lots of panels from lots of manufacturers
- + Reasonable cost, good availability: $20-30 qty1
- + Low power and small
- + Many use the KS0108B, so software compatibility across
manufacturers
- -
Lots of variations in CS levels, pinouts, sizes, backlights,
etc.
- -
Vertical byte orientation is inconvenient for writing images
- -
Ties up 8 + 5 = 13 I/O pins.
- + Electrically similar interface to alphanumeric LCDs
- + Can be driven from 3V or 5V logic
- + Single +5V power supply
- + Breadboard-friendly .1" headers
- - 20 pin .1" cable is not off-the-shelf, requires labor
to crimp 20 pins.
- -
Requires 5V-tolerant I/O
- + Not many pixels to draw, so fast.
- -
Very slow to draw individual pixels
- -
Not great resolution, no color or greyscale. Looks like it's
from the 80's. You can see the individual pixels on fonts and
lines.
- -
Fonts need to be multiples of 8 pixels tall including spaces, or
else need to be drawn one dot at a time.
The
Blog for this project
Back to
STM32 Page
Multi-Zone
Preamp Page
Main Page
BoatBus and AVR Projects
Last Updated:
2/17/2012