0% found this document useful (0 votes)
4 views10 pages

Module 4 Notes

The document discusses heap-based message queue communication, emphasizing the efficiency of using pointers instead of data, and outlines the roles of boot code and device drivers in embedded systems. It also covers fundamental services provided by RTOS, re-entrant application libraries, exception handling, debugging techniques, and good coding practices for real-time embedded systems. Additionally, it explains the differences between binary semaphores and mutexes, highlighting their usage in managing resource access in concurrent programming.

Uploaded by

sreeni 1005
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views10 pages

Module 4 Notes

The document discusses heap-based message queue communication, emphasizing the efficiency of using pointers instead of data, and outlines the roles of boot code and device drivers in embedded systems. It also covers fundamental services provided by RTOS, re-entrant application libraries, exception handling, debugging techniques, and good coding practices for real-time embedded systems. Additionally, it explains the differences between binary semaphores and mutexes, highlighting their usage in managing resource access in concurrent programming.

Uploaded by

sreeni 1005
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

heap-based message queue communication between Tasks with a neat diagram.

A variant use of message queues that improves efficiency is the heap message queue. In this
case; pointers are sent as messages rather than data. The pointers are set to point to a buffer
allocated by the sender and the pointer received is used to access and process the buffer. The
receiver normally frees the buffer. It is key that the sender allocate the buffer and the receiver
deallocate to avoid exhaustion of the associated buffer heap (a pool of reusable buffers).

Figure shows a heap message queue. The heap message queue avoids the copy otherwise
required, which takes considerable CPU time and wastes memory due to double—buffering
of the same data. Because the buffer heap associated with the message queue is typically
much larger than the queue depth (size), normally the queue will become filled with pointers
and block writers before the heap is exhausted. As long as the sender always allocates heap
and the receiver always deallocates, the heap message queue works safely and much more
efficiently.

 Exceptions and explain the divide-by-zero exception handled by RTOS


Code is often developed as a set of functions to be called by other code modules or
applications in a larger system. When code is important to program defensively so that a
function l passed only expected arguments. Likewise, for applications calling library functions
that are perhaps linked in as object code and not verified at the source level it’s possible that
this code might perform an illegal instruction, attempt to decode j a bad address, overflow
its stack, or any number of other errant behaviors. In general, mature code bases will not
suffer from such shortcomings, but during developed and test, it may be useful to use
exception handling with reentrarant functions and code blocks.
Implementing API functions that take care of the above steps. These functions are named
load_module_debugger() and init_module_debugger(). The load_module_debugger() routine
handles step 1 of the loading and linking mechanism by allocating memory space and loading
the pre-compiled debugger module into this memory location. The first place that is looked
for loading the debugger module is a free memory block in the heap section of the memory. If
there is no such block available in which to fit the debugger module, another module of the
RTOS such as the scheduler is replaced by the debugger module. We assume that after an
error is detected, the programmer will not want to continue the execution but will modify the
code in order to remove the bug reported by the debugger module. Then, he or she will re-
compile the code with the original components and reexecute the program.

concept of Boot code and Device Drivers

Boot Code :

The universal definition of firmware is code or software that runs out of a non-volatile device
to make hardware resources available for the rest of the application software. Firmware
providing this function is normally referred to in general as board support package (BSP)
firmware because traditionally, this firmware has initialized and made available all on—
board resources for a processor complex to software applications. Before the resources have
been fully initialized, the firmware boots the board by executing code out of a nonvolatile
device so that one or more basic interfaces is made operable and the system can now
download additional application software. For example, the BSP boot firmware might
initialize an Ethernet interface and provide TFTP download of application code for execution.

Architecture of a Device driver firmware interface :

Device Driver in computing refers to a special kind of software program or a specific type
of software application which controls a specific hardware device that enables different
hardware devices for communication with the computer’s Operating System
A device driver communicates with the computer hardwares by computer subsystem or
computer bus connected to the hardware.

Device interface drivers are most often considered firmware because they directly interface to
hardware resources and make those resources available to higherlevel software applications.
The architecture of a device driver interface is depicted in and includes both a HW bottom
half interface and a SW top half interface. Device Drivers depend upon the Operating
System’s instruction to access the device and performing any particular action. After the
action they also shows their reactions by delivering output or status/message from hardware
device to the Operating system.
fundamental services and mechanisms provided by RTOS.

1. Priority preemptive scheduler for threads


2. Thread control block management
3. Inter—thread synchronization and communication (e.g., semaphores and message
queues)
4. Basic 1/ O for system debug and bring—up(e.g., serial, Ethernet, LED)
5. ISR (Interrupt Service Routine) installation on interrupt vectors
6. Transition from boot to operational state
7. Timers for delays and blocked thread timeouts
8. Drivers for basic hardware devices (serial, Ethernet, timers, nonvolatile memory)

concept of Re-entrant Application Libraries

Code shared by multiple threads of execution, as is often the case with application C
code, must be reentrant. Reentrant code is able to be interrupted and preempted in P the
execution context of one thread and then executed in the context of a new f thread without
side effects that would cause either thread to suffer functional bugs. I So, reentrant code
must carefully handle global resources and protect them so that P} they are mutually
exclusively used by multiple threads. The following are the four main methods to ensure
that global data is either protected or converted into task specific context data:

1. Protection of data with use of intLock() and intUnlock() to ensure that preA
emption around global data accesses is impossible at the ISR and task level.

2. Protection of data with use of taskLock() and taskUn1ock( ) to ensure that


preemption around global data accesses is impossible at the task level.

3. Elimination of global data with task variables so that data is no longer shared but
owned by a task context and stored in the TCB (Task Control Block).

4. Protection of global data with use of semMCreate() to establish a mutex sema~


phore and semTake() and semGive() to wrap the critical sections where global
data is manipulated with multiple instructions that could otherwise be interrupted
or preempted.

5. Use of stack data only (C parameters and function locals) so that each calling task
has its own copy of the data.

Any of these global data elimination or protection methods will make functions thread safe so
that they are re—entrant and can be used by multiple concurrently active threads. One of the
best and simplest ways to make a function thread safe is to recall that global data can be
eliminated by making use of stack only.

Importance of Assertion in Exception Handling with an example.

Preventing exceptions rather than handling them is more proactive. Certainly code can check
for conditions that would cause an exception and Verifyarguments to avoid the possibility of
task suspension or target reboot. The standard method for this type of defensive programming
is to include assert checks in code to isolate errant conditions for debug. In C code, pointers
are often passed to functions for efficiency. A caller of a function might not pass a valid
pointer, and this can cause an exception or errant behavior in the called function that can be
difficult to trace back to the bad pointer.

The following code demonstrates this with a very simple example that first passes print Add
r a valid pointer and then passes a NULL pointer:
Running the preceding code on a VxWorks target or VxSim produces the following output:

ptr = 0xOOf453ac

Assertion failed: (int)ptr,

file C:/Home/Sam/Book/CDROM/Example— Code/assert.c,

Use of assert checking in code makes the error in the calling arguments obvious and avoids
confusion. Without the assert check on the pointer parameter, it might seem that there is an
error in the function called when it finally attempts to dereference or otherwise use the
pointer, which would most likely cause an eXception. The assert check is also supported in
Linux.

Single-step debugging

Single-step debugging is often the most powerful way to analyze and understand both
software algorithmic errors, hardware/software interfaces errors, and sometimes even
hardware design flaws. Single-step debugging can be done at three different levels in most
embedded systems:

 Task- or process-level debugging


 System- or kernel-level debugging
 Processor-level debugging
Most application developers are accustomed to task- or process-level debugging. In this case,
a process or task is started in VxWorks or Linux, and most often a break point is set for the
entry point of the task or process.
Task-level debugging in VxWorks is simple. Command-line debugging can be performed
directly within the windshell. Graphical debugging can be performed using the Tornado tool
known as Cross Wind, accessed and controlled through a source viewer that displays C code,
assembly, or a mixed mode.
For embedded systems, debugging is described as cross-debugging because the host system
on which the debug interface runs does not have to be the same architecture as the target
system being debugged.
One of the most basic features of any debugger is the ability to set break points and to run or
single-step between them. There are two ways that break points are most often implemented:
● Hardware break points
● Software break points
Hardware break points require that the processor include a break point address register, a
comparator that determines whether the IP (Instruction Pointer) or PC (Program Counter)
matches the requested break address, and a mechanism to raise a debug exception.
The debug exception causes a halt in the normal thread of execution, and the debug agent
installs a handler so that the user can examine the state of the target at the point of this
exception.

C Program code to Illustrate the working of binary semaphore

The binary semaphore is the simplest and most often used mechanism in the RTOS. The
semGive() function is often used in ISR context to unblock a service handling task when data
becomes available as indicated by a hardware interrupt. The semTake () call is most often
used by tasks to wait for a server request (new data available) or to synchronize with another
task. The two_tasks . c code on the CDROM provides an example of tasks that synchronize
each other using a binary semaphore. Care should be taken to set the binary semaphore initial
state (FULLor EMPTY), and the protocol for unblocking must be selected. Protocols for
unblocking include SEM__Q_FIFOand SEM_O_PRIORITY.For SEM_Q_FIFO, if multiple
tasks block on the same semaphore, then they are unblocked in the order that they originally
arrived and blocked. If instead SEM_Q_PRIORITYis used, then the highest priority task will
be unblocked [Link] FIFO protocol ensures fairness, and the PRIORITY protocol helps
minimize potential priority inversion. Finally in cases where multiple tasks may be blocked
and if all blocking tasks should be released at the same time, the semF1ush() function
provides this feature.

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
int a, b;
sem_t sem;
void ScanNumbers(void *ptr){
for (;;){
printf("%s", (char *)ptr);
scanf("%d %d", &a, &b);
sem_post(&sem);
usleep(100 * 1000);
}
}
void SumAndPrint(void *ptr){
for (;;){
sem_wait(&sem);
printf("%s %d\n", (char *)ptr, a + b);
}
}
int main()
{
pthread_t thread1;
pthread_t thread2;
char *Msg1 = "Enter Number Two No\n";
char *Msg2 = "sum = ";
/*
int sem_init(
sem_t *sem // pointer to semaphore variable ,
int pshared // If = 0: can be used in threads only, else in process,
unsigned int value // initial value of the semaphore counter
);
return value 0 on successful & -1 on failure
*/
sem_init(&sem, 0, 0); // Can also use `sem = sem_open( "SemaphoreName",
O_CREAT, 0777, 0);`
pthread_create(&thread1, NULL, (void *)ScanNumbers, (void *)Msg1);
pthread_create(&thread2, NULL, (void *)SumAndPrint, (void *)Msg2);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Wait For Both Thread Finished\n");
sem_destroy(&sem); // Can also use `sem_unlink( "SemaphoreName");`
return 0;
}

Good coding practices to be followed in developing a code for


Real Time Embedded Systems.

1. Know THE REQUUIREMENTt

2. Choose the Best Coding Standard for Your Industry

3. Use Coding Rules and Follow Recommendations

4. Describe the Intent Behind the Rule

5. Update Coding Standards With Care

6. Consider Open vs. Closed Standards

7. Prioritize Coding Rules

8. Plan for Rule Deviations

Concept of Binary and Mutex Semaphores

Binary Semaphore :
Binary semaphores are semaphores which can assume the values 0 and 1 only. They
are used for implementing the locks by using signalling mechanism for achieving
mutual exclusion.
Here, if the value of semaphore is 0 it means it is locked so, lock is unavailable.
If the value of semaphore is 1 it means it is unlocked so, lock is available.
Mutex :
A mutex provides mutual exclusion, either producer or consumer can have the key
(mutex) and proceed with their work. As long as the buffer is filled by producer, the
consumer needs to wait, and vice versa.
At any point of time, only one thread can work with the entire buffer. The concept
can be generalized using semaphore.
Difference between binary semaphore and mutex :
Binary Semaphore Mutex
Its functions based up on signalling Its functions based up on locking
mechanism mechanism

The thread which is having higher The thread which has acquired mutex
priority than current thread can also can only release Mutex when it exits
release binary semaphore and take lock. from critical section.

Semaphore value is changed according to Mutex values can be modified just as


wait () and signal () operations. locked or unlocked.

Multiple number of threads can acquire Only one thread can acquire mutex at
binary semaphore at a time concurrently. a time

There is ownership associated with


mutex because only owner can
Binary semaphore have no ownership. release the lock.

They are slower than binary


They are faster than mutex because any semaphores because only thread
other thread/process can unlock binary which has acquired must release the
semaphore. lock.

You might also like