libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
scif.c
Go to the documentation of this file.
1/** @addtogroup scif
2 *
3 * @brief <b>Access functions for the SAM4 System Controf Interface (SCIF)</b>
4 * @ingroup SAM4
5 * LGPL License Terms @ref lgpl_license
6 * @author @htmlonly &copy; @endhtmlonly 2016
7 * Maxim Sloyko <maxims@google.com>
8 *
9 */
10
11/*
12 * This file is part of the libopencm3 project.
13 *
14 * This library is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this library. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#include <libopencm3/sam/scif.h>
29
30/** @brief Enable external oscillator.
31 *
32 * @param[in] mode enum osc_mode: Oscillator mode (which pins oscillator connected to).
33 * @param[in] freq uint32_t: External Oscillator frequency, in Hertz. Must be 0.6MHz - 30MHz
34 * @param[in] startup enum osc_startup: Oscillator start time in RCSYS clock cycles.
35 *
36 * @returns zero upon success.
37 */
38int scif_osc_enable(enum osc_mode mode, uint32_t freq, enum osc_startup startup)
39{
40 uint8_t gain;
41 const uint32_t kHz = 1000;
42 const uint32_t MHz = 1000 * kHz;
43
44 if (freq > 600 * kHz && freq <= 2 * MHz) {
45 gain = 0;
46 } else if (freq > 2 * MHz && freq <= 4 * MHz) {
47 gain = 1;
48 } else if (freq > 4 * MHz && freq <= 8 * MHz) {
49 gain = 2;
50 } else if (freq > 8 * MHz && freq <= 16 * MHz) {
51 gain = 3;
52 } else if (freq > 16 * MHz && freq <= 30 * MHz) {
53 gain = 4;
54 } else {
55 return -1;
56 }
57
61
62 while (!(SCIF_PCLKSR & SCIF_OSC0RDY));
63 return 0;
64}
65
66/** @brief Configure and enable PLL clock.
67 *
68 * @param[in] delay uint8_t: Specifies the number of RCSYS clock cycles before
69 * ISR.PLLLOCKn will be set after PLL has been written, or after PLL has
70 * been automatically re-enabled after exiting a sleep mode.
71 * @param[in] mul uint8_t: Multiply factor.
72 * @param[in] div uint8_t: Division factor.These fields determine the ratio of
73 * the PLL output frequency to the source oscillator frequency:
74 * f_vco = (PLLMUL+1)/PLLDIV * f_ref if PLLDIV >0
75 * f_vco = 2*(PLLMUL+1) * f_ref if PLLDIV = 0
76 * Note that the PLLMUL field should always be greater than 1 or the
77 * behavior of the PLL will be undefined.
78 * @param[in] pll_opt uint8_t: PLL Options.
79 *
80 * @returns zero upon success.
81 */
82int scif_enable_pll(uint8_t delay, uint8_t mul, uint8_t div, uint8_t pll_opt, enum pll_clk_src source_clock)
83{
84 // First, PLL needs to be disabled, otherwise the configuration register
85 // is unaccessible.
86 uint32_t pll_val = SCIF_PLL0;
87 if (pll_val & SCIF_PLL0_PLLEN) {
89 SCIF_PLL0 = pll_val & (~SCIF_PLL0_PLLEN);
90 }
91
92 if (mul == 0)
93 mul = 1;
94
95 pll_val = SCIF_PLL0_PLLOSC_MASKED(source_clock)
100
102 SCIF_PLL0 = pll_val;
103
104 // Now enable TODO: does this really need to be separate operation?
106 SCIF_PLL0 = pll_val | SCIF_PLL0_PLLEN;
107
108 while(!(SCIF_PCLKSR & SCIF_PLL0LOCK));
109
110 return 0;
111}
112
113/** @brief Configure and enable Generic Clock
114 *
115 * @param[in] gclk enum generic_clock: Generic Clock to configure and enable.
116 * @param[in] source_clock enum gclk_src: Source Clock for this Generic Clock.
117 * @param[in] div uint16_t: Division Factor. Upper 8 bits only used for Generic Clock 11,
118 * If 0, clock is undivided.
119 */
120void scif_enable_gclk(enum generic_clock gclk, enum gclk_src source_clock, uint16_t div)
121{
122 uint32_t reg_val = SCIF_GCCTRL_CEN | SCIF_GCCTRL_OSCSEL_MASKED(source_clock);
123 if (div) {
124 if (gclk < GENERIC_CLOCK11) {
125 div &= 0xf;
126 }
127
129 }
130
131 SCIF_GCTRL(gclk) = reg_val;
132}
#define SCIF_UNLOCK
Definition: 4l/scif.h:45
#define SCIF_PLL0_PLLEN
Definition: 4l/scif.h:195
#define SCIF_OSCCTRL_GAIN_SHIFT
Definition: 4l/scif.h:186
#define SCIF_OSCCTRL0_KEY
Definition: 4l/scif.h:53
#define SCIF_OSC0RDY
Definition: 4l/scif.h:175
#define SCIF_PLL0_PLLMUL_MASKED(V)
Definition: 4l/scif.h:210
#define SCIF_OSCCTRL0
Definition: 4l/scif.h:52
#define SCIF_GCTRL(N)
Definition: 4l/scif.h:140
osc_mode
Definition: 4l/scif.h:227
#define SCIF_PLL0_PLLDIV_MASKED(V)
Definition: 4l/scif.h:206
pll_clk_src
Definition: 4l/scif.h:250
#define SCIF_PLL0LOCK
Definition: 4l/scif.h:180
#define SCIF_GCCTRL_DIV_MASKED(V)
Definition: 4l/scif.h:224
generic_clock
Definition: 4l/scif.h:303
@ GENERIC_CLOCK11
Definition: 4l/scif.h:316
#define SCIF_GCCTRL_OSCSEL_MASKED(V)
Definition: 4l/scif.h:221
#define SCIF_PLL0_KEY
Definition: 4l/scif.h:57
#define SCIF_PLL0_PLLOPT_MASKED(V)
Definition: 4l/scif.h:202
#define SCIF_PLL0_PLLOSC_MASKED(V)
Definition: 4l/scif.h:198
#define SCIF_PLL0_PLLCOUNT_MASKED(V)
Definition: 4l/scif.h:214
#define SCIF_OSCCTRL_OSCEN
Definition: 4l/scif.h:191
#define SCIF_OSCCTRL_STARTUP_SHIFT
Definition: 4l/scif.h:189
#define SCIF_PCLKSR
Definition: 4l/scif.h:42
#define SCIF_GCCTRL_DIVEN
Definition: 4l/scif.h:218
#define SCIF_GCCTRL_CEN
Definition: 4l/scif.h:217
#define SCIF_PLL0
Definition: 4l/scif.h:56
gclk_src
Definition: 4l/scif.h:278
osc_startup
Definition: 4l/scif.h:232
int scif_osc_enable(enum osc_mode mode, uint32_t freq, enum osc_startup startup)
Enable external oscillator.
Definition: scif.c:38
void scif_enable_gclk(enum generic_clock gclk, enum gclk_src source_clock, uint16_t div)
Configure and enable Generic Clock.
Definition: scif.c:120
int scif_enable_pll(uint8_t delay, uint8_t mul, uint8_t div, uint8_t pll_opt, enum pll_clk_src source_clock)
Configure and enable PLL clock.
Definition: scif.c:82