diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 13:46:41 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 13:46:41 -0700 |
commit | 93b063fedfcf7409a67df035170ea5670cad22e1 (patch) | |
tree | a23321a7465d966b1ccf196ca00e65a70c9f9110 /src/arch | |
parent | b040195d31df6ad759f16ea3456471897f55daa1 (diff) | |
download | stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.gz stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.bz2 stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.zip |
Moved action to top level.
Removed old iterations of the project and moved the files from 02-usart
to the root directory since that's the sole place where the action is
and that subproject has outgrown its initial title.
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/stm32l4xxx/peripherals/clock.c | 117 | ||||
-rw-r--r-- | src/arch/stm32l4xxx/peripherals/irq.c | 96 | ||||
-rw-r--r-- | src/arch/stm32l4xxx/peripherals/usart.c | 152 |
3 files changed, 365 insertions, 0 deletions
diff --git a/src/arch/stm32l4xxx/peripherals/clock.c b/src/arch/stm32l4xxx/peripherals/clock.c new file mode 100644 index 0000000..9051572 --- /dev/null +++ b/src/arch/stm32l4xxx/peripherals/clock.c @@ -0,0 +1,117 @@ +/* + * This file sets the system clock to its full glory of 80Mhz + */ + +#include "arch/stm32l4xxx/peripherals/clock.h" +#include "arch/stm32l4xxx/peripherals/flash.h" + +#include "kern/init.h" + +#include <stdint.h> + +#define TIMEOUT 10000 + + +int pll_off() +{ + uint32_t c; + + RCC.c_r &= ~BIT(24); /* Turn off pll. */ + for (c = 0; c < TIMEOUT && RCC.c_r & BIT(25); ++c) + ; /* Wait for OFF. */ + + if (c == TIMEOUT) { + return E_TIMEOUT; + } + + return 0; +} + +int pll_on() +{ + uint32_t c; + + RCC.c_r |= BIT(24); /* Turn on PLL. */ + for (c = 0; c < TIMEOUT && !(RCC.c_r & BIT(25)); ++c) + ; /* Wait for RDY. */ + + if (c == TIMEOUT) { + return E_TIMEOUT; + } + + return 0; +} + +int configure_pll( + uint8_t pllp_div_factor, pll_divisor_t pllr, /* System clock divisor. */ + pll_divisor_t pllq, /* Divison factor for PLL48M1CLK. */ + pllp_divisor_t pllp, /* Divison factor for PLLSAI2CLK. */ + uint8_t plln, /* PLL numerator. */ + pllm_divisor_t pllm, /* PLL denominator. */ + pll_src_t pllsrc /* PLL source */) +{ + if (RCC.c_r & BIT(25)) { + /* PLL must be off to configure it. */ + return E_NOT_OFF; + } + + /* Make sure inputs are valid. */ + if (pllp_div_factor == 1 || pllp_div_factor > 31) { + return E_BADPLLP_DIV; + } + if (plln < 8 || plln > 86) { + return E_BADPLLN; + } + + RCC.pllcfg_r = (pllp_div_factor << 27) | (pllr << 24) | (pllq << 20) | + (pllp << 16) | (plln << 8) | (pllm << 4) | (pllsrc << 0); + + return 0; +} + +static _no_init uint8_t clock_mHz; +uint8_t get_clock_mhz() +{ + return clock_mHz; +} + +int set_system_clock_MHz(uint8_t mhz) +{ + clock_mHz = mhz; + + /* Set the source of the system colck to MSI temporarily. */ + set_system_clock_src(SYSTEM_CLOCK_SRC_MSI); + + if (mhz <= 8 || mhz > 80) { + return E_BAD_ARG; + } + + pll_off(); + + configure_pll( + 0 /* pllp_div_factor */, PLL_DIVISOR_4 /* pllr: VCO / 4 = mhz MHz. */, + PLL_DIVISOR_4 /* pllq: VCO / 4 = mhz MHz */, PLLP_DIVISOR_7 /* pllp */, + + /* The following set the frequency of VCO to (mhz*4)MHz: mhz * 1 * 4MHz. + */ + mhz /* plln | mhz */, PLLM_DIVISOR_1 /* pllm | 01 */, + PLL_SRC_MSI /* pll src | 04 Mhz */); + + pll_on(); + + /* Configure the flash to have 4 wait states. This is required at + * 80 MHz. */ + FLASH.ac_r &= ~0x07; + FLASH.ac_r |= 0x04; + + /* Set the source of the system colck to PLL. */ + set_system_clock_src(SYSTEM_CLOCK_SRC_PLL); + return 0; +} + +int set_system_clock_src(system_clock_src_t src) +{ + uint8_t value = RCC.cfg_r & ~0x03; + RCC.cfg_r = value | src; + return 0; +} diff --git a/src/arch/stm32l4xxx/peripherals/irq.c b/src/arch/stm32l4xxx/peripherals/irq.c new file mode 100644 index 0000000..364b9a7 --- /dev/null +++ b/src/arch/stm32l4xxx/peripherals/irq.c @@ -0,0 +1,96 @@ +#include "arch/stm32l4xxx/peripherals/irq.h" +#include "arch/stm32l4xxx/peripherals/gpio.h" +#include "arch/stm32l4xxx/peripherals/nvic.h" + +#include "arch.h" +#include "kern/delay.h" +#include "kern/gpio/gpio_manager.h" + +#define IRQ_RESERVED(n) +#define IRQ(name, uname_, n) \ + void WEAK name () { \ + unhandled_isr(n); \ + } +#include "arch/stm32l4xxx/peripherals/isrs.inc" +#undef IRQ_RESERVED +#undef IRQ + +void isr_simple_pin_on() +{ + int ec; + gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT; + gpio_reserved_pin_t pin3 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec); + + set_gpio_pin_high(pin3); +} + +#define IRQ_RESERVED(n) 0, +#define IRQ(name, uname_, n) name, +const void* vectors[] __attribute__((section(".vectors"))) = { + (void*)0x2000c000, /* Top of stack at top of sram1. 48k */ +#include "arch/stm32l4xxx/peripherals/isrs.inc" +}; +#undef IRQ_RESERVED +#undef IRQ + +/* Encodes the provided number as a series of flashes on the on-board + * LED. The flashes follow as such: + * + * Before the bits of the code are flashed, a rapid succession of 20 flashes + * followed by a pause will occur indicating that the next 8 flashes indicate + * the bits of the provided code. + * + * Eoch of the next eight flashes indicate either a 1 or 0 depending on the + * length of flash. The first flash is the least-significant bit, the next the + * second least, the third third least, etc. + * + * - A quick flash followed by a long pause indicates a 0 bit. + * - A "long" flash followed by a equally long pause indicates a 1 bit. + */ +void unhandled_isr(uint8_t number) +{ + int ec; + gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT; + gpio_reserved_pin_t pin3 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec); + + for (;;) { + for (int i = 0; i < 20; ++ i) { + set_gpio_pin_high(pin3); + delay(1000000); + set_gpio_pin_low(pin3); + delay(1000000); + } + delay(50000000); + + int n = number; + for (int i = 0; i < 8; ++ i) { + if (n & 1) { + // LSB is a 1 + set_gpio_pin_high(pin3); + delay(15000000); + set_gpio_pin_low(pin3); + delay(15000000); + } else { + // LSB is a 0 + set_gpio_pin_high(pin3); + delay(1000000); + set_gpio_pin_low(pin3); + delay(29000000); + } + + n >>= 1; + } + } +} + +void enable_interrupts(interrupt_set_t* interrupts) +{ + for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i) + NVIC.ise_r[i] = interrupts->irqs[i]; +} + +void disable_interrupts(interrupt_set_t* interrupts) +{ + for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i) + NVIC.ice_r[i] = interrupts->irqs[i]; +} diff --git a/src/arch/stm32l4xxx/peripherals/usart.c b/src/arch/stm32l4xxx/peripherals/usart.c new file mode 100644 index 0000000..7309b48 --- /dev/null +++ b/src/arch/stm32l4xxx/peripherals/usart.c @@ -0,0 +1,152 @@ +#include "arch/stm32l4xxx/peripherals/usart.h" +#include "kern/delay.h" +#include "kern/lib.h" +#include <stdarg.h> + +void set_usart1_clock_src(__IO rcc_t* rcc, usart_clk_src_t usart_clk_src) +{ + rcc->ccip_r = (rcc->ccip_r & (~0x03)) | usart_clk_src; +} + +void set_usart2_clock_src(__IO rcc_t* rcc, usart_clk_src_t usart_clk_src) +{ + rcc->ccip_r = (rcc->ccip_r & ~(0x03 << 2)) | (usart_clk_src << 2); +} + +void set_usart2_clock_enabled(__IO rcc_t* rcc, bool enable) +{ + if (enable) { + rcc->apb1en1_r |= BIT(17); + } else { + rcc->apb1en1_r &= ~BIT(17); + } +} + +void set_usart1_clock_enabled(__IO rcc_t* rcc, bool enable) +{ + if (enable) { + rcc->apb2en_r |= BIT(14); + } else { + rcc->apb2en_r &= ~BIT(14); + } +} + +void usart_set_parity(__IO usart_t* usart, usart_parity_t parity) +{ + uint32_t c_r1 = usart->c_r1; + c_r1 &= ~(0x3 << 9); + c_r1 |= parity; + usart->c_r1 = c_r1; +} + +void usart_set_enabled(__IO usart_t* usart, usart_enable_t enabled) +{ + if (!enabled) { + regset(usart->c_r1, usart_ue, 0); + } else { + /* Set the rx enabled. */ + regset(usart->c_r1, usart_re, !!(enabled & USART_ENABLE_RX)); + regset(usart->c_r1, usart_te, !!(enabled & USART_ENABLE_TX)); + regset(usart->c_r1, usart_ue, 1); + } +} + +void usart_transmit_byte_sync(__IO usart_t* usart, uint8_t byte) +{ + usart->td_r = byte; + /* Per the manual, when bit 7 of the IS register is set, then the usart + * data has been sent to the shift register. + * + * This bit is cleared by writing to the TD register. */ + while (!(usart->is_r & BIT(7))) + ; +} + +void usart_transmit_bytes_sync(__IO usart_t* usart, const uint8_t* bytes, uint32_t n) +{ + while (n --) { + usart_transmit_byte_sync(usart, *(bytes ++)); + } +} + +void usart_transmit_str_sync(__IO usart_t* usart, const char* str) +{ + while (*str) { + if (*str == '\n') { + usart_transmit_byte_sync(usart, '\r'); + } + usart_transmit_byte_sync(usart, *(str ++)); + } +} + +void usart_enable_dma(__IO usart_t* usart, usart_enable_t enabled) +{ + switch(enabled) { + case USART_ENABLE_DISABLED: + regset(usart->c_r3, usart_dmar, 0); + regset(usart->c_r3, usart_dmat, 0); + break; + + case USART_ENABLE_TX: + regset(usart->c_r3, usart_dmat, 1); + break; + + case USART_ENABLE_RX: + regset(usart->c_r3, usart_dmar, 1); + break; + }; +} + +void usart_vprintf(__IO usart_t* usart, const char* fmt, va_list l) +{ + union { + void* ptr; + char* str; + int i; + } b; + char buf[128]; + + while (*fmt != 0) { + if (*fmt == '%') { + switch (*(++fmt)) { + case 0: + goto end; + case '%': + usart_transmit_byte_sync(usart, '%'); + break; + case 'p': + b.ptr = va_arg(l, void*); + hexify(ptr2reg(b.ptr), buf); + usart_transmit_str_sync(usart, "0x"); + usart_transmit_str_sync(usart, buf); + break; + case 'd': + case 'i': + b.i = va_arg(l, int); + decimalify(b.i, buf); + usart_transmit_str_sync(usart, buf); + break; + case 's': + b.str = va_arg(l, char*); + usart_transmit_str_sync(usart, b.str); + } + ++ fmt; + } else { + if (*fmt == '\n') { + usart_transmit_byte_sync(usart, '\r'); + } + usart_transmit_byte_sync(usart, *(fmt ++)); + } + } + +end: + va_end(l); +} + +void usart_printf(__IO usart_t* usart, const char* fmt, ...) +{ + va_list l; + va_start(l, fmt); + + usart_vprintf(usart, fmt, l); +} |