Showing posts with label MQX. Show all posts
Showing posts with label MQX. Show all posts

Wednesday, February 6, 2013

3.1 Event Groups, Event Componets

In MQX, there is an entity called Event Component.
Overall hierarchy is like this:  Event component has event group and Event groups have events. And each event group has events.

If you do not exclusively create event component, one default one gets created at the time when you create an event group. So bottom line is MQX supports more events that any sane RTOS application would ever need.

Below discussion is regarding light weight events.
 

Event Group

Each event in event group normally can contain number of events equal to bits present in _mqx_uint (on most of platforms its 32).

Creating event group is also straight forward.
You need to allocate global storage by declaring array which can hold number of event groups you want to create. OR in short declared an array of Event Groups.

Then you need to ask  kernel to initialize it (i.e. setting up data structure like list of waiting tasks, current bit value of it, flags associated with event etc. This is achieved by kernel call named  "_lwevent_create".


A word about kernel calls

As with most of other kernel calls, _lwevent_create this call internal  would be
1)disable interrupts
2)Get kernel data pointer
3)What ever event group pointer you have passed, hook it with kernel. ie. kernel data pointers would point to this location
4)enable interrupt

Steps 1,2,4 are invariably common while creating/updating any kernel entity.




Subsequently, while setting/clearing events and you have to give event group and particular event bit position.



MQX interrupts post is here




Sunday, January 6, 2013

Heisenbug : Missing Event Problem, Interesting Embedded system problem


I was working on a embedded environment where different processors would interact with each other. Let call them Master and Slave1 and Slave2.

Normal flow was like this, Master processor based on the input would ask Slave1 and Slave2 to do the work. Master processor can queue up more than one job for either Slave1 or Slave2.

Master keeps tracks of how many jobs it asked for particular Slave and would expect same number of responses (RTOS event) from the slave.

When slave completes a job it sends a interrupt to the master. Interrupt would generate an RTOS event.

Here was the problem, during hour’s long stress testing; one of the test was failing. I took the failed test case and fired it as standalone test And it failed.

Now was the time to put breakpoint in debugger and check, but, hey, if I put break point everything seems to be working fine. This is classic example of Heisenberg.

Well, I don’t think there is any hard and fast rule to fix Heisenberg problem . You should have thorough understanding of system.

In my case, one ‘other’ module , which was called before the problematic modules, was leaving one of the unhanded RTOS event from Slave2. So during stress testing, even before Slave2 has completed the Job, Master was getting a response, and subsequently it thinks that Slave2 has finished the job. But, in actuality Slave2 was still processing the job.

When I was hooking up the debugger, by the time I was stepping thought the program, Slave2 had enough time to finish the job and hence problem was getting masked.






Monday, October 15, 2012

6. What are Semaphores, RTOS Semaphores, MQX Semaphores

I would try to explain

what are semaphores?
What you need to take care if you want to implement your own semaphores?
Though I have label this post as MQX. But description is more on general term.


Semaphores

When They are used
Semaphores are used for two purposes
1) Process Synchronization
2) Critical Section problem / Mutual Exclusion

Is their any alternative to Semaphores?
Yes there are few solutions know as n process synchronize(software solutions) and Hardware solutions. Hardware solutions becomes complicated when number of process increases and secondly in all these you have busy waiting (it means you are eating CPU cycles when waiting and no other productive work can be done during this). So practically they are never used.

What are Semaphore?
They are synchronization tool. In a very abstract terms, semaphore is a global variables, which apart form initialization can be modified by only two operations wait() and signal().

Suppose S is semaphore
where wait is as simple as
wait(s)
{
     while(s <=0)
         ; //do no operation
    s--;
}

signal(S)
{
       S++;
}

Example of Usage
1) n process critical section problem
put every process code like this
do {
       wait ( mutex );
       critical section;
       signal(mutex);
       reminder section;
}while(1);

2) Example of using semaphores for Synchronization
Lets say, two concurrent process P1 and P2 having statements S1 and S2. We want in any case S1 should execute first. this can be achieved easily by
initialize Sem=0;

In process P1
{
   // Execute what ever you want to do
   // before executing P2
   S1;
   signal(Sem);

}

in process P2
{
     wait(Sem);
     S2;
}


Why not use Global Variables instead of semaphores to synchronize ?

Now if world was perfect, global variables can be used. You can write above mentioned functions in your C code to create semaphores. But(as its case with World anyway), its not that simple. In addition to above things we need to ensure

1) Modification of S value must be done exclusively.
2) In addition checking of while(s<=0) in wait and possible modification S--, should also be done without interruption
3) Above implementation is having busy wait too

How OS/RTOS implement Semaphores.What is spin lock?

The very basic implementation which I showed above has one problem they also have busy waiting. This is not at very appreciated in real time environments where wasting CPU is crime, equivalent to murdering someone (i.e murdering in civilized society). These type of semaphores are called the spin-lock semaphores.

But spin-lock semaphores have advantage too. There is no context switch required when process wait on Semaphore. Hence if waiting time is minimal this approach is very helpful.

How to overcome busy waiting.
You can modify wait and signal functions. When ever you have to wait, instead of looping you can block the current process. Bock is very common system call present in every Operating system.
In signal you simply call wakeup() for that process.
You also have to make sure that you maintain queue for all blocked process.

 There is one more important point.  On wakeup() you are simply putting it on ready queue. Its up to CPU scheduler scheduling policy when that process will be executed.


Critical Section Problem of Semaphore implementation.
The critical aspect of semaphore implementation that they are executed atomically. We must guarantee that no two processes can execute wait and signal operations on the same semaphores at same time. This is called critical section problem and can be solved in 2 ways.

1) In uni-processor environment, we can simply inhibit (disable) interrupts during the time that wait and signal operations are executing. This works very well in uni processor environment. Because, once interrupts are inhibited, there is no one, I mean literally no one (even 'the one' from matrix) can ask CPU to execute some thing else.

2)In multiprocessor env inhibiting of interrupts does not work. Instructions from different processors many be interleaved in some arbitrary way. We can  not employ any simple software solutions (not discussed here) for critical section problem.

I again emphasize what I said earlier, that MQX gives you two type of implementation one is called light weight implementation. When you call light weight implementation, MQX RTOS forgets about complexity of multiprocessor environment.


Friday, October 12, 2012

5. MQX RTOS Handling Interrupts -2


How to install an application ISR?

By call _int_install_isr(). MQX updates its interrupt vector table appropriately and calls your ISR handler when ever your interrupt occurs.

You might have guessed from my previous post when installing an ISR you have to supply
  • Interrupt Number
  • ISR function pointer
  • data pointer
Whats most frequent things Done in ISR?
  • setting a event bit
  • posting a semaphore, message queues etc.
  • DE-queing a task from task queue
 Whats all  MQX does not allow to place in an ISR?
 Basically, MQX has put some intelligent to stop you doing some stupid thing inside ISR. If you try to perform those illegal operations MQX would return error. You cannot 
  • cannot create/destroy a semaphore/message queue/events
  • cannot wait for an event inside an ISR
  • to cut the chase, you can not create any kernel object inside an ISR
 What you should not call inside an ISR?
  • No IO functions as they may take unpredictable time
  • never call _int_default_isr
  • any wait event function
  • any mutex lock operation
  • never create/destroy a task
  •  
     Next topic explains Semaphores in detail. Click here

Thursday, October 11, 2012

4. MQX RTOS Handing Interrupts -1



MQX handles HW interrupts and exceptions with interrupt service routines (ISR). Please note the sentence ‘exceptions are handled by ISR’. In due course I would discuss my experience with some very interesting problem involving exception ISR.

What an ISR? What goes inside an ISR?
ISR is not a task. It’s a small piece of code which is executed whenever an interrupt occurs. The main functionally of ISR may include
a)      Servicing a device
b)      Clearing an error condition
c)       Singling a task

MQX allows to pass a parameter to the ISR handler whenever application is installing an ISR. This parameter is a pointer. Please note that this pointer should not be at task stack, as it can be called even before task is created.

People keep on saying ISR should be precise. Well, that makes lots of sense as during ISR other interrupts may be disabled. And you definitely not want to miss the interrupts. Are you asking for example?
Hmm, let’s say whenever aeroplane’s engine is getting too hot, cooling procedure should be initiated immediately.  Now, this is how it would work, a sensor would trigger an HW interrupt, and ISR would ask you application to run the Cooling Task. But wait, you application is handling a pervioius ISR which has disabled other interrupts. And you are playing ‘print Hello word’ a zillion time game there in ISR(just kidding!). So you would miss the interrupt.( And lets hope you are not flying on the plane )


Back to serious stuff.

What is Kernel ISR?
MQX provides a kernel ISR(_init_kernel_isr()) which is written in assembly language. The kernel ISR runs before any other ISR. And it
a)      saves the context of the active task.
b)      switches to the interrupt stack .
c)       calls the appropriate ISR .
d)      after the ISR has returned, restores the context of the highest-priority ready task
When MQX starts it installs kernel ISR to all interrupts.

Initializing interrupt handling/Installing interrupts and Default ISR
       When MQX starts, it initializes its ISR vector table which has entry for all interrupts. Each entry consists of  a)   pointer to ISR  b)data to pass as parameter c)   Default exception handler.

Initially ISR for each entry is ‘_int_default_isr()’.
All of this is performed by a MQX kernel function called _int_init(), which loops for all interrupts and does what I mentioned above.

continued in next post. Click here

Good article on ARM exception handling
http://www.csie.nctu.edu.tw/~wjtsai/EmbeddedSystemDesign/Ch3-1.pdf 

Wednesday, October 10, 2012

3. MQX Events. Event Handling, Building an Event based application

Events



Events can be used to synchronize tasks. Just to make it simpler, you can imagine an event a bit in the 32 bit integer number (mostly, that is the word size of a MQX RTOS).
So this is how it would happen:
a) Somebody-1 would be waiting for this bit to be set. Until this bit is set that somebody would be stuck.
b) And Somebody-2 would set that bit so that somebody-1 can proceed further.
So in crude and very layman sense, events in RTOS are nothing but setting/clearing one bit.  

Now let’s add few more technicalities to it.

Somebody-1 above normally would be tasks which would wait for something. And sombebody-2 could be another Task or ISR.
In fact many embedded applications work this way, ISR gets triggered and as ISR handlers should be very small, they normal set an event and exit. So it serves both purposed ISR finishes quickly and also your application logic of waiting gets out of ISR. (in fact this is the most widely approach of designing ISR/task based applications).  

Why not use Setting/Clearing of bits than Events? What extra ROTS event handling adds apart from setting clearing bits?

a)      First and for most, whenever RTOS calls are setting/clearing event bit that part of kernel code is 100% atomic and safe. I mean, as done for other parts of kernel, when updating (here setting/clearing bit) interrupts are disabled.
      (Imagine you try to mimic the events and you are about to clear the bit and suddenly and ISR comes which tries to set the same bit. Well, that would be it for your logic.)  
If you have access to MQX source it would be fun exercise to trace the implementation of set/get event.

b)      Option to wait for single event (one event) or many events in single call.
_event_wait_all -> if you choose this one your wait call would be blocked until all the events(bits) you specified in the mask are set.
_event_wait_any -> if any of the events(bit) specified in the mask is triggered.

c)       RTOS has data structure called run queue and blocked queue. So event wait call need not be a infinite for loop. If you are implementing the events try to think how would be your WaitEvent call. As you don't have those data structure it would have to be infinite loop.
      RTOS has that(run, blocked queue) info, so when it hits a event wait call, it puts that task to blocked list. When it receives the event it checks the blocked queue and puts that task to ready queue.
      Infinite loop are big NO in embedded systems. As in that case, CPU would be performing loop operation and consuming power.

d)      Option to unblock all the tasks. Suppose 3 tasks are waiting for an event, and event is received. There in an option in MQX which would automatically clear the event as soon as it arrives and unblock all the tasks.

e)      You can also pass timer parameter to the wait event calls, means you will only be blocked for x mill secs.


BTW, MQX comes with two type of event handling, one with lightweight event handling and second one is (let’s say) normal event handling. Lightweight APIs are targeted to single processor systems while other one can handle more than one processor. Remember, in first MQX  post when I said MQX can handle more than one processors.


 PS: I intentionally have avoided to put the API names, thinking behind this is concepts are more important than the API names.


Continue reading about events here

One interesting MQX problem I faced can be found here


Tuesday, October 9, 2012

2. Starting MQX, Scheduling and Managing Tasks

I talked about the Task templates in my last post.
The lower the priority value of the task the higher the priority. You can remember this easily by knowing that if you create a task with priority 0, this task will run will interrupts disabled.

There is one more thing you should remember, MQX creates one ready queue for each task up to lowest priority. This creation is done by reading task template at the boot up time. So, you cannot create a task having lower priority than the lowest of task template.

If (hopefully) you are aware of any OS task creation APIs, well this ones is not that much different. Only names would change so I am skipping typing the obvious here.

Scheduling of Tasks 

I won't be able to discuss the topic without describing various states of a task in MQX.
There are three states
1) Blocked : task is not ready because its blocked on some condition to occur. 
2) Ready : task is ready to become active but its not active. This is because its same or lower priority than the active task.
3) Active : Task is running.

Task Creation APIs
 Nothing much different than any other OS. You can create a task by api called '_task_create', you could also create a task which would be in blocked state by api named '_task_create_blocked'. Blocked task can be made ready by _task_ready().

There are other APIs too to get task id, get creator task id, get error code id,  getting/setting exit handler, restarting task, setting error code etc.

Its worth mentioning error code here. Whenever something bad happens to a task it given an error code. If task is allowed to run even after error it may enter to some other error state. But the first error code is not overwritten, this is just to give clear indication to the user whats the original error.


Terminating Task 
A task can terminate itself or it can be terminated by other task. Whenever a task is terminated its children are NOT killed. Whenever a task terminates, MQX frees it all resources like dynamic allocated memory blocks and partition blocks, lightweight semaphore, message queues, mutex etc.


Task Scheduling  
Three policies are provided. Please note all are preemptive.

i) FIFO 


Its default policy. Next task to run here would be that which is waiting for longest. The active task runs until anyone of flowing occurs
-        -Active task voluntarily relinquishes the processor because it calls a blocking function.
-       -Higher priority interrupt occurs
-       -A task having higher priority becomes ready


ii) Round Robin
 Same as FIFO but it has additional constraint that each round robin task a maximum amount of time slice during which it can be active.
You do need to set the time slice for this type of scheduling.  

iii) Task Queues
Look for this space will scribe about it later.

Read about MQX Events. Event Handling, Building an Event based application here