1 /**
2 * \file
3 *
4 * \brief SAM System Interrupt Driver
5 *
6 * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46 #include "system_interrupt.h"
47
48 /**
49 * \brief Check if a interrupt line is pending.
50 *
51 * Checks if the requested interrupt vector is pending.
52 *
53 * \param[in] vector Interrupt vector number to check
54 *
55 * \returns A boolean identifying if the requested interrupt vector is pending.
56 *
57 * \retval true Specified interrupt vector is pending
58 * \retval false Specified interrupt vector is not pending
59 *
60 */
system_interrupt_is_pending(const enum system_interrupt_vector vector)61 bool system_interrupt_is_pending(
62 const enum system_interrupt_vector vector)
63 {
64 bool result;
65
66 if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) {
67 result = ((NVIC->ISPR[0] & (1 << vector)) != 0);
68 } else if (vector == SYSTEM_INTERRUPT_SYSTICK) {
69 result = ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) != 0);
70 } else {
71 Assert(false);
72 result = false;
73 }
74
75 return result;
76 }
77
78 /**
79 * \brief Set a interrupt vector as pending.
80 *
81 * Set the requested interrupt vector as pending (i.e. issues a software
82 * interrupt request for the specified vector). The software handler will be
83 * handled (if enabled) in a priority order based on vector number and
84 * configured priority settings.
85 *
86 * \param[in] vector Interrupt vector number which is set as pending
87 *
88 * \returns Status code identifying if the vector was successfully set as
89 * pending.
90 *
91 * \retval STATUS_OK If no error was detected
92 * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given
93 */
system_interrupt_set_pending(const enum system_interrupt_vector vector)94 enum status_code system_interrupt_set_pending(
95 const enum system_interrupt_vector vector)
96 {
97 enum status_code status = STATUS_OK;
98
99 if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) {
100 NVIC->ISPR[0] = (1 << vector);
101 } else if (vector == SYSTEM_INTERRUPT_NON_MASKABLE) {
102 /* Note: Because NMI has highest priority it will be executed
103 * immediately after it has been set pending */
104 SCB->ICSR = SCB_ICSR_NMIPENDSET_Msk;
105 } else if (vector == SYSTEM_INTERRUPT_SYSTICK) {
106 SCB->ICSR = SCB_ICSR_PENDSTSET_Msk;
107 } else {
108 /* The user want to set something unsupported as pending */
109 Assert(false);
110 status = STATUS_ERR_INVALID_ARG;
111 }
112
113 return status;
114 }
115
116 /**
117 * \brief Clear pending interrupt vector.
118 *
119 * Clear a pending interrupt vector, so the software handler is not executed.
120 *
121 * \param[in] vector Interrupt vector number to clear
122 *
123 * \returns A status code identifying if the interrupt pending state was
124 * successfully cleared.
125 *
126 * \retval STATUS_OK If no error was detected
127 * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given
128 */
system_interrupt_clear_pending(const enum system_interrupt_vector vector)129 enum status_code system_interrupt_clear_pending(
130 const enum system_interrupt_vector vector)
131 {
132 enum status_code status = STATUS_OK;
133
134 if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) {
135 NVIC->ICPR[0] = (1 << vector);
136 } else if (vector == SYSTEM_INTERRUPT_NON_MASKABLE) {
137 /* Note: Clearing of NMI pending interrupts does not make sense and is
138 * not supported by the device, as it has the highest priority and will
139 * always be executed at the moment it is set */
140 return STATUS_ERR_INVALID_ARG;
141 } else if (vector == SYSTEM_INTERRUPT_SYSTICK) {
142 SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
143 } else {
144 Assert(false);
145 status = STATUS_ERR_INVALID_ARG;
146 }
147
148 return status;
149 }
150
151 /**
152 * \brief Set interrupt vector priority level.
153 *
154 * Set the priority level of an external interrupt or exception.
155 *
156 * \param[in] vector Interrupt vector to change
157 * \param[in] priority_level New vector priority level to set
158 *
159 * \returns Status code indicating if the priority level of the interrupt was
160 * successfully set.
161 *
162 * \retval STATUS_OK If no error was detected
163 * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given
164 */
system_interrupt_set_priority(const enum system_interrupt_vector vector,const enum system_interrupt_priority_level priority_level)165 enum status_code system_interrupt_set_priority(
166 const enum system_interrupt_vector vector,
167 const enum system_interrupt_priority_level priority_level)
168 {
169 enum status_code status = STATUS_OK;
170
171 if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) {
172 uint8_t register_num = vector / 4;
173 uint8_t priority_pos = ((vector % 4) * 8) + (8 - __NVIC_PRIO_BITS);
174
175 NVIC->IP[register_num] =
176 (NVIC->IP[register_num] & ~(_SYSTEM_INTERRUPT_PRIORITY_MASK << priority_pos)) |
177 (priority_level << priority_pos);
178
179 } else if (vector == SYSTEM_INTERRUPT_SYSTICK) {
180 SCB->SHP[1] = (priority_level << _SYSTEM_INTERRUPT_SYSTICK_PRI_POS);
181 } else {
182 Assert(false);
183 status = STATUS_ERR_INVALID_ARG;
184 }
185
186 return status;
187 }
188
189 /**
190 * \brief Get interrupt vector priority level.
191 *
192 * Retrieves the priority level of the requested external interrupt or exception.
193 *
194 * \param[in] vector Interrupt vector of which the priority level will be read
195 *
196 * \return Currently configured interrupt priority level of the given interrupt
197 * vector.
198 */
system_interrupt_get_priority(const enum system_interrupt_vector vector)199 enum system_interrupt_priority_level system_interrupt_get_priority(
200 const enum system_interrupt_vector vector)
201 {
202 uint8_t register_num = vector / 4;
203 uint8_t priority_pos = ((vector % 4) * 8) + (8 - __NVIC_PRIO_BITS);
204
205 enum system_interrupt_priority_level priority = SYSTEM_INTERRUPT_PRIORITY_LEVEL_0;
206
207 if (vector >= 0) {
208 priority = (enum system_interrupt_priority_level)
209 ((NVIC->IP[register_num] >> priority_pos) & _SYSTEM_INTERRUPT_PRIORITY_MASK);
210 } else if (vector == SYSTEM_INTERRUPT_SYSTICK) {
211 priority = (enum system_interrupt_priority_level)
212 ((SCB->SHP[1] >> _SYSTEM_INTERRUPT_SYSTICK_PRI_POS) & _SYSTEM_INTERRUPT_PRIORITY_MASK);
213 }
214
215 return priority;
216 }
217
218