]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_MPU_CEC_MEC_17xx_51xx_Keil_GCC/peripheral_library/interrupt/interrupt_api.c
Change name of the CEC and MEC directory to CORTEX_MPU_CEC_MEC_17xx_51xx_Keil_GCC...
[freertos] / FreeRTOS / Demo / CORTEX_MPU_CEC_MEC_17xx_51xx_Keil_GCC / peripheral_library / interrupt / interrupt_api.c
1 /*****************************************************************************\r
2 * © 2015 Microchip Technology Inc. and its subsidiaries.\r
3 * You may use this software and any derivatives exclusively with\r
4 * Microchip products.\r
5 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS".\r
6 * NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,\r
7 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,\r
8 * AND FITNESS FOR A PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP\r
9 * PRODUCTS, COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.\r
10 * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,\r
11 * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND\r
12 * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS\r
13 * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.\r
14 * TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL\r
15 * CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF\r
16 * FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.\r
17 * MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE\r
18 * OF THESE TERMS.\r
19 ******************************************************************************\r
20 \r
21 Version Control Information (Perforce)\r
22 ******************************************************************************\r
23 $Revision: #1 $ \r
24 $DateTime: 2016/09/22 08:03:49 $ \r
25 $Author: pramans $\r
26 Last Change: Renamed ecia_init to interrupt_init\r
27 ******************************************************************************/\r
28 /** @file interrupt_api.c\r
29 * \brief Interrupt APIs Source File\r
30 * \author jvasanth\r
31\r
32 * This file implements the Interrupt Source file  \r
33 ******************************************************************************/\r
34 \r
35 /** @defgroup Interrupt\r
36  *  @{\r
37  */\r
38  \r
39 #include "common_lib.h"\r
40 #include "interrupt.h"\r
41 #include "..\pcr\pcr.h"\r
42 \r
43 static uint8_t interrupt_is_girq_direct(uint8_t girq_num);\r
44 \r
45 /* ------------------------------------------------------------------------------- */\r
46 /*                  NVIC,ECIA Routing Policy for Direct Mode                       */\r
47 /* ------------------------------------------------------------------------------- */\r
48 /* In Direct Mode, some interrupts could be configured to be used as aggregated.\r
49  * Configuration:\r
50  *      1. Always set ECS Interrupt Direct enable bit.         \r
51  *      2. If GIRQn aggregated set Block Enable bit.\r
52  *      3. If GIRQn direct then clear Block Enable bit and enable individual NVIC inputs.\r
53  *  Switching issues:\r
54  *  Aggregate enable/disable requires set/clear single GIRQn bit in GIRQ Block En/Clr registers.\r
55  *  Also requires set/clear of individual NVIC Enables.\r
56  *  \r
57  * Note: interrupt_is_girq_direct() internal function uses this policy to detect \r
58  * if any interrupt is configured as direct or aggregated\r
59 */\r
60 \r
61 /** Initialize EC Interrupt Aggregator\r
62  * @param mode 1 - Direct Map mode, 0 - Fully Aggregated Mode \r
63  * @param girq_bitmask - BitMask of GIRQ to be configured as aggregated \r
64  *                     This parameter is only applicable in direct mode.\r
65  * @note All GPIO's and wake capable sources are always \r
66  * aggregated! GPIO's interrupts will still work in direct mode.\r
67  * Block wakes are not be routed to the processor in direct \r
68  * mode. \r
69  * Note2: This function disables and enables global interrupt \r
70  */\r
71 void interrupt_init(uint8_t mode, uint32_t girq_bitmask)\r
72 {\r
73     uint32_t isave;\r
74         \r
75     isave = __get_PRIMASK();\r
76     __disable_irq();\r
77                 \r
78     //Clear Sleep for Interrupt block\r
79     pcr_sleep_enable(PCR_INT, 0);\r
80 \r
81     interrupt_mode_set(mode);\r
82 \r
83     p_interrupt_ecia_girqs_enable_reset();        \r
84     \r
85     p_interrupt_nvic_enpend_clr();\r
86         \r
87     p_interrupt_nvic_priorities_default_set();\r
88     \r
89     if (mode)\r
90     {//If direct mode, enable specific GIRQs to be aggregated\r
91         p_interrupt_ecia_block_enable_bitmask_set(girq_bitmask);\r
92     }\r
93        \r
94     if (!isave) {\r
95         __enable_irq();\r
96     }\r
97 }\r
98 \r
99 /** Set interrupt routing mode to aggregated or direct. \r
100  * @param mode 1 = Direct (except GPIO & wake), 0 = All Aggregated \r
101  * @note In direct mode, one could enable certain GIRQs as aggregated using \r
102  * p_interrupt_ecia_block_enable_set function\r
103  */\r
104 void interrupt_mode_set(uint8_t mode)\r
105 {\r
106     if (mode) \r
107         {\r
108                 p_interrupt_ecia_block_enable_all_clr();        \r
109     } \r
110         else \r
111         {\r
112                 p_interrupt_ecia_block_enable_all_set();        \r
113     }\r
114                 \r
115     p_interrupt_control_set(mode);\r
116 }\r
117 \r
118 /** Clears all individual interrupts Enables and Source in ECIA,\r
119  *  and Clears all NVIC external enables and pending bits  \r
120  */\r
121 void interrupt_reset(void)\r
122 {       \r
123     p_interrupt_ecia_girqs_enable_reset();\r
124     p_interrupt_ecia_girqs_source_reset();      \r
125 \r
126     p_interrupt_nvic_enpend_clr();\r
127 }\r
128 \r
129 /** Enables interrupt for a device \r
130  * @param dev_iroute - source IROUTING information  \r
131  * @note This function disables and enables global interrupt \r
132  */\r
133 void interrupt_device_enable(uint32_t dev_iroute)\r
134 {\r
135     uint32_t isave;\r
136     IRQn_Type nvic_num;\r
137     uint8_t girq_num;\r
138     uint8_t ia_bitpos;\r
139     \r
140     girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
141     ia_bitpos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu;    \r
142     \r
143     if (interrupt_is_girq_direct(girq_num)) \r
144     { // GIRQ is hooked direct        \r
145         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);\r
146     } \r
147     else \r
148     { // GIRQ is aggregated        \r
149         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
150     }\r
151     \r
152     isave = __get_PRIMASK();\r
153     __disable_irq();\r
154 \r
155     NVIC_EnableIRQ(nvic_num);\r
156     p_interrupt_ecia_girq_enable_set(girq_num, ia_bitpos);    \r
157     __DSB();                                            \r
158 \r
159     if (!isave) {\r
160         __enable_irq();\r
161     }\r
162 }\r
163 \r
164 \r
165 /** Disables interrupt for a device\r
166  * @param dev_iroute - source IROUTING information  \r
167  * @note This function disables and enables global interrupt \r
168  */\r
169 void interrupt_device_disable(uint32_t dev_iroute)\r
170 {\r
171     uint32_t isave;\r
172     IRQn_Type nvic_num;\r
173     uint8_t girq_num;\r
174     uint8_t ia_bitpos;\r
175 \r
176     girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
177     ia_bitpos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu;    \r
178     \r
179     isave = __get_PRIMASK();\r
180     __disable_irq();\r
181     \r
182     if (interrupt_is_girq_direct(girq_num)) \r
183     { // GIRQ is hooked direct        \r
184         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);\r
185         NVIC_DisableIRQ(nvic_num);\r
186     }   \r
187         \r
188     p_interrupt_ecia_girq_enable_clr(girq_num, ia_bitpos);    \r
189     __DSB();                                            \r
190 \r
191     if (!isave) {\r
192         __enable_irq();\r
193     }\r
194 }\r
195 \r
196 /** ecia_is_girq_direct - Return true if GIRQn sources can be directly \r
197  * connected to the NVIC - based on ECS->INTERRUPT_CONTROL and GIRQ block enable\r
198  * @param girq_num - enum MEC_GIRQ_IDS\r
199  * @return 1 if GIRQn sources can be directly routed to the NVIC, else 0\r
200  */\r
201 static uint8_t interrupt_is_girq_direct(uint8_t girq_num)\r
202 {    \r
203     uint32_t bpos;\r
204     uint8_t retVal;\r
205     uint8_t girq_block_enabled;\r
206     \r
207     retVal = 0;\r
208     \r
209     bpos = (girq_num & 0x1Fu) + 8u;\r
210     \r
211     if ((ECIA_GIRQ_DIRECT_BITMAP) & (1ul << bpos)) \r
212     {        \r
213         if (p_interrupt_control_get())                \r
214         {// direct NVIC enabled\r
215            \r
216             girq_block_enabled = p_interrupt_ecia_block_enable_get(girq_num);\r
217             \r
218             if (!girq_block_enabled)\r
219             {\r
220                 retVal = 1;\r
221             }\r
222         }\r
223     }\r
224     return retVal;\r
225 }\r
226 \r
227 \r
228 /* ------------------------------------------------------------------------------- */\r
229 /*                  ECIA APIs using device IROUTE() as input                       */ \r
230 /* ------------------------------------------------------------------------------- */\r
231 \r
232 /** Clear Source in the ECIA for the device  \r
233  * @param devi - device IROUTING value  \r
234  */\r
235 void interrupt_device_ecia_source_clear(const uint32_t dev_iroute)\r
236 {    \r
237     uint8_t girq_num;\r
238     uint8_t ia_bit_pos;\r
239     \r
240     girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
241     ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu;           \r
242             \r
243     p_interrupt_ecia_girq_source_clr(girq_num, ia_bit_pos);        \r
244     __DSB();\r
245 }\r
246 \r
247 /** Get the Source bit in the ECIA for the device  \r
248  * @param devi - device IROUTING value  \r
249  * @return 0 if source bit not set; else non-zero value\r
250  */\r
251 uint32_t interrupt_device_ecia_source_get(const uint32_t dev_iroute)\r
252 {    \r
253     uint8_t girq_num;\r
254     uint8_t ia_bit_pos;\r
255     uint8_t retVal;\r
256     \r
257     girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
258     ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu;           \r
259             \r
260     retVal = p_interrupt_ecia_girq_source_get(girq_num, ia_bit_pos);        \r
261     return retVal;\r
262 }\r
263 \r
264 /** Get the Result bit in the ECIA for the device  \r
265  * @param devi - device IROUTING value  \r
266  * @return 0 if result bit not set; else non-zero value\r
267  */\r
268 uint32_t interrupt_device_ecia_result_get(const uint32_t dev_iroute)\r
269 {    \r
270     uint8_t girq_num;\r
271     uint8_t ia_bit_pos;\r
272     uint8_t retVal;\r
273     \r
274     girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
275     ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu;           \r
276             \r
277     retVal = p_interrupt_ecia_girq_result_get(girq_num, ia_bit_pos);        \r
278     return retVal;\r
279 }\r
280 \r
281 /* ------------------------------------------------------------------------------- */\r
282 /*                  NVIC APIs using device IROUTE() as input                       */ \r
283 /* ------------------------------------------------------------------------------- */\r
284 /* Note that if the device interrupt is aggregated, then these APIs would affect the \r
285  * NVIC corresponding to the aggregated GIRQ \r
286  */\r
287 \r
288 /**  Enable/Disable the NVIC (in the NVIC controller) for the device\r
289  * @param dev_iroute : source IROUTING information (encoded in a uint32_t)\r
290  * @param en_flag : 1 = Enable the NVIC IRQ, 0 = Disable the NVIC IRQ \r
291  * @note 1. Recommended to use interrupt_device_enable, interrupt_device_disable\r
292  * to enable/disable interrupts for the device, since those APIs configure ECIA as well\r
293  * 2. This function disables and enables global interrupt    \r
294  */\r
295 void interrupt_device_nvic_enable(uint32_t dev_iroute, uint8_t en_flag)\r
296 {\r
297     uint32_t isave;\r
298     IRQn_Type nvic_num;\r
299                 \r
300     if (p_interrupt_control_get())        \r
301     { // direct                         \r
302         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
303     } \r
304     else // fully aggregated\r
305     {                           \r
306         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
307     }\r
308     \r
309     isave = __get_PRIMASK();\r
310     __disable_irq();\r
311     \r
312     p_interrupt_nvic_enable(nvic_num, en_flag);         \r
313    \r
314     if (!isave) {\r
315         __enable_irq();\r
316     }\r
317 }\r
318 \r
319 \r
320 /** Set NVIC priority for specified peripheral interrupt \r
321  * @param dev_iroute - source IROUTING information (encoded in a uint32_t)\r
322  * @param nvic_pri - NVIC Priority\r
323  * @note If ECIA is in aggregated mode, the priority affects all interrupt \r
324  * sources in the GIRQ. \r
325  */\r
326 void interrupt_device_nvic_priority_set(const uint32_t dev_iroute, const uint8_t nvic_pri)\r
327 {\r
328     IRQn_Type nvic_num;\r
329         \r
330     if (p_interrupt_control_get())        \r
331     { // direct                         \r
332         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
333     } \r
334     else // fully aggregated\r
335     {                           \r
336         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
337     }\r
338                 \r
339     NVIC_SetPriority(nvic_num, (uint32_t)nvic_pri);\r
340 }\r
341 \r
342 /** Return NVIC priority for the device's interrupt\r
343  * @param dev_iroute - source IROUTING information \r
344  * @return uint32_t  NVIC priority \r
345  */\r
346 uint32_t interrupt_device_nvic_priority_get(const uint32_t dev_iroute)\r
347 {\r
348     IRQn_Type nvic_num;\r
349         uint32_t nvic_priority;\r
350     \r
351     if (p_interrupt_control_get())        \r
352     { // direct                         \r
353         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
354     } \r
355     else // fully aggregated\r
356     {                           \r
357         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
358     }\r
359     \r
360     nvic_priority = NVIC_GetPriority(nvic_num);\r
361                 \r
362     return nvic_priority;\r
363 }\r
364 \r
365 \r
366 /** Return NVIC pending for the device\r
367  * @param dev_iroute - source IROUTING information \r
368  * @return uint8_t 0(not pending), 1 (pending in NVIC) \r
369  *  \r
370  */\r
371 uint8_t interrupt_device_nvic_pending_get(const uint32_t dev_iroute)\r
372 {\r
373     IRQn_Type nvic_num;\r
374     uint8_t nvic_pending;\r
375     \r
376     if (p_interrupt_control_get())        \r
377     { // direct                         \r
378         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
379     } \r
380     else // fully aggregated\r
381     {                           \r
382         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
383     }\r
384     \r
385     nvic_pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));\r
386                 \r
387     return nvic_pending;\r
388 }\r
389 \r
390 \r
391 /** Set NVIC pending for interrupt source\r
392  * @param dev_iroute - source IROUTING information   \r
393  */\r
394 void interrupt_device_nvic_pending_set(const uint32_t dev_iroute)\r
395 {\r
396     IRQn_Type nvic_num;    \r
397     \r
398     if (p_interrupt_control_get())        \r
399     { // direct                         \r
400         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
401     } \r
402     else // fully aggregated\r
403     {                           \r
404         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
405     }\r
406     \r
407     NVIC_SetPendingIRQ(nvic_num);   \r
408 }\r
409 \r
410 /** Clears NVIC pending for interrupt source\r
411  * @param dev_iroute - source IROUTING information \r
412  * @return uint8_t 0(not pending), 1 (pending in NVIC) - before clear \r
413  * @note This function disables and enables global interrupt  \r
414  */\r
415 uint8_t interrupt_device_nvic_pending_clear(const uint32_t dev_iroute)\r
416 {\r
417     uint32_t was_masked;\r
418     IRQn_Type nvic_num;\r
419     uint8_t pending;\r
420     \r
421     if (p_interrupt_control_get())        \r
422     { // direct                         \r
423         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);                                         \r
424     } \r
425     else // fully aggregated\r
426     {                           \r
427         nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
428     }\r
429     \r
430     was_masked = __get_PRIMASK();\r
431     __disable_irq();\r
432     \r
433     pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));\r
434 \r
435     NVIC_ClearPendingIRQ(nvic_num);\r
436     __DSB();\r
437     \r
438     if (!was_masked) {\r
439         __enable_irq();\r
440     }\r
441                 \r
442     return pending;\r
443 }\r
444 \r
445 /* ------------------------------------------------------------------------------- */\r
446 \r
447 /* end interrupt_api.c */\r
448 /**   @}\r
449  */\r