- •List of Figures
- •List of Tables
- •Preface
- •1 Requirements
- •1.1 General Requirements
- •1.2 Memory Requirements
- •1.3 Performance
- •1.4 Portability
- •2 Concepts
- •2.1.1 Compiling and Linking
- •2.2 Loading and Execution of Programs
- •2.3 Preemptive Multitasking
- •2.3.1 Duplication of Hardware
- •2.3.2 Task Switch
- •2.3.3 Task Control Blocks
- •2.3.4 De-Scheduling
- •2.4 Semaphores
- •2.5 Queues
- •2.5.1 Ring Buffers
- •2.5.2 Ring Buffer with Get Semaphore
- •2.5.3 Ring Buffer with Put Semaphore
- •2.5.4 Ring Buffer with Get and Put Semaphores
- •3 Kernel Implementation
- •3.1 Kernel Architecture
- •3.2 Hardware Model
- •3.2.1 Processor
- •3.2.2 Memory Map
- •3.2.3 Peripherals
- •3.2.4 Interrupt Assignment
- •3.2.5 Data Bus Usage
- •3.3 Task Switching
- •3.4 Semaphores
- •3.4.1 Semaphore Constructors
- •3.4.2 Semaphore Destructor
- •3.4.3 Semaphore P()
- •3.4.4 Semaphore Poll()
- •3.4.5 Semaphore V()
- •3.5 Queues
- •3.5.1 Ring Buffer Constructor and Destructor
- •3.5.2 RingBuffer Member Functions
- •3.5.3 Queue Put and Get Functions
- •3.5.4 Queue Put and Get Without Disabling Interrupts
- •3.6 Interprocess Communication
- •3.7 Serial Input and Output
- •3.7.1 Channel Numbers
- •3.7.2 SerialIn and SerialOut Classes and Constructors/Destructors
- •3.7.3 Public SerialOut Member Functions
- •3.7.4 Public SerialIn Member Functions
- •3.8 Interrupt Processing
- •3.8.1 Hardware Initialization
- •3.8.2 Interrupt Service Routine
- •3.9 Memory Management
- •3.10 Miscellaneous Functions
- •4 Bootstrap
- •4.1 Introduction
- •4.3.1 Task Parameters
- •4.3.2 Task Creation
- •4.3.3 Task Activation
- •4.3.4 Task Deletion
- •5 An Application
- •5.1 Introduction
- •5.2 Using the Monitor
- •5.3 A Monitor Session
- •5.4 Monitor Implementation
- •6 Development Environment
- •6.1 General
- •6.2 Terminology
- •6.3 Prerequisites
- •6.3.1 Scenario 1: UNIX or Linux Host
- •6.3.2 Scenario 2: DOS Host
- •6.3.3 Scenario 3: Other Host or Scenarios 1 and 2 Failed
- •6.4 Building the Cross-Environment
- •6.4.1 Building the GNU cross-binutils package
- •6.4.2 Building the GNU cross-gcc package
- •6.4.3 The libgcc.a library
- •6.5 The Target Environment
- •6.5.2 The skip_aout Utility
- •7 Miscellaneous
- •7.1 General
- •7.2 Porting to different Processors
- •7.2.1 Porting to MC68000 or MC68008 Processors
- •7.2.2 Porting to Other Processor families
- •7.3 Saving Registers in Interrupt Service Routines
- •A Appendices
- •A.1 Startup Code (crt0.S)
- •A.3 Task.cc
- •A.6 Semaphore.hh
- •A.7 Queue.hh
- •A.8 Queue.cc
- •A.9 Message.hh
- •A.10 Channels.hh
- •A.11 SerialOut.hh
- •A.12 SerialOut.cc
- •A.13 SerialIn.hh
- •A.14 SerialIn.cc
- •A.15 TaskId.hh
- •A.18 ApplicationStart.cc
- •A.19 Monitor.hh
- •A.20 Monitor.cc
- •A.22 SRcat.cc
- •Index
30 |
2.5 Queues |
|
|
driven serial port. For each direction, a buffer is used between the task and the serial port, as shown in Figure 2.14. Assume further that the task shall echo all characters received to the serial port, possibly running at a lower speed. At a first glance, you may expect to have the (upper) receive buffer used with a get semaphore, and the (lower) transmit buffer with a put semaphore. The task will be blocked most of the time on the get semaphore, which is a normal condition. What would happen, however, if the task would block on the put semaphore, i.e. if the transmit buffer is full? This will eventually happen if the transmit data rate is lower than the receive data rate. In this case, one would normally signal the sender at the far end to stop transmission for a while, for example by hardware or software handshake. A blocked task, however, would not be able to do this. This scenario is quite common, and one would use a get semaphore for the upper buffer, but a plain ring buffer for the lower one.
Serial Port
Put |
Get |
Rx
Task
Tx
Get |
Put |
FIGURE 2.14 Serial Communication between a Task and a Serial Port
2.5.4 Ring Buffer with Get and Put Semaphores
The final option is to use both a get and a put semaphore. The buffer and the semaphores are initialized as described in the previous sections.
For each Put(), a P() call is made to the put semaphore before the item is inserted, and a V() call is made to the get semaphore after the item is inserted:
• |
Call P() for PutSemaphore |
(block until there is space) |
•Buffer[PutIndex] = Item
•PutIndex = (PutIndex + 1) modulo BufferSize
• |
Call V() for GetSemaphore |
(indicate a new item) |
For each Get(), a removed, and a P() from the buffer.
V() call is made on the get semaphore before an item is call is made on the put semaphore after removing an item
2. Concepts |
31 |
|
|
• |
Call P() for GetSemaphore |
(block until there is an item) |
•Item = Buffer[GettIndex]
•GetIndex = (GetIndex + 1) modulo BufferSize
• |
Call V() for PutSemaphore |
(indicate space available) |
•Return Item
This ring buffer with get and put semaphore is optimal in the sense that no time is wasted, and no error condition is returned on either full or empty queues. However, it cannot be used in any ISR, since both sides, Put() and Get(), use the P() call which is forbidden for ISRs. Thus the only application for this scheme would be the communication between tasks. Moreover, the disadvantages of put semaphores apply here as well.
32