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
19 ******************************************************************************
\r
21 Version Control Information (Perforce)
\r
22 ******************************************************************************
\r
24 $DateTime: 2016/09/22 08:03:49 $
\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
32 * This file implements the Interrupt Source file
\r
33 ******************************************************************************/
\r
35 /** @defgroup Interrupt
\r
39 #include "common_lib.h"
\r
40 #include "interrupt.h"
\r
41 #include "..\pcr\pcr.h"
\r
43 static uint8_t interrupt_is_girq_direct(uint8_t girq_num);
\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
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
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
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
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
69 * Note2: This function disables and enables global interrupt
\r
71 void interrupt_init(uint8_t mode, uint32_t girq_bitmask)
\r
75 isave = __get_PRIMASK();
\r
78 //Clear Sleep for Interrupt block
\r
79 pcr_sleep_enable(PCR_INT, 0);
\r
81 interrupt_mode_set(mode);
\r
83 p_interrupt_ecia_girqs_enable_reset();
\r
85 p_interrupt_nvic_enpend_clr();
\r
87 p_interrupt_nvic_priorities_default_set();
\r
90 {//If direct mode, enable specific GIRQs to be aggregated
\r
91 p_interrupt_ecia_block_enable_bitmask_set(girq_bitmask);
\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
104 void interrupt_mode_set(uint8_t mode)
\r
108 p_interrupt_ecia_block_enable_all_clr();
\r
112 p_interrupt_ecia_block_enable_all_set();
\r
115 p_interrupt_control_set(mode);
\r
118 /** Clears all individual interrupts Enables and Source in ECIA,
\r
119 * and Clears all NVIC external enables and pending bits
\r
121 void interrupt_reset(void)
\r
123 p_interrupt_ecia_girqs_enable_reset();
\r
124 p_interrupt_ecia_girqs_source_reset();
\r
126 p_interrupt_nvic_enpend_clr();
\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
133 void interrupt_device_enable(uint32_t dev_iroute)
\r
136 IRQn_Type nvic_num;
\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
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
148 { // GIRQ is aggregated
\r
149 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
152 isave = __get_PRIMASK();
\r
155 NVIC_EnableIRQ(nvic_num);
\r
156 p_interrupt_ecia_girq_enable_set(girq_num, ia_bitpos);
\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
169 void interrupt_device_disable(uint32_t dev_iroute)
\r
172 IRQn_Type nvic_num;
\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
179 isave = __get_PRIMASK();
\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
188 p_interrupt_ecia_girq_enable_clr(girq_num, ia_bitpos);
\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
201 static uint8_t interrupt_is_girq_direct(uint8_t girq_num)
\r
205 uint8_t girq_block_enabled;
\r
209 bpos = (girq_num & 0x1Fu) + 8u;
\r
211 if ((ECIA_GIRQ_DIRECT_BITMAP) & (1ul << bpos))
\r
213 if (p_interrupt_control_get())
\r
214 {// direct NVIC enabled
\r
216 girq_block_enabled = p_interrupt_ecia_block_enable_get(girq_num);
\r
218 if (!girq_block_enabled)
\r
228 /* ------------------------------------------------------------------------------- */
\r
229 /* ECIA APIs using device IROUTE() as input */
\r
230 /* ------------------------------------------------------------------------------- */
\r
232 /** Clear Source in the ECIA for the device
\r
233 * @param devi - device IROUTING value
\r
235 void interrupt_device_ecia_source_clear(const uint32_t dev_iroute)
\r
238 uint8_t ia_bit_pos;
\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
243 p_interrupt_ecia_girq_source_clr(girq_num, ia_bit_pos);
\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
251 uint32_t interrupt_device_ecia_source_get(const uint32_t dev_iroute)
\r
254 uint8_t ia_bit_pos;
\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
260 retVal = p_interrupt_ecia_girq_source_get(girq_num, ia_bit_pos);
\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
268 uint32_t interrupt_device_ecia_result_get(const uint32_t dev_iroute)
\r
271 uint8_t ia_bit_pos;
\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
277 retVal = p_interrupt_ecia_girq_result_get(girq_num, ia_bit_pos);
\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
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
295 void interrupt_device_nvic_enable(uint32_t dev_iroute, uint8_t en_flag)
\r
298 IRQn_Type nvic_num;
\r
300 if (p_interrupt_control_get())
\r
302 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
304 else // fully aggregated
\r
306 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
309 isave = __get_PRIMASK();
\r
312 p_interrupt_nvic_enable(nvic_num, en_flag);
\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
326 void interrupt_device_nvic_priority_set(const uint32_t dev_iroute, const uint8_t nvic_pri)
\r
328 IRQn_Type nvic_num;
\r
330 if (p_interrupt_control_get())
\r
332 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
334 else // fully aggregated
\r
336 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
339 NVIC_SetPriority(nvic_num, (uint32_t)nvic_pri);
\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
346 uint32_t interrupt_device_nvic_priority_get(const uint32_t dev_iroute)
\r
348 IRQn_Type nvic_num;
\r
349 uint32_t nvic_priority;
\r
351 if (p_interrupt_control_get())
\r
353 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
355 else // fully aggregated
\r
357 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
360 nvic_priority = NVIC_GetPriority(nvic_num);
\r
362 return nvic_priority;
\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
371 uint8_t interrupt_device_nvic_pending_get(const uint32_t dev_iroute)
\r
373 IRQn_Type nvic_num;
\r
374 uint8_t nvic_pending;
\r
376 if (p_interrupt_control_get())
\r
378 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
380 else // fully aggregated
\r
382 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
385 nvic_pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));
\r
387 return nvic_pending;
\r
391 /** Set NVIC pending for interrupt source
\r
392 * @param dev_iroute - source IROUTING information
\r
394 void interrupt_device_nvic_pending_set(const uint32_t dev_iroute)
\r
396 IRQn_Type nvic_num;
\r
398 if (p_interrupt_control_get())
\r
400 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
402 else // fully aggregated
\r
404 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
407 NVIC_SetPendingIRQ(nvic_num);
\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
415 uint8_t interrupt_device_nvic_pending_clear(const uint32_t dev_iroute)
\r
417 uint32_t was_masked;
\r
418 IRQn_Type nvic_num;
\r
421 if (p_interrupt_control_get())
\r
423 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);
\r
425 else // fully aggregated
\r
427 nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);
\r
430 was_masked = __get_PRIMASK();
\r
433 pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));
\r
435 NVIC_ClearPendingIRQ(nvic_num);
\r
445 /* ------------------------------------------------------------------------------- */
\r
447 /* end interrupt_api.c */
\r