eMOS Whitepaper

eMOS – an embedded message passing real time OS

eMOS is a real time OS for embedded systems with a preemptive message passing kernel at its core. The message passing API provides a uniform model for supporting additional software stacks such as UART driver, File System, USB stack, TCP/IP and CAN library etc.

Design Principles

eMOS is designed for embedded microcontrollers. It can be used on low end 8 bits AVR microcontrollers with 8K of flash and 2K of RAM to 32 bits ARM devices with lots of memory. The microkernel API takes just a few K bytes and can be used by itself in minimal systems to provide basic multiasking services.

In designing the eMOS tasking model, we feel that a preemptive priority based round robin scheduler is the simplest model for users, allowing the natural “functions as tasks” style of writing programs. It places no restriction on how users may structure their code and users do not need to work around the tasking model. To minimize resource consumption, a separate kernel stack is used by the kernel calls, so that tasks would not duplicate the resource needed for by kernel calls. For the advance users, scheduling APIs provide the control needed to further minimize task scheduling and resource consumption.

For process synchronization and interprocess communication, we adopt the message passing semantics made popular by OS such as QNX. A set of 3 primitives provides a robust and fast solution to both synchronization and interprocess communication requirements. Priority inversion is handled automatically as well. For simpler needs, eMOS also provides semaphores.

As many embedded systems are used in low power situations, eMOS includes timer API and provides hooks to the idle task so that you may place the system in low power mode to conserve power, to be awaken by interrupts or timer events.

The general philosophy is to provide flexibility rather than optimizing the design for a particular niche (e.g. memory constraint devices). Thus eMOS uses dynamic memory allocation (via a best-fit always-merge allocator to lessen memory fragmentation) and places no arbitrary limits on the number of tasks or task priorities and allow dynamic task creation and deletion. This approach allows eMOS to scale up and down except to the most memory constrainted situations.

In theory, scheduling algorithm is f(n) where n is the number of tasks in the READY state and task allocation is affected by the memory allocator. However in practice, these should not be worse than other schemes in any meaningful way as the number of READY tasks are few and allocation is fast.

/* eMOS
 * Copyright (C) 2008 ImageCraft Creations Inc. All Right Reserved.
 * info@imagecraft.com http://www.imagecraft.com
 */

/* fucntion that returns a status:
 * status >= 0, function succeeded
 * 0 > status,  function failed
 */

/* uKERNEL AND SCHEDULER API
 */
/* initialize eMOS, must be call first */                     int  eMOS_SysInit(void);
/* start eMOS scheduler */                                    int  eMOS_SysStart(void);
/* arrange "func" to be called when the system is idle */     int  eMOS_SysIdleHook(void (*func)(void));
/* return non-zero if there are runnable tasks */             int  eMOS_isSysBusy(void);
/* return non-zero if all other tasks are waiting */          int  eMOS_isSysWait(void);

/* create a task and return the process ID */                 int  eMOS_TaskCreate(void (*func)(void), unsigned stacksize, unsigned prio, unsigned hw_stacksize);
/* give up processing time */                                 void eMOS_TaskYield(void);
/* hibernate */                                               void eMOS_TaskHibernate(void);
/* wake a task from hibernation, can be called from ISR */    int  eMOS_TaskWakeup(void);
/* kill a task */                                             int eMOS_TaskKill(int pid);

/* temporarily disable the scheduler, any syscall will
   also re-enable it */                                       void eMOS_SchedOff(void);
/* re-enable the scheduler */                                 void eMOS_SchedOn(void);

/* MESSAGE PASSING API
 * if the buffer lengths do not match between the send/receive or send/reply calls,
 * then the shorter len is used
 */
/* send a message and wait until a reply */                   int eMOS_MsgSend(void *sendbuf, int sendlen, void *reqbuf, int reqlen);
/* (wait and) receive a message */                            int eMOS_MsgReceive(void *recbuf, int reclen);
/* reply to a request */                                      int eMOS_MsgReply(void *reqbuf, int reqlen);

/* SEMAPHORE API
 */
/* create a semaphore */                                      int eMOS_SemCreate(void);
/* lock a semaphore, wait if not available */                 int eMOS_SemLock(int semid);
/* unlock a semaphore */                                      int eMOS_SemUnlock(int semid);

/* Timer, RTC, etc.
 */
/* sleep for X seconds */                                     void eMOS_Sleep(int secs);
/* sleep for X milliseconds */                                void eMOS_SleepMs(int msecs);
/* set the RTC clock */                                       void eMOS_ClkPut(unsigned long time);
/* get the RTC clock */                                       unsigned long eMOS_ClkGet(void);
/* arrange "func" to be called for the system tick ISR */     void eMOS_SystemTickISRHook(void (*func)(void));
/* set the current time */                                    void eMOS_TimePut(unsigned long time);
/* get the current time */                                    unsigned long eMOS_TimeGet(void);

/* MEMORY MANAGEMENT API
 * Default allocator is best-fit always-merge
 */
/* set the system free space range */                         void eMOS_FreeSpace(unsigned begin, unsigned end);
/* allocate memory and zero out the content */                void *eMOS_MemAlloc(unsigned size);
/* free memory */                                             void eMOS_MemFree(void * ptr);

/* Ring Buffer UART
 */
/* initialize the COM port subsystem */                       void eMOS_ComInit(void);
/* open a COM port and set the ring buffer size */            int  eMOS_ComOpen(int portn, int n);
/* close a COM port */                                        int  eMOS_ComClose(void);
/* ??? */ eMOS_ComTerm();
/* read a character and wait if none is available */          int  eMOS_ComRead(int com);
/* write a character */                                       int  eMOS_ComWrite(int c);
/* ISR for putting a character into the output buffer */      void eMOS_ComISRPut(void);
/* ISR for getting a character into the input buffer */       void eMOS_ComISRGet(void);
/* read a string and wait if no input is available */         char *eMOS_ComGets(int com, char *buf, int size);
/* write a string */                                          int  eMOS_ComPuts(char *buf);
/* return non-zero if input is available */                   int  eMOS_ComReady(int com);

5 Comments

  1. Matthias says:

    Is there a Datasheet explaning more about eMOS??

    e.g. API usage ?? example code ?? debugging via AVRStudio ??

    thanks

    Matthias

  2. sarath says:

    Hi, Does this eMOS RTOS works with NXP LPC24xx/28xx devices and ICCV7.
    Thanks
    Sarath C Myneni

  3. imagecraft says:

    > Does this eMOS RTOS works with NXP LPC24xx/28xx devices and ICCV7.

    eMOS will be released for the AVR first. The next port will likely be the MSP430 and the ARM7 core. Most of eMOS is written in C, but since we do know the ICC compilers :-) we can optimize certain flow. For example, most system calls do not need to save all registers since we know the C calling convention. A port to the LPC24xx should be fairly easy.

    // richard

  4. sarath says:

    Thanks Richard,
    Is it possible to know when is the expected release of eMOS for LPC24XX. If it is not near by can we ask ImageCraft to do the porting with LPC24XX and ICCV7

  5. imagecraft says:

    Sarath, please email me richard @
    imagecraft.com. I tried to send you an email, but not sure it got through. Thanks.

Leave a comment