Sign in

Not a member? | Forgot your Password?

Search lpc2000

Search tips

Subscribe to lpc2000

Free PDF Downloads

An Engineer's Guide to the LPC2100 Series

Advanced Linux Programming

What Every Programmer Should Know About Memory

Introduction to Embedded Systems

C++ Tutorial

Embedded Systems - Theory and Design Methodology

Microcontroller Programming and Interfacing

Introduction to Microcontrollers


More Free PDF Downloads

Discussion Groups

See Also

ElectronicsDSPFPGA

Discussion Groups | LPC2000 | Setting Pixels for ST7920 based 128x64 LCD

Discussion group dedicated to the Philips LPC2000 family of ARM MCUs

Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 24 21:42:41 2008

I've been working on a driver for a ST7920 LCD I received today,
since most of the drivers I found on the web tend to be for
KS0107/0108 LCDs. I'd like to post the driver here when I'm finished
so that other people don't have to pull their own hair out, but I was
wondering if anyone would be able to offer some help on setting
individual pixels.

I've got everything working with the basic command set, and can
display text, initialise, etc. I can't figure out how to get the
extended command set working, though, specifically the ability to set
pixels individually.

I've noticed that you need to change the GDRam address to a position
in an 8x4 grid (see: st7920_setGDRamAddress), and then you can set
pixels in a 16x16 block, but how to set those 16x16 pixels is where
I'm stuck.

Does anyone here have any experience with this LCD controller that
could perhaps fill in the "st7920_setPixel(U8 x, U8 y)" method
appropriately?

http://www.sitronix.com.tw/sitronix/product.nsf/Doc/ST7920

I'll post the code in the another message

Kevin.


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 24 21:44:48 2008

ST7920.H
=============================================================
#ifndef ST7920_H
#define ST7920_H

#include "sysdefs.h"

/* Common Aliases */
#ifndef PIN
#define PIN(n) (U32)(1 << (n))
#endif

/* Pin Registers */
#define ST7920_BUSPIN0 16 // Parallel Bus
(P0.16..23)
#define ST7920_DATA ((U32)0xff< #define ST7920_BUSALL 0x00FF0000 // Parallel Bus Mask
(P0.16..23)
#define ST7920_PSB PIN(28) // Parallel Select (0 Serial Mode, 1 = 8/4-Bit Parallel Bus Mode) (P0.28)
#define ST7920_RW PIN(29) // RW (P0.29)
#define ST7920_DI PIN(6) // RS (P0.6)
#define ST7920_E PIN(30) // Enable (P0.30)
#define ST7920_RST PIN(25) // Reset (P0.25)

/* General Definitions */
#define ST7920_BUSIN 0 // Parallel Bus as Input
#define ST7920_BUSOUT 1 // Parallel Bus as Output
#define ST7920_BUSY 0x80 // Busy Flag

/* Basic ST7920 Commands */
#define ST7920_CMD_CLEAR 0x01 // Clear Display
#define ST7920_CMD_HOME 0x02 // Move Cursor Home
#define ST7920_CMD_EM 0x04 // Entry Mode Base
#define ST7920_CMD_EM_INCRR 0x02 // Increment Cursor Right
#define ST7920_CMD_EM_INCRL 0x00 // Increment Cursor Left
#define ST7920_CMD_EM_SHFTR 0x03 // Shift Display Right
#define ST7920_CMD_EM_SHFTL 0x01 // Shift Display Left
#define ST7920_CMD_DC 0x08 // Display Control
#define ST7920_CMD_DC_DISPON 0x04 // Display On
#define ST7920_CMD_DC_CURON 0x02 // Cursor On
#define ST7920_CMD_DC_BLNKON 0x01 // Blink On
#define ST7920_CMD_FNC 0x20 // Function Set
#define ST7920_CMD_FNC_DL8 0x10 // 8-Bit Interface
#define ST7920_CMD_FNC_DL4 0x00 // 4-Bit Interface
#define ST7920_CMD_FNC_EXTINS 0x04 // Extended Instruction Set
#define ST7920_CMD_FNC_BASINS 0x00 // Basic Instruction Set
#define ST7920_CMD_CGRAM_ADDR 0x40 // Set CGRAM Address
#define ST7920_CMD_DDRAM_ADDR 0x80 // Set DDRAM Address

/* Extended ST7920 Commands */
#define ST7920_ECMD_GFXDISPON 0x36 // Ext. Display Control (8-
bit, Extended Instructions, GFX Display On)

// Method Prototypes
void st7920_init(void);
void st7920_clear(void);
void st7920_printf(U8 *text);
void st7920_setPixel(U8 x, U8 y);

#endif

ST7920.C
=============================================================
#include "lpc214x.h"
#include "st7920.h"
#include "delay.h"

void st7920_strobeEnable(void)
{
GPIO0_IOSET = ST7920_E;
DelayMS(15);
GPIO0_IOCLR = ST7920_E;
}

void st7920_setBusDir(U8 dir)
{
if (dir==ST7920_BUSOUT)
{
GPIO0_IODIR |= (ST7920_BUSALL);
}
else
{
GPIO0_IODIR &= ~(ST7920_BUSALL);
}
}

void st7920_waitWhileBusy()
{
U8 rdata;

st7920_setBusDir(ST7920_BUSIN);

// Read busy flag
GPIO0_IOCLR = ST7920_DI; /* Clear RS */
GPIO0_IOSET = ST7920_RW; /* Set Read Mode */

st7920_strobeEnable();

// Loop until no longer busy
while ((rdata & 0x7F) == ST7920_BUSY)
{
rdata = (unsigned char)(GPIO0_IOPIN >> ST7920_BUSPIN0);
}

st7920_setBusDir(ST7920_BUSOUT);
GPIO0_IOCLR = (U32)(ST7920_BUSALL); /* Set all pins low */
GPIO0_IOCLR = ST7920_DI;
GPIO0_IOCLR = ST7920_RW; /* Read mode */
}

void st7920_data(U8 data)
{
st7920_setBusDir(ST7920_BUSOUT);

GPIO0_IOSET = ST7920_DI;
GPIO0_IOCLR = ST7920_RW;

GPIO0_IOSET = ((U32)data< st7920_strobeEnable();

GPIO0_IOSET = ST7920_RW;
GPIO0_IOCLR = (U32)(ST7920_BUSALL);
GPIO0_IOCLR = ST7920_DI;

DelayMS(2);
}

void st7920_command(U8 command)
{
st7920_setBusDir(ST7920_BUSOUT);

st7920_waitWhileBusy();
GPIO0_IOCLR = ST7920_DI;
GPIO0_IOCLR = ST7920_RW;
GPIO0_IOSET = ((U32)command< st7920_strobeEnable();

GPIO0_IOSET = ST7920_RW;
GPIO0_IOCLR = (U32)(ST7920_BUSALL);
GPIO0_IOCLR = ST7920_DI;

DelayMS(2);
}

// 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87
// 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97
// 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f
// 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f
void st7920_setGDRamAddress(U8 addr)
{
st7920_command(addr);
}

/* Public Methods
********************************************************** */
void st7920_init(void)
{
// Set pin to default state
U32 mask = (U32)(ST7920_RST | ST7920_PSB | ST7920_RW | ST7920_DI |
ST7920_E);
GPIO0_IOCLR = mask; // Clear all pins
GPIO0_IODIR |= mask; // Set all pins for output
GPIO0_IOSET = ST7920_PSB; // Set PSB High (0 = Serial Mode,
1 = 8/4-Bit Parallel Bus Mode)

// Wait until the LCD is not busy
st7920_waitWhileBusy();

// Toggle Reset
GPIO0_IOSET = ST7920_RST;
DelayMS(21);
GPIO0_IOCLR = ST7920_RST;
DelayMS(20);
GPIO0_IOSET = ST7920_RST;
DelayMS(20);

// Instantiate intialisation commands (Assigned here for debug
purposes. Remove variables in a production environment.)
U8 functionSetBas = (ST7920_CMD_FNC | ST7920_CMD_FNC_DL8 |
ST7920_CMD_FNC_BASINS); // (8-bit, Basic Instruction Set)
U8 functionSetExt = (ST7920_CMD_FNC | ST7920_CMD_FNC_DL8 |
ST7920_CMD_FNC_EXTINS); // (8-bit, Extended Instruction Set)
U8 displayCmd = (ST7920_CMD_DC | ST7920_CMD_DC_DISPON |
ST7920_CMD_DC_BLNKON); // (Display On, Blink On, Cursor OFF)
U8 entryMode = (ST7920_CMD_EM |
ST7920_CMD_EM_INCRR); // (Increment cursor
right, no shift)

// Send initialisation command sequence
st7920_command(functionSetBas); // Basic Function Set
st7920_command(functionSetBas); // Repeat Function Set
st7920_command(displayCmd); // Display
st7920_command(ST7920_CMD_CLEAR); // Clear Display
st7920_command(entryMode); // Set Entry Mode
st7920_command(functionSetExt); // Extended Function Set
st7920_command(ST7920_ECMD_GFXDISPON); // Graphic Display On

st7920_setPixel(1,1);
}

void st7920_clear(void)
{
st7920_command(ST7920_CMD_CLEAR); // Clear Display
}

void st7920_printf(U8 *text)
{
while(*text != 0)
{
st7920_data(*text);
text++;
}
}

void st7920_setPixel(U8 x, U8 y)
{
st7920_setGDRamAddress(0x80);

// ToDo: How to set individual pixels?
}



Re: Setting Pixels for ST7920 based 128x64 LCD - al_b...@vp.pl - Nov 25 5:20:31 2008

l... napisa(a):
ST7920.H

[...]
// ToDo: How to set individual pixels?
}

Try:
void st7920_setPixel(U8 x, U8 y)
{
U16 val;

val = 0x8000 >> (x & 0xF);
st7920_command(ST7920_CMD_DDRAM_ADDR + y);
st7920_command(ST7920_CMD_DDRAM_ADDR + (x >> 4));
st7920_command(val >> 8);
st7920_command(val & 0xFF);
}
Albert


_____________________________
 Free pdf download: An Engineer's Guide to the LPC2100 Series.


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 25 8:43:52 2008

Albert:

Thanks for the reply. I tried the supplied code, but don't seem to have any luck with it.
Whenever I send 'val >> 8' the screen clears as if I was in basic (text-only) mode, even
though I'm in extended mode. I've come up with the following code to at least put move
to the correct 16x16 block by means of the GDRAM Address ... I'm just missing what
command I need to send to set, say, pixel '8, 3' in the current 16x16 block. The code can
be heavily optimised later ... for the moment I just want to get it working, and understand
how it works:

void st7920_drawPixel(U8 x, U8 y, U8 color)
{
U8 xBlock, yBlock;
U8 xPixel, yPixel;

// Set horizontal GDRam position (0-7)
if (x > 15) { xBlock = x / 16; }
else { xBlock = 0; }

// Set vertical GDRam position (0-3)
if (y > 15) { yBlock = y / 16; }
else { yBlock = 0; }

// Move to appropriate GDRam block
st7920_setGDRamAddress(xBlock, yBlock);

// Determine 16x16 block address of the requested pixel
if (x < 16) { xPixel = x; }
else { xPixel = x - (xBlock * 16); }
if (y < 16) { yPixel = y; }
else { yPixel = y - (yBlock * 16); }

// ToDo: How to set individual pixels using xPixel and yPixel 16x16 position?
}



Re: Setting Pixels for ST7920 based 128x64 LCD - Albert Bartoszko - Nov 25 16:36:53 2008

Dnia 2008-11-25, wto o godzinie 13:43 +0000, Kevin Townsend pisze:
> Albert:
>
> Thanks for the reply. I tried the supplied code, but don't seem to
> have any luck with it.
> Whenever I send 'val >> 8' the screen clears as if I was in basic
Yes, my mistake.
Correct is:
...
st7920_data(val >> 8);
st7920_data(val & 0xFF);
...

See also:
http://www.crystalfontz.com/forum/showthread.php?tV05

Albert


_____________________________
 Free pdf download: An Engineer's Guide to the LPC2100 Series.


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 26 10:10:40 2008

Albert:

That's a lot closer to what I was hoping for, thanks. However, whenever I set one 'column'
of pixels, it seems to clear all the previous ones in the same 16x16 block. For example, I
would expect the code in 'main()' below to product a solid black block 128x8 pixels in size
along the top of the screen. Instead, I have 15 blank pixels, 1 black pixel, 15 blank, 1
black, repeated for each 16x16 block, 8 pixels high:

................................................ (etc.)
................................................ (etc.)
................................................ (etc.)
................................................ (etc.)
................................................ (etc.)
................................................ (etc.)
................................................ (etc.)
................................................ (etc.)

I see that the pixels are all set as the program executes, but they mysteriously get cleared
as pixels on the following column are set. Any idea why this might be?

int main(void)
{
st7920_init();
for (int x = -1; x < 127; x++)
{
for (int y = -1; y < 7; y++)
{
st7920_setPixel(x,y);
}
}

while (1);
}

--------------

void st7920_drawPixel(U8 x, U8 y)
{
U16 val;

val = 0x8000 >> (x & 0xF);
st7920_command(ST7920_CMD_DDRAM_ADDR + y);
st7920_command(ST7920_CMD_DDRAM_ADDR + (x >> 4));
st7920_data(val >> 8);
st7920_data(val & 0xFF);
}

In any case, thanks for your help. It's already a big lead in the right direction. I have really
been scratching my head with the datasheet trying to figure out what I was missing.

Kevin.


_____________________________
 Free pdf download: An Engineer's Guide to the LPC2100 Series.


Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 11:32:29 2008

Am Mittwoch, 26. November 2008 schrieb Kevin Townsend:
> Albert:
>
> That's a lot closer to what I was hoping for, thanks. However, whenever I
> set one 'column' of pixels, it seems to clear all the previous ones in the
> same 16x16 block. For example, I would expect the code in 'main()' below to
> product a solid black block 128x8 pixels in size along the top of the
> screen. Instead, I have 15 blank pixels, 1 black pixel, 15 blank, 1 black,
> repeated for each 16x16 block, 8 pixels high:
>
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
> ................................................ (etc.)
>
> I see that the pixels are all set as the program executes, but they
> mysteriously get cleared as pixels on the following column are set. Any
> idea why this might be?
>

Hello Kevin,

you access the display's memory directly, so it does know of any "setpixel" or
whatever commands. Therefore, it does not know how to combine the data in the
memory already, with the data you just send. So it just overwrites the data.

To set an individual pixel anywhere, without affecting already set pixels, you
need to read the display ram first. So, set the address, read the old content
from the display, combine with the new data, write back to the display. Many
displays offer a special mode where a read does not advance the display's
address-counter, but a write will do. That would save you an "set address"
command inbetween.

Lets assume a stripe (pixel row) is byte-wide, and the display is 128x64
pixels. A simple function to read-modify-write the display could look like
this "pseudo-code":

#define WIDTH 128
#define HEIGHT 64

setPixel(pos_x, pos_y, colour)
{
// row_data holds a stripe, pix_pos is the position of the bit in the
stripe.
unsigned char row_data, pix_pos;

setDisplayAddress( (x >> 3) + (y * (WIDTH >> 3)) ); // >>3 equals /8

row_data = readDisplayRam(); // read stripe from the display

pix_pos = x % 8; //calculate the new pixel position inside a stripe

if(colour) // if != 0, draw pixel
{
row_data |= (0x80 >> pix_pos); // combine old data and new pixel using OR
}
else
{
row_data &= ~(0x80 >> pix_pos); // combine using AND with the inverted
new-pixel-stripe
}

setDisplayAddress( (x >> 3) + (y * (WIDTH >> 3)) ); // set address again

writeDisplayData(row_data); // write out the new stripe
}
Here i assume that inside a stripe pixel 0 is on the left. If it is different,
just do a "0x01 << pix_pos" instead. If you want to invert a pixel on the
display, combine using XOR "row_data ^= (0x80 >> pix_pos);", etc, etc...

The pseudo-code is not meant to be functional, just an example to show how it
should be done. It sets the display address twice, that could be avoided
depending on the display.

An alternative method would be to have a display-buffer in local RAM and work
on that, if you can afford it. Then just send the modified bytes from the
internal buffer to the display. That could allow you a flicker-free update of
the whole display, at the expense using more RAM resources on the chip. In
any case, the method would be the same when working on an internal buffer:
read-modify-write.

Greetings,

Chris


_____________________________
 Free pdf download: An Engineer's Guide to the LPC2100 Series.


Re: Setting Pixels for ST7920 based 128x64 LCD - Timo - Nov 26 11:58:38 2008

Kevin Townsend wrote:
> st7920_data(val >> 8);
> st7920_data(val & 0xFF);

This doesn't only set pixels on, it *writes* them 16 pixels at once. So
when value of val is 0x0001, then you get 15 leftmost pixels cleared and
one rightmost pixel set on.

When your code writes 16 times into the same address, the effect of the
last write remains. And that happens to be always 0x0001 which you see
on your display.

I glanced over the datasheet and didn't see any method to touch only one
pixel at a time.

--

Timo



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 26 12:48:39 2008

Chris:

Thanks for the lengthy reply. After a bit of thought, that's what I assummed was happening,
but it's nice to have a clear explanation of how to resolve it. I'll adjust the code accordingly.
Hopefully, once I can add some support for fonts, etc., I can optimise the code a bit and
upload it here so other's can avoid some of the same problems.

Kevin.


Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 12:58:45 2008

Am Mittwoch, 26. November 2008 schrieb Kevin Townsend:
> Chris:
>
> Thanks for the lengthy reply. After a bit of thought, that's what I
> assummed was happening, but it's nice to have a clear explanation of how to
> resolve it. I'll adjust the code accordingly. Hopefully, once I can add
> some support for fonts, etc., I can optimise the code a bit and upload it
> here so other's can avoid some of the same problems.
>
> Kevin.

Hello Kevin,

quite some while ago i did some code for an LPC2220 based remote-control. It
also contains LCD routines for drawing, and the display also need's the
read-copy-modify method. If you want you can take a look at it. You can find
the code is svn, at svn://svn.mamalala.org/boop id you use a svn client, or
by web-interface at http://svn.mamalala.org/ and then the "boop" project.
There you will find a trunk/display/ folder which contains the code.

It has functions to draw lines, circles, rectangles, fonts, ....

It's far from perfect, but works for me. Maybe that will give you some ideas
for your stuff. Font-Handling is a bit uncommon in that code. If you need
help with that stuff, drop me a note. i'm not that good at documenting code,
as you can see ;)

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 26 15:38:45 2008

Christian:

Thanks for the link. I'll take a look at the code ... it seems straight-forward enough that I
should be able to make sense of it as is. :-) I've noticed that you are setting levels of gray or
something similar. What LCD were you using, if you don't mind me asking? I'd love to find
something that supports a few shades of gray without breaking the bank, if possible. It
would allow very basic anti-aliasing, for example, without all the headaches of a full color
LCD.

Kevin.


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 26 15:44:39 2008

Thanks to everyone's help here, I now have the screen acting like I expected, and can set all
the pixels. I'm a bit turned off by the performance, though. I've made some efforts to
minimise all the required delays, etc., but it is impossible to have instant-seeming screen
refreshes on an lpc2148 or similar device? I can put everything in a memory map and then
write it all at once (16-bit row by row), but I'm still seeing the scren visible 'scroll down' as I
draw on the screen, taking maybe 1/2s to draw the whole screen.

Any idea how I might be able to most efficiently fill the screen with black pixels, for example,
without the user seeing the pixels scroll down the screen?


Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 17:20:31 2008

Am Mittwoch, 26. November 2008 schrieb Kevin Townsend:
> Christian:
>
> Thanks for the link. I'll take a look at the code ... it seems
> straight-forward enough that I should be able to make sense of it as is.
> :-) I've noticed that you are setting levels of gray or something similar.
> What LCD were you using, if you don't mind me asking? I'd love to find
> something that supports a few shades of gray without breaking the bank, if
> possible. It would allow very basic anti-aliasing, for example, without
> all the headaches of a full color LCD.
>
> Kevin.

Hi Kevin,

while i dont know what the exact display is, it is a 128x160 pixel display
using the SSD1854 controller. It is capable of 4 gray levels. To be true,
there is not much gain using "anti-aliasing" on a 2bpp display. After all you
end up only having white, light-gray, dark-gray and black as "colours".

The whole remote control i talked about was a for some kind of interactive-tv
system they had in germany for a while. Never used it as intended, instead it
makes a nice platform to get used to the LPC's. And it made a fun project to
hack that thing ;) It has flash, lcd, sound, buttons, a cc1100 rf
transceiver, infrared, etc....

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 17:28:24 2008

Am Mittwoch, 26. November 2008 schrieb Kevin Townsend:
> Thanks to everyone's help here, I now have the screen acting like I
> expected, and can set all the pixels. I'm a bit turned off by the
> performance, though. I've made some efforts to minimise all the required
> delays, etc., but it is impossible to have instant-seeming screen refreshes
> on an lpc2148 or similar device? I can put everything in a memory map and
> then write it all at once (16-bit row by row), but I'm still seeing the
> scren visible 'scroll down' as I draw on the screen, taking maybe 1/2s to
> draw the whole screen.
>
> Any idea how I might be able to most efficiently fill the screen with black
> pixels, for example, without the user seeing the pixels scroll down the
> screen?

Hi Kevin,

there are serveral things you can do to speed up things.

First, dont expect to use it like a regular, generic computer graphics thing.
There are many things you can optimize, but you have to trade off
some "genericness" then.

First, use a small local buffer, much smaller than the whole display. Like, a
complete line or two. Do all drawing on that buffer, and send it out once
done. You can also use a buffer as tile, say, 32x32 pixels, work on that and
update at once.

Next, write special functions for special cases. Like, horizontal and vertical
lines, instead od a single function for all. Note that the bresenham i use in
my code is far from optimal. Another example is the one you brought up,
clearing the screen. Instead of drawing one pixel after the other, just send
the same byte(s) over and over again, until the display is filled. So, all
1's or all 0's, depending on what you want (black vs. white).

If the chip has an external memory bus, connect the lcd to that instead (this
is also what is done here in the remotes). So instead of fiddling with i/o
pins yourself, just write/read to/from a memory address.

Next, put your critical graphic routines in RAM instead of flash, since ram is
somewhat faster usually, at least here for me.

In any case, try to prepare as much graphics as possible in a local buffer,
combine the display's memory with that, and then (in a second pass) write out
all the data at once.

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 17:35:36 2008

Hi again,

with "running from RAM", i mean the LPC's internal SRAM, if it has any.

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 26 18:17:26 2008

Christian:

Thanks again for the (very thorough) reply. I'll likely have to spend a day or two on it, but
I'll try some of the suggestions you made (particularly the ram buffer) and see where I can
get.

In any case, the biggest offender in terms of performance seems to be the following
method:

// Toggles the Enable pin on then off
void st7920_strobeEnable(void)
{
GPIO0_IOSET = ST7920_E;
DelayUS(750);
GPIO0_IOCLR = ST7920_E;
}

If I drop the delay below 700 S between toggling the Enable pin high and low, the display
goes all nutty, but leaving it this high unfortunately means that I'm adding a decent
amount of delay every single time I send either a command or data to the controller, and I
don't see how I can avoid that?

Kevin.

PS: The remote indeed sounds like an interesting project. I've only been playing with
embedded devices for a couple months myself (coming from a background of 10 years in
PC software development), but it's the kind of project that would interest me just to see
what the end result might be with a bit of effort on my part. I've found embedded
development a lot more satisfying on the whole, just because at the end of all that effort
you at least have something you can hold in your hand. Sometimes it seems crazy to me
that I can spend 2 years working on a project at work, and have nothing to show for it but
a few dozen screenshots of Internet Explorer, or Windows, etc. :-)


Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 18:59:13 2008

Am Donnerstag, 27. November 2008 schrieb Kevin Townsend:
> Christian:
>
> Thanks again for the (very thorough) reply. I'll likely have to spend a
> day or two on it, but I'll try some of the suggestions you made
> (particularly the ram buffer) and see where I can get.
>
> In any case, the biggest offender in terms of performance seems to be the
> following method:
>
> // Toggles the Enable pin on then off
> void st7920_strobeEnable(void)
> {
> GPIO0_IOSET = ST7920_E;
> DelayUS(750);
> GPIO0_IOCLR = ST7920_E;
> }
>
> If I drop the delay below 700 S between toggling the Enable pin high and
> low, the display goes all nutty, but leaving it this high unfortunately
> means that I'm adding a decent amount of delay every single time I send
> either a command or data to the controller, and I don't see how I can avoid
> that?

Hi Kevin,

hmm, that doesnt sound right. According to the Datasheet of the LCD controller
you use, the enable cycle time Tc is given as 1200 or 1800 nS, which is 1.2
or 1.8 S. So, a wait of 750 S for the toggling of the enable-line looks way
too much.

Have you checked the signal integrity with a scope, on the physical line? What
C do you use, at what frequency, and what PLL (if any)? How is the display
connected?

>
> Kevin.
>
> PS: The remote indeed sounds like an interesting project. I've only been
> playing with embedded devices for a couple months myself (coming from a
> background of 10 years in PC software development), but it's the kind of
> project that would interest me just to see what the end result might be
> with a bit of effort on my part. I've found embedded development a lot
> more satisfying on the whole, just because at the end of all that effort
> you at least have something you can hold in your hand. Sometimes it seems
> crazy to me that I can spend 2 years working on a project at work, and have
> nothing to show for it but a few dozen screenshots of Internet Explorer, or
> Windows, etc. :-)

Well, as said, the remote itself is not a project of mine. You can grab them
for 10 or 20 Euro on eBay in Germany. Maybe you still can get some in
Switzerland on eBay as well. They have not been used anywhere else, from what
i know. The package comes with the remote, a modem and a scart-adapter (to
grab the VTX signal). They all communicate through the 433 MHz band, using
the CC1100 chips. We are just about to write new firmware for that thing,
since the company who made the system is out of business.

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 26 19:06:13 2008

Oh,

and even keeping in mind the execution time for the commands, which is 72 S,
the 750 S is way too high, imho. Only the display clear command takes
longer, 1.6 mS. Reading the busy flag is immediate, 0 S.

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 27 3:18:23 2008

> Hi Kevin,
>
> hmm, that doesnt sound right. According to the Datasheet of the LCD controller
> you use, the enable cycle time Tc is given as 1200 or 1800 nS, which is 1.2
> or 1.8 S. So, a wait of 750 S for the toggling of the enable-line looks way
> too much.
>
> Have you checked the signal integrity with a scope, on the physical line? What
> C do you use, at what frequency, and what PLL (if any)? How is the display
> connected?

I managed to speed it up significantly by lowering all the delays to 100 microSeconds, but
putting an explicit 12ms delay after the clear command (which requires a > 10ms delay
according to the datasheet). There is probably still some room for improvement, but this
allows me to reduce the delay when toggling the Enable pin from 750 us to 110 us, and
significantly improves performance.

Thanks again for everyone's help with this. There are still some off issues to sort out with
this controller, but I suspect I understand enough to figure out the rest.

Kevin.



Re: Setting Pixels for ST7920 based 128x64 LCD - donhamilton2002 - Nov 27 5:06:46 2008

--- In l..., Christian Klippel wrote:

> Well, as said, the remote itself is not a project of mine. You can
grab them
> for 10 or 20 Euro on eBay in Germany. Maybe you still can get some in
> Switzerland on eBay as well. They have not been used anywhere else,
from what
> i know. The package comes with the remote, a modem and a
scart-adapter (to
> grab the VTX signal). They all communicate through the 433 MHz band,
using
> the CC1100 chips. We are just about to write new firmware for that
thing,
> since the company who made the system is out of business.
>
> Greetings,
>
> Chris
>

Do you have a ebay link to this device you can post ??

thanks

donH


Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 27 6:29:05 2008

Am Donnerstag, 27. November 2008 schrieb donhamilton2002:
>
> Do you have a ebay link to this device you can post ??
>
> thanks
>
> donH

Hello Don,

here are some eBay auctions for that thing:
http://shop.ebay.de/?_from=R40&_nkwtty+Fernbedienung&_sacat=See-All-Categories

Here is our Wiki about it:
http://bettyhacks.com/wiki/index.php/Main_Page

And a forum exists as well:
http://bettyhacks.com/forum/

Of course its mostly in german, since that remote is a german/swiss thing
only.

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 27 7:10:00 2008

Christian (or anyone else):

One last question (hopefully) ... I've noticed that whatever I do, I am only able to fill one
half of the screen. I assume this is because there are actually two controllers, each driving
half of the screen, but I don't see anything in the datasheet to indicate how to switch
between the controllers to set any pixels on row 33-64 (I have rows 1-32 working as I
expected).

I've reworked the code to work with a 16-bit 8x64 memory map to avoid having to send
read commands (the 2148 has more than enough memory for this), but when I update the
screen from the map, I can't seem to find a way to force controller for the bottom of the
screen to update it's memory. I'm sure I'll figure it out eventually, but perhaps you know
the answer off the top of your head? I assume I just need to modify an address in the
'st7920_writeRow' method below???

// Fills the entire screen with the supplied 16-pixel wide pattern.
// '0xFFFF' will fill the screen with black pixels, '0X0000' will clear
// the entire screen, and '0xAAAA' will fill the screen with alternating
// pixels, for example.
void st7920_fill(U16 pattern)
{
st7920_fillMemoryMap(pattern);
st7920_refreshScreen();
}

// Renders the contents of the memory map to the LCD screen (16x1 pixels at a time)
void st7920_refreshScreen(void)
{
U8 pixelX;

for (U8 x = 0; x < ST7920_MEMMAP_WIDTH; x++) // Scroll through all columns (16
pixels wide)
{
for (U8 y = 0; y < ST7920_MEMMAP_HEIGHT; y++) // Scroll through all rows (1 pixel
high)
{
pixelX = x * 16; // pixelX = current column (x) * 16
st7920_writeRow(pixelX, y, _memoryMap[x][y]); // Send the current column/row to
LCD display
}
}
}

// Writes data to a 16 pixel row corresponding to the supplied X and Y co-ordinates
void st7920_writeRow(U8 column, U8 row, U16 value)
{
value = value >> (column & 0xF);
st7920_sendCommand(ST7920_CMD_DDRAM_ADDR + row);
st7920_sendCommand(ST7920_CMD_DDRAM_ADDR + (column >> 4));
st7920_sendData(value >> 8);
st7920_sendData(value & 0xFF);
}



Re: Setting Pixels for ST7920 based 128x64 LCD - Christian Klippel - Nov 27 7:40:55 2008

Am Donnerstag, 27. November 2008 schrieb Kevin Townsend:
> Christian (or anyone else):
>
> One last question (hopefully) ... I've noticed that whatever I do, I am
> only able to fill one half of the screen. I assume this is because there
> are actually two controllers, each driving half of the screen, but I don't
> see anything in the datasheet to indicate how to switch between the
> controllers to set any pixels on row 33-64 (I have rows 1-32 working as I
> expected).
>
> I've reworked the code to work with a 16-bit 8x64 memory map to avoid
> having to send read commands (the 2148 has more than enough memory for
> this), but when I update the screen from the map, I can't seem to find a
> way to force controller for the bottom of the screen to update it's memory.
> I'm sure I'll figure it out eventually, but perhaps you know the answer
> off the top of your head? I assume I just need to modify an address in the
> 'st7920_writeRow' method below???

Hi Kevin,

hmm, from what i see the single lcd controller is capable for up to 256x64
pixel, so i think you see a driver chip there instead of a second controller,
unless you display is bigger than that.

Have you tried to fill the whole possible memory range of the lcd controller?
There is a slight chance that the memory mapping isnt linear for the two
screen-half's, altough mostly such memory would be linear.

In your writeRow() function, at the very first you do a "value = value >>
(column & 0xF);" Do you really want that, since "value" seems to be the
pixel-data you actually want to send.

Finally, _if_ there is a second controller on the lcd, it probably would have
its own enable line, while sharing the other lines.

What exact type/brand is the display that you use? Any link at hand?

Greetings,

Chris



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 27 8:05:39 2008

I think I've figure it out. The screen is expecting pixel addresses of 256x32, even though
the screen is 128x64. To set pixel 0,32 (the first pixel on the bottom half of the screen),
you actually need to pass the address 128, 0 (and then 129, 0, etc.).

Thanks again for the quick help,
Kevin

// Renders the contents of the memory map to the LCD screen (16 pixels at a time)
void st7920_refreshScreen(void)
{
U8 pixelX;

for (U8 x = 0; x < ST7920_MEMMAP_WIDTH; x++) // Scroll through all columns (16
pixels wide)
{
for (U8 y = 0; y < ST7920_MEMMAP_HEIGHT; y++) // Scroll through all rows (1 pixel
high)
{
// Top half of screen
if (y < 32)
{
pixelX = x * 16; // pixelX = current column (x) * 16
st7920_writeRow(pixelX, y, _memoryMap[x][y]); // Send the current column/row to
LCD display
}
// Bottom half of screen
else
{
pixelX = (x * 16) + 128; // pixelX = current column (x) * 16
st7920_writeRow(pixelX, y - 32, _memoryMap[x][y]); // Send the current column/row
to LCD display
}
}
}
}



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 27 8:53:29 2008

> Hi Kevin,
>
> hmm, from what i see the single lcd controller is capable for up to 256x64
> pixel, so i think you see a driver chip there instead of a second controller,
> unless you display is bigger than that.

You're right ... there is only one controller, but two 'drivers'. The diagram in the datasheet
shows one ST7920 connected to two ST7921s which are connected to the LCD. The key
may be that the display is shown as 256x32, when the screen is actually 128x64. As I
mentionned, I'm sure it is simply a problem of finding the right address.

> Have you tried to fill the whole possible memory range of the lcd controller?
> There is a slight chance that the memory mapping isnt linear for the two
> screen-half's, altough mostly such memory would be linear.

I'll give it a shot.

> In your writeRow() function, at the very first you do a "value = value >>
> (column & 0xF);" Do you really want that, since "value" seems to be the
> pixel-data you actually want to send.

I'm not sure ... that's the method I had the hardest time to wrap my head around, and that
code was supplied by someone earlier in this thread. As I mentionned, I'm sure the
problem is here ... but I don't particularly understand the logic of how the addressing
works relative to actual pixel locations.

> Finally, _if_ there is a second controller on the lcd, it probably would have
> its own enable line, while sharing the other lines.
>
> What exact type/brand is the display that you use? Any link at hand?

http://cgi.ebay.fr/ws/eBayISAPI.dll?
ViewItem&ssPageName=STRK:MEWNX:IT&item&0312979724#ht_2331wt_0

http://www.pic16.net/down/12864液晶中文资料.pdf

Kevin



Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 27 12:16:30 2008

I have uploaded a beta version of this driver in the files section
named 'ST7920-Graphic-LCD-Driver.zip'. I'm sure there are still bugs,
and the performance could probably be significantly improved, but it
should at least serve as a decent starting point for further
development by other people.

I will probably update it later if I add font support, etc., but for
now I wanted to at least post something. For reference sake, I have
made no effort to support the LCD's 'basic' (text only) mode, since I
will only use the display in graphic (pixel) mode.

All pixels are stored in an internal 8x64 16-bit memory map, and when
you modify a pixel via the appropriate method you have the option to
update the LCD entirely, partially, or not at all (depending on your
performance requirements). Please see the main.c file for examples of
all three ways to update the screen. I made the decision to use the
memory map since the lpc2148 has lots of memory, and it saves me from
having to read the LCD contents every time a pixel is modified to make
sure I'm not overwriting other existing data. Feel free to change the
code if you're requirements are different.

Thanks again for all the help/advice I received on this (Christian,
Albert, etc.)! I would have a lot more gray hairs if this forum wasn't
as helpful and informative as it typically is. :-)

Kevin.


Re: Setting Pixels for ST7920 based 128x64 LCD - Mukund Deshmukh - Nov 27 23:21:48 2008

> I will probably update it later if I add font support, etc., but for
> now I wanted to at least post something. For reference sake, I have
> made no effort to support the LCD's 'basic' (text only) mode, since I
> will only use the display in graphic (pixel) mode.
>

In file section I have uploaded LCD driver for T6369 and K107/108. You may
take some clue about fonts.
Warm Regards,

Mukund Deshmukh,
Beta Computronics Pvt Ltd.
10/1 IT Park, Parsodi,
Nagpur -440022 India.
Web site - http://betacomp.com

Meet us at our Stall No M91 Hall No 18 MZ ,
PLASTINDIA 2009 , Feb 4 -9, 2009,
Pragati Maidan, New Delhi, INDIA


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 28 15:24:18 2008

Mukund:

I was looking at it, and it looks interesting but I'm having a hard
time compiling it in Crossworks (using the GCC compiler I believe).

I get errors on all of the following lines in fonts.c:

const struct FONT_DEF Font_System3x6 = {3, 6, au8FontSystem3x6};
const struct FONT_DEF Font_System5x8 = {5, 8, au8FontSystem5x8};
const struct FONT_DEF Font_System7x8 = {7, 8, au8FontSystem7x8};
const struct FONT_DEF Font_Courrier8x12 = {8, 12,
au8FontCourrier8x12};
const struct FONT_DEF Font_8x8thk = {8, 8, au8Font8x8thk};
const struct FONT_DEF Font_8x8thn = {8, 8, au8Font8x8thn};
const struct FONT_DEF Font_8x8ord = {8, 8, au8Font8x8ord};

The error is: "variable 'Font_System3x6' has initializer but
incomplete type" (etc.)

They definitions in fonts.h are as follows:

/* Extern definitions */

typedef struct
{
U8 u8Width; /* Character width for storage */
U8 u8Height; /* Character height for storage */
U8 *au8FontTable; /* Font table start address in memory */
} FONT_DEF ;

extern const struct FONT_DEF Font_System3x6;
extern const struct FONT_DEF Font_System5x8;
extern const struct FONT_DEF Font_System7x8;
extern const struct FONT_DEF Font_Courrier8x12;
extern const struct FONT_DEF Font_8x8thk;
extern const struct FONT_DEF Font_8x8thn;
extern const struct FONT_DEF Font_8x8ord;

extern const U8 au8FontSystem3x6[];
extern const U8 au8FontSystem5x8[];
extern const U8 au8FontSystem7x8[];
extern const U8 au8FontCourrier8x12[];
extern const U8 au8Font8x8thk[];
extern const U8 au8Font8x8thn[];
extern const U8 au8Font8x8ord[];

I don't really see what the problem is, but I'm fairly new to
embedded and C development. Any idea yourself?

Kevin.


Re: Setting Pixels for ST7920 based 128x64 LCD - Kevin Townsend - Nov 28 19:24:49 2008

Mukund:

I found the problem with the compiler ... I just needed to change a
declaration.

I've now got the fonts working (the 3x6 font anyway ... I haven't tried
the others, yet). The only disadvantage I can see to the way you've
defined your font data is that you can't naturally have fonts more than
8 pixels high because you are using 8 bit values for each 'column'.
Obviously moving up to 16-bit values (16 pixels high) will double the
memory requirements, but I'll probably modify the code to use U16
instead of U8 for added flexbility.

In any case, thanks for the code to serve as a good starting point!

Kevin.



Re: Setting Pixels for ST7920 based 128x64 LCD - Mukund Deshmukh - Nov 28 22:47:41 2008

> Mukund:
>
> I was looking at it, and it looks interesting but I'm having a hard
> time compiling it in Crossworks (using the GCC compiler I believe).
>
> I get errors on all of the following lines in fonts.c:

The code works well on GCC 4.1.1.
Try T6963 code, it has bigger fonts and better.
Warm Regards,

Mukund Deshmukh,
Beta Computronics Pvt Ltd.
10/1 IT Park, Parsodi,
Nagpur -440022 India.
Web site - http://betacomp.com

Meet us at our Stall No M91 Hall No 18 MZ ,
PLASTINDIA 2009 , Feb 4 -9, 2009,
Pragati Maidan, New Delhi, INDIA



Re: Setting Pixels for ST7920 based 128x64 LCD - Mukund Deshmukh - Nov 28 22:48:20 2008

> I found the problem with the compiler ... I just needed to change a
> declaration.
>
> I've now got the fonts working (the 3x6 font anyway ... I haven't tried
> the others, yet). The only disadvantage I can see to the way you've
> defined your font data is that you can't naturally have fonts more than
> 8 pixels high because you are using 8 bit values for each 'column'.

If you look at 18 dot font in T6963 code, the font width is 3 byte (24
pixel) and height is 18 bytes (or pixel). We are using these fonts in our
products with LPC2136.
It is worth while to mention that credit for these fonts goes to Michael J.
Karas, I only implemented it on K107/108 and T6963.
Warm Regards,

Mukund Deshmukh,
Beta Computronics Pvt Ltd.
10/1 IT Park, Parsodi,
Nagpur -440022 India.
Web site - http://betacomp.com

Meet us at our Stall No M91 Hall No 18 MZ ,
PLASTINDIA 2009 , Feb 4 -9, 2009,
Pragati Maidan, New Delhi, INDIA