--- /dev/null
+include $(TOPDIR)/stm/Makefile-stm.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_flash_pins.h \
+ ao_flash_stm_pins.h \
+ ao_flash_task.h \
+ ao_pins.h \
+ ao_product.h \
+ Makefile
+
+#
+# Common AltOS sources
+#
+SRC = \
+ ao_interrupt.c \
+ ao_romconfig.c \
+ ao_boot_chain.c \
+ ao_boot_pin.c \
+ ao_product.c \
+ ao_notask.c \
+ ao_timer.c \
+ ao_usb_stm.c \
+ ao_flash_stm.c \
+ ao_flash_task.c \
+ ao_flash_loader_stm.c
+
+OBJ=$(SRC:.c=.o)
+
+PRODUCT=AltosFlash
+PRODUCT_DEF=-DALTOS_FLASH
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos-loader.ld -n
+
+PROGNAME=altos-flash
+PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+
+$(PROG): Makefile $(OBJ) altos-loader.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+all: $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+# Disable floating-point support in printf to save space
+
+PICOLIBC_PRINTF_CFLAGS = -DPICOLIBC_INTEGER_PRINTF_SCANF
+
+include $(TOPDIR)/Makefile.defs
+
+vpath % $(TOPDIR)/stm32l0:$(AO_VPATH)
+
+CC=$(ARM_CC)
+
+STML0_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb \
+ -I$(TOPDIR)/stm32l0 $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/stm32l0/Makefile-stm32l0.defs
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32l0 -Taltos.ld
--- /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.
+ */
+
+__flash = 0x08000000;
+__flash_size = 12k;
+__storage = __flash + __flash_size;
+__storage_size = 16k - __flash_size;
+__ram = 0x20000000;
+__ram_size = 2k;
+__stack_size = 512;
+
+PROVIDE(__storage = __storage);
+PROVIDE(__storage_size = __storage_size);
+
+INCLUDE picolibc.ld
+INCLUDE stm32l0.ld
--- /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.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stdio.h>
+#include <stm32l0.h>
+
+/*
+ * STM32L0 definitions and code fragments for AltOS
+ */
+
+#ifndef AO_STACK_SIZE
+#define AO_STACK_SIZE 256
+#endif
+
+#define HAS_USB 0
+
+#define AO_PORT_TYPE uint16_t
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() \
+ (stm_scb.aircr = ((STM_SCB_AIRCR_VECTKEY_KEY << STM_SCB_AIRCR_VECTKEY) | \
+ (1 << STM_SCB_AIRCR_SYSRESETREQ)))
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
+
+#ifndef AO_SYSCLK
+#if AO_HSE
+#define AO_PLLSRC AO_HSE
+#else
+#define AO_PLLSRC STM_HSI_FREQ
+#endif
+
+#define AO_PLLVCO (AO_PLLSRC * AO_PLLMUL)
+#define AO_SYSCLK (AO_PLLVCO / AO_PLLDIV)
+#endif
+
+#define AO_HCLK (AO_SYSCLK / AO_AHB_PRESCALER)
+#define AO_FCLK AO_HCLK
+#define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER)
+#define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER)
+#define AO_SYSTICK (AO_HCLK / 8)
+
+#if AO_APB1_PRESCALER == 1
+#define AO_TIM23467_CLK AO_PCLK1
+#else
+#define AO_TIM23467_CLK (2 * AO_PCLK1)
+#endif
+
+#if AO_APB2_PRESCALER == 1
+#define AO_TIM91011_CLK AO_PCLK2
+#else
+#define AO_TIM91011_CLK (2 * AO_PCLK2)
+#endif
+
+/* The stm32l implements only 4 bits of the priority fields */
+
+#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
+
+void ao_lcd_stm_init(void);
+
+void ao_lcd_font_init(void);
+
+void ao_lcd_font_string(char *s);
+
+extern const uint32_t ao_radio_cal;
+
+void
+ao_adc_init(void);
+
+/* ADC maximum reported value */
+#define AO_ADC_MAX 4095
+
+#define HAS_BOOT_LOADER 0
+
+#ifndef AO_LED_TYPE
+#define AO_LED_TYPE uint16_t
+#endif
+
+#endif /* _AO_ARCH_H_ */
+
+
--- /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.
+ */
+
+#ifndef _AO_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+/* ao_spi_stm.c
+ */
+
+/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */
+
+#define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2
+#define AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
+#define AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
+#define AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
+#define AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
+#define AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
+#define AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
+#define AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
+
+#define AO_SPI_SPEED_FAST AO_SPI_SPEED_8MHz
+
+/* Companion bus wants something no faster than 200kHz */
+
+#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_125kHz
+
+#define AO_SPI_CPOL_BIT 4
+#define AO_SPI_CPHA_BIT 5
+
+#define AO_SPI_CONFIG_1 0x00
+#define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1
+#define AO_SPI_2_CONFIG_PB13_PB14_PB15 AO_SPI_CONFIG_1
+
+#define AO_SPI_CONFIG_2 0x04
+#define AO_SPI_1_CONFIG_PB3_PB4_PB5 AO_SPI_CONFIG_2
+#define AO_SPI_2_CONFIG_PD1_PD3_PD4 AO_SPI_CONFIG_2
+
+#define AO_SPI_CONFIG_3 0x08
+#define AO_SPI_1_CONFIG_PE13_PE14_PE15 AO_SPI_CONFIG_3
+
+#define AO_SPI_CONFIG_NONE 0x0c
+
+#define AO_SPI_INDEX_MASK 0x01
+#define AO_SPI_CONFIG_MASK 0x0c
+
+#define AO_SPI_1_PA5_PA6_PA7 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PA5_PA6_PA7)
+#define AO_SPI_1_PB3_PB4_PB5 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PB3_PB4_PB5)
+#define AO_SPI_1_PE13_PE14_PE15 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PE13_PE14_PE15)
+
+#define AO_SPI_2_PB13_PB14_PB15 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PB13_PB14_PB15)
+#define AO_SPI_2_PD1_PD3_PD4 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PD1_PD3_PD4)
+
+#define AO_SPI_INDEX(id) ((id) & AO_SPI_INDEX_MASK)
+#define AO_SPI_CONFIG(id) ((id) & AO_SPI_CONFIG_MASK)
+#define AO_SPI_PIN_CONFIG(id) ((id) & (AO_SPI_INDEX_MASK | AO_SPI_CONFIG_MASK))
+#define AO_SPI_CPOL(id) ((uint32_t) (((id) >> AO_SPI_CPOL_BIT) & 1))
+#define AO_SPI_CPHA(id) ((uint32_t) (((id) >> AO_SPI_CPHA_BIT) & 1))
+
+#define AO_SPI_MAKE_MODE(pol,pha) (((pol) << AO_SPI_CPOL_BIT) | ((pha) << AO_SPI_CPHA_BIT))
+#define AO_SPI_MODE_0 AO_SPI_MAKE_MODE(0,0)
+#define AO_SPI_MODE_1 AO_SPI_MAKE_MODE(0,1)
+#define AO_SPI_MODE_2 AO_SPI_MAKE_MODE(1,0)
+#define AO_SPI_MODE_3 AO_SPI_MAKE_MODE(1,1)
+
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id);
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_start_bytes(uint8_t spi_index);
+
+void
+ao_spi_stop_bytes(uint8_t spi_index);
+
+static inline void
+ao_spi_send_byte(uint8_t byte, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi;
+
+ switch (AO_SPI_INDEX(spi_index)) {
+ case 0:
+ stm_spi = &stm_spi1;
+ break;
+ case 1:
+ stm_spi = &stm_spi2;
+ break;
+ }
+
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)))
+ ;
+ stm_spi->dr = byte;
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)))
+ ;
+ (void) stm_spi->dr;
+}
+
+static inline uint8_t
+ao_spi_recv_byte(uint8_t spi_index)
+{
+ struct stm_spi *stm_spi;
+
+ switch (AO_SPI_INDEX(spi_index)) {
+ case 0:
+ stm_spi = &stm_spi1;
+ break;
+ case 1:
+ stm_spi = &stm_spi2;
+ break;
+ }
+
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)))
+ ;
+ stm_spi->dr = 0xff;
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)))
+ ;
+ return stm_spi->dr;
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index);
+
+extern uint16_t ao_spi_speed[STM_NUM_SPI];
+
+void
+ao_spi_init(void);
+
+#define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16)
+#define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask))
+
+#define ao_spi_get_mask(reg,mask,bus, speed) do { \
+ ao_spi_get(bus, speed); \
+ ao_spi_set_cs(reg,mask); \
+ } while (0)
+
+static inline uint8_t
+ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t speed, uint8_t task_id)
+{
+ if (!ao_spi_try_get(bus, speed, task_id))
+ return 0;
+ ao_spi_set_cs(reg, mask);
+ return 1;
+}
+
+#define ao_spi_put_mask(reg,mask,bus) do { \
+ ao_spi_clr_cs(reg,mask); \
+ ao_spi_put(bus); \
+ } while (0)
+
+#define ao_spi_get_bit(reg,bit,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+#define ao_enable_port(port) do { \
+ if ((port) == &stm_gpioa) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPAEN); \
+ else if ((port) == &stm_gpiob) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPBEN); \
+ else if ((port) == &stm_gpioc) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPCEN); \
+ else if ((port) == &stm_gpiod) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPDEN); \
+ else if ((port) == &stm_gpioe) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPEEN); \
+ else if ((port) == &stm_gpioh) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPHEN); \
+ } while (0)
+
+#define ao_disable_port(port) do { \
+ if ((port) == &stm_gpioa) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPAEN); \
+ else if ((port) == &stm_gpiob) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPBEN); \
+ else if ((port) == &stm_gpioc) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPCEN); \
+ else if ((port) == &stm_gpiod) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPDEN); \
+ else if ((port) == &stm_gpioe) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPEEN); \
+ else if ((port) == &stm_gpioh) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPHEN); \
+ } while (0)
+
+
+#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)
+
+#define ao_enable_output(port,bit,v) do { \
+ ao_enable_port(port); \
+ ao_gpio_set(port, bit, v); \
+ stm_moder_set(port, bit, STM_MODER_OUTPUT);\
+ } while (0)
+
+#define ao_enable_output_mask(port,bits,mask) do { \
+ ao_enable_port(port); \
+ ao_gpio_set_mask(port, bits, mask); \
+ ao_set_output_mask(port, mask); \
+ } while (0)
+
+#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL
+#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN
+
+#define ao_gpio_set_output_mode(port,bit,mode) \
+ stm_otyper_set(port, pin, mode)
+
+#define ao_gpio_set_mode(port,bit,mode) do { \
+ if (mode == AO_EXTI_MODE_PULL_UP) \
+ stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \
+ else if (mode == AO_EXTI_MODE_PULL_DOWN) \
+ stm_pupdr_set(port, bit, STM_PUPDR_PULL_DOWN); \
+ else \
+ stm_pupdr_set(port, bit, STM_PUPDR_NONE); \
+ } while (0)
+
+#define ao_gpio_set_mode_mask(port,mask,mode) do { \
+ if (mode == AO_EXTI_MODE_PULL_UP) \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \
+ else if (mode == AO_EXTI_MODE_PULL_DOWN) \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \
+ else \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE); \
+ } while (0)
+
+#define ao_set_input(port, bit) do { \
+ stm_moder_set(port, bit, STM_MODER_INPUT); \
+ } while (0)
+
+#define ao_set_output(port, bit, v) do { \
+ ao_gpio_set(port, bit, v); \
+ stm_moder_set(port, bit, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_set_output_mask(port, mask) do { \
+ stm_moder_set_mask(port, mask, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_set_input_mask(port, mask) do { \
+ stm_moder_set_mask(port, mask, STM_MODER_INPUT); \
+ } while (0)
+
+#define ao_enable_input(port,bit,mode) do { \
+ ao_enable_port(port); \
+ ao_set_input(port, bit); \
+ ao_gpio_set_mode(port, bit, mode); \
+ } while (0)
+
+#define ao_enable_input_mask(port,mask,mode) do { \
+ ao_enable_port(port); \
+ ao_gpio_set_mode_mask(port, mask, mode); \
+ ao_set_input_mask(port, mask); \
+ } while (0)
+
+#define _ao_enable_cs(port, bit) do { \
+ stm_gpio_set((port), bit, 1); \
+ stm_moder_set((port), bit, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_enable_cs(port,bit) do { \
+ ao_enable_port(port); \
+ _ao_enable_cs(port, bit); \
+ } while (0)
+
+#define ao_spi_init_cs(port, mask) do { \
+ ao_enable_port(port); \
+ if ((mask) & 0x0001) _ao_enable_cs(port, 0); \
+ if ((mask) & 0x0002) _ao_enable_cs(port, 1); \
+ if ((mask) & 0x0004) _ao_enable_cs(port, 2); \
+ if ((mask) & 0x0008) _ao_enable_cs(port, 3); \
+ if ((mask) & 0x0010) _ao_enable_cs(port, 4); \
+ if ((mask) & 0x0020) _ao_enable_cs(port, 5); \
+ if ((mask) & 0x0040) _ao_enable_cs(port, 6); \
+ if ((mask) & 0x0080) _ao_enable_cs(port, 7); \
+ if ((mask) & 0x0100) _ao_enable_cs(port, 8); \
+ if ((mask) & 0x0200) _ao_enable_cs(port, 9); \
+ if ((mask) & 0x0400) _ao_enable_cs(port, 10);\
+ if ((mask) & 0x0800) _ao_enable_cs(port, 11);\
+ if ((mask) & 0x1000) _ao_enable_cs(port, 12);\
+ if ((mask) & 0x2000) _ao_enable_cs(port, 13);\
+ if ((mask) & 0x4000) _ao_enable_cs(port, 14);\
+ if ((mask) & 0x8000) _ao_enable_cs(port, 15);\
+ } while (0)
+
+/* ao_dma_stm.c
+ */
+
+extern uint8_t ao_dma_done[STM_NUM_DMA];
+
+void
+ao_dma_set_transfer(uint8_t index,
+ volatile void *peripheral,
+ void *memory,
+ uint16_t count,
+ uint32_t ccr);
+
+void
+ao_dma_set_isr(uint8_t index, void (*isr)(int index));
+
+void
+ao_dma_start(uint8_t index);
+
+void
+ao_dma_done_transfer(uint8_t index);
+
+void
+ao_dma_alloc(uint8_t index);
+
+void
+ao_dma_init(void);
+
+/* ao_i2c_stm.c */
+
+void
+ao_i2c_get(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_start(uint8_t i2c_index, uint16_t address);
+
+void
+ao_i2c_put(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
+
+uint8_t
+ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
+
+void
+ao_i2c_init(void);
+
+#if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW
+#define HAS_SERIAL_SW_FLOW 1
+#else
+#define HAS_SERIAL_SW_FLOW 0
+#endif
+
+#if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW
+#define HAS_SERIAL_HW_FLOW 1
+#else
+#define HAS_SERIAL_HW_FLOW 0
+#endif
+
+/* ao_serial_stm.c */
+struct ao_stm_usart {
+ struct ao_fifo rx_fifo;
+ struct ao_fifo tx_fifo;
+ struct stm_usart *reg;
+ uint8_t tx_running;
+ uint8_t draining;
+#if HAS_SERIAL_SW_FLOW
+ /* RTS - 0 if we have FIFO space, 1 if not
+ * CTS - 0 if we can send, 0 if not
+ */
+ struct stm_gpio *gpio_rts;
+ struct stm_gpio *gpio_cts;
+ uint8_t pin_rts;
+ uint8_t pin_cts;
+ uint8_t rts;
+#endif
+};
+
+void
+ao_debug_out(char c);
+
+#if HAS_SERIAL_1
+extern struct ao_stm_usart ao_stm_usart1;
+#endif
+
+#if HAS_SERIAL_2
+extern struct ao_stm_usart ao_stm_usart2;
+#endif
+
+#if HAS_SERIAL_3
+extern struct ao_stm_usart ao_stm_usart3;
+#endif
+
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+typedef uint32_t ao_arch_irq_t;
+
+static inline void
+ao_arch_block_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+ asm("cpsid i");
+#endif
+}
+
+static inline void
+ao_arch_release_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (0x0));
+#else
+ asm("cpsie i");
+#endif
+}
+
+static inline uint32_t
+ao_arch_irqsave(void) {
+ uint32_t val;
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("mrs %0,basepri" : "=r" (val));
+#else
+ asm("mrs %0,primask" : "=r" (val));
+#endif
+ ao_arch_block_interrupts();
+ return val;
+}
+
+static inline void
+ao_arch_irqrestore(uint32_t basepri) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (basepri));
+#else
+ asm("msr primask,%0" : : "r" (basepri));
+#endif
+}
+
+static inline void
+ao_arch_memory_barrier(void) {
+ asm volatile("" ::: "memory");
+}
+
+static inline void
+ao_arch_irq_check(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ uint32_t basepri;
+ asm("mrs %0,basepri" : "=r" (basepri));
+ if (basepri == 0)
+ ao_panic(AO_PANIC_IRQ);
+#else
+ uint32_t primask;
+ asm("mrs %0,primask" : "=r" (primask));
+ if ((primask & 1) == 0)
+ ao_panic(AO_PANIC_IRQ);
+#endif
+}
+
+#if HAS_TASK
+static inline void
+ao_arch_init_stack(struct ao_task *task, void *start)
+{
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
+ uint32_t a = (uint32_t) start;
+ int i;
+
+ /* Return address (goes into LR) */
+ ARM_PUSH32(sp, a);
+
+ /* Clear register values r0-r7 */
+ i = 8;
+ while (i--)
+ ARM_PUSH32(sp, 0);
+
+ /* APSR */
+ ARM_PUSH32(sp, 0);
+
+ /* PRIMASK with interrupts enabled */
+ ARM_PUSH32(sp, 0);
+
+ task->sp32 = sp;
+}
+
+static inline void ao_arch_save_regs(void) {
+ /* Save general registers */
+ asm("push {r0-r7,lr}\n");
+
+ /* Save APSR */
+ asm("mrs r0,apsr");
+ asm("push {r0}");
+
+ /* Save PRIMASK */
+ asm("mrs r0,primask");
+ asm("push {r0}");
+}
+
+static inline void ao_arch_save_stack(void) {
+ uint32_t *sp;
+ asm("mov %0,sp" : "=&r" (sp) );
+ ao_cur_task->sp32 = (sp);
+}
+
+static inline void ao_arch_restore_stack(void) {
+ /* Switch stacks */
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
+
+ /* Restore PRIMASK */
+ asm("pop {r0}");
+ asm("msr primask,r0");
+
+ /* Restore APSR */
+ asm("pop {r0}");
+ asm("msr apsr_nczvq,r0");
+
+ /* Restore general registers */
+ asm("pop {r0-r7,pc}\n");
+}
+
+#ifndef HAS_SAMPLE_PROFILE
+#define HAS_SAMPLE_PROFILE 0
+#endif
+
+#if DEBUG
+#define HAS_ARCH_VALIDATE_CUR_STACK 1
+
+static inline void
+ao_validate_cur_stack(void)
+{
+ uint8_t *psp;
+
+ asm("mrs %0,psp" : "=&r" (psp));
+ if (ao_cur_task &&
+ psp <= ao_cur_task->stack &&
+ psp >= ao_cur_task->stack - 256)
+ ao_panic(AO_PANIC_STACK);
+}
+#endif
+
+#if !HAS_SAMPLE_PROFILE
+#define HAS_ARCH_START_SCHEDULER 1
+
+static inline void ao_arch_start_scheduler(void) {
+ uint32_t sp;
+ uint32_t control;
+
+ asm("mrs %0,msp" : "=&r" (sp));
+ asm("msr psp,%0" : : "r" (sp));
+ asm("mrs %0,control" : "=r" (control));
+ control |= (1 << 1);
+ asm("msr control,%0" : : "r" (control));
+ asm("isb");
+}
+#endif
+
+#define ao_arch_isr_stack()
+
+#endif
+
+static inline void
+ao_arch_wait_interrupt(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm(
+ "dsb\n" /* Serialize data */
+ "isb\n" /* Serialize instructions */
+ "cpsid i\n" /* Block all interrupts */
+ "msr basepri,%0\n" /* Allow all interrupts through basepri */
+ "wfi\n" /* Wait for an interrupt */
+ "cpsie i\n" /* Allow all interrupts */
+ "msr basepri,%1\n" /* Block interrupts through basepri */
+ : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+ asm("\twfi\n");
+ ao_arch_release_interrupts();
+ ao_arch_block_interrupts();
+#endif
+}
+
+#define ao_arch_critical(b) do { \
+ uint32_t __mask = ao_arch_irqsave(); \
+ do { b } while (0); \
+ ao_arch_irqrestore(__mask); \
+ } while (0)
+
+void start(void);
+
+#endif /* _AO_ARCH_FUNCS_H_ */
--- /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"
+
+#define NUM_DMA 7
+
+struct ao_dma_config {
+ void (*isr)(int index);
+};
+
+uint8_t ao_dma_done[NUM_DMA];
+
+static struct ao_dma_config ao_dma_config[NUM_DMA];
+static uint8_t ao_dma_allocated[NUM_DMA];
+static uint8_t ao_dma_mutex[NUM_DMA];
+
+static void
+ao_dma_isr(uint8_t index) {
+ /* Get channel interrupt bits */
+ uint32_t isr = stm_dma.isr & (STM_DMA_ISR_MASK <<
+ STM_DMA_ISR(index));
+
+ /* Ack them */
+ stm_dma.ifcr = isr;
+ if (ao_dma_config[index].isr)
+ (*ao_dma_config[index].isr)(index);
+ else {
+ ao_dma_done[index] = 1;
+ ao_wakeup(&ao_dma_done[index]);
+ }
+}
+
+void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); }
+void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); }
+#ifdef STM_DMA1_3_STOLEN
+#define LEAVE_DMA_ON
+#else
+void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); }
+#endif
+void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); }
+#ifdef STM_DMA1_5_STOLEN
+#define LEAVE_DMA_ON
+#else
+void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); }
+#endif
+void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); }
+void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); }
+
+#ifndef LEAVE_DMA_ON
+static uint8_t ao_dma_active;
+#endif
+
+void
+ao_dma_set_transfer(uint8_t index,
+ volatile void *peripheral,
+ void *memory,
+ uint16_t count,
+ uint32_t ccr)
+{
+ if (ao_dma_allocated[index]) {
+ if (ao_dma_mutex[index])
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_mutex[index] = 0xff;
+ } else
+ ao_mutex_get(&ao_dma_mutex[index]);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (ao_dma_active++ == 0)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
+ stm_dma.channel[index].cndtr = count;
+ stm_dma.channel[index].cpar = peripheral;
+ stm_dma.channel[index].cmar = memory;
+ ao_dma_config[index].isr = NULL;
+}
+
+void
+ao_dma_set_isr(uint8_t index, void (*isr)(int))
+{
+ ao_dma_config[index].isr = isr;
+}
+
+void
+ao_dma_start(uint8_t index)
+{
+ ao_dma_done[index] = 0;
+ stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN);
+}
+
+void
+ao_dma_done_transfer(uint8_t index)
+{
+ stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (--ao_dma_active == 0)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ if (ao_dma_allocated[index])
+ ao_dma_mutex[index] = 0;
+ else
+ ao_mutex_put(&ao_dma_mutex[index]);
+}
+
+void
+ao_dma_alloc(uint8_t index)
+{
+ if (ao_dma_allocated[index])
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_allocated[index] = 1;
+}
+
+#if DEBUG
+void
+ao_dma_dump_cmd(void)
+{
+ int i;
+
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (ao_dma_active++ == 0)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.ifcr);
+ for (i = 0; i < NUM_DMA; i++)
+ printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n",
+ i,
+ ao_dma_done[i],
+ ao_dma_allocated[i],
+ ao_dma_mutex[i],
+ stm_dma.channel[i].ccr,
+ stm_dma.channel[i].cndtr,
+ stm_dma.channel[i].cpar,
+ stm_dma.channel[i].cmar,
+ ao_dma_config[i].isr);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (--ao_dma_active == 0)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+}
+
+static const struct ao_cmds ao_dma_cmds[] = {
+ { ao_dma_dump_cmd, "D\0Dump DMA status" },
+ { 0, NULL }
+};
+#endif
+
+void
+ao_dma_init(void)
+{
+ int index;
+
+#ifdef LEAVE_DMA_ON
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+#endif
+ for (index = 0; index < STM_NUM_DMA; index++) {
+#if STM_DMA1_5_STOLEN
+ if (index == STM_DMA_INDEX(5)) {
+ ao_dma_allocated[index] = 1;
+ ao_dma_mutex[index] = 0xff;
+ continue;
+ }
+#endif
+#if STM_DMA1_3_STOLEN
+ if (index == STM_DMA_INDEX(3)) {
+ ao_dma_allocated[index] = 1;
+ ao_dma_mutex[index] = 0xff;
+ continue;
+ }
+#endif
+ stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index);
+ stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index,
+ AO_STM_NVIC_MED_PRIORITY);
+ ao_dma_allocated[index] = 0;
+ ao_dma_mutex[index] = 0;
+ }
+#if DEBUG
+ ao_cmd_register(&ao_dma_cmds[0]);
+#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.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING 1
+#define AO_EXTI_MODE_FALLING 2
+#define AO_EXTI_MODE_PULL_NONE 0
+#define AO_EXTI_MODE_PULL_UP 4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW 16
+#define AO_EXTI_PRIORITY_MED 0
+#define AO_EXTI_PRIORITY_HIGH 32
+#define AO_EXTI_PIN_NOCONFIGURE 64
+
+void
+ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void));
+
+void
+ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode);
+
+void
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void));
+
+void
+ao_exti_enable(struct stm_gpio *gpio, uint8_t pin);
+
+void
+ao_exti_disable(struct stm_gpio *gpio, uint8_t pin);
+
+void
+ao_exti_init(void);
+
+#endif /* _AO_EXTI_H_ */
--- /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 <ao_exti.h>
+
+static void (*ao_exti_callback[16])(void);
+
+uint32_t ao_last_exti;
+
+static void ao_exti_one_isr(uint8_t pin) {
+ uint32_t pending = (ao_last_exti = stm_exti.pr) & (1 << pin);
+
+ stm_exti.pr = pending;
+ if (pending && ao_exti_callback[pin])
+ (*ao_exti_callback[pin])();
+}
+
+static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) {
+ uint16_t pending = (ao_last_exti = stm_exti.pr) & mask;
+ uint8_t pin;
+ static uint16_t last_mask;
+ static uint8_t last_pin;
+
+ if (pending == last_mask) {
+ stm_exti.pr = last_mask;
+ (*ao_exti_callback[last_pin])();
+ return;
+ }
+ stm_exti.pr = pending;
+ for (pin = first; pin <= last; pin++)
+ if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) {
+ last_mask = (1 << pin);
+ last_pin = pin;
+ (*ao_exti_callback[pin])();
+ }
+}
+
+void stm_exti0_isr(void) { ao_exti_one_isr(0); }
+void stm_exti1_isr(void) { ao_exti_one_isr(1); }
+void stm_exti2_isr(void) { ao_exti_one_isr(2); }
+void stm_exti3_isr(void) { ao_exti_one_isr(3); }
+void stm_exti4_isr(void) { ao_exti_one_isr(4); }
+void stm_exti9_5_isr(void) { ao_exti_range_isr(5, 9, 0x3e0); }
+void stm_exti15_10_isr(void) { ao_exti_range_isr(10, 15, 0xfc00); }
+
+void
+ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+ uint32_t mask = 1 << pin;
+ uint32_t pupdr;
+ uint8_t irq;
+ uint8_t prio;
+
+ ao_exti_callback[pin] = callback;
+
+ /* configure gpio to interrupt routing */
+ stm_exticr_set(gpio, pin);
+
+ if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+ /* configure pin as input, setting selected pull-up/down mode */
+ stm_moder_set(gpio, pin, STM_MODER_INPUT);
+ switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
+ case 0:
+ default:
+ pupdr = STM_PUPDR_NONE;
+ break;
+ case AO_EXTI_MODE_PULL_UP:
+ pupdr = STM_PUPDR_PULL_UP;
+ break;
+ case AO_EXTI_MODE_PULL_DOWN:
+ pupdr = STM_PUPDR_PULL_DOWN;
+ break;
+ }
+ stm_pupdr_set(gpio, pin, pupdr);
+ }
+
+ /* Set interrupt mask and rising/falling mode */
+ stm_exti.imr &= ~mask;
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+
+ if (pin <= 4)
+ irq = STM_ISR_EXTI0_POS + pin;
+ else if (pin <= 9)
+ irq = STM_ISR_EXTI9_5_POS;
+ else
+ irq = STM_ISR_EXTI15_10_POS;
+
+ /* Set priority */
+ prio = AO_STM_NVIC_MED_PRIORITY;
+ if (mode & AO_EXTI_PRIORITY_LOW)
+ prio = AO_STM_NVIC_LOW_PRIORITY;
+ else if (mode & AO_EXTI_PRIORITY_HIGH)
+ prio = AO_STM_NVIC_HIGH_PRIORITY;
+
+ stm_nvic_set_priority(irq, prio);
+ stm_nvic_set_enable(irq);
+}
+
+void
+ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) {
+ (void) gpio;
+
+ uint32_t mask = 1 << pin;
+
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+}
+
+void
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void)) {
+ (void) gpio;
+ ao_exti_callback[pin] = callback;
+}
+
+void
+ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.pr = mask;
+ stm_exti.imr |= mask;
+}
+
+void
+ao_exti_disable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.imr &= ~mask;
+ stm_exti.pr = mask;
+}
+
+void
+ao_exti_init(void)
+{
+}
--- /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 <string.h>
+#include <ao_boot.h>
+
+/* Interrupt functions */
+
+void stm_halt_isr(void)
+{
+ ao_panic(AO_PANIC_CRASH);
+}
+
+void stm_ignore_isr(void)
+{
+}
+
+void _start(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(rtc)
+isr(flash)
+isr(rcc_crs)
+isr(exti1_0)
+isr(exti3_2)
+isr(exti15_4)
+isr(dma1_channel1)
+isr(dma1_channel3_2)
+isr(dma1_channel7_4)
+isr(adc_comp)
+isr(lptim1)
+isr(usart4_usart5)
+isr(tim2)
+isr(tim3)
+isr(tim4)
+isr(tim6)
+isr(tim7)
+isr(tim21)
+isr(i2c3)
+isr(tim22)
+isr(i2c1)
+isr(i2c2)
+isr(spi1)
+isr(spi2)
+isr(usart1)
+isr(usart2)
+isr(usart3)
+isr(lpuart1_aes)
+
+#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
+
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+void main(void) __attribute__((__noreturn__));
+
+__attribute__ ((section(".init")))
+const void *const __interrupt_vector[] = {
+ [0] = &__stack,
+ [1] = _start,
+ i(0x08, nmi),
+ i(0x0c, hardfault),
+ i(0x2c, svc),
+ i(0x38, pendsv),
+ i(0x3c, systick),
+ i(0x40, wwdg),
+ i(0x44, pvd),
+ i(0x48, rtc),
+ i(0x4c, flash),
+ i(0x50, rcc_crs),
+ i(0x54, exti1_0),
+ i(0x58, exti3_2),
+ i(0x5c, exti15_4),
+ i(0x64, dma1_channel1),
+ i(0x68, dma1_channel3_2),
+ i(0x6c, dma1_channel7_4),
+ i(0x70, adc_comp),
+ i(0x74, lptim1),
+ i(0x78, usart4_usart5),
+ i(0x7c, tim2),
+ i(0x80, tim3),
+ i(0x84, tim6),
+ i(0x88, tim7),
+ i(0x90, tim21),
+ i(0x94, i2c3),
+ i(0x98, tim22),
+ i(0x9c, i2c1),
+ i(0xa0, i2c2),
+ i(0xa4, spi1),
+ i(0xa8, spi2),
+ i(0xac, usart1),
+ i(0xb0, usart2),
+ i(0xb4, lpuart1_aes),
+};
+
+extern char __data_source[];
+extern char __data_start[];
+extern char __data_size[];
+extern char __bss_start[];
+extern char __bss_size[];
+
+void _start(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
+ memcpy(__data_start, __data_source, (uintptr_t) __data_size);
+ memset(__bss_start, '\0', (uintptr_t) __bss_size);
+
+ main();
+}
--- /dev/null
+/*
+ * Copyright © 2015 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_pwm.h"
+
+static uint8_t pwm_running;
+
+static uint16_t pwm_value[NUM_PWM];
+
+static void
+ao_pwm_up(void)
+{
+ if (pwm_running++ == 0) {
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ tim->ccr1 = 0;
+ tim->ccr2 = 0;
+ tim->ccr3 = 0;
+ tim->ccr4 = 0;
+ tim->arr = PWM_MAX - 1; /* turn on the timer */
+ tim->cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+ (0 << STM_TIM234_CR1_ARPE) |
+ (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+ (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+ (0 << STM_TIM234_CR1_OPM) |
+ (0 << STM_TIM234_CR1_URS) |
+ (0 << STM_TIM234_CR1_UDIS) |
+ (1 << STM_TIM234_CR1_CEN));
+
+ /* Set the timer running */
+ tim->egr = (1 << STM_TIM234_EGR_UG);
+ }
+}
+
+static void
+ao_pwm_down(void)
+{
+ if (--pwm_running == 0) {
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ tim->arr = 0;
+ tim->cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+ (0 << STM_TIM234_CR1_ARPE) |
+ (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+ (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+ (0 << STM_TIM234_CR1_OPM) |
+ (0 << STM_TIM234_CR1_URS) |
+ (0 << STM_TIM234_CR1_UDIS) |
+ (0 << STM_TIM234_CR1_CEN));
+
+ /* Stop the timer */
+ tim->egr = (1 << STM_TIM234_EGR_UG);
+ }
+}
+
+void
+ao_pwm_set(uint8_t pwm, uint16_t value)
+{
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ if (value > PWM_MAX)
+ value = PWM_MAX;
+ if (value != 0) {
+ if (pwm_value[pwm] == 0)
+ ao_pwm_up();
+ }
+ switch (pwm) {
+ case 0:
+ tim->ccr1 = value;
+ break;
+ case 1:
+ tim->ccr2 = value;
+ break;
+ case 2:
+ tim->ccr3 = value;
+ break;
+ case 3:
+ tim->ccr4 = value;
+ break;
+ }
+ if (value == 0) {
+ if (pwm_value[pwm] != 0)
+ ao_pwm_down();
+ }
+ pwm_value[pwm] = value;
+}
+
+static void
+ao_pwm_cmd(void)
+{
+ uint8_t ch;
+ uint16_t val;
+
+ ch = ao_cmd_decimal();
+ val = ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+
+ printf("Set channel %d to %d\n", ch, val);
+ ao_pwm_set(ch, val);
+}
+
+static const struct ao_cmds ao_pwm_cmds[] = {
+ { ao_pwm_cmd, "P <ch> <val>\0Set PWM ch to val" },
+ { 0, NULL },
+};
+
+void
+ao_pwm_init(void)
+{
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ stm_rcc.apb1enr |= (1 << AO_PWM_TIMER_ENABLE);
+
+ tim->cr1 = 0;
+ tim->psc = AO_PWM_TIMER_SCALE - 1;
+ tim->cnt = 0;
+ tim->ccer = ((1 << STM_TIM234_CCER_CC1E) |
+ (0 << STM_TIM234_CCER_CC1P) |
+ (1 << STM_TIM234_CCER_CC2E) |
+ (0 << STM_TIM234_CCER_CC2P) |
+ (1 << STM_TIM234_CCER_CC3E) |
+ (0 << STM_TIM234_CCER_CC3P) |
+ (1 << STM_TIM234_CCER_CC4E) |
+ (0 << STM_TIM234_CCER_CC4P));
+
+ tim->ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
+ (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) |
+ (0 << STM_TIM234_CCMR1_OC2PE) |
+ (0 << STM_TIM234_CCMR1_OC2FE) |
+ (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
+
+ (0 << STM_TIM234_CCMR1_OC1CE) |
+ (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) |
+ (0 << STM_TIM234_CCMR1_OC1PE) |
+ (0 << STM_TIM234_CCMR1_OC1FE) |
+ (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
+
+
+ tim->ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
+ (STM_TIM234_CCMR2_OC4M_PWM_MODE_1 << STM_TIM234_CCMR2_OC4M) |
+ (0 << STM_TIM234_CCMR2_OC4PE) |
+ (0 << STM_TIM234_CCMR2_OC4FE) |
+ (STM_TIM234_CCMR2_CC4S_OUTPUT << STM_TIM234_CCMR2_CC4S) |
+
+ (0 << STM_TIM234_CCMR2_OC3CE) |
+ (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M) |
+ (0 << STM_TIM234_CCMR2_OC3PE) |
+ (0 << STM_TIM234_CCMR2_OC3FE) |
+ (STM_TIM234_CCMR2_CC3S_OUTPUT << STM_TIM234_CCMR2_CC3S));
+ tim->egr = 0;
+
+ tim->sr = 0;
+ tim->dier = 0;
+ tim->smcr = 0;
+ tim->cr2 = ((0 << STM_TIM234_CR2_TI1S) |
+ (STM_TIM234_CR2_MMS_RESET<< STM_TIM234_CR2_MMS) |
+ (0 << STM_TIM234_CR2_CCDS));
+
+ stm_afr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_OSPEEDR_40MHz);
+#if NUM_PWM > 1
+ stm_afr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_OSPEEDR_40MHz);
+#endif
+#if NUM_PWM > 2
+ stm_afr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_OSPEEDR_40MHz);
+#endif
+#if NUM_PWM > 3
+ stm_afr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_OSPEEDR_40MHz);
+#endif
+ ao_cmd_register(&ao_pwm_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2020 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.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+void
+ao_debug_out(char c)
+{
+ if (c == '\n')
+ ao_debug_out('\r');
+ while (!(stm_usart1.isr & (1 << STM_USART_ISR_TXE)));
+ stm_usart1.tdr = c;
+}
+
+static int
+_ao_usart_tx_start(struct ao_stm_usart *usart)
+{
+ if (!ao_fifo_empty(usart->tx_fifo)) {
+#if HAS_SERIAL_SW_FLOW
+ if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts) == 1) {
+ ao_exti_enable(usart->gpio_cts, usart->pin_cts);
+ return 0;
+ }
+#endif
+ if (usart->reg->isr & (1 << STM_USART_ISR_TXE))
+ {
+ usart->tx_running = 1;
+ usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE);
+ ao_fifo_remove(usart->tx_fifo, usart->reg->tdr);
+ ao_wakeup(&usart->tx_fifo);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#if HAS_SERIAL_SW_FLOW
+static void
+_ao_usart_cts(struct ao_stm_usart *usart)
+{
+ if (_ao_usart_tx_start(usart))
+ ao_exti_disable(usart->gpio_cts, usart->pin_cts);
+}
+#endif
+
+static void
+_ao_usart_rx(struct ao_stm_usart *usart, int is_stdin)
+{
+ if (usart->reg->isr & (1 << STM_USART_ISR_RXNE)) {
+ usart->reg->icr = (1 << STM_USART_ICR_ORECF);
+ if (!ao_fifo_full(usart->rx_fifo)) {
+ ao_fifo_insert(usart->rx_fifo, usart->reg->rdr);
+ ao_wakeup(&usart->rx_fifo);
+ if (is_stdin)
+ ao_wakeup(&ao_stdin_ready);
+#if HAS_SERIAL_SW_FLOW
+ /* If the fifo is nearly full, turn off RTS and wait
+ * for it to drain a bunch
+ */
+ if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) {
+ ao_gpio_set(usart->gpio_rts, usart->pin_rts, 1);
+ usart->rts = 0;
+ }
+#endif
+ } else {
+ usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE);
+ }
+ }
+}
+
+static void
+ao_usart_isr(struct ao_stm_usart *usart, int is_stdin)
+{
+ _ao_usart_rx(usart, is_stdin);
+
+ if (!_ao_usart_tx_start(usart))
+ usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
+
+ if (usart->reg->isr & (1 << STM_USART_ISR_TC)) {
+ usart->tx_running = 0;
+ usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE);
+ if (usart->draining) {
+ usart->draining = 0;
+ ao_wakeup(&usart->tx_fifo);
+ }
+ }
+}
+
+static int
+_ao_usart_pollchar(struct ao_stm_usart *usart)
+{
+ int c;
+
+ if (ao_fifo_empty(usart->rx_fifo))
+ c = AO_READ_AGAIN;
+ else {
+ uint8_t u;
+ ao_fifo_remove(usart->rx_fifo,u);
+ if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) {
+ if (ao_fifo_barely(usart->rx_fifo))
+ usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE);
+ }
+#if HAS_SERIAL_SW_FLOW
+ /* If we've cleared RTS, check if there's space now and turn it back on */
+ if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) {
+ ao_gpio_set(usart->gpio_rts, usart->pin_rts, 0);
+ usart->rts = 1;
+ }
+#endif
+ c = u;
+ }
+ return c;
+}
+
+static char
+ao_usart_getchar(struct ao_stm_usart *usart)
+{
+ int c;
+ ao_arch_block_interrupts();
+ while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
+ ao_sleep(&usart->rx_fifo);
+ ao_arch_release_interrupts();
+ return (char) c;
+}
+
+#if 0
+static inline uint8_t
+_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
+{
+ return ao_sleep_for(&usart->rx_fifo, timeout);
+}
+#endif
+
+static void
+ao_usart_putchar(struct ao_stm_usart *usart, char c)
+{
+ ao_arch_block_interrupts();
+ while (ao_fifo_full(usart->tx_fifo))
+ ao_sleep(&usart->tx_fifo);
+ ao_fifo_insert(usart->tx_fifo, c);
+ _ao_usart_tx_start(usart);
+ ao_arch_release_interrupts();
+}
+
+static void
+ao_usart_drain(struct ao_stm_usart *usart)
+{
+ ao_arch_block_interrupts();
+ while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) {
+ usart->draining = 1;
+ ao_sleep(&usart->tx_fifo);
+ }
+ ao_arch_release_interrupts();
+}
+
+static const uint32_t ao_usart_speeds[] = {
+ [AO_SERIAL_SPEED_4800] = 4800,
+ [AO_SERIAL_SPEED_9600] = 9600,
+ [AO_SERIAL_SPEED_19200] = 19200,
+ [AO_SERIAL_SPEED_57600] = 57600,
+ [AO_SERIAL_SPEED_115200] = 115200,
+};
+
+static void
+ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
+{
+ if (speed > AO_SERIAL_SPEED_115200)
+ return;
+ usart->reg->brr = AO_PCLK2 / ao_usart_speeds[speed];
+}
+
+static void
+ao_usart_init(struct ao_stm_usart *usart, int hw_flow)
+{
+ usart->reg->cr1 = ((0 << STM_USART_CR1_M1) |
+ (0 << STM_USART_CR1_EOBIE) |
+ (0 << STM_USART_CR1_RTOIE) |
+ (0 << STM_USART_CR1_DEAT) |
+ (0 << STM_USART_CR1_DEDT) |
+ (0 << STM_USART_CR1_OVER8) |
+ (0 << STM_USART_CR1_CMIE) |
+ (0 << STM_USART_CR1_MME) |
+ (0 << STM_USART_CR1_M0) |
+ (0 << STM_USART_CR1_WAKE) |
+ (0 << STM_USART_CR1_PCE) |
+ (0 << STM_USART_CR1_PS) |
+ (0 << STM_USART_CR1_PEIE) |
+ (0 << STM_USART_CR1_TXEIE) |
+ (0 << STM_USART_CR1_TCIE) |
+ (1 << STM_USART_CR1_RXNEIE) |
+ (0 << STM_USART_CR1_IDLEIE) |
+ (1 << STM_USART_CR1_TE) |
+ (1 << STM_USART_CR1_RE) |
+ (0 << STM_USART_CR1_UESM) |
+ (0 << STM_USART_CR1_UE));
+
+ usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) |
+ (0 << STM_USART_CR2_RTOEN) |
+ (0 << STM_USART_CR2_ABRMOD) |
+ (0 << STM_USART_CR2_ABREN) |
+ (0 << STM_USART_CR2_MSBFIRST) |
+ (0 << STM_USART_CR2_DATAINV) |
+ (0 << STM_USART_CR2_TXINV) |
+ (0 << STM_USART_CR2_RXINV) |
+ (0 << STM_USART_CR2_SWAP) |
+ (0 << STM_USART_CR2_LINEN) |
+ (0 << STM_USART_CR2_STOP) |
+ (0 << STM_USART_CR2_CLKEN) |
+ (0 << STM_USART_CR2_CPOL) |
+ (0 << STM_USART_CR2_CHPA) |
+ (0 << STM_USART_CR2_LBCL) |
+ (0 << STM_USART_CR2_LBDIE) |
+ (0 << STM_USART_CR2_LBDL) |
+ (0 << STM_USART_CR2_ADDM7));
+
+ uint32_t cr3 = ((0 << STM_USART_CR3_WUFIE) |
+ (0 << STM_USART_CR3_WUS) |
+ (0 << STM_USART_CR3_SCARCNT) |
+ (0 << STM_USART_CR3_DEP) |
+ (0 << STM_USART_CR3_DEM) |
+ (0 << STM_USART_CR3_DDRE) |
+ (0 << STM_USART_CR3_OVRDIS) |
+ (0 << STM_USART_CR3_ONEBIT) |
+ (0 << STM_USART_CR3_CTIIE) |
+ (0 << STM_USART_CR3_CTSE) |
+ (0 << STM_USART_CR3_RTSE) |
+ (0 << STM_USART_CR3_DMAT) |
+ (0 << STM_USART_CR3_DMAR) |
+ (0 << STM_USART_CR3_SCEN) |
+ (0 << STM_USART_CR3_NACK) |
+ (0 << STM_USART_CR3_HDSEL) |
+ (0 << STM_USART_CR3_IRLP) |
+ (0 << STM_USART_CR3_IREN) |
+ (0 << STM_USART_CR3_EIE));
+
+ if (hw_flow)
+ cr3 |= ((1 << STM_USART_CR3_CTSE) |
+ (1 << STM_USART_CR3_RTSE));
+
+ usart->reg->cr3 = cr3;
+
+ /* Pick a 9600 baud rate */
+ ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
+
+ /* Enable the usart */
+ usart->reg->cr1 |= (1 << STM_USART_CR1_UE);
+}
+
+#if HAS_SERIAL_1
+
+struct ao_stm_usart ao_stm_usart1;
+
+void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
+
+char
+ao_serial1_getchar(void)
+{
+ return ao_usart_getchar(&ao_stm_usart1);
+}
+
+void
+ao_serial1_putchar(char c)
+{
+ ao_usart_putchar(&ao_stm_usart1, c);
+}
+
+int
+_ao_serial1_pollchar(void)
+{
+ return _ao_usart_pollchar(&ao_stm_usart1);
+}
+
+#if 0
+uint8_t
+_ao_serial1_sleep_for(uint16_t timeout)
+{
+ return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
+}
+#endif
+
+void
+ao_serial1_drain(void)
+{
+ ao_usart_drain(&ao_stm_usart1);
+}
+
+void
+ao_serial1_set_speed(uint8_t speed)
+{
+ ao_usart_drain(&ao_stm_usart1);
+ ao_usart_set_speed(&ao_stm_usart1, speed);
+}
+#endif /* HAS_SERIAL_1 */
+
+#if HAS_SERIAL_2
+
+struct ao_stm_usart ao_stm_usart2;
+
+void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
+
+char
+ao_serial2_getchar(void)
+{
+ return ao_usart_getchar(&ao_stm_usart2);
+}
+
+void
+ao_serial2_putchar(char c)
+{
+ ao_usart_putchar(&ao_stm_usart2, c);
+}
+
+int
+_ao_serial2_pollchar(void)
+{
+ return _ao_usart_pollchar(&ao_stm_usart2);
+}
+
+#if 0
+uint8_t
+_ao_serial2_sleep_for(uint16_t timeout)
+{
+ return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
+}
+#endif
+
+void
+ao_serial2_drain(void)
+{
+ ao_usart_drain(&ao_stm_usart2);
+}
+
+void
+ao_serial2_set_speed(uint8_t speed)
+{
+ ao_usart_drain(&ao_stm_usart2);
+ ao_usart_set_speed(&ao_stm_usart2, speed);
+}
+
+#if USE_SERIAL_2_FLOW && USE_SERIAL_2_SW_FLOW
+void
+ao_serial2_cts(void)
+{
+ _ao_usart_cts(&ao_stm_usart2);
+}
+#endif
+
+#endif /* HAS_SERIAL_2 */
+
+#if HAS_SERIAL_SW_FLOW
+static void
+ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
+ void (*isr)(void),
+ struct stm_gpio *port_rts,
+ int pin_rts,
+ struct stm_gpio *port_cts,
+ int pin_cts)
+{
+ /* Pull RTS low to note that there's space in the FIFO
+ */
+ ao_enable_output(port_rts, pin_rts, 0);
+ usart->gpio_rts = port_rts;
+ usart->pin_rts = pin_rts;
+ usart->rts = 1;
+
+ ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
+ usart->gpio_cts = port_cts;
+ usart->pin_cts = pin_cts;
+}
+#endif
+
+void
+ao_serial_shutdown(void)
+{
+#if HAS_SERIAL_1
+ stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_USART1EN);
+#endif
+#if HAS_SERIAL_2
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USART2EN);
+#endif
+}
+
+void
+ao_serial_init(void)
+{
+#if HAS_SERIAL_1
+#endif
+
+#if HAS_SERIAL_2
+ /*
+ * TX RX
+ * PA2 PA3
+ * PA9 PA10
+ * PA14 PA15
+ * PB6 PB7
+ */
+
+# if SERIAL_2_PA2_PA3
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 2, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 3, STM_AFR_AF4);
+# elif SERIAL_2_PA9_PA10
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 9, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 10, STM_AFR_AF4);
+# elif SERIAL_2_PA14_PA15
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 14, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 15, STM_AFR_AF4);
+# elif SERIAL_2_PB6_PB7
+ ao_enable_port(&stm_gpiob);
+ stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0);
+# else
+# error "No SERIAL_2 port configuration specified"
+# endif
+ /* Enable USART */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
+
+ ao_stm_usart2.reg = &stm_usart2;
+ ao_usart_init(&ao_stm_usart2, USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW);
+
+ stm_nvic_set_enable(STM_ISR_USART2_POS);
+ stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
+# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
+ ao_add_stdio(_ao_serial2_pollchar,
+ ao_serial2_putchar,
+ NULL);
+# endif
+#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>
+
+struct ao_spi_stm_info {
+ uint8_t miso_dma_index;
+ uint8_t mosi_dma_index;
+ struct stm_spi *stm_spi;
+};
+
+static uint8_t ao_spi_mutex[STM_NUM_SPI];
+static uint8_t ao_spi_pin_config[STM_NUM_SPI];
+
+static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
+ {
+ .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
+ .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
+ &stm_spi1
+ },
+ {
+ .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
+ .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
+ &stm_spi2
+ }
+};
+
+static uint8_t spi_dev_null;
+
+#if DEBUG
+static struct {
+ uint8_t task;
+ uint8_t which;
+ AO_TICK_TYPE tick;
+ uint16_t len;
+} spi_tasks[64];
+static uint8_t spi_task_index;
+
+static void
+validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
+{
+ uint32_t sr = stm_spi->sr;
+
+ if (stm_spi != &stm_spi2)
+ return;
+ spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
+ spi_tasks[spi_task_index].which = which;
+ spi_tasks[spi_task_index].tick = ao_time();
+ spi_tasks[spi_task_index].len = len;
+ spi_task_index = (spi_task_index + 1) & (63);
+ if (sr & (1 << STM_SPI_SR_FRE))
+ ao_panic(0x40 | 1);
+ if (sr & (1 << STM_SPI_SR_BSY))
+ ao_panic(0x40 | 2);
+ if (sr & (1 << STM_SPI_SR_OVR))
+ ao_panic(0x40 | 3);
+ if (sr & (1 << STM_SPI_SR_MODF))
+ ao_panic(0x40 | 4);
+ if (sr & (1 << STM_SPI_SR_UDR))
+ ao_panic(0x40 | 5);
+ if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ao_panic(0x40 | 6);
+ if (sr & (1 << STM_SPI_SR_RXNE))
+ ao_panic(0x40 | 7);
+ if (which != 5 && which != 6 && which != 13)
+ if (ao_cur_task->task_id != ao_spi_mutex[1])
+ ao_panic(0x40 | 8);
+}
+#else
+#define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
+#endif
+
+static void
+ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+
+ ao_dma_set_transfer(mosi_dma_index,
+ &stm_spi->dr,
+ (void *) data,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (minc << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+}
+
+static void
+ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
+
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ data,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (minc << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+}
+
+static void
+ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
+
+ validate_spi(stm_spi, which, len);
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (1 << STM_SPI_CR2_TXDMAEN) |
+ (1 << STM_SPI_CR2_RXDMAEN));
+
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
+
+ validate_spi(stm_spi, which+1, len);
+
+ stm_spi->cr2 = 0;
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ /* Set up the transmit DMA to deliver data */
+ ao_spi_set_dma_mosi(id, block, len, 1);
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+ ao_spi_run(id, 1, len);
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ /* Set up the transmit DMA to deliver data */
+ ao_spi_set_dma_mosi(id, &value, len, 0);
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+ ao_spi_run(id, 3, len);
+}
+
+void
+ao_spi_start_bytes(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+ validate_spi(stm_spi, 5, 0xffff);
+}
+
+void
+ao_spi_stop_bytes(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ;
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+ ;
+ /* Clear the OVR flag */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+ validate_spi(stm_spi, 6, 0xffff);
+ stm_spi->cr2 = 0;
+}
+
+void
+ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ const uint8_t *b = block;
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+ validate_spi(stm_spi, 7, len);
+ while (len--) {
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
+ stm_spi->dr = *b++;
+ }
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ;
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+ ;
+ /* Clear the OVR flag */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+ validate_spi(stm_spi, 8, len);
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ spi_dev_null = 0xff;
+
+ /* Set up transmit DMA to make the SPI hardware actually run */
+ ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
+
+ /* Set up the receive DMA to capture data */
+ ao_spi_set_dma_miso(id, block, len, 1);
+
+ ao_spi_run(id, 9, len);
+}
+
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ /* Set up transmit DMA to send data */
+ ao_spi_set_dma_mosi(id, out, len, 1);
+
+ /* Set up the receive DMA to capture data */
+ ao_spi_set_dma_miso(id, in, len, 1);
+
+ ao_spi_run(id, 11, len);
+}
+
+static void
+ao_spi_disable_pin_config(uint8_t spi_pin_config)
+{
+ /* Disable current config
+ */
+ switch (spi_pin_config) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_gpio_set(&stm_gpioa, 5, 1);
+ stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_gpio_set(&stm_gpiob, 3, 1);
+ stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_1_PE13_PE14_PE15:
+ stm_gpio_set(&stm_gpioe, 13, 1);
+ stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_gpio_set(&stm_gpiob, 13, 1);
+ stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_2_PD1_PD3_PD4:
+ stm_gpio_set(&stm_gpiod, 1, 1);
+ stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
+ break;
+ }
+}
+
+static void
+ao_spi_enable_pin_config(uint8_t spi_pin_config)
+{
+ /* Enable new config
+ */
+ switch (spi_pin_config) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
+ break;
+ case AO_SPI_1_PE13_PE14_PE15:
+ stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
+ break;
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+ break;
+ case AO_SPI_2_PD1_PD3_PD4:
+ stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
+ break;
+ }
+}
+
+static void
+ao_spi_config(uint8_t spi_index, uint32_t speed)
+{
+ uint8_t spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ if (spi_pin_config != ao_spi_pin_config[id]) {
+
+ /* Disable old config
+ */
+ ao_spi_disable_pin_config(ao_spi_pin_config[id]);
+
+ /* Enable new config
+ */
+ ao_spi_enable_pin_config(spi_pin_config);
+
+ /* Remember current config
+ */
+ ao_spi_pin_config[id] = spi_pin_config;
+ }
+
+ /* Turn the SPI transceiver on and set the mode */
+ stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
+ (0 << STM_SPI_CR1_BIDIOE) |
+ (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
+ (0 << STM_SPI_CR1_CRCNEXT) |
+ (0 << STM_SPI_CR1_DFF) |
+ (0 << STM_SPI_CR1_RXONLY) |
+ (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
+ (1 << STM_SPI_CR1_SSI) | /* ... */
+ (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
+ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
+ (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
+ (1 << STM_SPI_CR1_MSTR) |
+ (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) | /* Format */
+ (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
+ validate_spi(stm_spi, 13, 0);
+}
+
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
+ return 0;
+ ao_spi_config(spi_index, speed);
+ return 1;
+}
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ ao_mutex_get(&ao_spi_mutex[id]);
+ ao_spi_config(spi_index, speed);
+}
+
+void
+ao_spi_put(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ stm_spi->cr1 = 0;
+ ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
+
+ stm_spi->cr1 = 0;
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+
+ /* Clear any pending data and error flags */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+}
+
+#if DEBUG
+void
+ao_spi_dump_cmd(void)
+{
+ int s;
+
+ for (s = 0; s < 64; s++) {
+ int i = (spi_task_index + s) & 63;
+ if (spi_tasks[i].which) {
+ int t;
+ const char *name = "(none)";
+ for (t = 0; t < ao_num_tasks; t++)
+ if (ao_tasks[t]->task_id == spi_tasks[i].task) {
+ name = ao_tasks[t]->name;
+ break;
+ }
+ printf("%2d: %5d task %2d which %2d len %5d %s\n",
+ s,
+ spi_tasks[i].tick,
+ spi_tasks[i].task,
+ spi_tasks[i].which,
+ spi_tasks[i].len,
+ name);
+ }
+ }
+ for (s = 0; s < STM_NUM_SPI; s++) {
+ struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
+
+ printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
+ s, ao_spi_mutex[s], ao_spi_index[s],
+ ao_spi_stm_info[s].miso_dma_index,
+ ao_spi_stm_info[s].mosi_dma_index);
+ printf(" cr1 %04x cr2 %02x sr %03x\n",
+ spi->cr1, spi->cr2, spi->sr);
+ }
+
+}
+
+static const struct ao_cmds ao_spi_cmds[] = {
+ { ao_spi_dump_cmd, "S\0Dump SPI status" },
+ { 0, NULL }
+};
+#endif
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_1
+# if SPI_1_PA5_PA6_PA7
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+ stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PB3_PB4_PB5
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+ stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PE13_PE14_PE15
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
+ stm_ospeedr_set(&stm_gpioe, 13, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioe, 14, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
+# endif
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+ ao_spi_pin_config[0] = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(0);
+#endif
+
+#if HAS_SPI_2
+# if SPI_2_PB13_PB14_PB15
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+ stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
+# endif
+# if SPI_2_PD1_PD3_PD4
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
+ stm_ospeedr_set(&stm_gpiod, 1, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiod, 3, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
+# endif
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+ ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(1);
+#endif
+#if DEBUG
+ ao_cmd_register(&ao_spi_cmds[0]);
+#endif
+}
--- /dev/null
+/*
+ * Copyright © 2020 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>
+#if HAS_FAKE_FLIGHT
+#include <ao_fake_flight.h>
+#endif
+
+#ifndef HAS_TICK
+#define HAS_TICK 1
+#endif
+
+#if HAS_TICK
+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 cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = stm_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+
+#if AO_DATA_ALL
+volatile uint8_t ao_data_interval = 1;
+volatile uint8_t ao_data_count;
+#endif
+
+void stm_systick_isr(void)
+{
+ if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) {
+ ++ao_tick_count;
+#if HAS_TASK_QUEUE
+ if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0)
+ ao_task_check_alarm((uint16_t) ao_tick_count);
+#endif
+#if AO_DATA_ALL
+ if (++ao_data_count == ao_data_interval) {
+ ao_data_count = 0;
+#if HAS_ADC
+#if HAS_FAKE_FLIGHT
+ if (ao_fake_flight_active)
+ ao_fake_flight_poll();
+ else
+#endif
+ ao_adc_poll();
+#endif
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+ ao_wakeup((void *) &ao_data_count);
+#endif
+ }
+#endif
+#ifdef AO_TIMER_HOOK
+ AO_TIMER_HOOK;
+#endif
+ }
+}
+
+#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
+
+void
+ao_timer_init(void)
+{
+ stm_systick.csr = 0;
+ stm_systick.rvr = SYSTICK_RELOAD;
+ stm_systick.cvr = 0;
+ stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) |
+ (1 << STM_SYSTICK_CSR_TICKINT) |
+ (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE));
+}
+
+#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 <ao_task.h>
+#if HAS_FAKE_FLIGHT
+#include <ao_fake_flight.h>
+#endif
+
+#ifndef HAS_TICK
+#define HAS_TICK 1
+#endif
+
+#if HAS_TICK || defined(AO_TIMER_HOOK)
+
+#if HAS_TICK
+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 cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = stm_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+
+#endif
+
+#if AO_DATA_ALL
+volatile uint8_t ao_data_interval = 1;
+volatile uint8_t ao_data_count;
+#endif
+
+void stm_systick_isr(void)
+{
+ ao_validate_cur_stack();
+ if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) {
+#if HAS_TICK
+ ++ao_tick_count;
+#endif
+#if HAS_TASK_QUEUE
+ if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0)
+ ao_task_check_alarm((uint16_t) ao_tick_count);
+#endif
+#if AO_DATA_ALL
+ if (++ao_data_count == ao_data_interval) {
+ ao_data_count = 0;
+#if HAS_FAKE_FLIGHT
+ if (ao_fake_flight_active)
+ ao_fake_flight_poll();
+ else
+#endif
+ ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+ ao_wakeup((void *) &ao_data_count);
+#endif
+ }
+#endif
+#ifdef AO_TIMER_HOOK
+ AO_TIMER_HOOK;
+#endif
+ }
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval)
+{
+ ao_arch_critical(
+ ao_data_interval = interval;
+ ao_data_count = 0;
+ );
+}
+#endif
+
+#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
+
+void
+ao_timer_init(void)
+{
+ stm_systick.rvr = SYSTICK_RELOAD;
+ stm_systick.cvr = 0;
+ stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) |
+ (1 << STM_SYSTICK_CSR_TICKINT) |
+ (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE));
+ stm_nvic.shpr15_12 |= AO_STM_NVIC_CLOCK_PRIORITY << 24;
+}
+
+#endif
+
+void
+ao_clock_init(void)
+{
+ uint32_t cfgr;
+ uint32_t cr;
+
+ /* Switch to MSI while messing about */
+ stm_rcc.cr |= (1 << STM_RCC_CR_MSION);
+ while (!(stm_rcc.cr & (1 << STM_RCC_CR_MSIRDY)))
+ ao_arch_nop();
+
+ stm_rcc.cfgr = (stm_rcc.cfgr & ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) |
+ (STM_RCC_CFGR_SW_MSI << STM_RCC_CFGR_SW);
+
+ /* wait for system to switch to MSI */
+ while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+ (STM_RCC_CFGR_SWS_MSI << STM_RCC_CFGR_SWS))
+ ao_arch_nop();
+
+ /* reset SW, HPRE, PPRE1, PPRE2, MCOSEL and MCOPRE */
+ stm_rcc.cfgr &= (uint32_t)0x88FFC00C;
+
+ /* reset HSION, HSEON, CSSON and PLLON bits */
+ stm_rcc.cr &= 0xeefefffe;
+
+ /* reset PLLSRC, PLLMUL and PLLDIV bits */
+ stm_rcc.cfgr &= 0xff02ffff;
+
+ /* 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 &= ~(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 (1 << 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
+#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK (0 << 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
+
+ /* 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);
+
+ /* Enable power interface clock */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+
+ /* 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");
+
+ /* HCLK to 16MHz -> AHB prescaler = /1 */
+ 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 &= ~(1 << STM_RCC_CR_PLLON);
+ while (stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY))
+ asm("nop");
+
+ /* PLLVCO to 96MHz (for USB) -> PLLMUL = 6, PLLDIV = 4 */
+ cfgr = stm_rcc.cfgr;
+ cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
+ cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
+
+ cfgr |= (AO_RCC_CFGR_PLLMUL << STM_RCC_CFGR_PLLMUL);
+ cfgr |= (AO_RCC_CFGR_PLLDIV << STM_RCC_CFGR_PLLDIV);
+
+ /* PLL source */
+ cfgr &= ~(1 << 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.
+ */
+
+#ifndef _STM32L0_H_
+#define _STM32L0_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t vuint32_t;
+typedef volatile void * vvoid_t;
+
+struct stm_gpio {
+ vuint32_t moder;
+ vuint32_t otyper;
+ vuint32_t ospeedr;
+ vuint32_t pupdr;
+
+ vuint32_t idr;
+ vuint32_t odr;
+ vuint32_t bsrr;
+ vuint32_t lckr;
+
+ vuint32_t afrl;
+ vuint32_t afrh;
+ vuint32_t brr;
+};
+
+#define STM_MODER_SHIFT(pin) ((pin) << 1)
+#define STM_MODER_MASK 3
+#define STM_MODER_INPUT 0
+#define STM_MODER_OUTPUT 1
+#define STM_MODER_ALTERNATE 2
+#define STM_MODER_ANALOG 3
+
+static inline void
+stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->moder = ((gpio->moder &
+ ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) |
+ value << STM_MODER_SHIFT(pin));
+}
+
+static inline uint32_t
+stm_spread_mask(uint16_t mask) {
+ uint32_t m = mask;
+
+ /* 0000000000000000mmmmmmmmmmmmmmmm */
+ m = (m & 0xff) | ((m & 0xff00) << 8);
+ /* 00000000mmmmmmmm00000000mmmmmmmm */
+ m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4);
+ /* 0000mmmm0000mmmm0000mmmm0000mmmm */
+ m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2);
+ /* 00mm00mm00mm00mm00mm00mm00mm00mm */
+ m = (m & 0x11111111) | ((m & 0x22222222) << 2);
+ /* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */
+ return m;
+}
+
+static inline void
+stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->moder = ((gpio->moder & ~mask32) | value32);
+}
+
+static inline uint32_t
+stm_moder_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK;
+}
+
+#define STM_OTYPER_SHIFT(pin) (pin)
+#define STM_OTYPER_MASK 1
+#define STM_OTYPER_PUSH_PULL 0
+#define STM_OTYPER_OPEN_DRAIN 1
+
+static inline void
+stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->otyper = ((gpio->otyper &
+ ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) |
+ value << STM_OTYPER_SHIFT(pin));
+}
+
+static inline uint32_t
+stm_otyper_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK;
+}
+
+#define STM_OSPEEDR_SHIFT(pin) ((pin) << 1)
+#define STM_OSPEEDR_MASK 3
+#define STM_OSPEEDR_LOW 0
+#define STM_OSPEEDR_MEDIUM 1
+#define STM_OSPEEDR_HIGH 2
+#define STM_OSPEEDR_VERY_HIGH 3
+
+static inline void
+stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ gpio->ospeedr = ((gpio->ospeedr &
+ ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) |
+ value << STM_OSPEEDR_SHIFT(pin));
+}
+
+static inline void
+stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32);
+}
+
+static inline uint32_t
+stm_ospeedr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK;
+}
+
+#define STM_PUPDR_SHIFT(pin) ((pin) << 1)
+#define STM_PUPDR_MASK 3
+#define STM_PUPDR_NONE 0
+#define STM_PUPDR_PULL_UP 1
+#define STM_PUPDR_PULL_DOWN 2
+#define STM_PUPDR_RESERVED 3
+
+static inline void
+stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ gpio->pupdr = ((gpio->pupdr &
+ ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) |
+ value << STM_PUPDR_SHIFT(pin));
+}
+
+static inline void
+stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->pupdr = (gpio->pupdr & ~mask32) | value32;
+}
+
+static inline uint32_t
+stm_pupdr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK;
+}
+
+#define STM_AFR_SHIFT(pin) ((pin) << 2)
+#define STM_AFR_MASK 0xf
+#define STM_AFR_NONE 0
+#define STM_AFR_AF0 0x0
+#define STM_AFR_AF1 0x1
+#define STM_AFR_AF2 0x2
+#define STM_AFR_AF3 0x3
+#define STM_AFR_AF4 0x4
+#define STM_AFR_AF5 0x5
+#define STM_AFR_AF6 0x6
+#define STM_AFR_AF7 0x7
+#define STM_AFR_AF8 0x8
+#define STM_AFR_AF9 0x9
+#define STM_AFR_AF10 0xa
+#define STM_AFR_AF11 0xb
+#define STM_AFR_AF12 0xc
+#define STM_AFR_AF13 0xd
+#define STM_AFR_AF14 0xe
+#define STM_AFR_AF15 0xf
+
+static inline void
+stm_afr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ /*
+ * Set alternate pin mode too
+ */
+ stm_moder_set(gpio, pin, STM_MODER_ALTERNATE);
+ if (pin < 8)
+ gpio->afrl = ((gpio->afrl &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ else {
+ pin -= 8;
+ gpio->afrh = ((gpio->afrh &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ }
+}
+
+static inline uint32_t
+stm_afr_get(struct stm_gpio *gpio, int pin) {
+ if (pin < 8)
+ return (gpio->afrl >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ else {
+ pin -= 8;
+ return (gpio->afrh >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ }
+}
+
+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 = value ? (1 << pin) : (1 << (pin + 16));
+}
+
+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 gpio->idr;
+}
+
+/*
+ * We can't define these in registers.ld or our fancy
+ * ao_enable_gpio macro will expand into a huge pile of code
+ * as the compiler won't do correct constant folding and
+ * dead-code elimination
+ */
+
+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;
+extern struct stm_gpio stm_gpioh;
+
+#define stm_gpiob (*((struct stm_gpio *) 0x50000400))
+#define stm_gpioa (*((struct stm_gpio *) 0x50000000))
+
+struct stm_usart {
+ vuint32_t cr1; /* control register 1 */
+ vuint32_t cr2; /* control register 2 */
+ vuint32_t cr3; /* control register 3 */
+ vuint32_t brr; /* baud rate register */
+
+ vuint32_t gtpr; /* guard time and prescaler */
+ vuint32_t rtor; /* receiver timeout register */
+ vuint32_t rqr; /* request register */
+ vuint32_t isr; /* interrupt and status register */
+
+ vuint32_t icr; /* interrupt flag clear register */
+ vuint32_t rdr; /* receive data register */
+ vuint32_t tdr; /* transmit data register */
+};
+
+#define STM_USART_CR1_M1 28
+#define STM_USART_CR1_EOBIE 27
+#define STM_USART_CR1_RTOIE 26
+#define STM_USART_CR1_DEAT 21
+#define STM_USART_CR1_DEDT 16
+#define STM_USART_CR1_OVER8 15
+#define STM_USART_CR1_CMIE 14
+#define STM_USART_CR1_MME 13
+#define STM_USART_CR1_M0 12
+#define STM_USART_CR1_WAKE 11
+#define STM_USART_CR1_PCE 10
+#define STM_USART_CR1_PS 9
+#define STM_USART_CR1_PEIE 8
+#define STM_USART_CR1_TXEIE 7
+#define STM_USART_CR1_TCIE 6
+#define STM_USART_CR1_RXNEIE 5
+#define STM_USART_CR1_IDLEIE 4
+#define STM_USART_CR1_TE 3
+#define STM_USART_CR1_RE 2
+#define STM_USART_CR1_UESM 1
+#define STM_USART_CR1_UE 0
+
+#define STM_USART_CR2_ADD 24
+#define STM_USART_CR2_RTOEN 23
+#define STM_USART_CR2_ABRMOD 21
+#define STM_USART_CR2_ABREN 20
+#define STM_USART_CR2_MSBFIRST 19
+#define STM_USART_CR2_DATAINV 18
+#define STM_USART_CR2_TXINV 17
+#define STM_USART_CR2_RXINV 16
+#define STM_USART_CR2_SWAP 15
+#define STM_USART_CR2_LINEN 14
+#define STM_USART_CR2_STOP 12
+#define STM_USART_CR2_CLKEN 11
+#define STM_USART_CR2_CPOL 10
+#define STM_USART_CR2_CHPA 9
+#define STM_USART_CR2_LBCL 8
+#define STM_USART_CR2_LBDIE 6
+#define STM_USART_CR2_LBDL 5
+#define STM_USART_CR2_ADDM7 4
+
+#define STM_USART_CR3_WUFIE 22
+#define STM_USART_CR3_WUS 20
+#define STM_USART_CR3_SCARCNT 17
+#define STM_USART_CR3_DEP 15
+#define STM_USART_CR3_DEM 14
+#define STM_USART_CR3_DDRE 13
+#define STM_USART_CR3_OVRDIS 12
+#define STM_USART_CR3_ONEBIT 11
+#define STM_USART_CR3_CTIIE 10
+#define STM_USART_CR3_CTSE 9
+#define STM_USART_CR3_RTSE 8
+#define STM_USART_CR3_DMAT 7
+#define STM_USART_CR3_DMAR 6
+#define STM_USART_CR3_SCEN 5
+#define STM_USART_CR3_NACK 4
+#define STM_USART_CR3_HDSEL 3
+#define STM_USART_CR3_IRLP 2
+#define STM_USART_CR3_IREN 1
+#define STM_USART_CR3_EIE 0
+
+#define STM_USART_GTPR_GT 8
+#define STM_USART_GTPR_PSC 0
+
+#define STM_USART_RQR_TXFRQ 4
+#define STM_USART_RQR_RXFRQ 3
+#define STM_USART_RQR_MMRQ 2
+#define STM_USART_RQR_SBKRQ 1
+#define STM_USART_RQR_ABRRQ 0
+
+#define STM_USART_ISR_REACK 22
+#define STM_USART_ISR_TEACK 21
+#define STM_USART_ISR_WUF 20
+#define STM_USART_ISR_RWU 19
+#define STM_USART_ISR_SBKF 18
+#define STM_USART_ISR_CMF 17
+#define STM_USART_ISR_BUSY 16
+#define STM_USART_ISR_ABRF 15
+#define STM_USART_ISR_ABRE 14
+#define STM_USART_ISR_EOBF 12
+#define STM_USART_ISR_RTOF 11
+#define STM_USART_ISR_CTS 10
+#define STM_USART_ISR_CTSIF 9
+#define STM_USART_ISR_LBDF 8
+#define STM_USART_ISR_TXE 7
+#define STM_USART_ISR_TC 6
+#define STM_USART_ISR_RXNE 5
+#define STM_USART_ISR_IDLE 4
+#define STM_USART_ISR_ORE 3
+#define STM_USART_ISR_NF 2
+#define STM_USART_ISR_FE 1
+#define STM_USART_ISR_PE 0
+
+#define STM_USART_ICR_WUCF 20
+#define STM_USART_ICR_CMCF 17
+#define STM_USART_ICR_EOBCF 12
+#define STM_USART_ICR_RTOCF 11
+#define STM_USART_ICR_CTSCF 9
+#define STM_USART_ICR_LBDCF 8
+#define STM_USART_ICR_TCCF 6
+#define STM_USART_ICR_IDLECF 4
+#define STM_USART_ICR_ORECF 3
+#define STM_USART_ICR_NCF 2
+#define STM_USART_ICR_FECF 1
+#define STM_USART_ICR_PECF 0
+
+extern struct stm_usart stm_usart1;
+extern struct stm_usart stm_usart2;
+#define stm_usart1 (*((struct stm_usart *) 0x40013800))
+#define stm_usart2 (*((struct stm_usart *) 0x40004400))
+
+struct stm_tim {
+};
+
+extern struct stm_tim stm_tim9;
+
+struct stm_tim1011 {
+ vuint32_t cr1;
+ uint32_t unused_4;
+ vuint32_t smcr;
+ vuint32_t dier;
+ vuint32_t sr;
+ vuint32_t egr;
+ vuint32_t ccmr1;
+ uint32_t unused_1c;
+ vuint32_t ccer;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+ uint32_t unused_30;
+ vuint32_t ccr1;
+ uint32_t unused_38;
+ uint32_t unused_3c;
+ uint32_t unused_40;
+ uint32_t unused_44;
+ uint32_t unused_48;
+ uint32_t unused_4c;
+ vuint32_t or;
+};
+
+extern struct stm_tim1011 stm_tim10;
+extern struct stm_tim1011 stm_tim11;
+
+#define STM_TIM1011_CR1_CKD 8
+#define STM_TIM1011_CR1_CKD_1 0
+#define STM_TIM1011_CR1_CKD_2 1
+#define STM_TIM1011_CR1_CKD_4 2
+#define STM_TIM1011_CR1_CKD_MASK 3
+#define STM_TIM1011_CR1_ARPE 7
+#define STM_TIM1011_CR1_URS 2
+#define STM_TIM1011_CR1_UDIS 1
+#define STM_TIM1011_CR1_CEN 0
+
+#define STM_TIM1011_SMCR_ETP 15
+#define STM_TIM1011_SMCR_ECE 14
+#define STM_TIM1011_SMCR_ETPS 12
+#define STM_TIM1011_SMCR_ETPS_OFF 0
+#define STM_TIM1011_SMCR_ETPS_2 1
+#define STM_TIM1011_SMCR_ETPS_4 2
+#define STM_TIM1011_SMCR_ETPS_8 3
+#define STM_TIM1011_SMCR_ETPS_MASK 3
+#define STM_TIM1011_SMCR_ETF 8
+#define STM_TIM1011_SMCR_ETF_NONE 0
+#define STM_TIM1011_SMCR_ETF_CK_INT_2 1
+#define STM_TIM1011_SMCR_ETF_CK_INT_4 2
+#define STM_TIM1011_SMCR_ETF_CK_INT_8 3
+#define STM_TIM1011_SMCR_ETF_DTS_2_6 4
+#define STM_TIM1011_SMCR_ETF_DTS_2_8 5
+#define STM_TIM1011_SMCR_ETF_DTS_4_6 6
+#define STM_TIM1011_SMCR_ETF_DTS_4_8 7
+#define STM_TIM1011_SMCR_ETF_DTS_8_6 8
+#define STM_TIM1011_SMCR_ETF_DTS_8_8 9
+#define STM_TIM1011_SMCR_ETF_DTS_16_5 10
+#define STM_TIM1011_SMCR_ETF_DTS_16_6 11
+#define STM_TIM1011_SMCR_ETF_DTS_16_8 12
+#define STM_TIM1011_SMCR_ETF_DTS_32_5 13
+#define STM_TIM1011_SMCR_ETF_DTS_32_6 14
+#define STM_TIM1011_SMCR_ETF_DTS_32_8 15
+#define STM_TIM1011_SMCR_ETF_MASK 15
+
+#define STM_TIM1011_DIER_CC1E 1
+#define STM_TIM1011_DIER_UIE 0
+
+#define STM_TIM1011_SR_CC1OF 9
+#define STM_TIM1011_SR_CC1IF 1
+#define STM_TIM1011_SR_UIF 0
+
+#define STM_TIM1011_EGR_CC1G 1
+#define STM_TIM1011_EGR_UG 0
+
+#define STM_TIM1011_CCMR1_OC1CE 7
+#define STM_TIM1011_CCMR1_OC1M 4
+#define STM_TIM1011_CCMR1_OC1M_FROZEN 0
+#define STM_TIM1011_CCMR1_OC1M_SET_1_ACTIVE_ON_MATCH 1
+#define STM_TIM1011_CCMR1_OC1M_SET_1_INACTIVE_ON_MATCH 2
+#define STM_TIM1011_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM1011_CCMR1_OC1M_FORCE_INACTIVE 4
+#define STM_TIM1011_CCMR1_OC1M_FORCE_ACTIVE 5
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM1011_CCMR1_OC1M_MASK 7
+#define STM_TIM1011_CCMR1_OC1PE 3
+#define STM_TIM1011_CCMR1_OC1FE 2
+#define STM_TIM1011_CCMR1_CC1S 0
+#define STM_TIM1011_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM1011_CCMR1_CC1S_MASK 3
+
+#define STM_TIM1011_CCMR1_IC1F_NONE 0
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_2 1
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_4 2
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_8 3
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_6 4
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_8 5
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_6 6
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_8 7
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_6 8
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_8 9
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_5 10
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_6 11
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_8 12
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_5 13
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_6 14
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_8 15
+#define STM_TIM1011_CCMR1_IC1F_MASK 15
+#define STM_TIM1011_CCMR1_IC1PSC 2
+#define STM_TIM1011_CCMR1_IC1PSC_1 0
+#define STM_TIM1011_CCMR1_IC1PSC_2 1
+#define STM_TIM1011_CCMR1_IC1PSC_4 2
+#define STM_TIM1011_CCMR1_IC1PSC_8 3
+#define STM_TIM1011_CCMR1_IC1PSC_MASK 3
+#define STM_TIM1011_CCMR1_CC1S 0
+
+#define STM_TIM1011_CCER_CC1NP 3
+#define STM_TIM1011_CCER_CC1P 1
+#define STM_TIM1011_CCER_CC1E 0
+
+#define STM_TIM1011_OR_TI1_RMP_RI 3
+#define STM_TIM1011_ETR_RMP 2
+#define STM_TIM1011_TI1_RMP 0
+#define STM_TIM1011_TI1_RMP_GPIO 0
+#define STM_TIM1011_TI1_RMP_LSI 1
+#define STM_TIM1011_TI1_RMP_LSE 2
+#define STM_TIM1011_TI1_RMP_RTC 3
+#define STM_TIM1011_TI1_RMP_MASK 3
+
+/* Flash interface */
+
+struct stm_flash {
+ vuint32_t acr;
+ vuint32_t pecr;
+ vuint32_t pdkeyr;
+ vuint32_t pekeyr;
+
+ vuint32_t prgkeyr;
+ vuint32_t optkeyr;
+ vuint32_t sr;
+ vuint32_t obr;
+
+ vuint32_t wrpr;
+};
+
+extern struct stm_flash stm_flash;
+
+#define STM_FLASH_ACR_RUN_PD (4)
+#define STM_FLASH_ACR_SLEEP_PD (3)
+#define STM_FLASH_ACR_ACC64 (2)
+#define STM_FLASH_ACR_PRFEN (1)
+#define STM_FLASH_ACR_LATENCY (0)
+
+#define STM_FLASH_PECR_OBL_LAUNCH 18
+#define STM_FLASH_PECR_ERRIE 17
+#define STM_FLASH_PECR_EOPIE 16
+#define STM_FLASH_PECR_FPRG 10
+#define STM_FLASH_PECR_ERASE 9
+#define STM_FLASH_PECR_FTDW 8
+#define STM_FLASH_PECR_DATA 4
+#define STM_FLASH_PECR_PROG 3
+#define STM_FLASH_PECR_OPTLOCK 2
+#define STM_FLASH_PECR_PRGLOCK 1
+#define STM_FLASH_PECR_PELOCK 0
+
+#define STM_FLASH_SR_OPTVERR 11
+#define STM_FLASH_SR_SIZERR 10
+#define STM_FLASH_SR_PGAERR 9
+#define STM_FLASH_SR_WRPERR 8
+#define STM_FLASH_SR_READY 3
+#define STM_FLASH_SR_ENDHV 2
+#define STM_FLASH_SR_EOP 1
+#define STM_FLASH_SR_BSY 0
+
+#define STM_FLASH_PEKEYR_PEKEY1 0x89ABCDEF
+#define STM_FLASH_PEKEYR_PEKEY2 0x02030405
+
+#define STM_FLASH_PRGKEYR_PRGKEY1 0x8C9DAEBF
+#define STM_FLASH_PRGKEYR_PRGKEY2 0x13141516
+
+struct stm_rcc {
+ vuint32_t cr;
+ vuint32_t icscr;
+ uint32_t unused08;
+ vuint32_t cfgr;
+
+ vuint32_t cier;
+ vuint32_t cifr;
+ vuint32_t cicr;
+ vuint32_t iopstr;
+
+ vuint32_t ahbrstr;
+ vuint32_t apb2rstr;
+ vuint32_t apb1rstr;
+ vuint32_t iopenr;
+
+ vuint32_t ahbenr;
+ vuint32_t apb2enr;
+ vuint32_t apb1enr;
+ vuint32_t iopsmen;
+
+ vuint32_t ahbsmenr;
+ vuint32_t apb2smenr;
+ vuint32_t apb1smenr;
+ vuint32_t ccipr;
+
+ vuint32_t csr;
+};
+
+extern struct stm_rcc stm_rcc;
+
+/* Nominal high speed internal oscillator frequency is 16MHz */
+#define STM_HSI_FREQ 16000000
+#define STM_MSI_FREQ 2097000
+
+#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 3
+
+#define STM_RCC_CR_CSSON (28)
+#define STM_RCC_CR_PLLRDY (25)
+#define STM_RCC_CR_PLLON (24)
+#define STM_RCC_CR_HSEBYP (18)
+#define STM_RCC_CR_HSERDY (17)
+#define STM_RCC_CR_HSEON (16)
+#define STM_RCC_CR_MSIRDY (9)
+#define STM_RCC_CR_MSION (8)
+#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 7
+
+#define STM_RCC_CFGR_MCOSEL (24)
+#define STM_RCC_CFGR_MCOSEL_DISABLE 0
+#define STM_RCC_CFGR_MCOSEL_SYSCLK 1
+#define STM_RCC_CFGR_MCOSEL_HSI 2
+#define STM_RCC_CFGR_MCOSEL_MSI 3
+#define STM_RCC_CFGR_MCOSEL_HSE 4
+#define STM_RCC_CFGR_MCOSEL_PLL 5
+#define STM_RCC_CFGR_MCOSEL_LSI 6
+#define STM_RCC_CFGR_MCOSEL_LSE 7
+#define STM_RCC_CFGR_MCOSEL_MASK 7
+
+#define STM_RCC_CFGR_PLLDIV (22)
+#define STM_RCC_CFGR_PLLDIV_2 1
+#define STM_RCC_CFGR_PLLDIV_3 2
+#define STM_RCC_CFGR_PLLDIV_4 3
+#define STM_RCC_CFGR_PLLDIV_MASK 3
+
+#define STM_RCC_CFGR_PLLMUL (18)
+#define STM_RCC_CFGR_PLLMUL_3 0
+#define STM_RCC_CFGR_PLLMUL_4 1
+#define STM_RCC_CFGR_PLLMUL_6 2
+#define STM_RCC_CFGR_PLLMUL_8 3
+#define STM_RCC_CFGR_PLLMUL_12 4
+#define STM_RCC_CFGR_PLLMUL_16 5
+#define STM_RCC_CFGR_PLLMUL_24 6
+#define STM_RCC_CFGR_PLLMUL_32 7
+#define STM_RCC_CFGR_PLLMUL_48 8
+#define STM_RCC_CFGR_PLLMUL_MASK 0xf
+
+#define STM_RCC_CFGR_PLLSRC (16)
+
+#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 7
+
+#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 7
+
+#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 0xf
+
+#define STM_RCC_CFGR_SWS (2)
+#define STM_RCC_CFGR_SWS_MSI 0
+#define STM_RCC_CFGR_SWS_HSI 1
+#define STM_RCC_CFGR_SWS_HSE 2
+#define STM_RCC_CFGR_SWS_PLL 3
+#define STM_RCC_CFGR_SWS_MASK 3
+
+#define STM_RCC_CFGR_SW (0)
+#define STM_RCC_CFGR_SW_MSI 0
+#define STM_RCC_CFGR_SW_HSI 1
+#define STM_RCC_CFGR_SW_HSE 2
+#define STM_RCC_CFGR_SW_PLL 3
+#define STM_RCC_CFGR_SW_MASK 3
+
+#define STM_RCC_IOPENR_IOPAEN 0
+#define STM_RCC_IOPENR_IOPBEN 1
+#define STM_RCC_IOPENR_IOPCEN 2
+#define STM_RCC_IOPENR_IOPDEN 3
+#define STM_RCC_IOPENR_IOPEEN 4
+#define STM_RCC_IOPENR_IOPHEN 7
+
+#define STM_RCC_AHBENR_DMA1EN 0
+#define STM_RCC_AHBENR_MIFEN 8
+#define STM_RCC_AHBENR_CRCEN 12
+#define STM_RCC_AHBENR_CRYPEN 24
+
+#define STM_RCC_APB2ENR_DBGEN (22)
+#define STM_RCC_APB2ENR_USART1EN (14)
+#define STM_RCC_APB2ENR_SPI1EN (12)
+#define STM_RCC_APB2ENR_ADC1EN (9)
+#define STM_RCC_APB2ENR_FWEN (7)
+#define STM_RCC_APB2ENR_TIM22EN (5)
+#define STM_RCC_APB2ENR_TIM21EN (2)
+#define STM_RCC_APB2ENR_SYSCFGEN (0)
+
+#define STM_RCC_APB1ENR_LPTIM1EN 31
+#define STM_RCC_APB1ENR_I2C3EN 30
+#define STM_RCC_APB1ENR_PWREN 28
+#define STM_RCC_APB1ENR_I2C2EN 22
+#define STM_RCC_APB1ENR_I2C1EN 21
+#define STM_RCC_APB1ENR_USART5EN 20
+#define STM_RCC_APB1ENR_USART4EN 19
+#define STM_RCC_APB1ENR_LPUART1EN 18
+#define STM_RCC_APB1ENR_USART2EN 17
+#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_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_OBLRSTF (25)
+#define STM_RCC_CSR_RMVF (24)
+#define STM_RCC_CSR_RTFRST (23)
+#define STM_RCC_CSR_RTCEN (22)
+#define STM_RCC_CSR_RTCSEL (16)
+
+#define STM_RCC_CSR_RTCSEL_NONE 0
+#define STM_RCC_CSR_RTCSEL_LSE 1
+#define STM_RCC_CSR_RTCSEL_LSI 2
+#define STM_RCC_CSR_RTCSEL_HSE 3
+#define STM_RCC_CSR_RTCSEL_MASK 3
+
+#define STM_RCC_CSR_LSEBYP (10)
+#define STM_RCC_CSR_LSERDY (9)
+#define STM_RCC_CSR_LSEON (8)
+#define STM_RCC_CSR_LSIRDY (1)
+#define STM_RCC_CSR_LSION (0)
+
+struct stm_pwr {
+ vuint32_t cr;
+ vuint32_t csr;
+};
+
+extern struct stm_pwr stm_pwr;
+
+#define STM_PWR_CR_LPRUN (14)
+
+#define STM_PWR_CR_VOS (11)
+#define STM_PWR_CR_VOS_1_8 1
+#define STM_PWR_CR_VOS_1_5 2
+#define STM_PWR_CR_VOS_1_2 3
+#define STM_PWR_CR_VOS_MASK 3
+
+#define STM_PWR_CR_FWU (10)
+#define STM_PWR_CR_ULP (9)
+#define STM_PWR_CR_DBP (8)
+
+#define STM_PWR_CR_PLS (5)
+#define STM_PWR_CR_PLS_1_9 0
+#define STM_PWR_CR_PLS_2_1 1
+#define STM_PWR_CR_PLS_2_3 2
+#define STM_PWR_CR_PLS_2_5 3
+#define STM_PWR_CR_PLS_2_7 4
+#define STM_PWR_CR_PLS_2_9 5
+#define STM_PWR_CR_PLS_3_1 6
+#define STM_PWR_CR_PLS_EXT 7
+#define STM_PWR_CR_PLS_MASK 7
+
+#define STM_PWR_CR_PVDE (4)
+#define STM_PWR_CR_CSBF (3)
+#define STM_PWR_CR_CWUF (2)
+#define STM_PWR_CR_PDDS (1)
+#define STM_PWR_CR_LPSDSR (0)
+
+#define STM_PWR_CSR_EWUP3 (10)
+#define STM_PWR_CSR_EWUP2 (9)
+#define STM_PWR_CSR_EWUP1 (8)
+#define STM_PWR_CSR_REGLPF (5)
+#define STM_PWR_CSR_VOSF (4)
+#define STM_PWR_CSR_VREFINTRDYF (3)
+#define STM_PWR_CSR_PVDO (2)
+#define STM_PWR_CSR_SBF (1)
+#define STM_PWR_CSR_WUF (0)
+
+struct stm_tim67 {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ uint32_t _unused_08;
+ vuint32_t dier;
+
+ vuint32_t sr;
+ vuint32_t egr;
+ uint32_t _unused_18;
+ uint32_t _unused_1c;
+
+ uint32_t _unused_20;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+};
+
+extern struct stm_tim67 stm_tim6;
+
+#define STM_TIM67_CR1_ARPE (7)
+#define STM_TIM67_CR1_OPM (3)
+#define STM_TIM67_CR1_URS (2)
+#define STM_TIM67_CR1_UDIS (1)
+#define STM_TIM67_CR1_CEN (0)
+
+#define STM_TIM67_CR2_MMS (4)
+#define STM_TIM67_CR2_MMS_RESET 0
+#define STM_TIM67_CR2_MMS_ENABLE 1
+#define STM_TIM67_CR2_MMS_UPDATE 2
+#define STM_TIM67_CR2_MMS_MASK 7
+
+#define STM_TIM67_DIER_UDE (8)
+#define STM_TIM67_DIER_UIE (0)
+
+#define STM_TIM67_SR_UIF (0)
+
+#define STM_TIM67_EGR_UG (0)
+
+struct stm_lcd {
+ vuint32_t cr;
+ vuint32_t fcr;
+ vuint32_t sr;
+ vuint32_t clr;
+ uint32_t unused_0x10;
+ vuint32_t ram[8*2];
+};
+
+extern struct stm_lcd stm_lcd;
+
+#define STM_LCD_CR_MUX_SEG (7)
+
+#define STM_LCD_CR_BIAS (5)
+#define STM_LCD_CR_BIAS_1_4 0
+#define STM_LCD_CR_BIAS_1_2 1
+#define STM_LCD_CR_BIAS_1_3 2
+#define STM_LCD_CR_BIAS_MASK 3
+
+#define STM_LCD_CR_DUTY (2)
+#define STM_LCD_CR_DUTY_STATIC 0
+#define STM_LCD_CR_DUTY_1_2 1
+#define STM_LCD_CR_DUTY_1_3 2
+#define STM_LCD_CR_DUTY_1_4 3
+#define STM_LCD_CR_DUTY_1_8 4
+#define STM_LCD_CR_DUTY_MASK 7
+
+#define STM_LCD_CR_VSEL (1)
+#define STM_LCD_CR_LCDEN (0)
+
+#define STM_LCD_FCR_PS (22)
+#define STM_LCD_FCR_PS_1 0x0
+#define STM_LCD_FCR_PS_2 0x1
+#define STM_LCD_FCR_PS_4 0x2
+#define STM_LCD_FCR_PS_8 0x3
+#define STM_LCD_FCR_PS_16 0x4
+#define STM_LCD_FCR_PS_32 0x5
+#define STM_LCD_FCR_PS_64 0x6
+#define STM_LCD_FCR_PS_128 0x7
+#define STM_LCD_FCR_PS_256 0x8
+#define STM_LCD_FCR_PS_512 0x9
+#define STM_LCD_FCR_PS_1024 0xa
+#define STM_LCD_FCR_PS_2048 0xb
+#define STM_LCD_FCR_PS_4096 0xc
+#define STM_LCD_FCR_PS_8192 0xd
+#define STM_LCD_FCR_PS_16384 0xe
+#define STM_LCD_FCR_PS_32768 0xf
+#define STM_LCD_FCR_PS_MASK 0xf
+
+#define STM_LCD_FCR_DIV (18)
+#define STM_LCD_FCR_DIV_16 0x0
+#define STM_LCD_FCR_DIV_17 0x1
+#define STM_LCD_FCR_DIV_18 0x2
+#define STM_LCD_FCR_DIV_19 0x3
+#define STM_LCD_FCR_DIV_20 0x4
+#define STM_LCD_FCR_DIV_21 0x5
+#define STM_LCD_FCR_DIV_22 0x6
+#define STM_LCD_FCR_DIV_23 0x7
+#define STM_LCD_FCR_DIV_24 0x8
+#define STM_LCD_FCR_DIV_25 0x9
+#define STM_LCD_FCR_DIV_26 0xa
+#define STM_LCD_FCR_DIV_27 0xb
+#define STM_LCD_FCR_DIV_28 0xc
+#define STM_LCD_FCR_DIV_29 0xd
+#define STM_LCD_FCR_DIV_30 0xe
+#define STM_LCD_FCR_DIV_31 0xf
+#define STM_LCD_FCR_DIV_MASK 0xf
+
+#define STM_LCD_FCR_BLINK (16)
+#define STM_LCD_FCR_BLINK_DISABLE 0
+#define STM_LCD_FCR_BLINK_SEG0_COM0 1
+#define STM_LCD_FCR_BLINK_SEG0_COMALL 2
+#define STM_LCD_FCR_BLINK_SEGALL_COMALL 3
+#define STM_LCD_FCR_BLINK_MASK 3
+
+#define STM_LCD_FCR_BLINKF (13)
+#define STM_LCD_FCR_BLINKF_8 0
+#define STM_LCD_FCR_BLINKF_16 1
+#define STM_LCD_FCR_BLINKF_32 2
+#define STM_LCD_FCR_BLINKF_64 3
+#define STM_LCD_FCR_BLINKF_128 4
+#define STM_LCD_FCR_BLINKF_256 5
+#define STM_LCD_FCR_BLINKF_512 6
+#define STM_LCD_FCR_BLINKF_1024 7
+#define STM_LCD_FCR_BLINKF_MASK 7
+
+#define STM_LCD_FCR_CC (10)
+#define STM_LCD_FCR_CC_MASK 7
+
+#define STM_LCD_FCR_DEAD (7)
+#define STM_LCD_FCR_DEAD_MASK 7
+
+#define STM_LCD_FCR_PON (4)
+#define STM_LCD_FCR_PON_MASK 7
+
+#define STM_LCD_FCR_UDDIE (3)
+#define STM_LCD_FCR_SOFIE (1)
+#define STM_LCD_FCR_HD (0)
+
+#define STM_LCD_SR_FCRSF (5)
+#define STM_LCD_SR_RDY (4)
+#define STM_LCD_SR_UDD (3)
+#define STM_LCD_SR_UDR (2)
+#define STM_LCD_SR_SOF (1)
+#define STM_LCD_SR_ENS (0)
+
+#define STM_LCD_CLR_UDDC (3)
+#define STM_LCD_CLR_SOFC (1)
+
+/* The SYSTICK starts at 0xe000e010 */
+
+struct stm_systick {
+ vuint32_t csr;
+ vuint32_t rvr;
+ vuint32_t cvr;
+ vuint32_t calib;
+};
+
+extern struct stm_systick stm_systick;
+
+#define STM_SYSTICK_CSR_ENABLE 0
+#define STM_SYSTICK_CSR_TICKINT 1
+#define STM_SYSTICK_CSR_CLKSOURCE 2
+#define STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 0
+#define STM_SYSTICK_CSR_CLKSOURCE_HCLK 1
+#define STM_SYSTICK_CSR_COUNTFLAG 16
+
+/* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */
+
+struct stm_nvic {
+ vuint32_t iser; /* 0x000 0xe000e100 Set Enable Register */
+
+ uint8_t _unused020[0x080 - 0x004];
+
+ vuint32_t icer; /* 0x080 0xe000e180 Clear Enable Register */
+
+ uint8_t _unused0a0[0x100 - 0x084];
+
+ vuint32_t ispr; /* 0x100 0xe000e200 Set Pending Register */
+
+ uint8_t _unused120[0x180 - 0x104];
+
+ vuint32_t icpr; /* 0x180 0xe000e280 Clear Pending Register */
+
+ uint8_t _unused1a0[0x300 - 0x184];
+
+ vuint32_t ipr[8]; /* 0x300 0xe000e400 Priority Register */
+};
+
+extern struct stm_nvic stm_nvic;
+
+#define IRQ_MASK(irq) (1 << (irq))
+#define IRQ_BOOL(v,irq) (((v) >> (irq)) & 1)
+
+static inline void
+stm_nvic_set_enable(int irq) {
+ stm_nvic.iser = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_enable(int irq) {
+ stm_nvic.icer = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_enabled(int irq) {
+ return IRQ_BOOL(stm_nvic.iser, irq);
+}
+
+static inline void
+stm_nvic_set_pending(int irq) {
+ stm_nvic.ispr = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_pending(int irq) {
+ stm_nvic.icpr = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_pending(int irq) {
+ return IRQ_BOOL(stm_nvic.ispr, 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 &= ~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_scb {
+ vuint32_t cpuid;
+ vuint32_t icsr;
+ vuint32_t vtor;
+ vuint32_t aircr;
+
+ vuint32_t scr;
+ vuint32_t ccr;
+ vuint32_t shpr1;
+ vuint32_t shpr2;
+
+ vuint32_t shpr3;
+ vuint32_t shcrs;
+ vuint32_t cfsr;
+ vuint32_t hfsr;
+
+ uint32_t unused_30;
+ vuint32_t mmfar;
+ vuint32_t bfar;
+};
+
+extern struct stm_scb stm_scb;
+
+#define STM_SCB_AIRCR_VECTKEY 16
+#define STM_SCB_AIRCR_VECTKEY_KEY 0x05fa
+#define STM_SCB_AIRCR_PRIGROUP 8
+#define STM_SCB_AIRCR_SYSRESETREQ 2
+#define STM_SCB_AIRCR_VECTCLRACTIVE 1
+#define STM_SCB_AIRCR_VECTRESET 0
+
+struct stm_mpu {
+ vuint32_t typer;
+ vuint32_t cr;
+ vuint32_t rnr;
+ vuint32_t rbar;
+
+ vuint32_t rasr;
+ vuint32_t rbar_a1;
+ vuint32_t rasr_a1;
+ vuint32_t rbar_a2;
+ vuint32_t rasr_a2;
+ vuint32_t rbar_a3;
+ vuint32_t rasr_a3;
+};
+
+extern struct stm_mpu stm_mpu;
+
+#define STM_MPU_TYPER_IREGION 16
+#define STM_MPU_TYPER_IREGION_MASK 0xff
+#define STM_MPU_TYPER_DREGION 8
+#define STM_MPU_TYPER_DREGION_MASK 0xff
+#define STM_MPU_TYPER_SEPARATE 0
+
+#define STM_MPU_CR_PRIVDEFENA 2
+#define STM_MPU_CR_HFNMIENA 1
+#define STM_MPU_CR_ENABLE 0
+
+#define STM_MPU_RNR_REGION 0
+#define STM_MPU_RNR_REGION_MASK 0xff
+
+#define STM_MPU_RBAR_ADDR 5
+#define STM_MPU_RBAR_ADDR_MASK 0x7ffffff
+
+#define STM_MPU_RBAR_VALID 4
+#define STM_MPU_RBAR_REGION 0
+#define STM_MPU_RBAR_REGION_MASK 0xf
+
+#define STM_MPU_RASR_XN 28
+#define STM_MPU_RASR_AP 24
+#define STM_MPU_RASR_AP_NONE_NONE 0
+#define STM_MPU_RASR_AP_RW_NONE 1
+#define STM_MPU_RASR_AP_RW_RO 2
+#define STM_MPU_RASR_AP_RW_RW 3
+#define STM_MPU_RASR_AP_RO_NONE 5
+#define STM_MPU_RASR_AP_RO_RO 6
+#define STM_MPU_RASR_AP_MASK 7
+#define STM_MPU_RASR_TEX 19
+#define STM_MPU_RASR_TEX_MASK 7
+#define STM_MPU_RASR_S 18
+#define STM_MPU_RASR_C 17
+#define STM_MPU_RASR_B 16
+#define STM_MPU_RASR_SRD 8
+#define STM_MPU_RASR_SRD_MASK 0xff
+#define STM_MPU_RASR_SIZE 1
+#define STM_MPU_RASR_SIZE_MASK 0x1f
+#define STM_MPU_RASR_ENABLE 0
+
+#define isr_decl(name) void stm_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+isr_decl(wwdg);
+isr_decl(pvd);
+isr_decl(rtc);
+isr_decl(flash);
+isr_decl(rcc_crs);
+isr_decl(exti1_0);
+isr_decl(exti3_2);
+isr_decl(exti15_4);
+isr_decl(dma1_channel1);
+isr_decl(dma1_channel3_2);
+isr_decl(dma1_channel7_4);
+isr_decl(adc_comp);
+isr_decl(lptim1);
+isr_decl(usart4_usart5);
+isr_decl(tim2);
+isr_decl(tim3);
+isr_decl(tim4);
+isr_decl(tim6);
+isr_decl(tim7);
+isr_decl(tim21);
+isr_decl(i2c3);
+isr_decl(tim22);
+isr_decl(i2c1);
+isr_decl(i2c2);
+isr_decl(spi1);
+isr_decl(spi2);
+isr_decl(usart1);
+isr_decl(usart2);
+isr_decl(usart3);
+isr_decl(lpuart1_aes);
+
+#undef isr_decl
+
+#define STM_ISR_WWDG_POS 0
+#define STM_ISR_PVD_POS 1
+#define STM_ISR_RTC_POS 2
+#define STM_ISR_FLASH_POS 3
+#define STM_ISR_RCC_CRS_POS 4
+#define STM_ISR_EXTI1_0_POS 5
+#define STM_ISR_EXTI3_2_POS 6
+#define STM_ISR_EXTI15_4_POS 7
+#define STM_ISR_DMA1_CHANNEL1_POS 9
+#define STM_ISR_DMA1_CHANNEL3_2_POS 10
+#define STM_ISR_DMA1_CHANNEL7_4_POS 11
+#define STM_ISR_ADC_COMP_POS 12
+#define STM_ISR_LPTIM1_POS 13
+#define STM_ISR_USART4_USART5_POS 14
+#define STM_ISR_TIM2_POS 15
+#define STM_ISR_TIM3_POS 16
+#define STM_ISR_TIM6_POS 17
+#define STM_ISR_TIM7_POS 18
+#define STM_ISR_TIM21_POS 20
+#define STM_ISR_I2C3_POS 21
+#define STM_ISR_TIM22_POS 22
+#define STM_ISR_I2C1_POS 23
+#define STM_ISR_I2C2_POS 24
+#define STM_ISR_SPI1_POS 25
+#define STM_ISR_SPI2_POS 26
+#define STM_ISR_USART1_POS 27
+#define STM_ISR_USART2_POS 28
+#define STM_ISR_LPUART1_AES_POS 29
+
+struct stm_syscfg {
+ vuint32_t memrmp;
+ vuint32_t pmc;
+ vuint32_t exticr[4];
+};
+
+extern struct stm_syscfg stm_syscfg;
+
+#define STM_SYSCFG_MEMRMP_MEM_MODE 0
+#define STM_SYSCFG_MEMRMP_MEM_MODE_MAIN_FLASH 0
+#define STM_SYSCFG_MEMRMP_MEM_MODE_SYSTEM_FLASH 1
+#define STM_SYSCFG_MEMRMP_MEM_MODE_SRAM 3
+#define STM_SYSCFG_MEMRMP_MEM_MODE_MASK 3
+
+#define STM_SYSCFG_PMC_USB_PU 0
+
+#define STM_SYSCFG_EXTICR_PA 0
+#define STM_SYSCFG_EXTICR_PB 1
+#define STM_SYSCFG_EXTICR_PC 2
+#define STM_SYSCFG_EXTICR_PD 3
+#define STM_SYSCFG_EXTICR_PE 4
+#define STM_SYSCFG_EXTICR_PH 5
+
+static inline void
+stm_exticr_set(struct stm_gpio *gpio, int pin) {
+ uint8_t reg = pin >> 2;
+ uint8_t shift = (pin & 3) << 2;
+ uint8_t val = 0;
+
+ /* Enable SYSCFG */
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGEN);
+
+ if (gpio == &stm_gpioa)
+ val = STM_SYSCFG_EXTICR_PA;
+ else if (gpio == &stm_gpiob)
+ val = STM_SYSCFG_EXTICR_PB;
+ else if (gpio == &stm_gpioc)
+ val = STM_SYSCFG_EXTICR_PC;
+ else if (gpio == &stm_gpiod)
+ val = STM_SYSCFG_EXTICR_PD;
+ else if (gpio == &stm_gpioe)
+ val = STM_SYSCFG_EXTICR_PE;
+
+ stm_syscfg.exticr[reg] = (stm_syscfg.exticr[reg] & ~(0xf << shift)) | val << shift;
+}
+
+struct stm_dma_channel {
+ vuint32_t ccr;
+ vuint32_t cndtr;
+ vvoid_t cpar;
+ vvoid_t cmar;
+ vuint32_t reserved;
+};
+
+#define STM_NUM_DMA 7
+
+struct stm_dma {
+ vuint32_t isr;
+ vuint32_t ifcr;
+ struct stm_dma_channel channel[STM_NUM_DMA];
+};
+
+extern struct stm_dma stm_dma;
+
+/* DMA channels go from 1 to 7, instead of 0 to 6 (sigh)
+ */
+
+#define STM_DMA_INDEX(channel) ((channel) - 1)
+
+#define STM_DMA_ISR(index) ((index) << 2)
+#define STM_DMA_ISR_MASK 0xf
+#define STM_DMA_ISR_TEIF 3
+#define STM_DMA_ISR_HTIF 2
+#define STM_DMA_ISR_TCIF 1
+#define STM_DMA_ISR_GIF 0
+
+#define STM_DMA_IFCR(index) ((index) << 2)
+#define STM_DMA_IFCR_MASK 0xf
+#define STM_DMA_IFCR_CTEIF 3
+#define STM_DMA_IFCR_CHTIF 2
+#define STM_DMA_IFCR_CTCIF 1
+#define STM_DMA_IFCR_CGIF 0
+
+#define STM_DMA_CCR_MEM2MEM (14)
+
+#define STM_DMA_CCR_PL (12)
+#define STM_DMA_CCR_PL_LOW (0)
+#define STM_DMA_CCR_PL_MEDIUM (1)
+#define STM_DMA_CCR_PL_HIGH (2)
+#define STM_DMA_CCR_PL_VERY_HIGH (3)
+#define STM_DMA_CCR_PL_MASK (3)
+
+#define STM_DMA_CCR_MSIZE (10)
+#define STM_DMA_CCR_MSIZE_8 (0)
+#define STM_DMA_CCR_MSIZE_16 (1)
+#define STM_DMA_CCR_MSIZE_32 (2)
+#define STM_DMA_CCR_MSIZE_MASK (3)
+
+#define STM_DMA_CCR_PSIZE (8)
+#define STM_DMA_CCR_PSIZE_8 (0)
+#define STM_DMA_CCR_PSIZE_16 (1)
+#define STM_DMA_CCR_PSIZE_32 (2)
+#define STM_DMA_CCR_PSIZE_MASK (3)
+
+#define STM_DMA_CCR_MINC (7)
+#define STM_DMA_CCR_PINC (6)
+#define STM_DMA_CCR_CIRC (5)
+#define STM_DMA_CCR_DIR (4)
+#define STM_DMA_CCR_DIR_PER_TO_MEM 0
+#define STM_DMA_CCR_DIR_MEM_TO_PER 1
+#define STM_DMA_CCR_TEIE (3)
+#define STM_DMA_CCR_HTIE (2)
+#define STM_DMA_CCR_TCIE (1)
+#define STM_DMA_CCR_EN (0)
+
+#define STM_DMA_CHANNEL_ADC1 1
+#define STM_DMA_CHANNEL_SPI1_RX 2
+#define STM_DMA_CHANNEL_SPI1_TX 3
+#define STM_DMA_CHANNEL_SPI2_RX 4
+#define STM_DMA_CHANNEL_SPI2_TX 5
+#define STM_DMA_CHANNEL_USART3_TX 2
+#define STM_DMA_CHANNEL_USART3_RX 3
+#define STM_DMA_CHANNEL_USART1_TX 4
+#define STM_DMA_CHANNEL_USART1_RX 5
+#define STM_DMA_CHANNEL_USART2_RX 6
+#define STM_DMA_CHANNEL_USART2_TX 7
+#define STM_DMA_CHANNEL_I2C2_TX 4
+#define STM_DMA_CHANNEL_I2C2_RX 5
+#define STM_DMA_CHANNEL_I2C1_TX 6
+#define STM_DMA_CHANNEL_I2C1_RX 7
+#define STM_DMA_CHANNEL_TIM2_CH3 1
+#define STM_DMA_CHANNEL_TIM2_UP 2
+#define STM_DMA_CHANNEL_TIM2_CH1 5
+#define STM_DMA_CHANNEL_TIM2_CH2 7
+#define STM_DMA_CHANNEL_TIM2_CH4 7
+#define STM_DMA_CHANNEL_TIM3_CH3 2
+#define STM_DMA_CHANNEL_TIM3_CH4 3
+#define STM_DMA_CHANNEL_TIM3_UP 3
+#define STM_DMA_CHANNEL_TIM3_CH1 6
+#define STM_DMA_CHANNEL_TIM3_TRIG 6
+#define STM_DMA_CHANNEL_TIM4_CH1 1
+#define STM_DMA_CHANNEL_TIM4_CH2 4
+#define STM_DMA_CHANNEL_TIM4_CH3 5
+#define STM_DMA_CHANNEL_TIM4_UP 7
+#define STM_DMA_CHANNEL_TIM6_UP_DA 2
+#define STM_DMA_CHANNEL_C_CHANNEL1 2
+#define STM_DMA_CHANNEL_TIM7_UP_DA 3
+#define STM_DMA_CHANNEL_C_CHANNEL2 3
+
+/*
+ * Only spi channel 1 and 2 can use DMA
+ */
+#define STM_NUM_SPI 2
+
+struct stm_spi {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t sr;
+ vuint32_t dr;
+ vuint32_t crcpr;
+ vuint32_t rxcrcr;
+ vuint32_t txcrcr;
+};
+
+extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
+
+/* SPI channels go from 1 to 3, instead of 0 to 2 (sigh)
+ */
+
+#define STM_SPI_INDEX(channel) ((channel) - 1)
+
+#define STM_SPI_CR1_BIDIMODE 15
+#define STM_SPI_CR1_BIDIOE 14
+#define STM_SPI_CR1_CRCEN 13
+#define STM_SPI_CR1_CRCNEXT 12
+#define STM_SPI_CR1_DFF 11
+#define STM_SPI_CR1_RXONLY 10
+#define STM_SPI_CR1_SSM 9
+#define STM_SPI_CR1_SSI 8
+#define STM_SPI_CR1_LSBFIRST 7
+#define STM_SPI_CR1_SPE 6
+#define STM_SPI_CR1_BR 3
+#define STM_SPI_CR1_BR_PCLK_2 0
+#define STM_SPI_CR1_BR_PCLK_4 1
+#define STM_SPI_CR1_BR_PCLK_8 2
+#define STM_SPI_CR1_BR_PCLK_16 3
+#define STM_SPI_CR1_BR_PCLK_32 4
+#define STM_SPI_CR1_BR_PCLK_64 5
+#define STM_SPI_CR1_BR_PCLK_128 6
+#define STM_SPI_CR1_BR_PCLK_256 7
+#define STM_SPI_CR1_BR_MASK 7
+
+#define STM_SPI_CR1_MSTR 2
+#define STM_SPI_CR1_CPOL 1
+#define STM_SPI_CR1_CPHA 0
+
+#define STM_SPI_CR2_TXEIE 7
+#define STM_SPI_CR2_RXNEIE 6
+#define STM_SPI_CR2_ERRIE 5
+#define STM_SPI_CR2_SSOE 2
+#define STM_SPI_CR2_TXDMAEN 1
+#define STM_SPI_CR2_RXDMAEN 0
+
+#define STM_SPI_SR_FRE 8
+#define STM_SPI_SR_BSY 7
+#define STM_SPI_SR_OVR 6
+#define STM_SPI_SR_MODF 5
+#define STM_SPI_SR_CRCERR 4
+#define STM_SPI_SR_UDR 3
+#define STM_SPI_SR_CHSIDE 2
+#define STM_SPI_SR_TXE 1
+#define STM_SPI_SR_RXNE 0
+
+struct stm_adc {
+ vuint32_t sr;
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t smpr1;
+ vuint32_t smpr2;
+ vuint32_t smpr3;
+ vuint32_t jofr1;
+ vuint32_t jofr2;
+ vuint32_t jofr3;
+ vuint32_t jofr4;
+ vuint32_t htr;
+ vuint32_t ltr;
+ vuint32_t sqr1;
+ vuint32_t sqr2;
+ vuint32_t sqr3;
+ vuint32_t sqr4;
+ vuint32_t sqr5;
+ vuint32_t jsqr;
+ vuint32_t jdr1;
+ vuint32_t jdr2;
+ vuint32_t jdr3;
+ vuint32_t jdr4;
+ vuint32_t dr;
+ uint8_t reserved[0x300 - 0x5c];
+ vuint32_t csr;
+ vuint32_t ccr;
+};
+
+extern struct stm_adc stm_adc;
+
+#define STM_ADC_SQ_TEMP 16
+#define STM_ADC_SQ_V_REF 17
+
+#define STM_ADC_SR_JCNR 9
+#define STM_ADC_SR_RCNR 8
+#define STM_ADC_SR_ADONS 6
+#define STM_ADC_SR_OVR 5
+#define STM_ADC_SR_STRT 4
+#define STM_ADC_SR_JSTRT 3
+#define STM_ADC_SR_JEOC 2
+#define STM_ADC_SR_EOC 1
+#define STM_ADC_SR_AWD 0
+
+#define STM_ADC_CR1_OVRIE 26
+#define STM_ADC_CR1_RES 24
+#define STM_ADC_CR1_RES_12 0
+#define STM_ADC_CR1_RES_10 1
+#define STM_ADC_CR1_RES_8 2
+#define STM_ADC_CR1_RES_6 3
+#define STM_ADC_CR1_RES_MASK 3
+#define STM_ADC_CR1_AWDEN 23
+#define STM_ADC_CR1_JAWDEN 22
+#define STM_ADC_CR1_PDI 17
+#define STM_ADC_CR1_PDD 16
+#define STM_ADC_CR1_DISCNUM 13
+#define STM_ADC_CR1_DISCNUM_1 0
+#define STM_ADC_CR1_DISCNUM_2 1
+#define STM_ADC_CR1_DISCNUM_3 2
+#define STM_ADC_CR1_DISCNUM_4 3
+#define STM_ADC_CR1_DISCNUM_5 4
+#define STM_ADC_CR1_DISCNUM_6 5
+#define STM_ADC_CR1_DISCNUM_7 6
+#define STM_ADC_CR1_DISCNUM_8 7
+#define STM_ADC_CR1_DISCNUM_MASK 7
+#define STM_ADC_CR1_JDISCEN 12
+#define STM_ADC_CR1_DISCEN 11
+#define STM_ADC_CR1_JAUTO 10
+#define STM_ADC_CR1_AWDSGL 9
+#define STM_ADC_CR1_SCAN 8
+#define STM_ADC_CR1_JEOCIE 7
+#define STM_ADC_CR1_AWDIE 6
+#define STM_ADC_CR1_EOCIE 5
+#define STM_ADC_CR1_AWDCH 0
+#define STM_ADC_CR1_AWDCH_MASK 0x1f
+
+#define STM_ADC_CR2_SWSTART 30
+#define STM_ADC_CR2_EXTEN 28
+#define STM_ADC_CR2_EXTEN_DISABLE 0
+#define STM_ADC_CR2_EXTEN_RISING 1
+#define STM_ADC_CR2_EXTEN_FALLING 2
+#define STM_ADC_CR2_EXTEN_BOTH 3
+#define STM_ADC_CR2_EXTEN_MASK 3
+#define STM_ADC_CR2_EXTSEL 24
+#define STM_ADC_CR2_EXTSEL_TIM9_CC2 0
+#define STM_ADC_CR2_EXTSEL_TIM9_TRGO 1
+#define STM_ADC_CR2_EXTSEL_TIM2_CC3 2
+#define STM_ADC_CR2_EXTSEL_TIM2_CC2 3
+#define STM_ADC_CR2_EXTSEL_TIM3_TRGO 4
+#define STM_ADC_CR2_EXTSEL_TIM4_CC4 5
+#define STM_ADC_CR2_EXTSEL_TIM2_TRGO 6
+#define STM_ADC_CR2_EXTSEL_TIM3_CC1 7
+#define STM_ADC_CR2_EXTSEL_TIM3_CC3 8
+#define STM_ADC_CR2_EXTSEL_TIM4_TRGO 9
+#define STM_ADC_CR2_EXTSEL_TIM6_TRGO 10
+#define STM_ADC_CR2_EXTSEL_EXTI_11 15
+#define STM_ADC_CR2_EXTSEL_MASK 15
+#define STM_ADC_CR2_JWSTART 22
+#define STM_ADC_CR2_JEXTEN 20
+#define STM_ADC_CR2_JEXTEN_DISABLE 0
+#define STM_ADC_CR2_JEXTEN_RISING 1
+#define STM_ADC_CR2_JEXTEN_FALLING 2
+#define STM_ADC_CR2_JEXTEN_BOTH 3
+#define STM_ADC_CR2_JEXTEN_MASK 3
+#define STM_ADC_CR2_JEXTSEL 16
+#define STM_ADC_CR2_JEXTSEL_TIM9_CC1 0
+#define STM_ADC_CR2_JEXTSEL_TIM9_TRGO 1
+#define STM_ADC_CR2_JEXTSEL_TIM2_TRGO 2
+#define STM_ADC_CR2_JEXTSEL_TIM2_CC1 3
+#define STM_ADC_CR2_JEXTSEL_TIM3_CC4 4
+#define STM_ADC_CR2_JEXTSEL_TIM4_TRGO 5
+#define STM_ADC_CR2_JEXTSEL_TIM4_CC1 6
+#define STM_ADC_CR2_JEXTSEL_TIM4_CC2 7
+#define STM_ADC_CR2_JEXTSEL_TIM4_CC3 8
+#define STM_ADC_CR2_JEXTSEL_TIM10_CC1 9
+#define STM_ADC_CR2_JEXTSEL_TIM7_TRGO 10
+#define STM_ADC_CR2_JEXTSEL_EXTI_15 15
+#define STM_ADC_CR2_JEXTSEL_MASK 15
+#define STM_ADC_CR2_ALIGN 11
+#define STM_ADC_CR2_EOCS 10
+#define STM_ADC_CR2_DDS 9
+#define STM_ADC_CR2_DMA 8
+#define STM_ADC_CR2_DELS 4
+#define STM_ADC_CR2_DELS_NONE 0
+#define STM_ADC_CR2_DELS_UNTIL_READ 1
+#define STM_ADC_CR2_DELS_7 2
+#define STM_ADC_CR2_DELS_15 3
+#define STM_ADC_CR2_DELS_31 4
+#define STM_ADC_CR2_DELS_63 5
+#define STM_ADC_CR2_DELS_127 6
+#define STM_ADC_CR2_DELS_255 7
+#define STM_ADC_CR2_DELS_MASK 7
+#define STM_ADC_CR2_CONT 1
+#define STM_ADC_CR2_ADON 0
+
+#define STM_ADC_CCR_TSVREFE 23
+#define STM_ADC_CCR_ADCPRE 16
+#define STM_ADC_CCR_ADCPRE_HSI_1 0
+#define STM_ADC_CCR_ADCPRE_HSI_2 1
+#define STM_ADC_CCR_ADCPRE_HSI_4 2
+#define STM_ADC_CCR_ADCPRE_MASK 3
+
+struct stm_temp_cal {
+ uint16_t vref;
+ uint16_t ts_cal_cold;
+ uint16_t reserved;
+ uint16_t ts_cal_hot;
+};
+
+extern struct stm_temp_cal stm_temp_cal;
+
+#define stm_temp_cal_cold 25
+#define stm_temp_cal_hot 110
+
+struct stm_dbg_mcu {
+ uint32_t idcode;
+};
+
+extern struct stm_dbg_mcu stm_dbg_mcu;
+
+static inline uint16_t
+stm_dev_id(void) {
+ return stm_dbg_mcu.idcode & 0xfff;
+}
+
+struct stm_flash_size {
+ uint16_t f_size;
+};
+
+extern struct stm_flash_size stm_flash_size_reg;
+#define stm_flash_size_reg (*((struct stm_flash_size *) 0x1ff8007c))
+
+/* Returns flash size in bytes */
+extern uint32_t
+stm_flash_size(void);
+
+struct stm_unique_id {
+ uint32_t u_id0;
+ uint32_t u_id1;
+ uint32_t u_id2;
+};
+
+extern struct stm_unique_id stm_unique_id;
+#define stm_unique_id (*((struct stm_unique_id) 0x1ff80050))
+
+struct stm_device_id {
+ uint32_t device_id;
+};
+
+extern struct stm_device_id stm_device_id;
+#define stm_device_id (*((struct stm_device_id) 0x40015800))
+
+#define STM_NUM_I2C 2
+
+#define STM_I2C_INDEX(channel) ((channel) - 1)
+
+struct stm_i2c {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t oar1;
+ vuint32_t oar2;
+ vuint32_t dr;
+ vuint32_t sr1;
+ vuint32_t sr2;
+ vuint32_t ccr;
+ vuint32_t trise;
+};
+
+extern struct stm_i2c stm_i2c1, stm_i2c2;
+
+#define STM_I2C_CR1_SWRST 15
+#define STM_I2C_CR1_ALERT 13
+#define STM_I2C_CR1_PEC 12
+#define STM_I2C_CR1_POS 11
+#define STM_I2C_CR1_ACK 10
+#define STM_I2C_CR1_STOP 9
+#define STM_I2C_CR1_START 8
+#define STM_I2C_CR1_NOSTRETCH 7
+#define STM_I2C_CR1_ENGC 6
+#define STM_I2C_CR1_ENPEC 5
+#define STM_I2C_CR1_ENARP 4
+#define STM_I2C_CR1_SMBTYPE 3
+#define STM_I2C_CR1_SMBUS 1
+#define STM_I2C_CR1_PE 0
+
+#define STM_I2C_CR2_LAST 12
+#define STM_I2C_CR2_DMAEN 11
+#define STM_I2C_CR2_ITBUFEN 10
+#define STM_I2C_CR2_ITEVTEN 9
+#define STM_I2C_CR2_ITERREN 8
+#define STM_I2C_CR2_FREQ 0
+#define STM_I2C_CR2_FREQ_2_MHZ 2
+#define STM_I2C_CR2_FREQ_4_MHZ 4
+#define STM_I2C_CR2_FREQ_8_MHZ 8
+#define STM_I2C_CR2_FREQ_16_MHZ 16
+#define STM_I2C_CR2_FREQ_24_MHZ 24
+#define STM_I2C_CR2_FREQ_32_MHZ 32
+#define STM_I2C_CR2_FREQ_MASK 0x3f
+
+#define STM_I2C_SR1_SMBALERT 15
+#define STM_I2C_SR1_TIMEOUT 14
+#define STM_I2C_SR1_PECERR 12
+#define STM_I2C_SR1_OVR 11
+#define STM_I2C_SR1_AF 10
+#define STM_I2C_SR1_ARLO 9
+#define STM_I2C_SR1_BERR 8
+#define STM_I2C_SR1_TXE 7
+#define STM_I2C_SR1_RXNE 6
+#define STM_I2C_SR1_STOPF 4
+#define STM_I2C_SR1_ADD10 3
+#define STM_I2C_SR1_BTF 2
+#define STM_I2C_SR1_ADDR 1
+#define STM_I2C_SR1_SB 0
+
+#define STM_I2C_SR2_PEC 8
+#define STM_I2C_SR2_PEC_MASK 0xff00
+#define STM_I2C_SR2_DUALF 7
+#define STM_I2C_SR2_SMBHOST 6
+#define STM_I2C_SR2_SMBDEFAULT 5
+#define STM_I2C_SR2_GENCALL 4
+#define STM_I2C_SR2_TRA 2
+#define STM_I2C_SR2_BUSY 1
+#define STM_I2C_SR2_MSL 0
+
+#define STM_I2C_CCR_FS 15
+#define STM_I2C_CCR_DUTY 14
+#define STM_I2C_CCR_CCR 0
+#define STM_I2C_CCR_MASK 0x7ff
+
+struct stm_tim234 {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t smcr;
+ vuint32_t dier;
+
+ vuint32_t sr;
+ vuint32_t egr;
+ vuint32_t ccmr1;
+ vuint32_t ccmr2;
+
+ vuint32_t ccer;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+
+ uint32_t reserved_30;
+ vuint32_t ccr1;
+ vuint32_t ccr2;
+ vuint32_t ccr3;
+
+ vuint32_t ccr4;
+ uint32_t reserved_44;
+ vuint32_t dcr;
+ vuint32_t dmar;
+
+ uint32_t reserved_50;
+};
+
+extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
+
+#define STM_TIM234_CR1_CKD 8
+#define STM_TIM234_CR1_CKD_1 0
+#define STM_TIM234_CR1_CKD_2 1
+#define STM_TIM234_CR1_CKD_4 2
+#define STM_TIM234_CR1_CKD_MASK 3
+#define STM_TIM234_CR1_ARPE 7
+#define STM_TIM234_CR1_CMS 5
+#define STM_TIM234_CR1_CMS_EDGE 0
+#define STM_TIM234_CR1_CMS_CENTER_1 1
+#define STM_TIM234_CR1_CMS_CENTER_2 2
+#define STM_TIM234_CR1_CMS_CENTER_3 3
+#define STM_TIM234_CR1_CMS_MASK 3
+#define STM_TIM234_CR1_DIR 4
+#define STM_TIM234_CR1_DIR_UP 0
+#define STM_TIM234_CR1_DIR_DOWN 1
+#define STM_TIM234_CR1_OPM 3
+#define STM_TIM234_CR1_URS 2
+#define STM_TIM234_CR1_UDIS 1
+#define STM_TIM234_CR1_CEN 0
+
+#define STM_TIM234_CR2_TI1S 7
+#define STM_TIM234_CR2_MMS 4
+#define STM_TIM234_CR2_MMS_RESET 0
+#define STM_TIM234_CR2_MMS_ENABLE 1
+#define STM_TIM234_CR2_MMS_UPDATE 2
+#define STM_TIM234_CR2_MMS_COMPARE_PULSE 3
+#define STM_TIM234_CR2_MMS_COMPARE_OC1REF 4
+#define STM_TIM234_CR2_MMS_COMPARE_OC2REF 5
+#define STM_TIM234_CR2_MMS_COMPARE_OC3REF 6
+#define STM_TIM234_CR2_MMS_COMPARE_OC4REF 7
+#define STM_TIM234_CR2_MMS_MASK 7
+#define STM_TIM234_CR2_CCDS 3
+
+#define STM_TIM234_SMCR_ETP 15
+#define STM_TIM234_SMCR_ECE 14
+#define STM_TIM234_SMCR_ETPS 12
+#define STM_TIM234_SMCR_ETPS_OFF 0
+#define STM_TIM234_SMCR_ETPS_DIV_2 1
+#define STM_TIM234_SMCR_ETPS_DIV_4 2
+#define STM_TIM234_SMCR_ETPS_DIV_8 3
+#define STM_TIM234_SMCR_ETPS_MASK 3
+#define STM_TIM234_SMCR_ETF 8
+#define STM_TIM234_SMCR_ETF_NONE 0
+#define STM_TIM234_SMCR_ETF_INT_N_2 1
+#define STM_TIM234_SMCR_ETF_INT_N_4 2
+#define STM_TIM234_SMCR_ETF_INT_N_8 3
+#define STM_TIM234_SMCR_ETF_DTS_2_N_6 4
+#define STM_TIM234_SMCR_ETF_DTS_2_N_8 5
+#define STM_TIM234_SMCR_ETF_DTS_4_N_6 6
+#define STM_TIM234_SMCR_ETF_DTS_4_N_8 7
+#define STM_TIM234_SMCR_ETF_DTS_8_N_6 8
+#define STM_TIM234_SMCR_ETF_DTS_8_N_8 9
+#define STM_TIM234_SMCR_ETF_DTS_16_N_5 10
+#define STM_TIM234_SMCR_ETF_DTS_16_N_6 11
+#define STM_TIM234_SMCR_ETF_DTS_16_N_8 12
+#define STM_TIM234_SMCR_ETF_DTS_32_N_5 13
+#define STM_TIM234_SMCR_ETF_DTS_32_N_6 14
+#define STM_TIM234_SMCR_ETF_DTS_32_N_8 15
+#define STM_TIM234_SMCR_ETF_MASK 15
+#define STM_TIM234_SMCR_MSM 7
+#define STM_TIM234_SMCR_TS 4
+#define STM_TIM234_SMCR_TS_ITR0 0
+#define STM_TIM234_SMCR_TS_ITR1 1
+#define STM_TIM234_SMCR_TS_ITR2 2
+#define STM_TIM234_SMCR_TS_ITR3 3
+#define STM_TIM234_SMCR_TS_TI1F_ED 4
+#define STM_TIM234_SMCR_TS_TI1FP1 5
+#define STM_TIM234_SMCR_TS_TI2FP2 6
+#define STM_TIM234_SMCR_TS_ETRF 7
+#define STM_TIM234_SMCR_TS_MASK 7
+#define STM_TIM234_SMCR_OCCS 3
+#define STM_TIM234_SMCR_SMS 0
+#define STM_TIM234_SMCR_SMS_DISABLE 0
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_1 1
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_2 2
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_3 3
+#define STM_TIM234_SMCR_SMS_RESET_MODE 4
+#define STM_TIM234_SMCR_SMS_GATED_MODE 5
+#define STM_TIM234_SMCR_SMS_TRIGGER_MODE 6
+#define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7
+#define STM_TIM234_SMCR_SMS_MASK 7
+
+#define STM_TIM234_DIER_TDE 14
+#define STM_TIM234_DIER_CC4DE 12
+#define STM_TIM234_DIER_CC3DE 11
+#define STM_TIM234_DIER_CC2DE 10
+#define STM_TIM234_DIER_CC1DE 9
+#define STM_TIM234_DIER_UDE 8
+
+#define STM_TIM234_DIER_TIE 6
+#define STM_TIM234_DIER_CC4IE 4
+#define STM_TIM234_DIER_CC3IE 3
+#define STM_TIM234_DIER_CC2IE 2
+#define STM_TIM234_DIER_CC1IE 1
+#define STM_TIM234_DIER_UIE 0
+
+#define STM_TIM234_SR_CC4OF 12
+#define STM_TIM234_SR_CC3OF 11
+#define STM_TIM234_SR_CC2OF 10
+#define STM_TIM234_SR_CC1OF 9
+#define STM_TIM234_SR_TIF 6
+#define STM_TIM234_SR_CC4IF 4
+#define STM_TIM234_SR_CC3IF 3
+#define STM_TIM234_SR_CC2IF 2
+#define STM_TIM234_SR_CC1IF 1
+#define STM_TIM234_SR_UIF 0
+
+#define STM_TIM234_EGR_TG 6
+#define STM_TIM234_EGR_CC4G 4
+#define STM_TIM234_EGR_CC3G 3
+#define STM_TIM234_EGR_CC2G 2
+#define STM_TIM234_EGR_CC1G 1
+#define STM_TIM234_EGR_UG 0
+
+#define STM_TIM234_CCMR1_OC2CE 15
+#define STM_TIM234_CCMR1_OC2M 12
+#define STM_TIM234_CCMR1_OC2M_FROZEN 0
+#define STM_TIM234_CCMR1_OC2M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR1_OC2M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR1_OC2M_TOGGLE 3
+#define STM_TIM234_CCMR1_OC2M_FORCE_LOW 4
+#define STM_TIM234_CCMR1_OC2M_FORCE_HIGH 5
+#define STM_TIM234_CCMR1_OC2M_PWM_MODE_1 6
+#define STM_TIM234_CCMR1_OC2M_PWM_MODE_2 7
+#define STM_TIM234_CCMR1_OC2M_MASK 7
+#define STM_TIM234_CCMR1_OC2PE 11
+#define STM_TIM234_CCMR1_OC2FE 10
+#define STM_TIM234_CCMR1_CC2S 8
+#define STM_TIM234_CCMR1_CC2S_OUTPUT 0
+#define STM_TIM234_CCMR1_CC2S_INPUT_TI2 1
+#define STM_TIM234_CCMR1_CC2S_INPUT_TI1 2
+#define STM_TIM234_CCMR1_CC2S_INPUT_TRC 3
+#define STM_TIM234_CCMR1_CC2S_MASK 3
+
+#define STM_TIM234_CCMR1_OC1CE 7
+#define STM_TIM234_CCMR1_OC1M 4
+#define STM_TIM234_CCMR1_OC1M_FROZEN 0
+#define STM_TIM234_CCMR1_OC1M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR1_OC1M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM234_CCMR1_OC1M_FORCE_LOW 4
+#define STM_TIM234_CCMR1_OC1M_FORCE_HIGH 5
+#define STM_TIM234_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM234_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM234_CCMR1_OC1M_MASK 7
+#define STM_TIM234_CCMR1_OC1PE 3
+#define STM_TIM234_CCMR1_OC1FE 2
+#define STM_TIM234_CCMR1_CC1S 0
+#define STM_TIM234_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM234_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM234_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM234_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM234_CCMR1_CC1S_MASK 3
+
+#define STM_TIM234_CCMR1_IC2F 12
+#define STM_TIM234_CCMR1_IC2F_NONE 0
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC2PSC 10
+#define STM_TIM234_CCMR1_IC2PSC_NONE 0
+#define STM_TIM234_CCMR1_IC2PSC_2 1
+#define STM_TIM234_CCMR1_IC2PSC_4 2
+#define STM_TIM234_CCMR1_IC2PSC_8 3
+#define STM_TIM234_CCMR1_IC1F 4
+#define STM_TIM234_CCMR1_IC1F_NONE 0
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC1PSC 2
+#define STM_TIM234_CCMR1_IC1PSC_NONE 0
+#define STM_TIM234_CCMR1_IC1PSC_2 1
+#define STM_TIM234_CCMR1_IC1PSC_4 2
+#define STM_TIM234_CCMR1_IC1PSC_8 3
+
+#define STM_TIM234_CCMR2_OC4CE 15
+#define STM_TIM234_CCMR2_OC4M 12
+#define STM_TIM234_CCMR2_OC4M_FROZEN 0
+#define STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR2_OC4M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR2_OC4M_TOGGLE 3
+#define STM_TIM234_CCMR2_OC4M_FORCE_LOW 4
+#define STM_TIM234_CCMR2_OC4M_FORCE_HIGH 5
+#define STM_TIM234_CCMR2_OC4M_PWM_MODE_1 6
+#define STM_TIM234_CCMR2_OC4M_PWM_MODE_2 7
+#define STM_TIM234_CCMR2_OC4M_MASK 7
+#define STM_TIM234_CCMR2_OC4PE 11
+#define STM_TIM234_CCMR2_OC4FE 10
+#define STM_TIM234_CCMR2_CC4S 8
+#define STM_TIM234_CCMR2_CC4S_OUTPUT 0
+#define STM_TIM234_CCMR2_CC4S_INPUT_TI4 1
+#define STM_TIM234_CCMR2_CC4S_INPUT_TI3 2
+#define STM_TIM234_CCMR2_CC4S_INPUT_TRC 3
+#define STM_TIM234_CCMR2_CC4S_MASK 3
+
+#define STM_TIM234_CCMR2_OC3CE 7
+#define STM_TIM234_CCMR2_OC3M 4
+#define STM_TIM234_CCMR2_OC3M_FROZEN 0
+#define STM_TIM234_CCMR2_OC3M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR2_OC3M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR2_OC3M_TOGGLE 3
+#define STM_TIM234_CCMR2_OC3M_FORCE_LOW 4
+#define STM_TIM234_CCMR2_OC3M_FORCE_HIGH 5
+#define STM_TIM234_CCMR2_OC3M_PWM_MODE_1 6
+#define STM_TIM234_CCMR2_OC3M_PWM_MODE_2 7
+#define STM_TIM234_CCMR2_OC3M_MASK 7
+#define STM_TIM234_CCMR2_OC3PE 3
+#define STM_TIM234_CCMR2_OC3FE 2
+#define STM_TIM234_CCMR2_CC3S 0
+#define STM_TIM234_CCMR2_CC3S_OUTPUT 0
+#define STM_TIM234_CCMR2_CC3S_INPUT_TI3 1
+#define STM_TIM234_CCMR2_CC3S_INPUT_TI4 2
+#define STM_TIM234_CCMR2_CC3S_INPUT_TRC 3
+#define STM_TIM234_CCMR2_CC3S_MASK 3
+
+#define STM_TIM234_CCER_CC4NP 15
+#define STM_TIM234_CCER_CC4P 13
+#define STM_TIM234_CCER_CC4P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC4P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC4E 12
+#define STM_TIM234_CCER_CC3NP 11
+#define STM_TIM234_CCER_CC3P 9
+#define STM_TIM234_CCER_CC3P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC3P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC3E 8
+#define STM_TIM234_CCER_CC2NP 7
+#define STM_TIM234_CCER_CC2P 5
+#define STM_TIM234_CCER_CC2P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC2P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC2E 4
+#define STM_TIM234_CCER_CC1NP 3
+#define STM_TIM234_CCER_CC1P 1
+#define STM_TIM234_CCER_CC1P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC1P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC1E 0
+
+struct stm_usb {
+ vuint32_t epr[8];
+ uint8_t reserved_20[0x40 - 0x20];
+ vuint32_t cntr;
+ vuint32_t istr;
+ vuint32_t fnr;
+ vuint32_t daddr;
+ vuint32_t btable;
+};
+
+#define STM_USB_EPR_CTR_RX 15
+#define STM_USB_EPR_CTR_RX_WRITE_INVARIANT 1
+#define STM_USB_EPR_DTOG_RX 14
+#define STM_USB_EPR_DTOG_RX_WRITE_INVARIANT 0
+#define STM_USB_EPR_STAT_RX 12
+#define STM_USB_EPR_STAT_RX_DISABLED 0
+#define STM_USB_EPR_STAT_RX_STALL 1
+#define STM_USB_EPR_STAT_RX_NAK 2
+#define STM_USB_EPR_STAT_RX_VALID 3
+#define STM_USB_EPR_STAT_RX_MASK 3
+#define STM_USB_EPR_STAT_RX_WRITE_INVARIANT 0
+#define STM_USB_EPR_SETUP 11
+#define STM_USB_EPR_EP_TYPE 9
+#define STM_USB_EPR_EP_TYPE_BULK 0
+#define STM_USB_EPR_EP_TYPE_CONTROL 1
+#define STM_USB_EPR_EP_TYPE_ISO 2
+#define STM_USB_EPR_EP_TYPE_INTERRUPT 3
+#define STM_USB_EPR_EP_TYPE_MASK 3
+#define STM_USB_EPR_EP_KIND 8
+#define STM_USB_EPR_EP_KIND_DBL_BUF 1 /* Bulk */
+#define STM_USB_EPR_EP_KIND_STATUS_OUT 1 /* Control */
+#define STM_USB_EPR_CTR_TX 7
+#define STM_USB_CTR_TX_WRITE_INVARIANT 1
+#define STM_USB_EPR_DTOG_TX 6
+#define STM_USB_EPR_DTOG_TX_WRITE_INVARIANT 0
+#define STM_USB_EPR_STAT_TX 4
+#define STM_USB_EPR_STAT_TX_DISABLED 0
+#define STM_USB_EPR_STAT_TX_STALL 1
+#define STM_USB_EPR_STAT_TX_NAK 2
+#define STM_USB_EPR_STAT_TX_VALID 3
+#define STM_USB_EPR_STAT_TX_WRITE_INVARIANT 0
+#define STM_USB_EPR_STAT_TX_MASK 3
+#define STM_USB_EPR_EA 0
+#define STM_USB_EPR_EA_MASK 0xf
+
+#define STM_USB_CNTR_CTRM 15
+#define STM_USB_CNTR_PMAOVRM 14
+#define STM_USB_CNTR_ERRM 13
+#define STM_USB_CNTR_WKUPM 12
+#define STM_USB_CNTR_SUSPM 11
+#define STM_USB_CNTR_RESETM 10
+#define STM_USB_CNTR_SOFM 9
+#define STM_USB_CNTR_ESOFM 8
+#define STM_USB_CNTR_RESUME 4
+#define STM_USB_CNTR_FSUSP 3
+#define STM_USB_CNTR_LP_MODE 2
+#define STM_USB_CNTR_PDWN 1
+#define STM_USB_CNTR_FRES 0
+
+#define STM_USB_ISTR_CTR 15
+#define STM_USB_ISTR_PMAOVR 14
+#define STM_USB_ISTR_ERR 13
+#define STM_USB_ISTR_WKUP 12
+#define STM_USB_ISTR_SUSP 11
+#define STM_USB_ISTR_RESET 10
+#define STM_USB_ISTR_SOF 9
+#define STM_USB_ISTR_ESOF 8
+#define STM_USB_ISTR_DIR 4
+#define STM_USB_ISTR_EP_ID 0
+#define STM_USB_ISTR_EP_ID_MASK 0xf
+
+#define STM_USB_FNR_RXDP 15
+#define STM_USB_FNR_RXDM 14
+#define STM_USB_FNR_LCK 13
+#define STM_USB_FNR_LSOF 11
+#define STM_USB_FNR_LSOF_MASK 0x3
+#define STM_USB_FNR_FN 0
+#define STM_USB_FNR_FN_MASK 0x7ff
+
+#define STM_USB_DADDR_EF 7
+#define STM_USB_DADDR_ADD 0
+#define STM_USB_DADDR_ADD_MASK 0x7f
+
+extern struct stm_usb stm_usb;
+
+union stm_usb_bdt {
+ struct {
+ vuint32_t addr_tx;
+ vuint32_t count_tx;
+ vuint32_t addr_rx;
+ vuint32_t count_rx;
+ } single;
+ struct {
+ vuint32_t addr;
+ vuint32_t count;
+ } double_tx[2];
+ struct {
+ vuint32_t addr;
+ vuint32_t count;
+ } double_rx[2];
+};
+
+#define STM_USB_BDT_COUNT_RX_BL_SIZE 15
+#define STM_USB_BDT_COUNT_RX_NUM_BLOCK 10
+#define STM_USB_BDT_COUNT_RX_NUM_BLOCK_MASK 0x1f
+#define STM_USB_BDT_COUNT_RX_COUNT_RX 0
+#define STM_USB_BDT_COUNT_RX_COUNT_RX_MASK 0x1ff
+
+#define STM_USB_BDT_SIZE 8
+
+extern uint8_t stm_usb_sram[] __attribute__ ((aligned(4)));
+
+struct stm_exti {
+ vuint32_t imr;
+ vuint32_t emr;
+ vuint32_t rtsr;
+ vuint32_t ftsr;
+
+ vuint32_t swier;
+ vuint32_t pr;
+};
+
+extern struct stm_exti stm_exti;
+
+#endif /* _STM32L0_H_ */
--- /dev/null
+/* IOPORT */
+stm_gpioh = 0x50001c00;
+stm_gpioe = 0x50001000;
+stm_gpiod = 0x50000c00;
+stm_gpioc = 0x50000800;
+stm_gpiob = 0x50000400;
+stm_gpioa = 0x50000000;
+
+/* AHB */
+stm_aes = 0x40026000;
+stm_crc = 0x40023000;
+stm_flash = 0x40022000;
+stm_rcc = 0x40021000;
+stm_dma1 = 0x40020000;
+
+/* APB2 */
+stm_dbg = 0x40015800;
+stm_usart1 = 0x40013800;
+stm_spi1 = 0x40013000;
+stm_adc1 = 0x40012400;
+stm_firewall = 0x41011c00;
+stm_tim22 = 0x41011400;
+stm_tim21 = 0x41010800;
+stm_exti = 0x41010400;
+stm_syscfg = 0x41010000;
+stm_comp = 0x41010000;
+
+/* APB1 */
+stm_lptim1 = 0x40007c00;
+stm_i2c3 = 0x40007800;
+stm_pwr = 0x40007000;
+stm_i2c2 = 0x40005800;
+stm_i2c1 = 0x40005400;
+stm_usart5 = 0x40005000;
+stm_usart4 = 0x40004c00;
+stm_lpuart1 = 0x40004800;
+stm_usart2 = 0x40004400;
+stm_spi2 = 0x40003800;
+stm_iwdg = 0x40003000;
+stm_wwdg = 0x40002c00;
+stm_rtc = 0x40002800;
+stm_timer7 = 0x40001400;
+stm_timer6 = 0x40001000;
+stm_timer3 = 0x40000400;
+stm_timer2 = 0x40000000;
+
+/* ARM */
+stm_systick = 0xe000e010;
+
+stm_nvic = 0xe000e100;
+
+stm_scb = 0xe000ed00;
+
+stm_mpu = 0xe000ed90;
+
+/* ID registers */
+stm_flash_size = 0x1ff8007c;
+stm_device_id = 0x1ff80050;