ST7920 Interface Question

I have uploaded a new beta for u8glib (v0.11): Google Code Archive - Long-term storage for Google Code Project Hosting.

  • updated memory model for the st7920 128x64 mode
  • SPI transfer for st7920
    I did not do any tests on it (hw not yet availabe). I only know that it compiles.
    Also, i did not do any speed optimization.
    Oliver

So I got my ST7920 LCD display in serial mode working again. I'm drawing a couple of circles and a straight line on the display, and writing 6 lines of proportionally-spaced text to it, most of which cover almost the full width of the display. Each iteration (which includes a refresh of almost the entire display) along with a few calculations takes less than 57ms.

So the limiting FPS with my driver appears to be above 17.5 fps.

  1. I managed to put my NHD-19232WG-BTMI-V#T into serial mode
  2. U8glib is up and running in SPI and parallel mode for the ST7920
  3. New download v0.12: Fixed memory mapping, improved speed for ST7920 SPI
  4. Fixed an issue with the ST7920 128x64 memory mapping
  5. Refresh rate: About 13 FPS (several lines, bitmaps and some text)
    Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

in my case it was a question of EN timing.

I started looking at whats going on through my logic analyzer. I've now crushed the EN toggle period to 4microseconds = 244 theoretical frames per second.

Time to start slowing the code down. I think I'll have to eat my words about the 7920 :blush:

To be able to compare FPS numbers,
I think it would it make sense to define some reproducible "FPS" operations
that represent what is done on each "frame".

That way we can actually compare equivalent operations across libraries and glcd modules.

How about any of these or even some combination of multiple ones.

a) render a full display bitmap
b) clear the display (might be done in s/w or by the module itself)
c) turning on all pixels, one pixel at a time.
(might even want to do two of these as painting horizontally might be different than vertically)
d) render a full display of text in a natural font size like 6x8 or 8x8
(maybe pick a single character like '@' so that everyone is rendering the same character).

I think it would be very interesting to be able to really compare between
libraries, glcd modules, and even different interface modes on the same module.

It would be pretty simple to do a or a and b together to offer at least one FPS data point
that could be compared.

--- bill

Good idea. The display size should be mentioned. Maybe the FPS should be scaled to a virtual 64x64 display:
If mFPS is the measured FPS rate and w and h are the display dimensions, then a comparable, size independent iFPS might be

iFPS = mFPS * 64 * 64 / (w * h)

Oliver

Ok, the results are in.

ST7920 - 25.6 frames per second in constant clear screen operation (toggle between B&W by writing whole screen to GRAM)

Soooo ... it is not a bad display after all, and in the morning I was like it ain't ever gonna work :grin:

Edit: Pinout Screen to Arduino Nano 328 in case someone wants to try it out
No guarantees ! Use on your own risk !

VSS -> GND
VDD -> +5
V0 -> NC
RS -> pin A0
RW -> pin A1
E -> pin A2
D0...D3 -> pin 8-11
D4...D7 -> pin 4-7
PSB -> high (Parallel / Serial bus select)
RST -> high (reset)
VOUT -> NC
BLA -> +5
BLK -> GND via 200 ohm resistor

Measured with logic analyzer and done with parallel interface and the following code:

#include <avr/io.h>
#include <util/delay.h>

#define LCD_ON				0x0C
#define LCD_OFF				0x08
#define LCD_SET_PAGE		        0x80 // X-address 
#define LCD_SET_ADD			0x80 // y-address 
#define LCD_RAM_ADDRESS_MODE		0x02
#define LCD_FUNCTION_SET_EXT		0x36
#define LCD_FUNCTION_SET_BASIC		0x30
#define LCD_CURSOR_CONTROL_SET		0x18
#define LCD_DISP_CLEAR		        0x01
#define LCD_ENTRY_MODE_SET	        0x06 // Display cursor shift left to right, page shift scroll down

#define DI           14 // same as RS, PORT C, bit 0
#define RW           15 // PORT c, bit 1
#define EN           16 // PORT c, bit2
// RESET ... straight to high

void setup() {
  Serial.begin(9600);  
  DDRD = DDRD | B11110000; // pins d7-d4 to output
  DDRB = DDRB | B1111; // pins d8 to d11 to output 
  DDRC = DDRC | B111; // pins A0 to A2 to output
  digitalWrite(DI, LOW);
  initlcd();
}

void initlcd(void) {
  delay(50);
  WriteCommand(LCD_FUNCTION_SET_BASIC);
  _delay_us(100);  
   WriteCommand(LCD_FUNCTION_SET_EXT);
  _delay_us(100);   
  WriteCommand(LCD_ON);
  _delay_us(100); 
  WriteCommand(LCD_DISP_CLEAR);
  delay(50);  
  WriteCommand(LCD_ENTRY_MODE_SET);
}

void WriteCommand(byte cmd)
{
  PORTC = B100; // EN | RW | DI 
  _delay_us(7);
  lcdDataOut(cmd);
  _delay_us(10);
  PORTC = B000; // EN | RW | DI
  _delay_us(30);
}

void WriteData(byte data) {
  PORTC = B101; // EN | RW | DI  
  _delay_us(3);
  lcdDataOut(data);				
  _delay_us(5);
  PORTC = B001; // EN | RW | DI 
  _delay_us(25);
}

void lcdDataOut(byte data) {  
  byte dataD = data & B11110000; //bits 7 to 4 for pins 4-7
  byte dataB = data & B1111; //bits 3 to 0 for pins 8-11 
  PORTB &= B11110000;
  PORTB |= dataB; //
  PORTD &= B00001111;  
  PORTD |= dataD; //lower nibble of 8 bits
}

void loop() {
        for (int i = 0; i < 32; i++) {
        WriteCommand(LCD_SET_PAGE | i); 
        WriteCommand(LCD_SET_ADD);
          for (int j =0; j < 16 ; j++) {
              WriteData(0xFF);
              WriteData(0xFF);
          }
        }
        for (int i = 0; i < 32; i++) {
        WriteCommand(LCD_SET_PAGE | i); 
        WriteCommand(LCD_SET_ADD);
        for (int j =0; j < 16 ; j++) {
          WriteData(0x00);
          WriteData(0x00);
        }
       }
}

Hi all, have just done a bit of testing on my library, anybody else having some problems with the display being to slow?

I'm controlling the display via shift registers and animation is too fast for the screen to fully illuminate its pixels. In fact without a delay the pixels barley change colour.

Has anybody suffered this same fate ( need faster screen, to keep up with arduino ) or is it due to contrast. I have a POT connected to 5v and GND with the wiper going to backlight anode. What is the proper way to do contrast on these displays as this just dims the backlight. Pixels to backlight contrast is still equal.

The only Identifiying marks my screen has is 'HJ12864ZW' and the datasheet is entirely in chinese, So I have had to use the generic ST7920 datasheet.

BTW: my screen is a blue screen with white pixels. Anyone with pictures of the ST7920 rendering an animated sprite?

And also, is the power supply speed ( arduino 5v ) a possible culprit ( not enough juice to quickly illuminate pixels ). would a bypass capacitor help accross the Vdd - Vss kind of like IC decoupling?

olikraus:
Good idea. The display size should be mentioned. Maybe the FPS should be scaled to a virtual 64x64 display:
If mFPS is the measured FPS rate and w and h are the display dimensions, then a comparable, size independent iFPS might be

iFPS = mFPS * 64 * 64 / (w * h)

Oliver

ooooo. I really like that.
But I think the math is flipped?
Shouldn't it be
iFPS = mFPS * (wh) / 6464

I think the "virtual" 64x64 display FPS rate should be double the measured rate with a 128x64 display right?

This would be useful even for some of the sed1520 displays the glcd library supports
that are 120x32 or 122x32

While things don't scale exactly linearly for different sizes,
it is about as good as it gets for comparisons of dissimilar displays.

--- bill

Oh, yes, thanks for the correction.

Oliver

Ok, so the FPS and iFPS (64x64) got me really curious.
I went and tested the glcd library on a ks0108 just to see how it compared
to the ST7920.
(I wrote a nifty little iFPS sketch that does the calculations)

With glcd on a 128x64 ks0108 using a clearscreen FPS test:
FPS = 79.08
iFPS = 158.16

glcd was using 8 bit direct port i/o driving all the glcd lines
(using nibbles on two ports vs 8 bits on single port slowed it down by 8 FPS)
glcd also uses delays with more accurate timing to match glcd spec timing
like Tas and Tdsw rather than using longer delays using <util/delay.h>
<util/delay.h> has many issues in its delay cycle calculations.
If you don't have the very latest AVRlibC you can get delays
that are many times longer or shorter than you ask for depending
on what you ask for and the F_CPU value.
This effect is worst at the low end like sub 3-5us which is where
these kinds of delays often are.

glcd uses Hans Hendriech's delay_x delay package instead.

So I think getting an FPS of 25.6 using much longer than needed timing delays
for control line setup, data hold times and strobe widths is actually quite good.

If the delays in WriteData() and WriteCommand() were
cut down closer to the spec, the fame rate would go up.

--- bill

bperrybap:
glcd also uses delays with more accurate timing to match glcd spec timing
like Tas and Tdsw rather than using longer delays using <util/delay.h>
<util/delay.h> has many issues in its delay cycle calculations.
...
If the delays in WriteData() and WriteCommand() were
cut down closer to the spec, the fame rate would go up.

Oops. I was looking at the datasheet a bit better this morning. The delays were indeed ns not us... oh well, that's a bit embarrassing. But its nice to know there is still easy room for improvement.

The purpose of the test was to see quickly whether this display is a completed dud. Now I'm confident something can be made of it, and getting rid of the crude delay is the next thing to do.

Can one of you please post a picture of it refreshing at or above 15 - 20 fps?
From 10 frames to 40 frames per second on my screen ( slowed with delays ), a 64x64 block is pretty much invisible as it scrolls across or down the screen.
Is anyone intending to use it for animation. I ask as I'm not sure weather it is my screen that is really slow or if all st7920 models are ( not the st7920 driver but actual display ).
Please see my post above...

Maybe I just need to purchase a green-black one as they might be faster ( mine is blue bg & white px ).

You're right, the liquid crystal in the display doesn't react fast enough for animation. I refresh the data on mine (while on blue) at 2 fps, because it takes around 0.5 sec for the display contrast to settle when the pixels change.

Bill, can you publish your code for the FPS measurement?
I would like to know how to calculate the overall FPS rate.

Thanks,
Oliver

Here are some results from u8glib:

ST7920_192X32, SPI: FPS: Box=7.6 @=9.8 iFPS: Box=11.4 @=14.7
ST7920_192X32, 8Bit: FPS: Box=6.2 @=7.5 iFPS: Box=9.3 @=11.2
DOGM128 SW SPI: FPS: Box=5.1 @=5.9 iFPS: Box=10.2 @=11.8
DOGM128 HW SPI: FPS: Box=5.5 @=6.3 iFPS: Box=11.0 @=12.6

The "Box" mode is what Bill has measured. I also added the @-draw test.
Not a surprise: U8glib is much slower. But it also supports write-only devices without the need of a full frame buffer.

Oliver

One of the things that glcd lib does, which is what makes the rendering code, especially for text
so complex is that it will avoid reads of display memory whenever possible.

For example, when rendering, it renders or paints pixels into a local 1 byte register
that is used as a 1 byte page buffer and then writes that byte to page memory.
Whenever the size of what is to be rendered is a multiple of the page size (8 pixels)
and aligns on a page boundary (8 pixels) then there will be no reads.

When clearing the screen, there are no reads from memory just writes to the glcd memory.
There will also be no reads from glcd/frame-buffer memory if rendering text that is 8, 16, 24, 32, ...
pixels in height that land on a vertical modulo 8 pixel boundary.
Nor would there be any reads from memory to render a bitmap that is a multiple of 8 pixels in height
and lands on a vertical module 8 pixel boundary.

While this is very fast and works great to eliminate reads, this rendering method only works
well for devices that use 8 pixel vertical pages. It also doesn't allow doing things like changing the x,y origin,
rotating the display orientation, or rotating the actual text.

In the big picture, once you get much beyond 4-5 FPS, it's pretty much ok since
the liquid crystal in the display often takes a while to change anyway.
The biggest thing is does the user notice any lag in the display being updated
or does it slow down the CPU to prevent it from getting its other tasks done.

--- bill

Bumping this topic.

pYro_65:
Has anybody suffered this same fate ( need faster screen, to keep up with arduino ) or is it due to contrast. I have a POT connected to 5v and GND with the wiper going to backlight anode. What is the proper way to do contrast on these displays as this just dims the backlight. Pixels to backlight contrast is still equal.

The only Identifiying marks my screen has is 'HJ12864ZW' and the datasheet is entirely in chinese, So I have had to use the generic ST7920 datasheet.

I have the same screen and the same problem. Pot wiper to v0 won't do anything, in fact, I haven't been able to change contrast at all.

The datasheet says "VLCD (V0 to VSS): max 7V". Also, under "DC characteristics": VLCD (LCD Voltage) Test condition:V0-VSS 3.0-7V .

Can anybody give me a clue?

Thanks!

Unfortunately the display sucks at 'fast' ( you can set and clear the display before the pixels fully illuminate ). The ST7920 chip is a good driver however. A different model ( green are usually good ) ST7920 screen may have a lot better performance.

It is a great display for static information as you can still write to it quickly.

Or are you having problems with static info displaying properly?

tilthz:
I have the same screen and the same problem. Pot wiper to v0 won't do anything, in fact, I haven't been able to change contrast at all.

The ST7920-based glcd that I purchased from eBay has a tiny pot for contrast adjustment, labelled VR1, on the back of the board. The Vout pin on the board is not connected to anything. Check yours in case it is similar.