1 /******************************************************************************
2 *  Filename:       interrupt.c
3 *  Revised:        2015-11-16 20:04:11 +0100 (Mon, 16 Nov 2015)
4 *  Revision:       45095
5 *
6 *  Description:    Driver for the NVIC Interrupt Controller.
7 *
8 *  Copyright (c) 2015, 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 <driverlib/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     //
114     // Go into an infinite loop.
115     //
116     while(1)
117     {
118     }
119 }
120 
121 //*****************************************************************************
122 //
123 // The processor vector table.
124 //
125 // This contains a list of the handlers for the various interrupt sources in
126 // the system. The layout of this list is defined by the hardware; assertion
127 // of an interrupt causes the processor to start executing directly at the
128 // address given in the corresponding location in this list.
129 //
130 //*****************************************************************************
131 #if defined(__IAR_SYSTEMS_ICC__)
132 #pragma data_alignment=256
133 static __no_init void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) @ ".vtable_ram";
134 #elif defined(__TI_COMPILER_VERSION__) || defined(DOXYGEN)
135 #pragma DATA_ALIGN(g_pfnRAMVectors, 256)
136 #pragma DATA_SECTION(g_pfnRAMVectors, ".vtable_ram")
137 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void);
138 #elif defined (__CC_ARM)
139 static __attribute__((section("vtable_ram")))
140 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256)));
141 #else
142 static __attribute__((section("vtable_ram")))
143 void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256)));
144 #endif
145 
146 //*****************************************************************************
147 //
148 //! Registers a function to be called when an interrupt occurs.
149 //
150 //*****************************************************************************
151 void
IntRegister(uint32_t ui32Interrupt,void (* pfnHandler)(void))152 IntRegister(uint32_t ui32Interrupt, void (*pfnHandler)(void))
153 {
154     uint32_t ui32Idx, ui32Value;
155 
156     //
157     // Check the arguments.
158     //
159     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
160 
161     //
162     // Make sure that the RAM vector table is correctly aligned.
163     //
164     ASSERT(((uint32_t)g_pfnRAMVectors & 0x000000ff) == 0);
165 
166     //
167     // See if the RAM vector table has been initialized.
168     //
169     if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors)
170     {
171         //
172         // Copy the vector table from the beginning of FLASH to the RAM vector
173         // table.
174         //
175         ui32Value = HWREG(NVIC_VTABLE);
176         for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++)
177         {
178             g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) +
179                                        ui32Value);
180         }
181 
182         //
183         // Point NVIC at the RAM vector table.
184         //
185         HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors;
186     }
187 
188     //
189     // Save the interrupt handler.
190     //
191     g_pfnRAMVectors[ui32Interrupt] = pfnHandler;
192 }
193 
194 //*****************************************************************************
195 //
196 //! Unregisters the function to be called when an interrupt occurs.
197 //
198 //*****************************************************************************
199 void
IntUnregister(uint32_t ui32Interrupt)200 IntUnregister(uint32_t ui32Interrupt)
201 {
202     //
203     // Check the arguments.
204     //
205     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
206 
207     //
208     // Reset the interrupt handler.
209     //
210     g_pfnRAMVectors[ui32Interrupt] = IntDefaultHandler;
211 }
212 
213 //*****************************************************************************
214 //
215 //! Sets the priority grouping of the interrupt controller.
216 //
217 //*****************************************************************************
218 void
IntPriorityGroupingSet(uint32_t ui32Bits)219 IntPriorityGroupingSet(uint32_t ui32Bits)
220 {
221     //
222     // Check the arguments.
223     //
224     ASSERT(ui32Bits < NUM_PRIORITY);
225 
226     //
227     // Set the priority grouping.
228     //
229     HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | g_pui32Priority[ui32Bits];
230 }
231 
232 //*****************************************************************************
233 //
234 //! Gets the priority grouping of the interrupt controller
235 //
236 //*****************************************************************************
237 uint32_t
IntPriorityGroupingGet(void)238 IntPriorityGroupingGet(void)
239 {
240     uint32_t ui32Loop, ui32Value;
241 
242     //
243     // Read the priority grouping.
244     //
245     ui32Value = HWREG(NVIC_APINT) & NVIC_APINT_PRIGROUP_M;
246 
247     //
248     // Loop through the priority grouping values.
249     //
250     for(ui32Loop = 0; ui32Loop < NUM_PRIORITY; ui32Loop++)
251     {
252         //
253         // Stop looping if this value matches.
254         //
255         if(ui32Value == g_pui32Priority[ui32Loop])
256         {
257             break;
258         }
259     }
260 
261     //
262     // Return the number of priority bits.
263     //
264     return(ui32Loop);
265 }
266 
267 //*****************************************************************************
268 //
269 //! Sets the priority of an interrupt
270 //
271 //*****************************************************************************
272 void
IntPrioritySet(uint32_t ui32Interrupt,uint8_t ui8Priority)273 IntPrioritySet(uint32_t ui32Interrupt, uint8_t ui8Priority)
274 {
275     uint32_t ui32Temp;
276 
277     //
278     // Check the arguments.
279     //
280     ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
281     ASSERT(ui8Priority <= INT_PRI_LEVEL7);
282 
283     //
284     // Set the interrupt priority.
285     //
286     ui32Temp = HWREG(g_pui32Regs[ui32Interrupt >> 2]);
287     ui32Temp &= ~(0xFF << (8 * (ui32Interrupt & 3)));
288     ui32Temp |= ui8Priority << (8 * (ui32Interrupt & 3));
289     HWREG(g_pui32Regs[ui32Interrupt >> 2]) = ui32Temp;
290 }
291 
292 //*****************************************************************************
293 //
294 //! Gets the priority of an interrupt
295 //
296 //*****************************************************************************
297 int32_t
IntPriorityGet(uint32_t ui32Interrupt)298 IntPriorityGet(uint32_t ui32Interrupt)
299 {
300     //
301     // Check the arguments.
302     //
303     ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
304 
305     //
306     // Return the interrupt priority.
307     //
308     return((HWREG(g_pui32Regs[ui32Interrupt >> 2]) >> (8 * (ui32Interrupt & 3))) &
309            0xFF);
310 }
311 
312 //*****************************************************************************
313 //
314 //! Enables an interrupt
315 //
316 //*****************************************************************************
317 void
IntEnable(uint32_t ui32Interrupt)318 IntEnable(uint32_t ui32Interrupt)
319 {
320     //
321     // Check the arguments.
322     //
323     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
324 
325     //
326     // Determine the interrupt to enable.
327     //
328     if(ui32Interrupt == INT_MEMMANAGE_FAULT)
329     {
330         //
331         // Enable the MemManage interrupt.
332         //
333         HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_MEM;
334     }
335     else if(ui32Interrupt == INT_BUS_FAULT)
336     {
337         //
338         // Enable the bus fault interrupt.
339         //
340         HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_BUS;
341     }
342     else if(ui32Interrupt == INT_USAGE_FAULT)
343     {
344         //
345         // Enable the usage fault interrupt.
346         //
347         HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_USAGE;
348     }
349     else if(ui32Interrupt == INT_SYSTICK)
350     {
351         //
352         // Enable the System Tick interrupt.
353         //
354         HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN;
355     }
356     else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
357     {
358         //
359         // Enable the general interrupt.
360         //
361         HWREG(NVIC_EN0) = 1 << (ui32Interrupt - 16);
362     }
363     else if(ui32Interrupt >= 48)
364     {
365         //
366         // Enable the general interrupt.
367         //
368         HWREG(NVIC_EN1) = 1 << (ui32Interrupt - 48);
369     }
370 }
371 
372 //*****************************************************************************
373 //
374 //! Disables an interrupt
375 //
376 //*****************************************************************************
377 void
IntDisable(uint32_t ui32Interrupt)378 IntDisable(uint32_t ui32Interrupt)
379 {
380     //
381     // Check the arguments.
382     //
383     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
384 
385     //
386     // Determine the interrupt to disable.
387     //
388     if(ui32Interrupt == INT_MEMMANAGE_FAULT)
389     {
390         //
391         // Disable the MemManage interrupt.
392         //
393         HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_MEM);
394     }
395     else if(ui32Interrupt == INT_BUS_FAULT)
396     {
397         //
398         // Disable the bus fault interrupt.
399         //
400         HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_BUS);
401     }
402     else if(ui32Interrupt == INT_USAGE_FAULT)
403     {
404         //
405         // Disable the usage fault interrupt.
406         //
407         HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_USAGE);
408     }
409     else if(ui32Interrupt == INT_SYSTICK)
410     {
411         //
412         // Disable the System Tick interrupt.
413         //
414         HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN);
415     }
416     else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
417     {
418         //
419         // Disable the general interrupt.
420         //
421         HWREG(NVIC_DIS0) = 1 << (ui32Interrupt - 16);
422     }
423     else if(ui32Interrupt >= 48)
424     {
425         //
426         // Disable the general interrupt.
427         //
428         HWREG(NVIC_DIS1) = 1 << (ui32Interrupt - 48);
429     }
430 }
431 
432 //*****************************************************************************
433 //
434 //! Pends an interrupt
435 //
436 //*****************************************************************************
437 void
IntPendSet(uint32_t ui32Interrupt)438 IntPendSet(uint32_t ui32Interrupt)
439 {
440     //
441     // Check the arguments.
442     //
443     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
444 
445     //
446     // Determine the interrupt to pend.
447     //
448     if(ui32Interrupt == INT_NMI_FAULT)
449     {
450         //
451         // Pend the NMI interrupt.
452         //
453         HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_NMI_SET;
454     }
455     else if(ui32Interrupt == INT_PENDSV)
456     {
457         //
458         // Pend the PendSV interrupt.
459         //
460         HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PEND_SV;
461     }
462     else if(ui32Interrupt == INT_SYSTICK)
463     {
464         //
465         // Pend the SysTick interrupt.
466         //
467         HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET;
468     }
469     else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
470     {
471         //
472         // Pend the general interrupt.
473         //
474         HWREG(NVIC_PEND0) = 1 << (ui32Interrupt - 16);
475     }
476     else if(ui32Interrupt >= 48)
477     {
478         //
479         // Pend the general interrupt.
480         //
481         HWREG(NVIC_PEND1) = 1 << (ui32Interrupt - 48);
482     }
483 }
484 
485 //*****************************************************************************
486 //
487 //! Query whether an interrupt is pending
488 //
489 //*****************************************************************************
490 bool
IntPendGet(uint32_t ui32Interrupt)491 IntPendGet(uint32_t ui32Interrupt)
492 {
493     uint32_t ui32IntPending;
494 
495     //
496     // Check the arguments.
497     //
498     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
499 
500     //
501     // Assume no interrupts are pending.
502     //
503     ui32IntPending = 0;
504 
505     //
506     // The lower 16 IRQ vectors are unsupported by this function
507     //
508     if (ui32Interrupt < 16)
509     {
510 
511        return 0;
512     }
513 
514     //
515     // Subtract lower 16 irq vectors
516     //
517     ui32Interrupt -= 16;
518 
519     //
520     // Check if the interrupt is pending
521     //
522     ui32IntPending = HWREG(NVIC_PEND0 + (ui32Interrupt / 32));
523     ui32IntPending &= (1 << (ui32Interrupt & 31));
524 
525     return ui32IntPending ? true : false;
526 }
527 
528 //*****************************************************************************
529 //
530 //! Unpends an interrupt
531 //
532 //*****************************************************************************
533 void
IntPendClear(uint32_t ui32Interrupt)534 IntPendClear(uint32_t ui32Interrupt)
535 {
536     //
537     // Check the arguments.
538     //
539     ASSERT(ui32Interrupt < NUM_INTERRUPTS);
540 
541     //
542     // Determine the interrupt to unpend.
543     //
544     if(ui32Interrupt == INT_PENDSV)
545     {
546         //
547         // Unpend the PendSV interrupt.
548         //
549         HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_UNPEND_SV;
550     }
551     else if(ui32Interrupt == INT_SYSTICK)
552     {
553         //
554         // Unpend the SysTick interrupt.
555         //
556         HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR;
557     }
558     else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
559     {
560         //
561         // Unpend the general interrupt.
562         //
563         HWREG(NVIC_UNPEND0) = 1 << (ui32Interrupt - 16);
564     }
565     else if(ui32Interrupt >= 48)
566     {
567         //
568         // Unpend the general interrupt.
569         //
570         HWREG(NVIC_UNPEND1) = 1 << (ui32Interrupt - 48);
571     }
572 }
573