Pages: [1] 2 3   Go Down
Author Topic: How to control 2 graphic LCDs with one Arduino  (Read 8471 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello

I plan to control 2 graphic LCD (http://www.sparkfun.com/products/710) using the KS0108 Graphics LCD library  (http://www.arduino.cc/playground/Code/GLCDks0108).

The library assumes you use one port (A,B or C) to connect one LCD.

I would like to know what I should modify in the library to use 2 LCDs?
Do I need to duplicate the library changing all functions name to address LCD 1 or LCD 2 (e.g. GLCD.ClearScreen1() for LCD 1 and GLCD.ClearScreen2() for LCD 2) ? Or is there any more elegant way to do it?
So far I am a user of the existing libraries but didn’t try myself to write one…
Thank you for your support.

Raoul.

Note: I am using a Mega 2560

Logged

Western New York, USA
Offline Offline
Faraday Member
**
Karma: 35
Posts: 4299
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is easy to do with the character mode LCDs and the same technique may very well work with graphical LCDs.  Check out this thread from the old forum: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265969050

Don
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7188
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have to complain that either ks0108 or glcd library (if they're not the same) is pretty big in SRAM so hope two instances will work. Essentially like what floresta pointed out (the post), if you can, instantiate two GLCDs and with same data lines but different CS1 and CS2.
Logged


0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi
Thank you for your quick reply, I will try it but seems it should work.
Raoul.
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi again
I am trying to use 2 instances of the graphic library; the issue here is that the pin assignment is done in the header file ( that it is not the case for LiquidCrystal)...

"To change pin assignments you must modify the ks0108.h header file. Find the section in the file that begins:

 /********************************************************/
 /* Configuration for assigning LCD bits to Arduino Pins */
 /********************************************************/

You will see the defines for the five command pins with their default pin assignments:

        Name    Arduino pin number
 #define CSEL1   14 (Analog pin 0)
 #define CSEL2   15 (Analog pin 1)
 #define R_W     16 (Analog pin 2)
 #define D_I     17 (Analog pin 3)
 #define EN      18 (Analog pin 4)"


Do you have any idea to workaround? Maybe adding a function to the library to assign the pins instead of doing it in the header file?

Thank you.
Raoul.

Logged

Western New York, USA
Offline Offline
Faraday Member
**
Karma: 35
Posts: 4299
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So far I am a user of the existing libraries but didn’t try myself to write one…
This would be a good opportunity to do just that.  Why not start by modifying the existing library to do the pin assignments the way that LiquidCrystal does?

Don 
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Don
You are right...
The LiquidCrystal is part of the Arduino software package, do you know where to download the source in order to understand it ?
Thanks.
Raoul
Logged

Western New York, USA
Offline Offline
Faraday Member
**
Karma: 35
Posts: 4299
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
do you know where to download the source in order to understand it ?
It's already on your computer if you have installed the Arduino IDE.  Where it is depends on which operating system you are using and which version of the Arduino IDE you have installed.  Look for a 'Libraries' folder and LiquidCrystal should be there.

Don
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2692
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have to complain that either ks0108 or glcd library (if they're not the same) is pretty big in SRAM so hope two instances will work. Essentially like what floresta pointed out (the post), if you can, instantiate two GLCDs and with same data lines but different CS1 and CS2.

Please elaborate on this. (I am the co-author of the glcd library).
Great pains were taken to minimize the RAM usage for the library.
That is why there is no frame buffer involved, which is what allows all
demo sketches shipped with the latest glcd v3 beta to work on a mega168 which
has only 1k of SRAM.

--- bill
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2692
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello

I plan to control 2 graphic LCD (http://www.sparkfun.com/products/710) using the KS0108 Graphics LCD library  (http://www.arduino.cc/playground/Code/GLCDks0108).

The library assumes you use one port (A,B or C) to connect one LCD.

I would like to know what I should modify in the library to use 2 LCDs?
Do I need to duplicate the library changing all functions name to address LCD 1 or LCD 2 (e.g. GLCD.ClearScreen1() for LCD 1 and GLCD.ClearScreen2() for LCD 2) ? Or is there any more elegant way to do it?
So far I am a user of the existing libraries but didn’t try myself to write one…
Thank you for your support.

Raoul.

Note: I am using a Mega 2560



Raul,
The library can run dual displays. I did this during the development of the new level code
that is in the current v3 beta version of the library.

I'd insert a photo of this running the demo sketches, but this forum
does not allow posting images.
 (Yes I know it allows linking but I'm not  going to upload it somewhere else)

There is a trick though. You must trick the library into "thinking" it is on larger display.
So rather than having 2 separate displays you change the config file to say it is
a 128x128 display with 4 chip selects.

The great thing is that it only takes 2 additional pins to do this.
Wiring up the displays is pretty simple as all the other pins,
D0-D7, EN, RW, DI, are all shared and wired together.

Then what you end up with is a 128x128 display is split across dual displays.
Not quite the same as 2 independent displays, but still very usable.
You can set up text areas that are limited to a single which makes text very easy.
For the graphics you have to be a bit careful not to transverse between the two
displays. And avoid things like GLCD.ClearScreen()

I have to go right now, but can elaborate further if you need more assistance.

--- bill

Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2692
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A bit of followup on the glcd library which is the next revision of the ks0108 library.
It was renamed to "glcd" because it now supports more than the ks0108.

The glcd v3 library is the "new and improved" ks0108 library.

With respect to device instantiation and runtime defining the pins,
this is not a simple task given the current code.

The current code has a single global instantiation "GLCD" and as you've seen defines the pins in a header file
rather than use runtime initialization.

There is a simple reason for this: Performance.
The standard arduino digital i/o routines are VERY slow and also only work on single pins.
By defining the pins in a header file the library code has access to them at compile.
Through much pre-processing magic (in avrio.h) and gcc compiler optimizations,
the final code for reading/writing pins can be usually reduced to a single AVR machine instruction.
The avrio.h code also optimizes across multiple pins so that depending on the AVR pins used,
things like reading the glcd data port can even be crushed down into a single instruction
vs having to call 8 digital read/write functions.
avrio is also smart enough to use nibble operations when possible, and will  revert to individual
bit i/o if necessary.
If the pins were runtime declared, the performance would drop significantly.

With respect to the GLCD global instantiation. That was done for several reasons.
The main one being to try to simplify the user experience since it is automatically instantiated,
there is no runtime pin configuration, and usually the user does not need to configure
the pins in the header files. It was an attempt to offer a "it just works" out of box experience.
In that respect I think it has succeeded.

But also, when the code uses a global and only one of them, the code can also
be smaller, faster and use less RAM memory.

Speaking of memory, I did take another look at memory/RAM consumption.
There is zero initialized data. (which ends up in RAM with avr-gcc)
There is 53 bytes of static data,
There will be 12 bytes of RAM for each text area declared.

What can really eat up ram is the use of character strings.
While it might be assumed that strings land in flash (and they do),
they also will be copied to RAM.
That can be avoided if you declare your strings to put them in flash (program memory) and
then call glcd routines like Puts_P() Printf_P() to print them.


Attached are images of running  the sketches supplied with the glcd v3 library
on dual ks0108 glcds using a teensy board.


--- bill


* ks0108_128x128_teensy_2.JPG (76.76 KB, 300x620 - viewed 98 times.)

* ks0108_128x128_teensy_3.JPG (75.12 KB, 300x620 - viewed 89 times.)

* ks0108_128x128_teensy_4.JPG (69.43 KB, 293x621 - viewed 86 times.)
« Last Edit: March 22, 2011, 03:51:26 pm by bperrybap » Logged

Global Moderator
Online Online
Brattain Member
*****
Karma: 480
Posts: 18730
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you don't mind using an extra chip per display, you could have a lot of them. I did an article about driving graphical LCD displays using I2C or SPI here:

http://www.gammon.com.au/forum/?id=10940

With I2C you could potentially have 8 displays (since you share the same 2 pins: SDA/SCL) and you can configure the chip to have up to 8 addresses. With SPI you can have as many displays as you can spare SS pins for (3 wires for MOSI/MISO/SCK plus one extra one for SS per display).

With a Mega you might not need to bother because you have some spare pins, but it is an idea.
Logged


Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2692
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you don't mind using an extra chip per display, you could have a lot of them. I did an article about driving graphical LCD displays using I2C or SPI here:

http://www.gammon.com.au/forum/?id=10940

With I2C you could potentially have 8 displays (since you share the same 2 pins: SDA/SCL) and you can configure the chip to have up to 8 addresses. With SPI you can have as many displays as you can spare SS pins for (3 wires for MOSI/MISO/SCK plus one extra one for SS per display).

With a Mega you might not need to bother because you have some spare pins, but it is an idea.

True, adding an i2C i/o expander chip would offer a way to support several displays with very few pins
but not with the current glcd library implementation since the glcd library doesn't currently support
multiple instances.

--- bill
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bill,

On the topic of hardcoding pin selections, there may be some middle ground. I had run into a similar problem when creating the PrimeVfd library:http://arduino.cc/playground/Main/PrimeVfd . digitalWrite() was nowhere near fast enough but I didn't want to limit the library to one pinout option and I wanted to support multiple displays.

What I did was to support a selection of hardcoded pin choices, with many choices intended to be used together with only the select pins differing. It is easy to expand the pin choices. The selection is specified as an enum and the constructor sets up some member variables based on that selection. This has negligible overhead for the most part. At the top of any method that is going to do something expensive, I copy the variable into a local register to help the compiler keep the variable in a register. When I looked at the assembly it looked pretty efficient.

I ran into one gotcha which may not even apply to glcd. PrimeVfd needs to clock out byte data which means setting a single output pin based on a bit value in a variable. If I hardcode to a pin on bit zero for example, then that becomes very easy. Even if it is not bit zero, it is fairly efficient if the amount of bit shifting is fixed. However, if the bit number is variable then it involves either a shift of unknown length at compile time (super expensive apparently) or an if-else operation. For this case however, it is possible to implement a branchless select which adds only a few instructions per bit.

This will burn some code space and add a few variables also. Overall, I felt the modest performance and memory hit was worth making the library more flexible, and IMO, a little easier to use.

- Jayeson
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 67
Posts: 2692
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Jayeson,
Its a really tough situation for using ks0108 glcd type devices on Arduinos,
particularly with the 168/328 based boards.

It is kind of the convergence of a perfect storm that  makes things so difficult.

There are so many pins involved, that it is tough to pick a set of pins
for a default configuration or even a group of configurations.

Also, unlike character type lcds, the glcd software is
having to deal with 8192 bits of pixel data in a low level
interface. This means many thousands of times more i/o operations
to get things done over typical character lcds or intelligent glcds.
(and that is for a 128x64 glcd, with larger displays it is even more data)

The Arduino i/o interface is individual pin oriented.
So at 16mhz having 4us of overhead to deal with each individual pin vs 62.5 ns becomes
very significant, especially when looking at so many i/o operations.
With direct port i/o on the large arduino boards all 8 bits of a data byte
can be written in a single AVR machine cycle.

Another very painful thing is (IMHO) the poor choice of pin assignments Atmel chose for
the mega 8/16/168/328 AVRs. Because of the pin assignments, it is impossible to get
an 8 bit byte in a single AVR register on those processors when using the serial port
on those AVRs.
Even using nibbles across multiple ports can be challenging because of the
alternate port functions and the very limited number of pins on those AVRs.

Now toss in the inability to use a local frame buffer because of SRAM constraints,
(which means you may have to read remote glcd memory before you can write to update a pixel)
you can't really off load any of the processing to an interrupt routine as the glcd update
would  make the ISR take too long (potentially several milliseconds),
and wanting to support user defined fonts of any size, and you quickly enter into a world
of having make many painful choices and sacrifices in order to get the functionality
working with reasonable performance across many different AVRs and different sized glcd displays.

The current implementation made many intentional design decisions and sacrifices
along the way to try to make the library easy to use and offer reasonably high performance
across all the arduino boards.
Ease of use was at the top of the list.

One thing that is in the current v3 implementation is that the user can use any arduino pin
for any glcd function. He just has to define these in a config file vs defining them runtime in his sketch.
This has allowed users to easily reconfigure the library to support freeing up pins for alternate functions.
The low level code has many complex macros and inline functions
under the hood that will automagically determine the best/fastest way to use AVR direct port i/o to
access the pins. For 8 bit operations it can reduce that down to a single AVR instruction or
use nibbles,  individual pin i/o or any combination depending on the pins selected.
This optimization can't be done if the pin information is not known at compile time by the library
or if multiple instances are used.

Multiple instances was not an initial priority especially given the number of pins involved
for these types of displays.

That said, multiple instances might be something that gets a second look in the future
but in my view, in order to really support multiple instances, the interface needs to be
moved to some form of serial interface, SPI/I2C etc...  vs individual control and data lines.
Which could be done very inexpensively using an i/o expander chip.

--- bill
« Last Edit: March 27, 2011, 03:32:20 pm by bperrybap » Logged

Pages: [1] 2 3   Go Up
Jump to: