1 /******************************************************************************
2 * Filename: interrupt.c
3 * Revised: 2017-05-19 11:31:39 +0200 (Fri, 19 May 2017)
4 * Revision: 49017
5 *
6 * Description: Driver for the NVIC Interrupt Controller.
7 *
8 * Copyright (c) 2015 - 2020, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38
39 #include "interrupt.h"
40
41 //*****************************************************************************
42 //
43 // Handle support for DriverLib in ROM:
44 // This section will undo prototype renaming made in the header file
45 //
46 //*****************************************************************************
47 #if !defined(DOXYGEN)
48 #undef IntRegister
49 #define IntRegister NOROM_IntRegister
50 #undef IntUnregister
51 #define IntUnregister NOROM_IntUnregister
52 #undef IntPriorityGroupingSet
53 #define IntPriorityGroupingSet NOROM_IntPriorityGroupingSet
54 #undef IntPriorityGroupingGet
55 #define IntPriorityGroupingGet NOROM_IntPriorityGroupingGet
56 #undef IntPrioritySet
57 #define IntPrioritySet NOROM_IntPrioritySet
58 #undef IntPriorityGet
59 #define IntPriorityGet NOROM_IntPriorityGet
60 #undef IntEnable
61 #define IntEnable NOROM_IntEnable
62 #undef IntDisable
63 #define IntDisable NOROM_IntDisable
64 #undef IntPendSet
65 #define IntPendSet NOROM_IntPendSet
66 #undef IntPendGet
67 #define IntPendGet NOROM_IntPendGet
68 #undef IntPendClear
69 #define IntPendClear NOROM_IntPendClear
70 #endif
71
72 //*****************************************************************************
73 //
74 //! This is a mapping between priority grouping encodings and the number of
75 //! preemption priority bits.
76 //
77 //*****************************************************************************
78 static const uint32_t g_pui32Priority[] =
79 {
80 NVIC_APINT_PRIGROUP_0_8, NVIC_APINT_PRIGROUP_1_7, NVIC_APINT_PRIGROUP_2_6,
81 NVIC_APINT_PRIGROUP_3_5, NVIC_APINT_PRIGROUP_4_4, NVIC_APINT_PRIGROUP_5_3,
82 NVIC_APINT_PRIGROUP_6_2, NVIC_APINT_PRIGROUP_7_1
83 };
84
85 //*****************************************************************************
86 //
87 //! This is a mapping between interrupt number and the register that contains
88 //! the priority encoding for that interrupt.
89 //
90 //*****************************************************************************
91 static const uint32_t g_pui32Regs[] =
92 {
93 0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3, NVIC_PRI0, NVIC_PRI1,
94 NVIC_PRI2, NVIC_PRI3, NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7,
95 NVIC_PRI8, NVIC_PRI9, NVIC_PRI10, NVIC_PRI11, NVIC_PRI12, NVIC_PRI13
96 };
97
98 //*****************************************************************************
99 //
100 //! \brief The default interrupt handler.
101 //!
102 //! This is the default interrupt handler for all interrupts. It simply loops
103 //! forever so that the system state is preserved for observation by a
104 //! debugger. Since interrupts should be disabled before unregistering the
105 //! corresponding handler, this should never be called.
106 //!
107 //! \return None
108 //
109 //*****************************************************************************
110 static void
IntDefaultHandler(void)111 IntDefaultHandler(void)
112 {
113 // Go into an infinite loop.
114 while(1)
115 {
116 }
117 }
118
119 //*****************************************************************************
120 //
121 //! \brief Global pointer to the (dynamic) interrupt vector table when placed in SRAM.
122 //!
123 //! Interrupt vector table is placed at "vtable_ram" defined in the linker file
124 //! provided by Texas Instruments. By default, this is at the beginning of SRAM.
125 //!
126 //! \note See \ti_code{interrupt.c} for compiler specific implementation!
127 //
128 //*****************************************************************************
129 #if defined(DOXYGEN)
130 // Dummy void pointer used as placeholder to generate Doxygen documentation.
131 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void);
132 #elif defined(__IAR_SYSTEMS_ICC__)
133 #pragma data_alignment=256
134 static __no_init void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) @ ".vtable_ram";
135 #elif defined(__TI_COMPILER_VERSION__)
136 #pragma DATA_ALIGN(g_pfnRAMVectors, 256)
137 #pragma DATA_SECTION(g_pfnRAMVectors, ".vtable_ram")
138 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void);
139 #elif defined (__CC_ARM)
140 static __attribute__((section("vtable_ram")))
141 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256)));
142 #else
143 static __attribute__((section("vtable_ram")))
144 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256)));
145 #endif
146
147 //*****************************************************************************
148 //
149 // Registers a function to be called when an interrupt occurs.
150 //
151 //*****************************************************************************
152 void
IntRegister(uint32_t ui32Interrupt,void (* pfnHandler)(void))153 IntRegister(uint32_t ui32Interrupt, void (*pfnHandler)(void))
154 {
155 uint32_t ui32Idx, ui32Value;
156
157 // Check the arguments.
158 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
159
160 // Make sure that the RAM vector table is correctly aligned.
161 ASSERT(((uint32_t)g_pfnRAMVectors & 0x000000ff) == 0);
162
163 // See if the RAM vector table has been initialized.
164 if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors)
165 {
166 // Copy the vector table from the beginning of FLASH to the RAM vector
167 // table.
168 ui32Value = HWREG(NVIC_VTABLE);
169 for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++)
170 {
171 g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) +
172 ui32Value);
173 }
174
175 // Point NVIC at the RAM vector table.
176 HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors;
177 }
178
179 // Save the interrupt handler.
180 g_pfnRAMVectors[ui32Interrupt] = pfnHandler;
181 }
182
183 //*****************************************************************************
184 //
185 // Unregisters the function to be called when an interrupt occurs.
186 //
187 //*****************************************************************************
188 void
IntUnregister(uint32_t ui32Interrupt)189 IntUnregister(uint32_t ui32Interrupt)
190 {
191 // Check the arguments.
192 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
193
194 // Reset the interrupt handler.
195 g_pfnRAMVectors[ui32Interrupt] = IntDefaultHandler;
196 }
197
198 //*****************************************************************************
199 //
200 // Sets the priority grouping of the interrupt controller.
201 //
202 //*****************************************************************************
203 void
IntPriorityGroupingSet(uint32_t ui32Bits)204 IntPriorityGroupingSet(uint32_t ui32Bits)
205 {
206 // Check the arguments.
207 ASSERT(ui32Bits < NUM_PRIORITY);
208
209 // Set the priority grouping.
210 HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | g_pui32Priority[ui32Bits];
211 }
212
213 //*****************************************************************************
214 //
215 // Gets the priority grouping of the interrupt controller
216 //
217 //*****************************************************************************
218 uint32_t
IntPriorityGroupingGet(void)219 IntPriorityGroupingGet(void)
220 {
221 uint32_t ui32Loop, ui32Value;
222
223 // Read the priority grouping.
224 ui32Value = HWREG(NVIC_APINT) & NVIC_APINT_PRIGROUP_M;
225
226 // Loop through the priority grouping values.
227 for(ui32Loop = 0; ui32Loop < NUM_PRIORITY; ui32Loop++)
228 {
229 // Stop looping if this value matches.
230 if(ui32Value == g_pui32Priority[ui32Loop])
231 {
232 break;
233 }
234 }
235
236 // Return the number of priority bits.
237 return(ui32Loop);
238 }
239
240 //*****************************************************************************
241 //
242 // Sets the priority of an interrupt
243 //
244 //*****************************************************************************
245 void
IntPrioritySet(uint32_t ui32Interrupt,uint8_t ui8Priority)246 IntPrioritySet(uint32_t ui32Interrupt, uint8_t ui8Priority)
247 {
248 uint32_t ui32Temp;
249
250 // Check the arguments.
251 ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
252 ASSERT(ui8Priority <= INT_PRI_LEVEL7);
253
254 // Set the interrupt priority.
255 ui32Temp = HWREG(g_pui32Regs[ui32Interrupt >> 2]);
256 ui32Temp &= ~(0xFF << (8 * (ui32Interrupt & 3)));
257 ui32Temp |= ui8Priority << (8 * (ui32Interrupt & 3));
258 HWREG(g_pui32Regs[ui32Interrupt >> 2]) = ui32Temp;
259 }
260
261 //*****************************************************************************
262 //
263 // Gets the priority of an interrupt
264 //
265 //*****************************************************************************
266 int32_t
IntPriorityGet(uint32_t ui32Interrupt)267 IntPriorityGet(uint32_t ui32Interrupt)
268 {
269 // Check the arguments.
270 ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
271
272 // Return the interrupt priority.
273 return((HWREG(g_pui32Regs[ui32Interrupt >> 2]) >> (8 * (ui32Interrupt & 3))) &
274 0xFF);
275 }
276
277 //*****************************************************************************
278 //
279 // Enables an interrupt
280 //
281 //*****************************************************************************
282 void
IntEnable(uint32_t ui32Interrupt)283 IntEnable(uint32_t ui32Interrupt)
284 {
285 // Check the arguments.
286 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
287
288 // Determine the interrupt to enable.
289 if(ui32Interrupt == INT_MEMMANAGE_FAULT)
290 {
291 // Enable the MemManage interrupt.
292 HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_MEM;
293 }
294 else if(ui32Interrupt == INT_BUS_FAULT)
295 {
296 // Enable the bus fault interrupt.
297 HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_BUS;
298 }
299 else if(ui32Interrupt == INT_USAGE_FAULT)
300 {
301 // Enable the usage fault interrupt.
302 HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_USAGE;
303 }
304 else if(ui32Interrupt == INT_SYSTICK)
305 {
306 // Enable the System Tick interrupt.
307 HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN;
308 }
309 else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
310 {
311 // Enable the general interrupt.
312 HWREG(NVIC_EN0) = 1 << (ui32Interrupt - 16);
313 }
314 else if(ui32Interrupt >= 48)
315 {
316 // Enable the general interrupt.
317 HWREG(NVIC_EN1) = 1 << (ui32Interrupt - 48);
318 }
319 }
320
321 //*****************************************************************************
322 //
323 // Disables an interrupt
324 //
325 //*****************************************************************************
326 void
IntDisable(uint32_t ui32Interrupt)327 IntDisable(uint32_t ui32Interrupt)
328 {
329 // Check the arguments.
330 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
331
332 // Determine the interrupt to disable.
333 if(ui32Interrupt == INT_MEMMANAGE_FAULT)
334 {
335 // Disable the MemManage interrupt.
336 HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_MEM);
337 }
338 else if(ui32Interrupt == INT_BUS_FAULT)
339 {
340 // Disable the bus fault interrupt.
341 HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_BUS);
342 }
343 else if(ui32Interrupt == INT_USAGE_FAULT)
344 {
345 // Disable the usage fault interrupt.
346 HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_USAGE);
347 }
348 else if(ui32Interrupt == INT_SYSTICK)
349 {
350 // Disable the System Tick interrupt.
351 HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN);
352 }
353 else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
354 {
355 // Disable the general interrupt.
356 HWREG(NVIC_DIS0) = 1 << (ui32Interrupt - 16);
357 }
358 else if(ui32Interrupt >= 48)
359 {
360 // Disable the general interrupt.
361 HWREG(NVIC_DIS1) = 1 << (ui32Interrupt - 48);
362 }
363 }
364
365 //*****************************************************************************
366 //
367 // Pends an interrupt
368 //
369 //*****************************************************************************
370 void
IntPendSet(uint32_t ui32Interrupt)371 IntPendSet(uint32_t ui32Interrupt)
372 {
373 // Check the arguments.
374 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
375
376 // Determine the interrupt to pend.
377 if(ui32Interrupt == INT_NMI_FAULT)
378 {
379 // Pend the NMI interrupt.
380 HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_NMI_SET;
381 }
382 else if(ui32Interrupt == INT_PENDSV)
383 {
384 // Pend the PendSV interrupt.
385 HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PEND_SV;
386 }
387 else if(ui32Interrupt == INT_SYSTICK)
388 {
389 // Pend the SysTick interrupt.
390 HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET;
391 }
392 else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
393 {
394 // Pend the general interrupt.
395 HWREG(NVIC_PEND0) = 1 << (ui32Interrupt - 16);
396 }
397 else if(ui32Interrupt >= 48)
398 {
399 // Pend the general interrupt.
400 HWREG(NVIC_PEND1) = 1 << (ui32Interrupt - 48);
401 }
402 }
403
404 //*****************************************************************************
405 //
406 // Query whether an interrupt is pending
407 //
408 //*****************************************************************************
409 bool
IntPendGet(uint32_t ui32Interrupt)410 IntPendGet(uint32_t ui32Interrupt)
411 {
412 uint32_t ui32IntPending;
413
414 // Check the arguments.
415 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
416
417 // Assume no interrupts are pending.
418 ui32IntPending = 0;
419
420 // The lower 16 IRQ vectors are unsupported by this function
421 if (ui32Interrupt < 16)
422 {
423
424 return 0;
425 }
426
427 // Subtract lower 16 irq vectors
428 ui32Interrupt -= 16;
429
430 // Check if the interrupt is pending
431 ui32IntPending = HWREG(NVIC_PEND0 + (ui32Interrupt / 32));
432 ui32IntPending &= (1 << (ui32Interrupt & 31));
433
434 return ui32IntPending ? true : false;
435 }
436
437 //*****************************************************************************
438 //
439 // Unpends an interrupt
440 //
441 //*****************************************************************************
442 void
IntPendClear(uint32_t ui32Interrupt)443 IntPendClear(uint32_t ui32Interrupt)
444 {
445 // Check the arguments.
446 ASSERT(ui32Interrupt < NUM_INTERRUPTS);
447
448 // Determine the interrupt to unpend.
449 if(ui32Interrupt == INT_PENDSV)
450 {
451 // Unpend the PendSV interrupt.
452 HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_UNPEND_SV;
453 }
454 else if(ui32Interrupt == INT_SYSTICK)
455 {
456 // Unpend the SysTick interrupt.
457 HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR;
458 }
459 else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
460 {
461 // Unpend the general interrupt.
462 HWREG(NVIC_UNPEND0) = 1 << (ui32Interrupt - 16);
463 }
464 else if(ui32Interrupt >= 48)
465 {
466 // Unpend the general interrupt.
467 HWREG(NVIC_UNPEND1) = 1 << (ui32Interrupt - 48);
468 }
469 }
470