Exchange & Comparison Two Real Time Operating Systems on a Micro-Controller System
- Art: Diplomarbeit
- Autor: Junyi Xu
- Abgabedatum: November 2004
- Umfang: 94 Seiten
- Dateigröße: 571,5 KB
- Note: 1,7
- Institution / Hochschule: Universität Duisburg-Essen, Standort Essen Deutschland
- Bibliografie: ca. 10
- ISBN (eBook): 978-3-8366-1328-6
- Sprache: Englisch
- Arbeit zitieren: Xu, Junyi November 2004: Exchange & Comparison Two Real Time Operating Systems on a Micro-Controller System, Hamburg: Diplomica Verlag
- Schlagworte: RTOS, Realtime operating system, Nokia OS, MicroCOS II, Micro Controller System
Diplomarbeit von Junyi Xu
Embedded systems are becoming an integral part of commercial products today. Mobile phones, watches, cars and flights controllers etc. are to name a few. There are critical elements between the system hardware and the software, one of the primary is the Real Time Operating System which ensures control, compatibility and timing. The Real Time Operating System has to interface/communicate well with the hardware below it to prevent casualty, and with the software above to ensure the applications running in a proper way. Therefore, more and more attention is being paid to the porting relationship between Real Time Operating System and Application Software by engineers in embedded field.
Comparing and evaluating the performance of different Real Time Operating Systems is getting more important. Measuring is the only way to provide useful information, for example, which Real Time Operating System is best suitable for a specific hardware configuration.
The purpose of this thesis paper is to find an approach to exchange MicroC/OS-II with NOKIA Car-kit OS on a micro-controller system. Besides porting MicroC/OS-II to the micro-controller system, the interfaces to higher level application software should be generated to adapt the application software to MicroC/OS-II. Finally, evaluate the advantages and disadvantages of them.
In chapter 1, a brief introduction is provided.
In chapter 2, the concept of RTOS and the development of Real Time Kernel are introduced. The field on which RTOS is always focusing and why RTOS is especially important in Embedded Systems are explained. The essential performance and the differences among several RTOS are also discussed in this chapter.
In chapter 3, the micro Real Time Kernel MicroC/OS-II is introduced in details. The speciality of MicroC/OS-II and the services provided from MicroC/OS-II are explained. Also, the micro-controllers that MicroC/OS-II supported are introduced.
In chapter 4, NOKIA Car-kit OS (NOKIA Car-kit Operating System) is introduced. The development history and some of important service mechanism are introduced briefly.
In chapter 5, the evaluation and comparison of these two Operating Systems are made. The most important characteristics, the advantages and disadvantages for both of these two RTOS are discussed.
In chapter 6, the software-mapping layer is discussed in detail. In this part, the whole software development procedure is explained. Issues from problem analyse, software design to software implementation are explained.
Finally, in chapter 7, the results from previous chapters are discussed. Some enhancement suggestions that are carried out from the whole porting and comparison procedure are given in this chapter.
Table of Contents:
|Abbreviations and Symbols||IX|
|2.1||General Information about OS||13|
|2.1.1||History of Operating Systems||13|
|2.2||Real Time Operating System||15|
|2.2.1||What Is Real time System?||15|
|2.2.2||Real Time Operating System||16|
|2.3||RTOS in Embedded systems||17|
|2.3.2||Running RTOS in Embedded Systems||18|
|3.1||Features of µC/OS-II||19|
|3.1.11||Robust and reliable||22|
|3.2||MicroC/OS-II Kernel Structure||22|
|3.2.5||Locking and Unlocking the Scheduler||24|
|3.2.7||Interrupts under µC/OS-II||25|
|3.3||Services provide from MicroC/OS-II||30|
|3.4.1||Pre-requirements for porting µC/OS-II||48|
|3.4.2||Portability of µC/OS-II||48|
|4.||Nokia Car-kit Operating System||49|
|4.1||Features of NOKIA CAR-KIT OS||49|
|4.1.4||Event-driven Real Time Kernel||50|
|4.2||NOKIA Car-kit Operating System Kernel Structure||50|
|4.2.2||System data and data definitions||51|
|4.3||Services Provided From Nokia Car-kit Operating System||54|
|5.||Evaluation and Comparison||66|
|5.1||Evaluation and Comparison||66|
|5.1.5||Interrupt and Exception Handling||74|
|5.1.6||Application Programming Interface||74|
|5.2||A Summary Comparison Review||76|
|5.2.1||Advantages and Disadvantages of MicroC/OS-II||76|
|5.2.2||Advantages and Disadvantages of NOKIA CAR-KIT OS||77|
|6.||Software Mapping Layer||79|
|6.2||Software Analysis for Mapping Layer||79|
|6.2.2||Functionality and Operational Concept Analysis||80|
|6.3||Software Design and Implementation for Mapping Layer||84|
|6.3.1||Software Design for mapping layer||84|
|6.3.2||Software Implementation for Mapping layer||87|
Chapter 184.108.40.206, Message Mailbox: A message mailbox (or simply a mailbox) is a µC/OS-II object that allows a task or an ISR to send a pointer size variable to another task. The pointer would typically be initialized to point to some application specific data structure containing a ‘message’.
A mailbox needs to be created before it can be used. Creating a mailbox is accomplished by calling OSMboxCreate() and specifying the initial value of the pointer. Typically, the initial value is a NULL pointer but a mailbox can initially contain a message. If you use the mailbox to signal the occurrence of an event (i.e. send a message) then you would typically initialize it to a NULL pointer because the event (most likely) would not have occurred. If you use the mailbox to access a shared resource then you would initialize the mailbox with a non-NULL pointer. In this case, you would basically use the mailbox as a binary semaphore.
µC/OS-II provides five services to access mailboxes: OSMboxCreate(), OSMboxPend(), OSMboxPost(), OSMboxAccept() and OSMboxQuery().
Creating a Mailbox: OSMboxCreate() is use in µC/OS-II to create a message mailbox. This function call returns a pointer. This pointer is used in subsequent calls to access the mailbox. The pointer is basically used as the mailbox handle. Note that if there are errors to create a mailbox, the returned value would be a NULL pointer. You should note that once a mailbox has been created, it couldn’t be deleted. It would be ‘dangerous’ to delete a message mailbox object if tasks were waiting on the mailbox.
Waiting for a message at a Mailbox: OSMboxPend() is use in µC/OS-II to let a task wait for a message at a mailbox. Again, the code is very similar to OSSemPend(). When a message is available, this function call returns the message. If a message is not available then the calling task must be suspended until either a message is posted or the specified timeout period expires.
Sending a message to a mailbox: OSMboxPost() is use in µC/OS-II to send a message to a mailbox. If there are tasks waiting for this message, the highest priority task waiting for the message will be removed from the wait list and make this task ready-to-run.
If there were no tasks waiting for a message to arrive at the mailbox, then the pointer to the message is saved in the mailbox, assuming there isn’t already a non-NULL pointer. Storing the pointer in the mailbox allows the next task to call OSMboxPend() to immediately get the message.
You should note that a context switch does not occur if OSMboxPost() is called by an ISR because context switching from an ISR can only occurs when OSIntExit() is called at the completion of the ISR, and from the last nested ISR.
Getting a message without waiting: OSMboxAccept() is use in µC/OS-II to get a message from a mailbox without waiting. It is possible to obtain a message from a mailbox without putting a task to sleep if the mailbox is empty. If a message is available, the mailbox is emptied. Finally, the original contents of the mailbox is returned to the caller. The code that called OSMboxAccept() will need to examine the returned value. If OSMboxAccept() returns a NULL pointer then a message was not available. A non-NULL pointer indicates that a message was deposited in the mailbox. An ISR should use OSMboxAccept() instead of OSMboxPend(). You can use OSMboxAccept() to ‘flush’ the contents of a mailbox.
Obtaining the status of a mailbox: OSMboxQuery() is use in µC/OS-II to obtain the status of a mailbox. This function call allows your application to take a ‘snapshot’ of the status for a message mailbox.
Using a mailbox as a binary semaphore: A message mailbox can be used as a binary semaphore by initializing the mailbox with a non-NULL pointer ((void *1) works well). A task requesting the ‘semaphore’ would call OSMboxPend() and would release the ‘semaphore’ by calling OSMboxPost(). You would use this technique to conserve code space if your application only needed binary semaphores and mailboxes. In this case, you could set and only use mailboxes instead of both mailboxes and semaphores.
Using a mailbox instead of Time Delay: The timeout feature of a mailbox can be used to simulate a call to OSTimeDly(). As shown in Figure 220.127.116.11, Task1() resumes execution after the time period expired if no message is received within the specified TIMEOUT period. This is basically identical to OSTimeDly(TIMEOUT). However, the task can be resumed by Task2() when Task2 post a ‘dummy’ message to the mailbox before the timeout expires. This is the same as calling OSTimeDlyResume() had Task1() called OSTimeDly(). You should note that the returned message is ignored because we are not actually looking to get a message from another task or an ISR.
Kapitel 18.104.22.168, Message Queues: A message queue (or simply a queue) is a µC/OS-II object that allows a task or an ISR to send pointer size variables to another task. Each pointer would typically be initialized to point to some application specific data structure containing a ‘message’.
A queue needs to be created before it can be used. Creating a queue is accomplished by calling OSQCreate() (see next section) and specifying the number of entries (i.e. pointers) that a queue can hold.
µC/OS-II provides seven services to access message queues: OSQCreate(), OSQPend(), OSQPost(), OSQPostFront(), OSQAccept(), OSQFlush() and OSQQuery(). Figure 22.214.171.124 shows a flow diagram to illustrate the relationship between tasks, ISRs and a message queue. Note that the symbology used to represent a queue looks like a mailbox with multiple entries. In fact, you can think of a queue as an array of mailboxes except that there is only one wait list associated with the queue. Again, what the pointers point to is application specific. ‘N’ represents the number of entries that the queue holds. The queue is full when your application has called OSQPost() (or OSQPostFront()) ‘N’ times before your application has called OSQPend() or OSQAccept(). As you can see from figure 126.96.36.199, a task or an ISR can call OSQPost(), OSQPostFront(), OSQFlush() or OSQAccept(). However, only tasks task are allowed to call OSQPend() and OSQQuery().
Creating a Queue: OSQCreate() is use in µC/OS-II to create a message queue. You should note that once a message queue has been created, it cannot be deleted. It would be ‘dangerous’ to delete a message queue object if tasks were waiting for messages from it.
Waiting for a message at a Queue: OSQPend() is use in µC/OS-II to wait a message at a queue. If a message is not available then the calling task must be suspended until either a message is posted or the specified timeout period expires. If there is a message available in the queue, the call is successful, some cleanup work is done to remove the message from the queue and the message is returned to the caller.
Sending a message to a queue (FIFO): OSQPost() is use in µC/OS-II to send a message to a queue by FIFO mode. If any task is waiting for a message to arrive at the queue, the highest priority task waiting for the message will be removed from the wait list, and this task will be made ready-to-run. If there were no tasks waiting for a message to arrive at the queue, then the pointer to the message is saved in the queue unless the queue is already full. You should note that if the queue is full, the message will not be inserted in the queue and thus, the message will basically be lost. Storing the pointer to the message in the queue allows the next task that calls OSQPend() (on this queue) to immediately get the pointer.
You should note that a context switch does not occur if OSQPost() is called by an ISR because context switching from an ISR can only occurs when OSIntExit() is called at the completion of the ISR, from the last nested ISR.
Sending a message to a queue (LIFO): OSQPostFront() is use in µC/OS-II to send a message to a queue by LIFO mode. OSQPostFront() is basically identical to OSQPost() except that OSQPostFront() uses the LIFO mechanism to handle the message. OSQPostFront() implements a LIFO queue because the next message extracted by OSQPend() will be the last message inserted by OSQPostFront().
Getting a message without waiting: OSQAccept() is use in µC/OS-II to get a message from a queue without waiting. It is possible to obtain a message from a queue without putting a task to sleep if the queue is empty. This is accomplished by calling OSQAccept(). If the queue contains at least one message, the next pointer is extracted from the queue. The code that calls OSQAccept() will need to examine the returned value. If OSQAccept() returns a NULL pointer then a message was not available. A non-NULL pointer indicates that a message pointer was available. An ISR should use OSQAccept() instead of OSQPend(). If an entry was available, OSQAccept() extracts the entry from the queue.
Flushing a queue: OSQFlush() is use in µC/OS-II to flush a message queue. OSQFlush() allows your application to remove all the messages posted to a queue and basically, start with a fresh queue.
Obtaining the status of a queue: OSQQuery() is use in µC/OS-II to obtain the status of a message queue. OSQQuery() allows your application to take a ‘snapshot’ of the contents of a message queue.
Using a queue as a counting semaphore: A message queue can be used as a counting semaphore by initializing and loading a queue with as many non-NULL pointer ((void *1) works well) as there are resources available. A task requesting the ‘semaphore’ would call OSQPend() and would release the ‘semaphore’ by calling OSQPost(). You would use this technique to conserve code space if your application only needed counting semaphores and message queues. You should note that this technique consumes a pointer size variable for each resource that the semaphore is guarding as well as requiring a queue control block. In other words, you will be sacrificing RAM space in order to save code space. Also, message queues services are slower than semaphore services. This technique would be very inefficient if your counting semaphore (in this case a queue) is guarding a large amount of resources (you would require a large array of pointers).