I'm trying to set up my code so that when a button is pressed some code runs and then some data is sent to an OLED screen. I noticed that the send-to-screen operation is really slow (about 200ms) and that during this time the arduino can't pick up any other input, thing that really breaks my project as it needs to be responsive and I don't want it to ignore inputs.
I read about the Interrupt function and I'm still learning it, but this function only works for some set pins, must be given to every piece of my code except the send-to-screen and I'm not sure about how implement it when a function calls another function that still have to be higher priority than the send-to-screen.
What I would like to do is something like this:
A button is pressed, data is generated and the send-to-screen process starts.
During the send-to-screen process, a button (the same or another) is pressed.
The arduino must pick up this input, the send-to-screen process have to be interrupted and the code associated with this button have to be processed.
If this code calls on another code or function, this has to be processed before the arduino returns to process the send-to-screen operation.
Basically, the send-to-screen operation have to be processed only if the arduino has no other things to do, as a low priority process. How should I do it?
Can you take a few steps back and describe what you are really trying to do? I think your problem is you've not yet learnt to write proper non blocking collaborative code. I would not expect loop to take more than a few milliseconds at most to go round once and I would not expect to have a problem with the priority of tasks.
You said:
... instead of the classic void loop.
That sets alarm bells ringing. 'classic void loop', the use of the word 'void' hints to me that you don't know what it means. The use of the word 'classic' is meaningless, what do you mean by 'classic'?
There is a lot of code posted here by beginners (understandable) and examples (written by people who should know better) that puts everything in the loop function (if you'd said 'loop function' I'd be more comfortable) and contains blocking code that means the loop function takes anything from hundreds of milliseconds to hundreds of seconds or even hundreds of minutes to go round once. If that's what you mean by 'classic' it's wrong and leads to bad code that is not responsive and with things not happening when they need to.
It would help if you posted a simple example of something that doesn't work the way you want coded with what you consider to be a 'classic void loop'.
Long blocking times for display updates are common.
Sadly true for a lot of library code. I was impressed with the capabilities of U8g2, but it takes far too long to update a display. I see there is an option to only update part of a display, so should be able to split the updates into smaller chunks. Next thing to play with...
I'm trying to make the arduino generate some data, giving some commands like doing math, getting inputs from buttons and other and send part of this data to a screen. The problem is that sending to screen some data requires about 200ms during which the inputs like the pushing of a button aren't picked up by the arduino. I want the process of sending the data to the screen to not interfere with the other tasks. This process should be done only if there are no other things currently going on.
Yes, you are right. I'm really new to arduino but I don't like the loop function that keeps going from top to bottom on the code and I find it really complex to debounce buttons. So I searched for and found that there are some library (I'm using the one I linked) that lets you code in an event-driven manner and debounces automatically the buttons without using delays.
*"*The use of the word 'classic' is meaningless, what do you mean by 'classic'?"
I mean the way which you start coding when you are a beginner. You start Arduino IDE, set some code in the Setup and then run some other code in the loop.
jimLee:
Long blocking times for display updates are common. 10x longer that you are seeing is not uncommon. I had one that was 5 sec. to update.
If you could break your update into "bite size chunks'. Letting them be picked off during idle time, that may help.
I thought it was really quicker than this seeing some videos online.
Mh, break the update? Nothing come to my mind as the way it should be done, and same goes for the picking part.
As for the libraries, I didn't know so I'll try to search for some others, but even though the waiting time could be less, it still blocks other input (I think), so I'm not sure it will be a solution
The problem is that sending to screen some data requires about 200ms during which the inputs like the pushing of a button aren't picked up by the Arduino. I want the process of sending the data to the screen to not interfere with the other tasks. This process should be done only if there are no other things currently going on.
If it takes 200ms then it takes 200ms, you can't fix that by wrapping some magic code around it. If 'nothing' is going on and the display update starts then 1ms into the update someone presses a button then the button is not going to be seen for at least 199ms. You have to fix the slow display update. As I hinted u8g2 has the ability to only update part of the display, if you can take advantage of that and only update the bits that need updating then you solve your problem. What are you using to update the display? Does it allow you to only update parts? What interface are you using (serial, I2C, SPI, something else)? Soft or hardware? you need to fix the slow display update, not try to work around it. My 64x128 OLED display takes about 40ms to update using I2C at 400kHz. An SPI display would probably be faster but I don't have one.
Study the examples and others and learn from them, but for now fix the slow updates.
It sounds to me like the issue is that, by adopting this all-in-one library, you now, instead of working on your own issues, are debugging deficiencies in their library. Not an uncommon position to end up in.
Maybe a better approach would be to find smaller libraries that solve the specific issues you want solved. IE a debouncing library, a screen library a timer library what have you. This way you are "closer to the hardware" and have more options when issues come up.
PerryBebbington:
If 'nothing' is going on and the display update starts then 1ms into the update someone presses a button then the button is not going to be seen for at least 199ms.
The function "Interrupt" (at least for the little I know) can actually interrupt that process, make a task and then go back to the interrupted function. I would use it if it wasn't for the fact that only some pins can do that and that this way I should place interrupts everywhere except for the sending to screen.
"You have to fix the slow display update"
Ok, I can try this. If I get to 40ms like you it will probably be good. "What are you using to update the display?"
I'm actually following a guide online, it made me use adafruit library, these one: SPI.h, Wire.h, Adafruit_GFX.h, Adafruit_SSD1306.h. "Does it allow you to only update parts?"
I don't think so, but I'm reading some documentation now. "What interface are you using (serial, I2C, SPI, something else)?"
Sorry, I forgot to say it, it's i2c. "Soft or hardware?" I don't know what you mean, sorry.
jimLee:
It sounds to me like the issue is that, by adopting this all-in-one library, you now, instead of working on your own issues, are debugging deficiencies in their library. Not an uncommon position to end up in.
This library is just for event-driven coding and debounce, the screen library are from adafruit
ariesbreath:
Basically, the send-to-screen operation have to be processed only if the arduino has no other things to do, as a low priority process. How should I do it?
If send-to-screen is slow, then you are looking at finding another library or somehow breaking it up into chunks. Maybe sens one line at a time.
Since you are using this "eventually" thing, you would turn sending a line into an eventually task. You'd have an 'always' task whose job is "if I have characters to send to the OLED, send them. Or send some of them, maybe". Perhaps it would have an array of characters matching the OLED, and a 16-bit value for each 16-character row with 'dirty' bits. (to find the leftmost 1-bit in v, use v^(v-1))&~(v-1) ... something like that. To find which bit that is, & that bit with FF00, F0F0, CCCC, AAAA )
Your other listeners would write to the OLED by calling a method on the OLED task object to queue up some stuff in the buffer.
A refinement might be to tell Eventually that rather than always running the OLED task, it should do so once every (say) 100ms.
The key is - you don't need the OLED write to be instantaneous, you need it to be faster than the duration of a user buton-press.
assuming your display size is 128x64 which is common for the SSD1306 OLED, and it's monochrome, meaning one pixel is 1 bit, and an I2C speed of 400 kHz, you can presumably update the display in around 20 ms plus/minus 1ms for overhead. This would mean using the hardware I2C where you send the I2C_MASTER_WRITE_ADDRESS, maybe one or two command/address bytes, and the 8192 bits for display data. This of course assumes that the display data is already buffered in SRAM and all you need to do is send it in a single I2C transaction.
I'm sure there are improvements that can be done on the wire library if you are writing/improving it specific to your MCU. I've seen some I2C libraries where each byte is sent as a single I2C transaction which would incur overhead that is unnecessary since the SSD1306 controller support a single transaction for 8192 bits of display data
jimLee:
It sounds to me like the issue is that, by adopting this all-in-one library, you now, instead of working on your own issues, are debugging deficiencies in their library. Not an uncommon position to end up in.