1 /**
2 * \file
3 *
4 * \brief Core related functionality implementation.
5 *
6 * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Subject to your compliance with these terms, you may use Microchip
13 * software and any derivatives exclusively with Microchip products.
14 * It is your responsibility to comply with third party license terms applicable
15 * to your use of third party software (including open source software) that
16 * may accompany Microchip software.
17 *
18 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
19 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
20 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
21 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
22 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
23 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
24 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
25 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
26 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
27 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
28 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
29 *
30 * \asf_license_stop
31 *
32 */
33
34 #include <hpl_core.h>
35 #include <hpl_irq.h>
36 #include <hpl_reset.h>
37 #include <hpl_sleep.h>
38 #include <hpl_delay.h>
39 #ifndef _UNIT_TEST_
40 #include <utils.h>
41 #endif
42 #include <utils_assert.h>
43 #include <peripheral_clk_config.h>
44
45 #ifndef CONF_HCLK_FREQUENCY
46 #define CONF_HCLK_FREQUENCY 300000000
47 #endif
48
49 #if CONF_HCLK_FREQUENCY < 1000
50 #define HCLK_FREQ_POWER 3
51 #elif CONF_HCLK_FREQUENCY < 10000
52 #define HCLK_FREQ_POWER 4
53 #elif CONF_HCLK_FREQUENCY < 100000
54 #define HCLK_FREQ_POWER 5
55 #elif CONF_HCLK_FREQUENCY < 1000000
56 #define HCLK_FREQ_POWER 6
57 #elif CONF_HCLK_FREQUENCY < 10000000
58 #define HCLK_FREQ_POWER 7
59 #elif CONF_HCLK_FREQUENCY < 100000000
60 #define HCLK_FREQ_POWER 8
61 #elif CONF_HCLK_FREQUENCY < 1000000000
62 #define HCLK_FREQ_POWER 9
63 #endif
64
65 /**
66 * \brief The array of interrupt handlers
67 */
68 struct _irq_descriptor *_irq_table[PERIPH_COUNT_IRQn];
69
70 /**
71 * \brief Reset MCU
72 */
_reset_mcu(void)73 void _reset_mcu(void)
74 {
75 NVIC_SystemReset();
76 }
77
78 /**
79 * \brief Retrieve the reset reason
80 */
_get_reset_reason(void)81 enum reset_reason _get_reset_reason(void)
82 {
83 return (enum reset_reason)hri_rstc_read_SR_RSTTYP_bf(RSTC);
84 }
85
86 /**
87 * \brief Retrieve current IRQ number
88 */
_irq_get_current(void)89 uint8_t _irq_get_current(void)
90 {
91 return (uint8_t)__get_IPSR() - 16;
92 }
93
94 /**
95 * \brief Disable the given IRQ
96 */
_irq_disable(uint8_t n)97 void _irq_disable(uint8_t n)
98 {
99 NVIC_DisableIRQ((IRQn_Type)n);
100 }
101
102 /**
103 * \brief Set the given IRQ
104 */
_irq_set(uint8_t n)105 void _irq_set(uint8_t n)
106 {
107 NVIC_SetPendingIRQ((IRQn_Type)n);
108 }
109
110 /**
111 * \brief Clear the given IRQ
112 */
_irq_clear(uint8_t n)113 void _irq_clear(uint8_t n)
114 {
115 NVIC_ClearPendingIRQ((IRQn_Type)n);
116 }
117
118 /**
119 * \brief Enable the given IRQ
120 */
_irq_enable(uint8_t n)121 void _irq_enable(uint8_t n)
122 {
123 NVIC_EnableIRQ((IRQn_Type)n);
124 }
125
126 /**
127 * \brief Register IRQ handler
128 */
_irq_register(const uint8_t n,struct _irq_descriptor * const irq)129 void _irq_register(const uint8_t n, struct _irq_descriptor *const irq)
130 {
131 ASSERT(n < PERIPH_COUNT_IRQn);
132
133 _irq_table[n] = irq;
134 }
135
136 /**
137 * \brief Default interrupt handler for unused IRQs.
138 */
Default_Handler(void)139 void Default_Handler(void)
140 {
141 while (1) {
142 }
143 }
144
145 /**
146 * \brief Retrieve the amount of cycles to delay for the given amount of us
147 */
_get_cycles_for_us_internal(const uint16_t us,const uint32_t freq,const uint8_t power)148 static inline uint32_t _get_cycles_for_us_internal(const uint16_t us, const uint32_t freq, const uint8_t power)
149 {
150 switch (power) {
151 case 9:
152 return (us * (freq / 1000000));
153 case 8:
154 return (us * (freq / 100000) + 9) / 10;
155 case 7:
156 return (us * (freq / 10000) + 99) / 100;
157 case 6:
158 return (us * (freq / 1000) + 999) / 1000;
159 case 5:
160 return (us * (freq / 100) + 9999) / 10000;
161 default:
162 return (us * freq + 999999) / 1000000;
163 }
164 }
165
166 /**
167 * \brief Retrieve the amount of cycles to delay for the given amount of us
168 */
_get_cycles_for_us(const uint16_t us)169 uint32_t _get_cycles_for_us(const uint16_t us)
170 {
171 return _get_cycles_for_us_internal(us, CONF_HCLK_FREQUENCY, HCLK_FREQ_POWER);
172 }
173
174 /**
175 * \brief Retrieve the amount of cycles to delay for the given amount of ms
176 */
_get_cycles_for_ms_internal(const uint16_t ms,const uint32_t freq,const uint8_t power)177 static inline uint32_t _get_cycles_for_ms_internal(const uint16_t ms, const uint32_t freq, const uint8_t power)
178 {
179 switch (power) {
180 case 9:
181 return (ms * (freq / 1000000) * 1000);
182 case 8:
183 return (ms * (freq / 100000) * 100);
184 case 7:
185 return (ms * (freq / 10000) * 10);
186 case 6:
187 return (ms * (freq / 1000));
188 case 5:
189 return (ms * (freq / 100) + 9) / 10;
190 default:
191 return (ms * (freq / 1) + 999) / 1000;
192 }
193 }
194
195 /**
196 * \brief Retrieve the amount of cycles to delay for the given amount of ms
197 */
_get_cycles_for_ms(const uint16_t ms)198 uint32_t _get_cycles_for_ms(const uint16_t ms)
199 {
200 return _get_cycles_for_ms_internal(ms, CONF_HCLK_FREQUENCY, HCLK_FREQ_POWER);
201 }
202 /**
203 * \brief Initialize delay functionality
204 */
_delay_init(void * const hw)205 void _delay_init(void *const hw)
206 {
207 (void)hw;
208 }
209
210 /**
211 * \brief Delay loop to delay n number of cycles
212 *
213 * \note In theory, a single loop runs take 2 cycles or more. But we find it
214 * really only needs 1 cycle through debugging.
215 *
216 */
_delay_cycles(void * const hw,uint32_t cycles)217 void _delay_cycles(void *const hw, uint32_t cycles)
218 {
219 #ifndef _UNIT_TEST_
220 (void)hw;
221 (void)cycles;
222 #if defined __GNUC__
223 __asm("__delay:\n"
224 "subs r1, r1, #1\n"
225 "bhi __delay\n");
226 #elif defined __CC_ARM
227 __asm("__delay:\n"
228 "subs cycles, cycles, #1\n"
229 "bhi __delay\n");
230 #elif defined __ICCARM__
231 __asm("__delay:\n"
232 "subs r1, r1, #1\n"
233 "bhi __delay\n");
234 #endif
235 #endif
236 }
237