Arduino loop is slow

Hello there,

I have a sketch that i build for my lab power supply,
It uses LCD I2C 20x4 (Fransisco Malpartida), ADS1115 (soligen2010), and MCP4725(adafruit),

The void loop(), was so slow it is around 200ms, it is supposed to be fast especially on the ADC reading and DAC.

I have try to put the ADC reading and DAC on the interrupt, but it freezes the arduino

The code was attached…

Thanks for any help…

DigiPoLyDuLo.ino (23.4 KB)

Look at the top of topics for how to attach info. Look at #7.

It exceed the maximum 9000 character, so i attached it.

517 lines for a single function? And you wonder why its slow?

I think the first plan of attack is to restructure loop() so that it is a just a few calls to functions than
manage a single input or output, then try to figure out where all the time is going - you use several
libraries and some of them appear to be I2C, so will take a little time anyway, but some of them
may be blocking libraries, which could be an issue.

You want loop to only call other functions when those functions have actual work to do, so its important
that you have a quick way to check for work for each of the things you are managing.

I also notice you are doing 4 ADC reads in loop each with a lot of float computation.

Firstly why not round-robin those reads and do one per call to loop?

Do you need to use float arithmetic, its very slow?

You also seem to be updating the LCD display everytime round loop()?

Why not do that every half-second or so, much less processor heavy, much less flickering in the display...

But most of them are just logic and simple math, reading the adc and output it using dac (this one need to be fast), do some calculation, do some encoder things, call lcd menus function every 100ms.

What do you mean by blocking libraries?, sorry english is not my native language.

Round-robin, you mean by sequencing it per loop?, adc0 first loop, adc1 second loop, etc...,

Yep, float calculation is slow, but what is the other way to do this then?

Ehm, one thing, i've been trying to comment the float computation and lcd, just counting up and down (outputting triangle waveform probably) using the dac, and it seems to be faster, but it's still pretty slow i think, i can still see the fluctuation with my multimeter, i don't have a scope there, so can't really conclude confidently

A blocking library waits for the hardware to finish, rather than returning immediately after sending the request. Your key and encoder libraries might be doing debouncing by waiting, for instance.

Characterise the time each library call takes to see which is worst and work on that first. Remember you can call micros() twice and take the difference to get a time accurate to 4µs

Have'nt checked the encoder and keypad, my guess is the ADS1115 and LCD that is blocking library, gonna try to characterise the time tomorrow,it's night there, thank you in advance

You might check to see if this LCD library is faster: https://github.com/duinoWitchery/hd44780

re: floats v performance

Always consider if you can use long ints by ‘multiplying’ the input values, do your processing, then ‘dividing’ back down to get the result. There are several ways to approach this. Manually keeping track of the decimal precision. It’s always an order of magnitude faster than ‘floats on the fly’ ! Remember numbers are just numbers.

Well, my guess is right it's the ADC and the LCD, the float was pretty slow too, here is the time characterization of the function in my sketch's loop

LCD : 146828 microseconds 4x ADS1115 Reading : 10640 microseconds Float Computation : 1192 microseconds Keypad : 340 microseconds DAC : 176 microseconds Encoder : 12 microseconds (without any event, probably still same even when there is an event though) 1 Loop total : 159212 microseconds

I think i'll optimize the float computation using method that 'lastchancename' suggest and i'll try to change the LCD Library, there are pretty lots of lcd library on google, but it's pretty hard to find ADS1115 library other than Adafruit, any suggestions?

EDIT : I've try pert suggestion, and the LCD takes 87740 microseconds, and using lcd.clear() instead of deleting each row using space improve the timing to 43716 microseconds.

A majority of the used time is spent on the LCD. Reconsider what information and how frequently You display it. I once, 30 years ago, built a speed indicator to my car while the original was out of order and repairs were told to be costly. Updating the display every 500 mS felt like very good to me. Too less, jumping info, to often, an unneccessary flying and unreadable numbers.

Writing to the LCD probably puts the message into a buffer and interrupts handles the output of the message. But! If the buffer gets full the sketch will be hanging, waiting for free space in the buffer. What do You think?

my suggestion would be to only write to the LCD when you really have to, and only write to it what you really have to.

But still, if i write the LCD for every 500ms (or any interval else), there will always a time that the DAC slowed down by 43ms because of LCD.

Emm, did there any suggestion for the ADS1115, it's pretty slow too,

I have not anlyzed Your program deaply, only read Your report telling that LCD consumes a majority of the execution time. Read sensors, calculate, but display the results less frequently. You can probably inhibit some sensor work that happends more often than twice per second. Why read and calculate data more often then they can be read?

figoarzaki:
But still, if i write the LCD for every 500ms (or any interval else), there will always a time that the DAC slowed down by 43ms because of LCD.

That’s where the advice comes in to only write what’s changed to the LCD.

You can also split up your writes: Write some data, do other stuff, write some data, do other stuff, etc.

You know tings I don't know. Your first issue was to cut down 200 mS of loop time. I don't understand how "43 mS" can be an issue. I hope You don't call LCD during a loop for several ADC. Perform the maintaining work, calculating outputs, read inputs when it's needed, and display data when they can be observed. Divide the display update in two parts if that would help.

Go to a cortex M0 :D. Especially for all the ADC reads and calculations.

pert: That's where the advice comes in to only write what's changed to the LCD.

You can also split up your writes: Write some data, do other stuff, write some data, do other stuff, etc.

Probably this will increase the performance, gonna try it, Did increasing the I2C frequency will make it faster?

Or do you have a faster I2C library?

Railroader: You know tings I don't know. Your first issue was to cut down 200 mS of loop time. I don't understand how "43 mS" can be an issue. I hope You don't call LCD during a loop for several ADC. Perform the maintaining work, calculating outputs, read inputs when it's needed, and display data when they can be observed. Divide the display update in two parts if that would help.

43ms will still be an issue, because the power supply needs to react fast on short circuited load,

The best way is using interrupt, but when i call DAC on interrupt the arduino freezes, Timer1 interrupt and 1000 microseconds. Any idea why?

wolframore: Go to a cortex M0 :D. Especially for all the ADC reads and calculations.

Definitely will go faster, but it's not a good solution, because the pcb already use atmega328 footprint....

My knowledge is small regarding interrupts, timers, internal registers. Sometimes various libs use systemfunctions like this. Double use of the same resource leads to trouble. Maybe a more experienced member can comment the use of interrupt, Do Yoi need to do all AD readings in every turn of loop? Can they be iffed regarding to what You are displaying for the moment? My guess….