1 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
2 // ==== IRQ Controller API ====
4 \defgroup irq_ctrl_gr Interrupts and Exceptions
5 \brief Generic functions to access the Interrupt Controller.
7 \details This section describes the device agnostic interrupt API viable for a wide range of specific interrupt controllers.
8 The IRQ Controller API allows interrupt dependend applications to be easily portable across a wide range of controllers.
10 \note The default implementation for \ref GIC_functions "Arm GIC (Generic Interrupt Controller)" can be found in \ref irq_ctrl_gic.c.
11 It uses \c weak functions thus it can easily be overwritten by an alternative user implementation if needed.
13 The Armv7-A architecture defines a common set of first level exceptions, see table below.
15 | Exception | CMSIS Handler | Offset | Description |
16 |-------------------------------|---------------|--------|-----------------------------------------------------------------------------|
17 | Reset | Reset_Handler | 0x0000 | First instruction executed after reset. |
18 | Undefined Instruction (Undef) | Undef_Handler | 0x0004 | Signals usage of an illegal instructions. |
19 | Supervisor Call (SVC) | SVC_Handler | 0x0008 | Issued by software using SVC instruction. |
20 | Prefetch Abort (PAbt) | PAbt_Handler | 0x000C | Signals a memory abort on istruction fetch. |
21 | Data Abort (DAbt) | DAbt_Handler | 0x0010 | Signals a memory abort on data read or write. |
22 | Hyp Trap | (NOP) | 0x0014 | Hypervisor instruction trap, only available with Virtualization Extensions. |
23 | IRQ interrupt | IRQ_Handler | 0x0018 | Interrupt Request (typically from Interrupt Controller) |
24 | FIQ interrupt | FIQ_Handler | 0x001C | Fast Interrupt Request (typically from Interrupt Controller) |
26 By default those handlers are defined as weak empty functions by the \ref startup_c_sec "device specific startup code".
27 Software and peripheral interrupts are all handled by one of the both central interrupt handlers (IRQ and FIQ). These needs to
28 be implemented application specific. If an RTOS is used the interrupt handlers are typically provided by the RTOS, e.g. when using
29 <a href="../../RTOS2/html/rtx5_impl.html">RTX5</a>.
31 The interrupts available depends on the actual device in use. According to CMSIS specification the interrupts are defined in \ref IRQn_Type in \ref device_h_pg. Using the generic IRQ API one can easily enable and disable interrupts, set up priorities, modes and preemption rules, and register interrupt callbacks.
41 IRQ_ClearPending((IRQn_ID_t)SGI0_IRQn);
45 /* Initialize the Interrupt Controller */
48 /* Register the user defined handler function */
49 IRQ_SetHandler((IRQn_ID_t)SGI0_IRQn, SGI0_Handler);
51 /* Set the priority considering the priority grouping */
52 const uint32_t subprio = IRQ_GetPriorityGroupBits();
53 IRQ_SetPriority((IRQn_ID_t)SGI0_IRQn, 1u << subprio);
55 /* Set interrupt mode to falling edge */
56 IRQ_SetMode((IRQn_ID_t)SGI0_IRQn, IRQ_MODE_TYPE_IRQ | IRQ_MODE_CPU_0 | IRQ_MODE_TRIG_EDGE | IRQ_MODE_TRIG_EDGE_FALLING);
58 IRQ_Enable((IRQn_ID_t)SGI0_IRQn);
60 /* Trigger interrupt */
61 IRQ_SetPending((IRQn_ID_t)SGI0_IRQn);
63 IRQ_Disable((IRQn_ID_t)SGI0_IRQn);
69 /**************************************************************************************************/
70 /** \brief Definition of IRQn numbers
73 The core exception enumeration names for IRQn values are defined in the \ref device_h_pg.
75 The table below describes the core exception names in Cortex-A core.
80 /****** Cortex-A Specific Interrupt Numbers **************************/
81 /* Software Generated Interrupts */
82 SGI0_IRQn = 0, ///< Software Generated Interrupt 0
83 SGI1_IRQn = 1, ///< Software Generated Interrupt 1
84 SGI2_IRQn = 2, ///< Software Generated Interrupt 2
85 SGI3_IRQn = 3, ///< Software Generated Interrupt 3
86 SGI4_IRQn = 4, ///< Software Generated Interrupt 4
87 SGI5_IRQn = 5, ///< Software Generated Interrupt 5
88 SGI6_IRQn = 6, ///< Software Generated Interrupt 6
89 SGI7_IRQn = 7, ///< Software Generated Interrupt 7
90 SGI8_IRQn = 8, ///< Software Generated Interrupt 8
91 SGI9_IRQn = 9, ///< Software Generated Interrupt 9
92 SGI10_IRQn = 10, ///< Software Generated Interrupt 10
93 SGI11_IRQn = 11, ///< Software Generated Interrupt 11
94 SGI12_IRQn = 12, ///< Software Generated Interrupt 12
95 SGI13_IRQn = 13, ///< Software Generated Interrupt 13
96 SGI14_IRQn = 14, ///< Software Generated Interrupt 14
97 SGI15_IRQn = 15, ///< Software Generated Interrupt 15
99 VirtualMaintenanceInterrupt_IRQn = 25, ///< Virtual Maintenance Interrupt
100 HypervisorTimer_IRQn = 26, ///< Hypervisor Timer Interrupt
101 VirtualTimer_IRQn = 27, ///< Virtual Timer Interrupt
102 Legacy_nFIQ_IRQn = 28, ///< Legacy nFIQ Interrupt
103 SecurePhyTimer_IRQn = 29, ///< Secure Physical Timer Interrupt
104 NonSecurePhyTimer_IRQn = 30, ///< Non-Secure Physical Timer Interrupt
105 Legacy_nIRQ_IRQn = 31, ///< Legacy nIRQ Interrupt
110 \defgroup irq_mode_defs IRQ Mode Bit-Masks
111 \brief Configure interrupt line mode
114 The following codes are used as values for the parameter \em mode of the function \ref IRQ_SetMode to configure interrupt line mode.
115 They are also returned by the function \ref IRQ_GetMode when retrieving interrupt line mode.
117 The values of \b IRQ_MODE_TRIG_x definitions specify
118 The values of \b IRQ_MODE_TYPE_x definitions specify
119 The values of \b IRQ_MODE_DOMAIN_x definitions specify
120 The values of \b IRQ_MODE_CPU_x definitions specify
122 // Interrupt mode bit-masks
123 \def IRQ_MODE_TRIG_LEVEL
124 \def IRQ_MODE_TRIG_LEVEL_LOW
125 \def IRQ_MODE_TRIG_LEVEL_HIGH
126 \def IRQ_MODE_TRIG_EDGE
127 \def IRQ_MODE_TRIG_EDGE_RISING
128 \def IRQ_MODE_TRIG_EDGE_FALLING
129 \def IRQ_MODE_TRIG_EDGE_BOTH
131 \def IRQ_MODE_TYPE_IRQ
132 \def IRQ_MODE_TYPE_FIQ
134 \def IRQ_MODE_DOMAIN_NONSECURE
135 \def IRQ_MODE_DOMAIN_SECURE
137 \def IRQ_MODE_CPU_ALL
152 \defgroup irq_priority_defs IRQ Priority Bit-Masks
153 \brief Definitions used by interrupt priority functions.
156 The following values are used by the interrupt priority functions.
158 The value of \b IRQ_PRIORITY_Msk specifies maximum interrupt priority value and can be used as parameter for the functions
159 \ref IRQ_GetPriority and \ref IRQ_SetPriorityGroupBits to retrieve implementation specific priority values.
161 The value of \b IRQ_PRIORITY_ERROR is used by functions \ref IRQ_GetPriority, IRQ_GetPriorityMask and \ref IRQ_GetPriorityGroupBits
162 to signal function execution error.
164 \def IRQ_PRIORITY_Msk
165 \def IRQ_PRIORITY_ERROR
169 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
171 \fn int32_t IRQ_Initialize (void)
172 \details This function initializes interrupt controller.
174 It disables all interrupt sources, clears all pending interrupts, sets interrupt priorities to highest priority and
175 configures priority mask to lowest priority. IRQ and FIQ signal lines should be enabled and all interrupt handlers should
178 For Arm GIC the default implementation looks like the following example:
181 /// Number of implemented interrupt lines
182 #ifndef IRQ_GIC_LINE_COUNT
183 #define IRQ_GIC_LINE_COUNT (1020U)
186 static IRQHandler IRQTable[IRQ_GIC_LINE_COUNT] = { 0U };
188 int32_t IRQ_Initialize (void) {
191 for (i = 0U; i < IRQ_GIC_LINE_COUNT; i++) {
192 IRQTable[i] = (IRQHandler)NULL;
200 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
202 \fn int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler)
203 \details This function registers address of the interrupt handler callback function corresponding to the specified interrupt
206 For Arm GIC the default implementation looks like the following example:
209 int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler) {
212 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
213 IRQTable[irqn] = handler;
224 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
226 \fn IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn)
227 \details This function retrieves address of the interrupt handler callback function corresponding to the specified interrupt
230 For Arm GIC the default implementation looks like the following example:
233 IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn) {
236 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
247 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
249 \fn int32_t IRQ_Enable (IRQn_ID_t irqn)
250 \details This function enables forwarding of the corresponding interrupt to the CPU.
252 For Arm GIC the default implementation looks like the following example:
255 int32_t IRQ_Enable (IRQn_ID_t irqn) {
258 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
259 GIC_EnableIRQ ((IRQn_Type)irqn);
270 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
272 \fn int32_t IRQ_Disable (IRQn_ID_t irqn)
273 \details This function disables forwarding of the corresponding interrupt to the CPU.
275 For Arm GIC the default implementation looks like the following example:
278 int32_t IRQ_Disable (IRQn_ID_t irqn) {
281 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
282 GIC_DisableIRQ ((IRQn_Type)irqn);
293 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
295 \fn uint32_t IRQ_GetEnableState (IRQn_ID_t irqn)
296 \details This function retrieves the interrupt enable status of the interrupt identified by the irqn parameter.
298 Interrupt enable status can be either disabled (0) or enabled (1). Disabled status is returned for interrupts
299 which cannot be identified by irqn.
301 For Arm GIC the default implementation looks like the following example:
304 uint32_t IRQ_GetEnableState (IRQn_ID_t irqn) {
307 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
308 enable = GIC_GetEnableIRQ((IRQn_Type)irqn);
318 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
320 \fn int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode)
322 \details This function configures the interrupt triggering mode, type, secure access and target CPUs of the interrupt
323 (see \ref irq_mode_defs) identified by the irqn parameter.
325 For Arm GIC the default implementation looks like the following example:
328 int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode) {
337 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
338 // Check triggering mode
339 val = (mode & IRQ_MODE_TRIG_Msk);
341 if (val == IRQ_MODE_TRIG_LEVEL) {
343 } else if (val == IRQ_MODE_TRIG_EDGE) {
349 // Check interrupt type
350 val = mode & IRQ_MODE_TYPE_Msk;
352 if (val != IRQ_MODE_TYPE_IRQ) {
356 // Check interrupt domain
357 val = mode & IRQ_MODE_DOMAIN_Msk;
359 if (val == IRQ_MODE_DOMAIN_NONSECURE) {
362 // Check security extensions support
363 val = GIC_DistributorInfo() & (1UL << 10U);
366 // Security extensions are supported
373 // Check interrupt CPU targets
374 val = mode & IRQ_MODE_CPU_Msk;
376 if (val == IRQ_MODE_CPU_ALL) {
379 cpu = val >> IRQ_MODE_CPU_Pos;
382 // Apply configuration if no mode error
384 GIC_SetConfiguration((IRQn_Type)irqn, cfg);
385 GIC_SetTarget ((IRQn_Type)irqn, cpu);
388 GIC_SetGroup ((IRQn_Type)irqn, secure);
398 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
400 \fn uint32_t IRQ_GetMode (IRQn_ID_t irqn)
401 \details This function retrieves interrupt mode configuration of the interrupt identified by the irqn parameter.
402 \ref IRQ_MODE_ERROR is returned for interrupts which cannot be identified by irqn.
404 For Arm GIC the default implementation looks like the following example:
407 uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
411 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
412 mode = IRQ_MODE_TYPE_IRQ;
415 val = GIC_GetConfiguration((IRQn_Type)irqn);
417 if ((val & 2U) != 0U) {
418 // Corresponding interrupt is edge triggered
419 mode |= IRQ_MODE_TRIG_EDGE;
421 // Corresponding interrupt is level triggered
422 mode |= IRQ_MODE_TRIG_LEVEL;
425 // Get interrupt CPU targets
426 mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
429 mode = IRQ_MODE_ERROR;
437 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
439 \fn IRQn_ID_t IRQ_GetActiveIRQ (void)
440 \details This function retrieves the interrupt ID number of current IRQ source and acknowledges the interrupt.
442 For Arm GIC the default implementation looks like the following example:
445 IRQn_ID_t IRQ_GetActiveIRQ (void) {
448 irqn = (IRQn_ID_t)GIC_AcknowledgePending();
455 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
457 \fn IRQn_ID_t IRQ_GetActiveFIQ (void)
458 \details This function retrieves the interrupt ID number of current FIQ source and acknowledges the interrupt.
460 For Arm GIC the default implementation looks like the following example:
463 IRQn_ID_t IRQ_GetActiveFIQ (void) {
464 // FIQ is not supported, return invalid ID
465 return ((IRQn_ID_t)-1);
470 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
472 \fn int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn)
473 \details This function informs the interrupt controller that the interrupt service routine processing of the currently
474 active interrupt request is completed.
476 The parameter irqn should specify the value previously returned by the \ref IRQ_GetActiveIRQ or \ref IRQ_GetActiveFIQ functions.
478 For Arm GIC the default implementation looks like the following example:
481 int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
484 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
485 GIC_EndInterrupt ((IRQn_Type)irqn);
501 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
503 \fn int32_t IRQ_SetPending (IRQn_ID_t irqn)
504 \details This function sets the pending status of the interrupt identified by the irqn parameter.
506 For Arm GIC the default implementation looks like the following example:
509 int32_t IRQ_SetPending (IRQn_ID_t irqn) {
512 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
513 GIC_SetPendingIRQ ((IRQn_Type)irqn);
524 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
526 \fn uint32_t IRQ_GetPending (IRQn_ID_t irqn)
527 \details This function retrieves the pending status of the interrupt identified by the irqn parameter.
529 Interrupt pending status can be either not pending (0) or pending (1). Not pending status is returned for interrupts which
530 cannot be identified by irqn.
532 For Arm GIC the default implementation looks like the following example:
535 uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
538 if ((irqn >= 16) && (irqn < IRQ_GIC_LINE_COUNT)) {
539 pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
544 return (pending & 1U);
549 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
551 \fn int32_t IRQ_ClearPending (IRQn_ID_t irqn)
552 \details This function clears the pending status of the interrupt identified by the irqn parameter.
554 For Arm GIC the default implementation looks like the following example:
557 int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
560 if ((irqn >= 16) && (irqn < IRQ_GIC_LINE_COUNT)) {
561 GIC_ClearPendingIRQ ((IRQn_Type)irqn);
572 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
574 \fn int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority)
575 \details This function sets the priority of the interrupt identified by the irqn parameter.
577 Higher priority numbers have lower priority. The highest interrupt priority has priority value 0, while the lowest value
578 depends on the number of implemented priority levels.
580 The number of implemented priority bits can be determined by setting value \ref IRQ_PRIORITY_Msk to arbitrary irqn and by
581 retrieving the actual stored value with IRQ_GetPriority function.
583 For Arm GIC the default implementation looks like the following example:
586 int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
589 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
590 GIC_SetPriority ((IRQn_Type)irqn, priority);
601 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
603 \fn uint32_t IRQ_GetPriority (IRQn_ID_t irqn)
604 \details This function retrieves the priority of the interrupt identified by the irqn parameter.
606 The valid priority value can be from zero (0) to the value of \ref IRQ_PRIORITY_Msk. \ref IRQ_PRIORITY_ERROR bit is set in
607 returned value for interrupts which cannot be identified by irqn.
609 For Arm GIC the default implementation looks like the following example:
612 uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
615 if ((irqn >= 0) && (irqn < IRQ_GIC_LINE_COUNT)) {
616 priority = GIC_GetPriority ((IRQn_Type)irqn);
618 priority = IRQ_PRIORITY_ERROR;
626 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
628 \fn int32_t IRQ_SetPriorityMask (uint32_t priority)
629 \details This function sets the priority masking threshold for the current processor.
631 It ensures that only interrupts with a higher priority than priority threshold value are signaled to the target processor.
632 Function returns error status -1 if priority masking is not supported.
634 For Arm GIC the default implementation looks like the following example:
637 IRQ_SetPriorityMask (uint32_t priority) {
638 GIC_SetInterfacePriorityMask (priority);
644 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
646 \fn uint32_t IRQ_GetPriorityMask (void)
647 \details This function retrieves the priority masking threshold for the current processor.
649 \ref IRQ_PRIORITY_ERROR value is returned if priority masking is not supported.
651 For Arm GIC the default implementation looks like the following example:
654 uint32_t IRQ_GetPriorityMask (void) {
655 return GIC_GetInterfacePriorityMask();
660 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
662 \fn int32_t IRQ_SetPriorityGroupBits (uint32_t bits)
663 \details This function sets the number of MSB priority bits used to determine whether a pending interrupt has sufficient
664 priority to preempt a currently active interrupt.
666 The number of implemented group priority bits can be determined by setting value \ref IRQ_PRIORITY_Msk and by retrieving the
667 actual stored value with \ref IRQ_GetPriorityGroupBits function.
668 Function returns error status -1 if priority grouping is not supported.
670 For Arm GIC the default implementation looks like the following example:
673 int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
676 if (bits == IRQ_PRIORITY_Msk) {
681 GIC_SetBinaryPoint (7U - bits);
692 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
694 \fn uint32_t IRQ_GetPriorityGroupBits (void)
695 \details This function retrieves the number of MSB bits used to determine whether a pending interrupt has sufficient
696 priority to preempt a currently active interrupt.
698 \ref IRQ_PRIORITY_ERROR value is returned when priority grouping is not supported.
700 For Arm GIC the default implementation looks like the following example:
703 uint32_t IRQ_GetPriorityGroupBits (void) {
706 bp = GIC_GetBinaryPoint() & 0x07U;
713 /** @} */ /* group irq_ctrl_gr */