blob: d3c1afb4345098775bd8393b2e69adebf6621512 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
// Code to setup clocks and gpio on stm32f0
//
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "autoconf.h" // CONFIG_CLOCK_REF_8M
#include "command.h" // DECL_CONSTANT_STR
#include "internal.h" // enable_pclock
#define FREQ_PERIPH 48000000
// Enable a peripheral clock
void
enable_pclock(uint32_t periph_base)
{
if (periph_base < SYSCFG_BASE) {
uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400;
RCC->APB1ENR |= 1 << pos;
RCC->APB1ENR;
} else if (periph_base < AHBPERIPH_BASE) {
uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400;
RCC->APB2ENR |= 1 << pos;
RCC->APB2ENR;
} else {
uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400;
RCC->AHBENR |= 1 << (pos + 17);
RCC->AHBENR;
}
}
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t periph_base)
{
if (periph_base < SYSCFG_BASE) {
uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400;
return RCC->APB1ENR & (1 << pos);
} else if (periph_base < AHBPERIPH_BASE) {
uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400;
return RCC->APB2ENR & (1 << pos);
} else {
uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400;
return RCC->AHBENR & (1 << (pos + 17));
}
}
// Return the frequency of the given peripheral clock
uint32_t
get_pclock_frequency(uint32_t periph_base)
{
return FREQ_PERIPH;
}
// Enable a GPIO peripheral clock
void
gpio_clock_enable(GPIO_TypeDef *regs)
{
uint32_t rcc_pos = ((uint32_t)regs - AHB2PERIPH_BASE) / 0x400;
RCC->AHBENR |= 1 << (rcc_pos + 17);
RCC->AHBENR;
}
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8;
uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0;
uint32_t pos = gpio % 16, af_reg = pos / 8;
uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift;
uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift;
regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift);
regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift);
regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift);
regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos);
regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift);
}
// Handle USB reboot requests
void
usb_request_bootloader(void)
{
}
#if CONFIG_CLOCK_REF_8M
DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PF0,PF1");
#endif
// Configure and enable the PLL as clock source
static void
pll_setup(void)
{
uint32_t cfgr;
if (CONFIG_CLOCK_REF_8M) {
// Configure 48Mhz PLL from external 8Mhz crystal (HSE)
RCC->CR |= RCC_CR_HSEON;
cfgr = RCC_CFGR_PLLSRC_HSE_PREDIV | ((6 - 2) << RCC_CFGR_PLLMUL_Pos);
} else {
// Configure 48Mhz PLL from internal 8Mhz oscillator (HSI)
cfgr = RCC_CFGR_PLLSRC_HSI_DIV2 | ((12 - 2) << RCC_CFGR_PLLMUL_Pos);
}
RCC->CFGR = cfgr;
RCC->CR |= RCC_CR_PLLON;
// Wait for PLL lock
while (!(RCC->CR & RCC_CR_PLLRDY))
;
// Switch system clock to PLL
RCC->CFGR = cfgr | RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL)
;
// Select PLL as source for USB clock
if (CONFIG_USBSERIAL)
RCC->CFGR3 = RCC_CFGR3_USBSW;
}
// Configure and enable internal 48Mhz clock on the stm32f042
static void
hsi48_setup(void)
{
#if CONFIG_MACH_STM32F042
// Enable HSI48
RCC->CR2 |= RCC_CR2_HSI48ON;
while (!(RCC->CR2 & RCC_CR2_HSI48RDY))
;
// Switch system clock to HSI48
RCC->CFGR = RCC_CFGR_SW_HSI48;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI48)
;
// Enable USB clock recovery
if (CONFIG_USBSERIAL) {
enable_pclock(CRS_BASE);
CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
}
#endif
}
// Main clock setup called at chip startup
void
clock_setup(void)
{
// Set flash latency
FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE;
// Configure main clock
if (CONFIG_MACH_STM32F042 && CONFIG_STM32_CLOCK_REF_INTERNAL)
hsi48_setup();
else
pll_setup();
}
|