altos/stm32f4: Add usart driver for usart6
authorKeith Packard <keithp@keithp.com>
Wed, 12 Sep 2018 01:49:22 +0000 (18:49 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 13 Oct 2018 15:23:25 +0000 (08:23 -0700)
This is what the disco board hooks up.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/stm32f4/ao_arch.h
src/stm32f4/ao_arch_funcs.h
src/stm32f4/ao_interrupt.c
src/stm32f4/ao_usart_stm32f4.c [new file with mode: 0644]
src/stm32f4/registers.ld
src/stm32f4/stm32f4.h

index d4c78f603dc32e04b0dacf6e1dca1c040b792281..083a4e5b448763779c24aa8d9d7c19e3a2ee021b 100644 (file)
 #define AO_SYSTICK     (AO_HCLK)
 #define AO_PANIC_DELAY_SCALE  (AO_SYSCLK / 12000000)
 
+/* The stm32f413 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
+
+#define AO_GPIO_MODE_PULL_NONE 0
+#define AO_GPIO_MODE_PULL_UP   4
+#define AO_GPIO_MODE_PULL_DOWN 8
+
+/* usart stuff */
+
+#define AO_SERIAL_SPEED_4800   4800
+#define AO_SERIAL_SPEED_9600   9600
+#define AO_SERIAL_SPEED_19200  19200
+#define AO_SERIAL_SPEED_57600  57600
+#define AO_SERIAL_SPEED_115200 115200
+
 #endif /* _AO_ARCH_H_ */
index 8c0da03bf37b402bc39826a946b712b2f62942c1..b1ffb5b6bc2378a6e00475a6d94fd9aa142b235b 100644 (file)
@@ -331,4 +331,10 @@ static inline void ao_disable_port(struct stm_gpio *port)
                ao_gpio_set_mode(port, bit, mode);                      \
        } while (0)
 
+/* usart */
+
+void
+ao_usart_init(void);
+
+
 #endif /* _AO_ARCH_FUNCS_H_ */
index a00df54bccb1ecfd206c061ed19593a73e78295e..f1cb8eee262ca13b9541e50886dcff25e01f7da7 100644 (file)
@@ -119,7 +119,7 @@ isr(spi2)
 isr(usart1)
 isr(usart2)
 isr(usart3)
-isr(exti5_10)
+isr(exti15_10)
 isr(rtc_alarm)
 isr(otg_fs_wkup)
 isr(tim8_brk_tim12)
@@ -231,9 +231,10 @@ const void *stm_interrupt_vector[] = {
        i(0xd4, usart1),
        i(0xd8, usart2),
        i(0xdc, usart3),
-       i(0xe0, exti5_10),
+       i(0xe0, exti15_10),
        i(0xe4, rtc_alarm),
        i(0xe8, otg_fs_wkup),
        i(0xec, tim8_brk_tim12),
        i(0xf0, tim8_up_tim13),
+       i(0x15c, usart6),
 };
diff --git a/src/stm32f4/ao_usart_stm32f4.c b/src/stm32f4/ao_usart_stm32f4.c
new file mode 100644 (file)
index 0000000..28331b1
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright © 2018 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+/* ao_serial_stm.c */
+struct ao_stm_usart {
+       struct ao_fifo          rx_fifo;
+       struct ao_fifo          tx_fifo;
+       struct stm_usart        *reg;
+       uint32_t                clk;
+       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
+};
+
+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, usart->reg->dr);
+                       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, 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 &= ~(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->sr & (1 << STM_USART_SR_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;
+}
+
+static inline uint8_t
+_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t 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 void
+ao_usart_set_speed(struct ao_stm_usart *usart, uint32_t speed)
+{
+       if (speed > 115200)
+               return;
+       usart->reg->brr = usart->clk / speed;
+}
+
+static void
+_ao_usart_init(struct ao_stm_usart *usart, int hw_flow)
+{
+       usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) |
+                         (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_ONEBIT) |
+                         (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, 9600);
+}
+
+#if HAS_SERIAL_HW_FLOW
+static void
+ao_usart_set_flow(struct ao_stm_usart *usart)
+{
+}
+#endif
+
+#if HAS_SERIAL_6
+
+struct ao_stm_usart ao_stm_usart6;
+
+void stm_usart6_isr(void) { ao_usart_isr(&ao_stm_usart6, USE_SERIAL_6_STDIN); }
+
+char
+ao_serial6_getchar(void)
+{
+       return ao_usart_getchar(&ao_stm_usart6);
+}
+
+void
+ao_serial6_putchar(char c)
+{
+       ao_usart_putchar(&ao_stm_usart6, c);
+}
+
+int
+_ao_serial6_pollchar(void)
+{
+       return _ao_usart_pollchar(&ao_stm_usart6);
+}
+
+uint8_t
+_ao_serial6_sleep_for(uint16_t timeout)
+{
+       return _ao_usart_sleep_for(&ao_stm_usart6, timeout);
+}
+
+void
+ao_serial6_set_speed(uint32_t speed)
+{
+       ao_usart_drain(&ao_stm_usart6);
+       ao_usart_set_speed(&ao_stm_usart6, speed);
+}
+
+void
+ao_serial6_drain(void)
+{
+       ao_usart_drain(&ao_stm_usart6);
+}
+#endif /* HAS_SERIAL_6 */
+
+#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_usart_init(void)
+{
+#if HAS_SERIAL_6
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART6EN);
+
+       ao_stm_usart6.reg = &stm_usart6;
+       ao_stm_usart6.clk = AO_P2CLK;
+
+       ao_enable_port(SERIAL_6_RX_PORT);
+       ao_enable_port(SERIAL_6_TX_PORT);
+
+       stm_afr_set(SERIAL_6_RX_PORT, SERIAL_6_RX_PIN, STM_AFR_AF8);
+       stm_afr_set(SERIAL_6_TX_PORT, SERIAL_6_TX_PIN, STM_AFR_AF8);
+
+       stm_nvic_set_enable(STM_ISR_USART6_POS);
+       stm_nvic_set_priority(STM_ISR_USART6_POS, AO_STM_NVIC_MED_PRIORITY);
+
+       _ao_usart_init(&ao_stm_usart6, USE_SERIAL_6_FLOW && !USE_SERIAL_6_SW_FLOW);
+
+# if USE_SERIAL_6_FLOW
+#  if USE_SERIAL_6_SW_FLOW
+       ao_serial_set_sw_rts_cts(&ao_stm_usart6,
+                                ao_serial6_cts,
+                                SERIAL_6_PORT_RTS,
+                                SERIAL_6_PIN_RTS,
+                                SERIAL_6_PORT_CTS,
+                                SERIAL_6_PIN_CTS);
+#  else
+       stm_afr_set(SERIAL_6_PORT_RTS, SERIAL_6_PIN_RTS, STM_AFR_AF8);
+       stm_afr_set(SERIAL_6_PORT_CTS, SERIAL_6_PIN_CTS, STM_AFR_AF8);
+#  endif
+#endif
+
+#if USE_SERIAL_6_STDIN && !DELAY_SERIAL_6_STDIN
+       ao_add_stdio(_ao_serial6_pollchar,
+                    ao_serial6_putchar,
+                    NULL);
+#endif
+#endif
+}
index b36b2098906c348bc696aaba8d467f970b232358..20ffa0a0337dc33d665a53d4c985fb04dcb64be2 100644 (file)
@@ -19,6 +19,26 @@ stm_dac1   = 0x40007400;
 stm_uart7  = 0x40007800;
 stm_uart8  = 0x40007c00;
 
+stm_tim1   = 0x40010000;
+stm_tim8   = 0x40010400;
+stm_usart1 = 0x40011000;
+stm_usart6 = 0x40011400;
+stm_uart9  = 0x40011800;
+stm_uart10 = 0x40011c00;
+stm_adc    = 0x40012000;
+stm_sdio   = 0x40012c00;
+stm_spi1   = 0x40013000;
+stm_spi4   = 0x40013400;
+stm_syscfg = 0x40013800;
+stm_exti   = 0x40013c00;
+stm_tim9   = 0x40014000;
+stm_tim10  = 0x40014400;
+stm_tim11  = 0x40014800;
+stm_spi5   = 0x40015000;
+stm_sai1   = 0x40015800;
+stm_dfsdm1 = 0x40016000;
+stm_dfsdm2 = 0x40016400;
+
 stm_gpioa  = 0x40020000;
 stm_gpiob  = 0x40020400;
 stm_gpioc  = 0x40020800;
index 3429e458a65de793c3e582a5d1716f575fb722a1..715a2c9288020bc028e0889355c899cec408544e 100644 (file)
@@ -223,6 +223,26 @@ extern struct stm_rcc stm_rcc;
 #define STM_RCC_APB1ENR_TIM3EN         1
 #define STM_RCC_APB1ENR_TIM2EN         0
 
+#define STM_RCC_APB2ENR_DFSDM2EN       25
+#define STM_RCC_APB2ENR_DFSDM1EN       24
+#define STM_RCC_APB2ENR_SAI1EN         22
+#define STM_RCC_APB2ENR_SPI5EN         20
+#define STM_RCC_APB2ENR_TIM11EN                18
+#define STM_RCC_APB2ENR_TIM10EN                17
+#define STM_RCC_APB2ENR_TIM9EN         16
+#define STM_RCC_APB2ENR_EXITEN         15
+#define STM_RCC_APB2ENR_SYSCFGEN       14
+#define STM_RCC_APB2ENR_SPI4EN         13
+#define STM_RCC_APB2ENR_SPI1EN         12
+#define STM_RCC_APB2ENR_SDIOEN         11
+#define STM_RCC_APB2ENR_ADC1EN         8
+#define STM_RCC_APB2ENR_UART10EN       7
+#define STM_RCC_APB2ENR_UART9EN                5
+#define STM_RCC_APB2ENR_USART6EN       5
+#define STM_RCC_APB2ENR_USART1EN       4
+#define STM_RCC_APB2ENR_TIM8EN         1
+#define STM_RCC_APB2ENR_TIM1EN         0
+
 #define STM_RCC_CSR_RMVF               24
 
 struct stm_ictr {
@@ -283,7 +303,7 @@ static inline int
 stm_nvic_enabled(int irq) {
        return IRQ_BOOL(stm_nvic.iser[IRQ_REG(irq)], irq);
 }
-       
+
 static inline void
 stm_nvic_set_pending(int irq) {
        stm_nvic.ispr[IRQ_REG(irq)] = IRQ_MASK(irq);
@@ -324,6 +344,152 @@ stm_nvic_get_priority(int irq) {
        return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
 }
 
+#define isr(name) void stm_ ## name ## _isr(void)
+
+isr(nmi);
+isr(hardfault);
+isr(memmanage);
+isr(busfault);
+isr(usagefault);
+isr(svc);
+isr(debugmon);
+isr(pendsv);
+isr(systick);
+isr(wwdg);
+isr(pvd);
+isr(tamper_stamp);
+isr(rtc_wkup);
+isr(flash);
+isr(rcc);
+isr(exti0);
+isr(exti1);
+isr(exti2);
+isr(exti3);
+isr(exti4);
+isr(dma1_stream0);
+isr(dma1_stream1);
+isr(dma1_stream2);
+isr(dma1_stream3);
+isr(dma1_stream4);
+isr(dma1_stream5);
+isr(dma1_stream6);
+isr(adc);
+isr(can1_tx);
+isr(can1_rx0);
+isr(can1_rx1);
+isr(can1_sce);
+isr(exti9_5);
+isr(tim1_brk_tim9);
+isr(tim1_up_tim10);
+isr(tim_trg_com_tim11);
+isr(tim1_cc);
+isr(tim2);
+isr(tim3);
+isr(tim4);
+isr(i2c1_evt);
+isr(i2c1_err);
+isr(i2c2_evt);
+isr(i2c2_err);
+isr(spi1);
+isr(spi2);
+isr(usart1);
+isr(usart2);
+isr(usart3);
+isr(exti15_10);
+isr(rtc_alarm);
+isr(otg_fs_wkup);
+isr(tim8_brk_tim12);
+isr(tim8_up_tim13);
+isr(tim8_trg_com_tim14);
+isr(tim8_cc);
+isr(dma1_stream7);
+isr(fsmc);
+isr(sdio);
+isr(tim5);
+isr(spi3);
+isr(uart4);
+isr(uart5);
+isr(tim6_glb_it);
+isr(tim7);
+isr(dma2_stream0);
+isr(dma2_stream1);
+isr(dma2_stream2);
+isr(dma2_stream3);
+isr(dma2_stream4);
+isr(dfsdm1_flt0);
+isr(dfsdm1_flt1);
+isr(can2_tx);
+isr(can2_rx0);
+isr(can2_rx1);
+isr(can2_sce);
+isr(otg_fs);
+isr(dma2_stream5);
+isr(dma2_stream6);
+isr(dma2_stream7);
+isr(usart6);
+isr(i2c3_ev);
+isr(i2c3_er);
+isr(can3_tx);
+isr(can3_rx0);
+isr(can3_rx1);
+isr(can3_sce);
+isr(crypto);
+isr(rng);
+isr(fpu);
+isr(uart7);
+isr(uart8);
+isr(spi4);
+isr(spi5);
+isr(sai1);
+isr(uart9);
+isr(uart10);
+isr(quad_spi);
+isr(i2cfmp1_ev);
+isr(i2cfmp1_er);
+isr(exti23);
+isr(dfsdm2_flt0);
+isr(dfsdm2_flt1);
+isr(dfsdm2_flt2);
+isr(dfsdm2_flt3);
+
+#undef isr
+
+#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_STREAM0_POS       11
+#define STM_ISR_DMA1_STREAM1_POS       12
+#define STM_ISR_DMA1_STREAM2_POS       13
+#define STM_ISR_DMA1_STREAM3_POS       14
+#define STM_ISR_DMA1_STREAM4_POS       15
+#define STM_ISR_DMA1_STREAM5_POS       16
+#define STM_ISR_DMA1_STREAM6_POS       17
+#define STM_ISR_ADC_POS                        18
+#define STM_ISR_CAN1_TX_POS            19
+#define STM_ISR_CAN1_RX0_POS           20
+#define STM_ISR_CAN1_RX1_POS           21
+#define STM_ISR_CAN1_SCE_POS           22
+#define STM_ISR_EXTI9_5_POS            23
+#define STM_ISR_USART1_POS             37
+#define STM_ISR_USART2_POS             38
+#define STM_ISR_USART3_POS             39
+#define STM_ISR_UART4_POS              52
+#define STM_ISR_UART5_POS              53
+#define STM_ISR_USART6_POS             71
+#define STM_ISR_UART7_POS              82
+#define STM_ISR_UART9_POS              88
+#define STM_ISR_UART10_POS             89
+
+#define STM_ISR_EXTI15_10_POS          40
+
 struct stm_flash {
        vuint32_t       acr;
        vuint32_t       keyr;
@@ -595,6 +761,13 @@ extern struct stm_scb stm_scb;
 #define STM_SCB_CPACR_FP0      STM_SCB_CPACR_CP(10)
 #define STM_SCB_CPACR_FP1      STM_SCB_CPACR_CP(11)
 
+#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
+
 /* The SYSTICK starts at 0xe000e010 */
 
 struct stm_systick {
@@ -615,6 +788,148 @@ extern struct stm_systick stm_systick;
 #define  STM_SYSTICK_CSR_CLKSOURCE_AHB                 1
 #define STM_SYSTICK_CSR_COUNTFLAG      16
 
+#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_PF           5
+#define STM_SYSCFG_EXTICR_PG           6
+#define STM_SYSCFG_EXTICR_PH           7
+
+struct stm_syscfg {
+       vuint32_t       memrmp;
+       vuint32_t       pmc;
+       vuint32_t       exticr[4];
+};
+
+extern struct stm_syscfg stm_syscfg;
+
+#define stm_syscfg (*((struct stm_syscfg *) 0x40013800))
+
+#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_ADC1DC2         0
+
+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;
+       else if (gpio == &stm_gpiof)
+               val = STM_SYSCFG_EXTICR_PF;
+       else if (gpio == &stm_gpiog)
+               val = STM_SYSCFG_EXTICR_PG;
+       else if (gpio == &stm_gpioh)
+               val = STM_SYSCFG_EXTICR_PH;
+
+       stm_syscfg.exticr[reg] = (stm_syscfg.exticr[reg] & ~(0xf << shift)) | val << shift;
+}
+
+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;
+
+#define stm_exti       (*((struct stm_exti *) 0x40013c00))
+
+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_usart6;
+
+#define stm_usart6     (*((struct stm_usart *) 0x40011400))
+
+#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_NF                (2)     /* Noise detected flag */
+#define STM_USART_SR_FE                (1)     /* Framing error */
+#define STM_USART_SR_PE                (0)     /* Parity error */
+
+#define STM_USART_CR1_OVER8    (15)    /* Oversampling mode */
+#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        3
+#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 0xf
+
+#define STM_USART_CR3_ONEBIT   (11)    /* One sample bit method enable */
+#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 */
+
 /* Errata 2.1.5
 
    Delay after an RCC peripheral clock enabling