|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-8B8CAEED-A89D-53B3-A311-51CF45B334B1" xml:lang="en"><title>IRQ |
|
13 and FIQ Dispatchers</title><shortdesc>The ASSP must supply two dispatcher functions, one for IRQ interrupts, |
|
14 and one for FIQ interrupts.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
15 <p> The following example code is a simple dispatcher for IRQ interrupts. |
|
16 It assumes a simplistic interrupt controller that provides 32 interrupt sources, |
|
17 and has a 32-bit pending-interrupt register where a 'one' bit indicates a |
|
18 pending interrupt and all ones are cleared when the register is read. </p> |
|
19 <codeblock id="GUID-1603305D-1509-5E80-89C1-B3998B557216" xml:space="preserve">void IrqDispatch() |
|
20 { |
|
21 TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); |
|
22 // for the purposes of this example we assume that reading |
|
23 // this register also clears the pending flags |
|
24 |
|
25 TInt index = 0; |
|
26 while( pendingIrqs ) |
|
27 { |
|
28 // while there is at least one pending IRQ |
|
29 if( pendingIrqs & 1 ) |
|
30 { |
|
31 // the next interrupt is pending - dispatch it |
|
32 (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); |
|
33 } |
|
34 ++index; |
|
35 pendingIrqs >>= 1; |
|
36 } |
|
37 } |
|
38 </codeblock> |
|
39 <p>The code assumes that the interrupt source represented by the low order |
|
40 bit in the pending-interrupt register is represented by interrupt ID number |
|
41 0 etc. </p> |
|
42 <p>When implementing the dispatcher it is usual to write it in C++ initially, |
|
43 but once you have it working you would probably want to rewrite it in assembler |
|
44 to gain maximum efficiency for what is a time-critical section of code. </p> |
|
45 <section id="GUID-3F0D4E4E-8D9C-51FD-A701-65C29D54AB94"><title>Dealing with |
|
46 chained interrupts</title> <p>There are two considerations when dealing with <xref href="GUID-76A30EC4-4B99-5471-9E80-F853C91485BC.dita#GUID-76A30EC4-4B99-5471-9E80-F853C91485BC/GUID-9026A4AC-57AF-545D-887C-AF43E0B37EDC">chained |
|
47 interrupts</xref>: </p> <ol id="GUID-DB84BE88-14E8-5124-9D43-4FC523311B65"> |
|
48 <li id="GUID-DA20FB18-6949-5CDC-B44B-65A43283558A"><p>how to identify interrupts |
|
49 on the lower priority chained controllers </p> </li> |
|
50 <li id="GUID-17C8A3C8-CCC5-574F-B7E2-C72CC2685569"><p>how to handle the dispatch |
|
51 of a chained interrupt. </p> </li> |
|
52 </ol> <p>The first point is a question of allocating locations in your <xref href="GUID-76A30EC4-4B99-5471-9E80-F853C91485BC.dita#GUID-76A30EC4-4B99-5471-9E80-F853C91485BC/GUID-77E83634-BBF6-5190-9434-9FB700547CD0">ISR |
|
53 table</xref> for the secondary controllers so that the <xref href="GUID-76A30EC4-4B99-5471-9E80-F853C91485BC.dita#GUID-76A30EC4-4B99-5471-9E80-F853C91485BC/GUID-8E58F4C9-0290-55E0-A4FD-B6C2361BE205">interrupt ID</xref> identifies which hardware controller the interrupt is |
|
54 on. For example, if each interrupt controller handles 32 interrupt sources, |
|
55 you could make the first 32 IDs refer to the highest-level controller, the |
|
56 next 32 refer to one of the second-level controllers etc. </p> <p>There is |
|
57 no need to change the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> functions, |
|
58 although you may need to consider extending the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-BB169E6E-D8F9-3762-899D-6DBA4B29CF87"><apiname>Interrupt::Enable()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-2D14E023-E6ED-39BF-8B31-6FA510957A8A"><apiname>Interrupt::Disable()</apiname></xref> functions |
|
59 to enable and disable the chain interrupt in a higher-level interrupt controller, |
|
60 if necessary. </p> <p>There are at least two ways of dispatching a chained |
|
61 interrupt: </p> <p><b>Dispatching a chained interrupt (1)</b> </p> <p>One |
|
62 way of dispatching a chained interrupt is simply to make it a special case |
|
63 in the main interrupt dispatcher. For example: </p> <codeblock id="GUID-189585CD-03BF-5E1F-ACD0-4AE2578D061B" xml:space="preserve">void IrqDispatch() |
|
64 { |
|
65 TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); |
|
66 |
|
67 TInt index = 0; |
|
68 while( pendingIrqs ) |
|
69 { |
|
70 if( pendingIrqs & 1 ) |
|
71 { |
|
72 if( index == EMainIntChainIrq ) |
|
73 { |
|
74 // second-level controller is signalling |
|
75 SecondLevelIrqDispatch(); |
|
76 } |
|
77 else |
|
78 { |
|
79 // call ISR |
|
80 (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); |
|
81 } |
|
82 } |
|
83 ++index; |
|
84 pendingIrqs >>= 1; |
|
85 } |
|
86 } |
|
87 </codeblock> <p>This approach works for a simple case, for example, where |
|
88 there is only a main and secondary interrupt controller. It is does not scale |
|
89 well because the special cases in the dispatcher become an overhead on the |
|
90 dispatch of normal, unchained interrupts as the number and depth of the chaining |
|
91 increases. </p> <p><b>Dispatching a chained interrupt (2)</b> </p> <p>A better |
|
92 way of handling chained interrupts is to bind an ISR to the interrupt source |
|
93 in the main interrupt controller and use it to dispatch the chained interrupt. |
|
94 This is far more scalable because you can bind any number of ISRs without |
|
95 having to add special cases to any of the interrupt dispatchers. </p> <p>The |
|
96 dispatcher code could then be re-implemented as: </p> <codeblock id="GUID-3B8BE593-C391-5D1F-BE94-5386306F773B" xml:space="preserve">void IrqDispatch() |
|
97 // MAIN IRQ DISPATCHER, FIRST-LEVEL INTERRUPT |
|
98 { |
|
99 TUint32 pendingIrqs = TheAssp::IrqPendingRegister(); |
|
100 |
|
101 TInt index = 0; |
|
102 while( pendingIrqs ) |
|
103 { |
|
104 if( pendingIrqs & 1 ) |
|
105 { |
|
106 (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); |
|
107 } |
|
108 ++index; |
|
109 pendingIrqs >>= 1; |
|
110 } |
|
111 } |
|
112 </codeblock> <codeblock id="GUID-D38C0DE2-3171-59AB-AEE2-7CC5E26C4E17" xml:space="preserve">void SecondLevelIrqDispatch( TAny* /* aParam */ ) |
|
113 { |
|
114 TUint32 pendingIrqs = TheAssp::SecondLevelIrqPendingRegister(); |
|
115 |
|
116 TInt index = EStartOfSecondLevelIntId; |
|
117 while( pendingIrqs ) |
|
118 { |
|
119 if( pendingIrqs & 1 ) |
|
120 { |
|
121 (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr); |
|
122 } |
|
123 ++index; |
|
124 pendingIrqs >>= 1; |
|
125 } |
|
126 } |
|
127 </codeblock> <codeblock id="GUID-87385945-E0DB-5396-A8EB-8B8F2B2EA80F" xml:space="preserve">void InitialiseSecondLevelDispatch() |
|
128 // Bind and enable the second-level dispatcher |
|
129 { |
|
130 Interrupt::Bind(EMainIntChainIrq,SecondLevelIrqDispatch,NULL); |
|
131 Interrupt::Enable( EMainIntChainIrq ); |
|
132 } |
|
133 </codeblock> <fig id="GUID-4109B9AA-BAE7-5454-9556-DC6D40AC75B9"> |
|
134 <title>Interrupt sources</title> |
|
135 <image href="GUID-970EC5A9-8ED3-53C5-93A3-2EC1A7B6F25F_d0e13980_href.png" placement="inline"/> |
|
136 </fig> <ul> |
|
137 <li id="GUID-7257146C-52C7-5C2F-B6F6-B32B558A0620"><p>The second level dispatcher, <codeph>SecondLevelIrqDispatch()</codeph>, |
|
138 is itself an ISR, and takes a <xref href="GUID-6D079976-9119-31FA-8E21-C3B815F94648.dita"><apiname>TAny</apiname></xref> * parameter, but is |
|
139 not needed in this specific example. It reads the interrupt pending register |
|
140 of the second-level interrupt controller. Note, however, that the <xref href="GUID-6D079976-9119-31FA-8E21-C3B815F94648.dita"><apiname>TAny</apiname></xref> * |
|
141 parameter may be useful when the second level dispatcher is in the variant |
|
142 as opposed to the ASSP. In that case you have separate interrupt IDs for variant |
|
143 level interrupts and separate ISR tables. The <xref href="GUID-6D079976-9119-31FA-8E21-C3B815F94648.dita"><apiname>TAny</apiname></xref> * parameter |
|
144 can point to the appropriate ISR table. Alternatively the <xref href="GUID-6D079976-9119-31FA-8E21-C3B815F94648.dita"><apiname>TAny</apiname></xref> * |
|
145 can point to a data block containing IO addresses - especially useful if you |
|
146 have many I/O devices mapped as hardware chunks. See the code in <filepath>...\assabet\specific\variant.cpp</filepath>. </p> </li> |
|
147 <li id="GUID-7ACA87E5-136F-56C2-855C-2F0C7486C13F"><p>The index count starts |
|
148 at offset <codeph>EStartOfSecondLevelIntId</codeph> into the ISR table, where |
|
149 the second-level interrupt ISRs are located. In this example, this symbol |
|
150 would equate to 32. </p> </li> |
|
151 <li id="GUID-0CDF7519-D979-5F49-ABBB-C3DC55426065"><p> <codeph>EMainIntChainIrq</codeph> is |
|
152 the interrupt ID of the chained interrupt source to the main interrupt controller. </p> </li> |
|
153 </ul> </section> |
|
154 <section id="GUID-BE4C910E-5FC7-4F83-AFF9-1070464FDA59"><title>Dealing with multiple interrupt sources</title> <p>The case |
|
155 where multiple peripherals are connected to the same interrupt source can |
|
156 be handled through the technique of pseudo interrupt sources. This involves |
|
157 assigning pseudo-interrupt IDs in the ISR table to correspond to each of the |
|
158 peripherals that is attached to the interrupt line, i.e. ISRs are bound to |
|
159 these pseudo-interrupt sources. </p> <p>Dealing with pseudo interrupt sources |
|
160 is, in essence, a special case of <xref href="GUID-76A30EC4-4B99-5471-9E80-F853C91485BC.dita#GUID-76A30EC4-4B99-5471-9E80-F853C91485BC/GUID-9026A4AC-57AF-545D-887C-AF43E0B37EDC">Chained |
|
161 interrupts</xref>. </p> <p>The dispatcher can do one of two things: </p> <ul> |
|
162 <li id="GUID-152A4626-FE77-5EED-9648-6ED1B08C04E8"><p>examine the peripheral |
|
163 hardware to determine which of the interrupts are pending, and then call the |
|
164 appropriate ISR </p> </li> |
|
165 <li id="GUID-320CC5CC-A60D-5681-92AD-922DE1F97D95"><p>call all the ISRs and |
|
166 leave them to determine whether their peripheral is actually signalling an |
|
167 interrupt. </p> </li> |
|
168 </ul> <p>As usual, it is entirely up to you to choose the ID numbers for these |
|
169 pseudo-interrupts. </p> <p>There should be no need to alter the implementations |
|
170 of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> or <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> but |
|
171 you will need some special handling in <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-BB169E6E-D8F9-3762-899D-6DBA4B29CF87"><apiname>Interrupt::Enable()</apiname></xref> to |
|
172 enable the true interrupt source, and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-2D14E023-E6ED-39BF-8B31-6FA510957A8A"><apiname>Interrupt::Disable()</apiname></xref> to |
|
173 disable this interrupt source. </p> <p>Dispatching the interrupt can be done |
|
174 in either of the two ways described in dealing with <xref href="GUID-76A30EC4-4B99-5471-9E80-F853C91485BC.dita#GUID-76A30EC4-4B99-5471-9E80-F853C91485BC/GUID-9026A4AC-57AF-545D-887C-AF43E0B37EDC">chained interrupts</xref>. Making use of a special case in the main interrupt |
|
175 dispatcher is acceptable for simple cases, but for more complicated cases |
|
176 with large numbers of pseudo-interrupts or a combination of chained and pseudo-interrupts, |
|
177 it is better to use an ISR dispatcher bound to the true interrupt source. </p> </section> |
|
178 </conbody></concept> |