diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,178 @@ + + + + + +IRQ +and FIQ DispatchersThe ASSP must supply two dispatcher functions, one for IRQ interrupts, +and one for FIQ interrupts. +

The following example code is a simple dispatcher for IRQ interrupts. +It assumes a simplistic interrupt controller that provides 32 interrupt sources, +and has a 32-bit pending-interrupt register where a 'one' bit indicates a +pending interrupt and all ones are cleared when the register is read.

+void IrqDispatch() + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + // for the purposes of this example we assume that reading + // this register also clears the pending flags + + TInt index = 0; + while( pendingIrqs ) + { + // while there is at least one pending IRQ + if( pendingIrqs & 1 ) + { + // the next interrupt is pending - dispatch it + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + +

The code assumes that the interrupt source represented by the low order +bit in the pending-interrupt register is represented by interrupt ID number +0 etc.

+

When implementing the dispatcher it is usual to write it in C++ initially, +but once you have it working you would probably want to rewrite it in assembler +to gain maximum efficiency for what is a time-critical section of code.

+
Dealing with +chained interrupts

There are two considerations when dealing with chained +interrupts:

    +
  1. how to identify interrupts +on the lower priority chained controllers

  2. +
  3. how to handle the dispatch +of a chained interrupt.

  4. +

The first point is a question of allocating locations in your ISR +table for the secondary controllers so that the interrupt ID identifies which hardware controller the interrupt is +on. For example, if each interrupt controller handles 32 interrupt sources, +you could make the first 32 IDs refer to the highest-level controller, the +next 32 refer to one of the second-level controllers etc.

There is +no need to change the Interrupt::Bind() and Interrupt::Unbind() functions, +although you may need to consider extending the Interrupt::Enable() and Interrupt::Disable() functions +to enable and disable the chain interrupt in a higher-level interrupt controller, +if necessary.

There are at least two ways of dispatching a chained +interrupt:

Dispatching a chained interrupt (1)

One +way of dispatching a chained interrupt is simply to make it a special case +in the main interrupt dispatcher. For example:

void IrqDispatch() + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + + TInt index = 0; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + if( index == EMainIntChainIrq ) + { + // second-level controller is signalling + SecondLevelIrqDispatch(); + } + else + { + // call ISR + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + } + ++index; + pendingIrqs >>= 1; + } + } +

This approach works for a simple case, for example, where +there is only a main and secondary interrupt controller. It is does not scale +well because the special cases in the dispatcher become an overhead on the +dispatch of normal, unchained interrupts as the number and depth of the chaining +increases.

Dispatching a chained interrupt (2)

A better +way of handling chained interrupts is to bind an ISR to the interrupt source +in the main interrupt controller and use it to dispatch the chained interrupt. +This is far more scalable because you can bind any number of ISRs without +having to add special cases to any of the interrupt dispatchers.

The +dispatcher code could then be re-implemented as:

void IrqDispatch() + // MAIN IRQ DISPATCHER, FIRST-LEVEL INTERRUPT + { + TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); + + TInt index = 0; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + void SecondLevelIrqDispatch( TAny* /* aParam */ ) + { + TUint32 pendingIrqs = TheAssp::SecondLevelIrqPendingRegister(); + + TInt index = EStartOfSecondLevelIntId; + while( pendingIrqs ) + { + if( pendingIrqs & 1 ) + { + (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); + } + ++index; + pendingIrqs >>= 1; + } + } + void InitialiseSecondLevelDispatch() + // Bind and enable the second-level dispatcher + { + Interrupt::Bind(EMainIntChainIrq,SecondLevelIrqDispatch,NULL); + Interrupt::Enable( EMainIntChainIrq ); + } + +Interrupt sources + +
    +
  • The second level dispatcher, SecondLevelIrqDispatch(), +is itself an ISR, and takes a TAny * parameter, but is +not needed in this specific example. It reads the interrupt pending register +of the second-level interrupt controller. Note, however, that the TAny * +parameter may be useful when the second level dispatcher is in the variant +as opposed to the ASSP. In that case you have separate interrupt IDs for variant +level interrupts and separate ISR tables. The TAny * parameter +can point to the appropriate ISR table. Alternatively the TAny * +can point to a data block containing IO addresses - especially useful if you +have many I/O devices mapped as hardware chunks. See the code in ...\assabet\specific\variant.cpp.

  • +
  • The index count starts +at offset EStartOfSecondLevelIntId into the ISR table, where +the second-level interrupt ISRs are located. In this example, this symbol +would equate to 32.

  • +
  • EMainIntChainIrq is +the interrupt ID of the chained interrupt source to the main interrupt controller.

  • +
+
Dealing with multiple interrupt sources

The case +where multiple peripherals are connected to the same interrupt source can +be handled through the technique of pseudo interrupt sources. This involves +assigning pseudo-interrupt IDs in the ISR table to correspond to each of the +peripherals that is attached to the interrupt line, i.e. ISRs are bound to +these pseudo-interrupt sources.

Dealing with pseudo interrupt sources +is, in essence, a special case of Chained +interrupts.

The dispatcher can do one of two things:

    +
  • examine the peripheral +hardware to determine which of the interrupts are pending, and then call the +appropriate ISR

  • +
  • call all the ISRs and +leave them to determine whether their peripheral is actually signalling an +interrupt.

  • +

As usual, it is entirely up to you to choose the ID numbers for these +pseudo-interrupts.

There should be no need to alter the implementations +of Interrupt::Bind() or Interrupt::Unbind() but +you will need some special handling in Interrupt::Enable() to +enable the true interrupt source, and Interrupt::Disable() to +disable this interrupt source.

Dispatching the interrupt can be done +in either of the two ways described in dealing with chained interrupts. Making use of a special case in the main interrupt +dispatcher is acceptable for simple cases, but for more complicated cases +with large numbers of pseudo-interrupts or a combination of chained and pseudo-interrupts, +it is better to use an ISR dispatcher bound to the true interrupt source.

+
\ No newline at end of file