Way to improve processing speed while displaying lcd output

Hi,

i am currently working on a project (see: http://forum.arduino.cc/). It is basically a laser tag game with all in one markers.

My repository with pictures is located here: GitHub - regnets/Lightduino: A Lightstrike compatible arduino sketch for your own Laser Tag System

So far everything works fine, the only problem i have are the slow display updates.

I am using an SSD1306 I2C OLED. I am updating only the display i an update is neccessary (i.e. something changed). However the display output takes about 170ms. My normal tick time without refreshing the display is 2-3ms.

Is there a way to thread the display output? I don't care how long it will take to refresh the display, it is more important that the main loop is able to recognize hits by ir signals.

I already thought of offloading the display output to another arduino, however i don't know if this will fix my problem...

Any help is appreciated.

Cheers

regnets

Well, many or most of us are not enthusiastic about ferreting through your repository to find the code. How about citing it here (I know you know how to - is it what you posted here)?

I am sure you could - and should - thread the display code, it just means you have to unwind the library yourself and turn it into a state machine using only the individual I2C calls.

That chip can take I2C at 400KHz so you can up the speed of that interface for a 4 times speed up.

You could also use the SPI interface and that would be even faster.

Paul__B:
Well, many or most of us are not enthusiastic about ferreting through your repository to find the code. How about citing it here (I know you know how to - is it what you posted here)?

I am sure you could - and should - thread the display code, it just means you have to unwind the library yourself and turn it into a state machine using only the individual I2C calls.

Thank you for your positive critic. I didn't want to quote my source code because i thought there is no specific problem with the source code. I need some general advice, because i searched a lot about threading display output on an arduino but i couldn't find any general explanation on how to do it.

So based on you answer i think there is no threading solution on one arduino.

Could you please explain me what do you mean by state machine? I am currently only updating the display if an update is neccessary.

void refreshDisplayValues() {
	if (updateDisplay == true) {
		updateDisplay = false;

		u8g.firstPage();
		do {
			u8g.setFont(u8g_font_6x10);
			u8g.setPrintPos(0, 10);
			u8g.print(teams[currentTeam].name);
			
			String temp = markers[currentMarker].name;
			u8g.setFont(u8g_font_5x7);
			u8g.drawStr(6, 25, F("Charges"));
			u8g.drawStr(78, 25, F("Energy"));
			
			u8g.setPrintPos((128 - ((temp.length() * 6) + 1)), 10);
			u8g.print(temp);
			u8g.drawStr(34, 62, F("Hit by "));
			u8g.setPrintPos(69, 62);
			u8g.print(hitByName);
			u8g.setFont(u8g_font_9x15);
		
			if (markers[currentMarker].type == 'P') {
				u8g.setPrintPos(14, 38);
				u8g.print("o");
				u8g.setPrintPos(21, 38);
				u8g.print("o");
			} else {
				u8g.setPrintPos(0, 38);
				u8g.print(currentCharge);
				u8g.drawStr(18, 38, "/");
				u8g.setPrintPos(27, 38);
				u8g.print(markers[currentMarker].charges);  
			}

			u8g.setPrintPos(60, 38);
			u8g.print(currentEnergy);
			u8g.setPrintPos(87, 38);
			u8g.print("/120");
		} while (u8g.nextPage());
	}
}

Grumpy_Mike:
That chip can take I2C at 400KHz so you can up the speed of that interface for a 4 times speed up.

You could also use the SPI interface and that would be even faster.

Thank you for your answer, thats a really good hint. I wasn't aware that i am able to speed up the i2c connction. I will have a closer look at the u8glib and if it possible with my current setup.

Cheers

regnets

Hi, I would advise against trying to thread the display code, this would be a nightmare and is not the right way to tackle the problem.

This is a classic "real time" processing problem where you need to respond quickly to something while a slow task is being executed. This simplest approach in your case is likely to be to use interrupts. I have not looked at your GitHub code in detail but I think you should either:

  • Use 2 interrupts, one on the trigger to fire an IR blast and one on the receiver input to detect the start of an IR receive signal. The receive interrupt should have priority, otherwise pulling the trigger will stop a hit from someone else being recorded which is a bit unfair!
  • Use a periodic timer of say every 2 or 3 milliseconds to poll the trigger and receiver.

The first is the better way forward but if you are not so familiar with interrupts there are some gotchas that can catch out newbies. I have used both approaches successfully, for example to read an analogue port at 100kHz using a timer interrupt and still update a TFT display in the loop().

regnets:
So based on you answer I think there is no threading solution on one Arduino.

On the contrary, that is what programming microcontrollers is all about.

regnets:
Could you please explain me what do you mean by state machine? I am currently only updating the display if an update is necessary.

A state machine is code that cycles rapidly through the main loop(), never waiting for an individual action to occur.

State variables are switches that enable sections of code as the loop() is traversed. Those code sections set the state variables to determine the next appropriate action on the next traversal through the loop, so that only one step at a time is ever executed. So one step would be to load the I2C hardware with a command, then the following step would be to check whether that command had been executed, only moving on to the next step on completion, otherwise falling through to other tasks in the loop(). You cannot "while()", you can only "if()".

The supplied libraries are generally not written for multi-tasking, though some have this functionality such as Serial.available().

With all that TFT code, you would have to break it up so that each of your lines became a single step in the state machine, with a case statement executing one after the other on successive loops, the delay in response would then be limited to the slowest function call. But if that slowest function call is acceptable, then that would work just fine.

I really think you really should focus on the interrupts, since it's the cleanest approach, easy readable and you can rely on the fact, that your critical code is executed in a 3ms cycle.

State machines tend to add complexity (and also generate more CPU load) which should always be avoided and besides that, I don't think this pattern will help you here. You say the refresh takes 170ms. That is really a lot. Assuming that the given code is your complete display refresh code, your state machine would only be allowed to execute 1 or 2 lines each loop()-cylce of the code to respect that 3ms interval.

One optimization you may do to save a few ms:
Only redraw areas on the display that change. Things like "Charges" or "Energy" don't need to be redrawn every cycle.

thomai:
I really think you really should focus on the interrupts, since it's the cleanest approach, easy readable and you can rely on the fact, that your critical code is executed in a 3ms cycle.

State machines tend to add complexity (and also generate more CPU load) which should always be avoided and besides that, I don't think this pattern will help you here. You say the refresh takes 170ms. That is really a lot. Assuming that the given code is your complete display refresh code, your state machine would only be allowed to execute 1 or 2 lines each loop()-cylce of the code to respect that 3ms interval.

One optimization you may do to save a few ms:
Only redraw areas on the display that change. Things like "Charges" or "Energy" don't need to be redrawn every cycle.

Ok, i think i will use two interrupts as you described.

I already tried to draw only items which contains new data. However then the other static data is removed from the display. I will have a closer look at this too.

Thank you very much so far.