From d2cb18542f4f6071232bd046fd1b257228c17a25 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Feb 2023 23:02:16 -0800 Subject: [PATCH] altos: Start work on stm32f1 support Got clocks working. CPU now running at 72MHz. Got systick timer working. Ticks at 100Hz. Got GPIO working. LED blinks. Signed-off-by: Keith Packard --- src/stm32f1/Makefile-raw.defs | 13 + src/stm32f1/Makefile-stm32f1.defs | 12 + src/stm32f1/Makefile.defs | 11 + src/stm32f1/altos-ram.ld | 8 + src/stm32f1/altos-raw.ld | 26 ++ src/stm32f1/ao_arch.h | 58 ++++ src/stm32f1/ao_arch_funcs.h | 74 +++++ src/stm32f1/ao_clock.c | 192 +++++++++++ src/stm32f1/ao_interrupt.c | 216 +++++++++++++ src/stm32f1/ao_timer.c | 72 +++++ src/stm32f1/openocd-stm32f1 | 12 + src/stm32f1/registers.ld | 45 +++ src/stm32f1/stm32f1.h | 522 ++++++++++++++++++++++++++++++ src/stm32f103-nucleo/Makefile | 39 +++ src/stm32f103-nucleo/ao_pins.h | 39 +++ src/stm32f103-nucleo/hello.c | 38 +++ src/stm32f103-nucleo/hello.ld | 7 + 17 files changed, 1384 insertions(+) create mode 100644 src/stm32f1/Makefile-raw.defs create mode 100644 src/stm32f1/Makefile-stm32f1.defs create mode 100644 src/stm32f1/Makefile.defs create mode 100644 src/stm32f1/altos-ram.ld create mode 100644 src/stm32f1/altos-raw.ld create mode 100644 src/stm32f1/ao_arch.h create mode 100644 src/stm32f1/ao_arch_funcs.h create mode 100644 src/stm32f1/ao_clock.c create mode 100644 src/stm32f1/ao_interrupt.c create mode 100644 src/stm32f1/ao_timer.c create mode 100755 src/stm32f1/openocd-stm32f1 create mode 100644 src/stm32f1/registers.ld create mode 100644 src/stm32f1/stm32f1.h create mode 100644 src/stm32f103-nucleo/Makefile create mode 100644 src/stm32f103-nucleo/ao_pins.h create mode 100644 src/stm32f103-nucleo/hello.c create mode 100644 src/stm32f103-nucleo/hello.ld diff --git a/src/stm32f1/Makefile-raw.defs b/src/stm32f1/Makefile-raw.defs new file mode 100644 index 00000000..91d30bd5 --- /dev/null +++ b/src/stm32f1/Makefile-raw.defs @@ -0,0 +1,13 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/stm32f1/Makefile-stm32f1.defs + +LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf +MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin +FLASH_ADDR=0x08000000 + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -Taltos-ram.ld -n + +.DEFAULT_GOAL=all diff --git a/src/stm32f1/Makefile-stm32f1.defs b/src/stm32f1/Makefile-stm32f1.defs new file mode 100644 index 00000000..b84f7397 --- /dev/null +++ b/src/stm32f1/Makefile-stm32f1.defs @@ -0,0 +1,12 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/Makefile.defs + +vpath % $(TOPDIR)/stm32f1:$(AO_VPATH) + +CC=$(ARM_CC) + +STM32F1_CFLAGS=-mlittle-endian -mcpu=cortex-m3 -mthumb \ + -I$(TOPDIR)/stm32f1 $(AO_CFLAGS) $(PICOLIBC_CFLAGS) diff --git a/src/stm32f1/Makefile.defs b/src/stm32f1/Makefile.defs new file mode 100644 index 00000000..e292fc67 --- /dev/null +++ b/src/stm32f1/Makefile.defs @@ -0,0 +1,11 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/stm32f1/Makefile-stm32f1.defs + +STM32F1_LINKER_SCRIPT=altos-raw.ld + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -T$(STM32F1_LINKER_SCRIPT) -n + +.DEFAULT_GOAL=all diff --git a/src/stm32f1/altos-ram.ld b/src/stm32f1/altos-ram.ld new file mode 100644 index 00000000..d409d2cb --- /dev/null +++ b/src/stm32f1/altos-ram.ld @@ -0,0 +1,8 @@ +__flash = 0x20000000; +__flash_size = 12k; +__ram = 0x20003000; +__ram_size = 4k; +__stack_size = 512; + +INCLUDE registers.ld +INCLUDE picolibc.ld diff --git a/src/stm32f1/altos-raw.ld b/src/stm32f1/altos-raw.ld new file mode 100644 index 00000000..1a7ccdd3 --- /dev/null +++ b/src/stm32f1/altos-raw.ld @@ -0,0 +1,26 @@ +/* + * Copyright © 2018 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +__flash = 0x08000000; +__flash_size = 64k; +__ram = 0x20000000; +__ram_size = 20k; +__stack_size = 512; + +INCLUDE registers.ld +INCLUDE picolibc.ld diff --git a/src/stm32f1/ao_arch.h b/src/stm32f1/ao_arch.h new file mode 100644 index 00000000..de5f2159 --- /dev/null +++ b/src/stm32f1/ao_arch.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_H_ +#define _AO_ARCH_H_ + +#include + +#ifndef AO_STACK_SIZE +#define AO_STACK_SIZE 512 +#endif + +#define AO_PORT_TYPE uint16_t + +#define ao_arch_naked_declare __attribute__((naked)) +#define ao_arch_naked_define +#define __interrupt(n) +#define __at(n) + +#define ao_arch_nop() asm("nop") + +#define ao_arch_interrupt(n) /* nothing */ + +#define AO_ROMCONFIG_SYMBOL __attribute__((section(".init.1"))) const +#define AO_USBCONFIG_SYMBOL __attribute__((section(".init.2"))) const + +#define AO_SYSTICK (AO_HCLK / 8) + +#if AO_NONMASK_INTERRUPT +#define AO_STM_NVIC_NONMASK_PRIORITY 0x00 + +/* Set the basepri register to this value to mask all + * non-maskable priorities + */ +#define AO_STM_NVIC_BASEPRI_MASK 0x10 +#endif + +#define AO_STM_NVIC_HIGH_PRIORITY 0x40 +#define AO_STM_NVIC_MED_PRIORITY 0x80 +#define AO_STM_NVIC_LOW_PRIORITY 0xC0 +#define AO_STM_NVIC_CLOCK_PRIORITY 0xf0 + +#endif /* _AO_ARCH_H_ */ diff --git a/src/stm32f1/ao_arch_funcs.h b/src/stm32f1/ao_arch_funcs.h new file mode 100644 index 00000000..db3cf9e4 --- /dev/null +++ b/src/stm32f1/ao_arch_funcs.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_FUNCS_H_ +#define _AO_ARCH_FUNCS_H_ + +static inline void +ao_enable_port(struct stm_gpio *port) +{ + if ((port) == &stm_gpioa) + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPAEN); + else if ((port) == &stm_gpiob) + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPBEN); + else if ((port) == &stm_gpioc) + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPCEN); + else if ((port) == &stm_gpiod) + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPDEN); + else if ((port) == &stm_gpioe) + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPEEN); +} + +static inline void +ao_disable_port(struct stm_gpio *port) +{ + if ((port) == &stm_gpioa) + stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPAEN); + else if ((port) == &stm_gpiob) + stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPBEN); + else if ((port) == &stm_gpioc) + stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPCEN); + else if ((port) == &stm_gpiod) + stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPDEN); + else if ((port) == &stm_gpioe) + stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPEEN); +} + +#define ao_gpio_set(port, bit, v) stm_gpio_set(port, bit, v) + +#define ao_gpio_get(port, bit) stm_gpio_get(port, bit) + +#define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits) + +#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask) + +#define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits); + +#define ao_gpio_get_all(port) stm_gpio_get_all(port) + +static inline void +ao_enable_output(struct stm_gpio *port, int bit, uint8_t v) +{ + ao_enable_port(port); + ao_gpio_set(port, bit, v); + stm_gpio_conf(port, bit, + STM_GPIO_CR_MODE_OUTPUT_10MHZ, + STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL); +} + +#endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/stm32f1/ao_clock.c b/src/stm32f1/ao_clock.c new file mode 100644 index 00000000..1ce32a90 --- /dev/null +++ b/src/stm32f1/ao_clock.c @@ -0,0 +1,192 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +void +ao_clock_init(void) +{ + uint32_t cfgr; + + /* Switch to HSI while messing about */ + stm_rcc.cr |= (1 << STM_RCC_CR_HSION); + while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY))) + ao_arch_nop(); + + stm_rcc.cfgr = (stm_rcc.cfgr & ~(uint32_t) (STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) | + (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW); + + /* wait for system to switch to HSI */ + while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) != + (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) + ao_arch_nop(); + + /* Disable all interrupts */ + stm_rcc.cir = 0; + +#if AO_HSE +#if AO_HSE_BYPASS + stm_rcc.cr |= (1 << STM_RCC_CR_HSEBYP); +#else + stm_rcc.cr &= ~(uint32_t) (1 << STM_RCC_CR_HSEBYP); +#endif + /* Enable HSE clock */ + stm_rcc.cr |= (1 << STM_RCC_CR_HSEON); + while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSERDY))) + asm("nop"); + +#define STM_RCC_CFGR_SWS_TARGET_CLOCK (STM_RCC_CFGR_SWS_HSE << STM_RCC_CFGR_SWS) +#define STM_RCC_CFGR_SW_TARGET_CLOCK (STM_RCC_CFGR_SW_HSE) +#define STM_PLLSRC AO_HSE +#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK (STM_RCC_CFGR_PLLSRC_HSE << STM_RCC_CFGR_PLLSRC) +#else +#define STM_HSI 16000000 +#define STM_RCC_CFGR_SWS_TARGET_CLOCK (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS) +#define STM_RCC_CFGR_SW_TARGET_CLOCK (STM_RCC_CFGR_SW_HSI) +#define STM_PLLSRC (STM_HSI/2) +#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK (STM_RCC_CFGR_PLLSRC_HSI_2 << STM_RCC_CFGR_PLLSRC) +#endif + +#if !AO_HSE || HAS_ADC || HAS_ADC_SINGLE + /* Enable HSI RC clock 16MHz */ + stm_rcc.cr |= (1 << STM_RCC_CR_HSION); + while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY))) + asm("nop"); +#endif + +#if 0 + /* Set flash latency to tolerate 32MHz SYSCLK -> 1 wait state */ + + /* Enable 64-bit access and prefetch */ + stm_flash.acr |= (1 << STM_FLASH_ACR_ACC64); + stm_flash.acr |= (1 << STM_FLASH_ACR_PRFEN); + + /* Enable 1 wait state so the CPU can run at 32MHz */ + stm_flash.acr |= (1 << STM_FLASH_ACR_LATENCY); +#endif + + /* Enable power interface clock */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); + +#if 0 + /* Set voltage range to 1.8V */ + + /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */ + while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0) + asm("nop"); + + /* Configure voltage scaling range */ + cr = stm_pwr.cr; + cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS); + cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS); + stm_pwr.cr = cr; + + /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */ + while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0) + asm("nop"); +#endif + + /* HCLK */ + cfgr = stm_rcc.cfgr; + cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE); + cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE); + stm_rcc.cfgr = cfgr; + while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) != + (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE)) + asm ("nop"); + + /* APB1 Prescaler = AO_APB1_PRESCALER */ + cfgr = stm_rcc.cfgr; + cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1); + cfgr |= (AO_RCC_CFGR_PPRE1_DIV << STM_RCC_CFGR_PPRE1); + stm_rcc.cfgr = cfgr; + + /* APB2 Prescaler = AO_APB2_PRESCALER */ + cfgr = stm_rcc.cfgr; + cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2); + cfgr |= (AO_RCC_CFGR_PPRE2_DIV << STM_RCC_CFGR_PPRE2); + stm_rcc.cfgr = cfgr; + + /* Disable the PLL */ + stm_rcc.cr &= ~(1UL << STM_RCC_CR_PLLON); + while (stm_rcc.cr & (1UL << STM_RCC_CR_PLLRDY)) + asm("nop"); + + /* PLLVCO */ + cfgr = stm_rcc.cfgr; + cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL); + + cfgr |= (AO_RCC_CFGR_PLLMUL << STM_RCC_CFGR_PLLMUL); + + /* PLL source */ + cfgr &= ~(1UL << STM_RCC_CFGR_PLLSRC); + cfgr |= STM_RCC_CFGR_PLLSRC_TARGET_CLOCK; + + stm_rcc.cfgr = cfgr; + + /* Enable the PLL and wait for it */ + stm_rcc.cr |= (1 << STM_RCC_CR_PLLON); + while (!(stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY))) + asm("nop"); + + /* Switch to the PLL for the system clock */ + + cfgr = stm_rcc.cfgr; + cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW); + cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW); + stm_rcc.cfgr = cfgr; + for (;;) { + uint32_t c, part, mask, val; + + c = stm_rcc.cfgr; + mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS); + val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS); + part = c & mask; + if (part == val) + break; + } + +#if 0 + stm_rcc.apb2rstr = 0xffff; + stm_rcc.apb1rstr = 0xffff; + stm_rcc.ahbrstr = 0x3f; + stm_rcc.ahbenr = (1 << STM_RCC_AHBENR_FLITFEN); + stm_rcc.apb2enr = 0; + stm_rcc.apb1enr = 0; + stm_rcc.ahbrstr = 0; + stm_rcc.apb1rstr = 0; + stm_rcc.apb2rstr = 0; +#endif + + /* Clear reset flags */ + stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF); + + +#if DEBUG_THE_CLOCK + /* Output SYSCLK on PA8 for measurments */ + + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + + stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0); + stm_moder_set(&stm_gpioa, 8, STM_MODER_ALTERNATE); + stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz); + + stm_rcc.cfgr |= (STM_RCC_CFGR_MCOPRE_DIV_1 << STM_RCC_CFGR_MCOPRE); + stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL); +#endif +} diff --git a/src/stm32f1/ao_interrupt.c b/src/stm32f1/ao_interrupt.c new file mode 100644 index 00000000..831a2c2a --- /dev/null +++ b/src/stm32f1/ao_interrupt.c @@ -0,0 +1,216 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include "stm32f1.h" +#include +#include + +extern void main(void); + +/* Interrupt functions */ + +void stm_halt_isr(void) +{ +// ao_panic(AO_PANIC_CRASH); +} + +void stm_ignore_isr(void) +{ +} + +#define STRINGIFY(x) #x + +#define isr(name) \ + void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr)) + +#define isr_halt(name) \ + void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_halt_isr)) + +isr(nmi); +isr_halt(hardfault); +isr_halt(memmanage); +isr_halt(busfault); +isr_halt(usagefault); +isr(svc); +isr(debugmon); +isr(pendsv); +isr(systick); +isr(wwdg); +isr(pvd); +isr(tamper_stamp); +isr(rtc_wkup); +isr(flash); +isr(rcc); +isr(exti0); +isr(exti1); +isr(exti2); +isr(exti3); +isr(exti4); +isr(dma1_channel1); +isr(dma1_channel2); +isr(dma1_channel3); +isr(dma1_channel4); +isr(dma1_channel5); +isr(dma1_channel6); +isr(dma1_channel7); +isr(adc1_2); +isr(usb_hp); +isr(usb_lp); +isr(can_rx1); +isr(can_sce); +isr(exti9_5); +isr(tim1_brk); +isr(tim1_up); +isr(tim1_trg_com); +isr(tim1_cc); +isr(tim2); +isr(tim3); +isr(tim4); +isr(i2c1_ev); +isr(i2c1_er); +isr(i2c2_ev); +isr(i2c2_er); +isr(spi1); +isr(spi2); +isr(usart1); +isr(usart2); +isr(usart3); +isr(exti15_10); +isr(rtc_alarm); +isr(usb_wakeup); +isr(tim8_brk); +isr(tim8_up); +isr(tim8_trg_com); +isr(tim8_cc); +isr(adc3); +isr(fsmc); +isr(sdio); +isr(tim5); +isr(spi3); +isr(uart4); +isr(uart5); +isr(tim6); +isr(tim7); +isr(dma2_channel1); +isr(dma2_channel2); +isr(dma2_channel3); +isr(dma2_channel4_5); + +#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr + +extern char __stack[]; +void _start(void) __attribute__((__noreturn__)); +void main(void) __attribute__((__noreturn__)); +void ao_setup(void) __attribute__((constructor)); + +/* This must be exactly 304 bytes long so that the configuration data + * gets loaded at the right place + */ + +__attribute__ ((section(".init"))) +const void * const __interrupt_vector[76] = { + [0] = &__stack, + [1] = _start, + i(0x08, nmi), + i(0x0c, hardfault), + i(0x10, memmanage), + i(0x14, busfault), + i(0x18, usagefault), + i(0x2c, svc), + i(0x30, debugmon), + i(0x38, pendsv), + i(0x3c, systick), + i(0x40, wwdg), + i(0x44, pvd), + i(0x48, tamper_stamp), + i(0x4c, rtc_wkup), + i(0x50, flash), + i(0x54, rcc), + i(0x58, exti0), + i(0x5c, exti1), + i(0x60, exti2), + i(0x64, exti3), + i(0x68, exti4), + i(0x6c, dma1_channel1), + i(0x70, dma1_channel2), + i(0x74, dma1_channel3), + i(0x78, dma1_channel4), + i(0x7c, dma1_channel5), + i(0x80, dma1_channel6), + i(0x84, dma1_channel7), + i(0x88, adc1_2), + i(0x8c, usb_hp), + i(0x90, usb_lp), + i(0x94, can_rx1), + i(0x98, can_sce), + i(0x9c, exti9_5), + i(0xa0, tim1_brk), + i(0xa4, tim1_up), + i(0xa8, tim1_trg_com), + i(0xac, tim1_cc), + i(0xb0, tim2), + i(0xb4, tim3), + i(0xb8, tim4), + i(0xbc, i2c1_ev), + i(0xc0, i2c1_er), + i(0xc4, i2c2_ev), + i(0xc8, i2c2_er), + i(0xcc, spi1), + i(0xd0, spi2), + i(0xd4, usart1), + i(0xd8, usart2), + i(0xdc, usart3), + i(0xe0, exti15_10), + i(0xe4, rtc_alarm), + i(0xe8, usb_wakeup), + i(0xec, tim8_brk), + i(0xf0, tim8_up), + i(0xf4, tim8_trg_com), + i(0xf8, tim8_cc), + i(0xfc, adc3), + i(0x100, fsmc), + i(0x104, sdio), + i(0x108, tim5), + i(0x10c, spi3), + i(0x110, uart4), + i(0x114, uart5), + i(0x118, tim6), + i(0x11c, tim7), + i(0x120, dma2_channel1), + i(0x124, dma2_channel2), + i(0x128, dma2_channel3), + i(0x12c, dma2_channel4_5), +}; + +void __attribute__((constructor)) ao_setup(void) { +#ifdef AO_BOOT_CHAIN + if (ao_boot_check_chain()) { +#ifdef AO_BOOT_PIN + if (ao_boot_check_pin()) +#endif + { + ao_boot_chain(AO_BOOT_APPLICATION_BASE); + } + } +#endif + /* Set interrupt vector table offset */ + stm_nvic.vto = (uint32_t) &__interrupt_vector; +} diff --git a/src/stm32f1/ao_timer.c b/src/stm32f1/ao_timer.c new file mode 100644 index 00000000..116d33ac --- /dev/null +++ b/src/stm32f1/ao_timer.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include + +#ifndef HAS_TICK +#define HAS_TICK 1 +#endif + +volatile AO_TICK_TYPE ao_tick_count; + +AO_TICK_TYPE +ao_time(void) +{ + return ao_tick_count; +} + +uint64_t +ao_time_ns(void) +{ + AO_TICK_TYPE before, after; + uint32_t val; + + do { + before = ao_tick_count; + val = stm_systick.val; + after = ao_tick_count; + } while (before != after); + + return (uint64_t) after * (1000000000ULL / AO_HERTZ) + + (uint64_t) val * (1000000000ULL / AO_SYSTICK); +} + +void stm_systick_isr(void) +{ + if (stm_systick.ctrl & (1 << STM_SYSTICK_CTRL_COUNTFLAG)) { + ++ao_tick_count; +// ao_task_check_alarm(); +#ifdef AO_TIMER_HOOK + AO_TIMER_HOOK; +#endif + } +} + +#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1) + +void +ao_timer_init(void) +{ + stm_systick.load = SYSTICK_RELOAD; + stm_systick.val = 0; + stm_systick.ctrl = ((1 << STM_SYSTICK_CTRL_ENABLE) | + (1 << STM_SYSTICK_CTRL_TICKINT) | + (STM_SYSTICK_CTRL_CLKSOURCE_HCLK_8 << STM_SYSTICK_CTRL_CLKSOURCE)); +// stm_nvic.shpr15_12 |= (uint32_t) AO_STM_NVIC_CLOCK_PRIORITY << 24; +} diff --git a/src/stm32f1/openocd-stm32f1 b/src/stm32f1/openocd-stm32f1 new file mode 100755 index 00000000..20b074ef --- /dev/null +++ b/src/stm32f1/openocd-stm32f1 @@ -0,0 +1,12 @@ +#!/bin/sh +#OPENOCD=openocd +#OPENOCD=/usr/bin/openocd +#OPENOCD=/local/src/openocd/src/openocd +OPENOCD=/local/bin/openocd +exec $OPENOCD \ + -f interface/stlink.cfg \ + -c 'transport select hla_swd' \ + -f target/stm32f1x.cfg -c init \ + -c 'reset halt' \ + -c 'stm32f1x.cpu arm semihosting enable' \ + "$@" diff --git a/src/stm32f1/registers.ld b/src/stm32f1/registers.ld new file mode 100644 index 00000000..b9431654 --- /dev/null +++ b/src/stm32f1/registers.ld @@ -0,0 +1,45 @@ +stm_crc = 0x40023000; +stm_flash = 0x40022000; +stm_rcc = 0x40021000; +stm_dma = 0x40020000; +stm_usart1 = 0x40013800; +stm_spi1 = 0x40013000; +stm_tim1 = 0x40012c00; +stm_adc2 = 0x40012800; +stm_adc1 = 0x40012400; +stm_gpioe = 0x40011800; +stm_gpiod = 0x40011400; +stm_gpioc = 0x40011000; +stm_gpiob = 0x40010c00; +stm_gpioa = 0x40010800; +stm_exti = 0x40010400; +stm_afio = 0x40010000; +stm_pwr = 0x40007000; +stm_bkp = 0x40006c00; +stm_bxcan = 0x40006400; +stm_usb_sram = 0x40006000; +stm_usb = 0x40005c00; +stm_i2c2 = 0x40005800; +stm_i2c1 = 0x40005400; +stm_usart3 = 0x40004800; +stm_usart2 = 0x40004400; +stm_spi2 = 0x40003800; +stm_iwdg = 0x40003000; +stm_wwdg = 0x40002c00; +stm_rtc = 0x40002800; +stm_tim4 = 0x40000800; +stm_tim3 = 0x40000400; +stm_tim2 = 0x40000000; + +stm_systick = 0xe000e010; + +stm_nvic = 0xe000e100; + +stm_scb = 0xe000ed00; + +stm_mpu = 0xe000ed90; + +stm_dbg_mcu = 0xe0042000; + +/* data in system memory */ +stm_flash_data = 0x1ffff7e0; diff --git a/src/stm32f1/stm32f1.h b/src/stm32f1/stm32f1.h new file mode 100644 index 00000000..5ac99e6c --- /dev/null +++ b/src/stm32f1/stm32f1.h @@ -0,0 +1,522 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _STM32F1_H_ +#define _STM32F1_H_ + +#include + +typedef volatile uint32_t vuint32_t; +typedef volatile uint16_t vuint16_t; +typedef volatile void * vvoid_t; + +struct stm_rcc { + vuint32_t cr; + vuint32_t cfgr; + vuint32_t cir; + vuint32_t apb2rstr; + + vuint32_t apb1rstr; + vuint32_t ahbenr; + vuint32_t apb2enr; + vuint32_t apb1enr; + + vuint32_t bdcr; + vuint32_t csr; + vuint32_t ahbstr; + vuint32_t cfgr2; +}; + +extern struct stm_rcc stm_rcc; + +//#define stm_rcc (*((struct stm_rcc *) 0x40021000)) + +#define STM_RCC_CR_RTCPRE (29) +#define STM_RCC_CR_RTCPRE_HSE_DIV_2 0 +#define STM_RCC_CR_RTCPRE_HSE_DIV_4 1 +#define STM_RCC_CR_RTCPRE_HSE_DIV_8 2 +#define STM_RCC_CR_RTCPRE_HSE_DIV_16 3 +#define STM_RCC_CR_RTCPRE_HSE_MASK 3UL + +#define STM_RCC_CR_PLL3RDY (29) +#define STM_RCC_CR_PLL3ON (28) +#define STM_RCC_CR_PLL2RDY (27) +#define STM_RCC_CR_PLL2ON (26) +#define STM_RCC_CR_PLLRDY (25) +#define STM_RCC_CR_PLLON (24) +#define STM_RCC_CR_CSSON (19) +#define STM_RCC_CR_HSEBYP (18) +#define STM_RCC_CR_HSERDY (17) +#define STM_RCC_CR_HSEON (16) +#define STM_RCC_CR_HSICAL (8) +#define STM_RCC_CR_HSITRIM (3) +#define STM_RCC_CR_HSIRDY (1) +#define STM_RCC_CR_HSION (0) + +#define STM_RCC_CFGR_MCOPRE (28) +#define STM_RCC_CFGR_MCOPRE_DIV_1 0 +#define STM_RCC_CFGR_MCOPRE_DIV_2 1 +#define STM_RCC_CFGR_MCOPRE_DIV_4 2 +#define STM_RCC_CFGR_MCOPRE_DIV_8 3 +#define STM_RCC_CFGR_MCOPRE_DIV_16 4 +#define STM_RCC_CFGR_MCOPRE_MASK 7UL + +#define STM_RCC_CFGR_MCO (24) +#define STM_RCC_CFGR_MCO_DISABLE 0 +#define STM_RCC_CFGR_MCO_SYSCLK 4 +#define STM_RCC_CFGR_MCO_HSI 5 +#define STM_RCC_CFGR_MCO_HSE 6 +#define STM_RCC_CFGR_MCO_PLL_2 7 +#define STM_RCC_CFGR_MCO_MASK 7UL + +#define STM_RCC_CFGR_USBPRE (22) +#define STM_RCC_CFGR_USBPRE_1_5 0 +#define STM_RCC_CFGR_USBPRE_1 1 + +#define STM_RCC_CFGR_PLLMUL (18) +#define STM_RCC_CFGR_PLLMUL_2 0 +#define STM_RCC_CFGR_PLLMUL_3 1 +#define STM_RCC_CFGR_PLLMUL_4 2 +#define STM_RCC_CFGR_PLLMUL_5 3 +#define STM_RCC_CFGR_PLLMUL_6 4 +#define STM_RCC_CFGR_PLLMUL_7 5 +#define STM_RCC_CFGR_PLLMUL_8 6 +#define STM_RCC_CFGR_PLLMUL_9 7 +#define STM_RCC_CFGR_PLLMUL_10 8 +#define STM_RCC_CFGR_PLLMUL_11 9 +#define STM_RCC_CFGR_PLLMUL_12 10 +#define STM_RCC_CFGR_PLLMUL_13 11 +#define STM_RCC_CFGR_PLLMUL_14 12 +#define STM_RCC_CFGR_PLLMUL_15 13 +#define STM_RCC_CFGR_PLLMUL_16 14 +#define STM_RCC_CFGR_PLLMUL_MASK 0xfUL + +#define STM_RCC_CFGR_PLLXTPRE (17) +#define STM_RCC_CFGR_PLLXTPRE_1 0 +#define STM_RCC_CFGR_PLLXTPRE_2 1 + +#define STM_RCC_CFGR_PLLSRC (16) +#define STM_RCC_CFGR_PLLSRC_HSI_2 0 +#define STM_RCC_CFGR_PLLSRC_HSE 1 + +#define STM_RCC_CFGR_ADCPRE (14) +#define STM_RCC_CFGR_ADCPRE_2 0 +#define STM_RCC_CFGR_ADCPRE_4 1 +#define STM_RCC_CFGR_ADCPRE_6 2 +#define STM_RCC_CFGR_ADCPRE_8 3 + +#define STM_RCC_CFGR_PPRE2 (11) +#define STM_RCC_CFGR_PPRE2_DIV_1 0 +#define STM_RCC_CFGR_PPRE2_DIV_2 4 +#define STM_RCC_CFGR_PPRE2_DIV_4 5 +#define STM_RCC_CFGR_PPRE2_DIV_8 6 +#define STM_RCC_CFGR_PPRE2_DIV_16 7 +#define STM_RCC_CFGR_PPRE2_MASK 7UL + +#define STM_RCC_CFGR_PPRE1 (8) +#define STM_RCC_CFGR_PPRE1_DIV_1 0 +#define STM_RCC_CFGR_PPRE1_DIV_2 4 +#define STM_RCC_CFGR_PPRE1_DIV_4 5 +#define STM_RCC_CFGR_PPRE1_DIV_8 6 +#define STM_RCC_CFGR_PPRE1_DIV_16 7 +#define STM_RCC_CFGR_PPRE1_MASK 7UL + +#define STM_RCC_CFGR_HPRE (4) +#define STM_RCC_CFGR_HPRE_DIV_1 0 +#define STM_RCC_CFGR_HPRE_DIV_2 8 +#define STM_RCC_CFGR_HPRE_DIV_4 9 +#define STM_RCC_CFGR_HPRE_DIV_8 0xa +#define STM_RCC_CFGR_HPRE_DIV_16 0xb +#define STM_RCC_CFGR_HPRE_DIV_64 0xc +#define STM_RCC_CFGR_HPRE_DIV_128 0xd +#define STM_RCC_CFGR_HPRE_DIV_256 0xe +#define STM_RCC_CFGR_HPRE_DIV_512 0xf +#define STM_RCC_CFGR_HPRE_MASK 0xfUL + +#define STM_RCC_CFGR_SWS (2) +#define STM_RCC_CFGR_SWS_HSI 0 +#define STM_RCC_CFGR_SWS_HSE 1 +#define STM_RCC_CFGR_SWS_PLL 2 +#define STM_RCC_CFGR_SWS_MASK 3UL + +#define STM_RCC_CFGR_SW (0) +#define STM_RCC_CFGR_SW_HSI 0 +#define STM_RCC_CFGR_SW_HSE 1 +#define STM_RCC_CFGR_SW_PLL 2 +#define STM_RCC_CFGR_SW_MASK 3UL + +#define STM_RCC_AHBENR_CRCEN 6 +#define STM_RCC_AHBENR_FLITFEN 4 +#define STM_RCC_AHBENR_SRAMEN 2 +#define STM_RCC_AHBENR_DMA2EN 1 +#define STM_RCC_AHBENR_DMA1EN 0 + + +#define STM_RCC_APB2ENR_USART1EN 14 +#define STM_RCC_APB2ENR_SPI1EN 12 +#define STM_RCC_APB2ENR_TIM1EN 11 +#define STM_RCC_APB2ENR_ADC2EN 10 +#define STM_RCC_APB2ENR_ADC1EN 9 +#define STM_RCC_APB2ENR_IOPEEN 6 +#define STM_RCC_APB2ENR_IOPDEN 5 +#define STM_RCC_APB2ENR_IOPCEN 4 +#define STM_RCC_APB2ENR_IOPBEN 3 +#define STM_RCC_APB2ENR_IOPAEN 2 +#define STM_RCC_APB2ENR_AFIOEN 0 + +#define STM_RCC_APB1ENR_DACEN 29 +#define STM_RCC_APB1ENR_PWREN 28 +#define STM_RCC_APB1ENR_BKPEN 27 +#define STM_RCC_APB1ENR_CAN2EN 26 +#define STM_RCC_APB1ENR_CAN1EN 25 +#define STM_RCC_APB1ENR_I2C2EN 22 +#define STM_RCC_APB1ENR_I2C1EN 21 +#define STM_RCC_APB1ENR_UART5EN 20 +#define STM_RCC_APB1ENR_UART4EN 19 +#define STM_RCC_APB1ENR_USART3EN 18 +#define STM_RCC_APB1ENR_USART2EN 17 +#define STM_RCC_APB1ENR_SPI3EN 15 +#define STM_RCC_APB1ENR_SPI2EN 14 +#define STM_RCC_APB1ENR_WWDGEN 11 +#define STM_RCC_APB1ENR_TIM7EN 5 +#define STM_RCC_APB1ENR_TIM6EN 4 +#define STM_RCC_APB1ENR_TIM5EN 3 +#define STM_RCC_APB1ENR_TIM4EN 2 +#define STM_RCC_APB1ENR_TIM3EN 1 +#define STM_RCC_APB1ENR_TIM2EN 0 + +#define STM_RCC_CSR_LPWRRSTF (31) +#define STM_RCC_CSR_WWDGRSTF (30) +#define STM_RCC_CSR_IWDGRSTF (29) +#define STM_RCC_CSR_SFTRSTF (28) +#define STM_RCC_CSR_PORRSTF (27) +#define STM_RCC_CSR_PINRSTF (26) +#define STM_RCC_CSR_RMVF (24) +#define STM_RCC_CSR_LSIRDY (1) +#define STM_RCC_CSR_LSION (0) + +struct stm_systick { + vuint32_t ctrl; + vuint32_t load; + vuint32_t val; + vuint32_t calib; +}; + +extern struct stm_systick stm_systick; + +#define stm_systick (*((struct stm_systick *) 0xe000e010)) + +#define STM_SYSTICK_CTRL_ENABLE 0 +#define STM_SYSTICK_CTRL_TICKINT 1 +#define STM_SYSTICK_CTRL_CLKSOURCE 2 +#define STM_SYSTICK_CTRL_CLKSOURCE_HCLK_8 0 +#define STM_SYSTICK_CTRL_CLKSOURCE_HCLK 1 +#define STM_SYSTICK_CTRL_COUNTFLAG 16 + +/* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */ + +struct stm_nvic { + vuint32_t iser[8]; /* 0x000 0xe000e100 Set Enable Register */ + + uint8_t _unused020[0x080 - 0x020]; + + vuint32_t icer[8]; /* 0x080 0xe000e180 Clear Enable Register */ + + uint8_t _unused0a0[0x100 - 0x0a0]; + + vuint32_t ispr[8]; /* 0x100 0xe000e200 Set Pending Register */ + + uint8_t _unused120[0x180 - 0x120]; + + vuint32_t icpr[8]; /* 0x180 0xe000e280 Clear Pending Register */ + + uint8_t _unused1a0[0x200 - 0x1a0]; + + vuint32_t iabr[8]; /* 0x200 0xe000e300 Active Bit Register */ + + uint8_t _unused220[0x300 - 0x220]; + + vuint32_t ipr[60]; /* 0x300 0xe000e400 Priority Register */ + + uint8_t _unused3f0[0xc00 - 0x3f0]; + + vuint32_t cpuid_base; /* 0xc00 0xe000ed00 CPUID Base Register */ + vuint32_t ics; /* 0xc04 0xe000ed04 Interrupt Control State Register */ + vuint32_t vto; /* 0xc08 0xe000ed08 Vector Table Offset Register */ + vuint32_t ai_rc; /* 0xc0c 0xe000ed0c Application Interrupt/Reset Control Register */ + vuint32_t sc; /* 0xc10 0xe000ed10 System Control Register */ + vuint32_t cc; /* 0xc14 0xe000ed14 Configuration Control Register */ + + vuint32_t shpr7_4; /* 0xc18 0xe000ed18 System Hander Priority Registers */ + vuint32_t shpr11_8; /* 0xc1c */ + vuint32_t shpr15_12; /* 0xc20 */ + + uint8_t _unusedc18[0xe00 - 0xc24]; + + vuint32_t stir; /* 0xe00 */ +}; + +extern struct stm_nvic stm_nvic; + +#define stm_nvic (*((struct stm_nvic *) 0xe000e100)) + +#define IRQ_REG(irq) ((irq) >> 5) +#define IRQ_BIT(irq) ((irq) & 0x1f) +#define IRQ_MASK(irq) (1 << IRQ_BIT(irq)) +#define IRQ_BOOL(v,irq) (((v) >> IRQ_BIT(irq)) & 1) + +static inline void +stm_nvic_set_enable(int irq) { + stm_nvic.iser[IRQ_REG(irq)] = IRQ_MASK(irq); +} + +static inline void +stm_nvic_clear_enable(int irq) { + stm_nvic.icer[IRQ_REG(irq)] = IRQ_MASK(irq); +} + +static inline int +stm_nvic_enabled(int irq) { + return IRQ_BOOL(stm_nvic.iser[IRQ_REG(irq)], irq); +} + +static inline void +stm_nvic_set_pending(int irq) { + stm_nvic.ispr[IRQ_REG(irq)] = IRQ_MASK(irq); +} + +static inline void +stm_nvic_clear_pending(int irq) { + stm_nvic.icpr[IRQ_REG(irq)] = IRQ_MASK(irq); +} + +static inline int +stm_nvic_pending(int irq) { + return IRQ_BOOL(stm_nvic.ispr[IRQ_REG(irq)], irq); +} + +static inline int +stm_nvic_active(int irq) { + return IRQ_BOOL(stm_nvic.iabr[IRQ_REG(irq)], irq); +} + +#define IRQ_PRIO_REG(irq) ((irq) >> 2) +#define IRQ_PRIO_BIT(irq) (((irq) & 3) << 3) +#define IRQ_PRIO_MASK(irq) (0xff << IRQ_PRIO_BIT(irq)) + +static inline void +stm_nvic_set_priority(int irq, uint8_t prio) { + int n = IRQ_PRIO_REG(irq); + uint32_t v; + + v = stm_nvic.ipr[n]; + v &= (uint32_t) ~IRQ_PRIO_MASK(irq); + v |= (prio) << IRQ_PRIO_BIT(irq); + stm_nvic.ipr[n] = v; +} + +static inline uint8_t +stm_nvic_get_priority(int irq) { + return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0); +} + +struct stm_flash_data { + vuint16_t f_size; + vuint16_t unused02; + vuint32_t unused04; + vuint32_t device_id[3]; +}; + +extern struct stm_flash_data stm_flash_data; + +static inline uint32_t stm_flash_size(void) { return (uint32_t) stm_flash_data.f_size * 1024; } + +#define stm_flash_data (*((struct stm_flash_data *) 0x1ffff7e0)) + +struct stm_gpio { + vuint32_t cr[2]; + vuint32_t idr; + vuint32_t odr; + + vuint32_t bsrr; + vuint32_t brr; + vuint32_t lckr; +}; + +#define STM_GPIO_CR(y) ((uint8_t) (y) >> 3) +#define STM_GPIO_CR_CNF(y) ((((uint8_t) (y) & 7) << 2) + 2) +#define STM_GPIO_CR_CNF_INPUT_ANALOG 0 +#define STM_GPIO_CR_CNF_INPUT_FLOATING 1 +#define STM_GPIO_CR_CNF_INPUT_PULL 2 +#define STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL 0 +#define STM_GPIO_CR_CNF_OUTPUT_OPEN_DRAIN 1 +#define STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL 2 +#define STM_GPIO_CR_CNF_OUTPUT_AF_OPEN_DRAIN 3 +#define STM_GPIO_CR_CNF_MASK 3U +#define STM_GPIO_CR_MODE(y) ((((y) & 7) << 2)) +#define STM_GPIO_CR_MODE_INPUT 0 +#define STM_GPIO_CR_MODE_OUTPUT_10MHZ 1 +#define STM_GPIO_CR_MODE_OUTPUT_2MHZ 2 +#define STM_GPIO_CR_MODE_OUTPUT_50MHZ 3 +#define STM_GPIO_CR_MODE_MASK 3U + +static inline void +stm_gpio_conf(struct stm_gpio *gpio, int pin, uint8_t mode, uint8_t cnf) +{ + uint8_t cr = STM_GPIO_CR(pin); + uint32_t v = gpio->cr[cr]; + + v &= ~((STM_GPIO_CR_CNF_MASK << STM_GPIO_CR_CNF(pin)) | + (STM_GPIO_CR_MODE_MASK << STM_GPIO_CR_MODE(pin))); + v |= (mode << STM_GPIO_CR_MODE(pin)) | (cnf << STM_GPIO_CR_CNF(pin)); + gpio->cr[cr] = v; +} + +static inline void +stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) { + /* Use the bit set/reset register to do this atomically */ + gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin); +} + +static inline void +stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) { + /* Use the bit set/reset register to do this atomically */ + gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask)); +} + +static inline void +stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) { + gpio->bsrr = bits; +} + +static inline void +stm_gpio_clr_bits(struct stm_gpio *gpio, uint16_t bits) { + gpio->bsrr = ((uint32_t) bits) << 16; +} + +static inline uint8_t +stm_gpio_get(struct stm_gpio *gpio, int pin) { + return (gpio->idr >> pin) & 1; +} + +static inline uint16_t +stm_gpio_get_all(struct stm_gpio *gpio) { + return (uint16_t) gpio->idr; +} + +extern struct stm_gpio stm_gpioa; +extern struct stm_gpio stm_gpiob; +extern struct stm_gpio stm_gpioc; +extern struct stm_gpio stm_gpiod; +extern struct stm_gpio stm_gpioe; + +#define stm_gpioe (*((struct stm_gpio *) 0x40011800)) +#define stm_gpiod (*((struct stm_gpio *) 0x40011400)) +#define stm_gpioc (*((struct stm_gpio *) 0x40011000)) +#define stm_gpiob (*((struct stm_gpio *) 0x40010c00)) +#define stm_gpioa (*((struct stm_gpio *) 0x40010800)) + +struct stm_afio { + vuint32_t evcr; + vuint32_t mapr; + vuint32_t exticr[4]; + vuint32_t mapr2; +}; + +extern struct stm_afio stm_afio; + +#define stm_afio (*((struct stm_afio *) 0x40010000)) + +#define isr_decl(name) void stm_ ## name ## _isr(void) + +isr_decl(halt); +isr_decl(ignore); + +isr_decl(nmi); +isr_decl(hardfault); +isr_decl(memmanage); +isr_decl(busfault); +isr_decl(usagefault); +isr_decl(svc); +isr_decl(debugmon); +isr_decl(pendsv); +isr_decl(systick); +isr_decl(wwdg); +isr_decl(pvd); +isr_decl(tamper_stamp); +isr_decl(rtc_wkup); +isr_decl(flash); +isr_decl(rcc); +isr_decl(exti0); +isr_decl(exti1); +isr_decl(exti2); +isr_decl(exti3); +isr_decl(exti4); +isr_decl(dma1_channel1); +isr_decl(dma1_channel2); +isr_decl(dma1_channel3); +isr_decl(dma1_channel4); +isr_decl(dma1_channel5); +isr_decl(dma1_channel6); +isr_decl(dma1_channel7); +isr_decl(adc1_2); +isr_decl(usb_hp); +isr_decl(usb_lp); +isr_decl(can_rx1); +isr_decl(can_sce); +isr_decl(exti9_5); +isr_decl(tim1_brk); +isr_decl(tim1_up); +isr_decl(tim1_trg_com); +isr_decl(tim1_cc); +isr_decl(tim2); +isr_decl(tim3); +isr_decl(tim4); +isr_decl(i2c1_ev); +isr_decl(i2c1_er); +isr_decl(i2c2_ev); +isr_decl(i2c2_er); +isr_decl(spi1); +isr_decl(spi2); +isr_decl(usart1); +isr_decl(usart2); +isr_decl(usart3); +isr_decl(exti15_10); +isr_decl(rtc_alarm); +isr_decl(usb_wakeup); +isr_decl(tim8_brk); +isr_decl(tim8_up); +isr_decl(tim8_trg_com); +isr_decl(tim8_cc); +isr_decl(adc3); +isr_decl(fsmc); +isr_decl(sdio); +isr_decl(tim5); +isr_decl(spi3); +isr_decl(uart4); +isr_decl(uart5); +isr_decl(tim6); +isr_decl(tim7); +isr_decl(dma2_channel1); +isr_decl(dma2_channel2); +isr_decl(dma2_channel3); +isr_decl(dma2_channel4_5); + +#undef isr_decl + +#endif diff --git a/src/stm32f103-nucleo/Makefile b/src/stm32f103-nucleo/Makefile new file mode 100644 index 00000000..3adc4acf --- /dev/null +++ b/src/stm32f103-nucleo/Makefile @@ -0,0 +1,39 @@ +include ../stm32f1/Makefile-raw.defs + +INC = \ + ao.h \ + ao_pins.h \ + ao_arch.h \ + ao_arch_funcs.h \ + stm32f1.h \ + Makefile + +ALTOS_SRC = \ + ao_clock.c \ + ao_timer.c \ + ao_interrupt.c \ + ao_led.c + +CFLAGS = $(PRODUCT_DEF) $(STM32F1_CFLAGS) + +PROGNAME=nucleo +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) hello.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) + $(call quiet,CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) --oslib=semihost + +$(OBJ): $(INC) + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stm32f103-nucleo/ao_pins.h b/src/stm32f103-nucleo/ao_pins.h new file mode 100644 index 00000000..37adc399 --- /dev/null +++ b/src/stm32f103-nucleo/ao_pins.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define AO_HSE 1 +#define AO_HSE_BYPASS 1 + +#define AO_SYSCLK 72000000 +#define AO_HCLK 72000000 +#define AO_APB1CLK 36000000 +#define AO_APB2CLK 72000000 +#define AO_ADCCLK 12000000 + +#define AO_RCC_CFGR_USBPRE STM_RCC_CFGR_USBPRE_1_5 +#define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_9 +#define AO_RCC_CFGR_PLLXTPRE STM_RCC_CFGR_PLLXTPRE_1 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_1 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE1_DIV_2 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 +#define AO_RCC_CFGR_ADCPRE STM_RCC_CFGR_ADCPRE_6 + +#define HAS_LED 1 +#define LED_0_PORT (&stm_gpioa) +#define LED_0_PIN 5 +#define AO_LED_GREEN (1 << 0) diff --git a/src/stm32f103-nucleo/hello.c b/src/stm32f103-nucleo/hello.c new file mode 100644 index 00000000..938afd2d --- /dev/null +++ b/src/stm32f103-nucleo/hello.c @@ -0,0 +1,38 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +void +ao_delay(AO_TICK_TYPE ticks) +{ + uint32_t then = ao_time(); + while ((int32_t) (ao_time() - then) < (int32_t) ticks) + ao_arch_nop(); +} + +int main(void) +{ + ao_clock_init(); + ao_timer_init(); + ao_led_init(); + for (;;) { + ao_led_for(AO_LED_GREEN, 50); + ao_delay(50); + } +} diff --git a/src/stm32f103-nucleo/hello.ld b/src/stm32f103-nucleo/hello.ld new file mode 100644 index 00000000..cc57e00c --- /dev/null +++ b/src/stm32f103-nucleo/hello.ld @@ -0,0 +1,7 @@ +__flash = 0x20000000; +__flash_size = 4k; +__ram = 0x20001000; +__ram_size = 4k; +__stack_size = 512; + +INCLUDE picolibc.ld -- 2.30.2