Enhanced LiquidCrystal

I posted the idea so people could use the work around. And perhaps to inspire someone with a different perspective to see a real fix.

Scrolling gets blown out of proportion when I work on the library, because its the complicated bunch of things the display can do and so is involved in many of the tests in my test program (which is included with the download). In real code, I have no use for it. I knew about the bug for at least 2 weeks before I posted anything about it; I was pretty sure no one would find it in a short period of time; I wouldn't have found it except that I started putting together a thorough test procedure when I started working on the library, adding tests as I added features and found problems to demonstrate. Then before I post code I run 4 interfaces on 4 different shapes of LCDs, 2 interfaces on the 40x4.
That takes almost an hour but it leaves me pretty confident I've found everything I ever knew could be a problem.

Great work.

I've been wondering about the RW pin.

I have a project in development that needs a very fast bar graph. I was going to use the programmable characters to make the last segment variable length to get a one dot wide bar resolution.

There are two, possibly academic questions:

  • Is "faster than the eye can see" really true for something like a bar graph?

  • Is there any way to, and do you get any advantage out of, trying to sync the value update (which is related to analog sampling in my case) to the refresh cycling of the LCD?

I was thinking of an experiment that involves getting the bar graph working, and then using something like an adjustable sine wave synthed signal to drive it. Walk the frequency up until you can't really get the bar graph to follow the signal. Try that with and without the RW.

I'm in the middle of building a shield for this project and can't try this experiment right now, but I'm planning to. Do you have an old version of the code around I could try?

Well I would like to do a bar graph on my 40x4 but it seems very slow at refreshing. When I write one character over another it is visibly taking a long time. Any ways of speeding it up?

I did see something on fast refresh on LCDs some time ago but I can't for the life of me find it. Anyone else know where it is?
[edit]I can't have been looking very hard before, here it is:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264215873/0[/edit]

Mowcius

"writing 80 characters to the screen then 80 blanks and looping through that 20 times. The results are:
4 data pins 727 milliseconds
8 data pins 644 milliseconds"
so (80+80)*20 = 3200 characters in less than 3/4 of a second. your bar graph is one line long so either 20 or 40 characters. Lets say you have 40 chars. 727 *40/3200 = 9 milliseconds. Probably the rest of your code will be the limiting factor.

in the benchmark I print 80 character long strings. If you use a for loop and call once per character, of course it will go slower because of all the loop and call overhead. If you need maximum speed you might create an array of strings of different lengths for the different bar lengths.

Yeah it was the other code. After having a play around it is much faster now :slight_smile:

Mowcius

other thoughts about bar graphs that may be obvious:

if you're using an array of strings they should follow the pattern "x ", "xx ","xxx ",.. so that trailing spaces overwrite what was left over from last time. If you use the for loop and single character print you want to do the same thing--print spaces over the old bar. Using clear takes 2 milliseconds and then you have to reconstruct the whole screen.

A program that does bar graphs is likely to want to divide somewhere and if you can work it out so that >> will do, that is a LOT faster. so putting a short label on the line and having 16 or 32 segments in the bar may have a big payoff in speed.

Yes, I will be sticking a bargraph in my media player project. It has an rMP3 and a 40x4 LCD showing lyrics, time, track etc. I will have a bargraph for the volume and for the track length (probably) but they don't need to be very fast...

Mowcius

I'm probably overthinking this. I had thought that the display had something like a 200Hz refresh cycle, but that appears to be the refresh of one row, not the whole display. The datasheet I'm looking at shows a 64hz frame rate. at 64 Hz, I only need to get the bar graph into the LCD in 15 ms more or less, which clearly works without the RW. I don't really want to use the RW, because I want to use the pin for something else :slight_smile:

Ok, for my media player thing (mentioned above) I have been experimenting with code.

I have a for command measuring the volume (mapped from 0-39) and then it writes the boxes on the LCD line accordingly. I tried getting it to write spaces over the unused places but it was very slow. I am currently getting it to write 40 spaces over the whole line before the write and this is just visible (when the display is doing nothing else).

Anyone got any ideas of what I can do to speed it up?

Mowcius

The media player sounds like a neat project!
How do you map the volume to 40 segments? Integer division is slow, but not a disaster. Floating point IS a disaster in terms of performance, of course. I suggested 32 segments and >>. There may be a way to think in terms of 64 segments and >> with the result ending up in only 40 real segments; I'm usually too dull to work tricks like that out.

If you were really willing to dig into Liquid Crystal you could take what I had posted with the busy flag, stop making it a library but pull it into your own program. At that point you know which pins are used and you can combine those 2 things with issue 140 in the google code forum for Arduino to use AVR ports instead of digitalRead and digitalWrite. This would make checking the busy flag feasible, faster than ever, and hugely speed up some other small places. You would need to use RW, so you'd lose that pin. There were some delayMicroseconds(1) lines that I commented out but never actually removed from the source which would have to be reactivated. That would be a lot of work but the Liquid crystal speed up would be roughly 40% over what it is now, I think. As long as its a library routine, the AVR ports/issue 140 thing seems unavailable.

One of the tricks to using AVR ports is that you can reverse the 4 data pins from write to read during the busy flag check with 1 instruction rather than 4 separate slow calls to functions that have a complex job mapping them; you and the compiler would now know at compile time how that mapping took place. That's where the big saving comes from.

As I was walking the dog I realized that one way to implement this would be to leave liquid crystal as a library routine, but when you call it pass in a function name for it to call to check the busy flag. then you would have to write that one routine. I REALLY like this idea. I will probably get to it in the next couple of weeks.

With the media player, using the rMP3 board gives me a reverse volume of 0-254 (0 being the highest)
I am ignoring any data below 40 (it is pretty quiet then) and then turning the data the opposite way to get it as 40 being the highest (then taking away 1 to write to the corresponding segments). I am however mapping a potentiometer input to control that volume. Anyway here is that bit of code. Not great but it works ok.

      volume = map(analogRead(4), 0, 1020, 40, 0);
      if(volume == 40)
      rmp3.setvolume(254);
      else
      rmp3.setvolume(volume);
      vol = 40-volume;

then slightly further down there is this:

lcd.setCursor(0,3);
      lcd.print("                                        "); //40 spaces - seemed like the fastest way
      for(int i=0; i<=vol-1; i++){
      lcd.setCursor(i,3);
      lcd.print(255, BYTE);
      }

Here is an image before I got the volume graph going:

Mowcius

you don't need to setCursor every time; just once above the loop. It should run about 3 times as fast then; x and y each take about as much time as a character.

You need to test >= 40 rather than ==.

You need to test >= 40 rather than ==.

volume = map(analogRead(4), 0, 1020, 40, 0);

It should never go above 40 due to the map command. The analog read will never go below 0. I'm sure I put a constrain in there somewhere though...

Regarding the setCursor, it needs to be there due to it using i to set the position. If it was outside then it would not work.

Mowcius

try this:
lcd.setCursor(0,3);
lcd.print(" "); //40 spaces - seemed like the fastest way
lcd.setCursor(0,3);

for(int i=0; i<=vol-1; i++){
lcd.print(255, BYTE);
}

try this:
lcd.setCursor(0,3);
lcd.print(" "); //40 spaces - seemed like the fastest way
lcd.setCursor(0,3);

for(int i=0; i<=vol-1; i++){
lcd.print(255, BYTE);
}

No cos that does not tell it where to put the 255s, the code fills up the 'i' positions with '255' (black boxes) to show the volume in a bar...

Mowcius

It seems that the server is down again... is this library available anywhere else?

http://healthriskappraisal.org/LiquidCrystal440.zip

Thanks.

is this library available anywhere else?

Not that I know of. The link seems to work if you wait long enough.

[edit]Maybe it's not going to work today :([/edit]
I will email it to you. Word of advice though, I recommend you hide your email address in the user CP as it is very visible to spammers at the moment...

Mowcius

Well that was different; the GFI wall socket had tripped. usually its one of the routers (I think they both have memory leaks that bring them down about monthly).
Thanks, Mowcius, for emailing him the software.