Help with small kernel..

Hi, I'm writing a little "kernel" for a small microprocessor. Right now it just implements tasks, and does scheduling. That is , I have a timer fire every ms in which the interrupt handler sets up the kernel stack and pc, and the "kernel" merly checks if the current task has reached its timeslice. Now I want to do some abstractios over events.For now interrupts, but have no idea what that takes. One of the interrupts signals the press of a button, I want tasks to wait on such an event. Whats the basis of doing that ? I'd like the interrupt handlers as small as possible. One solution I can think of is to let the interrupt handler append events to a queue, and on each kernel tick check the event queue and if there are any task waiting.. but that seems odd. And rather high latency since little happens until my 1 ms tick. Basically, how to make tasks wait for events, and how to let interrupt handlers signal that an event happened.

Reply to
noselasd
Loading thread data ...

Message que seems like one possible answer, I know that things like this are oftenly done (waiting for a event) in a way that your function (for example wait_button()) returns 0 if button wasn't pressed and returns 1 if button was pressed. And in your task you would have something like:

function task_keypad() { if (wait_button()) { ... do_button_routine ... } }

I have seen this kind of event handling in Dynamic C (for Rabbit processors).

Mickey

Reply to
MArk

This is no problem. The problem is what does the wait_button() do. How and when should my "kernel" handle the(for this example) button event, what should the interrupt handler for the button do.

Reply to
Nils O. Selåsdal

wait_button() sees if there's an unhandled button event that needs processed. If there is, the code proceeds without delay. If not, it suspends (moves them to the waiting queue) the current task and appends itself onto the list of tasks waiting for a button event.

The interrupt handler for the button handles the hardware and flags the OS that a button event has occured.

The OS scheduler, when it gets a button event, sees if there are any processes that are suspended waiting for a button event. If there are, those processes are moved to the ready queue.

Almost any college OS text in the last 20 years covers this in detail.

Kelly

Reply to
Kelly Hall

When faced with the task of making a very simple kernel for a nonetheless significant project, I chose to abandon the system tick as a basis for task context switch. Instead, the "wait for event queue non-empty" primitive was used as the primary task synchronization feature. The interrupt service routines do indeed insert events in queues as your post suggests.

This is now part of the ABCD Proto-Kernel(tm) at

formatting link

- Thierry Moreau

CONNOTECH Experts-conseils inc.

9130 Place de Montgolfier Montreal, Qc H2M 2A1

Tel.: (514)385-5691 Fax: (514)385-5900

e-mail: snipped-for-privacy@connotech.com

Reply to
Thierry Moreau

Thanks, I'll take a look at it.

Reply to
Nils O. Selåsdal

Take a look at

formatting link
It has a preemptive priority based scheduler. It should give you some ideas on how to 'wake-up' threads from an interrupt services without having to check state of every thread on every interrupt.

Reply to
John Taylor

The classic mechanism is a semaphore. A task does a "P" (pend) operation on a semaphore. If the semaphore count is zero, the task is suspended. One implementation is for the semaphore to point to a queue of tasks waiting on the semaphore. Waiting tasks should be queued in priority order.

An interrupt routine can activate a task by performing a "V" operation on a semaphore. If any tasks are waiting on it, the OS then makes the highest priority task ready to run. If the newly ready task has a higher priority than the task which was running when the interrupt occurred, the active task indicator is changed.

In order to accomplish this with multiple interrupt nesting allowed, usually the interrupt handler increments the interrupt nesting level. When exiting the interrupt, the OS decrements the nesting level. If it is non-zero, the normal return is made. If zero, the check is made for task switch. If none, a normal exit is done. If switching occurred, magic happens: it saves the state of the old task in its TCB and then performs a return from interrupt which resumes the newly active task.

The activation can be done without semaphores by having the interrupt routine directly activate a given task.

All this must be done with careful consideration of what code can be interrupted and what must be protected. If interrupts are disabled for too long, interrupt latency suffers.

Thad

Reply to
Thad Smith

I haven't a wide experience with embedded systems, but the system tick concept always seemed a bit odd to me. One OS we dealt with was slightly annoying since the system tick functionality stole a very useful timer.

Basic semaphores, of the type that have been around for many decades, solve the problem. A task waits on a semaphore and is suspended, and the interrupt signals the semaphore which may cause it to wake up. The implementation isn't hard. Each semaphore has a list or array of tasks waiting on it, and when it's signaled one of the tasks becomes runnable again. At the end of the interrupt the task with the highest priority is resumed, which may not necessarily be the task that was interrupted.

All other synchronization or IPC mechanisms can be built on top of a semaphore primitive, such as message queues.

--
Darin Johnson
    "Floyd here now!"
Reply to
Darin Johnson

This problem has been thoroughly thought out and solved with a simple round-robin multitasker in Forth. Free with most/many variants. Whenever a 'pause' is encoutered the cooperative multitasker relinquishes control to the next task. If that task is sleeping then the cost is a simple jump instruction to the next task.

Any task can put any other task to sleep, wake another task, or add a task. Pre-emptive multitaskers usually have a lot of overhead to consider.

-- Regards, Albert

---------------------------------------------------------------------- AM Research, Inc. The Embedded Systems Experts

formatting link
916.780.7623

----------------------------------------------------------------------

Reply to
Albert Lee Mitchell

Ever notice that virtually all programming issues, especially embedded ones, were solved years ago in Forth (:

Reply to
Jim Stewart

Thanks for all the great info folks. Are there any good online material on this ? I'd rather take pointers from folks who have been there instead of googling myself to death ;)

Reply to
Nils O. Selåsdal

In this case, perhaps it is because multitasking has been commonly available in Forth environments for a very long time. Most commercial Forth cross compilers have always supplied multitaskers as part of the standard package, whereas even now this is not standard practice with C compiler vendors.

Stephen

-- Stephen Pelc, snipped-for-privacy@INVALID.mpeltd.demon.co.uk MicroProcessor Engineering Ltd - More Real, Less Time

133 Hill Lane, Southampton SO15 5AF, England tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691 web:
formatting link
- free VFX Forth downloads
Reply to
Stephen Pelc

IMHO, with a multi-threaded system available, there is very little real need for nested interrupts. An equivalent mechanism can be built with high-priority threads doing the lengthy parts of the interrupt service. In an interrupt handler, the only really necessary things to take care of are: acknowledging the hardware so that it drops the interupt request, and signaling the handler thread. One example of this kind of handling is the 'bottom half' of a Linux driver interrupt handling.

The nested interrupts very often create more problems than solutions. The necessary overhead can easily waste more processing power than the advantages of the nesting.

Been there - made it (since 1973).

Tauno Voipio tauno voipio @ iki fi

Reply to
Tauno Voipio

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.