1 /******************************************************************************
2 *
3 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4 * Analog Devices, Inc.),
5 * Copyright (C) 2023-2024 Analog Devices, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************************/
20
21 /**
22 * @file mxc_sys.h
23 * @brief System level header file.
24 */
25
26 #ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32662_MXC_SYS_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32662_MXC_SYS_H_
28
29 #include "mxc_device.h"
30 #include "gcr_regs.h"
31 #include "mcr_regs.h"
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36
37 /**
38 * @defgroup mxc_sys System Configuration (MXC_SYS)
39 * @ingroup syscfg
40 * @details API for system configuration including clock source selection and entering critical sections of code.
41 * @{
42 */
43
44 /** @brief System reset0 and reset1 enumeration. Used in MXC_SYS_PeriphReset0 function */
45 typedef enum {
46 MXC_SYS_RESET0_DMA = MXC_F_GCR_RST0_DMA_POS, /**< Reset DMA */
47 MXC_SYS_RESET0_WDT = MXC_F_GCR_RST0_WDT_POS, /**< Reset WDT */
48 MXC_SYS_RESET0_GPIO0 = MXC_F_GCR_RST0_GPIO0_POS, /**< Reset GPIO0 */
49 MXC_SYS_RESET0_TMR0 = MXC_F_GCR_RST0_TMR0_POS, /**< Reset TMR0 */
50 MXC_SYS_RESET0_TMR1 = MXC_F_GCR_RST0_TMR1_POS, /**< Reset TMR1 */
51 MXC_SYS_RESET0_TMR2 = MXC_F_GCR_RST0_TMR2_POS, /**< Reset TMR2 */
52 MXC_SYS_RESET0_UART0 = MXC_F_GCR_RST0_UART0_POS, /**< Reset UART0 */
53 MXC_SYS_RESET0_UART1 = MXC_F_GCR_RST0_UART1_POS, /**< Reset UART1 */
54 MXC_SYS_RESET0_SPI0 = MXC_F_GCR_RST0_SPI0_POS, /**< Reset SPI0 */
55 MXC_SYS_RESET0_SPI1 = MXC_F_GCR_RST0_SPI1_POS, /**< Reset SPI1 */
56 MXC_SYS_RESET0_I2C0 = MXC_F_GCR_RST0_I2C0_POS, /**< Reset I2C0 */
57 MXC_SYS_RESET0_CAN = MXC_F_GCR_RST0_CAN_POS, /**< Reset CAN */
58 MXC_SYS_RESET0_TRNG = MXC_F_GCR_RST0_TRNG_POS, /**< Reset TRNG */
59 MXC_SYS_RESET0_ADC = MXC_F_GCR_RST0_ADC_POS, /**< Reset ADC */
60 MXC_SYS_RESET0_SOFT = MXC_F_GCR_RST0_SOFT_POS, /**< Soft reset */
61 MXC_SYS_RESET0_PERIPH = MXC_F_GCR_RST0_PERIPH_POS, /**< Peripheral reset */
62 MXC_SYS_RESET0_SYS = MXC_F_GCR_RST0_SYS_POS, /**< System reset */
63 /* RESET1 Below this line we add 32 to separate RESET0 and RESET1 */
64 MXC_SYS_RESET1_I2C1 = (MXC_F_GCR_RST1_I2C1_POS + 32), /**< Reset I2C1 */
65 MXC_SYS_RESET1_PT = (MXC_F_GCR_RST1_PT_POS + 32), /**< Reset PT */
66 MXC_SYS_RESET1_AES = (MXC_F_GCR_RST1_AES_POS + 32), /**< Reset AES */
67 MXC_SYS_RESET1_AC = (MXC_F_GCR_RST1_AC_POS + 32), /**< Reset Auto-Cal */
68 MXC_SYS_RESET1_I2S = (MXC_F_GCR_RST1_I2S_POS + 32), /**< Reset I2S */
69 /* LP Peripheral Reset below this line. Adding 64 to separate from non-LP periphs. */
70 MXC_SYS_RESET_TMR3 = (MXC_F_MCR_RST_TMR3_POS + 64), /**< Reset TMR3 */
71 MXC_SYS_RESET_RTC = (MXC_F_MCR_RST_RTC_POS + 64) /**< Reset RTC */
72 } mxc_sys_reset_t;
73
74 /** @brief System clock disable enumeration. Used in MXC_SYS_ClockDisable and MXC_SYS_ClockEnable functions */
75 typedef enum {
76 MXC_SYS_PERIPH_CLOCK_GPIO0 =
77 MXC_F_GCR_PCLKDIS0_GPIO0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO0 clock */
78 MXC_SYS_PERIPH_CLOCK_DMA =
79 MXC_F_GCR_PCLKDIS0_DMA_POS, /**< Disable MXC_F_GCR_PCLKDIS0_DMA clock */
80 MXC_SYS_PERIPH_CLOCK_SPI0 =
81 MXC_F_GCR_PCLKDIS0_SPI0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI0 clock */
82 MXC_SYS_PERIPH_CLOCK_SPI1 =
83 MXC_F_GCR_PCLKDIS0_SPI1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI1 clock */
84 MXC_SYS_PERIPH_CLOCK_UART0 =
85 MXC_F_GCR_PCLKDIS0_UART0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART0 clock */
86 MXC_SYS_PERIPH_CLOCK_UART1 =
87 MXC_F_GCR_PCLKDIS0_UART1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART1 clock */
88 MXC_SYS_PERIPH_CLOCK_I2C0 =
89 MXC_F_GCR_PCLKDIS0_I2C0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C0 clock */
90 MXC_SYS_PERIPH_CLOCK_TMR0 =
91 MXC_F_GCR_PCLKDIS0_TMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR0 clock */
92 MXC_SYS_PERIPH_CLOCK_TMR1 =
93 MXC_F_GCR_PCLKDIS0_TMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR1 clock */
94 MXC_SYS_PERIPH_CLOCK_TMR2 =
95 MXC_F_GCR_PCLKDIS0_TMR2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR2 clock */
96 MXC_SYS_PERIPH_CLOCK_ADC =
97 MXC_F_GCR_PCLKDIS0_ADC_POS, /**< Disable MXC_F_GCR_PCLKDIS0_ADC clock */
98 MXC_SYS_PERIPH_CLOCK_I2C1 =
99 MXC_F_GCR_PCLKDIS0_I2C1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C1 clock */
100 MXC_SYS_PERIPH_CLOCK_PT = MXC_F_GCR_PCLKDIS0_PT_POS, /**< Disable MXC_F_GCR_PCLKDIS0_PT clock */
101 /* PCLKDIS1 below this line we add 32 to separate PCLKDIS0 and PCLKDIS1 */
102 MXC_SYS_PERIPH_CLOCK_TRNG =
103 (MXC_F_GCR_PCLKDIS1_TRNG_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_TRNG clock */
104 MXC_SYS_PERIPH_CLOCK_WDT =
105 (MXC_F_GCR_PCLKDIS1_WDT_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_WDT clock */
106 MXC_SYS_PERIPH_CLOCK_CAN =
107 (MXC_F_GCR_PCLKDIS1_CAN_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_CAM clock */
108 MXC_SYS_PERIPH_CLOCK_AES =
109 (MXC_F_GCR_PCLKDIS1_AES_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_AES clock */
110 MXC_SYS_PERIPH_CLOCK_I2S =
111 (MXC_F_GCR_PCLKDIS1_I2S_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_I2S clock */
112 /* MCR_PCLKDIS below this line we add 64 to separate from GCR_PCLKDIS0 and GCR_PCLKDIS1 */
113 MXC_SYS_PERIPH_CLOCK_TMR3 =
114 (MXC_F_MCR_PCLKDIS_TMR3_POS + 64), /**< Disable MXC_F_GCR_PCLKDIS1_I2S clock */
115 } mxc_sys_periph_clock_t;
116
117 /** @brief Enumeration to select System Clock source */
118 typedef enum {
119 MXC_SYS_CLOCK_IPO =
120 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IPO, /**< Select the Internal Primary Oscillator (IPO) */
121 MXC_SYS_CLOCK_ERFO =
122 MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERFO, /**< Select the External RF Crystal Oscillator */
123 MXC_SYS_CLOCK_IBRO =
124 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IBRO, /**< Select the Internal Baud Rate Oscillator (IBRO) */
125 MXC_SYS_CLOCK_INRO =
126 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_INRO, /**< Select the External RF Crystal Oscillator */
127 MXC_SYS_CLOCK_ERTCO =
128 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERTCO, /**< Select the External RTC Crystal Oscillator */
129 MXC_SYS_CLOCK_EXTCLK =
130 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_EXTCLK /**< Use the external system clock input */
131 } mxc_sys_system_clock_t;
132
133 typedef enum {
134 MXC_SYS_CLOCK_DIV_1 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1,
135 MXC_SYS_CLOCK_DIV_2 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV2,
136 MXC_SYS_CLOCK_DIV_4 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV4,
137 MXC_SYS_CLOCK_DIV_8 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV8,
138 MXC_SYS_CLOCK_DIV_16 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV16,
139 MXC_SYS_CLOCK_DIV_32 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV32,
140 MXC_SYS_CLOCK_DIV_64 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV64,
141 MXC_SYS_CLOCK_DIV_128 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128
142 } mxc_sys_system_clock_div_t;
143
144 #define MXC_SYS_USN_CHECKSUM_LEN 16 // Length of the USN + padding for checksum compute
145 #define MXC_SYS_USN_CSUM_FIELD_LEN 2 // Size of the checksum field in the USN
146 #define MXC_SYS_USN_LEN 13 // Size of the USN including the checksum
147
148 /***** Function Prototypes *****/
149
150 typedef struct {
151 int ie_status;
152 int in_critical;
153 } mxc_crit_state_t;
154
155 static mxc_crit_state_t _state = { .ie_status = (int)0xFFFFFFFF, .in_critical = 0 };
156
_mxc_crit_get_state(void)157 static inline void _mxc_crit_get_state(void)
158 {
159 #ifndef __riscv
160 /*
161 On ARM M the 0th bit of the Priority Mask register indicates
162 whether interrupts are enabled or not.
163
164 0 = enabled
165 1 = disabled
166 */
167 uint32_t primask = __get_PRIMASK();
168 _state.ie_status = (primask == 0);
169 #else
170 /*
171 On RISC-V bit position 3 (Machine Interrupt Enable) of the
172 mstatus register indicates whether interrupts are enabled.
173
174 0 = disabled
175 1 = enabled
176 */
177 uint32_t mstatus = get_mstatus();
178 _state.ie_status = ((mstatus & (1 << 3)) != 0);
179 #endif
180 }
181
182 /**
183 * @brief Enter a critical section of code that cannot be interrupted. Call @ref MXC_SYS_Crit_Exit to exit the critical section.
184 * @details Ex:
185 * @code
186 * MXC_SYS_Crit_Enter();
187 * printf("Hello critical section!\n");
188 * MXC_SYS_Crit_Exit();
189 * @endcode
190 * The @ref MXC_CRITICAL macro is also provided as a convencience macro for wrapping a code section in this way.
191 * @returns None
192 */
MXC_SYS_Crit_Enter(void)193 static inline void MXC_SYS_Crit_Enter(void)
194 {
195 _mxc_crit_get_state();
196 if (_state.ie_status)
197 __disable_irq();
198 _state.in_critical = 1;
199 }
200
201 /**
202 * @brief Exit a critical section of code from @ref MXC_SYS_Crit_Enter
203 * @returns None
204 */
MXC_SYS_Crit_Exit(void)205 static inline void MXC_SYS_Crit_Exit(void)
206 {
207 if (_state.ie_status) {
208 __enable_irq();
209 }
210 _state.in_critical = 0;
211 _mxc_crit_get_state();
212 /*
213 ^ Reset the state again to prevent edge case
214 where interrupts get disabled, then Crit_Exit() gets
215 called, which would inadvertently re-enable interrupts
216 from old state.
217 */
218 }
219
220 /**
221 * @brief Polls whether code is currently executing from a critical section.
222 * @returns 1 if code is currently in a critical section (interrupts are disabled).
223 * 0 if code is not in a critical section.
224 */
MXC_SYS_In_Crit_Section(void)225 static inline int MXC_SYS_In_Crit_Section(void)
226 {
227 return _state.in_critical;
228 }
229
230 // clang-format off
231 /**
232 * @brief Macro for wrapping a section of code to make it critical (interrupts disabled). Note: this macro
233 * does not support nesting.
234 * @details
235 * Ex:
236 * \code
237 * MXC_CRITICAL(
238 * printf("Hello critical section!\n");
239 * )
240 * \endcode
241 * This macro places a call to @ref MXC_SYS_Crit_Enter before the code, and a call to @ref MXC_SYS_Crit_Exit after.
242 * @param code The code section to wrap.
243 */
244 #define MXC_CRITICAL(code) {\
245 MXC_SYS_Crit_Enter();\
246 code;\
247 MXC_SYS_Crit_Exit();\
248 }
249 // clang-format on
250
251 /**
252 * @brief Reads the device USN and verifies the checksum.
253 * @param usn Pointer to store the USN. Array must be at least MXC_SYS_USN_LEN bytes long.
254 * @param checksum Optional pointer to store the AES checksum. If not NULL, checksum is verified with AES engine.
255 * @returns E_NO_ERROR if everything is successful.
256 */
257 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum);
258
259 /**
260 * @brief Determines if the selected peripheral clock is enabled.
261 * @param clock Enumeration for desired clock.
262 * @returns 0 is the clock is disabled, non 0 if the clock is enabled.
263 */
264 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock);
265
266 /**
267 * @brief Disables the selected peripheral clock.
268 * @param clock Enumeration for desired clock.
269 */
270 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock);
271
272 /**
273 * @brief Enables the selected peripheral clock.
274 * @param clock Enumeration for desired clock.
275 */
276 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock);
277
278 /**
279 * @brief Enables the 32kHz oscillator
280 * @param mxc_sys_cfg Not used, may be NULL.
281 */
282 void MXC_SYS_RTCClockEnable(void);
283
284 /**
285 * @brief Disables the 32kHz oscillator
286 * @returns E_NO_ERROR if everything is successful
287 */
288 int MXC_SYS_RTCClockDisable(void);
289
290 /**
291 * @brief Enable System Clock Source without switching to it
292 * @param clock The clock to enable
293 * @return E_NO_ERROR if everything is successful
294 */
295 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock);
296
297 /**
298 * @brief Disable System Clock Source
299 * @param clock The clock to disable
300 * @return E_NO_ERROR if everything is successful
301 */
302 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock);
303
304 /**
305 * @brief Select the system clock.
306 * @param clock Enumeration for desired clock. Note: If using the external clock input be sure to define EXTCLK_FREQ correctly.
307 * The default EXTCLK_FREQ value is defined in the system_max32662.h file and can be overridden at compile time.
308 * @returns E_NO_ERROR if everything is successful.
309 */
310 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock);
311
312 /**
313 * @brief Set the system clock divider.
314 * @param div Enumeration for desired clock divider.
315 */
316 void MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div);
317
318 /**
319 * @brief Get the system clock divider.
320 * @returns System clock divider.
321 */
322 mxc_sys_system_clock_div_t MXC_SYS_GetClockDiv(void);
323
324 /**
325 * @brief Wait for a clock to enable with timeout
326 * @param ready The clock to wait for
327 * @return E_NO_ERROR if ready, E_TIME_OUT if timeout
328 */
329 int MXC_SYS_Clock_Timeout(uint32_t ready);
330
331 /**
332 * @brief Reset the peripherals and/or CPU in the rstr0 or rstr1 register.
333 * @param Enumeration for what to reset. Can reset multiple items at once.
334 */
335 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset);
336
337 /**
338 * @brief This function PERMANENTLY locks the Debug Access Port.
339 *
340 * @warning After executing this function you will never be able
341 * to reprogram the target micro.
342 */
343 int MXC_SYS_LockDAP_Permanent(void);
344
345 #ifdef __cplusplus
346 }
347 #endif
348
349 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32662_MXC_SYS_H_
350