From: Keith Packard Date: Sat, 20 Jun 2020 22:13:09 +0000 (-0700) Subject: altos: Add initial stm32l0 support X-Git-Tag: 1.9.5~1^2~53 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=d907b0fe40d31995848e5b207009ba230da2e36e altos: Add initial stm32l0 support A low-power cortex M0 chip for MicroPeak v2.0 Signed-off-by: Keith Packard --- diff --git a/src/stm32l0/Makefile-flash.defs b/src/stm32l0/Makefile-flash.defs new file mode 100644 index 00000000..08a4b177 --- /dev/null +++ b/src/stm32l0/Makefile-flash.defs @@ -0,0 +1,58 @@ +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: diff --git a/src/stm32l0/Makefile-stm32l0.defs b/src/stm32l0/Makefile-stm32l0.defs new file mode 100644 index 00000000..1eab283a --- /dev/null +++ b/src/stm32l0/Makefile-stm32l0.defs @@ -0,0 +1,16 @@ +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) diff --git a/src/stm32l0/Makefile.defs b/src/stm32l0/Makefile.defs new file mode 100644 index 00000000..911d8dc9 --- /dev/null +++ b/src/stm32l0/Makefile.defs @@ -0,0 +1,7 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/stm32l0/Makefile-stm32l0.defs + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32l0 -Taltos.ld diff --git a/src/stm32l0/altos.ld b/src/stm32l0/altos.ld new file mode 100644 index 00000000..5c9688e3 --- /dev/null +++ b/src/stm32l0/altos.ld @@ -0,0 +1,31 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +__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 diff --git a/src/stm32l0/ao_arch.h b/src/stm32l0/ao_arch.h new file mode 100644 index 00000000..e51ab319 --- /dev/null +++ b/src/stm32l0/ao_arch.h @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ARCH_H_ +#define _AO_ARCH_H_ + +#include +#include + +/* + * 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_ */ + + diff --git a/src/stm32l0/ao_arch_funcs.h b/src/stm32l0/ao_arch_funcs.h new file mode 100644 index 00000000..5b23081f --- /dev/null +++ b/src/stm32l0/ao_arch_funcs.h @@ -0,0 +1,605 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#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<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_ */ diff --git a/src/stm32l0/ao_dma_stm32l0.c b/src/stm32l0/ao_dma_stm32l0.c new file mode 100644 index 00000000..962b3acc --- /dev/null +++ b/src/stm32l0/ao_dma_stm32l0.c @@ -0,0 +1,202 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "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 +} diff --git a/src/stm32l0/ao_exti.h b/src/stm32l0/ao_exti.h new file mode 100644 index 00000000..1d19a48f --- /dev/null +++ b/src/stm32l0/ao_exti.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#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_ */ diff --git a/src/stm32l0/ao_exti_stm.c b/src/stm32l0/ao_exti_stm.c new file mode 100644 index 00000000..3a2748a9 --- /dev/null +++ b/src/stm32l0/ao_exti_stm.c @@ -0,0 +1,162 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +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) +{ +} diff --git a/src/stm32l0/ao_interrupt.c b/src/stm32l0/ao_interrupt.c new file mode 100644 index 00000000..47effe5f --- /dev/null +++ b/src/stm32l0/ao_interrupt.c @@ -0,0 +1,153 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include + +/* 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(); +} diff --git a/src/stm32l0/ao_pwm_stm.c b/src/stm32l0/ao_pwm_stm.c new file mode 100644 index 00000000..341f8887 --- /dev/null +++ b/src/stm32l0/ao_pwm_stm.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2015 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "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 \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]); +} diff --git a/src/stm32l0/ao_serial_stm.c b/src/stm32l0/ao_serial_stm.c new file mode 100644 index 00000000..84710044 --- /dev/null +++ b/src/stm32l0/ao_serial_stm.c @@ -0,0 +1,443 @@ +/* + * Copyright © 2020 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include + +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 +} diff --git a/src/stm32l0/ao_spi_stm32l0.c b/src/stm32l0/ao_spi_stm32l0.c new file mode 100644 index 00000000..1a04a289 --- /dev/null +++ b/src/stm32l0/ao_spi_stm32l0.c @@ -0,0 +1,542 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +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 +} diff --git a/src/stm32l0/ao_timer.c b/src/stm32l0/ao_timer.c new file mode 100644 index 00000000..3b77afc0 --- /dev/null +++ b/src/stm32l0/ao_timer.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2020 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include +#if HAS_FAKE_FLIGHT +#include +#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 diff --git a/src/stm32l0/ao_timer_stm32l0.h b/src/stm32l0/ao_timer_stm32l0.h new file mode 100644 index 00000000..d00deffa --- /dev/null +++ b/src/stm32l0/ao_timer_stm32l0.h @@ -0,0 +1,299 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include +#if HAS_FAKE_FLIGHT +#include +#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 +} diff --git a/src/stm32l0/stm32l0.h b/src/stm32l0/stm32l0.h new file mode 100644 index 00000000..6fb88390 --- /dev/null +++ b/src/stm32l0/stm32l0.h @@ -0,0 +1,2113 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _STM32L0_H_ +#define _STM32L0_H_ + +#include + +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_ */ diff --git a/src/stm32l0/stm32l0.ld b/src/stm32l0/stm32l0.ld new file mode 100644 index 00000000..8f867361 --- /dev/null +++ b/src/stm32l0/stm32l0.ld @@ -0,0 +1,58 @@ +/* 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;