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