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