Announcing CoRTOS - A minimalist Cooperative RTOS

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

CoRTOS - The world's simplest RTOS (?) is available under GPL V3

 

(Please see below for the V1a update)

 

It is fully documented, with a 30 page pdf manual and fully commented source code.

 

The intended audience includes:

    •    Those needing a small footprint RTOS for moderately complex products such as IOT, appliances, industrial controls, sensors, and toys;
    •    Students learning about Real Time techniques;
    •    Makers wanting to program ‘close to the metal.’

 

CoRTOS has the following features:

    •    Small kernel size of 16 lines of C, making it fast and reliable;
    •    Simplified task design as there is no interference from preemption;
    •    Full featured with add-on modules for delays and other time related functions, messaging, mutexes and signaling;
    •    Designed and written in a straight-forward way, making it easy to understand and expand.

Attachment(s): 

Nicholas O. Lindan

Cleveland Engineering Design, LLC

Last Edited: Tue. Mar 14, 2017 - 03:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

nolindan wrote:
Simplified task design as there is no interference from preemption

 

Of course, the lack of preemption can bring its own set of complications to task design ...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Of course, the lack of preemption can bring its own set of complications to task design ...

 

As the IBM salesman said to the customer: "It's not a bug, it's a feature!"

 

The right RTOS for the job is the one that removes the most complications.  Sometimes that is a preemptive system, sometimes a cooperative system and sometimes no system at all.

 

There is no one-size-fits-all RTOS - one-size-fits-all equals one-size-fits-none.

 

I've been designing embedded RTOS kernels and dragging client organizations into the the light for 35 years.  To gain acceptance an RTOS must fit the client's goals, and, funnily, also fit the client's organizational structure.  Very top down organizations really like preemption; laissez-faire organizations are happiest with the most innocuous of task switchers.  When I first read about the relationship between the organization of the employees and the organization of the software they write in "The Mythical Man-Month," I thought to myself "What piffle!"  But I have found it to be true, and not surprising - employees do best in an organization that mimics the organization of their psyche.

Nicholas O. Lindan

Cleveland Engineering Design, LLC

Last Edited: Tue. Mar 7, 2017 - 02:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, it's always fun to study a new RTOS! 

 

Jim

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

It's worth flagging up, as I can't see it mentioned in the documentation or source, that for the AVR this will only work when using GCC. For any other compiler you'll need to rewrite the context switch.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are the names of the filenames really enhanced by having CoRTOS* as a prefix on each? Makes it more difficult to split the wood from the trees in my umble opinion. Surely you just put all this in a CoRTOS directory and then name the files "normally"?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
for the AVR this will only work when using GCC

 

Good point - I should add the development environment to the manual.  For the AVR I imagine it would be the stack pointer reference, possibly the punctuation in the pushall/popall in-line assembler macros and the timer ISR syntax that would be sensitive to the development environment.

 

clawson wrote:
Are the names of the filenames really enhanced by having CoRTOS* as a prefix on each?

 

No, they are not, it's a pain in the pitooty.  Please feel free to rename them and chuck the *MSP.* and *PIC.*.  Over the years I have written so many different OSs that I need the prefix/suffix to keep things organized.  Experience has told me that twenty files all named timer.c and all different is recipe for disaster and a scramble for the backups.  When developing I use the obvious "kernel.c" and separate directories.

 

The goal was to make something simple enough that anyone can modify it easily as they see fit.  Please feel free.

Nicholas O. Lindan

Cleveland Engineering Design, LLC

Last Edited: Wed. Mar 8, 2017 - 05:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should switch to C++. You handle all this with "namespace" (or just the class name) so you can have as many SetTimer()s or whatever as you like as they are likely either SomeClass::SetTimer() or SomeNamespace::SetTimer()

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

nolindan wrote:

For the AVR I imagine it would be the stack pointer reference, ...The goal was to make something simple enough that anyone can modify it easily as they see fit.  Please feel free.

 

Codevision uses a 2 stack model with the hardware stack used as the call stack and Y used to implement a data stack so it's not quite as straight forwards as GCC but it's not too bad. Oh, and different registers need to be saved across a function call.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:

nolindan wrote:

For the AVR I imagine it would be the stack pointer reference, ...The goal was to make something simple enough that anyone can modify it easily as they see fit.  Please feel free.

 

Codevision uses a 2 stack model with the hardware stack used as the call stack and Y used to implement a data stack so it's not quite as straight forwards as GCC but it's not too bad. Oh, and different registers need to be saved across a function call.

 

Imagecraft is also a two stack model, similar to CV.

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

C++/Two Stack/....

 

Thanks for the suggestions but the goal here is simplicity.  How simply can one make a usable RTOS?

 

To that end there are no #ifdefs in the source, no configuration files, the source is (hopefully) intelligently commented, the manual (hopefully) understandable, the system is created with the chip maker's standard IDE, and feature creep is the user's responsibility.

 

I hope that it is easy to understand and easy to customize.  Are there any suggestions to that end?

 

There are no end of good elaborate systems out there; CoRTOS isn't going head-to-head with them but standing apart.

Nicholas O. Lindan

Cleveland Engineering Design, LLC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Attached is a minor update to CoRTOS.

 

CoRTOS now works with interrupts enabled at all times.

 

CoRTOS is not a task scheduler.  

 

CoRTOS works like any other RTOS.  Tasks schedule themselves, picking up where they left off after making a call to the OS.

Please feel free to send questions to nolindan@ix.netcom.com

Attachment(s): 

Nicholas O. Lindan

Cleveland Engineering Design, LLC

Last Edited: Tue. Mar 14, 2017 - 03:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A very minor update:

 

Sending signals to the same counter by two interrupts of different priorities on RISC processors will need an interrupt enable/disable when incrementing the counter.  Many RISC processors can not atomically increment memory values.

 

Hows that for obscure...

 

 

Attachment(s): 

Nicholas O. Lindan

Cleveland Engineering Design, LLC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Nicholas for sharing this work. I'll be using it as somewhat of an applied "teaching tool" for a group of folks inexperienced with real time operating systems, and control systems in general. It's interesting to read the expert comments to your posting of this nice work. It's true that many here have gone far beyond simple approaches to 8-bit projects. I wouldn't dare entertain converting this "bare metal" work to C++, as referenced above. I applaud that you stick with GCC and that environment. I've recently read code that gave me a headache because of the "if IAR..." conditionals. I look forward to using this "KISS" RTOS and will let you know the results.

-Ken

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a random assortment of issues I came across when skimming the code.

 

The code is GPL, hence any application will also be GPL as is statically links against the code. Maybe that's intended, I just wanted to point that out.

 

#include <avr\io.h>
#include <avr\interrupt.h>

That's wrong.  Even under MS-ish hosts, directory separator is /.

 

 

CoRTOSsignal.h and other files use status_t, uint8_t and mode without defining these.  This might lead to errors if you don't follow include orders, and you must always know the header dependencies when using them.

 

 

void rtos_int_disable (void)
{
	...
	TIMSK1 &= ~bit1;
}

Glitch. Changing a bit of TIMSK1 is non-atomic, and in some ISR you are setting TIMSK1.  Presumably, the code is just intended as an example, but users will follow it.  Examples are excellent multiplicators for bugs :-)

 

typedef unsigned char uint8_t;
// typedef char int8_t; AVR include file collides
typedef unsigned int uint16_t;
typedef int int16_t;
#define true 1
#define false 0
#define NULL ((void *)0)

Don't do this; that's realm of the standard.  Use stdint.h, stdbool.h (you are implying C99 anyway) and stddef.h or whatever brings stuff specified by the language.  This is particularly nasty because avr/io.h and friends include stdint.h as they also use uint8_t and friends.

 

 

Some of the files serve as examples, make this clear by using other naming convention for the files, not "CoRTOS*" as a file name.  Similar naming conventions might be useful for objects / types / macros introduced by the OS.  When reading the code it's unclear which are from user code and which from OS.  Examples for different architectures would go into their own "example/arch" (sub) folder.

 

 

Numer of tasts must be statically known.

Same applies for stack used by /each/ task.

Same applies for "resource queue" for each task.

Same applies for "message queue"s.

 

It's unclear which system resources (timers) are occupied by the OS. It's unclear what amout of memory is needed (e.g. amount of memory occupied as formula in number of tasks, queues, stacks, etc.).  Rough estimation of WCET (worst case execution time) for critical OS functions would be nice — just to credit the "RT" in CoRTOS.

 

 

 

 

Naming convention is confusing as to what are macros (ALLCAPS is common) and functions (alllowercase or CamelCase are common).  For example, popall() gives the wrong impression that's a function, but it's a function-like macro.

 

	cli ();
	SP = starting_stack[current_task];
	sei ();

This is hack.  If it works, then just by accident.  You are writing C, hence the compiler is on control of SP.  If all of the "OS" boils down to this one function, switch to asm (not: inline asm) and you are the master of stack.

	OCR1AH = 0x04;
	OCR1AL = 0xe2;

Nope.  Just "OCR1A = value".

 

#define bit0 0x01
#define bit1 0x02
#define bit2 0x04
#define bit3 0x08
#define bit4 0x10
#define bit5 0x20
#define bit6 0x40
#define bit7 0x80
#define bit8 0x0100
#define bit9 0x0200
#define bit10 0x0400
#define bit11 0x0800
#define bit12 0x1000
#define bit13 0x2000
#define bit14 0x4000
#define bit15 0x8000

non sunt multiplicanda entia sine necessitate...

static uint8_t resource_owner [number_of_resources];
...
static uint8_t resource_queue_add_index [number_of_resources];
static uint8_t resource_queue_remove_index [number_of_resources];
static uint8_t resource_queue_n [number_of_resources];

...whereas this cries for a resource_t. This might even improve code quality when traversing the resources, as you would have one address per resource (with different offsets for components like .owner), avoiding the need to compute again and again address into each of the unrelated arrays.

 

/*	RTOS data defining tasks and the size of their stacks.

	number_of_tasks can be found in CoRTOStask.h. */

#include "CoRTOScomdefs.h"

task task0 (void);
task task1 (void);
task task2 (void);
task task3 (void);

task_address_type start_addresses [number_of_tasks] = ...

Sample that just won't compile. "task" is not defined and only sensible definition would be "void".  If CoRTOStask.h is needed then include it, otherwise potential users will get impression of "exercise left to the reader, I just don't care enough to do it properly".

 

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi SprinterSB,

Wow, You are obviously a very good critic. I was very excited about using this small and easy to understand RTOS for a training class for newbies. How about I use the one that you've written instead?

-Ken

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note mr sprinter is heavily involved in the development of avr-gcc. Ignore his comments at your own peril!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

KenwickVS wrote:
I was very excited about using this small and easy to understand RTOS for a training class for newbies. How about I use the one that you've written instead?

 

Was that sarcastic? If so, then you're definitively barking up the wrong tree.

 

FYI SprinterSB (Georg-Johann Lay) is heavily active in developing the AVR-specific parts of GCC. It is my opinion that without him we would definitively not have such a good open-source compiler available and maintained. E.g. a substantial number of the bugs discovered over the past years have been reported and fixed by SprinterSB, and he has also contributed with new functionality.

 

If SprinterSB critiques something it is wise to read it through and consider it seriously.

 

Which of his points are you not agreeing with?

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ported "CoRTOSsuperblinkyAVR.c" to an E70xpd board. 

Attached is the Atmel Studio 7.0.1417 Template.

 

I added __set_APSR() to  "core_cmFunc.h".

 

based the port on the ASF "Getting_started" example.

added a LED on PC31. So the 2 LEDs are PC8 (on board) & PC31 off board.

 

Made other changes, like uint32_t for uint16_t.

 

Use the systick timer interrupt.

increased the task stack size.

 

haven't extensively tested or commented.

 

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jstampfl wrote:
an E70xpd board.

You mean a SAM E70 ?

 

So Cortex-M7 with 2M Flash and 384K RAM

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes SAM E70 Xplained

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, forgot to mention, baudrate is 250000

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I updated "CoRTOStimer.c" & "CoRTOStimer.h"  changed uint16_t to uint32_t

Attachment(s):