From 9f28e53c71d28d04e2775c59944d2887a99f1e86 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sun, 22 Nov 2020 01:06:30 -0700 Subject: Large reorganization. What was in core/ is now moved to arch/stm34l4xxx/peripherals. This new directory is *supposed to* to contain raw header files defining just the pertinent register structures for the various peripherals. Peripheral management belongs somewhere in the new `kern/..` directories. This is not completely the case at the moment, so more refactoring needs to be done. What was sitting in the root has now been moved into the kern/ directory. The kern/ directory is to contain everything else other than raw device register definitions. The root of the kern/ tree is reserved for standard library-esque headers. The kern/ directory contains management systems for that peripheral. (At the moment DMA is the only peripheral with a decent management system.) Preferably these peripheral systems should only include their correlating header in arch/stm34l4xxx/peripherals, and use other management systems for handling other peripherals rather than manipulating their raw registers directly. (Though this ideal will require much more critical mass of management systems.) --- 02-usart/src/arch/stm32l4xxx/peripherals/clock.c | 107 ++++++++ 02-usart/src/arch/stm32l4xxx/peripherals/gpio.c | 52 ++++ 02-usart/src/arch/stm32l4xxx/peripherals/init.c | 49 ++++ 02-usart/src/arch/stm32l4xxx/peripherals/irq.c | 92 +++++++ 02-usart/src/arch/stm32l4xxx/peripherals/usart.c | 147 +++++++++++ 02-usart/src/core/clock.c | 107 -------- 02-usart/src/core/gpio.c | 52 ---- 02-usart/src/core/init.c | 49 ---- 02-usart/src/core/irq.c | 92 ------- 02-usart/src/core/usart.c | 147 ----------- 02-usart/src/delay.c | 9 - 02-usart/src/kern/delay.c | 9 + 02-usart/src/kern/dma/dma_manager.c | 312 +++++++++++++++++++++++ 02-usart/src/kern/lib.c | 56 ++++ 02-usart/src/kern/main.c | 117 +++++++++ 02-usart/src/kern/mem.c | 206 +++++++++++++++ 02-usart/src/kern/spin.c | 49 ++++ 02-usart/src/kern/stdlibrepl.c | 13 + 02-usart/src/kern/string.c | 9 + 02-usart/src/kern/vector.c | 0 02-usart/src/lib.c | 56 ---- 02-usart/src/main.c | 115 --------- 02-usart/src/mem.c | 206 --------------- 02-usart/src/peri/dma.c | 312 ----------------------- 02-usart/src/spin.c | 49 ---- 02-usart/src/stdlibrepl.c | 13 - 02-usart/src/vector.c | 0 27 files changed, 1218 insertions(+), 1207 deletions(-) create mode 100644 02-usart/src/arch/stm32l4xxx/peripherals/clock.c create mode 100644 02-usart/src/arch/stm32l4xxx/peripherals/gpio.c create mode 100644 02-usart/src/arch/stm32l4xxx/peripherals/init.c create mode 100644 02-usart/src/arch/stm32l4xxx/peripherals/irq.c create mode 100644 02-usart/src/arch/stm32l4xxx/peripherals/usart.c delete mode 100644 02-usart/src/core/clock.c delete mode 100644 02-usart/src/core/gpio.c delete mode 100644 02-usart/src/core/init.c delete mode 100644 02-usart/src/core/irq.c delete mode 100644 02-usart/src/core/usart.c delete mode 100644 02-usart/src/delay.c create mode 100644 02-usart/src/kern/delay.c create mode 100644 02-usart/src/kern/dma/dma_manager.c create mode 100644 02-usart/src/kern/lib.c create mode 100644 02-usart/src/kern/main.c create mode 100644 02-usart/src/kern/mem.c create mode 100644 02-usart/src/kern/spin.c create mode 100644 02-usart/src/kern/stdlibrepl.c create mode 100644 02-usart/src/kern/string.c create mode 100644 02-usart/src/kern/vector.c delete mode 100644 02-usart/src/lib.c delete mode 100644 02-usart/src/main.c delete mode 100644 02-usart/src/mem.c delete mode 100644 02-usart/src/peri/dma.c delete mode 100644 02-usart/src/spin.c delete mode 100644 02-usart/src/stdlibrepl.c delete mode 100644 02-usart/src/vector.c (limited to '02-usart/src') diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c new file mode 100644 index 0000000..ba127a9 --- /dev/null +++ b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c @@ -0,0 +1,107 @@ +/* + * 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 +#include "kern/spin.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; +} + +int set_system_clock_MHz(uint8_t 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/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c b/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c new file mode 100644 index 0000000..a1e82c7 --- /dev/null +++ b/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c @@ -0,0 +1,52 @@ +#include "arch/stm32l4xxx/peripherals/gpio.h" +#include "arch/stm32l4xxx/peripherals/rcc.h" + +/* + * Sets the mode of a pin on a gpio por. + */ +void set_gpio_pin_mode( + __IO gpio_port_t* gpio_port, gpio_pin_t pin, gpio_pin_mode_t mode) +{ + /* Each pin has a 2-bit mode provided at bits pin#*2 and pin#*2+1 */ + gpio_port->mode_r &= ~(0x03 << pin * 2); + gpio_port->mode_r |= mode << pin * 2; +} + +gpio_output_pin_t set_gpio_pin_output( + __IO gpio_port_t* gpio_port, gpio_pin_t pin) +{ + set_gpio_pin_mode(gpio_port, pin, MODE_OUTPUT); + + return (gpio_output_pin_t){.gpio_port = gpio_port, .pin = pin}; +} + +void set_gpio_output_pin(gpio_output_pin_t pin, bool onoff) +{ + if (onoff) { + pin.gpio_port->output_r |= 1 << pin.pin; + } else { + pin.gpio_port->output_r &= ~(1 << pin.pin); + } +} + +void set_gpio_alternate_function( + __IO gpio_port_t* port, gpio_pin_t gpio_pin, alternate_function_t afn) +{ + __IO uint32_t* reg; + if (gpio_pin < 8) { + reg = &(port->af_rl); + } else { + reg = &(port->af_rh); + gpio_pin -= 8; + } + + uint32_t tmp = *reg & (~0x0f << gpio_pin * 4); + *reg = tmp | (afn << gpio_pin * 4); +} + +#define GPIO_PORTS_BASE_ADDR ((uint8_t*)0x48000000) +__IO gpio_port_t* enable_gpio(gpio_port_number_t gpio_port_number) +{ + RCC.ahb2en_r |= 1 << gpio_port_number; /* Enable the GPIO port. */ + return (__IO gpio_port_t*)(GPIO_PORTS_BASE_ADDR + (gpio_port_number * 0x400)); +} diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/init.c b/02-usart/src/arch/stm32l4xxx/peripherals/init.c new file mode 100644 index 0000000..47bfaa5 --- /dev/null +++ b/02-usart/src/arch/stm32l4xxx/peripherals/init.c @@ -0,0 +1,49 @@ +#include "arch.h" +#include "arch/stm32l4xxx/peripherals/system.h" + +/* Forward-declare the main function. This is implemented in main.c. */ +void main(); + +/* These are defined in the linker script. */ + +#ifdef ARCH_STM32L4 +extern uint32_t INIT_DATA_VALUES; +extern uint32_t DATA_SEGMENT_START; +extern uint32_t DATA_SEGMENT_STOP; +extern uint32_t BSS_START; +extern uint32_t BSS_END; + +/* + * Runs before main. Initializes the data and bss segments by loading them + * into memory. + */ +_Noreturn void on_reset() +{ + uint32_t* src; + uint32_t* dest; + + src = &INIT_DATA_VALUES; + dest = &DATA_SEGMENT_START; + + /* Copy the values from flash into the data segment. */ + while (dest != &DATA_SEGMENT_STOP) { + *(dest++) = *(src++); + } + + /* Everything in the BSS segment is set to zero. */ + dest = &BSS_START; + while (dest != &BSS_END) { + *(dest++) = 0; + } + + /* Set the vector offset table to be at the start + * of FLASH memory. */ + SCB.vto_r = 0x08000000; + + /* Jump to main. */ + main(); + + for(;;); +} + +#endif /* ARCH_STM32L4 */ diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/irq.c b/02-usart/src/arch/stm32l4xxx/peripherals/irq.c new file mode 100644 index 0000000..8fb3e49 --- /dev/null +++ b/02-usart/src/arch/stm32l4xxx/peripherals/irq.c @@ -0,0 +1,92 @@ +#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" + +#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() +{ + __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); + gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); + + pin_on(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) +{ + __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); + gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); + for (;;) { + for (int i = 0; i < 20; ++ i) { + pin_on(pin3); + delay(1000000); + pin_off(pin3); + delay(1000000); + } + delay(50000000); + + int n = number; + for (int i = 0; i < 8; ++ i) { + if (n & 1) { + // LSB is a 1 + pin_on(pin3); + delay(15000000); + pin_off(pin3); + delay(15000000); + } else { + // LSB is a 0 + pin_on(pin3); + delay(1000000); + pin_off(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/02-usart/src/arch/stm32l4xxx/peripherals/usart.c b/02-usart/src/arch/stm32l4xxx/peripherals/usart.c new file mode 100644 index 0000000..d37eee2 --- /dev/null +++ b/02-usart/src/arch/stm32l4xxx/peripherals/usart.c @@ -0,0 +1,147 @@ +#include "arch/stm32l4xxx/peripherals/usart.h" +#include "kern/delay.h" +#include "kern/lib.h" +#include + +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_printf(__IO usart_t* usart, const char* fmt, ...) +{ + va_list l; + union { + void* ptr; + char* str; + int i; + } b; + char buf[128]; + + va_start(l, fmt); + + 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); +} diff --git a/02-usart/src/core/clock.c b/02-usart/src/core/clock.c deleted file mode 100644 index f32cb4e..0000000 --- a/02-usart/src/core/clock.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file sets the system clock to its full glory of 80Mhz - */ - -#include "core/clock.h" -#include "core/flash.h" - -#include -#include "spin.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; -} - -int set_system_clock_MHz(uint8_t 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/02-usart/src/core/gpio.c b/02-usart/src/core/gpio.c deleted file mode 100644 index c46b1ff..0000000 --- a/02-usart/src/core/gpio.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "core/gpio.h" -#include "core/rcc.h" - -/* - * Sets the mode of a pin on a gpio por. - */ -void set_gpio_pin_mode( - __IO gpio_port_t* gpio_port, gpio_pin_t pin, gpio_pin_mode_t mode) -{ - /* Each pin has a 2-bit mode provided at bits pin#*2 and pin#*2+1 */ - gpio_port->mode_r &= ~(0x03 << pin * 2); - gpio_port->mode_r |= mode << pin * 2; -} - -gpio_output_pin_t set_gpio_pin_output( - __IO gpio_port_t* gpio_port, gpio_pin_t pin) -{ - set_gpio_pin_mode(gpio_port, pin, MODE_OUTPUT); - - return (gpio_output_pin_t){.gpio_port = gpio_port, .pin = pin}; -} - -void set_gpio_output_pin(gpio_output_pin_t pin, bool onoff) -{ - if (onoff) { - pin.gpio_port->output_r |= 1 << pin.pin; - } else { - pin.gpio_port->output_r &= ~(1 << pin.pin); - } -} - -void set_gpio_alternate_function( - __IO gpio_port_t* port, gpio_pin_t gpio_pin, alternate_function_t afn) -{ - __IO uint32_t* reg; - if (gpio_pin < 8) { - reg = &(port->af_rl); - } else { - reg = &(port->af_rh); - gpio_pin -= 8; - } - - uint32_t tmp = *reg & (~0x0f << gpio_pin * 4); - *reg = tmp | (afn << gpio_pin * 4); -} - -#define GPIO_PORTS_BASE_ADDR ((uint8_t*)0x48000000) -__IO gpio_port_t* enable_gpio(gpio_port_number_t gpio_port_number) -{ - RCC.ahb2en_r |= 1 << gpio_port_number; /* Enable the GPIO port. */ - return (__IO gpio_port_t*)(GPIO_PORTS_BASE_ADDR + (gpio_port_number * 0x400)); -} diff --git a/02-usart/src/core/init.c b/02-usart/src/core/init.c deleted file mode 100644 index 0a7cb7f..0000000 --- a/02-usart/src/core/init.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "arch.h" -#include "core/system.h" - -/* Forward-declare the main function. This is implemented in main.c. */ -void main(); - -/* These are defined in the linker script. */ - -#ifdef ARCH_STM32L4 -extern uint32_t INIT_DATA_VALUES; -extern uint32_t DATA_SEGMENT_START; -extern uint32_t DATA_SEGMENT_STOP; -extern uint32_t BSS_START; -extern uint32_t BSS_END; - -/* - * Runs before main. Initializes the data and bss segments by loading them - * into memory. - */ -_Noreturn void on_reset() -{ - uint32_t* src; - uint32_t* dest; - - src = &INIT_DATA_VALUES; - dest = &DATA_SEGMENT_START; - - /* Copy the values from flash into the data segment. */ - while (dest != &DATA_SEGMENT_STOP) { - *(dest++) = *(src++); - } - - /* Everything in the BSS segment is set to zero. */ - dest = &BSS_START; - while (dest != &BSS_END) { - *(dest++) = 0; - } - - /* Set the vector offset table to be at the start - * of FLASH memory. */ - SCB.vto_r = 0x08000000; - - /* Jump to main. */ - main(); - - for(;;); -} - -#endif /* ARCH_STM32L4 */ diff --git a/02-usart/src/core/irq.c b/02-usart/src/core/irq.c deleted file mode 100644 index 47ad924..0000000 --- a/02-usart/src/core/irq.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "core/irq.h" -#include "core/gpio.h" -#include "core/nvic.h" - -#include "arch.h" -#include "delay.h" - -#define IRQ_RESERVED(n) -#define IRQ(name, uname_, n) \ - void WEAK name () { \ - unhandled_isr(n); \ - } -#include "core/isrs.inc" -#undef IRQ_RESERVED -#undef IRQ - -void isr_simple_pin_on() -{ - __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); - gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); - - pin_on(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 "core/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) -{ - __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); - gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); - for (;;) { - for (int i = 0; i < 20; ++ i) { - pin_on(pin3); - delay(1000000); - pin_off(pin3); - delay(1000000); - } - delay(50000000); - - int n = number; - for (int i = 0; i < 8; ++ i) { - if (n & 1) { - // LSB is a 1 - pin_on(pin3); - delay(15000000); - pin_off(pin3); - delay(15000000); - } else { - // LSB is a 0 - pin_on(pin3); - delay(1000000); - pin_off(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/02-usart/src/core/usart.c b/02-usart/src/core/usart.c deleted file mode 100644 index 19d982e..0000000 --- a/02-usart/src/core/usart.c +++ /dev/null @@ -1,147 +0,0 @@ -#include "core/usart.h" -#include "delay.h" -#include "lib.h" -#include - -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_printf(__IO usart_t* usart, const char* fmt, ...) -{ - va_list l; - union { - void* ptr; - char* str; - int i; - } b; - char buf[128]; - - va_start(l, fmt); - - 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); -} diff --git a/02-usart/src/delay.c b/02-usart/src/delay.c deleted file mode 100644 index 2a16d47..0000000 --- a/02-usart/src/delay.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "delay.h" - -void delay(uint32_t delay) -{ - while (delay--) { - /* needed to keep the compiler from optimizing away the loop. */ - asm volatile(""); - } -} diff --git a/02-usart/src/kern/delay.c b/02-usart/src/kern/delay.c new file mode 100644 index 0000000..28ef710 --- /dev/null +++ b/02-usart/src/kern/delay.c @@ -0,0 +1,9 @@ +#include "kern/delay.h" + +void delay(uint32_t delay) +{ + while (delay--) { + /* needed to keep the compiler from optimizing away the loop. */ + asm volatile(""); + } +} diff --git a/02-usart/src/kern/dma/dma_manager.c b/02-usart/src/kern/dma/dma_manager.c new file mode 100644 index 0000000..4336496 --- /dev/null +++ b/02-usart/src/kern/dma/dma_manager.c @@ -0,0 +1,312 @@ +#include "kern/dma/dma_manager.h" +#include "arch/stm32l4xxx/peripherals/dma.h" +#include "arch/stm32l4xxx/peripherals/usart.h" +#include "arch/stm32l4xxx/peripherals/rcc.h" + + +/* Bitmask of DMA2 channels in use. */ +static uint8_t dma_inuse[2]; + +static inline dma_t* get_dma(int dma) +{ + if (dma) { + return &DMA2; + } else { + return &DMA1; + } +} + +static dma_t* get_raw_dma(dma_channel_t chan) +{ + return get_dma(chan.dma); +} + +static dma_channel_config_t* get_raw_channel_config(dma_channel_t chan) +{ + dma_t* dma = get_raw_dma(chan); + return &dma->channel_config[chan.chan]; +} + +static uint32_t get_periph_location(dma_peripheral_t operipheral) +{ +#define CASE(p, n) case p: return ptr2reg(n); + switch (operipheral) { + CASE(DMA1_PERIPH_USART1_RX, &USART1.rd_r) + CASE(DMA1_PERIPH_USART1_TX, &USART1.td_r) + CASE(DMA1_PERIPH_USART2_RX, &USART2.rd_r) + CASE(DMA1_PERIPH_USART2_TX, &USART2.td_r) + + default: + return 0; + }; +#undef CASE +} + +static dma_channel_t allocate_dma_channel( + dma_peripheral_t operipheral, int* modesel) +{ + dma_peripheral_t peripheral = operipheral & 0xff; + int dmasel = peripheral >= DMA2_DMA1_SWITCH__; + if (dmasel) { + peripheral -= DMA2_DMA1_SWITCH__; + } + int chan = peripheral % DMA_N_CHANNELS; + + *modesel = peripheral / 7; + return (dma_channel_t) { + .dma = dmasel, + .chan = chan + }; +} + +/* + * Atomically reserves the DMA channel so other calls + * cannot erroneously reserve the same DMA channel. + * + * Returns 0 if this function was unable to reserve + * the channel. + */ +static int try_reserve_dma_channel( + dma_channel_t chan) +{ + int in_use = __sync_fetch_and_or( + &dma_inuse[chan.dma], 1 << chan.chan); + + return !(in_use & (1 << chan.chan)); +} + + // int in_use = __sync_fetch_and_or(&dma_inuse[dmasel], 1 << chan); +void release_dma_channel(dma_channel_t chan) +{ + dma_channel_config_t* config = get_raw_channel_config(chan); + regset(config->cc_r, dma_cc_en, 0); /* Disable the register. */ + dma_inuse[chan.dma] &= ~(1 << chan.chan); /* Release the DMA. */ + + if (!dma_inuse[chan.dma]) { + /* Power-down the DMA if not in use. */ + if (chan.dma) { + regset(RCC.ahb1en_r, rcc_dma2en, 0); + } else { + regset(RCC.ahb1en_r, rcc_dma1en, 0); + } + } +} + +void configure_dma_channel( + dma_channel_t chan, + dma_peripheral_t operipheral, + dma_opts_t* opts, + dma_dir_t dir, + int selmode, + bool mem2mem, + int* error_out) +{ + if (chan.dma) { + regset(RCC.ahb1en_r, rcc_dma2en, 1); + } else { + regset(RCC.ahb1en_r, rcc_dma1en, 1); + } + + dma_t* dma = get_raw_dma(chan); + regset(dma->csel_r, 0xF << (4 * chan.chan), selmode); + dma_channel_config_t* config = + &dma->channel_config[chan.chan]; + + uint32_t reg = 0; + + regset(reg, dma_cc_dir, dir); + regset(reg, dma_cc_tcie, opts->transfer_complete_interrupt_enable); + regset(reg, dma_cc_htie, opts->half_transfer_interrupt_enable); + regset(reg, dma_cc_teie, opts->transfer_error_interrupt_enable); + regset(reg, dma_cc_circ, opts->circular_mode); + regset(reg, dma_cc_pinc, opts->peripheral_increment); + regset(reg, dma_cc_minc, opts->memory_increment); + regset(reg, dma_cc_psize, opts->peripheral_block_size); + regset(reg, dma_cc_msize, opts->memory_block_size); + regset(reg, dma_cc_pl, opts->priority); + regset(reg, dma_cc_mem2mem, mem2mem); + + config->cc_r = reg; + config->cpa_r = get_periph_location(operipheral); + + *error_out = 0; +} + +dma_mem2mem_channel_t select_dma_channel_mem2mem( + int channel, + dma_opts_t* opts, + int* error_out) +{ + +#define WRAP(c) ((dma_mem2mem_channel_t) { .c_ = c }) + // TODO this should probably be in a critical section. + dma_channel_t chan; + if (channel == -1) { + chan.dma = 1; + if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) { + chan.dma = 0; + } + + if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) { + *error_out = DMA_ERROR_CHANNEL_IN_USE; + return WRAP(DMA_CHAN_ERROR); + } + + uint8_t t = ~(dma_inuse[chan.dma] << 1); + chan.chan = 6 - (__builtin_clz(t) - 24); + } else { + if (channel < 7) { + chan.dma = 0; + chan.chan = channel; + } else { + chan.dma = 0; + chan.chan = channel - 7; + } + } + + if (!try_reserve_dma_channel(chan)) { + *error_out = DMA_ERROR_CHANNEL_IN_USE; + return WRAP(DMA_CHAN_ERROR); + } + + int ec = 0; + configure_dma_channel( + chan, + -1 /* No peripheral */, + opts, + READ_FROM_PERIPHERAL, + /* selmode = */ 0x8, + /* mem2mem = */ true, + &ec); + + if (ec) { + *error_out = ec; + return WRAP(DMA_CHAN_ERROR); + } + + *error_out = 0; + return WRAP(chan); +#undef WRAP +} + +dma_mem2p_channel_t select_dma_channel_mem2p( + dma_peripheral_t peripheral, + dma_opts_t* opts_in, + int* error_out) +{ +#define WRAP(c) ((dma_mem2p_channel_t) { .c_ = c }) + *error_out = 0; + + int modesel; + dma_channel_t ret = + allocate_dma_channel(peripheral, &modesel); + + if (!try_reserve_dma_channel(ret)) { + *error_out = DMA_ERROR_CHANNEL_IN_USE; + return WRAP(DMA_CHAN_ERROR); + } + + configure_dma_channel( + ret, + peripheral, + opts_in, + READ_FROM_MEMORY, + modesel, + /* mem2mem = */ false, + error_out); + + if (*error_out) { + return WRAP(DMA_CHAN_ERROR); + } + + *error_out = 0; + return WRAP(ret); +#undef WRAP +} + +dma_p2mem_channel_t select_dma_channel_p2mem( + dma_peripheral_t peripheral, + dma_opts_t* opts_in, + int* error_out) +{ +#define WRAP(c) ((dma_p2mem_channel_t) { .c_ = c }) + *error_out = 0; + + int modesel; + dma_channel_t ret = + allocate_dma_channel(peripheral, &modesel); + + if (!try_reserve_dma_channel(ret)) { + *error_out = DMA_ERROR_CHANNEL_IN_USE; + return WRAP(DMA_CHAN_ERROR); + } + + configure_dma_channel( + ret, + peripheral, + opts_in, + READ_FROM_PERIPHERAL, + modesel, + /* mem2mem = */ false, + error_out); + + if (*error_out) { + return WRAP(DMA_CHAN_ERROR); + } + + *error_out = 0; + return WRAP(ret); +#undef WRAP +} + + +void dma_mem2p_initiate_transfer( + dma_mem2p_channel_t chan, const void* from_loc, uint16_t nblocks) +{ + dma_channel_config_t* config = get_raw_channel_config(chan.c_); + config->cma_r = ptr2reg(from_loc); + config->cndt_r = nblocks; + + regset(config->cc_r, dma_cc_en, 1); +} + +void dma_mem2mem_initiate_transfer( + dma_mem2mem_channel_t chan, + void* to_loc, + const void* from_loc, + uint16_t nblocks) +{ + dma_channel_config_t* config = get_raw_channel_config(chan.c_); + config->cma_r = ptr2reg(to_loc); + config->cpa_r = ptr2reg(from_loc); + config->cndt_r = nblocks; + + regset(config->cc_r, dma_cc_en, 1); +} + +void dma_p2mem_initiate_transfer( + dma_p2mem_channel_t chan, void* to_loc, uint16_t nblocks) +{ + dma_channel_config_t* config = get_raw_channel_config(chan.c_); + + config->cma_r = ptr2reg(to_loc); + config->cndt_r = nblocks; + + regset(config->cc_r, dma_cc_en, 1); +} + +interrupt_t dma_channel_get_interrupt(dma_channel_t chan) +{ + if (chan.dma == 0) { + return IRQ_DMA1_CHANNEL1_IRQ + chan.chan; + } else { + switch (chan.chan) { + case 5: + return IRQ_DMA1_CHANNEL6_IRQ; + case 6: + return IRQ_DMA1_CHANNEL7_IRQ; + default: + return IRQ_DMA2_CHANNEL1_IRQ + chan.chan; + } + } +} diff --git a/02-usart/src/kern/lib.c b/02-usart/src/kern/lib.c new file mode 100644 index 0000000..88188cc --- /dev/null +++ b/02-usart/src/kern/lib.c @@ -0,0 +1,56 @@ +#include "kern/lib.h" + +#define nybble_to_hex(n) \ + ((n) < 10 ? 0x30 + (n) : ('A' + ((n) - 10))) + +void hexify(uint32_t v, char* into) +{ + into += 8; + + *(into--) = 0; + + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *(into--) = nybble_to_hex(v & 0x0F); + v >>= 4; + *into = nybble_to_hex(v & 0x0F); + v >>= 4; +} + +void decimalify(int v, char* into) +{ + int c = 0; + int i; + + if (v == 0) { + *(into ++) = '0'; + *into = 0; + return; + } else { + while (v > 0) { + *(into ++) = 0x30 + (v % 10); + v /= 10; + ++ c; + } + } + *into = 0; + + into -= c; + for (i = 0; i < c / 2; ++ i) { + char tmp = into[i]; + into[i] = into[c - i - 1]; + into[c - i - 1] = tmp; + } + +} diff --git a/02-usart/src/kern/main.c b/02-usart/src/kern/main.c new file mode 100644 index 0000000..0e0c89c --- /dev/null +++ b/02-usart/src/kern/main.c @@ -0,0 +1,117 @@ + +#include "arch.h" + +#include "arch/stm32l4xxx/peripherals/clock.h" +#include "arch/stm32l4xxx/peripherals/dma.h" +#include "arch/stm32l4xxx/peripherals/gpio.h" +#include "arch/stm32l4xxx/peripherals/system.h" +#include "arch/stm32l4xxx/peripherals/usart.h" +#include "arch/stm32l4xxx/peripherals/nvic.h" +#include "arch/stm32l4xxx/peripherals/irq.h" + +#include "kern/dma/dma_manager.h" + +#include "kern/delay.h" +#include "kern/mem.h" +#include "kern/spin.h" +#include "kern/string.h" + +/** Overrides the default systick irq handler. */ +void on_systick() +{ + static int is_on = 0; + + __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); + gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); + + if (is_on) { + pin_off(pin3); + } else { + pin_on(pin3); + } + + is_on = ! is_on; +} + +void setup_usart2(uint32_t baud_rate) +{ + __IO gpio_port_t* port_a = enable_gpio(GPIO_PORT_A); + enable_hsi(&RCC, true); + + set_usart2_clock_src(&RCC, USART_CLK_SRC_HSI16); + set_usart2_clock_enabled(&RCC, USART_CLK_SRC_HSI16); + + set_gpio_pin_mode(port_a, PIN_2, MODE_ALTERNATE); + set_gpio_pin_mode(port_a, PIN_15, MODE_ALTERNATE); + set_gpio_alternate_function(port_a, PIN_2, AFN_7); + set_gpio_alternate_function(port_a, PIN_15, AFN_3); + + /* De-assert reset of USART2 */ + regset(RCC.apb1rst1_r, rcc_usart2rst, 0); + + USART2.c_r1 = 0; + USART2.c_r2 = 0; + USART2.c_r3 = 0; + + usart_set_divisor(&USART2, 16000000 / baud_rate); +} + +#ifdef ARCH_STM32L4 + +/* Main function. This gets executed from the interrupt vector defined above. */ +int main() +{ + /* Enable a higher clock frequency. */ + set_system_clock_MHz(80); + + setup_usart2(115200); + regset(USART2.c_r1, usart_txeie, 1); + regset(USART2.c_r1, usart_rxneie, 1); + usart_enable_dma(&USART2, USART_ENABLE_TX); + usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); + + + dma_opts_t opts = DEFAULT_DMA_OPTS; + opts.transfer_complete_interrupt_enable = 1; + int ec = 0; + dma_mem2p_channel_t dma_chan = + select_dma_channel_mem2p(DMA1_PERIPH_USART2_TX, &opts, &ec); + enable_interrupt(dma_channel_get_interrupt(dma_chan.c_)); + + if (ec) { + usart_printf(&USART2, "Select DMA channel failed :( %d\n", ec); + for (;;); + } + + // const char* thing = "Good Thing This Works!"; + + char* str = halloc(128); + kstrcpy(str, "Hello, Heap!"); + + usart_printf(&USART2, "DATA_SEGMENT_START %p\n", &DATA_SEGMENT_START); + usart_printf(&USART2, "DATA_SEGMENT_STOP: %p\n", &DATA_SEGMENT_STOP); + usart_printf(&USART2, "str at: %p\n", str); + usart_printf(&USART2, "str: %s\n", str); + // usart_printf(&USART2, "%s\n", thing); + // regset(USART2.ic_r, usart_tccf, 1); + // dma_mem2p_initiate_transfer(dma_chan, thing, strlen(thing)); + + __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); + gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); + pin_on(pin3); + + // usart_printf(&USART2, "Start Configuring Countdown!\n"); + + /* Set the countdown to start from 1,000,0000. */ + SCB.strv_r = 10000000; + + /* Enable interrupts. */ + regset(SCB.stcs_r, scb_tickint, 1); + + /* Start the systick. */ + regset(SCB.stcs_r, scb_enable, 1); + + // usart_printf(&USART2, "Start Countdown Started!\n"); +} + +#endif diff --git a/02-usart/src/kern/mem.c b/02-usart/src/kern/mem.c new file mode 100644 index 0000000..79bcabf --- /dev/null +++ b/02-usart/src/kern/mem.c @@ -0,0 +1,206 @@ +#include "arch.h" +#include "kern/mem.h" +#include "kern/common.h" + +#ifdef ARCH_STM32L4 +/* Provide a definition for memset() when not provided for the + * microcontroller. */ +void* memset(void* dest, int c, size_t n) +{ + uint8_t c8 = (uint8_t) c; + uint8_t* dest8 = (uint8_t*) dest; + uint8_t* to = dest8 + n; + + while(dest8 < to) { + *(dest8 ++) = c8; + } + + return dest; +} + +#else + +void* memset(void* dest, int c, size_t n); + +#endif + +typedef uint16_t halloc_off_t; + +// The sizes will count the number of WORDS allocated. +// Since there's a max size of 16k, only 12 bits will be +// needed for this. +typedef struct HALLOC_NODE { + union { + uint32_t header; + struct { + /* Is this memory block currently in use (hasn't been hfree'd) */ + bool used:1; + /* Number of words allocated. Does not include the header. */ + uint16_t size:15; + /* The location of the previous block (in WORDS from offest) */ + halloc_off_t prev; + } PACKED; + }; + + uint8_t mem[]; /* The memory to use. */ +} halloc_node_t; + +halloc_node_t* halloc_start; + +#define halloc_node_next(cur) \ + ((halloc_node_t*)(((uint8_t*)(cur)) + (((cur)->size + 1) * 4))) + +#define halloc_node_prev(cur) halloc_node_at_off(cur->prev) + +#define halloc_node_at_off(offset) \ + ((halloc_node_t*)(((uint8_t*) halloc_start) + (offset) * 4)) + +#define halloc_node_get_off(node) \ + (((uint32_t)(((uint8_t*)(node)) - ((uint8_t*)(halloc_start)))) / 4) + +#define size_for(n) \ + (((n) / 4) + ((n) % 4 != 0)) + +void* halloc(size_t size) +{ + if (!halloc_start) { + halloc_start = (halloc_node_t*) DATA_SEGMENT_STOP_ADDR; + memset(halloc_start, 0, sizeof(halloc_node_t)); + halloc_start->size = (MAX_HEAP_SIZE / 4) - 1; + } + + size_t realsz = size_for(size); /* Clip the size to the nearest word. */ + halloc_off_t offset = 0; + while (offset < (MAX_HEAP_SIZE / 4)) { + halloc_node_t* cur = halloc_node_at_off(offset); + + if (!cur->used && (cur->size >= realsz)) { + cur->used = true; + size_t orig_size = cur->size; + cur->size = realsz; + + if (orig_size > realsz) { + /* This halloc node needs to split into two blocks. */ + halloc_node_t* next = halloc_node_next(cur); + next->used = 0; + next->size = orig_size - realsz - sizeof(halloc_node_t) / 4; + next->prev = offset; + + halloc_node_t* nextnext = halloc_node_next(next); + if (halloc_node_get_off(nextnext) < (MAX_HEAP_SIZE / 4)) { + nextnext->prev = halloc_node_get_off(next); + } + } + + return (void*) cur->mem; + } + + offset += (sizeof(halloc_node_t) / 4) + cur->size; + } + + return NULL; +} + +/* Joins this node with the previous and next nodes if they're free. */ +static void coalesce(halloc_node_t* cur) +{ + if (cur->used) return; + + halloc_node_t* next = halloc_node_next(cur); + if (!next->used) { + cur->size += next->size + sizeof(halloc_node_t) / 4; + } + + if (cur != halloc_start) { + coalesce(halloc_node_prev(cur)); + } +} + +void hfree(void* mem) +{ + /* TODO this should be a critical section. */ + if (!mem) { + /* Consistent with C, freeing a NULL pointer does nothing. */ + return; + } + + halloc_node_t* header = ((halloc_node_t*) mem) - 1; + + if (!header->used) { +#ifdef FOR_TESTING + assert(header->used); +#endif + return; // TODO make this fail on ARM. + } + + header->used = 0; + coalesce(header); +} + +#ifdef FOR_TESTING + +#include + +void* debug_halloc_get_next_ptr(void* ptr) +{ + halloc_node_t* node = ptr - sizeof(halloc_node_t); + halloc_node_t* next = halloc_node_next(node); + + return next->mem; +} + +void* debug_halloc_get_prev_ptr(void* ptr) +{ + halloc_node_t* node = ptr - sizeof(halloc_node_t); + halloc_node_t* prev = halloc_node_prev(node); + + return prev->mem; +} + +/* Tests that we can walk up and down the allocated blocks and that they + * are properly aligned. */ +int debug_halloc_assert_consistency(char* error, size_t len) +{ + halloc_node_t* cur = halloc_node_at_off(0); + size_t total_size = 0; + size_t loop_check = 0; + + while(1) { + total_size += cur->size + 1; + + halloc_node_t* next = halloc_node_next(cur); + if ((uint8_t*) next == ((uint8_t*)&DATA_SEGMENT_STOP) + MAX_HEAP_SIZE) { + break; + } else if ((uint8_t*) next > (uint8_t*)DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE){ + snprintf( + error, len, "Next node points is out of bounds. %p vs max of %p\n", + next, + (void*)(DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE)); + return 1; + } + cur = next; + } + + if (total_size * 4 != MAX_HEAP_SIZE) { + snprintf( + error, len, "Total recorded size is inconsistent. %lu vs %lu\n", + total_size * 4, MAX_HEAP_SIZE); + return 1; + } + + while (loop_check < 10000) { + halloc_node_t* prev = halloc_node_prev(cur); + + if (prev == halloc_start) { + return 0; + } + + cur = prev; + ++ loop_check; + } + + snprintf(error, len, "Loop check failed.\n"); + return 1; +} + +#endif diff --git a/02-usart/src/kern/spin.c b/02-usart/src/kern/spin.c new file mode 100644 index 0000000..7c4f6eb --- /dev/null +++ b/02-usart/src/kern/spin.c @@ -0,0 +1,49 @@ +#include "kern/spin.h" +#include "kern/delay.h" +#include "arch/stm32l4xxx/peripherals/gpio.h" + +#define SHORT_DELAY 200000 +#define LONG_DELAY (SHORT_DELAY * 2) + +static void flash_bit( + uint32_t base, gpio_output_pin_t out_pin, + uint8_t bit /* 0 => 0, non-zero => 1 */) +{ + pin_on(out_pin); + if (bit) { + delay(base * 2); + } else { + delay(base); + } + pin_off(out_pin); + delay(base); +} + +void spin(uint32_t base, uint8_t c) +{ + uint8_t code; + __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); + gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); + + for (;;) { + code = c; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + + code <<= 1; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + code <<= 1; + flash_bit(base, pin3, code & 0x80); + + delay(base * 4); + } +} diff --git a/02-usart/src/kern/stdlibrepl.c b/02-usart/src/kern/stdlibrepl.c new file mode 100644 index 0000000..2d9d839 --- /dev/null +++ b/02-usart/src/kern/stdlibrepl.c @@ -0,0 +1,13 @@ +/* + * Replacement for common stdlib functions that don't exist + * on the ARM bare-metal compilation environment. + */ + +#include + +size_t strlen(char* ch) +{ + size_t ret = 0; + while(*(ch ++) != 0) ++ ret; + return ret; +} diff --git a/02-usart/src/kern/string.c b/02-usart/src/kern/string.c new file mode 100644 index 0000000..4afa228 --- /dev/null +++ b/02-usart/src/kern/string.c @@ -0,0 +1,9 @@ +#include "kern/string.h" + +void kstrcpy(char* into, const char* from) +{ + while(*from) { + *(into ++) = *(from ++); + } + *into = 0; +} diff --git a/02-usart/src/kern/vector.c b/02-usart/src/kern/vector.c new file mode 100644 index 0000000..e69de29 diff --git a/02-usart/src/lib.c b/02-usart/src/lib.c deleted file mode 100644 index d5d81da..0000000 --- a/02-usart/src/lib.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "lib.h" - -#define nybble_to_hex(n) \ - ((n) < 10 ? 0x30 + (n) : ('A' + ((n) - 10))) - -void hexify(uint32_t v, char* into) -{ - into += 8; - - *(into--) = 0; - - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *(into--) = nybble_to_hex(v & 0x0F); - v >>= 4; - *into = nybble_to_hex(v & 0x0F); - v >>= 4; -} - -void decimalify(int v, char* into) -{ - int c = 0; - int i; - - if (v == 0) { - *(into ++) = '0'; - *into = 0; - return; - } else { - while (v > 0) { - *(into ++) = 0x30 + (v % 10); - v /= 10; - ++ c; - } - } - *into = 0; - - into -= c; - for (i = 0; i < c / 2; ++ i) { - char tmp = into[i]; - into[i] = into[c - i - 1]; - into[c - i - 1] = tmp; - } - -} diff --git a/02-usart/src/main.c b/02-usart/src/main.c deleted file mode 100644 index b050d3e..0000000 --- a/02-usart/src/main.c +++ /dev/null @@ -1,115 +0,0 @@ - -#include "arch.h" -#include "core/clock.h" -#include "core/dma.h" -#include "core/gpio.h" -#include "core/system.h" -#include "core/usart.h" -#include "core/nvic.h" -#include "core/irq.h" - -#include "peri/dma.h" -#include "delay.h" -#include "mem.h" -#include "spin.h" -#include "string.h" - -/** Overrides the default systick irq handler. */ -void on_systick() -{ - static int is_on = 0; - - __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); - gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); - - if (is_on) { - pin_off(pin3); - } else { - pin_on(pin3); - } - - is_on = ! is_on; -} - -void setup_usart2(uint32_t baud_rate) -{ - __IO gpio_port_t* port_a = enable_gpio(GPIO_PORT_A); - enable_hsi(&RCC, true); - - set_usart2_clock_src(&RCC, USART_CLK_SRC_HSI16); - set_usart2_clock_enabled(&RCC, USART_CLK_SRC_HSI16); - - set_gpio_pin_mode(port_a, PIN_2, MODE_ALTERNATE); - set_gpio_pin_mode(port_a, PIN_15, MODE_ALTERNATE); - set_gpio_alternate_function(port_a, PIN_2, AFN_7); - set_gpio_alternate_function(port_a, PIN_15, AFN_3); - - /* De-assert reset of USART2 */ - regset(RCC.apb1rst1_r, rcc_usart2rst, 0); - - USART2.c_r1 = 0; - USART2.c_r2 = 0; - USART2.c_r3 = 0; - - usart_set_divisor(&USART2, 16000000 / baud_rate); -} - -#ifdef ARCH_STM32L4 - -/* Main function. This gets executed from the interrupt vector defined above. */ -int main() -{ - /* Enable a higher clock frequency. */ - set_system_clock_MHz(80); - - setup_usart2(115200); - regset(USART2.c_r1, usart_txeie, 1); - regset(USART2.c_r1, usart_rxneie, 1); - usart_enable_dma(&USART2, USART_ENABLE_TX); - usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); - - - dma_opts_t opts = DEFAULT_DMA_OPTS; - opts.transfer_complete_interrupt_enable = 1; - int ec = 0; - dma_mem2p_channel_t dma_chan = - select_dma_channel_mem2p(DMA1_PERIPH_USART2_TX, &opts, &ec); - enable_interrupt(dma_channel_get_interrupt(dma_chan.c_)); - - if (ec) { - usart_printf(&USART2, "Select DMA channel failed :( %d\n", ec); - for (;;); - } - - // const char* thing = "Good Thing This Works!"; - - char* str = halloc(128); - strcpy(str, "Hello, Heap!"); - - usart_printf(&USART2, "DATA_SEGMENT_START %p\n", &DATA_SEGMENT_START); - usart_printf(&USART2, "DATA_SEGMENT_STOP: %p\n", &DATA_SEGMENT_STOP); - usart_printf(&USART2, "str at: %p\n", str); - usart_printf(&USART2, "str: %s\n", str); - // usart_printf(&USART2, "%s\n", thing); - // regset(USART2.ic_r, usart_tccf, 1); - // dma_mem2p_initiate_transfer(dma_chan, thing, strlen(thing)); - - __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); - gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); - pin_on(pin3); - - // usart_printf(&USART2, "Start Configuring Countdown!\n"); - - /* Set the countdown to start from 1,000,0000. */ - // SCB.strv_r = 10000000; - - /* Enable interrupts. */ - // regset(SCB.stcs_r, scb_tickint, 1); - - /* Start the systick. */ - // regset(SCB.stcs_r, scb_enable, 1); - - // usart_printf(&USART2, "Start Countdown Started!\n"); -} - -#endif diff --git a/02-usart/src/mem.c b/02-usart/src/mem.c deleted file mode 100644 index 27e0fc2..0000000 --- a/02-usart/src/mem.c +++ /dev/null @@ -1,206 +0,0 @@ -#include "arch.h" -#include "mem.h" -#include "common.h" - -#ifdef ARCH_STM32L4 -/* Provide a definition for memset() when not provided for the - * microcontroller. */ -void* memset(void* dest, int c, size_t n) -{ - uint8_t c8 = (uint8_t) c; - uint8_t* dest8 = (uint8_t*) dest; - uint8_t* to = dest8 + n; - - while(dest8 < to) { - *(dest8 ++) = c8; - } - - return dest; -} - -#else - -void* memset(void* dest, int c, size_t n); - -#endif - -typedef uint16_t halloc_off_t; - -// The sizes will count the number of WORDS allocated. -// Since there's a max size of 16k, only 12 bits will be -// needed for this. -typedef struct HALLOC_NODE { - union { - uint32_t header; - struct { - /* Is this memory block currently in use (hasn't been hfree'd) */ - bool used:1; - /* Number of words allocated. Does not include the header. */ - uint16_t size:15; - /* The location of the previous block (in WORDS from offest) */ - halloc_off_t prev; - } PACKED; - }; - - uint8_t mem[]; /* The memory to use. */ -} halloc_node_t; - -halloc_node_t* halloc_start; - -#define halloc_node_next(cur) \ - ((halloc_node_t*)(((uint8_t*)(cur)) + (((cur)->size + 1) * 4))) - -#define halloc_node_prev(cur) halloc_node_at_off(cur->prev) - -#define halloc_node_at_off(offset) \ - ((halloc_node_t*)(((uint8_t*) halloc_start) + (offset) * 4)) - -#define halloc_node_get_off(node) \ - (((uint32_t)(((uint8_t*)(node)) - ((uint8_t*)(halloc_start)))) / 4) - -#define size_for(n) \ - (((n) / 4) + ((n) % 4 != 0)) - -void* halloc(size_t size) -{ - if (!halloc_start) { - halloc_start = (halloc_node_t*) DATA_SEGMENT_STOP_ADDR; - memset(halloc_start, 0, sizeof(halloc_node_t)); - halloc_start->size = (MAX_HEAP_SIZE / 4) - 1; - } - - size_t realsz = size_for(size); /* Clip the size to the nearest word. */ - halloc_off_t offset = 0; - while (offset < (MAX_HEAP_SIZE / 4)) { - halloc_node_t* cur = halloc_node_at_off(offset); - - if (!cur->used && (cur->size >= realsz)) { - cur->used = true; - size_t orig_size = cur->size; - cur->size = realsz; - - if (orig_size > realsz) { - /* This halloc node needs to split into two blocks. */ - halloc_node_t* next = halloc_node_next(cur); - next->used = 0; - next->size = orig_size - realsz - sizeof(halloc_node_t) / 4; - next->prev = offset; - - halloc_node_t* nextnext = halloc_node_next(next); - if (halloc_node_get_off(nextnext) < (MAX_HEAP_SIZE / 4)) { - nextnext->prev = halloc_node_get_off(next); - } - } - - return (void*) cur->mem; - } - - offset += (sizeof(halloc_node_t) / 4) + cur->size; - } - - return NULL; -} - -/* Joins this node with the previous and next nodes if they're free. */ -static void coalesce(halloc_node_t* cur) -{ - if (cur->used) return; - - halloc_node_t* next = halloc_node_next(cur); - if (!next->used) { - cur->size += next->size + sizeof(halloc_node_t) / 4; - } - - if (cur != halloc_start) { - coalesce(halloc_node_prev(cur)); - } -} - -void hfree(void* mem) -{ - /* TODO this should be a critical section. */ - if (!mem) { - /* Consistent with C, freeing a NULL pointer does nothing. */ - return; - } - - halloc_node_t* header = ((halloc_node_t*) mem) - 1; - - if (!header->used) { -#ifdef FOR_TESTING - assert(header->used); -#endif - return; // TODO make this fail on ARM. - } - - header->used = 0; - coalesce(header); -} - -#ifdef FOR_TESTING - -#include - -void* debug_halloc_get_next_ptr(void* ptr) -{ - halloc_node_t* node = ptr - sizeof(halloc_node_t); - halloc_node_t* next = halloc_node_next(node); - - return next->mem; -} - -void* debug_halloc_get_prev_ptr(void* ptr) -{ - halloc_node_t* node = ptr - sizeof(halloc_node_t); - halloc_node_t* prev = halloc_node_prev(node); - - return prev->mem; -} - -/* Tests that we can walk up and down the allocated blocks and that they - * are properly aligned. */ -int debug_halloc_assert_consistency(char* error, size_t len) -{ - halloc_node_t* cur = halloc_node_at_off(0); - size_t total_size = 0; - size_t loop_check = 0; - - while(1) { - total_size += cur->size + 1; - - halloc_node_t* next = halloc_node_next(cur); - if ((uint8_t*) next == ((uint8_t*)&DATA_SEGMENT_STOP) + MAX_HEAP_SIZE) { - break; - } else if ((uint8_t*) next > (uint8_t*)DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE){ - snprintf( - error, len, "Next node points is out of bounds. %p vs max of %p\n", - next, - (void*)(DATA_SEGMENT_STOP_ADDR + MAX_HEAP_SIZE)); - return 1; - } - cur = next; - } - - if (total_size * 4 != MAX_HEAP_SIZE) { - snprintf( - error, len, "Total recorded size is inconsistent. %lu vs %lu\n", - total_size * 4, MAX_HEAP_SIZE); - return 1; - } - - while (loop_check < 10000) { - halloc_node_t* prev = halloc_node_prev(cur); - - if (prev == halloc_start) { - return 0; - } - - cur = prev; - ++ loop_check; - } - - snprintf(error, len, "Loop check failed.\n"); - return 1; -} - -#endif diff --git a/02-usart/src/peri/dma.c b/02-usart/src/peri/dma.c deleted file mode 100644 index ceae2e6..0000000 --- a/02-usart/src/peri/dma.c +++ /dev/null @@ -1,312 +0,0 @@ -#include "peri/dma.h" -#include "core/dma.h" -#include "core/usart.h" -#include "core/rcc.h" - - -/* Bitmask of DMA2 channels in use. */ -static uint8_t dma_inuse[2]; - -static inline dma_t* get_dma(int dma) -{ - if (dma) { - return &DMA2; - } else { - return &DMA1; - } -} - -static dma_t* get_raw_dma(dma_channel_t chan) -{ - return get_dma(chan.dma); -} - -static dma_channel_config_t* get_raw_channel_config(dma_channel_t chan) -{ - dma_t* dma = get_raw_dma(chan); - return &dma->channel_config[chan.chan]; -} - -static uint32_t get_periph_location(dma_peripheral_t operipheral) -{ -#define CASE(p, n) case p: return ptr2reg(n); - switch (operipheral) { - CASE(DMA1_PERIPH_USART1_RX, &USART1.rd_r) - CASE(DMA1_PERIPH_USART1_TX, &USART1.td_r) - CASE(DMA1_PERIPH_USART2_RX, &USART2.rd_r) - CASE(DMA1_PERIPH_USART2_TX, &USART2.td_r) - - default: - return 0; - }; -#undef CASE -} - -static dma_channel_t allocate_dma_channel( - dma_peripheral_t operipheral, int* modesel) -{ - dma_peripheral_t peripheral = operipheral & 0xff; - int dmasel = peripheral >= DMA2_DMA1_SWITCH__; - if (dmasel) { - peripheral -= DMA2_DMA1_SWITCH__; - } - int chan = peripheral % DMA_N_CHANNELS; - - *modesel = peripheral / 7; - return (dma_channel_t) { - .dma = dmasel, - .chan = chan - }; -} - -/* - * Atomically reserves the DMA channel so other calls - * cannot erroneously reserve the same DMA channel. - * - * Returns 0 if this function was unable to reserve - * the channel. - */ -static int try_reserve_dma_channel( - dma_channel_t chan) -{ - int in_use = __sync_fetch_and_or( - &dma_inuse[chan.dma], 1 << chan.chan); - - return !(in_use & (1 << chan.chan)); -} - - // int in_use = __sync_fetch_and_or(&dma_inuse[dmasel], 1 << chan); -void release_dma_channel(dma_channel_t chan) -{ - dma_channel_config_t* config = get_raw_channel_config(chan); - regset(config->cc_r, dma_cc_en, 0); /* Disable the register. */ - dma_inuse[chan.dma] &= ~(1 << chan.chan); /* Release the DMA. */ - - if (!dma_inuse[chan.dma]) { - /* Power-down the DMA if not in use. */ - if (chan.dma) { - regset(RCC.ahb1en_r, rcc_dma2en, 0); - } else { - regset(RCC.ahb1en_r, rcc_dma1en, 0); - } - } -} - -void configure_dma_channel( - dma_channel_t chan, - dma_peripheral_t operipheral, - dma_opts_t* opts, - dma_dir_t dir, - int selmode, - bool mem2mem, - int* error_out) -{ - if (chan.dma) { - regset(RCC.ahb1en_r, rcc_dma2en, 1); - } else { - regset(RCC.ahb1en_r, rcc_dma1en, 1); - } - - dma_t* dma = get_raw_dma(chan); - regset(dma->csel_r, 0xF << (4 * chan.chan), selmode); - dma_channel_config_t* config = - &dma->channel_config[chan.chan]; - - uint32_t reg = 0; - - regset(reg, dma_cc_dir, dir); - regset(reg, dma_cc_tcie, opts->transfer_complete_interrupt_enable); - regset(reg, dma_cc_htie, opts->half_transfer_interrupt_enable); - regset(reg, dma_cc_teie, opts->transfer_error_interrupt_enable); - regset(reg, dma_cc_circ, opts->circular_mode); - regset(reg, dma_cc_pinc, opts->peripheral_increment); - regset(reg, dma_cc_minc, opts->memory_increment); - regset(reg, dma_cc_psize, opts->peripheral_block_size); - regset(reg, dma_cc_msize, opts->memory_block_size); - regset(reg, dma_cc_pl, opts->priority); - regset(reg, dma_cc_mem2mem, mem2mem); - - config->cc_r = reg; - config->cpa_r = get_periph_location(operipheral); - - *error_out = 0; -} - -dma_mem2mem_channel_t select_dma_channel_mem2mem( - int channel, - dma_opts_t* opts, - int* error_out) -{ - -#define WRAP(c) ((dma_mem2mem_channel_t) { .c_ = c }) - // TODO this should probably be in a critical section. - dma_channel_t chan; - if (channel == -1) { - chan.dma = 1; - if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) { - chan.dma = 0; - } - - if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) { - *error_out = DMA_ERROR_CHANNEL_IN_USE; - return WRAP(DMA_CHAN_ERROR); - } - - uint8_t t = ~(dma_inuse[chan.dma] << 1); - chan.chan = 6 - (__builtin_clz(t) - 24); - } else { - if (channel < 7) { - chan.dma = 0; - chan.chan = channel; - } else { - chan.dma = 0; - chan.chan = channel - 7; - } - } - - if (!try_reserve_dma_channel(chan)) { - *error_out = DMA_ERROR_CHANNEL_IN_USE; - return WRAP(DMA_CHAN_ERROR); - } - - int ec = 0; - configure_dma_channel( - chan, - -1 /* No peripheral */, - opts, - READ_FROM_PERIPHERAL, - /* selmode = */ 0x8, - /* mem2mem = */ true, - &ec); - - if (ec) { - *error_out = ec; - return WRAP(DMA_CHAN_ERROR); - } - - *error_out = 0; - return WRAP(chan); -#undef WRAP -} - -dma_mem2p_channel_t select_dma_channel_mem2p( - dma_peripheral_t peripheral, - dma_opts_t* opts_in, - int* error_out) -{ -#define WRAP(c) ((dma_mem2p_channel_t) { .c_ = c }) - *error_out = 0; - - int modesel; - dma_channel_t ret = - allocate_dma_channel(peripheral, &modesel); - - if (!try_reserve_dma_channel(ret)) { - *error_out = DMA_ERROR_CHANNEL_IN_USE; - return WRAP(DMA_CHAN_ERROR); - } - - configure_dma_channel( - ret, - peripheral, - opts_in, - READ_FROM_MEMORY, - modesel, - /* mem2mem = */ false, - error_out); - - if (*error_out) { - return WRAP(DMA_CHAN_ERROR); - } - - *error_out = 0; - return WRAP(ret); -#undef WRAP -} - -dma_p2mem_channel_t select_dma_channel_p2mem( - dma_peripheral_t peripheral, - dma_opts_t* opts_in, - int* error_out) -{ -#define WRAP(c) ((dma_p2mem_channel_t) { .c_ = c }) - *error_out = 0; - - int modesel; - dma_channel_t ret = - allocate_dma_channel(peripheral, &modesel); - - if (!try_reserve_dma_channel(ret)) { - *error_out = DMA_ERROR_CHANNEL_IN_USE; - return WRAP(DMA_CHAN_ERROR); - } - - configure_dma_channel( - ret, - peripheral, - opts_in, - READ_FROM_PERIPHERAL, - modesel, - /* mem2mem = */ false, - error_out); - - if (*error_out) { - return WRAP(DMA_CHAN_ERROR); - } - - *error_out = 0; - return WRAP(ret); -#undef WRAP -} - - -void dma_mem2p_initiate_transfer( - dma_mem2p_channel_t chan, const void* from_loc, uint16_t nblocks) -{ - dma_channel_config_t* config = get_raw_channel_config(chan.c_); - config->cma_r = ptr2reg(from_loc); - config->cndt_r = nblocks; - - regset(config->cc_r, dma_cc_en, 1); -} - -void dma_mem2mem_initiate_transfer( - dma_mem2mem_channel_t chan, - void* to_loc, - const void* from_loc, - uint16_t nblocks) -{ - dma_channel_config_t* config = get_raw_channel_config(chan.c_); - config->cma_r = ptr2reg(to_loc); - config->cpa_r = ptr2reg(from_loc); - config->cndt_r = nblocks; - - regset(config->cc_r, dma_cc_en, 1); -} - -void dma_p2mem_initiate_transfer( - dma_p2mem_channel_t chan, void* to_loc, uint16_t nblocks) -{ - dma_channel_config_t* config = get_raw_channel_config(chan.c_); - - config->cma_r = ptr2reg(to_loc); - config->cndt_r = nblocks; - - regset(config->cc_r, dma_cc_en, 1); -} - -interrupt_t dma_channel_get_interrupt(dma_channel_t chan) -{ - if (chan.dma == 0) { - return IRQ_DMA1_CHANNEL1_IRQ + chan.chan; - } else { - switch (chan.chan) { - case 5: - return IRQ_DMA1_CHANNEL6_IRQ; - case 6: - return IRQ_DMA1_CHANNEL7_IRQ; - default: - return IRQ_DMA2_CHANNEL1_IRQ + chan.chan; - } - } -} diff --git a/02-usart/src/spin.c b/02-usart/src/spin.c deleted file mode 100644 index 4d1aede..0000000 --- a/02-usart/src/spin.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "spin.h" -#include "delay.h" -#include "core/gpio.h" - -#define SHORT_DELAY 200000 -#define LONG_DELAY (SHORT_DELAY * 2) - -static void flash_bit( - uint32_t base, gpio_output_pin_t out_pin, - uint8_t bit /* 0 => 0, non-zero => 1 */) -{ - pin_on(out_pin); - if (bit) { - delay(base * 2); - } else { - delay(base); - } - pin_off(out_pin); - delay(base); -} - -void spin(uint32_t base, uint8_t c) -{ - uint8_t code; - __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); - gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3); - - for (;;) { - code = c; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - - code <<= 1; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - code <<= 1; - flash_bit(base, pin3, code & 0x80); - - delay(base * 4); - } -} diff --git a/02-usart/src/stdlibrepl.c b/02-usart/src/stdlibrepl.c deleted file mode 100644 index 2d9d839..0000000 --- a/02-usart/src/stdlibrepl.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Replacement for common stdlib functions that don't exist - * on the ARM bare-metal compilation environment. - */ - -#include - -size_t strlen(char* ch) -{ - size_t ret = 0; - while(*(ch ++) != 0) ++ ret; - return ret; -} diff --git a/02-usart/src/vector.c b/02-usart/src/vector.c deleted file mode 100644 index e69de29..0000000 -- cgit