61
\$\begingroup\$

I have seen many articles that tell me I should be using RTOS for time management and resource management. My time has not permitted my own research, so I come to chiphacker for advice.

I use low resource microcontrollers(MSP430, PIC) and was looking for RTOSs I can use.

To the point:

  1. Resource cost of system
  2. Advantages of system
  3. Disadvantages of system
  4. Implementation Tricks
  5. Situations the RTOS should/should not be used in.

I do not use systems like the arduino, the projects I work with cannot support the cost of such a system.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ I am confused as to what this received a down-vote for. If the voter could give me feedback I will try to avoid such an action in the future. \$\endgroup\$
    – Kortuk
    Commented Dec 3, 2009 at 1:56
  • 1
    \$\begingroup\$ ditto. It's a great question.... \$\endgroup\$
    – Jason S
    Commented Dec 3, 2009 at 4:51
  • \$\begingroup\$ I accepted a question because, even thought this is open ended, I had a number of great responses and wanted to reward at least one writer for the effort. \$\endgroup\$
    – Kortuk
    Commented Jun 3, 2010 at 22:14

9 Answers 9

29
\$\begingroup\$

I haven't had much personal experience with RTOS's other than QNX (which is great on the whole but it's not cheap and I have had a really bad experience with a particular board vendor and QNX's we-don't-care attitude for systems other than their most common) which is too large for PICs and MSP430's.

Where you will benefit from an RTOS is in areas such as

  • thread management/scheduling
  • inter-thread communications + synchronization
  • I/O on systems with stdin/stdout/stderr or serial ports or ethernet support or a filesystem (not an MSP430 or PIC for the most part, except for the serial ports)

For peripherals of a PIC or MSP430: for serial ports I'd use a ring buffer + interrupts... something I write once per system and just reuse; other peripherals I don't think you'd find much support from an RTOS, as they are so vendor-specific.

If you need timing that is rock-solid to the microsecond, an RTOS probably won't help -- RTOS's have bounded timing, but typically do have timing jitter in their scheduling due to context switching delays... QNX running on a PXA270 had jitter in the tens of microseconds typical, 100-200us maximum, so I wouldn't use it for stuff that has to run faster than about 100Hz or which needs timing much more accurate than about 500us. For that kind of stuff you probably will have to implement your own interrupt handling. Some RTOS's will play nicely with that, and others will make it a royal pain: your timing and their timing may not be able to coexist well.

If the timing/scheduling is not too complex, you may be better off using a well-designed state machine. I would highly recommend reading Practical Statecharts in C/C++ if you haven't already. We've used this approach in some of our projects where I work, and it's got some real advantages over traditional state machines for managing complexity.... which is really the only reason you need an RTOS.

\$\endgroup\$
5
  • \$\begingroup\$ I work at a startup company where the most experienced embedded systems guys are just out of college(ie. Myself and the other guy that has been working with me for about 2 years). I spend a very large portion of time teaching myself about industry practice during my work week. As I have been reading I have been informed for all but our lowest cost system an RTOS would be a large improvment. \$\endgroup\$
    – Kortuk
    Commented Dec 3, 2009 at 22:13
  • \$\begingroup\$ There seem to be very low resource RTOS system for things like PICs and MSP430s that can help create a deterministic system out of a very complicated one, also greatly cleaning up our management of keeping modules separated. I have been part of a two man team that effectively built an in field data collection and routing system. Now that I look at RTOS I see it is perfect for what we designed. \$\endgroup\$
    – Kortuk
    Commented Dec 3, 2009 at 22:22
  • \$\begingroup\$ Sorry for using three post slots, your answer is very helpful, I am looking for a very low resource solution, but this information is valuable to have, thank you for the help. \$\endgroup\$
    – Kortuk
    Commented Dec 3, 2009 at 22:23
  • \$\begingroup\$ don't worry about the comment count (IMHO one thing that the StackExchange framework is lacking is support for discussions... the Q / A format covers most things but not some)... sounds like you have a pretty good handle on what you're looking for. I haven't looked at the FreeRTOS that Steve has mentioned but if it has been ported to low-end microcontrollers perhaps it will do the scheduling management you need. \$\endgroup\$
    – Jason S
    Commented Dec 4, 2009 at 0:10
  • \$\begingroup\$ It seems to save the state of each thread though the stack(something like 50 push/pull statements) and can handle timed interrupts. My system would normally use a port interrupt for thread switching, but the task looks doable. I do wish this site type handled discussion in a better format. \$\endgroup\$
    – Kortuk
    Commented Dec 4, 2009 at 0:46
26
\$\begingroup\$

Have you tried FreeRTOS? It's free (subject to T&C), and has been ported to both the MSP430, and several flavours of PIC.

It's small compared to some others, but this also makes it easy to learn, especially if you haven't used an RTOS before.

A (non-free) commercial license is available, as well as a IEC 61508/SIL 3 version.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you a ton, I will look into it within the week, I will leave the question open for other answers, but you are a great help! \$\endgroup\$
    – Kortuk
    Commented Dec 3, 2009 at 0:30
  • \$\begingroup\$ @Kortuk, did you learn FreeRTOS or ThreadX at the end? \$\endgroup\$
    – quantum231
    Commented Aug 8, 2021 at 12:38
12
\$\begingroup\$

I just found out about NuttX RTOS, that can even work on an 8052 (8-bit) system. It's doesn't have a lot of ports, but it looks interesting. The POSIX can be a plus, because it may make some of your code a little more portable if you move up to a beefier processor and you want to run real-time linux or QNX.

I don't have any experience with commercial RTOS's myself, but I have used homemade ones for years! They are great at helping you divide up your code development among many programmers, because they can essentially each get a "task" or "thread" to work on their part. You still have to coordinate and someone must oversee the whole project to make sure each task can make it's deadline.

I also recommend you research Rate Monotonic Analysis or RMA when using an RTOS. This will help you guarantee that your critical tasks will meet their deadlines.

I would also look into Miro Samek's QP-nano event-driven programming framework that can work with or without an RTOS and still give you real-time capability. With it, you're dividing up your design into hierarchical state machines instead of traditional tasks. Jason S mentioned Miro's book in his post. An excellent read!

\$\endgroup\$
0
9
\$\begingroup\$

One thing I've found useful on a number of machines is a simple stack switcher. I haven't actually written one for the PIC, but I would expect the approach would work just fine on the PIC18 if both/all threads use a total of 31 or fewer stack levels. On the 8051, the main routine is:

_taskswitch:
  xch  a,SP
  xch  a,_altSP
  xch  a,SP
  ret

On the PIC, I forget the name of the stack pointer, but the routine would be something like:

_taskswitch:
  movlb _altSP >> 8
  movf  _altSP ,w,b
  movff _STKPTR,altSP 
  movwf _STKPTR,c
  return

At the start of your program, call a task2() routine which loads altSP with the address of the alternate stack (16 would probably work well for a PIC18Fxx) and runs the task2 loop; this routine must never return or else things will die a painful death. Instead, it should call _taskswitch whenever it wants to yield control to the primary task; the primary task should then call _taskswitch whenever it wants to yield to the secondary task. Often, one will have cute little routines like:

void delay_t1(unsigned short val)
{
  do
    taskswitch();
  while((unsigned short)(millisecond_clock - val) > 0xFF00);  
}

Note that the task switcher doesn't have any means of doing any 'wait for condition'; all it supports is a spinwait. On the other hand, the task switch is so fast that a attempting a taskswitch() while the other task is waiting for a timer to expire will switch to the other task, check the timer, and switch back faster than a typical task-switcher would determine that it doesn't need to taskswitch.

Note that cooperative multitasking has some limitations, but it avoids the needs for a lot of locking and other mutex-related code in cases where invariants that are temporarily disturbed can be reestablished quickly.

(Edit): A couple caveats regarding automatic variables and such:

  1. if a routine which uses task-switching is called from both threads, it will generally be necessary to compile two copies of the routine (possibly by #including the same source file twice, with different #define statements). Any given source file will either contain code for only one thread, or else will contain code which will be compiled twice--once for each thread--so I can use macros like "#define delay(x) delay_t1(x)" or #define delay(x) delay_tx(x)" depending upon which thread I'm using.
  2. I believe that PIC compilers that can't "see" a function being called will assume that such a function may trash any and all CPU registers, thus avoiding the need to save any registers in the task-switch routine [a nice benefit compared with preemptive multitasking]. Anyone considering a similar task switcher for any other CPU needs to be aware of the register conventions in use. Pushing registers before a task switch and popping them after is an easy way to take care of things, assuming adequate stack space exists.

Cooperative multitasking doesn't allow one to completely escape issues of locking and such, but it really does greatly simplify things. In a preemptive RTOS with a compacting garbage collector, for example, it's necessary to allow objects to be pinned. When using a cooperative switcher, this isn't necessary provided that code assumes GC objects may move any time taskswitch() is called. A compacting collector which doesn't have to worry about pinned objects can be much simpler than one which does.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Awesome answer. I think it would be interesting to get some links on resources on approaching my own RTOS. My focus here really was getting a high quality RTOS from a vendor whom has done the work of ensuring hard real time, but this might be a fun hobbyist project for myself. \$\endgroup\$
    – Kortuk
    Commented Mar 16, 2011 at 7:03
  • 1
    \$\begingroup\$ Cool, never thought of tasks as just switching the SP... \$\endgroup\$
    – NickHalden
    Commented Jun 24, 2011 at 18:46
  • 1
    \$\begingroup\$ @JGord: I've done tiny task-switchers on the 8x51 and on a TI DSP. The 8051, shown above, is designed for precisely two tasks. The DSP one is used with four and it's a bit more complicated. I just had a crazy idea, though: one could handle four tasks by simply using three taskswitchers. Every time one of the first two tasks wants to task-switch, it should call TaskSwitch1 and TaskSwitch2. When one of the second two tasks wants to taskswitch it should call Taskswitch1 and Taskswitch3. Assume code starts in stack0, and each task switcher is set with its corresponding stack number. \$\endgroup\$
    – supercat
    Commented Jun 24, 2011 at 18:57
  • \$\begingroup\$ @JGord: Hmm... that doesn't quite work; it seems to yield a 3-way round-robin and ignores the third switcher. Well, experiment and I think you'll probably find a good formula. \$\endgroup\$
    – supercat
    Commented Jun 24, 2011 at 19:06
7
\$\begingroup\$

I have used Salvo on the MSP430. This was very light on processor resources and, providing that you obey the implementation rules, very easy to use and reliable. This is a co-operative OS and requires that task switches are performed at the outer function call level of the task functions. This constraint allows the OS to work in very small memory devices without using vast amounts of stack space maintaining task contexts.

On the AVR32 I am using FreeRTOS. Again very reliable so far but I have had some configuration/version discrepancies between the version that FreeRTOS publish and the version supplied with the Atmel framework. This however has the advantage that it is free!

\$\endgroup\$
5
\$\begingroup\$

The December edition of Everyday Practical Electronics has part 3 of a series on Real Time Operating Systems for PICs (in the PIC n' Mix Column) and has details of setting up FreeRTOS with MPLAB and a PICKit 2. The previous two articles (which I haven't seen) appear to have discussed the merits of various RTOSes and settled on FreeRTOS. Once the current article has setup the development environment they go on to start designing a binary digital clock. It appears that there's at least one more part to come on this topic.

I'm not sure how available EPE is in the US, but there does appear to be a US Store linked to from their site and there may be electronic copies available.

\$\endgroup\$
4
\$\begingroup\$

The CCS compiler for the PIC comes with a simple RTOS. I haven't tried it, but if you have this compiler, it would be easy to experiment with.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I actually tried this as my first. It is not an RTOS in any real meaning of the word. It is not preemptive in any way. It requires regular use of yield commands so that the RTOS can decide who runs next, you have to intentionally put them in constantly in case another program needs to take over. \$\endgroup\$
    – Kortuk
    Commented Jun 4, 2010 at 3:41
  • 2
    \$\begingroup\$ I think that it's still called an RTOS. It just sounds like it has a cooperative scheduler instead of a fully preemptive scheduler. \$\endgroup\$ Commented Jun 4, 2010 at 18:16
  • \$\begingroup\$ Yes, it is still technically an RTOS, but I had and still have very little value for it. I know it is a personal thing, but to me it needs to be preemptive to be valuable. I still +1 as it was a good answer and of value. \$\endgroup\$
    – Kortuk
    Commented Jun 6, 2010 at 20:45
3
\$\begingroup\$

Closely related question: https://stackoverflow.com/questions/1624237/multithreading-using-c-on-pic18

\$\endgroup\$
3
  • \$\begingroup\$ Thanks! It looks like most people did not get the question, but it is still interesting. \$\endgroup\$
    – Kortuk
    Commented Jun 10, 2010 at 0:24
  • \$\begingroup\$ I posted on the question on SO inviting the user to come to E&R for help! \$\endgroup\$
    – Kortuk
    Commented Nov 8, 2010 at 18:15
  • \$\begingroup\$ I think we "got" the question on SO, it was asking something different but related to this question. As for your comment there about certification; that depends on many things. Looking at the answers here, I like DoxaLogos's answer referring to QP-nano; my experience leads me to prefer event driven code over threads and implicit context switching of threads. \$\endgroup\$
    – janm
    Commented Nov 9, 2010 at 2:59
3
\$\begingroup\$

You haven't said much about your application. Whether you use an RTOS depends a lot on what you need to do in the PIC. Unless you're doing several different asynchronous things, which require strict time bounds, or have several threads running, then an RTOS might be overkill.

There are many ways to organise the time on a microcontroller depending on what's most important:

  1. Constant frame rate: For a PIC running a servo controller which must run at 1000Hz for example. If the PID algorithm takes less than 1ms to execute, then you can use the remainder of the millisecond to do other tasks, like check the CAN bus, read sensors, etc.

  2. All interrupts: Everything that happens in the PIC is triggered by an interrupt. The interrupts can be prioritised according to the importance of the event.

  3. Stick it in a loop and do everything as fast as you can. You might find this provides suitable time bounds.

\$\endgroup\$
1
  • \$\begingroup\$ I understand other methods, but am wanting to expand to an RTOS. I will be running multiple tasks and having a hard real time system, but am willing to start without the requirements of hard real time. Thank you for taking the time to answer, but I am wanting to learn an RTOS so that I can use it in a high demand situation. \$\endgroup\$
    – Kortuk
    Commented Jan 24, 2011 at 22:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.