EmbeddedRelated.com
Forums

Setting Pixels for ST7920 based 128x64 LCD

Started by Kevin Townsend November 24, 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

An Engineer's Guide to the LPC2100 Series

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);
}

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

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
}
}
}
}

> 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

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.
> 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
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.
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.

> 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