ST9720 128x64 - slow loop time, what can I do ? Due/u8glib/HWSPI ?

Hello Everyone!

I know this is an old subject but Ive seatche the inthernet and the forum without any luck . I'm working on a water control project and trying to use the 128x64 ST9720 driver LCD currently I'm using u8glib and it runs fine, but there is a big problem I have an interface with the LCD and some buttons (4 buttons with resistors on one analog input) while I don't really care about the refresh rate of the screen, the picture loop is taking a lot of time of the main loop and when I press a button it takes a long time for it to be recognized, i guess its because AnalogRead() executes only 3-4 times a second and there is not always a match in the value for it to be recognized.

A while ago when i was choosing the hardware for the project I thought of a DUE or a MEGA. I have both now, but chose the DUE for the project because it faster and its 3.3v that is better for interfacing a SD card and a bluetooth module, and thought it would me much faster with the LCD in the loop, but its not.

Ive tried using HW SPI on the due but no luck, It just won't work, although it says here https://code.google.com/p/u8glib/wiki/device that with Page size of 512 Bytes it supposed to work on the DUE, I dont really know what that means. It is working on the mega.

so I think my options are: 1. use another method/library for the LCD with HW SPI enabled for faster loop. (I really like u8glib) 2. use some clever programming in order to "draw" on the screen only when needed - so the main loop wont "draw" every time / all my tries to do so have failed 3. use an extra arduino mini/micro/nano to only drive the screen while every thing else will be done by the DUE. (have no real theory on how to do this) 4. use the MEGA instead with HW SPI, hope for a fast loop and use level shifters for the SD and Bluetooth. 5. you will suggest something hyper-simple and clever and i will be a happy man :)

any suggestions ? thank you in advance

Hi

HW SPI will not increase speed in all cases. One common cause for slow refresh is using something else than pure u8glib graphics functions inside the picture loop. In general you should place commands like AnalogRead() outside of the picture loop, store the result of AnalogRead in a global variable and draw the value of this global inside the picture loop. Same applies to all kind of calculation, which should also happen outside the picture loop.

Please paste your picure loop for further discussion.

Oliver

I have edited my post in some parts because it was unclear.

In my searches on the subject, I have read your advice about not interfering with the picture loop so I did exactly as you said.
my code is far from complete but already very long so ill paste a small part of it this is the main loop and some display fuctions.

void loop() {
  //main screen draw
displayMain();
if(btnOK()==true){
  //menu draw
 displayMenu(); 
}
analogWrite(2, analogRead(A0)/4);
updatePH();
relayToggle();
delay(1);
}

void displayMain(){
  u8g.firstPage();  
  do {
  u8g.setFont(u8g_font_baby);
    u8g.drawStr( 0, 5, "Aqua Control V2");
    u8g.drawLine(0, 7, 128, 7);
    u8g.drawLine(0, 56, 128, 56);
    u8g.drawStr( 0, 63, "Light   Air   Heat   Pump   CO2");
    u8g.setFont(u8g_font_7x14B);
    u8g.drawStr( 0, 20, "25.5c");
    u8g.setPrintPos(60,20);
    u8g.print("pH: ");
    u8g.print(pH,1);
    u8g.setPrintPos(0,40);
  } while( u8g.nextPage() );
}

void displayMenu(){
  while(!btnBack()){
  u8g.firstPage();  
  do {
  u8g.setFont(u8g_font_baby);
    u8g.drawStr( 0, 5, "Menu");
    u8g.drawLine(0, 7, 128, 7);  
 } while( u8g.nextPage() );
}
}

boolean btnOK() {
  int sensorValue = analogRead(A8);
  if((sensorValue > 880) && (sensorValue <900)){
  return  true;
  }
    return false;
}

it lacks optimization but the main concept is clear.
Im thinking on using digitalRead on the buttons (using 4 digital pins instead of 1 analog). maybe the button recognition will be more instantaneous because it has only high and low and it wont be busy waiting for the right analog read to match a button.

as you said in the issue comments that software spi is already fast,
but when I checked, hardware spi on the MEGA works 2-3 times faster than software SPI on the DUE.
even its faster, still buttons are misfiring.

from what i understand there is no stopping the picture loop,
I was hoping i could execute the draw function only when I need the screen to refresh,
but everything i tried the screen displays nothing.

but on the other hand the screen continue displaying what have been drawn (in normal operation) when i disconnect the data pins from the arduino, so im a little confused by that, because the driver does stores the data in its memory.

thank you on your advice and support!

displayMain();
if(btnOK()==true){
  //menu draw
 displayMenu(); 
}

This does not make sense, because displayMenu() will overwrite the output of displayMain(). You will never see the output of displayMain(). Maybe use a else clause here?

  while(!btnBack()){
  u8g.firstPage();  
  do {
  u8g.setFont(u8g_font_baby);
    u8g.drawStr( 0, 5, "Menu");
    u8g.drawLine(0, 7, 128, 7);  
 } while( u8g.nextPage() );
}

The code of btnBack() is not shown, but the code will force to redraw the screen with constant data. I think you could do something like this:

  if(!btnBack()){
  u8g.firstPage();  
  do {
  u8g.setFont(u8g_font_baby);
    u8g.drawStr( 0, 5, "Menu");
    u8g.drawLine(0, 7, 128, 7);  
 } while( u8g.nextPage() );
while(!btnBack())
   ;
}

This would at least improve the reaction time.

still buttons are misfiring.

I think this is mainly because of the missing debouncing. You should check for a transition from true to false of the btnOk() function.

from what i understand there is no stopping the picture loop,

At least, you should not jump out of the loop or terminate the loop. Still, you can decide not to execute the complete loop as long as nothing has changed.

Maybe it is worth to study this tutorial: https://code.google.com/p/u8glib/wiki/tmenu. Especially the part about code optimization (the use of the update variable).

Oliver

the idea of my code is to have buttons, and functions for them btnOK() btnBack() btnUp() ...in order to navigate the menu and interface they return true if the analog read matches a value within the values I declared

I know i need to debounce them, but even without the debounce it takes sometimes a 1-2.5 seconds to react if I hold it pressed sometimes it instantaneous.

what you said that doesn't make any sense goes like this: main loop: display the mainscreen if a OK button is pressed -> display and navigate menu and submenus until Back is pressed (if Back is pressed return to main loop)

the only difference in my method is that I have multiple picture loops and when Im navigating the code is "stuck" in the specific picture loop and nothing else happens

I have read the "tmenu" tutorial and it was very informative

The "tmenu" way is much smarter because you stay with one picture loop inside the main loop where everything continues to happen and it does not get "stuck" , and you are updating / changing the picture loop for your need.

I believe that using digitalRead() for the buttons will boost the response time a lot and be very fluid and consistent.

but there still a thing that annoys me and its this line:

analogWrite(2, analogRead(A0)/4);

this line of code receives a value from A0 that is connected to a photodiode divides it by 4 and writes it to a PWM pin 2 which is connected to a NPN transistor and it changes the brightness of LCD backlight.

and its slow.. the brightness change is not as fluid as I wanted it to be... one might say "who cares ?" but I want the screen BL to be fading in and out on some occasions. and it will never be fluid this way ..

so with all optimizations I suppose the interface speed will be acceptable except the screen BL fading

Just one question about running HW SPI on the due, i know it does not work, BUT when I tried to make it work and the screen was blank, even if it was not working, does the picture loop still fully executed ? does the arduino try to write to the screen full time or the code is ignored ?

Thank you very much Oliver !

I still think the performance problem is not because of U8glib. What I understood so far is, that your software must do several things in parallel: - Control Backlight - Read keys - Display a menu - Execute u8glib

These tasks have to happen in parallel, otherwise they will distrub and delay each other.

Just to check the performance, try the chess demo example. Or download M2tklib for U8glib and do some testing with the menues. The control of the backlight is a secondary problem. Solve the menu problem first.

Just one question about running HW SPI on the due, i know it does not work, BUT when I tried to make it work and the screen was blank, even if it was not working, does the picture loop still fully executed ? does the arduino try to write to the screen full time or the code is ignored ?

The low level procedures will evaluate to a nul function. The picture loop is still fully executed.

Oliver

What you can do is quite involved. Write some test sketches to Serial.print the microseconds taken by each group of parts of your screen writing. How long does it take to do

long ut1, ut2, du3;

........

ut1=micros();
lcd.print(".");
ut2=micros();
du3 = ut2-ut1;
Serial.print(du3);

ut1=micros();
lcd.print("....................");
ut2=micros();
du3 = ut2-ut1;
Serial.print(du3);

now, can you decide on a Q ms required response time of your switches and chop up your screen writing into parts which each take less than Q ms ?

I have just measured how much time it takes for my setup to print stuff.
but instead of using micros() I have used millis()

on arduino mega HW SPI
i have measured the loop time like this:

// at the top of the  loop
 int start = millis();
 // at the bottom of the loop
Serial.println(millis()-start);

those are the results :
Hello world example - ~40 millis that are about ~25 fps
just drawing a box on the whole screen - 50 millis that are about ~20 fps
Chess example mid game - 100 millis - ~10 fps
menu example redraw - 70 millis - ~14 fps
my menu redraw -70 millis as well…
my main screen - 240 millis - ~4-5 fps ← this is my problem

studying many u8glib examples I finally got what I was looking for… not redrawing (im a little slow … :sweat_smile:)
the problem is my menu tree is very vast and complex … some screens need refreshing and some don’t.

so I’m changing back to the DUE because except the picture loop it does :
temperature readings
pH reading
read keys
controlling backlight
switching relays
5 timers
and many more

just now on the mega, when barely anything is executing (even excluding the picture loop) the loop time is around 160 milliseconds …

hopping someday there would be HWSPI enabled on the st9720 on the DUE :sweat_smile:

Thanks for the help !

For sure, there is a plan to add HW SPI for U8glib... but currently i do not have much time for this project :roll_eyes:

Oliver