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