aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/rcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple/rcc.c')
-rw-r--r--libmaple/rcc.c148
1 files changed, 106 insertions, 42 deletions
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index fbf9160..9bd2663 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -23,66 +23,73 @@
* ****************************************************************************/
/**
- * @file rcc.c
- *
* @brief Implements pretty much only the basic clock setup on the stm32,
- * exposes a handful of clock enable/disable and peripheral reset commands.
+ * clock enable/disable and peripheral reset commands.
*/
#include "libmaple.h"
#include "flash.h"
#include "rcc.h"
-#define RCC_CFGR_PPRE1 (0x7 << 8)
-#define RCC_CFGR_PPRE2 (0x7 << 11)
-#define RCC_CFGR_HPRE (0xF << 4)
-#define RCC_CFGR_PLLSRC (0x1 << 16)
-
-#define RCC_CFGR_SWS (0x3 << 2)
-#define RCC_CFGR_SWS_PLL (0x2 << 2)
-#define RCC_CFGR_SWS_HSE (0x1 << 2)
-
-#define RCC_CFGR_SW (0x3 << 0)
-#define RCC_CFGR_SW_PLL (0x2 << 0)
-#define RCC_CFGR_SW_HSE (0x1 << 0)
-
-/* CR status bits */
-#define RCC_CR_HSEON (0x1 << 16)
-#define RCC_CR_HSERDY (0x1 << 17)
-#define RCC_CR_PLLON (0x1 << 24)
-#define RCC_CR_PLLRDY (0x1 << 25)
+enum {
+ APB1,
+ APB2,
+ AHB
+};
-#define RCC_WRITE_CFGR(val) __write(RCC_CFGR, val)
-#define RCC_READ_CFGR() __read(RCC_CFGR)
+struct rcc_dev_info {
+ const uint8 clk_domain;
+ const uint8 line_num;
+};
-#define RCC_WRITE_CR(val) __write(RCC_CR, val)
-#define RCC_READ_CR() __read(RCC_CR)
+/* device descriptor tables */
+static const struct rcc_dev_info rcc_dev_table[] = {
+ [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 },
+ [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 },
+ [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 },
+ [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 },
+ [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, // High-density devices only
+ [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, // High-density devices only
+ [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, // High-density devices only
+ [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 },
+ [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 },
+ [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 },
+ [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
+ [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
+ [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
+ [RCC_USART4] = { .clk_domain = APB1, .line_num = 19 }, // High-density devices only
+ [RCC_USART5] = { .clk_domain = APB1, .line_num = 20 }, // High-density devices only
+ [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 },
+ [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 },
+ [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 },
+ [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 },
+ [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, // High-density devices only
+ [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, // High-density devices only
+ [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, // High-density devices only
+ [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, // High-density devices only
+ [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 },
+ [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 },
+ [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, // High-density devices only
+ [RCC_DAC] = { .clk_domain = APB1, .line_num = 9 }, // High-density devices only
+};
/**
- * @brief Initialize the clock control system. Sets up only the basics:
- * APB1 clock prescaler
- * APB2 clock prescaler
- * AHB clock prescaler
- * System clock source (Must be PLL)
- * PLL clock source (Must be high-speed external clock)
- * PLL Multiplier
- * @param dev initialization struct
- * @sideeffect Switches clock source to PLL, clock speed to HSE_CLK*PLLMUL
+ * @brief Initialize the clock control system. Initializes the system
+ * clock source to use the PLL driven by an external oscillator
+ * @param sysclk_src system clock source, must be PLL
+ * @param pll_src pll clock source, must be HSE
+ * @param pll_mul pll multiplier
*/
-void rcc_init(struct rcc_device *dev) {
+void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) {
/* Assume that we're going to clock the chip off the PLL, fed by
* the HSE */
- ASSERT(dev->sysclk_src == RCC_CLKSRC_PLL &&
- dev->pll_src == RCC_PLLSRC_HSE);
+ ASSERT(sysclk_src == RCC_CLKSRC_PLL &&
+ pll_src == RCC_PLLSRC_HSE);
uint32 cfgr = 0;
uint32 cr = RCC_READ_CR();
- cfgr = (dev->apb1_prescale |
- dev->apb2_prescale |
- dev->ahb_prescale |
- dev->pll_src |
- dev->pll_mul);
+ cfgr = (pll_src | pll_mul);
RCC_WRITE_CFGR(cfgr);
/* Turn on the HSE */
@@ -104,3 +111,60 @@ void rcc_init(struct rcc_device *dev) {
while ((RCC_READ_CFGR() & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
;
}
+
+
+
+/**
+ * @brief Turn on the clock line on a device
+ * @param dev_num device to turn on
+ */
+void rcc_clk_enable(uint32 dev_num) {
+ static const uint32 enable_regs[] = {
+ [APB1] = RCC_APB1ENR,
+ [APB2] = RCC_APB2ENR,
+ [AHB] = RCC_AHBENR,
+ };
+
+ uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+
+ __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+}
+
+
+/**
+ * @brief Set the divider on a device prescaler
+ * @param prescaler prescaler to set
+ * @param divider prescaler divider
+ */
+void rcc_set_prescaler(uint32 prescaler, uint32 divider) {
+ static const uint32 masks[] = {
+ [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
+ [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
+ [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
+ [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE,
+ [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE,
+ };
+
+ uint32 cfgr = RCC_READ_CFGR();
+
+ cfgr &= ~masks[prescaler];
+ cfgr |= divider;
+ RCC_WRITE_CFGR(cfgr);
+}
+
+
+/**
+ * @brief reset a device
+ * @param dev_num device to reset
+ */
+void rcc_reset_dev(uint32 dev_num) {
+ static const uint32 reset_regs[] = {
+ [APB1] = RCC_APB1RSTR,
+ [APB2] = RCC_APB2RSTR,
+ };
+
+ uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+
+ __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+ __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+}