mikroSDK Reference Manual
usb_hw.h
Go to the documentation of this file.
1/****************************************************************************
2**
3** Copyright (C) 2024 MikroElektronika d.o.o.
4** Contact: https://www.mikroe.com/contact
5**
6** This file is part of the mikroSDK package
7**
8** Commercial License Usage
9**
10** Licensees holding valid commercial NECTO compilers AI licenses may use this
11** file in accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The MikroElektronika Company.
14** For licensing terms and conditions see
15** https://www.mikroe.com/legal/software-license-agreement.
16** For further information use the contact form at
17** https://www.mikroe.com/contact.
18**
19**
20** GNU Lesser General Public License Usage
21**
22** Alternatively, this file may be used for
23** non-commercial projects under the terms of the GNU Lesser
24** General Public License version 3 as published by the Free Software
25** Foundation: https://www.gnu.org/licenses/lgpl-3.0.html.
26**
27** The above copyright notice and this permission notice shall be
28** included in all copies or substantial portions of the Software.
29**
30** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31** OF MERCHANTABILITY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
32** TO THE WARRANTIES FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
34** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
35** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
36** OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37**
38****************************************************************************/
45#ifndef _USB_HW_H_
46#define _USB_HW_H_
47
48#ifdef __cplusplus
49extern "C"{
50#endif
51
52#include "mcu.h"
53#include <stdbool.h>
54#include "interrupts.h"
55
70// TODO - VBUS pin sense disables or not.
71// Define it here.
72#define VBUS_SENSE_OFF false
73
74#define pointer_byte(_reg) (*(volatile uint8_t *)(uint32_t)(_reg))
75#define pointer_word(_reg) (*(volatile uint16_t *)(uint32_t)(_reg))
76#define pointer_dword(_reg) (*(volatile uint32_t *)(uint32_t)(_reg))
77
78#define HXTAL_STARTUP_TIMEOUT ((uint16_t)0xFFFF)
79
80#define BITS(start, end) ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end))))
81
82// AHB prescaler selection.
83#define CFG0_AHBPSC(regval) (BITS(4,7) & ((uint32_t)(regval) << 4))
84#define RCU_AHB_CKSYS_DIV1 CFG0_AHBPSC(0)
85#define RCU_AHB_CKSYS_DIV2 CFG0_AHBPSC(8)
86#define RCU_AHB_CKSYS_DIV4 CFG0_AHBPSC(9)
87#define RCU_AHB_CKSYS_DIV8 CFG0_AHBPSC(10)
88#define RCU_AHB_CKSYS_DIV16 CFG0_AHBPSC(11)
89#define RCU_AHB_CKSYS_DIV64 CFG0_AHBPSC(12)
90#define RCU_AHB_CKSYS_DIV128 CFG0_AHBPSC(13)
91#define RCU_AHB_CKSYS_DIV256 CFG0_AHBPSC(14)
92#define RCU_AHB_CKSYS_DIV512 CFG0_AHBPSC(15)
93
94// APB1 prescaler selection.
95#define CFG0_APB1PSC(regval) (BITS(8,10) & ((uint32_t)(regval) << 8))
96#define RCU_APB1_CKAHB_DIV1 CFG0_APB1PSC(0)
97#define RCU_APB1_CKAHB_DIV2 CFG0_APB1PSC(4)
98#define RCU_APB1_CKAHB_DIV4 CFG0_APB1PSC(5)
99#define RCU_APB1_CKAHB_DIV8 CFG0_APB1PSC(6)
100#define RCU_APB1_CKAHB_DIV16 CFG0_APB1PSC(7)
101
102// APB2 prescaler selection.
103#define CFG0_APB2PSC(regval) (BITS(11,13) & ((uint32_t)(regval) << 11))
104#define RCU_APB2_CKAHB_DIV1 CFG0_APB2PSC(0)
105#define RCU_APB2_CKAHB_DIV2 CFG0_APB2PSC(4)
106#define RCU_APB2_CKAHB_DIV4 CFG0_APB2PSC(5)
107#define RCU_APB2_CKAHB_DIV8 CFG0_APB2PSC(6)
108#define RCU_APB2_CKAHB_DIV16 CFG0_APB2PSC(7)
109
110// RCU_CFG0 register bit define system clock source select.
111#define CFG0_SCS(regval) (BITS(0,1) & ((uint32_t)(regval) << 0))
112#define RCU_CKSYSSRC_IRC8M CFG0_SCS(0)
113#define RCU_CKSYSSRC_HXTAL CFG0_SCS(1)
114#define RCU_CKSYSSRC_PLL CFG0_SCS(2)
115
116// System clock source select status.
117#define CFG0_SCSS(regval) (BITS(2,3) & ((uint32_t)(regval) << 2))
118#define RCU_SCSS_IRC8M CFG0_SCSS(0)
119#define RCU_SCSS_HXTAL CFG0_SCSS(1)
120#define RCU_SCSS_PLL CFG0_SCSS(2)
121
122// PLL clock source selection.
123#define RCU_PLLSRC_IRC8M_DIV2 ((uint32_t)0x00000000U)
124#define RCU_PLLSRC_HXTAL RCU_CFG0_PLLSEL
125
126// PLL clock multiplication factor.
127#define PLLMF_4 RCU_CFG0_PLLMF_4
128
129#define CFG0_PLLMF(regval) (BITS(18,21) & ((uint32_t)(regval) << 18))
130#define RCU_PLL_MUL2 CFG0_PLLMF(0)
131#define RCU_PLL_MUL3 CFG0_PLLMF(1)
132#define RCU_PLL_MUL4 CFG0_PLLMF(2)
133#define RCU_PLL_MUL5 CFG0_PLLMF(3)
134#define RCU_PLL_MUL6 CFG0_PLLMF(4)
135#define RCU_PLL_MUL7 CFG0_PLLMF(5)
136#define RCU_PLL_MUL8 CFG0_PLLMF(6)
137#define RCU_PLL_MUL9 CFG0_PLLMF(7)
138#define RCU_PLL_MUL10 CFG0_PLLMF(8)
139#define RCU_PLL_MUL11 CFG0_PLLMF(9)
140#define RCU_PLL_MUL12 CFG0_PLLMF(10)
141#define RCU_PLL_MUL13 CFG0_PLLMF(11)
142#define RCU_PLL_MUL14 CFG0_PLLMF(12)
143#define RCU_PLL_MUL6_5 CFG0_PLLMF(13)
144#define RCU_PLL_MUL16 CFG0_PLLMF(14)
145#define RCU_PLL_MUL17 (PLLMF_4 | CFG0_PLLMF(0))
146#define RCU_PLL_MUL18 (PLLMF_4 | CFG0_PLLMF(1))
147#define RCU_PLL_MUL19 (PLLMF_4 | CFG0_PLLMF(2))
148#define RCU_PLL_MUL20 (PLLMF_4 | CFG0_PLLMF(3))
149#define RCU_PLL_MUL21 (PLLMF_4 | CFG0_PLLMF(4))
150#define RCU_PLL_MUL22 (PLLMF_4 | CFG0_PLLMF(5))
151#define RCU_PLL_MUL23 (PLLMF_4 | CFG0_PLLMF(6))
152#define RCU_PLL_MUL24 (PLLMF_4 | CFG0_PLLMF(7))
153#define RCU_PLL_MUL25 (PLLMF_4 | CFG0_PLLMF(8))
154#define RCU_PLL_MUL26 (PLLMF_4 | CFG0_PLLMF(9))
155#define RCU_PLL_MUL27 (PLLMF_4 | CFG0_PLLMF(10))
156#define RCU_PLL_MUL28 (PLLMF_4 | CFG0_PLLMF(11))
157#define RCU_PLL_MUL29 (PLLMF_4 | CFG0_PLLMF(12))
158#define RCU_PLL_MUL30 (PLLMF_4 | CFG0_PLLMF(13))
159#define RCU_PLL_MUL31 (PLLMF_4 | CFG0_PLLMF(14))
160#define RCU_PLL_MUL32 (PLLMF_4 | CFG0_PLLMF(15))
161
162// PREDV0 input clock source selection.
163#define RCU_PREDV0SRC_HXTAL ((uint32_t)0x00000000U)
164#define RCU_PREDV0SRC_CKPLL1 RCU_CFG1_PREDV0SEL
165
166// PLL1 clock multiplication factor.
167#define CFG1_PLL1MF(regval) (BITS(8,11) & ((uint32_t)(regval) << 8))
168#define RCU_PLL1_MUL8 CFG1_PLL1MF(6)
169#define RCU_PLL1_MUL9 CFG1_PLL1MF(7)
170#define RCU_PLL1_MUL10 CFG1_PLL1MF(8)
171#define RCU_PLL1_MUL11 CFG1_PLL1MF(9)
172#define RCU_PLL1_MUL12 CFG1_PLL1MF(10)
173#define RCU_PLL1_MUL13 CFG1_PLL1MF(11)
174#define RCU_PLL1_MUL14 CFG1_PLL1MF(12)
175#define RCU_PLL1_MUL15 CFG1_PLL1MF(13)
176#define RCU_PLL1_MUL16 CFG1_PLL1MF(14)
177#define RCU_PLL1_MUL20 CFG1_PLL1MF(15)
178
179// PREDV0 division factor.
180#define CFG1_PREDV0(regval) (BITS(0,3) & ((uint32_t)(regval) << 0))
181#define RCU_PREDV0_DIV1 CFG1_PREDV0(0)
182#define RCU_PREDV0_DIV2 CFG1_PREDV0(1)
183#define RCU_PREDV0_DIV3 CFG1_PREDV0(2)
184#define RCU_PREDV0_DIV4 CFG1_PREDV0(3)
185#define RCU_PREDV0_DIV5 CFG1_PREDV0(4)
186#define RCU_PREDV0_DIV6 CFG1_PREDV0(5)
187#define RCU_PREDV0_DIV7 CFG1_PREDV0(6)
188#define RCU_PREDV0_DIV8 CFG1_PREDV0(7)
189#define RCU_PREDV0_DIV9 CFG1_PREDV0(8)
190#define RCU_PREDV0_DIV10 CFG1_PREDV0(9)
191#define RCU_PREDV0_DIV11 CFG1_PREDV0(10)
192#define RCU_PREDV0_DIV12 CFG1_PREDV0(11)
193#define RCU_PREDV0_DIV13 CFG1_PREDV0(12)
194#define RCU_PREDV0_DIV14 CFG1_PREDV0(13)
195#define RCU_PREDV0_DIV15 CFG1_PREDV0(14)
196#define RCU_PREDV0_DIV16 CFG1_PREDV0(15)
197
198// PREDV1 division factor.
199#define CFG1_PREDV1(regval) (BITS(4,7) & ((uint32_t)(regval) << 4))
200#define RCU_PREDV1_DIV1 CFG1_PREDV1(0)
201#define RCU_PREDV1_DIV2 CFG1_PREDV1(1)
202#define RCU_PREDV1_DIV3 CFG1_PREDV1(2)
203#define RCU_PREDV1_DIV4 CFG1_PREDV1(3)
204#define RCU_PREDV1_DIV5 CFG1_PREDV1(4)
205#define RCU_PREDV1_DIV6 CFG1_PREDV1(5)
206#define RCU_PREDV1_DIV7 CFG1_PREDV1(6)
207#define RCU_PREDV1_DIV8 CFG1_PREDV1(7)
208#define RCU_PREDV1_DIV9 CFG1_PREDV1(8)
209#define RCU_PREDV1_DIV10 CFG1_PREDV1(9)
210#define RCU_PREDV1_DIV11 CFG1_PREDV1(10)
211#define RCU_PREDV1_DIV12 CFG1_PREDV1(11)
212#define RCU_PREDV1_DIV13 CFG1_PREDV1(12)
213#define RCU_PREDV1_DIV14 CFG1_PREDV1(13)
214#define RCU_PREDV1_DIV15 CFG1_PREDV1(14)
215#define RCU_PREDV1_DIV16 CFG1_PREDV1(15)
216
217// RCU_CFG0 bits.
218#define _RCU_CFG0_PLLMF BITS(18,21)
219#define _RCU_CFG1_PLL1MF BITS(8,11)
220#define _RCU_CFG1_PREDV0 BITS(0,3)
221#define _RCU_CFG1_PREDV1 BITS(4,7)
222#define _RCU_CFG0_SCS BITS(0,1)
223
224static inline void system_rcu_clock_reset( void ) {
225 pointer_dword(RCU_BASE+RCU_CTL) |= RCU_CTL_IRC8MEN;
226
227 // Wait for IRC8M to stabilize.
228 while( !(pointer_dword(RCU_BASE+RCU_CTL) & RCU_CTL_IRC8MSTB ) );
229
235 pointer_dword(RCU_BASE+RCU_CFG0) &= ~(RCU_CFG0_SCS_Msk | RCU_CFG0_AHBPSC_Msk |
236 RCU_CFG0_APB1PSC_Msk | RCU_CFG0_APB2PSC_Msk |
237 RCU_CFG0_ADCPSC_Msk | RCU_CFG0_CKOUT0SEL_Msk |
238 RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB |
239 RCU_CFG0_PLLMF_Msk | RCU_CFG0_USBFSPSC_Msk);
240
241 // Reset HXTALEN, CKMEN, PLLEN bits.
242 pointer_dword(RCU_BASE+RCU_CTL) &= ~(RCU_CTL_HXTALEN |
243 RCU_CTL_CKMEN |
244 RCU_CTL_PLLEN);
245
250 while( ( pointer_dword(RCU_BASE+RCU_CTL) & RCU_CTL_HXTALEN ) );
251 pointer_dword(RCU_BASE+RCU_CTL) &= ~(RCU_CTL_HXTALBPS);
252
253 // Reset PLLSEL, PREDV0_LSB, PLLMF, USBFSPSC bits.
254 pointer_dword(RCU_BASE+RCU_CFG0) &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB |
255 RCU_CFG0_PLLMF_Msk | RCU_CFG0_USBFSPSC_Msk);
256
261 pointer_dword(RCU_BASE+RCU_CFG1) &= ~(0x7FFFFul);
262
263 // Reset HXTALEN, CKMEN, PLLEN, PLL1EN and PLL2EN bits.
264 pointer_dword(RCU_BASE+RCU_CTL) &= ~(RCU_CTL_PLLEN | RCU_CTL_PLL1EN |
265 RCU_CTL_PLL2EN | RCU_CTL_CKMEN |
266 RCU_CTL_HXTALEN);
267
272 pointer_dword(RCU_BASE+RCU_INT) |= 0x00FF0000ul;
273}
274
275static uint8_t clock_48m_hxtal(bool hse_25) {
276 uint32_t timeout = 0U;
277 uint32_t stab_flag = 0U;
278
279 (void)system_rcu_clock_reset();
280
281 // Enable HXTAL.
282 *(uint32_t volatile *)(RCU_BASE+RCU_CTL) |= RCU_CTL_HXTALEN;
283
284 // @ait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT.
285 do{
286 timeout++;
287 stab_flag = (*(uint32_t volatile *)(RCU_BASE+RCU_CTL) & RCU_CTL_HXTALSTB);
288 }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
289
290 // If it fails.
291 if(0U == (*(uint32_t volatile *)(RCU_BASE+RCU_CTL) & RCU_CTL_HXTALSTB)){
292 return 1;
293 }
294
295 // Continue if HXTAL is stable.
296
297 // AHB = SYSCLK.
298 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) |= RCU_AHB_CKSYS_DIV1;
299 // APB2 = AHB/1.
300 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) |= RCU_APB2_CKAHB_DIV1;
301 // APB1 = AHB/2.
302 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) |= RCU_APB1_CKAHB_DIV2;
303
304 // CK_PLL = (CK_PREDIV0) * 12 = 48 MHz.
305 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) &= ~(_RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
306 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL12);
307
308 // HSE 25MHz
309 if(hse_25){
310 // CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz.
311 *(uint32_t volatile *)(RCU_BASE+RCU_CFG1) &= ~(RCU_CFG1_PREDV0SEL | _RCU_CFG1_PLL1MF | _RCU_CFG1_PREDV1 | _RCU_CFG1_PREDV0);
312 *(uint32_t volatile *)(RCU_BASE+RCU_CFG1) |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
313
314 // Enable PLL1.
315 *(uint32_t volatile *)(RCU_BASE+RCU_CTL) |= RCU_CTL_PLL1EN;
316 // Wait till PLL1 is ready.
317 while((*(uint32_t volatile *)(RCU_BASE+RCU_CTL) & RCU_CTL_PLL1STB) == 0){
318 }
319 // HSE 8MHz
320 } else {
321 *(uint32_t volatile *)(RCU_BASE+RCU_CFG1) &= ~(RCU_CFG1_PREDV0SEL | _RCU_CFG1_PREDV1 | _RCU_CFG1_PLL1MF | _RCU_CFG1_PREDV0);
322 *(uint32_t volatile *)(RCU_BASE+RCU_CFG1) |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
323 }
324
325 // Enable PLL.
326 *(uint32_t volatile *)(RCU_BASE+RCU_CTL) |= RCU_CTL_PLLEN;
327
328 // Wait until PLL is stable.
329 while(0U == (*(uint32_t volatile *)(RCU_BASE+RCU_CTL) & RCU_CTL_PLLSTB)){
330 }
331
332 // Select PLL as system clock.
333 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) &= ~_RCU_CFG0_SCS;
334 *(uint32_t volatile *)(RCU_BASE+RCU_CFG0) |= RCU_CKSYSSRC_PLL;
335
336 // Wait until PLL is selected as system clock.
337 while(0U == (*(uint32_t volatile *)(RCU_BASE+RCU_CFG0) & RCU_SCSS_PLL)){
338 }
339
340 return 0;
341}
342
343// GPIO mode values set.
344#define GPIO_MODE_SET(n,mode) ((uint32_t)((uint32_t)(mode) << (4U * (n))))
345#define GPIO_MODE_MASK(n) (0xFU << (4U * (n)))
346
347// GPIO mode definitions.
348#define GPIO_MODE_AIN ((uint8_t)0x00U)
349#define GPIO_MODE_IN_FLOATING ((uint8_t)0x04U)
350#define GPIO_MODE_IPD ((uint8_t)0x28U)
351#define GPIO_MODE_IPU ((uint8_t)0x48U)
352#define GPIO_MODE_OUT_OD ((uint8_t)0x14U)
353#define GPIO_MODE_OUT_PP ((uint8_t)0x10U)
354#define GPIO_MODE_AF_OD ((uint8_t)0x1CU)
355#define GPIO_MODE_AF_PP ((uint8_t)0x18U)
356
357// GPIO output max speed value.
358#define GPIO_OSPEED_10MHZ ((uint8_t)0x01U)
359#define GPIO_OSPEED_2MHZ ((uint8_t)0x02U)
360#define GPIO_OSPEED_50MHZ ((uint8_t)0x03U)
361
362// GPIO pin definitions.
363#define GPIO_PIN_0 BIT(0)
364#define GPIO_PIN_1 BIT(1)
365#define GPIO_PIN_2 BIT(2)
366#define GPIO_PIN_3 BIT(3)
367#define GPIO_PIN_4 BIT(4)
368#define GPIO_PIN_5 BIT(5)
369#define GPIO_PIN_6 BIT(6)
370#define GPIO_PIN_7 BIT(7)
371#define GPIO_PIN_8 BIT(8)
372#define GPIO_PIN_9 BIT(9)
373#define GPIO_PIN_10 BIT(10)
374#define GPIO_PIN_11 BIT(11)
375#define GPIO_PIN_12 BIT(12)
376#define GPIO_PIN_13 BIT(13)
377#define GPIO_PIN_14 BIT(14)
378#define GPIO_PIN_15 BIT(15)
379#define GPIO_PIN_ALL BITS(0, 15)
380
381#define BIT(x) ((uint32_t)((uint32_t)0x01U<<(x)))
382
383static void gpio_init_ctlx(
384 uint32_t gpio_periph, uint32_t mode[2],
385 uint32_t speed, uint32_t pin
386 )
387{
388 uint32_t offset, reg = 0U;
389
390 offset = GPIO_CTL0;
391 if (pin > GPIO_PIN_7)
392 offset = GPIO_CTL1;
393
394 for (uint8_t i = 0U; i < 8U; i++) {
395 if ((1U << i) & pin) {
396 reg = *(uint32_t volatile *)(gpio_periph+offset);
397
398 // Clear the specified pin mode bits.
399 reg &= ~GPIO_MODE_MASK(i);
400 // Set the specified pin mode bits.
401 reg |= GPIO_MODE_SET(i, mode[1]);
402
403 // Set IPD or IPU.
404 if (GPIO_MODE_IPD == mode[0]) {
405 // Reset the corresponding OCTL bit.
406 *(uint32_t volatile *)(gpio_periph+GPIO_BC) = (uint32_t) ((1U << i) & pin);
407 } else {
408 // Set the corresponding OCTL bit.
409 if (GPIO_MODE_IPU == mode[0]) {
410 *(uint32_t volatile *)(gpio_periph+GPIO_BOP) = (uint32_t) ((1U << i) & pin);
411 }
412 }
413 // Set GPIO_CTLx register.
414 *(uint32_t volatile *)(gpio_periph+offset) = reg;
415 }
416 }
417}
418
419static void gpio_init(
420 uint32_t gpio_periph, uint32_t mode,
421 uint32_t speed, uint32_t pin
422 )
423{
424 uint16_t i;
425 uint32_t temp_mode[2] = {mode, 0U};
426 uint32_t reg = 0U;
427
428 // GPIO mode configuration.
429 temp_mode[1] = (uint32_t) (mode & ((uint32_t) 0x0FU));
430
431 // GPIO speed configuration.
432 if (((uint32_t) 0x00U) != ((uint32_t) mode & ((uint32_t) 0x10U))) {
433 // Output mode max speed:10MHz,2MHz,50MHz.
434 temp_mode[1] |= (uint32_t) speed;
435 }
436
437 // Configure the port pin.
438 gpio_init_ctlx(gpio_periph, temp_mode, speed, pin);
439}
440
441#define GET_BITS(regval, start, end) (((regval) & BITS((start),(end))) >> (start))
442
443// Define clock source.
444#define SEL_IRC8M ((uint16_t)0U)
445#define SEL_HXTAL ((uint16_t)1U)
446#define SEL_PLL ((uint16_t)2U)
447
448// USBFS prescaler select.
449#define CFG0_USBPSC(regval) (BITS(22,23) & ((uint32_t)(regval) << 22))
450#define RCU_CKUSB_CKPLL_DIV1_5 CFG0_USBPSC(0)
451#define RCU_CKUSB_CKPLL_DIV1 CFG0_USBPSC(1)
452#define RCU_CKUSB_CKPLL_DIV2_5 CFG0_USBPSC(2)
453#define RCU_CKUSB_CKPLL_DIV2 CFG0_USBPSC(3)
454#define _RCU_CFG0_USBFSPSC BITS(22,23)
455
456#define IRC8M_VALUE ((uint32_t)8000000)
457#define MIKROE_HW_HXTAL ((uint32_t)25000000)
458
459// Define value of high speed crystal oscillator (HXTAL) in Hz.
460#if !defined HXTAL_VALUE
461 #ifdef MCU_CARD_FOR_RISC_V
462 #define HXTAL_VALUE MIKROE_HW_HXTAL
463 #else
464 #define HXTAL_VALUE IRC8M_VALUE
465 #endif
466#endif
467
468// Rcu clock frequency.
469typedef enum {
470 CK_SYS = 0,
471 CK_AHB,
472 CK_APB1,
473 CK_APB2,
474} rcu_clock_freq_enum;
475
487static uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
488{
489 uint32_t sws, ck_freq = 0U;
490 uint32_t cksys_freq, ahb_freq, apb1_freq, apb2_freq;
491 uint32_t pllsel, predv0sel, pllmf,ck_src, idx, clk_exp;
492 uint32_t predv0, predv1, pll1mf;
493
494 // Exponent of AHB, APB1 and APB2 clock divider.
495 uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
496 uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
497 uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
498
499 sws = GET_BITS(pointer_dword(RCU_BASE+RCU_CFG0), 2, 3);
500 switch(sws){
501 // IRC8M is selected as CK_SYS.
502 case SEL_IRC8M:
503 cksys_freq = IRC8M_VALUE;
504 break;
505 // HXTAL is selected as CK_SYS.
506 case SEL_HXTAL:
507 cksys_freq = HXTAL_VALUE;
508 break;
509 // PLL is selected as CK_SYS.
510 case SEL_PLL:
511 // PLL clock source selection, HXTAL or IRC8M/2.
512 pllsel = (pointer_dword(RCU_BASE+RCU_CFG0) & RCU_CFG0_PLLSEL);
513
514 if(RCU_PLLSRC_HXTAL == pllsel) {
515 // PLL clock source is HXTAL.
516 ck_src = HXTAL_VALUE;
517
518 predv0sel = (pointer_dword(RCU_BASE+RCU_CFG1) & RCU_CFG1_PREDV0SEL);
519 // Source clock use PLL1.
520 if(RCU_PREDV0SRC_CKPLL1 == predv0sel){
521 predv1 = (uint32_t)((pointer_dword(RCU_BASE+RCU_CFG1) & _RCU_CFG1_PREDV1) >> 4) + 1U;
522 pll1mf = (uint32_t)((pointer_dword(RCU_BASE+RCU_CFG1) & _RCU_CFG1_PLL1MF) >> 8) + 2U;
523 if(17U == pll1mf){
524 pll1mf = 20U;
525 }
526 ck_src = (ck_src / predv1) * pll1mf;
527 }
528 predv0 = (pointer_dword(RCU_BASE+RCU_CFG1) & _RCU_CFG1_PREDV0) + 1U;
529 ck_src /= predv0;
530 }else{
531 // PLL clock source is IRC8M/2.
532 ck_src = IRC8M_VALUE/2U;
533 }
534
535 // PLL multiplication factor.
536 pllmf = GET_BITS(pointer_dword(RCU_BASE+RCU_CFG0), 18, 21);
537 if((pointer_dword(RCU_BASE+RCU_CFG0) & RCU_CFG0_PLLMF_4)){
538 pllmf |= 0x10U;
539 }
540 if(pllmf < 15U){
541 pllmf += 2U;
542 }else{
543 pllmf += 1U;
544 }
545
546 cksys_freq = ck_src * pllmf;
547
548 if(15U == pllmf){
549 // PLL source clock multiply by 6.5.
550 cksys_freq = ck_src * 6U + ck_src / 2U;
551 }
552
553 break;
554
555 // IRC8M is selected as CK_SYS.
556 default:
557 cksys_freq = IRC8M_VALUE;
558 break;
559 }
560
561 // Calculate AHB clock frequency.
562 idx = GET_BITS(pointer_dword(RCU_BASE+RCU_CFG0), 4, 7);
563 clk_exp = ahb_exp[idx];
564 ahb_freq = cksys_freq >> clk_exp;
565
566 // Calculate APB1 clock frequency.
567 idx = GET_BITS(pointer_dword(RCU_BASE+RCU_CFG0), 8, 10);
568 clk_exp = apb1_exp[idx];
569 apb1_freq = ahb_freq >> clk_exp;
570
571 // Calculate APB2 clock frequency.
572 idx = GET_BITS(pointer_dword(RCU_BASE+RCU_CFG0), 11, 13);
573 clk_exp = apb2_exp[idx];
574 apb2_freq = ahb_freq >> clk_exp;
575
576 // Return the clock frequency.
577 switch(clock){
578 case CK_SYS:
579 ck_freq = cksys_freq;
580 break;
581 case CK_AHB:
582 ck_freq = ahb_freq;
583 break;
584 case CK_APB1:
585 ck_freq = apb1_freq;
586 break;
587 case CK_APB2:
588 ck_freq = apb2_freq;
589 break;
590
591 default:
592 break;
593 }
594
595 return ck_freq;
596}
597
598static inline void rcu_usb_clock_config(uint32_t usb_psc)
599{
600 uint32_t reg;
601
602 reg = pointer_dword(RCU_BASE+RCU_CFG0);
603
604 // Configure the USBFS prescaler factor.
605 reg &= ~_RCU_CFG0_USBFSPSC;
606 pointer_dword(RCU_BASE+RCU_CFG0) = (reg | usb_psc);
607}
608
609static inline void usb_rcu_config(bool config_clock) {
610 if (config_clock)
611 // Initialize with external OSCILATTOR?
612 (void)clock_48m_hxtal(HXTAL_VALUE == MIKROE_HW_HXTAL);
613
614 static volatile uint32_t usbfs_prescaler = 0;
615 volatile uint32_t system_clock = rcu_clock_freq_get(CK_SYS);
616
617 if (system_clock == 48000000) {
618 usbfs_prescaler = RCU_CKUSB_CKPLL_DIV1;
619 } else if (system_clock == 72000000) {
620 usbfs_prescaler = RCU_CKUSB_CKPLL_DIV1_5;
621 } else if (system_clock == 96000000) {
622 usbfs_prescaler = RCU_CKUSB_CKPLL_DIV2;
623 } else {
624 // Reserved //
625 return;
626 }
627
628 rcu_usb_clock_config(usbfs_prescaler);
629 pointer_dword(RCU_BASE+RCU_AHBEN) |= RCU_AHBEN_USBFSEN;
630}
631
640static inline void usb_hw_init(void) {
641 interrupts_disable();
642 (void)usb_rcu_config(false);
643 pointer_dword(RCU_BASE+RCU_APB2EN) |= RCU_APB2EN_PAEN; // PORTA clock.
644 pointer_dword(RCU_BASE+RCU_APB2EN) |= RCU_APB2EN_AFEN; // AF clock.
645 #if VBUS_SENSE_OFF
646 gpio_init(GPIOA_BASE, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
647 pointer_dword(USBFS_BASE+USBFS_GCCFG) |= USBFS_GCCFG_VBUSIG;
648 #endif
649 pointer_dword(USBFS_BASE+USBFS_GCCFG) |= USBFS_GCCFG_VBUSBCEN | USBFS_GCCFG_PWRON;
650 pointer_dword(RCU_BASE+RCU_APB1EN) |= RCU_APB1EN_PMUEN;
651 interrupts_enable();
652}
653
654 // usb
655 // middleware
656
657#ifdef __cplusplus
658}
659#endif
660
661#endif // _USB_HW_H_
662// ------------------------------------------------------------------------- END
#define GPIOA_BASE
Definition MK60D10.h:6908