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 <keithp@keithp.com>
--- /dev/null
+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
--- /dev/null
+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)
--- /dev/null
+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
--- /dev/null
+__flash = 0x20000000;
+__flash_size = 12k;
+__ram = 0x20003000;
+__ram_size = 4k;
+__stack_size = 512;
+
+INCLUDE registers.ld
+INCLUDE picolibc.ld
--- /dev/null
+/*
+ * Copyright © 2018 Keith Packard <keithp@keithp.com>
+ *
+ * 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
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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 <stm32f1.h>
+
+#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_ */
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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_ */
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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
+}
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * 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 "stm32f1.h"
+#include <string.h>
+#include <ao_boot.h>
+
+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;
+}
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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 <ao_task.h>
+
+#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;
+}
--- /dev/null
+#!/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' \
+ "$@"
--- /dev/null
+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;
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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 <stdint.h>
+
+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
--- /dev/null
+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:
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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)
--- /dev/null
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * 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_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);
+ }
+}
--- /dev/null
+__flash = 0x20000000;
+__flash_size = 4k;
+__ram = 0x20001000;
+__ram_size = 4k;
+__stack_size = 512;
+
+INCLUDE picolibc.ld