diff options
author | Matt Baker <baker.matt.j@gmail.com> | 2021-04-22 13:44:39 -0700 |
---|---|---|
committer | KevinOConnor <kevin@koconnor.net> | 2022-09-15 11:51:26 -0400 |
commit | d9c917b95099617b32dfaca4ae90c9e2dd641fff (patch) | |
tree | a6a7adb3fec7d84a5fa0bbb75432a229b1ee7699 /src/stm32/stm32l4.c | |
parent | 57b0eb5d43e4324c2c52282925ddc63fc36df783 (diff) | |
download | kutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.tar.gz kutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.tar.xz kutter-d9c917b95099617b32dfaca4ae90c9e2dd641fff.zip |
stm32l4: add stm32l412 support with adc,i2c,spi,usb
Signed-off-by: Matt Baker <baker.matt.j@gmail.com>
Diffstat (limited to 'src/stm32/stm32l4.c')
-rw-r--r-- | src/stm32/stm32l4.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/stm32/stm32l4.c b/src/stm32/stm32l4.c new file mode 100644 index 00000000..8fb50a23 --- /dev/null +++ b/src/stm32/stm32l4.c @@ -0,0 +1,175 @@ +// Code to setup clocks and gpio on stm32l4 +// +// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ +#include "board/armcm_boot.h" // VectorTable +#include "board/irq.h" // irq_disable +#include "board/usb_cdc.h" // usb_request_bootloader +#include "command.h" // DECL_CONSTANT_STR +#include "internal.h" // enable_pclock +#include "sched.h" // sched_main + +#define FREQ_PERIPH_DIV 1 +#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / FREQ_PERIPH_DIV) + +// Map a peripheral address to its enable bits +struct cline +lookup_clock_line(uint32_t periph_base) +{ + if (periph_base < APB2PERIPH_BASE) { + uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; + if (pos < 32) { + return (struct cline){.en = &RCC->APB1ENR1, + .rst = &RCC->APB1RSTR1, + .bit = 1 << pos}; + } else { + return (struct cline){.en = &RCC->APB1ENR2, + .rst = &RCC->APB1RSTR2, + .bit = 1 << (pos - 32)}; + } + } else if (periph_base < AHB1PERIPH_BASE) { + uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; + return (struct cline){.en = &RCC->APB2ENR, + .rst = &RCC->APB2RSTR, + .bit = 1 << pos}; + + } else if (periph_base < AHB2PERIPH_BASE) { + uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400; + return (struct cline){.en = &RCC->AHB1ENR, + .rst = &RCC->AHB1RSTR, + .bit = 1 << pos}; + + } else if (periph_base == ADC1_BASE) { + return (struct cline){.en = &RCC->AHB2ENR, + .rst = &RCC->AHB2RSTR, + .bit = RCC_AHB2ENR_ADCEN}; + } + return (struct cline){.en = &RCC->AHB2ENR, + .rst = &RCC->AHB2RSTR, + .bit = 0}; +} + +// Return the frequency of the given peripheral clock +uint32_t +get_pclock_frequency(uint32_t periph_base) +{ + return FREQ_PERIPH; +} + +// Enable a GPIO peripheral clock +void +gpio_clock_enable(GPIO_TypeDef *regs) +{ + uint32_t rcc_pos = ((uint32_t)regs - GPIOA_BASE) / 0x400; + RCC->AHB2ENR |= 1 << rcc_pos; + RCC->AHB2ENR; +} + +#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096) +#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" + +// Handle USB reboot requests +void +usb_request_bootloader(void) +{ + irq_disable(); + // System DFU Bootloader + *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; + NVIC_SystemReset(); +} + +void +bootloader_request(void) +{ + usb_request_bootloader(); +} + +#if !CONFIG_STM32_CLOCK_REF_INTERNAL +DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PC14,PC15"); +#endif + +static void +enable_clock_stm32l4(void) +{ + uint32_t pll_base = 4000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr; + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure 80Mhz PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base - 1; + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR & RCC_CR_HSERDY)) + ; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSE | (div << RCC_PLLCFGR_PLLM_Pos); + } else { + // Configure 80Mhz PLL from internal 16Mhz oscillator (HSI) + uint32_t div = 16000000 / pll_base - 1; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos); + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) + ; + } + RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos) + | (0 << RCC_PLLCFGR_PLLR_Pos)); + RCC->CR |= RCC_CR_PLLON; + + // Enable 48Mhz USB clock using clock recovery + if (CONFIG_USBSERIAL) { + RCC->CRRCR |= RCC_CRRCR_HSI48ON; + while (!(RCC->CRRCR & RCC_CRRCR_HSI48RDY)) + ; + enable_pclock(CRS_BASE); + CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN; + enable_pclock(PWR_BASE); + PWR->CR2 |= PWR_CR2_USV; + } +} + +// Main clock setup called at chip startup +static void +clock_setup(void) +{ + enable_clock_stm32l4(); + + // Set flash latency + uint32_t latency = ((CONFIG_CLOCK_FREQ>64000000) ? FLASH_ACR_LATENCY_4WS : + ((CONFIG_CLOCK_FREQ>48000000) ? FLASH_ACR_LATENCY_3WS : + ((CONFIG_CLOCK_FREQ>32000000) ? FLASH_ACR_LATENCY_2WS : + ((CONFIG_CLOCK_FREQ>16000000) ? FLASH_ACR_LATENCY_1WS : + FLASH_ACR_LATENCY_0WS)))); + FLASH->ACR = (latency | FLASH_ACR_ICEN | FLASH_ACR_DCEN + | FLASH_ACR_PRFTEN); + + // Wait for PLL lock + while (!(RCC->CR & RCC_CR_PLLRDY)) + ; + + RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN; + + // Switch system clock to PLL + RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV1 | RCC_CFGR_PPRE2_DIV1 + | RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) + ; +} + +// Main entry point - called from armcm_boot.c:ResetHandler() +void +armcm_main(void) +{ + if (CONFIG_USBSERIAL && *(uint64_t*)USB_BOOT_FLAG_ADDR == USB_BOOT_FLAG) { + *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; + uint32_t *sysbase = (uint32_t*)0x1fff0000; + asm volatile("mov sp, %0\n bx %1" + : : "r"(sysbase[0]), "r"(sysbase[1])); + } + + // Run SystemInit() and then restore VTOR + SystemInit(); + SCB->VTOR = (uint32_t)VectorTable; + + clock_setup(); + + sched_main(); +} |