1 /**
2 * @file mxc_sys.h
3 * @brief System level header file.
4 */
5
6 /******************************************************************************
7 *
8 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9 * Analog Devices, Inc.),
10 * Copyright (C) 2023-2024 Analog Devices, Inc.
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 ******************************************************************************/
25
26 #ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32672_MXC_SYS_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32672_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_WDT0 = MXC_F_GCR_RST0_WDT0_POS, /**< Reset WDT */
48 MXC_SYS_RESET0_GPIO0 = MXC_F_GCR_RST0_GPIO0_POS, /**< Reset GPIO0 */
49 MXC_SYS_RESET0_GPIO1 = MXC_F_GCR_RST0_GPIO1_POS, /**< Reset GPIO1 */
50 MXC_SYS_RESET0_TMR0 = MXC_F_GCR_RST0_TMR0_POS, /**< Reset TIMER0 */
51 MXC_SYS_RESET0_TMR1 = MXC_F_GCR_RST0_TMR1_POS, /**< Reset TIMER1 */
52 MXC_SYS_RESET0_TMR2 = MXC_F_GCR_RST0_TMR2_POS, /**< Reset TIMER2 */
53 MXC_SYS_RESET0_TMR3 = MXC_F_GCR_RST0_TMR3_POS, /**< Reset TIMER3 */
54 MXC_SYS_RESET0_UART0 = MXC_F_GCR_RST0_UART0_POS, /**< Reset UART0 */
55 MXC_SYS_RESET0_UART1 = MXC_F_GCR_RST0_UART1_POS, /**< Reset UART1 */
56 MXC_SYS_RESET0_SPI0 = MXC_F_GCR_RST0_SPI0_POS, /**< Reset SPI0 */
57 MXC_SYS_RESET0_SPI1 = MXC_F_GCR_RST0_SPI1_POS, /**< Reset SPI1 */
58 MXC_SYS_RESET0_SPI2 = MXC_F_GCR_RST0_SPI2_POS, /**< Reset SPI2 */
59 MXC_SYS_RESET0_I2C0 = MXC_F_GCR_RST0_I2C0_POS, /**< Reset I2C0 */
60 MXC_SYS_RESET0_RTC = MXC_F_MCR_RST_RTC_POS, /**< Reset RTC */
61 MXC_SYS_RESET0_CTB = MXC_F_GCR_RST0_CTB_POS, /**< Reset CTB */
62 MXC_SYS_RESET0_TRNG = MXC_F_GCR_RST0_TRNG_POS, /**< Reset TRNG */
63 MXC_SYS_RESET0_ADC = MXC_F_GCR_RST0_ADC_POS, /**< Reset ADC */
64 MXC_SYS_RESET0_UART2 = MXC_F_GCR_RST0_UART2_POS, /**< Reset UART2 */
65 MXC_SYS_RESET0_SRST = MXC_F_GCR_RST0_SOFT_POS, /**< Soft reset */
66 MXC_SYS_RESET0_PRST = MXC_F_GCR_RST0_PERIPH_POS, /**< Peripheral reset */
67 MXC_SYS_RESET0_SYS = MXC_F_GCR_RST0_SYS_POS, /**< System reset */
68 /* RESET1 Below this line we add 32 to separate RESET0 and RESET1 */
69 MXC_SYS_RESET1_I2C1 = (MXC_F_GCR_RST1_I2C1_POS + 32), /**< Reset I2C1 */
70 MXC_SYS_RESET1_WDT1 = (MXC_F_GCR_RST1_WDT1_POS + 32), /**< Reset WDT1 */
71 MXC_SYS_RESET1_AES = (MXC_F_GCR_RST1_AES_POS + 32), /**< Reset AES */
72 MXC_SYS_RESET1_I2C2 = (MXC_F_GCR_RST1_I2C2_POS + 32), /**< Reset I2C2*/
73 MXC_SYS_RESET1_I2S = (MXC_F_GCR_RST1_I2S_POS + 32), /**< Reset I2S*/
74 MXC_SYS_RESET1_QDEC = (MXC_F_GCR_RST1_QDEC_POS + 32), /**< Reset QDEC*/
75 /* LPGCR RESET Below this line we add 64 to separate LPGCR and GCR */
76 MXC_SYS_RESET_TMR4 = (MXC_F_MCR_RST_LPTMR0_POS + 64), /**< Reset TMR4 */
77 MXC_SYS_RESET_TMR5 = (MXC_F_MCR_RST_LPTMR1_POS + 64), /**< Reset TMR5 */
78 MXC_SYS_RESET_UART3 = (MXC_F_MCR_RST_LPUART0_POS + 64), /**< Reset UART3 */
79 } mxc_sys_reset_t;
80
81 /** @brief System clock disable enumeration. Used in MXC_SYS_ClockDisable and MXC_SYS_ClockEnable functions */
82 typedef enum {
83 MXC_SYS_PERIPH_CLOCK_GPIO0 =
84 MXC_F_GCR_PCLKDIS0_GPIO0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO0 clock */
85 MXC_SYS_PERIPH_CLOCK_GPIO1 =
86 MXC_F_GCR_PCLKDIS0_GPIO1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO1 clock */
87 MXC_SYS_PERIPH_CLOCK_DMA =
88 MXC_F_GCR_PCLKDIS0_DMA_POS, /**< Disable MXC_F_GCR_PCLKDIS0_DMA clock */
89 MXC_SYS_PERIPH_CLOCK_SPI0 =
90 MXC_F_GCR_PCLKDIS0_SPI0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI0 clock */
91 MXC_SYS_PERIPH_CLOCK_SPI1 =
92 MXC_F_GCR_PCLKDIS0_SPI1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI1 clock */
93 MXC_SYS_PERIPH_CLOCK_SPI2 =
94 MXC_F_GCR_PCLKDIS0_SPI2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI2 clock */
95 MXC_SYS_PERIPH_CLOCK_UART0 =
96 MXC_F_GCR_PCLKDIS0_UART0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART0 clock */
97 MXC_SYS_PERIPH_CLOCK_UART1 =
98 MXC_F_GCR_PCLKDIS0_UART1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART1 clock */
99 MXC_SYS_PERIPH_CLOCK_I2C0 =
100 MXC_F_GCR_PCLKDIS0_I2C0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C0 clock */
101 MXC_SYS_PERIPH_CLOCK_TMR0 =
102 MXC_F_GCR_PCLKDIS0_TMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR0 clock */
103 MXC_SYS_PERIPH_CLOCK_TMR1 =
104 MXC_F_GCR_PCLKDIS0_TMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR1 clock */
105 MXC_SYS_PERIPH_CLOCK_TMR2 =
106 MXC_F_GCR_PCLKDIS0_TMR2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR2 clock */
107 MXC_SYS_PERIPH_CLOCK_TMR3 =
108 MXC_F_GCR_PCLKDIS0_TMR3_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR3 clock */
109 MXC_SYS_PERIPH_CLOCK_ADC =
110 MXC_F_GCR_PCLKDIS0_ADC_POS, /**< Disable MXC_F_GCR_PCLKDIS0_ADC clock */
111 MXC_SYS_PERIPH_CLOCK_I2C1 =
112 MXC_F_GCR_PCLKDIS0_I2C1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C1 clock */
113 MXC_SYS_PERIPH_CLOCK_CTB =
114 MXC_F_GCR_PCLKDIS0_CTB_POS, /**< Disable MXC_F_GCR_PCLKDIS0_CTB clock */
115 /* PCLKDIS1 Below this line we add 32 to separate PCLKDIS0 and PCLKDIS1 */
116 MXC_SYS_PERIPH_CLOCK_UART2 =
117 (MXC_F_GCR_PCLKDIS1_UART2_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_UART2 clock */
118 MXC_SYS_PERIPH_CLOCK_TRNG =
119 (MXC_F_GCR_PCLKDIS1_TRNG_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_TRNG clock */
120 MXC_SYS_PERIPH_CLOCK_WDT0 =
121 (MXC_F_GCR_PCLKDIS1_WDT0_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_WDT0 clock */
122 MXC_SYS_PERIPH_CLOCK_WDT1 =
123 (MXC_F_GCR_PCLKDIS1_WDT1_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_WDT1 clock */
124 MXC_SYS_PERIPH_CLOCK_ICACHE =
125 (MXC_F_GCR_PCLKDIS1_ICC0_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_ICACHE clock */
126 MXC_SYS_PERIPH_CLOCK_AES =
127 (MXC_F_GCR_PCLKDIS1_AES_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_AES clock */
128 MXC_SYS_PERIPH_CLOCK_I2C2 =
129 (MXC_F_GCR_PCLKDIS1_I2C2_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_I2C2 clock */
130 MXC_SYS_PERIPH_CLOCK_I2S =
131 (MXC_F_GCR_PCLKDIS1_I2S_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_I2S clock */
132 MXC_SYS_PERIPH_CLOCK_QDEC =
133 (MXC_F_GCR_PCLKDIS1_QDEC_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_QDEC clock */
134 /* LPGCR PCLKDIS Below this line we add 64 to seperate GCR and LPGCR registers */
135 MXC_SYS_PERIPH_CLOCK_TMR4 =
136 (MXC_F_MCR_PCLKDIS_LPTMR0_POS + 64), /**< Disable MXC_F_LPGCR_PCLKDIS_TMR4 clock */
137 MXC_SYS_PERIPH_CLOCK_TMR5 =
138 (MXC_F_MCR_PCLKDIS_LPTMR1_POS + 64), /**< Disable MXC_F_LPGCR_PCLKDIS_TMR5 clock */
139 MXC_SYS_PERIPH_CLOCK_UART3 =
140 (MXC_F_MCR_PCLKDIS_LPUART0_POS + 64), /**< Disable MXC_F_LPGCR_PCLKDIS_UART3 clock */
141 } mxc_sys_periph_clock_t;
142
143 /** @brief Enumeration to select System Clock source */
144 typedef enum {
145 MXC_SYS_CLOCK_IPO =
146 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IPO, /**< Select the Internal Primary Oscillator (IPO) */
147 MXC_SYS_CLOCK_IBRO =
148 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IBRO, /**< Select the Internal Baud Rate Oscillator (IBRO) */
149 MXC_SYS_CLOCK_ERFO =
150 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERFO, /**< Select the External RF Crystal Oscillator */
151 MXC_SYS_CLOCK_INRO =
152 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_INRO, /**< Select the Internal Nanoring Oscillator (INRO) */
153 MXC_SYS_CLOCK_ERTCO =
154 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERTCO, /**< Select the External RTC Crystal Oscillator */
155 MXC_SYS_CLOCK_EXTCLK =
156 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_EXTCLK /**< Use the external system clock input */
157 } mxc_sys_system_clock_t;
158
159 typedef enum {
160 MXC_SYS_CLOCK_DIV_1 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1,
161 MXC_SYS_CLOCK_DIV_2 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV2,
162 MXC_SYS_CLOCK_DIV_4 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV4,
163 MXC_SYS_CLOCK_DIV_8 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV8,
164 MXC_SYS_CLOCK_DIV_16 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV16,
165 MXC_SYS_CLOCK_DIV_32 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV32,
166 MXC_SYS_CLOCK_DIV_64 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV64,
167 MXC_SYS_CLOCK_DIV_128 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128
168 } mxc_sys_system_clock_div_t;
169
170 #define MXC_SYS_USN_CHECKSUM_LEN 16 // Length of the USN + padding for checksum compute
171 #define MXC_SYS_USN_CSUM_FIELD_LEN 2 // Size of the checksum field in the USN
172 #define MXC_SYS_USN_LEN 13 // Size of the USN including the checksum
173
174 /***** Function Prototypes *****/
175
176 typedef struct {
177 int ie_status;
178 int in_critical;
179 } mxc_crit_state_t;
180
181 static mxc_crit_state_t _state = { .ie_status = (int)0xFFFFFFFF, .in_critical = 0 };
182
_mxc_crit_get_state(void)183 static inline void _mxc_crit_get_state(void)
184 {
185 #ifndef __riscv
186 /*
187 On ARM M the 0th bit of the Priority Mask register indicates
188 whether interrupts are enabled or not.
189
190 0 = enabled
191 1 = disabled
192 */
193 uint32_t primask = __get_PRIMASK();
194 _state.ie_status = (primask == 0);
195 #else
196 /*
197 On RISC-V bit position 3 (Machine Interrupt Enable) of the
198 mstatus register indicates whether interrupts are enabled.
199
200 0 = disabled
201 1 = enabled
202 */
203 uint32_t mstatus = get_mstatus();
204 _state.ie_status = ((mstatus & (1 << 3)) != 0);
205 #endif
206 }
207
208 /**
209 * @brief Enter a critical section of code that cannot be interrupted. Call @ref MXC_SYS_Crit_Exit to exit the critical section.
210 * @details Ex:
211 * @code
212 * MXC_SYS_Crit_Enter();
213 * printf("Hello critical section!\n");
214 * MXC_SYS_Crit_Exit();
215 * @endcode
216 * The @ref MXC_CRITICAL macro is also provided as a convencience macro for wrapping a code section in this way.
217 * @returns None
218 */
MXC_SYS_Crit_Enter(void)219 static inline void MXC_SYS_Crit_Enter(void)
220 {
221 _mxc_crit_get_state();
222 if (_state.ie_status)
223 __disable_irq();
224 _state.in_critical = 1;
225 }
226
227 /**
228 * @brief Exit a critical section of code from @ref MXC_SYS_Crit_Enter
229 * @returns None
230 */
MXC_SYS_Crit_Exit(void)231 static inline void MXC_SYS_Crit_Exit(void)
232 {
233 if (_state.ie_status) {
234 __enable_irq();
235 }
236 _state.in_critical = 0;
237 _mxc_crit_get_state();
238 /*
239 ^ Reset the state again to prevent edge case
240 where interrupts get disabled, then Crit_Exit() gets
241 called, which would inadvertently re-enable interrupts
242 from old state.
243 */
244 }
245
246 /**
247 * @brief Polls whether code is currently executing from a critical section.
248 * @returns 1 if code is currently in a critical section (interrupts are disabled).
249 * 0 if code is not in a critical section.
250 */
MXC_SYS_In_Crit_Section(void)251 static inline int MXC_SYS_In_Crit_Section(void)
252 {
253 return _state.in_critical;
254 }
255
256 // clang-format off
257 /**
258 * @brief Macro for wrapping a section of code to make it critical (interrupts disabled). Note: this macro
259 * does not support nesting.
260 * @details
261 * Ex:
262 * \code
263 * MXC_CRITICAL(
264 * printf("Hello critical section!\n");
265 * )
266 * \endcode
267 * This macro places a call to @ref MXC_SYS_Crit_Enter before the code, and a call to @ref MXC_SYS_Crit_Exit after.
268 * @param code The code section to wrap.
269 */
270 #define MXC_CRITICAL(code) {\
271 MXC_SYS_Crit_Enter();\
272 code;\
273 MXC_SYS_Crit_Exit();\
274 }
275 // clang-format on
276
277 /**
278 * @brief Reads the device USN and verifies the checksum.
279 * @param usn Pointer to store the USN. Array must be at least MXC_SYS_USN_LEN bytes long.
280 * @param checksum Optional pointer to store the AES checksum. If not NULL, checksum is verified with AES engine.
281 * @returns E_NO_ERROR if everything is successful.
282 */
283 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum);
284
285 /**
286 * @brief Gets design revision of the chip.
287 *
288 * @return Design revision.
289 */
290 int MXC_SYS_GetRevision(void);
291
292 /**
293 * @brief Determines if the selected peripheral clock is enabled.
294 * @param clock Enumeration for desired clock.
295 * @returns 0 is the clock is disabled, non 0 if the clock is enabled.
296 */
297 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock);
298
299 /**
300 * @brief Disables the selected peripheral clock.
301 * @param clock Enumeration for desired clock.
302 */
303 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock);
304
305 /**
306 * @brief Enables the selected peripheral clock.
307 * @param clock Enumeration for desired clock.
308 */
309 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock);
310
311 /**
312 * @brief Enables the 32kHz oscillator
313 * @param mxc_sys_cfg Not used, may be NULL.
314 */
315 void MXC_SYS_RTCClockEnable(void);
316
317 /**
318 * @brief Disables the 32kHz oscillator
319 * @returns E_NO_ERROR if everything is successful
320 */
321 int MXC_SYS_RTCClockDisable(void);
322
323 /**
324 * @brief Enable System Clock Source without switching to it
325 * @param clock The clock to enable
326 * @return E_NO_ERROR if everything is successful
327 */
328 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock);
329
330 /**
331 * @brief Disable System Clock Source
332 * @param clock The clock to disable
333 * @return E_NO_ERROR if everything is successful
334 */
335 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock);
336
337 /**
338 * @brief Select the system clock.
339 * @param clock Enumeration for desired clock. Note: If using the external clock input be sure to define EXTCLK_FREQ correctly.
340 * The default EXTCLK_FREQ value is defined in the system_max32672.h file and can be overridden at compile time.
341 * @returns E_NO_ERROR if everything is successful.
342 */
343 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock);
344
345 /**
346 * @brief Set the system clock divider.
347 * @param div Enumeration for desired clock divider.
348 */
349 void MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div);
350
351 /**
352 * @brief Get the system clock divider.
353 * @returns System clock divider.
354 */
355 mxc_sys_system_clock_div_t MXC_SYS_GetClockDiv(void);
356
357 /**
358 * @brief Wait for a clock to enable with timeout
359 * @param ready The clock to wait for
360 * @return E_NO_ERROR if ready, E_TIME_OUT if timeout
361 */
362 int MXC_SYS_Clock_Timeout(uint32_t ready);
363
364 /**
365 * @brief Reset the peripherals and/or CPU in the rstr0 or rstr1 register.
366 * @param Enumeration for what to reset. Can reset multiple items at once.
367 */
368 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset);
369
370 /**
371 * @brief This function PERMANENTLY locks the Debug Access Port.
372 *
373 * @warning After executing this function you will never be able
374 * to reprogram the target micro.
375 */
376 int MXC_SYS_LockDAP_Permanent(void);
377
378 #ifdef __cplusplus
379 }
380 #endif
381
382 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32672_MXC_SYS_H_
383