views:

538

answers:

5

Hi all,

I want to know how events are used in embedded system code.

Main intention is to know how exactly event flags are set/reset in code. and how to identify which task is using which event flag and which bits of the flag are getting set/reset by each task.

Please put your suggestion or comments about it.

Thanks in advance.


(edit 1: copied from clarification in answer below)

Sorry for not specifying the details required. Actually I am interested in the analysis of any application written in C language using vxworks/Itron/OSEK OS. For example there is eventLib library in vxworks to support event handling. I want to know that how one can make use of such system routines to handle events in task. What is event flag(is it global/local...or what ?), how to set bits of any event flag and which can be the possible relationship between task and event flags ??

How task can wait for multiple events in AND and OR mode ?? I came across one example in which the scenario given below looks dangerous, but why ??

            Scenarios is ==> *[Task1 : Set(e1), Task2 : Wait(e1) and Set(e2), Task3 : Wait(e2) ]*

I know that multiple event flags waited by one task or circular dependency between multiple tasks(deadlock) are dangerous cases in task-event relationship, but how above scenario is dangerous, I am not getting it....Kindly explain.

                (Are there any more such scenarios possible in task-event handling which should be reviewed in code ?? )

I hope above information is sufficient ....

+1  A: 

This question needs to provide more context. Embedded systems can be created using a wide range of languages, operating systems (including no operating system), frameworks etc. There is nothing universal about how events are created and handled in an embedded system, just as there is nothing universal about how events are created and handled in computing in general.

Bill Forster
+2  A: 

Many embedded systems use Interrupt Service Routines (ISR) to handle events. You would define an ISR for a given "flag" and reset that flag after you handle the event.

For instance say you have a device performing Analog to Digital Conversions (ADC). On the device you could have an ISR that fires each time the ADC completes a conversion and then handle it within the ISR or notify some other task that the data is available (if you want to send it across some communications protocol). After you complete that you would reset the ADC flag so that it can fire again at it's next conversion.

Usually there are a set of ISRs defined in the devices manual. Sometimes they provide general purpose flags that you could also handle as you wish. Each time resetting the flag that caused the routine to fire.

Sean
A: 

Hi Bill,

Sorry for not specifying the details required. Actually I am interested in the analysis of any application written in C language using vxworks/Itron/OSEK OS. For example there is eventLib library in vxworks to support event handling. I want to know that how one can make use of such system routines to handle events in task. What is event flag(is it global/local...or what ?), how to set bits of any event flag and which can be the possible relationship between task and event flags ??

I hope above information is sufficient ....

Please delete this and put the clarification in the question itself (you can edit your question for this purpose).
Ilya
+1  A: 

The eventLib in VxWorks is similar to signal() in unix -- it can indicate to a different thread that something occurred. If you need to pass data with the event, you may want to use Message Queues instead.

The events are "global" between the sender and receiver. Since each sender indicates which task the event is intended for, there can be multiple event masks in the system with each sender/receiver pair having their own interpretation.

A basic example:

 #define EVENT1       0x00000001
 #define EVENT2       0x00000002
 #define EVENT3       0x00000004
 ...
 #define EVENT_EXIT   0x80000000

 /* Spawn the event handler task (event receiver) */
 rcvTaskId = taskSpawn("tRcv",priority,0,stackSize,handleEvents,0,0,0,0,0,0,0,0,0,0);
 ...

 /* Receive thread: Loop to receive events */
 STATUS handleEvents(void)
 {
     UINT32 rcvEventMask = 0xFFFFFFFF;

     while(1)
     {
         UINT32 events = 0;

         if (eventReceive(rcvEventMask. EVENTS_WAIT_ANY, WAIT_FOREVER, &events) == OK)
         {
             /* Process events */
             if (events & EVENT1)
                 handleEvent1();
             if (events & EVENT2)
                 handleEvent2();
             ...
             if (events & EVENT_EXIT)
                 break;
         }
     }

     return OK;
 }

The event sender is typically a hardware driver (BSP) or another thread. When a desired action occurs, the driver builds a mask of all pertinent events and sends them to the receiver task.

The sender needs to obtain the taskID of the receiver. The taskID can be a global,

int RcvTaskID = ERROR;
...
eventSend(RcvTaskID, eventMask);

it can be registered with the driver/sender task by the receiver,

static int RcvTaskID = ERROR;

void DRIVER_setRcvTaskID(int rcvTaskID)
{
    RcvTaskID = rcvTaskID;
}
...
eventSend(RcvTaskID, eventMask);

or the driver/sender task can call a receiver API method to send the event (wrapper).

static int RcvTaskID;
void RECV_sendEvents(UINT32 eventMask)
{
    eventSend(RcvTaskID, eventMask);
}
JayG
A: 

If you're asking how to set, clear, and check the various bits that represent events, this example may help. The basic strategy is to declare a (usually global) variable and use one bit to represent each condition.

unsigned char bit_flags = 0;

Now we can assign events to the bits:

#define TIMER_EXPIRED   0x01   // 0000 0001
#define DATA_READY      0x02   // 0000 0010
#define BUFFER_OVERFLOW 0x04   // 0000 0100

And we can set, clear, and check bits with bitwise operators:

// Bitwise OR: bit_flags | 00000001 sets the first bit.
bit_flags |=  TIMER_EXPIRED;  // Set TIMER_EXPIRED bit.

// Bitwise AND w/complement clears bits: flags & 11111101 clears the 2nd bit.
bit_flags &= ~DATA_READY;     // Clear DATA_READY bit.

// Bitwise AND tests a bit.  The result is BUFFER_OVERFLOW
// if the bit is set, 0 if the bit is clear.
had_ovflow = bit_flags & BUFFER_OVERFLOW;

We can also set or clear combinations of bits:

// Set DATA_READY and BUFFER_OVERFLOW bits.
bit_flags |=  (DATA_READY | BUFFER_OVERFLOW);

You'll often see these operations implemented as macros:

#define SET_BITS(bits, data)    data |=  (bits)
#define CLEAR_BITS(bits, data)  data &= ~(bits)
#define CHECK_BITS(bits, data)  (data & (bits))

Also, a note about interrupts and interrupt service routines: they need to run fast, so a typical ISR will simply set a flag, increment a counter, or copy some data and exit immediately. Then you can check the flag and attend to the event at your leisure. You probably do not want to undertake lengthy or error-prone activities in your ISR.

Hope that's helpful!

Adam Liss