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