OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [AVR32_UC3/] [DRIVERS/] [INTC/] [intc.c] - Blame information for rev 612

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 589 jeremybenn
/*This file is prepared for Doxygen automatic documentation generation.*/
2
/*! \file *********************************************************************
3
 *
4
 * \brief INTC driver for AVR32 UC3.
5
 *
6
 * AVR32 Interrupt Controller driver module.
7
 *
8
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
9
 * - Supported devices:  All AVR32 devices with an INTC module can be used.
10
 * - AppNote:
11
 *
12
 * \author               Atmel Corporation: http://www.atmel.com \n
13
 *                       Support and FAQ: http://support.atmel.no/
14
 *
15
 ******************************************************************************/
16
 
17
/* Copyright (c) 2007, Atmel Corporation All rights reserved.
18
 *
19
 * Redistribution and use in source and binary forms, with or without
20
 * modification, are permitted provided that the following conditions are met:
21
 *
22
 * 1. Redistributions of source code must retain the above copyright notice,
23
 * this list of conditions and the following disclaimer.
24
 *
25
 * 2. Redistributions in binary form must reproduce the above copyright notice,
26
 * this list of conditions and the following disclaimer in the documentation
27
 * and/or other materials provided with the distribution.
28
 *
29
 * 3. The name of ATMEL may not be used to endorse or promote products derived
30
 * from this software without specific prior written permission.
31
 *
32
 * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
33
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
35
 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
36
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
41
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
 */
43
 
44
 
45
#include <avr32/io.h>
46
#include "compiler.h"
47
#include "preprocessor.h"
48
#include "intc.h"
49
 
50
 
51
//! Values to store in the interrupt priority registers for the various interrupt priority levels.
52
extern const unsigned int ipr_val[AVR32_INTC_NUM_INT_LEVELS];
53
 
54
//! Creates a table of interrupt line handlers per interrupt group in order to optimize RAM space.
55
//! Each line handler table contains a set of pointers to interrupt handlers.
56
#if __GNUC__
57
#define DECL_INT_LINE_HANDLER_TABLE(GRP, unused) \
58
static volatile __int_handler _int_line_handler_table_##GRP[Max(AVR32_INTC_NUM_IRQS_PER_GRP##GRP, 1)];
59
#elif __ICCAVR32__
60
#define DECL_INT_LINE_HANDLER_TABLE(GRP, unused) \
61
static volatile __no_init __int_handler _int_line_handler_table_##GRP[Max(AVR32_INTC_NUM_IRQS_PER_GRP##GRP, 1)];
62
#endif
63
MREPEAT(AVR32_INTC_NUM_INT_GRPS, DECL_INT_LINE_HANDLER_TABLE, ~);
64
#undef DECL_INT_LINE_HANDLER_TABLE
65
 
66
//! Table containing for each interrupt group the number of interrupt request
67
//! lines and a pointer to the table of interrupt line handlers.
68
static const struct
69
{
70
  unsigned int num_irqs;
71
  volatile __int_handler *_int_line_handler_table;
72
} _int_handler_table[AVR32_INTC_NUM_INT_GRPS] =
73
{
74
#define INSERT_INT_LINE_HANDLER_TABLE(GRP, unused) \
75
  {AVR32_INTC_NUM_IRQS_PER_GRP##GRP, _int_line_handler_table_##GRP},
76
  MREPEAT(AVR32_INTC_NUM_INT_GRPS, INSERT_INT_LINE_HANDLER_TABLE, ~)
77
#undef INSERT_INT_LINE_HANDLER_TABLE
78
};
79
 
80
 
81
/*! \brief Default interrupt handler.
82
 *
83
 * \note Taken and adapted from Newlib.
84
 */
85
#if __GNUC__
86
__attribute__((__interrupt__))
87
#elif __ICCAVR32__
88
__interrupt
89
#endif
90
static void _unhandled_interrupt(void)
91
{
92
  // Catch unregistered interrupts.
93
  while (TRUE);
94
}
95
 
96
 
97
/*! \brief Gets the interrupt handler of the current event at the \a int_lev
98
 *         interrupt priority level (called from exception.S).
99
 *
100
 * \param int_lev Interrupt priority level to handle.
101
 *
102
 * \return Interrupt handler to execute.
103
 *
104
 * \note Taken and adapted from Newlib.
105
 */
106
__int_handler _get_interrupt_handler(unsigned int int_lev)
107
{
108
  // ICR3 is mapped first, ICR0 last.
109
  // Code in exception.S puts int_lev in R12 which is used by AVR32-GCC to pass
110
  // a single argument to a function.
111
  unsigned int int_grp = (&AVR32_INTC.icr3)[INT3 - int_lev];
112
  unsigned int int_req = AVR32_INTC.irr[int_grp];
113
 
114
  // As an interrupt may disappear while it is being fetched by the CPU
115
  // (spurious interrupt caused by a delayed response from an MCU peripheral to
116
  // an interrupt flag clear or interrupt disable instruction), check if there
117
  // are remaining interrupt lines to process.
118
  // If a spurious interrupt occurs, the status register (SR) contains an
119
  // execution mode and interrupt level masks corresponding to a level 0
120
  // interrupt, whatever the interrupt priority level causing the spurious
121
  // event. This behavior has been chosen because a spurious interrupt has not
122
  // to be a priority one and because it may not cause any trouble to other
123
  // interrupts.
124
  // However, these spurious interrupts place the hardware in an unstable state
125
  // and could give problems in other/future versions of the CPU, so the
126
  // software has to be written so that they never occur. The only safe way of
127
  // achieving this is to always clear or disable peripheral interrupts with the
128
  // following sequence:
129
  // 1: Mask the interrupt in the CPU by setting GM (or IxM) in SR.
130
  // 2: Perform the bus access to the peripheral register that clears or
131
  //    disables the interrupt.
132
  // 3: Wait until the interrupt has actually been cleared or disabled by the
133
  //    peripheral. This is usually performed by reading from a register in the
134
  //    same peripheral (it DOES NOT have to be the same register that was
135
  //    accessed in step 2, but it MUST be in the same peripheral), what takes
136
  //    bus system latencies into account, but peripheral internal latencies
137
  //    (generally 0 cycle) also have to be considered.
138
  // 4: Unmask the interrupt in the CPU by clearing GM (or IxM) in SR.
139
  // Note that steps 1 and 4 are useless inside interrupt handlers as the
140
  // corresponding interrupt level is automatically masked by IxM (unless IxM is
141
  // explicitly cleared by the software).
142
  //
143
  // Get the right IRQ handler.
144
  //
145
  // If several interrupt lines are active in the group, the interrupt line with
146
  // the highest number is selected. This is to be coherent with the
147
  // prioritization of interrupt groups performed by the hardware interrupt
148
  // controller.
149
  //
150
  // If no handler has been registered for the pending interrupt,
151
  // _unhandled_interrupt will be selected thanks to the initialization of
152
  // _int_line_handler_table_x by INTC_init_interrupts.
153
  //
154
  // exception.S will provide the interrupt handler with a clean interrupt stack
155
  // frame, with nothing more pushed onto the stack. The interrupt handler must
156
  // manage the `rete' instruction, what can be done thanks to pure assembly,
157
  // inline assembly or the `__attribute__((__interrupt__))' C function
158
  // attribute.
159
  return (int_req) ? _int_handler_table[int_grp]._int_line_handler_table[32 - clz(int_req) - 1] : NULL;
160
}
161
 
162
 
163
void INTC_init_interrupts(void)
164
{
165
  unsigned int int_grp, int_req;
166
 
167
  // For all interrupt groups,
168
  for (int_grp = 0; int_grp < AVR32_INTC_NUM_INT_GRPS; int_grp++)
169
  {
170
    // For all interrupt request lines of each group,
171
    for (int_req = 0; int_req < _int_handler_table[int_grp].num_irqs; int_req++)
172
    {
173
      // Assign _unhandled_interrupt as default interrupt handler.
174
      _int_handler_table[int_grp]._int_line_handler_table[int_req] = &_unhandled_interrupt;
175
    }
176
 
177
    // Set the interrupt group priority register to its default value.
178
    // By default, all interrupt groups are linked to the interrupt priority
179
    // level 0 and to the interrupt vector _int0.
180
    AVR32_INTC.ipr[int_grp] = ipr_val[INT0];
181
  }
182
}
183
 
184
 
185
void INTC_register_interrupt(__int_handler handler, unsigned int irq, unsigned int int_lev)
186
{
187
  // Determine the group of the IRQ.
188
  unsigned int int_grp = irq / AVR32_INTC_MAX_NUM_IRQS_PER_GRP;
189
 
190
  // Store in _int_line_handler_table_x the pointer to the interrupt handler, so
191
  // that _get_interrupt_handler can retrieve it when the interrupt is vectored.
192
  _int_handler_table[int_grp]._int_line_handler_table[irq % AVR32_INTC_MAX_NUM_IRQS_PER_GRP] = handler;
193
 
194
  // Program the corresponding IPRX register to set the interrupt priority level
195
  // and the interrupt vector offset that will be fetched by the core interrupt
196
  // system.
197
  // NOTE: The _intx functions are intermediate assembly functions between the
198
  // core interrupt system and the user interrupt handler.
199
  AVR32_INTC.ipr[int_grp] = ipr_val[int_lev & (AVR32_INTC_IPR0_INTLEV_MASK >> AVR32_INTC_IPR0_INTLEV_OFFSET)];
200
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.