I2C LCD Display Timing Issues

Hello everyone,

i want to run some parallel tasks on an Arduino Mega. I know the ATmega is a single Core chip, so real Parallel working processes are not possible. So i created a Timeslice sketch. Basically every element of an Array of Integer (called Counters) will be decreased by an Interrupt Service Routine. The ISR is Triggered by a Timer Interrupt every 2,5 ms. If the counter of the timeslice is less than 1 the determined piece of code will be executed and set the counter to a Value. Thats the Basic Concept of my Code.

So the Timeslice with the longest Duration is the limiting Factor. All other Timeslices have to run in a greater or equal Timedistance otherwise a new instruction should be executed during the Processor is working on the last Timeslice.
To adjust the Timing i measured the time for the Execution of each Timeslice (comment in the loop function) .
The Measurement works fine with all timeslices except the Timeslice for the LCD Display.

That is my fist Question: If i print out the Duration (end-begin) i got a negative value. i don’t know what is the reason for that. The result was -33000. I took the Absolut Value of that and thought that the Duration is 33ms.
I can’t explain that, maybe a reason could be that the I2C Library uses delay and delay Microseconds to controll the LC-Display. It would be nice if you would tell me some ideas what is causal for that.

The second Thing is that the LCD Timeslice is just a nice to have Feature and not important for my Project. The second longest timeslice is the Ethernet bus with 13 ms. Because of the long duration of the LC-Display i can’t listen faster to the Ethernet Bus, what is very important for me.

Do you have some ideas to solve my Problems?

Thank you in advance!

i have shorted the code a little bit, so please do not wonder about missing declarations and suff like that.

#include <Arduino.h>
#include "Ethernet2.h"
#include "SPI.h"
#include "LiquidCrystal_I2C.h"
#include "Wire.h"

void TIM1_callback();	
void printlcd();
//End of Auto generated function prototypes by Atmel Studio


byte mac[] = {0xA8, 0x61, 0x0A, 0xAE, 0x2F, 0xAB };
IPAddress ip(192, 168, 178, 177);
//IPAddress myDns(0, 0, 0, 0);
IPAddress gateway(10, 11, 141, 254);
IPAddress subnet(255, 255, 255, 0);

MCP3304 adc(49);
EthernetServer server(23);
SCPI_Parser Ultracap_Solution;
LiquidCrystal_I2C lcd(0x27,16,2);
Ultracap C1(39,8,3.519,1); //Constructor(bleeding Pin, Temp Pin, Factor Pos, Factor Neg)
Ultracap C2(41,9,7.829,3.519);
Ultracap C3(45,10,11,7.829);
Ultracap C4(43,11,15.705,11);


int counters[NO_COUNTERS];
bool Displaystatus = false;
int begin = 0;
int end = 0; 
void setup() {
	pinMode(17, INPUT);
	pinMode(SS,OUTPUT);
	Ethernet.begin(mac, ip);//, gateway, subnet);
	server.begin();
	lcd.begin();
	Serial.begin(115200);
	Timer1.initialize(1000000UL/INTS_PER_SECOND); // Timer Interrupt every 2500µs -> 400 Ints per Second...
	Timer1.attachInterrupt(TIM1_callback);
	for (byte i = 0; i < NO_COUNTERS; i++)
	{
		counters[i] = -1;
	}
}
void loop() {
	if (counters[Ethernet_Bus] < 1) {
		counters[Ethernet_Bus] =15;  // around 13.15ms
		EthernetClient client = server.available();
		if(client){
			Ultracap_Solution.Execute(client);
		}
	}

	if (counters[Volts] < 1) {
		counters[Volts] = 10;// around 800µs
		Akt_Vol();
	}
	
	if (counters[I2C_Display] < 1) {
		begin = micros();
		counters[I2C_Display] = 100; //around 33ms
		printlcd();
		end = micros();
		Serial.println(end - begin);
	}
	if(counters[Cap_Temps]<100){
		counters[Cap_Temps] = 80;// around 3 ms
		Akt_Temp();
	}
	if(counters[Taster]<1){ 
		counters[Taster] = 2; //knapp 1 ms 
		if((PINH & 0b00000001) == 0b00000001){
				Displaystatus = !Displaystatus;
			
		}
	}
}
void TIM1_callback()
{
	byte i = 0;

	for (i = 0; i < NO_COUNTERS; i++)
	{
		if (counters[i] > -1)
		counters[i]--;
	}
}

void printlcd(){
	if(Displaystatus==HIGH){
	lcd.setCursor(0,0);
	lcd.print("Vol1=");
	lcd.print(C1.Get_Voltage(),2);
	lcd.setCursor(0,16);
	lcd.print("Vol2=");
	lcd.print(C2.Get_Voltage(),2);
	}
	if(Displaystatus==LOW){
		lcd.setCursor(0,0);
		lcd.print("Temp1");
		lcd.print(C1.Get_Temperature());
		lcd.setCursor(0,16);
		lcd.print("Temp2 ");
		lcd.print(C2.Get_Temperature());
	}
}

void Akt_Temp(){
	C1.MeaTemp();
	C2.MeaTemp();
	C3.MeaTemp();
	C4.MeaTemp();
	}

I suspect you are using an Arduino with 16-bit ‘int’. That will overflow in 32.768 milliseconds worth of micros(). All millis() and micros() variables should be ‘unsigned long’ and not ‘int’.

Thank you for the tip, that was the reason for the negative Times.
But that doesn’t matter in terms of my main Problem with accelerating the controlling of the LC-Display.

Now that you are getting valid timing numbers, how many microseconds does it take to update the LCD? How much of that time is in the ‘.Get_Voltage()’ and ‘.Get_Temperature()’ functions? Do you really need the LCD to update every 33 milliseconds (30 times a second)? I would think that 500 milliseconds would be frequent enough, especially if the time spent updating the LCD is causing other tasks to be delayed.

I’m very confused by your timer numbers.

    counters[Ethernet_Bus] = 15; // around 13.15ms
    counters[Volts] =        10; // around 800µs
    counters[I2C_Display] = 100; // around 33ms
    counters[Cap_Temps] =    80; // around 3 ms
    counters[Taster] =        2; // knapp  1 ms

I can’t figure out how 2 counts is 1 millisecond but 10 counts is 0.8 milliseconds??? And how is 100 counts == 33 milliseconds but 80 counts is only 3 milliseconds???

There is a fork of the freeRTOS library optimized for the avr architectures like the Mega. It might be worth a look.
https://github.com/feilipu/Arduino_FreeRTOS_Library