The Muti-tasking Arduino

I have always wondered that if a Arduino board, such as a Mega, could do TWO things at a time, such as play music on a speaker and display words on a lcd. Imagine the possibilities if the Arduino could muti-task! :slight_smile:

Please share your comments about this idea.

Certainly the hardware is capable of threading or multi-tasking.

That behavior is usually considered as an operating system feature and the Arduino libraries provide a simpler "way of looking at the world". There are a few task scheduler libraries that provide something close to what you want and they are more practical on the ARM processors with more speed and memory.

Threading or multi-tasking does bring out the need for coordination between activities so that shared resources can be used. Semaphores or other mutual exclusion methods are common solutions but this brings in the need for more speed and memory.

The Arduino libraries attempt to bring us closer to the "bare metal" concepts and do not do much to prevent the problems that multi-tasking would bring. Their simplicity is their strength but it also a weakness when applications multi-task. This is probably beyond the scope of the standard Arduino libraries but, as this is all open source, there is nothing to prevent you from solving them in your application or running Linux or some real-time OS.

If you wanted to do multiple activities exactly at once you might need to use a processor with multiple processing cores or else use separate processors.

Then do Arduino boards only have 1 core? And plus, I also wondered if arduinos could really muti-task, how would you program each core?

Then I wondered how Microsoft programmed each core of the cpu. Sometimes, they have so many cores, and since they used modern-day technology, computes have 32GB ram!!! While other computers only have 1 or 2 cores and 1 or 2GB, they are so slow.

If somehow, we find a bug that enables us to muti-task the Arduino, or the Arduino team makes a Arduino with multiple cores, this would be my idea:

If an Arduino has two cores, then we could have two tabs, one for each core. etc.

Then do Arduino boards only have 1 core?

Yes.

if arduinos could really muti-task, how would you program each core?

You don't need multiple cores to do multitasking - Arduinos can multi-task.
Multi-tasking and multi-processing (or parallel processing) are different things.

computes have 32GB ram!!!

Pfffft. Mine has 64GB. (Is that worth six exclamation marks?)

If somehow, we find a bug that enables us to muti-task the Arduino,

What kind of "bug" is going to enable multi-tasking on an Arduino? As already explained, Arduinos are perfectly capable of multi-tasking. Multi-tasking does not require multiple cores.

If an Arduino has two cores, then we could have two tabs

Non sequitur. If you're talking about tabs in the IDE, the IDE runs on the PC and can have as many tabs as you like and that has nothing to do with the number of cores in the PC's processor.

Pete

IMNSHO, it would be nice to have an Arduino board that ran a multitasking OS that was somewhere between the "bare metal" AVR and ARM chips, and the Linux-running Yun/etc.
Sort of like the MSP432 TI Launchpad will run TI-RTOS to multitask Arduino "loop" functions. (I wonder how that's going, anyway? I haven't been paying attention.)

Unsigned_Arduino:
I have always wondered that if a Arduino board, such as a Mega, could do TWO things at a time, such as play music on a speaker and display words on a lcd.

That doesn't require multi-tasking. I could program a basic UNO to play music on a speaker, print the lyrics on an LCD, flash LEDs in time to the music, and control a set of servos to dance to it all at the same time. I don't need any multi-tasking OS to do all of that. Just careful use of non-blocking code.

Just careful use of non-blocking code.

Which ... is a form of multi-tasking (perhaps the simplest, but still a form.)
It might turn out to be more difficult than you think - perhaps that LCD code is full of "short delays" because the LCD chip is slow, or uses I2C, or something, that you wouldn't normally notice, but are long enough to interfere with your music-playing... "Just re-write all the LCD and I2C libraries!" - right.

Any examples? :slight_smile:

That is considerd muti-tasking.

But I was thinking of like adding 2 numbers at the same time, timer and game.

Any examples? :slight_smile:

Look at the top of the Project Guidance board. There's a whole thread full of example. Don't be afraid to look around the site and do some reading.

Example:
parseGetline_nb() is a non-blocking function that parses a line of text from the serial port (with rubout/etc)
delay_without_delaying() is a non-blocking wrapper around checking millis() for a timeout.
The loop blinks an LED and reads the serial port "at the same time"...

void loop() {
  char *p;
  int8_t cmd;
  int n;
  if (parseGetline_nb()) {
    do {
      enum {
        CMD_RED, CMD_GREEN, CMD_BLUE, CMD_RESET  // make sure this matches the string
      };
      cmd = parseKeyword(PSTR("red green blue reset")); // look for a command.

      if (cmd >= 0) {
        n = parseNumber();
      }
      switch (cmd) {
        case CMD_RED:
          red = n;
          break;
        case CMD_BLUE:
 /// etc
        case CMD_RESET:
          red = green = blue = 0;
          break;
        case PARSER_EOL:
          Serial.print("RED = "); Serial.print(red);
          Serial.print(" GREEN = "); Serial.print(green);
          Serial.print(" BLUE= "); Serial.println(blue);
          break;
        default:
          Serial.println("Invalid command");
          break;
      }
    } while (cmd >= 0);
    parseReset();
    Serial.print(F("Enter command: "));
  } // if line
  
  static int ledstate = false;
  if (delay_without_delaying(ledtime, 500)) {
    ledstate = !ledstate;
    digitalWrite(13, ledstate);
  }
}

westfw:
It might turn out to be more difficult than you think - perhaps that LCD code is full of "short delays" because the LCD chip is slow, or uses I2C, or something, that you wouldn't normally notice, but are long enough to interfere with your music-playing...

Bulls eye! I had to modify huge parts of the LCD595 library to speed it up. Otherwise time spent displaying the information was slowing down the program so that it wasn't able to do other tasks. Changing digitalWrite to direct register writes (at the price of loosing flexibility of pin selection) did the trick.

Bzdurek:
Bulls eye! I had to modify huge parts of the LCD595 library to speed it up.

Most all of the libraries you find out there are written by other hobbyists and some of them are good at it and some are not. If LCD595 does what I think it sounds like it does then I have a suggestion to make it lots lots faster. You can run a 595 shift register off the SPI hardware. Since the LCD isn't going to send any responses back to you, you don't have to worry about receiving. You just need a send buffer and the interrupt off of SPIF in SPSR to keep loading out bytes. It takes a few clock cycles to fetch the next value and load it into SPDR and return. Not only are you talking super fast to the LCD, but the rest of the program isn't being blocked while you do the transmission. I've got a blocking version of a library like that already, let me see if I can mod it to use the SPIF interrupt.

Thank you for the info, didn't know about the SPI route. Still, it means modifying the LCD library, so we are back at the square one, don't we? Or am I missing something?

Bzdurek:
so we are back at the square one, don't we?

Yes. But that's how coding works, you write the bits that nobody has written yet. Were you hoping that a bunch of hobbyists and volunteers would have somehow already covered the gambit of everything you might possibly ever need?

I have a library that runs a parallel LCD off a 595 with SPI but it blocks during transmission. You're welcome to it if you want to try to modify it to use an interrupt or something.

You can see one hooked up here: REBL_UI/Documentation/REBL_Schematic.png at master · delta-G/REBL_UI · GitHub. Ignore the button and encoder parts.

Here, I banged this out real quick as a modification of the one in the post above. It compiles, but is totally untested as I don't have an LCD set up right now to test it. I think it should work, or at least get close. Test it out and let me know what happens. It implements a 64 byte circular buffer to hold the data and drives the data out using the SPI_STC (serial transfer complete) interrupt to load the next character out of the buffer if there is one or turn the transmission off when the buffer is full. It should run "in the background" rather nicely.

The only drawback is that if you want to send any commands to the LCD, like changing the cursor position, then it has to block until the buffer is empty before it can send it. Otherwise it would send the cursor change in the middle of the last word you tried to print and it wouldn't look right. In order to queue the commands in with the data you'd have to have some way of marking the bytes in the buffer whether they were commands or data bytes and I haven't figured out a good way to do that without having to use more memory. I thought about restricting the data to the 127 regular ascii characters which gives me bit 7 unused and use it to mark them, but the commands themselves still need 8 bits so I can't squeeze the marker into that.

Either way you're welcome to try it and play with it. I make no guarantees. I just banged this out real quick in Eclipse. It's written as .h and .cpp files because I'm writing in Eclipse. You should be able to create a new sketch in Arduino and copy all four files into the same folder with it. Then you can have as the ONLY line in the .ino

#include "Example.h"

Nothing else goes in the .ino because setup and loop and all that are defined in Example.cpp

If you get it working you can remove the Example.h and Example.cpp files and make a proper library out of it.

LCD595SPIF.cpp (7.68 KB)

LCD595SPIF.h (2.22 KB)

Example.cpp (538 Bytes)

Example.h (214 Bytes)

BTW: The answer to the blocking command issue lies in letting commands take up two bytes each in the buffer. One marks that the next byte is a command and the next is the command itself. This restricts things a little though as we have to give up at least one non-printable character to serve as the marker, 0x00 or 0xFF maybe. Will that affect creating custom characters? Should that be done in a blocking fashion before the real program starts?