Unos 0.1.1 - Programs on SD Card Now Supported

goodinventor:
Well, I see that a real-time operating system for scheduling tasks would be really useful for the Arduino. I think I simply need to restructure my approach.

Yes, pick a single problem and work towards that. Don't try to do everything.

A task scheduler is a good idea, but that's all it is: a task scheduler. Please don't call it a real time operating system, it simply isn't.

Here is an example of an Arduino task scheduler: Metro It provides a mechanism to set up a periodic time base, and you call a function to determine if it's time to perform your function. If it returns true, do your periodic process. A library along those lines is a good fit for an Arduino. The limitation here is that the periodic tasks are small functions that must run to completion before the next task can be considered.

A more advanced library is Scheduler which schedules the running of multiple tasks that can run in parallel: one task doesn't have to complete before the next task has a chance to run. But keep in mind that this library is only for an Arduino Due, which has an ARM processor making it much more capable than an Uno class Arduino. Its processor is closer to the class found in a small Linux computer.

See the trend here? Simple processor, simple functions; more complex processor, more complex functions.

When planning a software project, the first step is to figure out the requirements and what you want to accomplish. Then you can choose a processor that has enough power to do what you want to do. In the latter case (running several tasks in parallel) the Uno class machine simply can't do it because it doesn't have enough RAM to hold a stack for each process, something that is necessary to be able to switch between multiple parallel processes. (Hint: don't try to come up with a scheduling system until you fully understand the basis behind that last statement.)

So for what I was originally intending to do, a Raspberry Pi or Beaglebone is a much better option. I think I'll look into those for a full system, and settle for a task scheduler for the Uno.

goodinventor:
Raspberry Pi or Beaglebone is a much better option
....
and settle for a task scheduler for the Uno.

Yes to RPi and Beaglebone

Personally I would need a lot of convincing that a task scheduler adds value to an Arduino when it is so easy to manage time using millis() - and a great deal more transparent to the programmer when things go wrong. I presume you are familiar with several things at a time.

...R

Somewhat. Having a scheduler, though, would simplify more demanding tasks involving time limits.

goodinventer wrote:

Having a scheduler, though, would simplify more demanding tasks involving time limits.

With the code I have seen thus far in your posts, I'm not sure how it would simplify anything for a programmer needing to have complex or 'demanding' time based event schedules, when, as Robin points out, it is just so easy to use existing functions provided by the compiler such as millis().

I am left wondering after so many suggestions to you that you take some time to learn about a number of concepts, what has your motivation been to continually forge on with what to many of us is seemingly pointless?

I too, would like to suggest to you as ShapeShifter has,

come up with some interesting projects that are appropriate for a limited embedded processor like the Arduino, and go and have some FUN with it!

As your alias might suggest, why not go and invent something good, good for you, where you alone experience enjoyment from learning and tinkering?

Maybe like so many other people, you too can make your Arduino poke, prod, scrunch, regurgitate data from the real world to push, pull, send, store, speak or light to put that child like grin on your face and laugh with delight at your achievement.

Then, we, too can be then happy for you.

I am tiring of this thread, and will now bail out to do more interesting things, I wish you luck.


Paul

goodinventor:
Somewhat. Having a scheduler, though, would simplify more demanding tasks involving time limits.

If the word "somewhat" refers to your familiarity with using millis() for timing then the VERY FIRST THING for your agenda is to become TOTALLY familiar with it before thinking about a scheduler.

I don't agree that a scheduler would benefit "more demanding tasks". All it will do is use more code and more CPU time to do the same job. Like hiring 2 accountants instead of one.

...R

On the contrary, I am completely familiar with using millis() in timing. It is simply the strategy used for schedulers in managing tasks that I do not fully understand.

How do I use my timing function that uses millis() for scheduling?

I am completely familiar with using millis() in timing

How do I use my timing function that uses millis() for scheduling?

Speechless.

I meant how do I schedule different tasks? Is there a link or a book that I can use to get an idea of how multitasking and process scheduling works?

Chapter 7, Bovet and Cesati's "Understanding the Linux Kernel"

OK. I'll have a look at that. Thanks.

Here is the new and improved version. It has a simple scheduler, an interrupt handler (could use some work), and a simple interpreter built in.

Unos_0_1_2.ino (9.18 KB)

FileSystem.cpp (826 Bytes)

FileSystem.h (674 Bytes)

Interrupts.cpp (1.04 KB)

Interrupts.h (931 Bytes)

Process.cpp (511 Bytes)

Process.h (1.31 KB)

Scheduler.cpp (1.68 KB)

Scheduler.h (1.09 KB)

SPI.cpp (476 Bytes)

SPI.h (422 Bytes)

Timer.cpp (1020 Bytes)

Timer.h (1.07 KB)

int Timer::Time()
{
// this will be used to access variables of class Timer
Timer Timer;

No it won't, at least not the ones you are expecting.

This creates a new Timer object, named Timer, it has not had its time_needed or last_time_update values set. Which means your timer uses unknown values, and the ones you did set aren't used.

Consider this sketch, it is equivalent to the problem in your Timer class (run this and see ):

struct Foo{
  
  int bar(){
    Foo Foo;
    return Foo.value;  
  }
  
  int value;
};


void setup() {
  Serial.begin( 9600 );
  
  Foo f;
  f.value = 44;
  
  Serial.println( f.bar() );
}

void loop() {}

Inside a class member function, if you want to access the members of the instance that was used to call the function, then you use the 'this' pointer, or simply just the name.

unsigned long interval = Timer.time_needed;  //WRONG
unsigned long interval = this->time_needed; //CORRECT
unsigned long interval = time_needed; //CORRECT

You need to slow down and test your code one piece at a time, before trying to bust out an entire OS. This Timer is used in your scheduler, so it is also flawed.

Is this better?

Unos_0_1_3.ino (9.17 KB)

FileSystem2.cpp (829 Bytes)

FileSystem2.h (666 Bytes)

Interrupts2.cpp (1.15 KB)

Interrupts2.h (934 Bytes)

Process2.cpp (529 Bytes)

Process2.h (1.31 KB)

Scheduler2.cpp (1.71 KB)

Scheduler2.h (1.08 KB)

SPI2.cpp (482 Bytes)

SPI2.h (425 Bytes)

Timer2.cpp (946 Bytes)

Timer2.h (1.08 KB)

goodinventor:
Is this better?

Have you tested thoroughly?
Have you gout multiple short sketches to test different scenarios?
Are there examples / documentation to show how each feature is used?
Do you expect the user to implement a 9Kb file in their sketch?

I personally do not care, I will not be using your system for anything, anyhow. But if you want others to use it (in the future) you'll have to start testing, asking questions & improving your C++ knowledge. Posting your code and asking whether its better simply shows you didn't test before hand, and didn't test afterwards.

A better approach would be to create a GitHub account, and add your project as a repository. Then here you can link to the project and post short snippets of errors, questions and things you're unsure about. (after you have tested it)

What do you expect the advantage of this is:

void executeInterpreterCommand(int myCommand)
{
  switch (myCommand)
  {
    case 0: // nop()
      nop();
      break;

You'll use more than one cycle getting to the nop() call.

pYro_65,

I did test it. However, I asked you to look at it in order to detect any potential problems that I did not catch. I'm thinking of eventually just using assembly instructions as the language in my interpreter instead of the simple C++ instructions.

goodinventor:
I'm thinking of eventually just using assembly instructions as the language in my interpreter instead of the simple C++ instructions.

sei(), cli(), nop() won't be any different. They already are implemented using a single asm instruction.

You are also missing the point, regardless of how you insert a nop, its only a single cycle. There is no logical use for it as the interpreter uses more than 1 cycle to interpret the command for a nop. Something that could delay a minimum number of cycles would be better.

goodinventor:
However, I asked you to look at it in order to detect any potential problems that I did not catch.

Build better tests. It doesn't look like your scheduler does anything...

pYro_65:
There is no logical use for it as the interpreter uses much MUCH MUCH more than 1 cycle to interpret the command for a nop.

There, I fixed it for you. 8)


goodinventor: Even if the whole interpreter were written in assembly language, the amount of time actually spent executing the NOP is negligible compared to the amount of time it takes to read in and translate the line of "code." This renders the instruction pointless.

pYro_65, I am still trying to figure out what I want the system to run the most, since there is such a limited amount of memory. I think that having a working interpreter where you can type in assembly programs would be really useful, so that's what I'll do.