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