[Solved] u8g Workaround for u8g picture loop?

Hi all, this is my first time using this forum so go easy, please.

I have an engineering capstone project for school, and I am making an instrument cluster for a vehicle that also logs data (the recording toggles on/off). I am using one 128*64 graphic LCD with an ST7920 backpack with the u8g library (also the Mega). When running, this device is supposed to log data and display it simultaneously (or..close to. I expect the LCD to lag a bit). Everything works very well, but I have a problem:

The arduino is supposed to write data to the SD card every 70ms, but the main loop of the program waits for the do..while picture loop (the one which displays the data on the LCD) to finish, causing the SD logging to lag significantly. While waiting for the picture loop to finish, the average save time between entries is 220-290ms. Now, the LCD does not have to update every 100ms. The fastest I expect it to update is around 2-3 times per second.

Now the way I see it, there are two ways around this:

1. Decrease picture loop time: The only way I can think to this is to connect the LCD in parallel mode instead of over SPI. I feel like the parallel connection would be faster, but I'm not sure because I have not had any experience comparing the two. Would it help? This also brings up another issue I've had:

a.How do I wire the ST7920 in parallel? I have followed a guide online as well as the helloworld example in the u8g library with the wiring perfect, and the display turns off (it also turns the arduino off and disconnects it from my computer) when the switch is flipped to PSB_ON (LPT). Does anyone have any knowledge or suggestions about this they are willing to share? I just cant get the damn thing to work in parallel mode, nor have I been able to find a hookup guide to use the LCD without a backpack.

2. Isolate the savedata-loop from the display-loop: When commenting out the picture loop, the logger writes an entry on the SD card every 70ms as it should. Nothing wrong here. This is how I concluded that it must be the picture loop working over an SPI connection that slows the entire system down. I have looked a bit on the forums and a few other places and it just seems impossible. Also, a lot of people say "go read blinkwithoutdelay and figure it out", but using a time-interval dependent structure doesn't work either because the picture loop still just takes its sweet time. Anyway, I cannot seem to find a way around this. I also read about the scheduler library, but it doesn't seem like it would help, considering the picture loop (correct me if I'm wrong). I feel like this is the more dependable option, so any suggestions on how to handle these two items independently would be fantastic.

Here is the general structure of my code (don't wanna post the 200+ lines):

void loop()
{
   if(recordstate == true)
   {
      if(time - prevtime >= interval)
         {
            if(!SD.exists(filename))
            {
               createfile();
            }
          writedatatocard();
       }
   }


u8g.firstPage()
do
{
   displaydata();
}while(u8g.nextPage());
}

Sorry for the lengthy post everyone, just wanted to try to get all the details and thoughts in. I really appreciate you taking the time to read this. This has been a frustrating situation just because it is so close to working as I imagined it. Any help is greatly appreciated.

Cheers,

Nick

Hi

There is a third option: Write within the picture loop.

u8g.firstPage()
do
{
   displaydata();
   write_to_sd_if_required();
}while(u8g.nextPage());

with

void write_to_sd_if_required(void)
{
      if(time - prevtime >= interval)
         {
            if(!SD.exists(filename))
            {
               createfile();
            }
          writedatatocard();
          prevtime = time;
       }
}

Oliver

Oliver,

Thanks for your very quick reply. I tried your idea, and it is working much closer to my expectations, though it still has subtle pulsations in the data stream. This concerns me because it makes me think the pulses would become more separated when I push more data to the LCD. Right now, I am only displaying G-force, but I also need to display speed, RPM, CVT ratio, etc. Would you have any idea how to reduce the pulsation?

Also, I have been having problems with distortion on my LCD. This is strange because I am giving the LCD 500ms to update, which seems like more than enough time to update clearly. I feel that I have had it updating faster and with more clarity in previous programs. Again, this may not be an issue if my LCD would work in parallel mode, as it should. Do you have any suggestions on how I could reduce this distortion? (I will post a photo).

Here is my current code:

void Record(void)
{
  savetime = millis();
  {
      saveprevtime = savetime;
         if(!SD.exists(filename))
        { 
           createfile();     
        }
   writedatatocard();
  }
}


void loop()
{
    displaytime = millis();
    if(displaytime - displayprevtime >= displayinterval)
       {
          displayprevtime = displaytime;
          u8g.firstPage();
          do
          { 
             displaydata();
             if(Rec == true)
               {
                 Record();
               }

            }while(u8g.nextPage());

Thanks again Oliver, I really appreciate your support.

Cheers,

-Nick

You may and should use a timer interrupt for your writing function. If you do that, it will pause/interrupt the picture loop if necessary and continue afterwards. Just make sure that the interrupt does noch change variables used within the picture loop.

@Nick:

You have introduced another delay for execution of the picture loop. However sd writing is still done inside the picture loop. This means, that sd writing will be only during display refresh. Maybe you want to call "record" also from outside:

    displaytime = millis();
    if(displaytime - displayprevtime >= displayinterval)
       {
          displayprevtime = displaytime;
          u8g.firstPage();
          do
          {
             displaydata();
             if(Rec == true)
               {
                 Record();
               }

            }while(u8g.nextPage());
        }
    else
    {
        // additional sd writing if the display is not refreshed.
             if(Rec == true)
               {
                 Record();
               }
    }

your second problem (corrupted display) might be caused by updated variables during the picture loop. You have not posted the code how you obtain the xyz values, but remember: All variables must be constant during the picture loop. This means any analog read must happen outside the picture loop.

Oliver

Oliver,

Thank you for bringing the variables to my attention. I never would have thought of them updating and being written simultaneously. I moved the statement that reads from the accelerometer into the display update so that it only reads data from it once when it is time to update the LCD. The readings on the LCD are clear now, but unfortunately, this also means the accelerometer’s resolution is reduced, now only updating once every 5-6 counts instead of every count (which would be the ratio of the save frequency to display frequency). I have tried including the accelerometer read function other places to help increases the sampling frequency, but it always produces distortions on the lcd. As for the other issue with the pulsating datastream, it sort of worked. I tried your suggestion of including it in an else{} statement, and it reduced the severity of the pulsation, though it did not eliminate it. I’d really like to reach uniformity with the intervals, but it may have to just be something I have to live with. I analyzed some of my save data, and you can easily see the variation in the sampling times (you can take a look in the attached image). Perhaps this is because the two time intervals have an overlap which creates a slight delay between the samples. Ideally, a uniform sampling frequency would be preferable, but I don’t know what else I could do to achieve this. I may have to settle. Thanks for your suggestion, Oliver. It seems that every change of this project brings its own tradeoff.

Fruchti, I tried your suggestion and I had no luck with the timer interrupts. When the recording was toggled on, it would only write 2-3 lines of data to the SD card. I have no idea why that is, but it was worth a try anyway. Thanks for the suggestion.

Here is my current code, though it’s basically the same as Oliver suggested:

    displaytime = millis();
    if(displaytime - displayprevtime >= displayinterval)
    {
      accel.read(); //The accelerometer is read when the display updates
      displayprevtime = displaytime;
      u8g.firstPage();
      do
      { 
        displaydata();
        if(Rec == true)
        {
          Writedata();
        }
        frame(); //This draws a short separation line
      }while(u8g.nextPage());
    }
    else
    {
      if(Rec == true)
      {
        Writedata();
      }
    }
}

The readings on the LCD are clear now, but unfortunately, this also means the accelerometer's resolution is reduced, now only updating once every 5-6 counts instead of every count (which would be the ratio of the save frequency to display frequency).

You could still read more often, but maybe you should keep the variable constant from which the display is refreshed: Introduce another variable for the display, which is a copy of the analog input value. Do the analog read as often as you want to increase resolution, but copy the analog value to the variable for the display outside of the picture loop.

Oliver

I’ll try your suggestion and reply to this post if I have any significant success. I appreciate your support in this project. Thanks, Oliver.

Cheers,

Nick