(原創) 如何在Qsys Subsystem使用Interrupt? (SOC) (Nios II) (Qsys)

Abstract
Qsys其中之一的賣點就是允許你建立hierarchical的subsystem。在SOC設計中,通常我們會將慢速的周邊使用較慢的clock而自成一個系統,在Qsys中允許我們將這些較慢的周邊包成一個peripheral subsystem,而不是像SOPC Builder一樣只能有一個system。當我們使用subsystem的架構時,該如何讓subsystem內IP使用interrupt的方式與Nios II溝通呢?

Introduction
使用環境:Windows XP SP3 + VirtualBox 4.1.2 + Quartus II 11.0

本文將討論以下主題:

1.如何使用IRQ Bridge連接subsystem的IRQ export到Nios II Processor?

2.如何避開Nios II SBT目前無法自動產生IRQ number常數在system.h的bug?

3.如何在App project使用Interrupt?

1.如何使用IRQ Bridge連接subsystem的IRQ export到Nios II Processor?

根據[1] Qsys Interconnect p.7-27 IRQ Bridge章節的建議,若要在subsystem使用interrupt,必須在包含Nios II的CPU subsystem使用IRQ Bridge接收Peripheral subsystem所export出來的IRQ,然後才連到Nios II Processor。至於下圖中的Merlin IRQ Mapper則並不是必需的,若你在CPU subsystem中也有IP要使用interrupt,這必須再包一層Merlin IRQ Mapper;若你在CPU subsystem沒有IP要使用interrupt,只有Peripheral subsystem使用interrupt,可以直接只使用IRQ Bridge連接到Nios II Processor。

常見的錯誤(也是我第一次的錯誤)是直接將Peripheral subsystem所export的IRQ直接連到Nios II Processor,這樣Qsys與Quartus II編譯都沒有任何錯誤,Nios II也沒有錯誤,不過Nios II的C code將收不到來自Peripheral subsystem的interrupt。

irq000

2.如何避開Nios II SBT目前無法自動產生IRQ number常數在system.h的bug?

除此之外,在[2] Quartus II 11.0 Release Notes的p.15已經承認在Quartus II 11.0有以下的bug。

irq001

簡單的說,就是若你在subsystem中使用interrupt,當你使用Generate BSP時,Nios II SBT根據*.sopcinfo在system.h所產生相對應的IRQ number常數,永遠都是-1,並無法反應出目前硬體架構中真正的IRQ number。且經過實測,這個問題在Quartus II 11.1也依然存在。

如圖所示,我們對push button使用interrupt,但在system.h的PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ常數卻是-1,與在Qsys上的IRQ number不同。

irq002

這會造成什麼影響呢?只要你的App project使用到有使用interrupt的IP,編譯就會產生錯誤,如下圖我們在system timer有使用interrupt,所以一編譯就產生錯誤無法繼續。

irq003

詳細錯誤訊息如下:

Error: Interrupt not connected for peripheral_system_timer_0. The system clock driver requires an interrupt to be connected. Please select an IRQ for this device in SOPC builder.

root cause就是system.h的IRQ number都是-1,所以App project找不到該IP的IRQ number而無法編譯。

Solution
既然在system.h的IRQ number都是-1,我們只好重新自己在system.h手動定義IRQ number。根據[3] Altera Wiki : New Qsys Issues for Interrupts的建議

irq014

當然你可以直接去修改system.h,但別忘了BSP project的所有檔案最好不要手動修改,應該交由Nios II SBT或者command line script去修改才對,因為每當你執行Generate BSP或者BSP Editor時,Nios II SBT都會重新產生system.h,也就是你做的所有修改都會被覆蓋掉。所以[3] Altera Wiki : New Qsys Issues for Interrupts 的解法雖然可行,但並不完美。

根據 [2] Quartus II 11.0 Release Notes的建議

irq001

看起來是要我們自己另開一個my_system.h,然後將system.h所有內容複製到system.h,自己在my_system.h加上IRQ number常數,並且App project也使用my_system.h,這樣Generate BSP與BSP Editor就不會改到我的my_system.h了。

這樣看似理想,但卻衍生另外一個問題:BSP project有大量的檔案都include "system.h",你必須手動一一的改成include "my_system.h",這也是個大工程。所以[2] Quartus II 11.0 Release Notes 看似也不盡理想。

我在此提供一個小技巧對付Nios II SBT目前這個bug。

在system.h的尾部自己加上IP IRQ number的定義如下圖,先執行#undef取消這個常數的定義,再用#define重新這個常數,因為若同一個常數在system.h重複#define,會產生warning,若使用#undef就完全沒有warning。

irq005

然後將這些#undef與#define另存一個文字檔,每當你執行Generate BSP或者BSP Editor時,system.h就會被Nios II SBT重新產生蓋掉你原先的設定,再將這些#undef與#define貼到system.h的最下方。如此就只需修改system.h,其他BSP檔案都不用做任何修改。

如此修改重新編譯後,就可順利Build Project,沒有任何錯誤。

irq006

3.如何在App project使用Interrupt?

根據[4] Exception Handling p.8-16與p.8-17的建議,我們將App project寫成如下的code使用interrupt。

nios2_onchip_leg_push_button.c / C

 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : nios2_onchip_led_push_button.c
5 Compiler : Nios II SBT 11.0
6 Description : test led, push_button & interrupt in subsystem
7 Release : Jan.06,2012 1.0
8 */
9
10 #include <stdio.h>
11 #include "system.h"
12 #include "alt_types.h"
13 #include "sys/alt_irq.h"
14 #include "altera_avalon_pio_regs.h"
15
16 volatile int edge_capture;
17
18 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
19 void handle_key_interrupts(void *context) {
20 #else
21 void handle_key_interrupts(void *context, alt_u32 id) {
22 #endif
23
24 volatile int *edge_capture_ptr = (volatile int*)context;
25 *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE);
26 IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0);
27
28 if (edge_capture == 0x01) {
29 printf("key 1 pressed!\n");
30 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFE);
31 edge_capture = 0x00;
32 }
33 else if (edge_capture == 0x02) {
34 printf("key 2 pressed\n");
35 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFD);
36 edge_capture = 0x00;
37 }
38 else if (edge_capture == 0x04) {
39 printf("key 3 pressed\n");
40 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xFB);
41 edge_capture = 0x00;
42 }
43 else if (edge_capture == 0x08) {
44 printf("key 4 pressed\n");
45 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xF7);
46 edge_capture = 0x00;
47 }
48 else if (edge_capture == 0x10) {
49 printf("key 5 pressed\n");
50 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xEF);
51 edge_capture = 0x00;
52 }
53 else if (edge_capture == 0x20) {
54 printf("key 6 pressed\n");
55 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xDF);
56 edge_capture = 0x00;
57 }
58 else if (edge_capture == 0x40) {
59 printf("key 7 pressed\n");
60 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0xBF);
61 edge_capture = 0x00;
62 }
63 else if (edge_capture == 0x80) {
64 printf("key 8 pressed\n");
65 IOWR(PERIPHERAL_SYSTEM_LED_PIO_BASE, 0x00, 0x7F);
66 edge_capture = 0x00;
67 }
68 }
69
70
71 void init_key() {
72 void *edge_capture_ptr = (void *)&edge_capture;
73 IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0xFF);
74 IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PERIPHERAL_SYSTEM_BUTTON_PIO_BASE, 0x0);
75
76 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
77 alt_ic_isr_register(PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ_INTERRUPT_CONTROLLER_ID,
78 PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ,
79 handle_key_interrupts,
80 edge_capture_ptr,
81 0x0);
82 #else
83
84 alt_irq_register(PERIPHERAL_SYSTEM_BUTTON_PIO_IRQ,
85 edge_capture_ptr,
86 handle_key_interrupts);
87 #endif
88 }
89
90
91 int main() {
92 printf("Nios II + Onchip + LED + Push Button Test!\n");
93
94 init_key();
95
96 while(1);
97
98 return 0;
99 }

以上的code我不打算一行一行講解,詳細請參考[4] Exception Handling p.8-16與p.8-17,我要強調的是,一般在使用interrupt時,Altera都會建議你使用新的alt_ic_isr_register(),而不要使用舊的alt_irq_register(),並且說未來Nios II SBT版本將只支援alt_ic_isr_register(),若在只有一層Qsys的system下,可以使用alt_ic_isr_register()沒有問題,但在具有Qsys subsystem下使用interrupt時,若使用alt_ic_isr_register()將會造成編譯錯誤,會說找不到alt_ic_isr_register(),為什麼會這樣呢?

在一般只有一層Qsys system,在system.h可以看到#define ALT_ENHANCED_INTERRUPT_API_PRESENT,如下圖所示:

irq007

但在使用Qsys subsystem的system.h下,看不到#define ALT_ENHANCED_INTERRUPT_API_PRESENT

irq008

在BSP的

sys/alt_irq.h / C

  1 #ifndef __ALT_IRQ_H__
2 #define __ALT_IRQ_H__
3
4 /******************************************************************************
5 * *
6 * License Agreement *
7 * *
8 * Copyright (c) 2009 Altera Corporation, San Jose, California, USA. *
9 * All rights reserved. *
10 * *
11 * Permission is hereby granted, free of charge, to any person obtaining a *
12 * copy of this software and associated documentation files (the "Software"), *
13 * to deal in the Software without restriction, including without limitation *
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
15 * and/or sell copies of the Software, and to permit persons to whom the *
16 * Software is furnished to do so, subject to the following conditions: *
17 * *
18 * The above copyright notice and this permission notice shall be included in *
19 * all copies or substantial portions of the Software. *
20 * *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
27 * DEALINGS IN THE SOFTWARE. *
28 * *
29 * This agreement shall be governed in all respects by the laws of the State *
30 * of California and by the laws of the United States of America. *
31 * *
32 ******************************************************************************/
33
34 /*
35 * alt_irq.h is the Nios II specific implementation of the interrupt controller
36 * interface.
37 *
38 * Nios II includes optional support for an external interrupt controller.
39 * When an external controller is present, the "Enhanced" interrupt API
40 * must be used to manage individual interrupts. The enhanced API also
41 * supports the processor's internal interrupt controller. Certain API
42 * members are accessible from either the "legacy" or "enhanced" interrpt
43 * API.
44 *
45 * Regardless of which API is in use, this file should be included by
46 * application code and device drivers that register ISRs or manage interrpts.
47 */
48 #include <errno.h>
49
50 #include "nios2.h"
51 #include "alt_types.h"
52 #include "system.h"
53
54 #ifdef __cplusplus
55 extern "C"
56 {
57 #endif /* __cplusplus */
58
59 /*
60 * Macros used by alt_irq_enabled
61 */
62 #define ALT_IRQ_ENABLED 1
63 #define ALT_IRQ_DISABLED 0
64
65 /*
66 * Number of available interrupts in internal interrupt controller.
67 */
68 #define ALT_NIRQ NIOS2_NIRQ
69
70 /*
71 * Used by alt_irq_disable_all() and alt_irq_enable_all().
72 */
73 typedef int alt_irq_context;
74
75 /* ISR Prototype */
76 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
77 typedef void (*alt_isr_func)(void* isr_context);
78 #else
79 typedef void (*alt_isr_func)(void* isr_context, alt_u32 id);
80 #endif
81
82 /*
83 * The following protypes and routines are supported by both
84 * the enhanced and legacy interrupt APIs
85 */
86
87 /*
88 * alt_irq_enabled can be called to determine if the processor's global
89 * interrupt enable is asserted. The return value is zero if interrupts
90 * are disabled, and non-zero otherwise.
91 *
92 * Whether the internal or external interrupt controller is present,
93 * individual interrupts may still be disabled. Use the other API to query
94 * a specific interrupt.
95 */
96 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_enabled (void)
97 {
98 int status;
99
100 NIOS2_READ_STATUS (status);
101
102 return status & NIOS2_STATUS_PIE_MSK;
103 }
104
105 /*
106 * alt_irq_disable_all()
107 *
108 * This routine inhibits all interrupts by negating the status register PIE
109 * bit. It returns the previous contents of the CPU status register (IRQ
110 * context) which can be used to restore the status register PIE bit to its
111 * state before this routine was called.
112 */
113 static ALT_INLINE alt_irq_context ALT_ALWAYS_INLINE
114 alt_irq_disable_all (void)
115 {
116 alt_irq_context context;
117
118 NIOS2_READ_STATUS (context);
119
120 NIOS2_WRITE_STATUS (context & ~NIOS2_STATUS_PIE_MSK);
121
122 return context;
123 }
124
125 /*
126 * alt_irq_enable_all()
127 *
128 * Enable all interrupts that were previously disabled by alt_irq_disable_all()
129 *
130 * This routine accepts a context to restore the CPU status register PIE bit
131 * to the state prior to a call to alt_irq_disable_all().
132
133 * In the case of nested calls to alt_irq_disable_all()/alt_irq_enable_all(),
134 * this means that alt_irq_enable_all() does not necessarily re-enable
135 * interrupts.
136 *
137 * This routine will perform a read-modify-write sequence to restore only
138 * status.PIE if the processor is configured with options that add additional
139 * writeable status register bits. These include the MMU, MPU, the enhanced
140 * interrupt controller port, and shadow registers. Otherwise, as a performance
141 * enhancement, status is overwritten with the prior context.
142 */
143 static ALT_INLINE void ALT_ALWAYS_INLINE
144 alt_irq_enable_all (alt_irq_context context)
145 {
146 #if (NIOS2_NUM_OF_SHADOW_REG_SETS > 0) || (defined NIOS2_EIC_PRESENT) || \
147 (defined NIOS2_MMU_PRESENT) || (defined NIOS2_MPU_PRESENT)
148 alt_irq_context status;
149
150 NIOS2_READ_STATUS (status);
151
152 status &= ~NIOS2_STATUS_PIE_MSK;
153 status |= (context & NIOS2_STATUS_PIE_MSK);
154
155 NIOS2_WRITE_STATUS (status);
156 #else
157 NIOS2_WRITE_STATUS (context);
158 #endif
159 }
160
161 /*
162 * The function alt_irq_init() is defined within the auto-generated file
163 * alt_sys_init.c. This function calls the initilization macros for all
164 * interrupt controllers in the system at config time, before any other
165 * non-interrupt controller driver is initialized.
166 *
167 * The "base" parameter is ignored and only present for backwards-compatibility.
168 * It is recommended that NULL is passed in for the "base" parameter.
169 */
170 extern void alt_irq_init (const void* base);
171
172 /*
173 * alt_irq_cpu_enable_interrupts() enables the CPU to start taking interrupts.
174 */
175 static ALT_INLINE void ALT_ALWAYS_INLINE
176 alt_irq_cpu_enable_interrupts ()
177 {
178 NIOS2_WRITE_STATUS(NIOS2_STATUS_PIE_MSK
179 #if defined(NIOS2_EIC_PRESENT) && (NIOS2_NUM_OF_SHADOW_REG_SETS > 0)
180 | NIOS2_STATUS_RSIE_MSK
181 #endif
182 );
183 }
184
185
186 /*
187 * Prototypes for the enhanced interrupt API.
188 */
189 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
190 /*
191 * alt_ic_isr_register() can be used to register an interrupt handler. If the
192 * function is succesful, then the requested interrupt will be enabled upon
193 * return.
194 */
195 extern int alt_ic_isr_register(alt_u32 ic_id,
196 alt_u32 irq,
197 alt_isr_func isr,
198 void *isr_context,
199 void *flags);
200
201 /*
202 * alt_ic_irq_enable() and alt_ic_irq_disable() enable/disable a specific
203 * interrupt by using IRQ port and interrupt controller instance.
204 */
205 int alt_ic_irq_enable (alt_u32 ic_id, alt_u32 irq);
206 int alt_ic_irq_disable(alt_u32 ic_id, alt_u32 irq);
207
208 /*
209 * alt_ic_irq_enabled() indicates whether a specific interrupt, as
210 * specified by IRQ port and interrupt controller instance is enabled.
211 */
212 alt_u32 alt_ic_irq_enabled(alt_u32 ic_id, alt_u32 irq);
213
214 #else
215 /*
216 * Prototypes for the legacy interrupt API.
217 */
218 #include "priv/alt_legacy_irq.h"
219 #endif
220
221
222 /*
223 * alt_irq_pending() returns a bit list of the current pending interrupts.
224 * This is used by alt_irq_handler() to determine which registered interrupt
225 * handlers should be called.
226 *
227 * This routine is only available for the Nios II internal interrupt
228 * controller.
229 */
230 #ifndef NIOS2_EIC_PRESENT
231 static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_irq_pending (void)
232 {
233 alt_u32 active;
234
235 NIOS2_READ_IPENDING (active);
236
237 return active;
238 }
239 #endif
240
241 #ifdef __cplusplus
242 }
243 #endif /* __cplusplus */
244
245 #endif /* __ALT_IRQ_H__ */

186行

 1 /*
2 * Prototypes for the enhanced interrupt API.
3 */
4 #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
5 /*
6 * alt_ic_isr_register() can be used to register an interrupt handler. If the
7 * function is succesful, then the requested interrupt will be enabled upon
8 * return.
9 */
10 extern int alt_ic_isr_register(alt_u32 ic_id,
11 alt_u32 irq,
12 alt_isr_func isr,
13 void *isr_context,
14 void *flags);
15
16 /*
17 * alt_ic_irq_enable() and alt_ic_irq_disable() enable/disable a specific
18 * interrupt by using IRQ port and interrupt controller instance.
19 */
20 int alt_ic_irq_enable (alt_u32 ic_id, alt_u32 irq);
21 int alt_ic_irq_disable(alt_u32 ic_id, alt_u32 irq);
22
23 /*
24 * alt_ic_irq_enabled() indicates whether a specific interrupt, as
25 * specified by IRQ port and interrupt controller instance is enabled.
26 */
27 alt_u32 alt_ic_irq_enabled(alt_u32 ic_id, alt_u32 irq);
28
29 #else
30 /*
31 * Prototypes for the legacy interrupt API.
32 */
33 #include "priv/alt_legacy_irq.h"
34 #endif

我們可以發現,當system.h有定義ALT_ENHANCED_INTERRUPT_API_PRESENT常數時,就有alt_ic_isr_register()可用,若沒定義,則#inlclude priv/alt_legacy_irq.h

alt_legacy_irq.h / C

  1 #ifndef __ALT_LEGACY_IRQ_H__
2 #define __ALT_LEGACY_IRQ_H__
3
4 /******************************************************************************
5 * *
6 * License Agreement *
7 * *
8 * Copyright (c) 2009 Altera Corporation, San Jose, California, USA. *
9 * All rights reserved. *
10 * *
11 * Permission is hereby granted, free of charge, to any person obtaining a *
12 * copy of this software and associated documentation files (the "Software"), *
13 * to deal in the Software without restriction, including without limitation *
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
15 * and/or sell copies of the Software, and to permit persons to whom the *
16 * Software is furnished to do so, subject to the following conditions: *
17 * *
18 * The above copyright notice and this permission notice shall be included in *
19 * all copies or substantial portions of the Software. *
20 * *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
27 * DEALINGS IN THE SOFTWARE. *
28 * *
29 * This agreement shall be governed in all respects by the laws of the State *
30 * of California and by the laws of the United States of America. *
31 * *
32 ******************************************************************************/
33
34 /*
35 * This file provides prototypes and inline implementations of certain routines
36 * used by the legacy interrupt API. Do not include this in your driver or
37 * application source files, use "sys/alt_irq.h" instead to access the proper
38 * public API.
39 */
40
41 #include <errno.h>
42 #include "system.h"
43
44 #ifndef NIOS2_EIC_PRESENT
45
46 #include "nios2.h"
47 #include "alt_types.h"
48
49 #include "sys/alt_irq.h"
50
51 #ifdef __cplusplus
52 extern "C"
53 {
54 #endif /* __cplusplus */
55
56 /*
57 * alt_irq_register() can be used to register an interrupt handler. If the
58 * function is succesful, then the requested interrupt will be enabled upon
59 * return.
60 */
61 extern int alt_irq_register (alt_u32 id,
62 void* context,
63 alt_isr_func handler);
64
65 /*
66 * alt_irq_disable() disables the individual interrupt indicated by "id".
67 */
68 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_disable (alt_u32 id)
69 {
70 alt_irq_context status;
71 extern volatile alt_u32 alt_irq_active;
72
73 status = alt_irq_disable_all ();
74
75 alt_irq_active &= ~(1 << id);
76 NIOS2_WRITE_IENABLE (alt_irq_active);
77
78 alt_irq_enable_all(status);
79
80 return 0;
81 }
82
83 /*
84 * alt_irq_enable() enables the individual interrupt indicated by "id".
85 */
86 static ALT_INLINE int ALT_ALWAYS_INLINE alt_irq_enable (alt_u32 id)
87 {
88 alt_irq_context status;
89 extern volatile alt_u32 alt_irq_active;
90
91 status = alt_irq_disable_all ();
92
93 alt_irq_active |= (1 << id);
94 NIOS2_WRITE_IENABLE (alt_irq_active);
95
96 alt_irq_enable_all(status);
97
98 return 0;
99 }
100
101 #ifndef ALT_EXCEPTION_STACK
102 /*
103 * alt_irq_initerruptable() should only be called from within an ISR. It is used
104 * to allow higer priority interrupts to interrupt the current ISR. The input
105 * argument, "priority", is the priority, i.e. interrupt number of the current
106 * interrupt.
107 *
108 * If this function is called, then the ISR is required to make a call to
109 * alt_irq_non_interruptible() before returning. The input argument to
110 * alt_irq_non_interruptible() is the return value from alt_irq_interruptible().
111 *
112 * Care should be taken when using this pair of functions, since they increasing
113 * the system overhead associated with interrupt handling.
114 *
115 * If you are using an exception stack then nested interrupts won't work, so
116 * these functions are not available in that case.
117 */
118 static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_irq_interruptible (alt_u32 priority)
119 {
120 extern volatile alt_u32 alt_priority_mask;
121 extern volatile alt_u32 alt_irq_active;
122
123 alt_u32 old_priority;
124
125 old_priority = alt_priority_mask;
126 alt_priority_mask = (1 << priority) - 1;
127
128 NIOS2_WRITE_IENABLE (alt_irq_active & alt_priority_mask);
129
130 NIOS2_WRITE_STATUS (1);
131
132 return old_priority;
133 }
134
135 /*
136 * See Comments above for alt_irq_interruptible() for an explanation of the use of this
137 * function.
138 */
139 static ALT_INLINE void ALT_ALWAYS_INLINE alt_irq_non_interruptible (alt_u32 mask)
140 {
141 extern volatile alt_u32 alt_priority_mask;
142 extern volatile alt_u32 alt_irq_active;
143
144 NIOS2_WRITE_STATUS (0);
145
146 alt_priority_mask = mask;
147
148 NIOS2_WRITE_IENABLE (mask & alt_irq_active);
149 }
150 #endif /* ALT_EXCEPTION_STACK */
151
152 #ifdef __cplusplus
153 }
154 #endif /* __cplusplus */
155
156 #endif /* NIOS2_EIC_PRESENT */
157
158 #endif /* __ALT_LEGACY_IRQ_H__ */

61行

extern int alt_irq_register (alt_u32 id, 
void* context,
alt_isr_func handler);

則是我們所用舊的alt_irq_register()。

至於ISR的prototype新舊不一樣,trace的方式也一樣,就不再贅述。

至於為什麼目前在subsystem的interrupt只能使用舊的ISR register方式,我並不清楚,或許Quartus II未來版本會有所改變。

使用以上方法後,就可正確的在App project收到subsystem的interrupt了。

irq011

Conclusion
我們在本文看到了Qsys與SOPC Builder在subsystem與interrupt的處理有很大的差異,也看到了目前Qsys與Nios II SBT尚有些bug待修正。目前Quartus II 11.0與Quartus II 11.1都還有system.h的bug,相信未來的版本一定會修正這個問題。假如你現在要在subsystem使用interrupt,可暫時使用本文的方式當作short term solution。

Reference
[1] Qsys Interconnect
[2] Quartus II 11.0 Release Notes
[3] Altera Wiki : New Qsys Issues for Interrupts
[4] Exception Handling

全文完。

posted on 2012-01-04 23:12  真 OO无双  阅读(6317)  评论(4编辑  收藏  举报

导航