From 87b64a15f55ecb20a0f8bb2556e77b45a4d82b82 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Feb 2023 15:44:32 -0800 Subject: [PATCH] altos/stm32f1: More stm32f103 work Serial driver works Interrupts work Signed-off-by: Keith Packard --- src/stm32f1/Makefile-raw.defs | 2 +- src/stm32f1/altos-ram.ld | 2 +- src/stm32f1/ao_arch.h | 3 + src/stm32f1/ao_arch_funcs.h | 228 +++++++ src/stm32f1/ao_clock.c | 12 +- src/stm32f1/ao_exti.h | 50 ++ src/stm32f1/ao_interrupt.c | 4 +- src/stm32f1/ao_serial_stm.c | 576 ++++++++++++++++ src/stm32f1/ao_timer.c | 4 +- src/stm32f1/ao_usb_stm.c | 1172 +++++++++++++++++++++++++++++++++ src/stm32f1/stm32f1.h | 445 +++++++++++-- 11 files changed, 2447 insertions(+), 51 deletions(-) create mode 100644 src/stm32f1/ao_exti.h create mode 100644 src/stm32f1/ao_serial_stm.c create mode 100644 src/stm32f1/ao_usb_stm.c diff --git a/src/stm32f1/Makefile-raw.defs b/src/stm32f1/Makefile-raw.defs index 91d30bd5..a3894ca8 100644 --- a/src/stm32f1/Makefile-raw.defs +++ b/src/stm32f1/Makefile-raw.defs @@ -8,6 +8,6 @@ LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin FLASH_ADDR=0x08000000 -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -Taltos-ram.ld -n +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -Taltos-raw.ld -n .DEFAULT_GOAL=all diff --git a/src/stm32f1/altos-ram.ld b/src/stm32f1/altos-ram.ld index d409d2cb..278d9401 100644 --- a/src/stm32f1/altos-ram.ld +++ b/src/stm32f1/altos-ram.ld @@ -1,7 +1,7 @@ __flash = 0x20000000; __flash_size = 12k; __ram = 0x20003000; -__ram_size = 4k; +__ram_size = 8k; __stack_size = 512; INCLUDE registers.ld diff --git a/src/stm32f1/ao_arch.h b/src/stm32f1/ao_arch.h index de5f2159..74365133 100644 --- a/src/stm32f1/ao_arch.h +++ b/src/stm32f1/ao_arch.h @@ -55,4 +55,7 @@ #define AO_STM_NVIC_LOW_PRIORITY 0xC0 #define AO_STM_NVIC_CLOCK_PRIORITY 0xf0 +#define AO_PCLK1 AO_APB1CLK +#define AO_PCLK2 AO_APB2CLK + #endif /* _AO_ARCH_H_ */ diff --git a/src/stm32f1/ao_arch_funcs.h b/src/stm32f1/ao_arch_funcs.h index db3cf9e4..35e9374f 100644 --- a/src/stm32f1/ao_arch_funcs.h +++ b/src/stm32f1/ao_arch_funcs.h @@ -71,4 +71,232 @@ ao_enable_output(struct stm_gpio *port, int bit, uint8_t v) STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL); } +#if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_SW_FLOW 1 +#else +#define HAS_SERIAL_SW_FLOW 0 +#endif + +#if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_HW_FLOW 1 +#else +#define HAS_SERIAL_HW_FLOW 0 +#endif + +/* ao_serial_stm.c */ +struct ao_stm_usart { + struct ao_fifo rx_fifo; + struct ao_fifo tx_fifo; + struct stm_usart *reg; + uint8_t tx_running; + uint8_t draining; +#if HAS_SERIAL_SW_FLOW + /* RTS - 0 if we have FIFO space, 1 if not + * CTS - 0 if we can send, 0 if not + */ + struct stm_gpio *gpio_rts; + struct stm_gpio *gpio_cts; + uint8_t pin_rts; + uint8_t pin_cts; + uint8_t rts; +#endif +}; + +void +ao_debug_out(char c); + +#if HAS_SERIAL_1 +extern struct ao_stm_usart ao_stm_usart1; +#endif + +#if HAS_SERIAL_2 +extern struct ao_stm_usart ao_stm_usart2; +#endif + +#if HAS_SERIAL_3 +extern struct ao_stm_usart ao_stm_usart3; +#endif + +#define ARM_PUSH32(stack, val) (*(--(stack)) = (val)) + +typedef uint32_t ao_arch_irq_t; + +static inline void +ao_arch_block_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else + asm("cpsid i"); +#endif +} + +static inline void +ao_arch_release_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (0x0)); +#else + asm("cpsie i"); +#endif +} + +static inline uint32_t +ao_arch_irqsave(void) { + uint32_t val; +#ifdef AO_NONMASK_INTERRUPTS + asm("mrs %0,basepri" : "=r" (val)); +#else + asm("mrs %0,primask" : "=r" (val)); +#endif + ao_arch_block_interrupts(); + return val; +} + +static inline void +ao_arch_irqrestore(uint32_t basepri) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (basepri)); +#else + asm("msr primask,%0" : : "r" (basepri)); +#endif +} + +static inline void +ao_arch_memory_barrier(void) { + asm volatile("" ::: "memory"); +} + +static inline void +ao_arch_irq_check(void) { +#ifdef AO_NONMASK_INTERRUPTS + uint32_t basepri; + asm("mrs %0,basepri" : "=r" (basepri)); + if (basepri == 0) + ao_panic(AO_PANIC_IRQ); +#else + uint32_t primask; + asm("mrs %0,primask" : "=r" (primask)); + if ((primask & 1) == 0) + ao_panic(AO_PANIC_IRQ); +#endif +} + +#if HAS_TASK +static inline void +ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start) +{ + uint32_t a = (uint32_t) start; + int i; + + /* Return address (goes into LR) */ + ARM_PUSH32(sp, a); + + /* Clear register values r0-r12 */ + i = 13; + while (i--) + ARM_PUSH32(sp, 0); + + /* APSR */ + ARM_PUSH32(sp, 0); + + /* BASEPRI with interrupts enabled */ + ARM_PUSH32(sp, 0); + + task->sp32 = sp; +} + +static inline void ao_arch_save_regs(void) { + /* Save general registers */ + asm("push {r0-r12,lr}\n"); + + /* Save APSR */ + asm("mrs r0,apsr"); + asm("push {r0}"); + +#ifdef AO_NONMASK_INTERRUPTS + /* Save BASEPRI */ + asm("mrs r0,basepri"); +#else + /* Save PRIMASK */ + asm("mrs r0,primask"); +#endif + 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) ); + +#ifdef AO_NONMASK_INTERRUPTS + /* Restore BASEPRI */ + asm("pop {r0}"); + asm("msr basepri,r0"); +#else + /* Restore PRIMASK */ + asm("pop {r0}"); + asm("msr primask,r0"); +#endif + + /* Restore APSR */ + asm("pop {r0}"); + asm("msr apsr_nczvq,r0"); + + /* Restore general registers */ + asm("pop {r0-r12,lr}\n"); + + /* Return to calling function */ + asm("bx lr"); +} +#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"); +} + +#define ao_arch_isr_stack() + +#endif /* HAS_TASK */ + +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) + +#define ao_arch_reboot() \ + (stm_scb.aircr = ((STM_SCB_AIRCR_VECTKEY_KEY << STM_SCB_AIRCR_VECTKEY) | \ + (1 << STM_SCB_AIRCR_SYSRESETREQ))) + #endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/stm32f1/ao_clock.c b/src/stm32f1/ao_clock.c index 1ce32a90..c203b012 100644 --- a/src/stm32f1/ao_clock.c +++ b/src/stm32f1/ao_clock.c @@ -69,16 +69,12 @@ ao_clock_init(void) asm("nop"); #endif -#if 0 - /* Set flash latency to tolerate 32MHz SYSCLK -> 1 wait state */ + /* Set flash latency to tolerate 72MHz SYSCLK -> 2 wait states */ /* Enable 64-bit access and prefetch */ - stm_flash.acr |= (1 << STM_FLASH_ACR_ACC64); - stm_flash.acr |= (1 << STM_FLASH_ACR_PRFEN); - - /* Enable 1 wait state so the CPU can run at 32MHz */ - stm_flash.acr |= (1 << STM_FLASH_ACR_LATENCY); -#endif + stm_flash.acr = ((1 << STM_FLASH_ACR_PRFTBE) | + (0 << STM_FLASH_ACR_HLFCYA) | + (STM_FLASH_ACR_LATENCY_2 << STM_FLASH_ACR_LATENCY)); /* Enable power interface clock */ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); diff --git a/src/stm32f1/ao_exti.h b/src/stm32f1/ao_exti.h new file mode 100644 index 00000000..1d19a48f --- /dev/null +++ b/src/stm32f1/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/stm32f1/ao_interrupt.c b/src/stm32f1/ao_interrupt.c index 831a2c2a..2259aefc 100644 --- a/src/stm32f1/ao_interrupt.c +++ b/src/stm32f1/ao_interrupt.c @@ -27,7 +27,7 @@ extern void main(void); void stm_halt_isr(void) { -// ao_panic(AO_PANIC_CRASH); + ao_panic(AO_PANIC_CRASH); } void stm_ignore_isr(void) @@ -212,5 +212,5 @@ void __attribute__((constructor)) ao_setup(void) { } #endif /* Set interrupt vector table offset */ - stm_nvic.vto = (uint32_t) &__interrupt_vector; + stm_scb.vtor = (uint32_t) &__interrupt_vector; } diff --git a/src/stm32f1/ao_serial_stm.c b/src/stm32f1/ao_serial_stm.c new file mode 100644 index 00000000..f5d51088 --- /dev/null +++ b/src/stm32f1/ao_serial_stm.c @@ -0,0 +1,576 @@ +/* + * 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 + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); + while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE))); + stm_usart1.dr = c; +} + +static volatile uint8_t tx; + +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->sr & (1 << STM_USART_SR_TXE)) + { + usart->tx_running = 1; + usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); + ao_fifo_remove(usart->tx_fifo, tx); + usart->reg->dr = tx; + 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->sr & (1 << STM_USART_SR_RXNE)) { + if (!ao_fifo_full(usart->rx_fifo)) { + ao_fifo_insert(usart->rx_fifo, (char) usart->reg->dr); + 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 &= ~(1UL << 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 &= ~(1UL << STM_USART_CR1_TXEIE); + + if (usart->reg->sr & (1 << STM_USART_SR_TC)) { + usart->tx_running = 0; + usart->reg->cr1 &= ~(1UL << 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; +} + +static inline uint8_t +_ao_usart_sleep_for(struct ao_stm_usart *usart, AO_TICK_TYPE timeout) +{ + return ao_sleep_for(&usart->rx_fifo, timeout); +} + +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 struct { + uint32_t baud; +} 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) +{ + uint32_t brr; + + if (speed > AO_SERIAL_SPEED_115200) + return; + if (usart == &ao_stm_usart1) + brr = AO_PCLK2 / ao_usart_speeds[speed].baud; + else + brr = AO_PCLK1 / ao_usart_speeds[speed].baud; + usart->reg->brr = brr; +} + +static void +ao_usart_init(struct ao_stm_usart *usart, int hw_flow) +{ + usart->reg->cr1 = ((1 << STM_USART_CR1_UE) | + (0 << STM_USART_CR1_M) | + (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_RWU) | + (0 << STM_USART_CR1_SBK)); + + usart->reg->cr2 = ((0 << STM_USART_CR2_LINEN) | + (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) | + (0 << STM_USART_CR2_CLKEN) | + (0 << STM_USART_CR2_CPOL) | + (0 << STM_USART_CR2_CPHA) | + (0 << STM_USART_CR2_LBCL) | + (0 << STM_USART_CR2_LBDIE) | + (0 << STM_USART_CR2_LBDL) | + (0 << STM_USART_CR2_ADD)); + + usart->reg->cr3 = ((0 << STM_USART_CR3_CTSIE) | + (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) + usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | + (1 << STM_USART_CR3_RTSE)); + + /* Pick a 9600 baud rate */ + ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); +} + +#if HAS_SERIAL_HW_FLOW +static void +ao_usart_set_flow(struct ao_stm_usart *usart) +{ +} +#endif + +#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); +} + +uint8_t +_ao_serial1_sleep_for(AO_TICK_TYPE timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart1, timeout); +} + +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); +} + +uint8_t +_ao_serial2_sleep_for(AO_TICK_TYPE timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart2, timeout); +} + +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 HAS_SERIAL_SW_FLOW +static void +ao_serial2_cts(void) +{ + _ao_usart_cts(&ao_stm_usart2); +} +#endif + +#endif /* HAS_SERIAL_2 */ + +#if HAS_SERIAL_3 + +struct ao_stm_usart ao_stm_usart3; + +void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); } + +char +ao_serial3_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart3); +} + +void +ao_serial3_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart3, c); +} + +int +_ao_serial3_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart3); +} + +uint8_t +_ao_serial3_sleep_for(AO_TICK_TYPE timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart3, timeout); +} + +void +ao_serial3_set_speed(uint8_t speed) +{ + ao_usart_drain(&ao_stm_usart3); + ao_usart_set_speed(&ao_stm_usart3, speed); +} + +void +ao_serial3_drain(void) +{ + ao_usart_drain(&ao_stm_usart3); +} +#endif /* HAS_SERIAL_3 */ + +#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, + uint8_t pin_rts, + struct stm_gpio *port_cts, + uint8_t 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_init(void) +{ +#if HAS_SERIAL_1 + /* + * TX RX + * PA9 PA10 + * PB6 PB7 * + */ + +#if SERIAL_1_PA9_PA10 + ao_enable_port(&stm_gpioa); + stm_gpio_conf(&stm_gpioa, 9, + STM_GPIO_CR_MODE_OUTPUT_2MHZ, + STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL); + + stm_gpio_conf(&stm_gpioa, 10, + STM_GPIO_CR_MODE_INPUT, + STM_GPIO_CR_CNF_INPUT_FLOATING); + + stm_set_afio_mapr(STM_AFIO_MAPR_USART1_REMAP, + STM_AFIO_MAPR_USART1_REMAP_PA9_PA10, + STM_AFIO_MAPR_USART1_REMAP_MASK); +#else +#if SERIAL_1_PB6_PB7 + ao_enable_port(&stm_gpiob); + stm_gpio_conf(&stm_gpiob, 6, + STM_GPIO_CR_MODE_OUTPUT_2MHZ, + STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL); + + stm_gpio_conf(&stm_gpiob, 7, + STM_GPIO_CR_MODE_INPUT, + STM_GPIO_CR_CNF_INPUT_FLOATING); + + stm_set_afio_mapr(STM_AFIO_MAPR_USART1_REMAP, + STM_AFIO_MAPR_USART1_REMAP_PB6_PB7, + STM_AFIO_MAPR_USART1_REMAP_MASK); +#else +#error "No SERIAL_1 port configuration specified" +#endif +#endif + /* Enable USART */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); + + ao_stm_usart1.reg = &stm_usart1; + ao_usart_init(&ao_stm_usart1, 0); + + stm_nvic_set_enable(STM_ISR_USART1_POS); + stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY); +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN + ao_add_stdio(_ao_serial1_pollchar, + ao_serial1_putchar, + NULL); +#endif +#endif + +#if HAS_SERIAL_2 + /* + * TX RX + * PA2 PA3 + * PD5 PD6 + */ + +#if SERIAL_2_PA2_PA3 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + + stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7); + stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7); +# if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_SW_FLOW + ao_serial_set_sw_rts_cts(&ao_stm_usart2, + ao_serial2_cts, + SERIAL_2_PORT_RTS, + SERIAL_2_PIN_RTS, + SERIAL_2_PORT_CTS, + SERIAL_2_PIN_CTS); +# else + stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7); + stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7); +# endif +# endif +#else +#if SERIAL_2_PD5_PD6 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); + + stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7); + stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7); +#if USE_SERIAL_2_FLOW +#error "Don't know how to set flowcontrol for serial 2 on PD" +#endif +#else +#error "No SERIAL_2 port configuration specified" +#endif +#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, AO_STM_NVIC_MED_PRIORITY); +#if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN + ao_add_stdio(_ao_serial2_pollchar, + ao_serial2_putchar, + NULL); +#endif +#endif + +#if HAS_SERIAL_3 + /* + * TX RX + * PB10 PB11 + * PC10 PC11 + * PD8 PD9 + */ +#if SERIAL_3_PB10_PB11 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); + + stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7); + stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7); +#else +#if SERIAL_3_PC10_PC11 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN); + + stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7); + stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7); +#else +#if SERIAL_3_PD8_PD9 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); + + stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7); + stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7); +#else +#error "No SERIAL_3 port configuration specified" +#endif +#endif +#endif + /* Enable USART */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN); + + ao_stm_usart3.reg = &stm_usart3; + ao_usart_init(&ao_stm_usart3, 0); + + stm_nvic_set_enable(STM_ISR_USART3_POS); + stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY); +#if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN + ao_add_stdio(_ao_serial3_pollchar, + ao_serial3_putchar, + NULL); +#endif +#endif +} diff --git a/src/stm32f1/ao_timer.c b/src/stm32f1/ao_timer.c index 116d33ac..37c4e1df 100644 --- a/src/stm32f1/ao_timer.c +++ b/src/stm32f1/ao_timer.c @@ -51,7 +51,7 @@ void stm_systick_isr(void) { if (stm_systick.ctrl & (1 << STM_SYSTICK_CTRL_COUNTFLAG)) { ++ao_tick_count; -// ao_task_check_alarm(); + ao_task_check_alarm(); #ifdef AO_TIMER_HOOK AO_TIMER_HOOK; #endif @@ -68,5 +68,5 @@ ao_timer_init(void) stm_systick.ctrl = ((1 << STM_SYSTICK_CTRL_ENABLE) | (1 << STM_SYSTICK_CTRL_TICKINT) | (STM_SYSTICK_CTRL_CLKSOURCE_HCLK_8 << STM_SYSTICK_CTRL_CLKSOURCE)); -// stm_nvic.shpr15_12 |= (uint32_t) AO_STM_NVIC_CLOCK_PRIORITY << 24; + stm_scb.shpr3 |= (uint32_t) AO_STM_NVIC_CLOCK_PRIORITY << 24; } diff --git a/src/stm32f1/ao_usb_stm.c b/src/stm32f1/ao_usb_stm.c new file mode 100644 index 00000000..3d632dde --- /dev/null +++ b/src/stm32f1/ao_usb_stm.c @@ -0,0 +1,1172 @@ +/* + * Copyright © 2023 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "ao_usb.h" +#include "ao_product.h" + +#define USB_DEBUG 0 +#define USB_DEBUG_DATA 0 +#define USB_ECHO 0 + +#ifndef USE_USB_STDIO +#define USE_USB_STDIO 1 +#endif + +#if USE_USB_STDIO +#define AO_USB_OUT_SLEEP_ADDR (&ao_stdin_ready) +#else +#define AO_USB_OUT_SLEEP_ADDR (&ao_usb_out_avail) +#endif + +#if USB_DEBUG +#define debug(format, args...) printf(format, ## args); +#else +#define debug(format, args...) +#endif + +#if USB_DEBUG_DATA +#define debug_data(format, args...) printf(format, ## args); +#else +#define debug_data(format, args...) +#endif + +struct ao_usb_setup { + uint8_t dir_type_recip; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +} ao_usb_setup; + +static uint8_t ao_usb_ep0_state; + +/* Pending EP0 IN data */ +static const uint8_t *ao_usb_ep0_in_data; /* Remaining data */ +static uint8_t ao_usb_ep0_in_len; /* Remaining amount */ + +/* Temp buffer for smaller EP0 in data */ +static uint8_t ao_usb_ep0_in_buf[2]; + +/* Pending EP0 OUT data */ +static uint8_t *ao_usb_ep0_out_data; +static uint8_t ao_usb_ep0_out_len; + +/* + * Objects allocated in special USB memory + */ + +/* Buffer description tables */ +static union stm_usb_bdt *ao_usb_bdt; +/* USB address of end of allocated storage */ +static uint16_t ao_usb_sram_addr; + +/* Pointer to ep0 tx/rx buffers in USB memory */ +static uint32_t *ao_usb_ep0_tx_buffer; +static uint32_t *ao_usb_ep0_rx_buffer; + +/* Pointer to bulk data tx/rx buffers in USB memory */ +static uint32_t *ao_usb_in_tx_buffer; +static uint32_t *ao_usb_out_rx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ +static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE]; +static uint8_t ao_usb_tx_count; + +static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE]; +static uint8_t ao_usb_rx_count, ao_usb_rx_pos; + +/* + * End point register indices + */ + +#define AO_USB_CONTROL_EPR 0 +#define AO_USB_INT_EPR 1 +#define AO_USB_OUT_EPR 2 +#define AO_USB_IN_EPR 3 + +/* Marks when we don't need to send an IN packet. + * This happens only when the last IN packet is not full, + * otherwise the host will expect to keep seeing packets. + * Send a zero-length packet as required + */ +static uint8_t ao_usb_in_flushed; + +/* Marks when we have delivered an IN packet to the hardware + * and it has not been received yet. ao_sleep on this address + * to wait for it to be delivered. + */ +static uint8_t ao_usb_in_pending; + +/* Marks when an OUT packet has been received by the hardware + * but not pulled to the shadow buffer. + */ +static uint8_t ao_usb_out_avail; +uint8_t ao_usb_running; +static uint8_t ao_usb_configuration; + +#define AO_USB_EP0_GOT_RESET 1 +#define AO_USB_EP0_GOT_SETUP 2 +#define AO_USB_EP0_GOT_RX_DATA 4 +#define AO_USB_EP0_GOT_TX_ACK 8 + +static uint8_t ao_usb_ep0_receive; +static uint8_t ao_usb_address; +static uint8_t ao_usb_address_pending; + +static inline uint32_t set_toggle(uint32_t current_value, + uint32_t mask, + uint32_t desired_value) +{ + return (current_value ^ desired_value) & mask; +} + +static inline uint32_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) +{ + return (uint32_t *) (((void *) ((uint8_t *) stm_usb_sram + 2 * sram_addr))); +} + +static inline uint32_t ao_usb_epr_stat_rx(uint32_t epr) { + return (epr >> STM_USB_EPR_STAT_RX) & STM_USB_EPR_STAT_RX_MASK; +} + +static inline uint32_t ao_usb_epr_stat_tx(uint32_t epr) { + return (epr >> STM_USB_EPR_STAT_TX) & STM_USB_EPR_STAT_TX_MASK; +} + +static inline uint32_t ao_usb_epr_ctr_rx(uint32_t epr) { + return (epr >> STM_USB_EPR_CTR_RX) & 1; +} + +static inline uint32_t ao_usb_epr_ctr_tx(uint32_t epr) { + return (epr >> STM_USB_EPR_CTR_TX) & 1; +} + +static inline uint32_t ao_usb_epr_setup(uint32_t epr) { + return (epr >> STM_USB_EPR_SETUP) & 1; +} + +static inline uint32_t ao_usb_epr_dtog_rx(uint32_t epr) { + return (epr >> STM_USB_EPR_DTOG_RX) & 1; +} + +static inline uint32_t ao_usb_epr_dtog_tx(uint32_t epr) { + return (epr >> STM_USB_EPR_DTOG_TX) & 1; +} + +/* + * Set current device address and mark the + * interface as active + */ +static void +ao_usb_set_address(uint8_t address) +{ + debug("ao_usb_set_address %02x\n", address); + stm_usb.daddr = (1 << STM_USB_DADDR_EF) | address; + ao_usb_address_pending = 0; +} + +/* + * Write these values to preserve register contents under HW changes + */ + +#define STM_USB_EPR_INVARIANT ((1 << STM_USB_EPR_CTR_RX) | \ + (STM_USB_EPR_DTOG_RX_WRITE_INVARIANT << STM_USB_EPR_DTOG_RX) | \ + (STM_USB_EPR_STAT_RX_WRITE_INVARIANT << STM_USB_EPR_STAT_RX) | \ + (1 << STM_USB_EPR_CTR_TX) | \ + (STM_USB_EPR_DTOG_TX_WRITE_INVARIANT << STM_USB_EPR_DTOG_TX) | \ + (STM_USB_EPR_STAT_TX_WRITE_INVARIANT << STM_USB_EPR_STAT_TX)) + +#define STM_USB_EPR_INVARIANT_MASK ((1 << STM_USB_EPR_CTR_RX) | \ + (STM_USB_EPR_DTOG_RX_MASK << STM_USB_EPR_DTOG_RX) | \ + (STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX) | \ + (1 << STM_USB_EPR_CTR_TX) | \ + (STM_USB_EPR_DTOG_TX_MASK << STM_USB_EPR_DTOG_TX) | \ + (STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX)) + +/* + * These bits are purely under sw control, so preserve them in the + * register by re-writing what was read + */ +#define STM_USB_EPR_PRESERVE_MASK ((STM_USB_EPR_EP_TYPE_MASK << STM_USB_EPR_EP_TYPE) | \ + (1 << STM_USB_EPR_EP_KIND) | \ + (STM_USB_EPR_EA_MASK << STM_USB_EPR_EA)) + +#define TX_DBG 0 +#define RX_DBG 0 + +#if TX_DBG +#define _tx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _tx_dbg0(msg) +#define _tx_dbg1(msg,value) +#endif + +#if RX_DBG +#define _rx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _rx_dbg0(msg) +#define _rx_dbg1(msg,value) +#endif + +#if TX_DBG || RX_DBG +static void _dbg(int line, char *msg, uint32_t value); +#endif + +/* + * Set the state of the specified endpoint register to a new + * value. This is tricky because the bits toggle where the new + * value is one, and we need to write invariant values in other + * spots of the register. This hardware is strange... + */ +static void +_ao_usb_set_stat_tx(int ep, uint32_t stat_tx) +{ + uint32_t epr_write, epr_old; + + _tx_dbg1("set_stat_tx top", stat_tx); + epr_old = epr_write = stm_usb.epr[ep]; + epr_write &= STM_USB_EPR_PRESERVE_MASK; + epr_write |= STM_USB_EPR_INVARIANT; + epr_write |= set_toggle(epr_old, + STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX, + stat_tx << STM_USB_EPR_STAT_TX); + stm_usb.epr[ep] = epr_write; + _tx_dbg1("set_stat_tx bottom", epr_write); +} + +static void +ao_usb_set_stat_tx(int ep, uint32_t stat_tx) +{ + ao_arch_block_interrupts(); + _ao_usb_set_stat_tx(ep, stat_tx); + ao_arch_release_interrupts(); +} + +static void +_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { + uint32_t epr_write, epr_old; + + epr_write = epr_old = stm_usb.epr[ep]; + epr_write &= STM_USB_EPR_PRESERVE_MASK; + epr_write |= STM_USB_EPR_INVARIANT; + epr_write |= set_toggle(epr_old, + STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX, + stat_rx << STM_USB_EPR_STAT_RX); + stm_usb.epr[ep] = epr_write; +} + +static void +ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { + ao_arch_block_interrupts(); + _ao_usb_set_stat_rx(ep, stat_rx); + ao_arch_release_interrupts(); +} + +/* + * Set just endpoint 0, for use during startup + */ + +static void +ao_usb_init_ep(uint8_t ep, uint32_t addr, uint32_t type, uint32_t stat_rx, uint32_t stat_tx) +{ + uint32_t epr; + ao_arch_block_interrupts(); + epr = stm_usb.epr[ep]; + epr = ((0 << STM_USB_EPR_CTR_RX) | + (epr & (1 << STM_USB_EPR_DTOG_RX)) | + set_toggle(epr, + (STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX), + (stat_rx << STM_USB_EPR_STAT_RX)) | + (type << STM_USB_EPR_EP_TYPE) | + (0 << STM_USB_EPR_EP_KIND) | + (0 << STM_USB_EPR_CTR_TX) | + (epr & (1 << STM_USB_EPR_DTOG_TX)) | + set_toggle(epr, + (STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX), + (stat_tx << STM_USB_EPR_STAT_TX)) | + (addr << STM_USB_EPR_EA)); + stm_usb.epr[ep] = epr; + ao_arch_release_interrupts(); + debug ("writing epr[%d] 0x%08x wrote 0x%08x\n", + ep, epr, stm_usb.epr[ep]); +} + +static void +ao_usb_set_ep0(void) +{ + uint8_t e; + + ao_usb_sram_addr = 0; + + /* buffer table is at the start of USB memory */ + stm_usb.btable = 0; + ao_usb_bdt = (void *) stm_usb_sram; + + ao_usb_sram_addr += 8 * STM_USB_BDT_SIZE; + + /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */ + + ao_usb_bdt[0].single.addr_tx = ao_usb_sram_addr; + ao_usb_bdt[0].single.count_tx = 0; + ao_usb_ep0_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + + ao_usb_bdt[0].single.addr_rx = ao_usb_sram_addr; + ao_usb_bdt[0].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | + (((AO_USB_CONTROL_SIZE / 32) - 1) << STM_USB_BDT_COUNT_RX_NUM_BLOCK)); + ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + + ao_usb_init_ep(AO_USB_CONTROL_EPR, AO_USB_CONTROL_EP, + STM_USB_EPR_EP_TYPE_CONTROL, + STM_USB_EPR_STAT_RX_VALID, + STM_USB_EPR_STAT_TX_NAK); + + /* Clear all of the other endpoints */ + for (e = 1; e < 8; e++) { + ao_usb_init_ep(e, 0, + STM_USB_EPR_EP_TYPE_CONTROL, + STM_USB_EPR_STAT_RX_DISABLED, + STM_USB_EPR_STAT_TX_DISABLED); + } + + ao_usb_set_address(0); + + ao_usb_running = 0; + + /* Reset our internal state + */ + + ao_usb_ep0_state = AO_USB_EP0_IDLE; + + ao_usb_ep0_in_data = NULL; + ao_usb_ep0_in_len = 0; + + ao_usb_ep0_out_data = 0; + ao_usb_ep0_out_len = 0; +} + +static void +ao_usb_set_configuration(void) +{ + debug ("ao_usb_set_configuration\n"); + + /* Set up the INT end point */ + ao_usb_bdt[AO_USB_INT_EPR].single.addr_tx = ao_usb_sram_addr; + ao_usb_bdt[AO_USB_INT_EPR].single.count_tx = 0; + ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_sram_addr += AO_USB_INT_SIZE; + + ao_usb_init_ep(AO_USB_INT_EPR, + AO_USB_INT_EP, + STM_USB_EPR_EP_TYPE_INTERRUPT, + STM_USB_EPR_STAT_RX_DISABLED, + STM_USB_EPR_STAT_TX_NAK); + + /* Set up the OUT end point */ + ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_sram_addr; + ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | + (((AO_USB_OUT_SIZE / 32) - 1) << STM_USB_BDT_COUNT_RX_NUM_BLOCK)); + ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_sram_addr += AO_USB_OUT_SIZE; + + ao_usb_init_ep(AO_USB_OUT_EPR, + AO_USB_OUT_EP, + STM_USB_EPR_EP_TYPE_BULK, + STM_USB_EPR_STAT_RX_VALID, + STM_USB_EPR_STAT_TX_DISABLED); + + /* Set up the IN end point */ + ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_sram_addr; + ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0; + ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_sram_addr += AO_USB_IN_SIZE; + + ao_usb_init_ep(AO_USB_IN_EPR, + AO_USB_IN_EP, + STM_USB_EPR_EP_TYPE_BULK, + STM_USB_EPR_STAT_RX_DISABLED, + STM_USB_EPR_STAT_TX_NAK); + + ao_usb_in_flushed = 0; + ao_usb_in_pending = 0; + ao_wakeup(&ao_usb_in_pending); + + ao_usb_out_avail = 0; + ao_usb_configuration = 0; + + ao_usb_running = 1; + ao_wakeup(&ao_usb_running); +} + +static uint16_t control_count; +static uint16_t int_count; +static uint16_t in_count; +static uint16_t out_count; +static uint16_t reset_count; + +/* The USB memory holds 16 bit values on 32 bit boundaries + * and must be accessed only in 32 bit units. Sigh. + */ + +static inline void +ao_usb_write_byte(uint8_t byte, uint32_t *base, uint16_t offset) +{ + base += offset >> 1; + if (offset & 1) { + *base = (*base & 0xff) | ((uint32_t) byte << 8); + } else { + *base = (*base & 0xff00) | byte; + } +} + +static inline void +ao_usb_write_short(uint16_t data, uint32_t *base, uint16_t offset) +{ + base[offset>>1] = data; +} + +static void +ao_usb_write(const uint8_t *src, uint32_t *base, uint16_t bytes) +{ + uint16_t offset = 0; + if (!bytes) + return; + while (bytes >= 2) { + debug_data (" %02x %02x", src[0], src[1]); + ao_usb_write_short((uint16_t) ((uint16_t) (src[1] << 8) | (uint16_t) src[0]), base, offset); + offset += 2; + src += 2; + bytes -= 2; + } + if (bytes) { + debug_data (" %02x", src[0]); + ao_usb_write_byte(*src, base, offset); + } +} + +static inline uint8_t +ao_usb_read_byte(uint32_t *base, uint16_t offset) +{ + base += offset >> 1; + if (offset & 1) + return (*base >> 8) & 0xff; + else + return *base & 0xff; +} + +static inline uint16_t +ao_usb_read_short(uint32_t *base, uint16_t offset) +{ + return (uint16_t) (base[offset>>1]); +} + +static void +ao_usb_read(uint8_t *dst, uint32_t *base, uint16_t offset, uint16_t bytes) +{ + if (!bytes) + return; + if (offset & 1) { + *dst++ = ao_usb_read_byte(base, offset++); + debug_data (" %02x", dst[-1]); + bytes--; + } + while (bytes >= 2) { + uint16_t s = ao_usb_read_short(base, offset); + dst[0] = (uint8_t) s; + dst[1] = (uint8_t) (s >> 8); + debug_data (" %02x %02x", dst[0], dst[1]); + offset += 2; + dst += 2; + bytes -= 2; + } + if (bytes) { + *dst = ao_usb_read_byte(base, offset); + debug_data (" %02x", dst[0]); + } +} + +/* Send an IN data packet */ +static void +ao_usb_ep0_flush(void) +{ + uint8_t this_len; + + /* Check to see if the endpoint is still busy */ + if (ao_usb_epr_stat_tx(stm_usb.epr[0]) == STM_USB_EPR_STAT_TX_VALID) { + debug("EP0 not accepting IN data\n"); + return; + } + + this_len = ao_usb_ep0_in_len; + if (this_len > AO_USB_CONTROL_SIZE) + this_len = AO_USB_CONTROL_SIZE; + + if (this_len < AO_USB_CONTROL_SIZE) + ao_usb_ep0_state = AO_USB_EP0_IDLE; + + ao_usb_ep0_in_len -= this_len; + + debug_data ("Flush EP0 len %d:", this_len); + ao_usb_write(ao_usb_ep0_in_data, ao_usb_ep0_tx_buffer, this_len); + debug_data ("\n"); + ao_usb_ep0_in_data += this_len; + + /* Mark the endpoint as TX valid to send the packet */ + ao_usb_bdt[AO_USB_CONTROL_EPR].single.count_tx = this_len; + ao_usb_set_stat_tx(AO_USB_CONTROL_EPR, STM_USB_EPR_STAT_TX_VALID); + debug ("queue tx. epr 0 now %08x\n", stm_usb.epr[AO_USB_CONTROL_EPR]); +} + +/* Read data from the ep0 OUT fifo */ +static void +ao_usb_ep0_fill(void) +{ + uint16_t len = ao_usb_bdt[0].single.count_rx & STM_USB_BDT_COUNT_RX_COUNT_RX_MASK; + + if (len > ao_usb_ep0_out_len) + len = ao_usb_ep0_out_len; + ao_usb_ep0_out_len -= (uint8_t) len; + + /* Pull all of the data out of the packet */ + debug_data ("Fill EP0 len %d:", len); + ao_usb_read(ao_usb_ep0_out_data, ao_usb_ep0_rx_buffer, 0, len); + debug_data ("\n"); + ao_usb_ep0_out_data += len; + + /* ACK the packet */ + ao_usb_set_stat_rx(0, STM_USB_EPR_STAT_RX_VALID); +} + +static void +ao_usb_ep0_in_reset(void) +{ + ao_usb_ep0_in_data = ao_usb_ep0_in_buf; + ao_usb_ep0_in_len = 0; +} + +static void +ao_usb_ep0_in_queue_byte(uint8_t a) +{ + if (ao_usb_ep0_in_len < sizeof (ao_usb_ep0_in_buf)) + ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; +} + +static void +ao_usb_ep0_in_set(const uint8_t *data, uint8_t len) +{ + ao_usb_ep0_in_data = data; + ao_usb_ep0_in_len = len; +} + +static void +ao_usb_ep0_out_set(uint8_t *data, uint8_t len) +{ + ao_usb_ep0_out_data = data; + ao_usb_ep0_out_len = len; +} + +static void +ao_usb_ep0_in_start(uint16_t max) +{ + /* Don't send more than asked for */ + if (ao_usb_ep0_in_len > max) + ao_usb_ep0_in_len = (uint8_t) max; + ao_usb_ep0_flush(); +} + +struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; + +/* Walk through the list of descriptors and find a match + */ +static void +ao_usb_get_descriptor(uint16_t value, uint16_t length) +{ + const uint8_t *descriptor; + uint8_t type = (uint8_t) (value >> 8); + uint8_t index = (uint8_t) value; + + descriptor = ao_usb_descriptors; + while (descriptor[0] != 0) { + if (descriptor[1] == type && index-- == 0) { + uint8_t len; + if (type == AO_USB_DESC_CONFIGURATION) + len = descriptor[2]; + else + len = descriptor[0]; + if (len > length) + len = (uint8_t) length; + ao_usb_ep0_in_set(descriptor, len); + break; + } + descriptor += descriptor[0]; + } +} + +static void +ao_usb_ep0_setup(void) +{ + /* Pull the setup packet out of the fifo */ + ao_usb_ep0_out_set((uint8_t *) &ao_usb_setup, 8); + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len != 0) { + debug ("invalid setup packet length\n"); + return; + } + + if ((ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) || ao_usb_setup.length == 0) + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + else + ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + + ao_usb_ep0_in_reset(); + + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { + case AO_USB_TYPE_STANDARD: + debug ("Standard setup packet\n"); + switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { + case AO_USB_RECIP_DEVICE: + debug ("Device setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + debug ("get status\n"); + ao_usb_ep0_in_queue_byte(0); + ao_usb_ep0_in_queue_byte(0); + break; + case AO_USB_REQ_SET_ADDRESS: + debug ("set address %d\n", ao_usb_setup.value); + ao_usb_address = (uint8_t) ao_usb_setup.value; + ao_usb_address_pending = 1; + break; + case AO_USB_REQ_GET_DESCRIPTOR: + debug ("get descriptor %d\n", ao_usb_setup.value); + ao_usb_get_descriptor(ao_usb_setup.value, ao_usb_setup.length); + break; + case AO_USB_REQ_GET_CONFIGURATION: + debug ("get configuration %d\n", ao_usb_configuration); + ao_usb_ep0_in_queue_byte(ao_usb_configuration); + break; + case AO_USB_REQ_SET_CONFIGURATION: + ao_usb_configuration = (uint8_t) ao_usb_setup.value; + debug ("set configuration %d\n", ao_usb_configuration); + ao_usb_set_configuration(); + break; + } + break; + case AO_USB_RECIP_INTERFACE: + debug ("Interface setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_in_queue_byte(0); + ao_usb_ep0_in_queue_byte(0); + break; + case AO_USB_REQ_GET_INTERFACE: + ao_usb_ep0_in_queue_byte(0); + break; + case AO_USB_REQ_SET_INTERFACE: + break; + } + break; + case AO_USB_RECIP_ENDPOINT: + debug ("Endpoint setup packet\n"); + switch(ao_usb_setup.request) { + case AO_USB_REQ_GET_STATUS: + ao_usb_ep0_in_queue_byte(0); + ao_usb_ep0_in_queue_byte(0); + break; + } + break; + } + break; + case AO_USB_TYPE_CLASS: + debug ("Class setup packet\n"); + switch (ao_usb_setup.request) { + case AO_USB_SET_LINE_CODING: + debug ("set line coding\n"); + ao_usb_ep0_out_set((uint8_t *) &ao_usb_line_coding, 7); + break; + case AO_USB_GET_LINE_CODING: + debug ("get line coding\n"); + ao_usb_ep0_in_set((const uint8_t *) &ao_usb_line_coding, 7); + break; + case AO_USB_SET_CONTROL_LINE_STATE: + break; + } + break; + } + + /* If we're not waiting to receive data from the host, + * queue an IN response + */ + if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) + ao_usb_ep0_in_start(ao_usb_setup.length); +} + +static void +ao_usb_ep0_handle(uint8_t receive) +{ + ao_usb_ep0_receive = 0; + if (receive & AO_USB_EP0_GOT_RESET) { + debug ("\treset\n"); + ao_usb_set_ep0(); + return; + } + if (receive & AO_USB_EP0_GOT_SETUP) { + debug ("\tsetup\n"); + ao_usb_ep0_setup(); + } + if (receive & AO_USB_EP0_GOT_RX_DATA) { + debug ("\tgot rx data\n"); + if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) { + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len == 0) { + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + ao_usb_ep0_in_start(0); + } + } + } + if (receive & AO_USB_EP0_GOT_TX_ACK) { + debug ("\tgot tx ack\n"); + +#if HAS_FLIGHT && AO_USB_FORCE_IDLE + ao_flight_force_idle = 1; +#endif + /* Wait until the IN packet is received from addr 0 + * before assigning our local address + */ + if (ao_usb_address_pending) + ao_usb_set_address(ao_usb_address); + if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) + ao_usb_ep0_flush(); + } +} + +void +stm_usb_lp_isr(void) +{ + uint32_t istr = stm_usb.istr; + + if (istr & (1 << STM_USB_ISTR_CTR)) { + uint8_t ep = istr & STM_USB_ISTR_EP_ID_MASK; + uint32_t epr, epr_write; + + /* Preserve the SW write bits, don't mess with most HW writable bits, + * clear the CTR_RX and CTR_TX bits + */ + epr = stm_usb.epr[ep]; + epr_write = epr; + epr_write &= STM_USB_EPR_PRESERVE_MASK; + epr_write |= STM_USB_EPR_INVARIANT; + epr_write &= ~(1UL << STM_USB_EPR_CTR_RX); + epr_write &= ~(1UL << STM_USB_EPR_CTR_TX); + stm_usb.epr[ep] = epr_write; + + switch (ep) { + case 0: + ++control_count; + if (ao_usb_epr_ctr_rx(epr)) { + if (ao_usb_epr_setup(epr)) + ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP; + else + ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA; + } + if (ao_usb_epr_ctr_tx(epr)) + ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK; + ao_usb_ep0_handle(ao_usb_ep0_receive); + break; + case AO_USB_OUT_EPR: + ++out_count; + if (ao_usb_epr_ctr_rx(epr)) { + _rx_dbg1("RX ISR", epr); + ao_usb_out_avail = 1; + _rx_dbg0("out avail set"); + ao_wakeup(AO_USB_OUT_SLEEP_ADDR); + _rx_dbg0("stdin awoken"); + } + break; + case AO_USB_IN_EPR: + ++in_count; + _tx_dbg1("TX ISR", epr); + if (ao_usb_epr_ctr_tx(epr)) { + ao_usb_in_pending = 0; + ao_wakeup(&ao_usb_in_pending); + } + break; + case AO_USB_INT_EPR: + ++int_count; + if (ao_usb_epr_ctr_tx(epr)) + _ao_usb_set_stat_tx(AO_USB_INT_EPR, STM_USB_EPR_STAT_TX_NAK); + break; + } + return; + } + + if (istr & (1 << STM_USB_ISTR_RESET)) { + ++reset_count; + stm_usb.istr &= ~(1UL << STM_USB_ISTR_RESET); + ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET; + ao_usb_ep0_handle(ao_usb_ep0_receive); + } +} + +void +stm_usb_wakeup_isr(void) +{ + /* USB wakeup, just clear the bit for now */ + stm_usb.istr &= ~(1UL << STM_USB_ISTR_WKUP); +} + +/* Queue the current IN buffer for transmission */ +static void +_ao_usb_in_send(void) +{ + _tx_dbg0("in_send start"); + debug ("send %d\n", ao_usb_tx_count); + while (ao_usb_in_pending) + ao_sleep(&ao_usb_in_pending); + ao_usb_in_pending = 1; + if (ao_usb_tx_count != AO_USB_IN_SIZE) + ao_usb_in_flushed = 1; + ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, ao_usb_tx_count); + ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count; + ao_usb_tx_count = 0; + _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); + _tx_dbg0("in_send end"); +} + +/* Wait for a free IN buffer. Interrupts are blocked */ +static void +_ao_usb_in_wait(void) +{ + for (;;) { + /* Check if the current buffer is writable */ + if (ao_usb_tx_count < AO_USB_IN_SIZE) + break; + + _tx_dbg0("in_wait top"); + /* Wait for an IN buffer to be ready */ + while (ao_usb_in_pending) + ao_sleep(&ao_usb_in_pending); + _tx_dbg0("in_wait bottom"); + } +} + +void +ao_usb_flush(void) +{ + if (!ao_usb_running) + return; + + /* Anytime we've sent a character since + * the last time we flushed, we'll need + * to send a packet -- the only other time + * we would send a packet is when that + * packet was full, in which case we now + * want to send an empty packet + */ + ao_arch_block_interrupts(); + while (!ao_usb_in_flushed) { + _tx_dbg0("flush top"); + _ao_usb_in_send(); + _tx_dbg0("flush end"); + } + ao_arch_release_interrupts(); +} + +void +ao_usb_putchar(char c) +{ + if (!ao_usb_running) + return; + + ao_arch_block_interrupts(); + _ao_usb_in_wait(); + + ao_usb_in_flushed = 0; + ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; + + /* Send the packet when full */ + if (ao_usb_tx_count == AO_USB_IN_SIZE) { + _tx_dbg0("putchar full"); + _ao_usb_in_send(); + _tx_dbg0("putchar flushed"); + } + ao_arch_release_interrupts(); +} + +static void +_ao_usb_out_recv(void) +{ + _rx_dbg0("out_recv top"); + ao_usb_out_avail = 0; + + ao_usb_rx_count = (uint8_t) (ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx & STM_USB_BDT_COUNT_RX_COUNT_RX_MASK); + + _rx_dbg1("out_recv count", ao_usb_rx_count); + debug ("recv %d\n", ao_usb_rx_count); + debug_data("Fill OUT len %d:", ao_usb_rx_count); + ao_usb_read(ao_usb_rx_buffer, ao_usb_out_rx_buffer, 0, ao_usb_rx_count); + debug_data("\n"); + ao_usb_rx_pos = 0; + + /* ACK the packet */ + _ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID); +} + +static int +_ao_usb_pollchar(void) +{ + uint8_t c; + + if (!ao_usb_running) + return AO_READ_AGAIN; + + for (;;) { + if (ao_usb_rx_pos != ao_usb_rx_count) + break; + + _rx_dbg0("poll check"); + /* Check to see if a packet has arrived */ + if (!ao_usb_out_avail) { + _rx_dbg0("poll none"); + return AO_READ_AGAIN; + } + _ao_usb_out_recv(); + } + + /* Pull a character out of the fifo */ + c = ao_usb_rx_buffer[ao_usb_rx_pos++]; + return c; +} + +char +ao_usb_getchar(void) +{ + int c; + + ao_arch_block_interrupts(); + while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) + ao_sleep(AO_USB_OUT_SLEEP_ADDR); + ao_arch_release_interrupts(); + return (char) c; +} + +#ifndef HAS_USB_DISABLE +#define HAS_USB_DISABLE 1 +#endif + +#if HAS_USB_DISABLE +void +ao_usb_disable(void) +{ + ao_arch_block_interrupts(); + stm_usb.cntr = (1 << STM_USB_CNTR_FRES); + stm_usb.istr = 0; + +#if HAS_USB_PULLUP + /* Disable USB pull-up */ + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 0); +#endif + + /* Switch off the device */ + stm_usb.cntr = (1 << STM_USB_CNTR_PDWN) | (1 << STM_USB_CNTR_FRES); + + /* Disable the interface */ + stm_rcc.apb1enr &= ~(1UL << STM_RCC_APB1ENR_USBEN); + ao_arch_release_interrupts(); +} +#endif + +void +ao_usb_enable(void) +{ + int t; + +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 0); +#endif + + /* Enable USB device */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USBEN); + + /* Do not touch the GPIOA configuration; USB takes priority + * over GPIO on pins A11 and A12, but if you select alternate + * input 10 (the documented correct selection), then USB is + * pulled low and doesn't work at all + */ + + ao_arch_block_interrupts(); + + /* Route interrupts */ + stm_nvic_set_priority(STM_ISR_USB_LP_POS, AO_STM_NVIC_LOW_PRIORITY); + stm_nvic_set_enable(STM_ISR_USB_LP_POS); + + ao_usb_configuration = 0; + + stm_usb.cntr = (1 << STM_USB_CNTR_FRES); + + /* Clear the power down bit */ + stm_usb.cntr = 0; + + /* Clear any spurious interrupts */ + stm_usb.istr = 0; + + debug ("ao_usb_enable\n"); + + /* Enable interrupts */ + stm_usb.cntr = ((1 << STM_USB_CNTR_CTRM) | + (0 << STM_USB_CNTR_PMAOVRM) | + (0 << STM_USB_CNTR_ERRM) | + (0 << STM_USB_CNTR_WKUPM) | + (0 << STM_USB_CNTR_SUSPM) | + (1 << STM_USB_CNTR_RESETM) | + (0 << STM_USB_CNTR_SOFM) | + (0 << STM_USB_CNTR_ESOFM) | + (0 << STM_USB_CNTR_RESUME) | + (0 << STM_USB_CNTR_FSUSP) | + (0 << STM_USB_CNTR_LP_MODE) | + (0 << STM_USB_CNTR_PDWN) | + (0 << STM_USB_CNTR_FRES)); + + ao_arch_release_interrupts(); + + for (t = 0; t < 1000; t++) + ao_arch_nop(); + + /* Enable USB pull-up */ +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 1); +#endif +} + +#if USB_ECHO +struct ao_task ao_usb_echo_task; + +static void +ao_usb_echo(void) +{ + char c; + + for (;;) { + c = ao_usb_getchar(); + ao_usb_putchar(c); + ao_usb_flush(); + } +} +#endif + +#if USB_DEBUG +static void +ao_usb_irq(void) +{ + printf ("control: %d out: %d in: %d int: %d reset: %d\n", + control_count, out_count, in_count, int_count, reset_count); +} + +const struct ao_cmds ao_usb_cmds[] = { + { ao_usb_irq, "I\0Show USB interrupt counts" }, + { 0, NULL } +}; +#endif + +void +ao_usb_init(void) +{ +#if HAS_USB_PULLUP + int i; + ao_enable_output(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 0); + for (i = 0; i < 40000; i++) + ao_arch_nop(); +#endif + ao_usb_enable(); + + debug ("ao_usb_init\n"); + ao_usb_ep0_state = AO_USB_EP0_IDLE; +#if USB_ECHO + ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo"); +#endif +#if USB_DEBUG + ao_cmd_register(&ao_usb_cmds[0]); +#endif +#if !USB_ECHO +#if USE_USB_STDIO + ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); +#endif +#endif +} + +#if TX_DBG || RX_DBG + +struct ao_usb_dbg { + int line; + char *msg; + uint32_t value; + uint32_t prival; +#if TX_DBG + uint16_t in_count; + uint32_t in_epr; + uint32_t in_pending; + uint32_t tx_count; + uint32_t in_flushed; +#endif +#if RX_DBG + uint8_t rx_count; + uint8_t rx_pos; + uint8_t out_avail; + uint32_t out_epr; +#endif +}; + +#define NUM_USB_DBG 16 + +static struct ao_usb_dbg dbg[NUM_USB_DBG]; +static int dbg_i; + +static void _dbg(int line, char *msg, uint32_t value) +{ + uint32_t prival; + dbg[dbg_i].line = line; + dbg[dbg_i].msg = msg; + dbg[dbg_i].value = value; +#if AO_NONMASK_INTERRUPT + asm("mrs %0,basepri" : "=&r" (prival)); +#else + asm("mrs %0,primask" : "=&r" (prival)); +#endif + dbg[dbg_i].prival = prival; +#if TX_DBG + dbg[dbg_i].in_count = in_count; + dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; + dbg[dbg_i].in_pending = ao_usb_in_pending; + dbg[dbg_i].tx_count = ao_usb_tx_count; + dbg[dbg_i].in_flushed = ao_usb_in_flushed; +#endif +#if RX_DBG + dbg[dbg_i].rx_count = ao_usb_rx_count; + dbg[dbg_i].rx_pos = ao_usb_rx_pos; + dbg[dbg_i].out_avail = ao_usb_out_avail; + dbg[dbg_i].out_epr = stm_usb.epr[AO_USB_OUT_EPR]; +#endif + if (++dbg_i == NUM_USB_DBG) + dbg_i = 0; +} +#endif diff --git a/src/stm32f1/stm32f1.h b/src/stm32f1/stm32f1.h index 5ac99e6c..b3b97736 100644 --- a/src/stm32f1/stm32f1.h +++ b/src/stm32f1/stm32f1.h @@ -182,8 +182,8 @@ extern struct stm_rcc stm_rcc; #define STM_RCC_APB1ENR_DACEN 29 #define STM_RCC_APB1ENR_PWREN 28 #define STM_RCC_APB1ENR_BKPEN 27 -#define STM_RCC_APB1ENR_CAN2EN 26 -#define STM_RCC_APB1ENR_CAN1EN 25 +#define STM_RCC_APB1ENR_CANEN 26 +#define STM_RCC_APB1ENR_USBEN 23 #define STM_RCC_APB1ENR_I2C2EN 22 #define STM_RCC_APB1ENR_I2C1EN 21 #define STM_RCC_APB1ENR_UART5EN 20 @@ -193,6 +193,9 @@ extern struct stm_rcc stm_rcc; #define STM_RCC_APB1ENR_SPI3EN 15 #define STM_RCC_APB1ENR_SPI2EN 14 #define STM_RCC_APB1ENR_WWDGEN 11 +#define STM_RCC_APB1ENR_TIM14EN 8 +#define STM_RCC_APB1ENR_TIM13EN 7 +#define STM_RCC_APB1ENR_TIM12EN 6 #define STM_RCC_APB1ENR_TIM7EN 5 #define STM_RCC_APB1ENR_TIM6EN 4 #define STM_RCC_APB1ENR_TIM5EN 3 @@ -219,7 +222,7 @@ struct stm_systick { extern struct stm_systick stm_systick; -#define stm_systick (*((struct stm_systick *) 0xe000e010)) +//#define stm_systick (*((struct stm_systick *) 0xe000e010)) #define STM_SYSTICK_CTRL_ENABLE 0 #define STM_SYSTICK_CTRL_TICKINT 1 @@ -231,49 +234,36 @@ extern struct stm_systick stm_systick; /* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */ struct stm_nvic { - vuint32_t iser[8]; /* 0x000 0xe000e100 Set Enable Register */ + vuint32_t iser[3]; /* 0x000 0xe000e100 Set Enable Register */ - uint8_t _unused020[0x080 - 0x020]; + uint8_t _unused00c[0x080 - 0x00c]; - vuint32_t icer[8]; /* 0x080 0xe000e180 Clear Enable Register */ + vuint32_t icer[3]; /* 0x080 0xe000e180 Clear Enable Register */ - uint8_t _unused0a0[0x100 - 0x0a0]; + uint8_t _unused08c[0x100 - 0x08c]; - vuint32_t ispr[8]; /* 0x100 0xe000e200 Set Pending Register */ + vuint32_t ispr[3]; /* 0x100 0xe000e200 Set Pending Register */ - uint8_t _unused120[0x180 - 0x120]; + uint8_t _unused10c[0x180 - 0x10c]; - vuint32_t icpr[8]; /* 0x180 0xe000e280 Clear Pending Register */ + vuint32_t icpr[3]; /* 0x180 0xe000e280 Clear Pending Register */ - uint8_t _unused1a0[0x200 - 0x1a0]; + uint8_t _unused18c[0x200 - 0x18c]; - vuint32_t iabr[8]; /* 0x200 0xe000e300 Active Bit Register */ + vuint32_t iabr[3]; /* 0x200 0xe000e300 Active Bit Register */ - uint8_t _unused220[0x300 - 0x220]; + uint8_t _unused20c[0x300 - 0x20c]; - vuint32_t ipr[60]; /* 0x300 0xe000e400 Priority Register */ + vuint32_t ipr[31]; /* 0x300 0xe000e400 Priority Register */ - uint8_t _unused3f0[0xc00 - 0x3f0]; + uint8_t _unused37c[0xe00 - 0x37c]; /* covers SCB */ - vuint32_t cpuid_base; /* 0xc00 0xe000ed00 CPUID Base Register */ - vuint32_t ics; /* 0xc04 0xe000ed04 Interrupt Control State Register */ - vuint32_t vto; /* 0xc08 0xe000ed08 Vector Table Offset Register */ - vuint32_t ai_rc; /* 0xc0c 0xe000ed0c Application Interrupt/Reset Control Register */ - vuint32_t sc; /* 0xc10 0xe000ed10 System Control Register */ - vuint32_t cc; /* 0xc14 0xe000ed14 Configuration Control Register */ - - vuint32_t shpr7_4; /* 0xc18 0xe000ed18 System Hander Priority Registers */ - vuint32_t shpr11_8; /* 0xc1c */ - vuint32_t shpr15_12; /* 0xc20 */ - - uint8_t _unusedc18[0xe00 - 0xc24]; - - vuint32_t stir; /* 0xe00 */ + vuint32_t stir; /* 0xe00 0xe000ee00 Software Trigger Interrupt Register */ }; extern struct stm_nvic stm_nvic; -#define stm_nvic (*((struct stm_nvic *) 0xe000e100)) +//#define stm_nvic (*((struct stm_nvic *) 0xe000e100)) #define IRQ_REG(irq) ((irq) >> 5) #define IRQ_BIT(irq) ((irq) & 0x1f) @@ -335,6 +325,67 @@ 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 mmar; + 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_flash { + vuint32_t acr; + vuint32_t keyr; + vuint32_t optkeyr; + vuint32_t sr; + + vuint32_t cr; + vuint32_t ar; + uint32_t _unused018; + vuint32_t obr; + + vuint32_t wrpr; +}; + +extern struct stm_flash stm_flash; + +//#define stm_flash (*((struct stm_flash *) 0x40022000)) + +#define STM_FLASH_ACR_PRFTBS 5 +#define STM_FLASH_ACR_PRFTBE 4 +#define STM_FLASH_ACR_HLFCYA 3 +#define STM_FLASH_ACR_LATENCY 0 +#define STM_FLASH_ACR_LATENCY_0 0 +#define STM_FLASH_ACR_LATENCY_1 1 +#define STM_FLASH_ACR_LATENCY_2 2 + +#define STM_FLASH_RDPRT_KEY 0x00A5 +#define STM_FLASH_KEY1 0x45670123 +#define STM_FLASH_KEY2 0xCDEF89AB + + struct stm_flash_data { vuint16_t f_size; vuint16_t unused02; @@ -346,7 +397,7 @@ extern struct stm_flash_data stm_flash_data; static inline uint32_t stm_flash_size(void) { return (uint32_t) stm_flash_data.f_size * 1024; } -#define stm_flash_data (*((struct stm_flash_data *) 0x1ffff7e0)) +//#define stm_flash_data (*((struct stm_flash_data *) 0x1ffff7e0)) struct stm_gpio { vuint32_t cr[2]; @@ -425,11 +476,11 @@ extern struct stm_gpio stm_gpioc; extern struct stm_gpio stm_gpiod; extern struct stm_gpio stm_gpioe; -#define stm_gpioe (*((struct stm_gpio *) 0x40011800)) -#define stm_gpiod (*((struct stm_gpio *) 0x40011400)) -#define stm_gpioc (*((struct stm_gpio *) 0x40011000)) -#define stm_gpiob (*((struct stm_gpio *) 0x40010c00)) -#define stm_gpioa (*((struct stm_gpio *) 0x40010800)) +//#define stm_gpioe (*((struct stm_gpio *) 0x40011800)) +//#define stm_gpiod (*((struct stm_gpio *) 0x40011400)) +//#define stm_gpioc (*((struct stm_gpio *) 0x40011000)) +//#define stm_gpiob (*((struct stm_gpio *) 0x40010c00)) +//#define stm_gpioa (*((struct stm_gpio *) 0x40010800)) struct stm_afio { vuint32_t evcr; @@ -440,7 +491,266 @@ struct stm_afio { extern struct stm_afio stm_afio; -#define stm_afio (*((struct stm_afio *) 0x40010000)) +//#define stm_afio (*((struct stm_afio *) 0x40010000)) + +#define STM_AFIO_MAPR_ADC2_ETRGREG_REMAP 20 +#define STM_AFIO_MAPR_ADC2_ETRGINJ_REMAP 19 +#define STM_AFIO_MAPR_ADC1_ETRGREG_REMAP 18 +#define STM_AFIO_MAPR_ADC1_ETRGINJ_REMAP 17 +#define STM_AFIO_MAPR_TIM5CH4_IREMAP 16 +#define STM_AFIO_MAPR_PD01_REMAP 15 +#define STM_AFIO_MAPR_CAN_REMAP 13 +#define STM_AFIO_MAPR_CAN_REMAP_PA11_PA12 0 +#define STM_AFIO_MAPR_CAN_REMAP_PB8_PB9 2 +#define STM_AFIO_MAPR_CAN_REMAP_PD0_PD1 3 +#define STM_AFIO_MAPR_CAN_REMAP_MASK 3 +#define STM_AFIO_MAPR_TIM4_REMAP 12 +#define STM_AFIO_MAPR_TIM3_REMAP 10 +#define STM_AFIO_MAPR_TIM3_REMAP_PA6_PA7_PB0_PB1 0 +#define STM_AFIO_MAPR_TIM3_REMAP_PB4_PB5_PB0_PB1 2 +#define STM_AFIO_MAPR_TIM3_REMAP_PC6_PC7_PC8_PC9 3 +#define STM_AFIO_MAPR_TIM3_REMAP_MASK 3 +#define STM_AFIO_MAPR_TIM2_REMAP 8 +#define STM_AFIO_MAPR_TIM2_REMAP_PA0_PA1_PA2_PA3 0 +#define STM_AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3 1 +#define STM_AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11 2 +#define STM_AFIO_MAPR_TIM2_REMAP_PA15_PB3_PB10_PB11 3 +#define STM_AFIO_MAPR_TIM2_REMAP_MASK 3 +#define STM_AFIO_MAPR_TIM1_REMAP 6 +#define STM_AFIO_MAPR_TIM1_REMAP_PA12_PA8_PA9_PA10_PA11_PB12_PB13_PB14_PB15 0 +#define STM_AFIO_MAPR_TIM1_REMAP_PA12_PA8_PA9_PA10_PA11_PA6_PA7_PB0_PB1 1 +#define STM_AFIO_MAPR_TIM1_REMAP_PE7_PE9_PE11_PE13_PE14_PE15_PE8_PE10_PE12 3 +#define STM_AFIO_MAPR_TIM1_REMAP_MASK 3 +#define STM_AFIO_MAPR_USART3_REMAP 4 +#define STM_AFIO_MAPR_USART3_REMAP_PB10_PB11_PB12_PB13_PB14 0 +#define STM_AFIO_MAPR_USART3_REMAP_PC10_PC11_PC12_PB13_PB14 1 +#define STM_AFIO_MAPR_USART3_REMAP_PD8_PD9_PD10_PD11_PD12 3 +#define STM_AFIO_MAPR_USART3_REMAP_MASK 3 +#define STM_AFIO_MAPR_USART2_REMAP 3 +#define STM_AFIO_MAPR_USART2_REMAP_PA0_PA1_PA2_PA3_PA4 0 +#define STM_AFIO_MAPR_USART2_REMAP_PD3_PD4_PD5_PD6_PD7 1 +#define STM_AFIO_MAPR_USART2_REMAP_MASK 1 +#define STM_AFIO_MAPR_USART1_REMAP 2 +#define STM_AFIO_MAPR_USART1_REMAP_PA9_PA10 0 +#define STM_AFIO_MAPR_USART1_REMAP_PB6_PB7 1 +#define STM_AFIO_MAPR_USART1_REMAP_MASK 1 +#define STM_AFIO_MAPR_I2C1_REMAP 1 +#define STM_AFIO_MAPR_I2C1_REMAP_PB6_PB7 0 +#define STM_AFIO_MAPR_I2C1_REMAP_PB8_PB9 1 +#define STM_AFIO_MAPR_I2C1_REMAP_MASK 1 +#define STM_AFIO_MAPR_SPI1_REMAP 0 +#define STM_AFIO_MAPR_SPI1_REMAP_PA4_PA5_PA6_PA7 0 +#define STM_AFIO_MAPR_SPI1_REMAP_PA15_PB3_PB4_PB5 1 +#define STM_AFIO_MAPR_SPI1_REMAP_MASK 1 + +static inline void +stm_set_afio_mapr(uint8_t bit, uint32_t val, uint32_t mask) { + uint32_t mapr = stm_afio.mapr; + + mapr &= ~(mask << bit); + mapr |= (val << bit); + stm_afio.mapr = mapr; +} + +struct stm_usart { + vuint32_t sr; /* status register */ + vuint32_t dr; /* data register */ + vuint32_t brr; /* baud rate register */ + vuint32_t cr1; /* control register 1 */ + + vuint32_t cr2; /* control register 2 */ + vuint32_t cr3; /* control register 3 */ + vuint32_t gtpr; /* guard time and prescaler */ +}; + +extern struct stm_usart stm_usart1; +extern struct stm_usart stm_usart2; +extern struct stm_usart stm_usart3; + +//#define stm_usart1 (*((struct stm_usart *) 0x40013800)) +//#define stm_usart2 (*((struct stm_usart *) 0x40004800)) +//#define stm_usart3 (*((struct stm_usart *) 0x40004400)) + +#define STM_USART_SR_CTS (9) /* CTS flag */ +#define STM_USART_SR_LBD (8) /* LIN break detection flag */ +#define STM_USART_SR_TXE (7) /* Transmit data register empty */ +#define STM_USART_SR_TC (6) /* Transmission complete */ +#define STM_USART_SR_RXNE (5) /* Read data register not empty */ +#define STM_USART_SR_IDLE (4) /* IDLE line detected */ +#define STM_USART_SR_ORE (3) /* Overrun error */ +#define STM_USART_SR_NE (2) /* Noise detected flag */ +#define STM_USART_SR_FE (1) /* Framing error */ +#define STM_USART_SR_PE (0) /* Parity error */ + +#define STM_USART_BRR_DIV_MANTISSA (4) +#define STM_USART_BRR_DIV_FRACTION (0) + +#define STM_USART_CR1_UE (13) /* USART enable */ +#define STM_USART_CR1_M (12) /* Word length */ +#define STM_USART_CR1_WAKE (11) /* Wakeup method */ +#define STM_USART_CR1_PCE (10) /* Parity control enable */ +#define STM_USART_CR1_PS (9) /* Parity selection */ +#define STM_USART_CR1_PEIE (8) /* PE interrupt enable */ +#define STM_USART_CR1_TXEIE (7) /* TXE interrupt enable */ +#define STM_USART_CR1_TCIE (6) /* Transmission complete interrupt enable */ +#define STM_USART_CR1_RXNEIE (5) /* RXNE interrupt enable */ +#define STM_USART_CR1_IDLEIE (4) /* IDLE interrupt enable */ +#define STM_USART_CR1_TE (3) /* Transmitter enable */ +#define STM_USART_CR1_RE (2) /* Receiver enable */ +#define STM_USART_CR1_RWU (1) /* Receiver wakeup */ +#define STM_USART_CR1_SBK (0) /* Send break */ + +#define STM_USART_CR2_LINEN (14) /* LIN mode enable */ +#define STM_USART_CR2_STOP (12) /* STOP bits */ +#define STM_USART_CR2_STOP_MASK 3UL +#define STM_USART_CR2_STOP_1 0 +#define STM_USART_CR2_STOP_0_5 1 +#define STM_USART_CR2_STOP_2 2 +#define STM_USART_CR2_STOP_1_5 3 + +#define STM_USART_CR2_CLKEN (11) /* Clock enable */ +#define STM_USART_CR2_CPOL (10) /* Clock polarity */ +#define STM_USART_CR2_CPHA (9) /* Clock phase */ +#define STM_USART_CR2_LBCL (8) /* Last bit clock pulse */ +#define STM_USART_CR2_LBDIE (6) /* LIN break detection interrupt enable */ +#define STM_USART_CR2_LBDL (5) /* lin break detection length */ +#define STM_USART_CR2_ADD (0) +#define STM_USART_CR2_ADD_MASK 0xfUL + +#define STM_USART_CR3_CTSIE (10) /* CTS interrupt enable */ +#define STM_USART_CR3_CTSE (9) /* CTS enable */ +#define STM_USART_CR3_RTSE (8) /* RTS enable */ +#define STM_USART_CR3_DMAT (7) /* DMA enable transmitter */ +#define STM_USART_CR3_DMAR (6) /* DMA enable receiver */ +#define STM_USART_CR3_SCEN (5) /* Smartcard mode enable */ +#define STM_USART_CR3_NACK (4) /* Smartcard NACK enable */ +#define STM_USART_CR3_HDSEL (3) /* Half-duplex selection */ +#define STM_USART_CR3_IRLP (2) /* IrDA low-power */ +#define STM_USART_CR3_IREN (1) /* IrDA mode enable */ +#define STM_USART_CR3_EIE (0) /* Error interrupt enable */ + +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; +}; + +/* + * USB DM: PA11 + * USB DP: PA12 + * + * Need a pull-up on a separate GPIO + */ +#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 3UL +#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 3UL +#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 3UL +#define STM_USB_EPR_EA 0 +#define STM_USB_EPR_EA_MASK 0xfUL + +#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 0xfUL + +#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 0x3UL +#define STM_USB_FNR_FN 0 +#define STM_USB_FNR_FN_MASK 0x7ffUL + +#define STM_USB_DADDR_EF 7 +#define STM_USB_DADDR_ADD 0 +#define STM_USB_DADDR_ADD_MASK 0x7fUL + +extern struct stm_usb stm_usb; + + +//#define stm_usb (*((struct stm_usb *) 0x40005c00)) + +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 0x1fUL +#define STM_USB_BDT_COUNT_RX_COUNT_RX 0 +#define STM_USB_BDT_COUNT_RX_COUNT_RX_MASK 0x3ffUL + +#define STM_USB_BDT_SIZE 8 + +extern uint8_t stm_usb_sram[] __attribute__ ((aligned(4))); + +//#define stm_usb_sram ((uint8_t *)0x40006000); #define isr_decl(name) void stm_ ## name ## _isr(void) @@ -519,4 +829,65 @@ isr_decl(dma2_channel4_5); #undef isr_decl +#define STM_ISR_WWDG_POS 0 +#define STM_ISR_PVD_POS 1 +#define STM_ISR_TAMPER_STAMP_POS 2 +#define STM_ISR_RTC_WKUP_POS 3 +#define STM_ISR_FLASH_POS 4 +#define STM_ISR_RCC_POS 5 +#define STM_ISR_EXTI0_POS 6 +#define STM_ISR_EXTI1_POS 7 +#define STM_ISR_EXTI2_POS 8 +#define STM_ISR_EXTI3_POS 9 +#define STM_ISR_EXTI4_POS 10 +#define STM_ISR_DMA1_CHANNEL1_POS 11 +#define STM_ISR_DMA1_CHANNEL2_POS 12 +#define STM_ISR_DMA1_CHANNEL3_POS 13 +#define STM_ISR_DMA1_CHANNEL4_POS 14 +#define STM_ISR_DMA1_CHANNEL5_POS 15 +#define STM_ISR_DMA1_CHANNEL6_POS 16 +#define STM_ISR_DMA1_CHANNEL7_POS 17 +#define STM_ISR_ADC1_2_POS 18 +#define STM_ISR_USB_HP_POS 19 +#define STM_ISR_USB_LP_POS 20 +#define STM_ISR_CAN_RX1_POS 21 +#define STM_ISR_CAN_SCE_POS 22 +#define STM_ISR_EXTI9_5_POS 23 +#define STM_ISR_TIM1_BRK_POS 24 +#define STM_ISR_TIM1_UP_POS 25 +#define STM_ISR_TIM1_TRG_COM_POS 26 +#define STM_ISR_TIM1_CC_POS 27 +#define STM_ISR_TIM2_POS 28 +#define STM_ISR_TIM3_POS 29 +#define STM_ISR_TIM4_POS 30 +#define STM_ISR_I2C1_EV_POS 31 +#define STM_ISR_I2C1_ER_POS 32 +#define STM_ISR_I2C2_EV_POS 33 +#define STM_ISR_I2C2_ER_POS 34 +#define STM_ISR_SPI1_POS 35 +#define STM_ISR_SPI2_POS 36 +#define STM_ISR_USART1_POS 37 +#define STM_ISR_USART2_POS 38 +#define STM_ISR_USART3_POS 39 +#define STM_ISR_EXTI15_10_POS 40 +#define STM_ISR_RTC_ALARM_POS 41 +#define STM_ISR_USB_WAKEUP_POS 42 +#define STM_ISR_TIM8_BRK_POS 43 +#define STM_ISR_TIM8_UP_POS 44 +#define STM_ISR_TIM8_TRG_COM_POS 45 +#define STM_ISR_TIM8_CC_POS 46 +#define STM_ISR_ADC3_POS 47 +#define STM_ISR_FSMC_POS 48 +#define STM_ISR_SDIO_POS 49 +#define STM_ISR_TIM5_POS 50 +#define STM_ISR_SPI3_POS 51 +#define STM_ISR_UART4_POS 52 +#define STM_ISR_UART5_POS 53 +#define STM_ISR_TIM6_POS 54 +#define STM_ISR_TIM7_POS 55 +#define STM_ISR_DMA2_CHANNEL1_POS 56 +#define STM_ISR_DMA2_CHANNEL2_POS 57 +#define STM_ISR_DMA2_CHANNEL3_POS 58 +#define STM_ISR_DMA3_CHANNEL4_5_POS 59 + #endif -- 2.30.2