aboutsummaryrefslogtreecommitdiffstats
path: root/docs/source/libmaple/api/rcc.rst
blob: 350695669683c5e0861af08bc5c6c837a57a5af5 (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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
.. highlight:: c
.. _libmaple-rcc:

``<libmaple/rcc.h>``
====================

Reset and Clock Control (RCC) support.

The RCC is responsible for managing the MCU's various clocks. This
includes the core clock SYSCLK, which determines the CPU clock
frequency, as well as the clock lines that drive peripherals.

Because of this, the available RCC functionality varies by target.
There are a :ref:`variety of abstractions <libmaple-rcc-core-types>`
in place to make managing this more convenient.

.. contents:: Contents
   :local:
   :depth: 2

.. _libmaple-rcc-core-types:

Core Types
----------

The core abstractions in place are
:ref:`rcc_clk_id <libmaple-rcc-rcc_clk_id>`,
:ref:`rcc_clk <libmaple-rcc-rcc_clk>`,
:ref:`rcc_sysclk_src <libmaple-rcc-rcc_sysclk_src>`,
:ref:`rcc_clk_domain <libmaple-rcc-rcc_clk_domain>`, and
:ref:`rcc_prescaler <libmaple-rcc-rcc_prescaler>`.

.. _libmaple-rcc-rcc_clk_id:

Peripheral Identifiers: ``rcc_clk_id``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``rcc_clk_id`` is an enum used to identify peripherals. The RCC
back-ends use them to look up a peripheral's bus and clock line, but
they are also generally useful as unique identifiers for each
peripheral.  You can manage peripherals using their ``rcc_clk_id``\ s
with :ref:`these functions <libmaple-rcc-clk-id-funcs>`.

Peripherals which are common across targets have the same token
(though not necessarily the same value) for their ``rcc_clk_id``
across different targets. For example, the ``rcc_clk_id`` for the ADC1
peripheral is always ``RCC_ADC1`` regardless of the target.
Additionally, as explained in :ref:`libmaple-overview-devices`, each
peripheral device type struct contains the ``rcc_clk_id`` for that
peripheral in a ``clk_id`` field.

The available ``rcc_clk_id``\ s on each supported target series are as
follows.

STM32F1 Targets
+++++++++++++++

.. doxygenenum:: stm32f1::rcc_clk_id

STM32F2-F4 Targets
++++++++++++++++++

.. doxygenenum:: stm32f2_f4::rcc_clk_id

.. _libmaple-rcc-rcc_sysclk_src:

System Clock (SYSCLK) Sources: ``rcc_sysclk_src``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SYSCLK is the core system clock. It determines the CPU clock rate, and
it's the base clock which is used to drive (most of) the peripherals
on the STM32. ``rcc_sysclk_src`` is an enum for the possible SYSCLK
sources. Switch the SYSCLK source with :ref:`rcc_switch_sysclk()
<libmaple-rcc-rcc_switch_sysclk>`.

.. doxygenenum:: rcc_sysclk_src

As a special case, you can configure the PLL with a call to
:ref:`rcc_configure_pll() <libmaple-rcc-rcc_configure_pll>`.

.. _libmaple-rcc-rcc_clk:

System and Secondary Clock Sources: ``rcc_clk``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``rcc_clk`` type gives available system and secondary clock
sources (e.g. HSI, HSE, LSE). As with :ref:`rcc_clk_id
<libmaple-rcc-rcc_clk_id>`, clock sources which are common across
targets have the same token, but not necessarily the same value, for
their ``rcc_clk`` on each target.  A variety of :ref:`clock management
functions <libmaple-rcc-clk-funcs>` are available.

Note that the inclusion of secondary clock sources, like LSI and LSE,
makes ``rcc_clk`` different from the SYSCLK sources, which are managed
using :ref:`rcc_sysclk_src <libmaple-rcc-rcc_sysclk_src>`.

The available ``rcc_clk``\ s for each supported target series are as
follows.

STM32F1 Targets
+++++++++++++++

.. doxygenenum:: stm32f1::rcc_clk

STM32F2-F4 Targets
++++++++++++++++++

.. doxygenenum:: stm32f2_f4::rcc_clk

.. _libmaple-rcc-rcc_clk_domain:

Clock Domains: ``rcc_clk_domain``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

These specify the available clock domains.  For example, each AHB and
APB is a clock domain.

This type mostly exists to enable asking devices what bus they're on,
which, given knowledge of your system's clock configuration, can be
useful when making decisions about prescalers, etc.

Given an :ref:`rcc_clk_id <libmaple-rcc-rcc_clk_id>`, you can get the
peripheral's clock domain with :ref:`rcc_dev_clk()
<libmaple-rcc-rcc_dev_clk>`.  Clock domains that are common across
series have the same token (but not necessarily the same value) for
their corresponding ``rcc_clk_domain``.

The available ``rcc_clk_domain``\ s for each supported target series
are as follows.

STM32F1 Targets
+++++++++++++++

.. doxygenenum:: stm32f1::rcc_clk_domain

STM32F2-F4 Targets
++++++++++++++++++

.. doxygenenum:: stm32f2_f4::rcc_clk_domain

.. _libmaple-rcc-rcc_prescaler:

Prescalers: ``rcc_prescaler`` and Friends
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Available prescalers are managed via the ``rcc_prescaler`` type, the
``rcc_set_prescaler()`` function, and a variety of related prescaler
divider types.  See :ref:`libmaple-rcc-prescalers` for more
information and usage notes.

Functions
---------

.. _libmaple-rcc-sysclk-funcs:
.. _libmaple-rcc-rcc_switch_sysclk:

SYSCLK Management
~~~~~~~~~~~~~~~~~

Change the SYSCLK source with ``rcc_switch_sysclk()``.

.. doxygenfunction:: rcc_switch_sysclk

.. _libmaple-rcc-rcc_configure_pll:

PLL Configuration
~~~~~~~~~~~~~~~~~

You can configure the PLL with ``rcc_configure_pll()``.  This takes an
``rcc_pll_cfg`` struct as its argument.  Though the definition of
``rcc_pll_cfg`` is common across series, its contents are entirely
target-dependent.

.. doxygenstruct:: rcc_pll_cfg
.. _rcc-rcc_configure_pll:
.. doxygenfunction:: rcc_configure_pll

The fields in an ``rcc_pll_cfg`` on each target are as follows.

rcc_pll_cfg on STM32F1 Targets
++++++++++++++++++++++++++++++

The ``pllsrc`` field is chosen from the following.

.. doxygenenum:: stm32f1::rcc_pllsrc

.. FIXME [0.0.13] We've got plans to redo this; make sure you watch
.. libmaple for changes here.

The ``data`` field must point to a ``struct stm32f1_rcc_pll_data``.
This just contains an ``rcc_pll_multiplier``.

.. doxygenenum:: stm32f1::rcc_pll_multiplier

.. doxygenstruct:: stm32f1::stm32f1_rcc_pll_data

rcc_pll_cfg on STM32F2-F4 Targets
+++++++++++++++++++++++++++++++++

The ``pllsrc`` field is chosen from the following.

.. doxygenenum:: stm32f2_f4::rcc_pllsrc

The ``data`` field must point to a ``struct stm32f2_rcc_pll_data``.

.. doxygenstruct:: stm32f2_f4::stm32f2_rcc_pll_data

.. _libmaple-rcc-clk-funcs:

System and Secondary Clock Management
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

These functions are useful for managing clocks via their :ref:`rcc_clk
<libmaple-rcc-rcc_clk>`.

.. doxygenfunction:: rcc_turn_on_clk
.. doxygenfunction:: rcc_turn_off_clk
.. doxygenfunction:: rcc_is_clk_on
.. doxygenfunction:: rcc_is_clk_ready

.. _libmaple-rcc-clk-id-funcs:

Peripheral Management
~~~~~~~~~~~~~~~~~~~~~

These functions are useful for managing peripherals via their
:ref:`rcc_clk_id <libmaple-rcc-rcc_clk_id>`.

.. _libmaple-rcc-rcc_clk_enable:
.. doxygenfunction:: rcc_clk_enable
.. doxygenfunction:: rcc_reset_dev
.. _libmaple-rcc-rcc_dev_clk:
.. doxygenfunction:: rcc_dev_clk

.. _libmaple-rcc-prescalers:

Prescaler Management
~~~~~~~~~~~~~~~~~~~~

All clock prescalers managed by RCC can be controlled with a single
function, ``rcc_set_prescaler()``.

.. doxygenfunction:: rcc_set_prescaler

The arguments to ``rcc_set_prescaler()`` are target-dependent, but
follow a common pattern:

- The first argument is the prescaler to set, so there's one for each
  peripheral clock domain, etc.  These have names like
  ``RCC_PRESCALER_FOO``, e.g. ``RCC_PRESCALER_APB1``.  Choose the
  prescaler from the ``rcc_prescaler``\ s on your target (see below).

- The second argument is the actual clock divider to use; it's chosen
  based on the first argument. The dividers for ``RCC_PRESCALER_FOO``
  are given by the type ``rcc_foo_divider``, and have values like
  ``RCC_FOO_xxx_DIV_y``. This means that the foo clock will be the
  ``xxx`` clock divided by ``y``.

For example, calling ``rcc_set_prescaler(RCC_PRESCALER_APB1,
RCC_APB1_HCLK_DIV_1)`` would set the APB1 clock to HCLK divided by 1.

Prescalers which are common across targets have the same token, though
not necessarily the same value, for their ``rcc_prescaler`` (for
example, ``RCC_PRESCALER_APB1`` is available on both STM32F1 and
STM32F2 targets). The available prescalers and dividers on each
supported target series are as follows.

STM32F1 Targets
+++++++++++++++

.. doxygenenum:: stm32f1::rcc_prescaler
.. doxygenenum:: stm32f1::rcc_adc_divider
.. doxygenenum:: stm32f1::rcc_apb1_divider
.. doxygenenum:: stm32f1::rcc_apb2_divider
.. doxygenenum:: stm32f1::rcc_ahb_divider

STM32F2-F4 Targets
++++++++++++++++++

.. doxygenenum:: stm32f2_f4::rcc_prescaler
.. doxygenenum:: stm32f2_f4::rcc_mco2_divider
.. doxygenenum:: stm32f2_f4::rcc_mco1_divider
.. doxygenenum:: stm32f2_f4::rcc_rtc_divider
.. doxygenenum:: stm32f2_f4::rcc_apb2_divider
.. doxygenenum:: stm32f2_f4::rcc_apb1_divider
.. doxygenenum:: stm32f2_f4::rcc_ahb_divider

Register Maps
-------------

These vary by target. The base pointer is always ``RCC_BASE``.

.. doxygendefine:: RCC_BASE

STM32F1 Targets
~~~~~~~~~~~~~~~

.. doxygenstruct:: stm32f1::rcc_reg_map

STM32F2-F4 Targets
~~~~~~~~~~~~~~~~~~

.. doxygenstruct:: stm32f2_f4::rcc_reg_map

Register Bit Definitions
------------------------

These are given as source code.  Available register bit definitions
vary by target.

.. We need this include to avoid crashing Emacs's ReST parser. Yuck.

.. include:: rcc-reg-bits.txt

Deprecated Functionality
------------------------

.. _rcc-rcc_clk_init:
.. doxygenfunction:: stm32f1::rcc_clk_init

To replace a call to ``rcc_clk_init()`` in order to set SYSCLK to PLL
driven by an external oscillator, you can use something like this,
which is portable except for the initialization of ``your_pll_cfg``::

    /* You need to make this point to something valid for your target; see
     * the documentation for rcc_configure_pll() for more details. */
    extern rcc_pll_cfg *your_pll_cfg;

    void pll_reconfigure() {
        /* Turn on HSI using rcc_turn_on_clk() and wait for it to
         * become ready by busy-waiting on rcc_is_clk_ready().
         *
         * Switch to HSI to ensure we're not using the PLL while we
         * reconfigure it. */
        rcc_turn_on_clk(RCC_CLK_HSI);
        while (!rcc_is_clk_ready(RCC_CLK_HSI))
            ;
        rcc_switch_sysclk(RCC_CLKSRC_HSI);

        /* Turn off HSE and the PLL, or we can't reconfigure it. */
        rcc_turn_off_clk(RCC_CLK_PLL);
        rcc_turn_off_clk(RCC_CLK_HSE);

        /* Reconfigure the PLL. You can also perform any other
         * prescaler management here. */
        rcc_configure_pll(your_pll_cfg);

        /* Turn on RCC_CLK_HSE. */
        rcc_turn_on_clk(RCC_CLK_HSE);
        while (!rcc_is_clk_ready(RCC_CLK_HSE))
            ;

        /* Turn on RCC_CLK_PLL. */
        rcc_turn_on_clk(RCC_CLK_PLL);
        while (!rcc_is_clk_ready(RCC_CLK_PLL))
            ;

        /* Finally, switch to the PLL. */
        rcc_switch_sysclk(RCC_CLKSRC_PLL);
    }