libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
clk.c
Go to the documentation of this file.
1/** @defgroup clk_file Clock peripheral API
2 * @ingroup peripheral_apis
3 * @brief SWM050 Clock API.
4 * LGPL License Terms @ref lgpl_license
5 * @author @htmlonly © @endhtmlonly 2019
6 * Caleb Szalacinski <contact@skiboy.net>
7 */
8/*
9 * This file is part of the libopencm3 project.
10 *
11 * Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
12 *
13 * This library is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this library. If not, see <http://www.gnu.org/licenses/>.
25 */
26/**@{*/
29
30/*---------------------------------------------------------------------------*/
31/** @brief Setup and change the system clock multiplier and divider
32
33Change system clock speed and wait for the clock to stabilize. The clock only
34needs time to stabilize on the first invocation of this function. This should be
35run at startup if you want to have a stable clock before doing anything.
36
37@param[in] mhz Base clock speed @ref clk_speeds
38 The base clock speed, before the clock divider
39
40@param[in] div Clock divider
41 Takes values from 0 to 1023 (in reality the possible values are the even
42 numbers from 2 to 1022, as well as the number 1). Anything more than the
43 first 10 bits is stripped off of the value. If the value is 0, it will
44 be treated as a 1. All odd values other than 1 are rounded down to the
45 closest even value, due to the fact that all odd values are treated by
46 the register as a 1, which would likely be unexpected. A value of 0
47 would also normally be treated as a 2, which would also be unexpected
48 behavior.
49*/
50void clk_speed(enum clk_speeds mhz, uint16_t div)
51{
52 static bool first_run = true;
53
54 if (first_run) {
55 first_run = false;
57
58 for (uint16_t i = 0; i < 10000; ++i) {
59 __asm__("nop");
60 }
61
62 /* The speed doesn't need to be changed
63 a second time if the user wants 18Mhz. */
64 if ((mhz == CLK_18MHZ) && (div <= 1)) {
65 return;
66 }
67 if ((mhz == CLK_36MHZ) && (div == 2)) {
68 return;
69 }
70 }
71
72 if (mhz == CLK_36MHZ) {
74 } else {
75 SYSCTL_SYS_DBLF &= ~BIT0;
76 }
77
78 if (div <= 1) {
80 } else {
81 uint32_t masked_reg32 = SYSCTL_SYS_CFG_0 & CLK_MASK;
82 SYSCTL_SYS_CFG_0 = masked_reg32 | (div & ~(CLK_MASK | 0x1));
83 }
84}
85/**@}*/
#define BIT0
Definition: common.h:81
void clk_speed(enum clk_speeds mhz, uint16_t div)
Setup and change the system clock multiplier and divider.
Definition: clk.c:50
#define CLK_MASK
Definition: clk.h:45
clk_speeds
Definition: clk.h:36
@ CLK_18MHZ
Definition: clk.h:37
@ CLK_36MHZ
Definition: clk.h:38
#define SYSCTL_SYS_CFG_0
Clock dividers for TIMERSE and SCLK.
Definition: sysctl.h:46
#define SYSCTL_SYS_DBLF
SCLK multiplier (18Mhz and 36Mhz)
Definition: sysctl.h:50