OpenMPTL - STM32F4
C++ Microprocessor Template Library
rcc.hpp
Go to the documentation of this file.
1 /*
2  * OpenMPTL - C++ Microprocessor Template Library
3  *
4  * Copyright (C) 2012-2017 Axel Burri <axel@tty0.ch>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef ARCH_RCC_HPP_INCLUDED
22 #define ARCH_RCC_HPP_INCLUDED
23 
24 #include <simulation.hpp>
25 #include <arch/reg/rcc.hpp>
26 #include <typelist.hpp>
27 #include <freq.hpp>
28 
29 namespace mptl {
30 
31 
32 //////////////////// rcc ////////////////////
33 
34 
35 class rcc
36 {
37 public: /* ------ configuration traits ------ */
38 
41 
44 
45 public: /* ------ static member functions ------ */
46 
47  static void wait_hse_ready() {
48  while(RCC::CR::HSERDY::test() == false);
49  }
50  static bool wait_hse_ready(unsigned timeout) {
51  while((RCC::CR::HSERDY::test() == false) && timeout) {
52  timeout--;
53  }
54  return timeout;
55  }
56 
57  static void wait_hsi_ready() {
58  while(RCC::CR::HSIRDY::test() == false);
59  }
60  static bool wait_hsi_ready(unsigned timeout) {
61  while((RCC::CR::HSIRDY::test() == false) && timeout) {
62  timeout--;
63  }
64  return timeout;
65  }
66 };
67 
68 
69 //////////////////// system_clock_hse ////////////////////
70 
71 
72 template< typename... Tp >
74 {
75  using cfg_list = reglist<
76  Tp...,
77  RCC::PLLCFGR::PLLSRC /* select HSE */
78  >;
79 
80  static void init(void) {
83  }
84 
85  static void configure(void) {
86  cfg_list::template strict_reset_to<
87  RCC::CFGR,
89  >();
90 
92  while(RCC::CR::PLLRDY::test() == false);
94  while(RCC::CFGR::SWS::PLL::test() == false);
95  }
96 };
97 
98 
99 /**
100  * PLL configuration with fixed PLLP=2
101  */
102 template< freq_t output_freq, freq_t hse_freq >
104  static constexpr freq_t vco_input = mhz(1); // It is recommended to select a frequency of 2 MHz to limit PLL jitter.
105 
106  static constexpr unsigned p = 2;
107  static constexpr unsigned m = hse_freq / vco_input;
108  static constexpr unsigned n = (output_freq / vco_input ) * p;
109  static constexpr unsigned q = n / 48 + (n % 48 ? 1 : 0); // use next higher value if n is not divisible without reminder
110 
111  static_assert(p==2 || p==4 || p==6 || p==8, "illegal PLLP value");
112  static_assert(q >= 2 && q <= 15, "illegal PLLQ value");
113  static_assert(n >= 192 && n <= 432, "illegal PLLN value");
114  static_assert(m >= 2 && m <= 63, "illegal PLLM value");
115 
116  static constexpr freq_t vco_output = vco_input * n;
117  static constexpr freq_t pll_output = vco_output / p;
118  static constexpr freq_t pll48clk = vco_output / q;
119 
120  static_assert(vco_input >= mhz(1) && vco_input <= mhz(2), "illegal VCO input frequency");
121  static_assert(vco_output >= mhz(192) && vco_output <= mhz(432), "illegal VCO output frequency");
122  static_assert(pll_output <= mhz(168), "illegal PLL output frequency");
123 
124  /* The USB OTG FS requires a 48 MHz clock to work correctly */
125  static constexpr bool usb_otg_available = ( pll48clk == mhz(48) );
126 
127  /* The SDIO and the random number generator need a frequency lower
128  * than or equal to 48 MHz to work correctly. */
129  static constexpr bool sdio_available = ( pll48clk <= mhz(48) );
130  static constexpr bool rng_available = ( pll48clk <= mhz(48) );
131 
132  /* assert on above restrictions for now */
133  static_assert(usb_otg_available, "USB OTG FS is not available");
134  static_assert(sdio_available, "SDIO is not available");
135  static_assert(rng_available, "RNG is not available");
136 
137  using type = reglist <
142  >;
143 
144 #ifdef OPENMPTL_SIMULATION
145  static void dump() {
146  std::cout << std::dec << "--------------------" << std::endl;
147  std::cout << "HCLK = " << output_freq / mhz(1) << " MHz" << std::endl;
148  std::cout << "HSE = " << hse_freq / mhz(1) << " MHz" << std::endl;
149  std::cout << std::dec << "--------------------" << std::endl;
150 
151  std::cout << "m=" << m << std::endl;
152  std::cout << "n=" << n << std::endl;
153  std::cout << "p=" << p << std::endl;
154  std::cout << "q=" << q << std::endl;
155 
156  std::cout << "vco_input = " << (vco_input / mhz(1)) << " MHz" << std::endl;
157  std::cout << "vco_output = " << (vco_output / mhz(1)) << " MHz" << std::endl;
158  std::cout << "pll_output = " << (pll_output / mhz(1)) << " MHz" << std::endl;
159  std::cout << "pll48clk = " << (pll48clk / mhz(1)) << " MHz" << std::endl;
160  }
161 #endif
162 };
163 
164 
165 /**
166  * Generic HSE system clock setup.
167  *
168  * Provides decent clock setup for
169  * output_freq (HCLK): 168MHz, 144MHz, 120Mhz, 96MHz.
170  *
171  * Template arguments:
172  *
173  * - output_freq: desired output (HCLK) frequency
174  * - hse_freq: frequency of the HSE external oscillator
175  */
176 template< freq_t output_freq, freq_t hse_freq = mhz(8) >
178 : public system_clock_hse_base<
179  RCC::CFGR::HPRE ::DIV1,
180  RCC::CFGR::PPRE1::DIV4,
181  RCC::CFGR::PPRE2::DIV2,
182  typename system_clock_pllcfgr< output_freq, hse_freq >::type
183  >
184 {
185  static_assert( output_freq <= mhz(168), "illegal output (HCLK) frequency" );
186  static_assert( hse_freq >= mhz(4) && hse_freq <= mhz(26), "illegal HSE frequency" );
187 
188  static constexpr freq_t hclk_freq = output_freq;
189  static constexpr freq_t pclk1_freq = hclk_freq / 4;
190  static constexpr freq_t pclk2_freq = hclk_freq / 2;
191 };
192 
193 
194 //////////////////// peripheral clock traits ////////////////////
195 
196 
197 /* Clock resource declarations (enable peripheral clocks) */
198 template<char> struct rcc_gpio_clock_resources;
199 template<unsigned> struct rcc_usart_clock_resources;
200 
201 /*
202  * Clock resource specialisation (enable peripheral clocks)
203  */
204 template<> struct rcc_gpio_clock_resources<'A'> : RCC::AHB1ENR::GPIOAEN { };
205 template<> struct rcc_gpio_clock_resources<'B'> : RCC::AHB1ENR::GPIOBEN { };
206 template<> struct rcc_gpio_clock_resources<'C'> : RCC::AHB1ENR::GPIOCEN { };
207 template<> struct rcc_gpio_clock_resources<'D'> : RCC::AHB1ENR::GPIODEN { };
208 template<> struct rcc_gpio_clock_resources<'E'> : RCC::AHB1ENR::GPIOEEN { };
209 template<> struct rcc_gpio_clock_resources<'F'> : RCC::AHB1ENR::GPIOFEN { };
210 template<> struct rcc_gpio_clock_resources<'G'> : RCC::AHB1ENR::GPIOGEN { };
211 template<> struct rcc_gpio_clock_resources<'H'> : RCC::AHB1ENR::GPIOHEN { };
212 template<> struct rcc_gpio_clock_resources<'I'> : RCC::AHB1ENR::GPIOIEN { };
213 
218 
219 } // namespace mptl
220 
221 #endif // ARCH_RCC_HPP_INCLUDED
Clock configuration register.
Definition: rcc.hpp:78
static void init(void)
Definition: rcc.hpp:80
Generic HSE system clock setup.
Definition: rcc.hpp:177
static bool wait_hse_ready(unsigned timeout)
Definition: rcc.hpp:50
unsigned int freq_t
static void configure(void)
Definition: rcc.hpp:85
Definition: rcc.hpp:73
Definition: rcc.hpp:198
Definition: rcc.hpp:35
static bool wait_hsi_ready(unsigned timeout)
Definition: rcc.hpp:60
reglist< regval< RCC::PLLCFGR::PLLM, m >, regval< RCC::PLLCFGR::PLLN, n >, regval< RCC::PLLCFGR::PLLP,(p > > 1) - 1 >, regval< RCC::PLLCFGR::PLLQ, q > > type
Definition: rcc.hpp:142
static void wait_hse_ready()
Definition: rcc.hpp:47
static constexpr freq_t mhz(unsigned long long x)
PLL configuration with fixed PLLP=2.
Definition: rcc.hpp:103
static void wait_hsi_ready()
Definition: rcc.hpp:57
Definition: rcc.hpp:199
PLL configuration register.
Definition: rcc.hpp:65