summaryrefslogtreecommitdiff
path: root/src/stmf0
diff options
context:
space:
mode:
Diffstat (limited to 'src/stmf0')
-rw-r--r--src/stmf0/Makefile-flash.defs11
-rw-r--r--src/stmf0/ao_adc_fast.c14
-rw-r--r--src/stmf0/ao_arch.h11
-rw-r--r--src/stmf0/ao_arch_funcs.h87
-rw-r--r--src/stmf0/ao_dma_stm.c34
-rw-r--r--src/stmf0/ao_exti.h2
-rw-r--r--src/stmf0/ao_exti_stm.c149
-rw-r--r--src/stmf0/ao_gpio.c71
-rw-r--r--src/stmf0/ao_pwm.c214
-rw-r--r--src/stmf0/ao_spi_stm.c478
-rw-r--r--src/stmf0/ao_timer.c130
-rw-r--r--src/stmf0/ao_usb_stm.c300
-rw-r--r--src/stmf0/registers.ld2
-rw-r--r--src/stmf0/stm32f0.h460
14 files changed, 1652 insertions, 311 deletions
diff --git a/src/stmf0/Makefile-flash.defs b/src/stmf0/Makefile-flash.defs
index 706b93ee..29d6ae45 100644
--- a/src/stmf0/Makefile-flash.defs
+++ b/src/stmf0/Makefile-flash.defs
@@ -39,17 +39,24 @@ LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos-loader.ld
PROGNAME=altos-flash
PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+BIN=$(HARDWARE)-$(PROGNAME)-$(VERSION).bin
+
+MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin
+FLASH_ADDR=0x08000000
+
+all: $(PROG) $(BIN)
$(PROG): Makefile $(OBJ) altos-loader.ld
$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+$(BIN): $(PROG)
+ $(MAKEBIN) --output=$@ --base=$(FLASH_ADDR) $(PROG)
+
ao_product.h: ao-make-product.5c $(TOPDIR)/Version
$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
$(OBJ): $(INC)
-all: $(PROG)
-
distclean: clean
clean:
diff --git a/src/stmf0/ao_adc_fast.c b/src/stmf0/ao_adc_fast.c
index 26e6691c..0a2e2c5c 100644
--- a/src/stmf0/ao_adc_fast.c
+++ b/src/stmf0/ao_adc_fast.c
@@ -72,7 +72,9 @@ _ao_adc_start(void)
(1 << STM_DMA_CCR_MINC) |
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
- (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+ (1 << STM_DMA_CCR_TCIE));
+
ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_dma_done);
ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1));
@@ -83,7 +85,6 @@ void
ao_adc_init(void)
{
uint32_t chselr;
- int i;
/* Reset ADC */
stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST);
@@ -157,12 +158,13 @@ ao_adc_init(void)
/* Shortest sample time */
stm_adc.smpr = STM_ADC_SMPR_SMP_1_5 << STM_ADC_SMPR_SMP;
+ /* Turn off enable and start */
+ stm_adc.cr &= ~((1 << STM_ADC_CR_ADEN) | (1 << STM_ADC_CR_ADSTART));
+
/* Calibrate */
stm_adc.cr |= (1 << STM_ADC_CR_ADCAL);
- for (i = 0; i < 0xf000; i++) {
- if ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) == 0)
- break;
- }
+ while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0)
+ ;
/* Enable */
stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h
index 6ee71ef9..2597cadc 100644
--- a/src/stmf0/ao_arch.h
+++ b/src/stmf0/ao_arch.h
@@ -25,7 +25,9 @@
* STM32F0 definitions and code fragments for AltOS
*/
+#ifndef AO_STACK_SIZE
#define AO_STACK_SIZE 512
+#endif
#define AO_LED_TYPE uint16_t
@@ -115,6 +117,7 @@ extern const uint32_t ao_radio_cal;
#define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER)
#define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER)
#define AO_SYSTICK (AO_HCLK)
+#define AO_PANIC_DELAY_SCALE (AO_SYSCLK / 12000000)
#if AO_APB1_PRESCALER == 1
#define AO_TIM23467_CLK AO_PCLK1
@@ -128,10 +131,10 @@ extern const uint32_t ao_radio_cal;
#define AO_TIM91011_CLK (2 * AO_PCLK2)
#endif
-#define AO_STM_NVIC_HIGH_PRIORITY 4
-#define AO_STM_NVIC_CLOCK_PRIORITY 6
-#define AO_STM_NVIC_MED_PRIORITY 8
-#define AO_STM_NVIC_LOW_PRIORITY 10
+#define AO_STM_NVIC_HIGH_PRIORITY (0 << 6)
+#define AO_STM_NVIC_CLOCK_PRIORITY (1 << 6)
+#define AO_STM_NVIC_MED_PRIORITY (2 << 6)
+#define AO_STM_NVIC_LOW_PRIORITY (3 << 6)
void ao_lcd_stm_init(void);
diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h
index 3db96be2..ccfa3fc7 100644
--- a/src/stmf0/ao_arch_funcs.h
+++ b/src/stmf0/ao_arch_funcs.h
@@ -18,25 +18,27 @@
#ifndef _AO_ARCH_FUNCS_H_
#define _AO_ARCH_FUNCS_H_
+#include <ao_power.h>
+
/* ao_spi_stm.c
*/
-/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */
+/* PCLK is set to 48MHz (HCLK 48MHz, HPRE 1, PPRE 1) */
-#define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2
-#define AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
-#define AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
-#define AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
-#define AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
-#define AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
-#define AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
-#define AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
+#define AO_SPI_SPEED_24MHz STM_SPI_CR1_BR_PCLK_2
+#define AO_SPI_SPEED_12MHz STM_SPI_CR1_BR_PCLK_4
+#define AO_SPI_SPEED_6MHz STM_SPI_CR1_BR_PCLK_8
+#define AO_SPI_SPEED_3MHz STM_SPI_CR1_BR_PCLK_16
+#define AO_SPI_SPEED_1500kHz STM_SPI_CR1_BR_PCLK_32
+#define AO_SPI_SPEED_750kHz STM_SPI_CR1_BR_PCLK_64
+#define AO_SPI_SPEED_375kHz STM_SPI_CR1_BR_PCLK_128
+#define AO_SPI_SPEED_187500Hz STM_SPI_CR1_BR_PCLK_256
-#define AO_SPI_SPEED_FAST AO_SPI_SPEED_8MHz
+#define AO_SPI_SPEED_FAST AO_SPI_SPEED_24MHz
/* Companion bus wants something no faster than 200kHz */
-#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_125kHz
+#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_187500Hz
#define AO_SPI_CONFIG_1 0x00
#define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1
@@ -118,27 +120,44 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s
#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
-#define ao_enable_port(port) do { \
- if ((port) == &stm_gpioa) \
- stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); \
- else if ((port) == &stm_gpiob) \
- stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); \
- else if ((port) == &stm_gpioc) \
- stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPCEN); \
- else if ((port) == &stm_gpiof) \
- stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPFEN); \
- } while (0)
+extern struct ao_power ao_power_gpioa;
+extern struct ao_power ao_power_gpiob;
+extern struct ao_power ao_power_gpioc;
+extern struct ao_power ao_power_gpiof;
-#define ao_disable_port(port) do { \
- if ((port) == &stm_gpioa) \
- stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPAEN); \
- else if ((port) == &stm_gpiob) \
- stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPBEN); \
- else if ((port) == &stm_gpioc) \
- stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPCEN); \
- else if ((port) == &stm_gpiof) \
- stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPFEN); \
- } while (0)
+static inline void ao_enable_port(struct stm_gpio *port)
+{
+ if ((port) == &stm_gpioa) {
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+ ao_power_register(&ao_power_gpioa);
+ } else if ((port) == &stm_gpiob) {
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+ ao_power_register(&ao_power_gpiob);
+ } else if ((port) == &stm_gpioc) {
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPCEN);
+ ao_power_register(&ao_power_gpioc);
+ } else if ((port) == &stm_gpiof) {
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPFEN);
+ ao_power_register(&ao_power_gpiof);
+ }
+}
+
+static inline void ao_disable_port(struct stm_gpio *port)
+{
+ if ((port) == &stm_gpioa) {
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPAEN);
+ ao_power_unregister(&ao_power_gpioa);
+ } else if ((port) == &stm_gpiob) {
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPBEN);
+ ao_power_unregister(&ao_power_gpiob);
+ } else if ((port) == &stm_gpioc) {
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPCEN);
+ ao_power_unregister(&ao_power_gpioc);
+ } else if ((port) == &stm_gpiof) {
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPFEN);
+ ao_power_unregister(&ao_power_gpiof);
+ }
+}
#define ao_gpio_set(port, bit, pin, v) stm_gpio_set(port, bit, v)
@@ -166,8 +185,7 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s
} while (0)
#define ao_enable_cs(port,bit) do { \
- stm_gpio_set((port), bit, 1); \
- stm_moder_set((port), bit, STM_MODER_OUTPUT); \
+ ao_enable_output(port, bit, pin, 1); \
} while (0)
#define ao_spi_init_cs(port, mask) do { \
@@ -395,6 +413,9 @@ ao_usb_free(uint16_t *buffer);
void
ao_usb_write(uint16_t *buffer, uint16_t len);
+
+void
+ao_usb_write2(uint16_t *buffer, uint16_t len);
#endif /* AO_USB_DIRECTIO */
#endif /* _AO_ARCH_FUNCS_H_ */
diff --git a/src/stmf0/ao_dma_stm.c b/src/stmf0/ao_dma_stm.c
index 78fabe18..e90c6bf8 100644
--- a/src/stmf0/ao_dma_stm.c
+++ b/src/stmf0/ao_dma_stm.c
@@ -28,9 +28,7 @@ static uint8_t ao_dma_allocated[STM_NUM_DMA];
static uint8_t ao_dma_mutex[STM_NUM_DMA];
static uint8_t ao_dma_active;
-#define id(ch) STM_DMA_INDEX(ch)
-#define id_mask(id) (STM_DMA_ISR_MASK << (id))
-#define ch_mask(ch) id_mask(id(ch))
+#define ch_mask(id) (STM_DMA_ISR_MASK << STM_DMA_ISR(id))
static void
ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
@@ -41,7 +39,7 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
/* Ack them */
stm_dma.ifcr = isr;
for (index = low_index; index <= high_index; index++) {
- if (isr & id_mask(index)) {
+ if (isr & ch_mask(index)) {
if (ao_dma_config[index].isr)
(*ao_dma_config[index].isr)(index);
else {
@@ -52,9 +50,25 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
}
}
-void stm_dma_ch1_isr(void) { ao_dma_isr(id(1), id(1), ch_mask(1)); }
-void stm_dma_ch2_3_isr(void) { ao_dma_isr(id(2), id(3), ch_mask(2) | ch_mask(3)); }
-void stm_dma1_ch4_5_6_isr(void) { ao_dma_isr(id(4), id(6), ch_mask(4) | ch_mask(5) | ch_mask(6)); }
+void stm_dma_ch1_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(1),
+ STM_DMA_INDEX(1),
+ ch_mask(STM_DMA_INDEX(1)));
+}
+
+void stm_dma_ch2_3_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(2),
+ STM_DMA_INDEX(3),
+ ch_mask(STM_DMA_INDEX(2)) |
+ ch_mask(STM_DMA_INDEX(3)));
+}
+
+void stm_dma1_ch4_5_6_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(4), STM_DMA_INDEX(6),
+ ch_mask(STM_DMA_INDEX(4)) |
+ ch_mask(STM_DMA_INDEX(5)) |
+ ch_mask(STM_DMA_INDEX(6)));
+}
void
ao_dma_set_transfer(uint8_t index,
@@ -73,11 +87,12 @@ ao_dma_set_transfer(uint8_t index,
if (ao_dma_active++ == 0)
stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMAEN);
);
- stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
+ ao_dma_config[index].isr = NULL;
+ ao_dma_done[index] = 0;
stm_dma.channel[index].cndtr = count;
stm_dma.channel[index].cpar = peripheral;
stm_dma.channel[index].cmar = memory;
- ao_dma_config[index].isr = NULL;
+ stm_dma.channel[index].ccr = ccr;
}
void
@@ -89,7 +104,6 @@ ao_dma_set_isr(uint8_t index, void (*isr)(int))
void
ao_dma_start(uint8_t index)
{
- ao_dma_done[index] = 0;
stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN);
}
diff --git a/src/stmf0/ao_exti.h b/src/stmf0/ao_exti.h
index ebea224d..192611bd 100644
--- a/src/stmf0/ao_exti.h
+++ b/src/stmf0/ao_exti.h
@@ -28,7 +28,7 @@
#define AO_EXTI_PIN_NOCONFIGURE 64
void
-ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
+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);
diff --git a/src/stmf0/ao_exti_stm.c b/src/stmf0/ao_exti_stm.c
new file mode 100644
index 00000000..910afcf7
--- /dev/null
+++ b/src/stmf0/ao_exti_stm.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2016 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+static void (*ao_exti_callback[16])(void);
+
+uint32_t ao_last_exti;
+
+static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) {
+ uint16_t pending = (ao_last_exti = stm_exti.pr) & mask;
+ uint8_t pin;
+ static uint16_t last_mask;
+ static uint8_t last_pin;
+
+ if (pending == last_mask) {
+ stm_exti.pr = last_mask;
+ (*ao_exti_callback[last_pin])();
+ return;
+ }
+ stm_exti.pr = pending;
+ for (pin = first; pin <= last; pin++)
+ if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) {
+ last_mask = (1 << pin);
+ last_pin = pin;
+ (*ao_exti_callback[pin])();
+ }
+}
+
+void stm_exti0_1_isr(void) { ao_exti_range_isr(0, 1, 0x0003); }
+void stm_exti2_3_isr(void) { ao_exti_range_isr(2, 3, 0x000c); }
+void stm_exti4_15_isr(void) { ao_exti_range_isr(4, 15, 0xfff0); }
+
+void
+ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+ uint32_t mask = 1 << pin;
+ uint32_t pupdr;
+ uint8_t irq;
+ uint8_t prio;
+
+ ao_exti_callback[pin] = callback;
+
+ /* configure gpio to interrupt routing */
+ stm_exticr_set(gpio, pin);
+
+ if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+ /* configure pin as input, setting selected pull-up/down mode */
+ stm_moder_set(gpio, pin, STM_MODER_INPUT);
+ switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
+ case 0:
+ default:
+ pupdr = STM_PUPDR_NONE;
+ break;
+ case AO_EXTI_MODE_PULL_UP:
+ pupdr = STM_PUPDR_PULL_UP;
+ break;
+ case AO_EXTI_MODE_PULL_DOWN:
+ pupdr = STM_PUPDR_PULL_DOWN;
+ break;
+ }
+ stm_pupdr_set(gpio, pin, pupdr);
+ }
+
+ /* Set interrupt mask and rising/falling mode */
+ stm_exti.imr &= ~mask;
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+
+ if (pin <= 1)
+ irq = STM_ISR_EXTI0_1_POS;
+ else if (pin <= 3)
+ irq = STM_ISR_EXTI2_3_POS;
+ else
+ irq = STM_ISR_EXTI4_15_POS;
+
+ /* Set priority */
+ prio = AO_STM_NVIC_MED_PRIORITY;
+ if (mode & AO_EXTI_PRIORITY_LOW)
+ prio = AO_STM_NVIC_LOW_PRIORITY;
+ else if (mode & AO_EXTI_PRIORITY_HIGH)
+ prio = AO_STM_NVIC_HIGH_PRIORITY;
+
+ stm_nvic_set_priority(irq, prio);
+ stm_nvic_set_enable(irq);
+}
+
+void
+ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) {
+ (void) gpio;
+
+ uint32_t mask = 1 << pin;
+
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+}
+
+void
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) {
+ (void) gpio;
+ ao_exti_callback[pin] = callback;
+}
+
+void
+ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.pr = mask;
+ stm_exti.imr |= (1 << pin);
+}
+
+void
+ao_exti_disable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.imr &= ~mask;
+ stm_exti.pr = mask;
+}
+
+void
+ao_exti_init(void)
+{
+}
diff --git a/src/stmf0/ao_gpio.c b/src/stmf0/ao_gpio.c
new file mode 100644
index 00000000..c7bf0797
--- /dev/null
+++ b/src/stmf0/ao_gpio.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2016 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; version 2 of the License.
+ *
+ * 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>
+
+static void
+ao_gpio_suspend(void *arg)
+{
+ struct stm_gpio *port = arg;
+ if (port == &stm_gpioa)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPAEN);
+ else if ((port) == &stm_gpiob)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPBEN);
+ else if ((port) == &stm_gpioc)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPCEN);
+ else if ((port) == &stm_gpiof)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPFEN);
+}
+
+static void
+ao_gpio_resume(void *arg)
+{
+ struct stm_gpio *port = arg;
+ if (port == &stm_gpioa)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+ else if ((port) == &stm_gpiob)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+ else if ((port) == &stm_gpioc)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPCEN);
+ else if ((port) == &stm_gpiof)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPFEN);
+}
+
+struct ao_power ao_power_gpioa = {
+ .suspend = ao_gpio_suspend,
+ .resume = ao_gpio_resume,
+ .arg = &stm_gpioa
+};
+
+struct ao_power ao_power_gpiob = {
+ .suspend = ao_gpio_suspend,
+ .resume = ao_gpio_resume,
+ .arg = &stm_gpiob
+};
+
+struct ao_power ao_power_gpioc = {
+ .suspend = ao_gpio_suspend,
+ .resume = ao_gpio_resume,
+ .arg = &stm_gpioc
+};
+
+struct ao_power ao_power_gpiof = {
+ .suspend = ao_gpio_suspend,
+ .resume = ao_gpio_resume,
+ .arg = &stm_gpiof
+};
+
diff --git a/src/stmf0/ao_pwm.c b/src/stmf0/ao_pwm.c
new file mode 100644
index 00000000..c1e157f5
--- /dev/null
+++ b/src/stmf0/ao_pwm.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright © 2016 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_pwm.h"
+
+static uint8_t pwm_running;
+
+static uint16_t pwm_value[NUM_PWM];
+
+static void
+ao_pwm_up(void)
+{
+ if (pwm_running++ == 0) {
+ struct stm_tim23 *tim = AO_PWM_TIMER;
+
+ tim->ccr1 = 0;
+ tim->ccr2 = 0;
+ tim->ccr3 = 0;
+ tim->ccr4 = 0;
+ tim->arr = PWM_MAX - 1; /* turn on the timer */
+ tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) |
+ (0 << STM_TIM23_CR1_ARPE) |
+ (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) |
+ (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) |
+ (0 << STM_TIM23_CR1_OPM) |
+ (0 << STM_TIM23_CR1_URS) |
+ (0 << STM_TIM23_CR1_UDIS) |
+ (1 << STM_TIM23_CR1_CEN));
+
+ /* Set the timer running */
+ tim->egr = (1 << STM_TIM23_EGR_UG);
+ }
+}
+
+static void
+ao_pwm_down(void)
+{
+ if (--pwm_running == 0) {
+ struct stm_tim23 *tim = AO_PWM_TIMER;
+
+ tim->arr = 0;
+ tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) |
+ (0 << STM_TIM23_CR1_ARPE) |
+ (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) |
+ (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) |
+ (0 << STM_TIM23_CR1_OPM) |
+ (0 << STM_TIM23_CR1_URS) |
+ (0 << STM_TIM23_CR1_UDIS) |
+ (0 << STM_TIM23_CR1_CEN));
+
+ /* Stop the timer */
+ tim->egr = (1 << STM_TIM23_EGR_UG);
+ }
+}
+
+void
+ao_pwm_set(uint8_t pwm, uint16_t value)
+{
+ struct stm_tim23 *tim = AO_PWM_TIMER;
+ uint8_t ch = AO_PWM_0_CH;
+
+ if (value > PWM_MAX)
+ value = PWM_MAX;
+ if (value != 0) {
+ if (pwm_value[pwm] == 0)
+ ao_pwm_up();
+ }
+#if NUM_PWM > 1
+ switch (pwm) {
+ case 0:
+ ch = AO_PWM_0_CH;
+ break;
+ case 1:
+ ch = AO_PWM_0_CH;
+ break;
+#if NUM_PWM > 2
+ case 2:
+ ch = AO_PWM_0_CH;
+ break;
+#endif
+#if NUM_PWM > 3
+ case 3:
+ ch = AO_PWM_0_CH;
+ break;
+#endif
+ }
+#endif
+
+ switch (ch) {
+ case 1:
+ tim->ccr1 = value;
+ break;
+ case 2:
+ tim->ccr2 = value;
+ break;
+ case 3:
+ tim->ccr3 = value;
+ break;
+ case 4:
+ tim->ccr4 = value;
+ break;
+ }
+ if (value == 0) {
+ if (pwm_value[pwm] != 0)
+ ao_pwm_down();
+ }
+ pwm_value[pwm] = value;
+}
+
+static void
+ao_pwm_cmd(void)
+{
+ uint8_t ch;
+ uint16_t val;
+
+ ao_cmd_decimal();
+ ch = ao_cmd_lex_u32;
+ ao_cmd_decimal();
+ val = ao_cmd_lex_u32;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+
+ printf("Set channel %d to %d\n", ch, val);
+ ao_pwm_set(ch, val);
+}
+
+static const struct ao_cmds ao_pwm_cmds[] = {
+ { ao_pwm_cmd, "P <ch> <val>\0Set PWM ch to val" },
+ { 0, NULL },
+};
+
+void
+ao_pwm_init(void)
+{
+ struct stm_tim23 *tim = AO_PWM_TIMER;
+
+ stm_rcc.apb1enr |= (1 << AO_PWM_TIMER_ENABLE);
+
+ tim->cr1 = 0;
+ tim->psc = AO_PWM_TIMER_SCALE - 1;
+ tim->cnt = 0;
+ tim->ccer = ((1 << STM_TIM23_CCER_CC1E) |
+ (0 << STM_TIM23_CCER_CC1P) |
+ (1 << STM_TIM23_CCER_CC2E) |
+ (0 << STM_TIM23_CCER_CC2P) |
+ (1 << STM_TIM23_CCER_CC3E) |
+ (0 << STM_TIM23_CCER_CC3P) |
+ (1 << STM_TIM23_CCER_CC4E) |
+ (0 << STM_TIM23_CCER_CC4P));
+
+ tim->ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) |
+ (STM_TIM23_CCMR1_OC2M_PWM_MODE_1 << STM_TIM23_CCMR1_OC2M) |
+ (0 << STM_TIM23_CCMR1_OC2PE) |
+ (0 << STM_TIM23_CCMR1_OC2FE) |
+ (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) |
+
+ (0 << STM_TIM23_CCMR1_OC1CE) |
+ (STM_TIM23_CCMR1_OC1M_PWM_MODE_1 << STM_TIM23_CCMR1_OC1M) |
+ (0 << STM_TIM23_CCMR1_OC1PE) |
+ (0 << STM_TIM23_CCMR1_OC1FE) |
+ (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S));
+
+
+ tim->ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) |
+ (STM_TIM23_CCMR2_OC4M_PWM_MODE_1 << STM_TIM23_CCMR2_OC4M) |
+ (0 << STM_TIM23_CCMR2_OC4PE) |
+ (0 << STM_TIM23_CCMR2_OC4FE) |
+ (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) |
+
+ (0 << STM_TIM23_CCMR2_OC3CE) |
+ (STM_TIM23_CCMR2_OC3M_PWM_MODE_1 << STM_TIM23_CCMR2_OC3M) |
+ (0 << STM_TIM23_CCMR2_OC3PE) |
+ (0 << STM_TIM23_CCMR2_OC3FE) |
+ (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S));
+ tim->egr = 0;
+
+ tim->sr = 0;
+ tim->dier = 0;
+ tim->smcr = 0;
+ tim->cr2 = ((0 << STM_TIM23_CR2_TI1S) |
+ (STM_TIM23_CR2_MMS_RESET<< STM_TIM23_CR2_MMS) |
+ (0 << STM_TIM23_CR2_CCDS));
+
+ stm_afr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_AFR_AF1);
+ stm_ospeedr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_OSPEEDR_MEDIUM);
+#if NUM_PWM > 1
+ stm_afr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_AFR_AF1);
+ stm_ospeedr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_OSPEEDR_MEDIUM);
+#endif
+#if NUM_PWM > 2
+ stm_afr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_AFR_AF1);
+ stm_ospeedr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_OSPEEDR_MEDIUM);
+#endif
+#if NUM_PWM > 3
+ stm_afr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_AFR_AF1);
+ stm_ospeedr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_OSPEEDR_MEDIUM);
+#endif
+ ao_cmd_register(&ao_pwm_cmds[0]);
+}
diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c
new file mode 100644
index 00000000..55bf59d2
--- /dev/null
+++ b/src/stmf0/ao_spi_stm.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright © 2016 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+struct ao_spi_stm_info {
+ uint8_t miso_dma_index;
+ uint8_t mosi_dma_index;
+ struct stm_spi *stm_spi;
+};
+
+static uint8_t ao_spi_mutex[STM_NUM_SPI];
+static uint8_t ao_spi_index[STM_NUM_SPI];
+
+static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
+ {
+ .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
+ .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
+ &stm_spi1
+ },
+ {
+ .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
+ .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
+ &stm_spi2
+ }
+};
+
+static uint8_t spi_dev_null;
+
+
+
+#define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) | \
+ (0 << STM_SPI_CR2_LDMA_RX) | \
+ (1 << STM_SPI_CR2_FRXTH) | \
+ (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) | \
+ (0 << STM_SPI_CR2_TXEIE) | \
+ (0 << STM_SPI_CR2_RXNEIE) | \
+ (0 << STM_SPI_CR2_ERRIE) | \
+ (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) | \
+ (0 << STM_SPI_CR2_NSSP) | \
+ (0 << STM_SPI_CR2_SSOE))
+
+#define SPI_CR2_DMA (SPI_CR2 | \
+ (1 << STM_SPI_CR2_TXDMAEN) | \
+ (1 << STM_SPI_CR2_RXDMAEN))
+
+#define SPI_CR2_SYNC (SPI_CR2 | \
+ (0 << STM_SPI_CR2_TXDMAEN) | \
+ (0 << STM_SPI_CR2_RXDMAEN))
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+ /* Set up the transmit DMA to deliver data */
+ ao_dma_set_transfer(mosi_dma_index,
+ &stm_spi->dr,
+ (void *) block,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (1 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+ (0 << STM_DMA_CCR_TCIE));
+
+ /* Clear RXNE */
+ (void) stm_spi->dr;
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ &spi_dev_null,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (0 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+ (1 << STM_DMA_CCR_TCIE));
+
+ stm_spi->cr2 = SPI_CR2_DMA;
+
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+ /* Set up the transmit DMA to deliver data */
+ ao_dma_set_transfer(mosi_dma_index,
+ &stm_spi->dr,
+ &value,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (0 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+ (0 << STM_DMA_CCR_TCIE));
+
+ /* Clear RXNE */
+ (void) stm_spi->dr;
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ &spi_dev_null,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (0 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+ (1 << STM_DMA_CCR_TCIE));
+
+ stm_spi->cr2 = SPI_CR2_DMA;
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t *b = block;
+ struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+
+ stm_spi->cr2 = SPI_CR2_SYNC;
+
+ /* Clear RXNE */
+ (void) stm_spi->dr;
+
+ while (len--) {
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
+ stm_spi->dr = *b++;
+ }
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+ spi_dev_null = 0xff;
+
+ /* Set up transmit DMA to make the SPI hardware actually run */
+ ao_dma_set_transfer(mosi_dma_index,
+ &stm_spi->dr,
+ &spi_dev_null,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (0 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+ (0 << STM_DMA_CCR_TCIE));
+
+ /* Clear RXNE */
+ (void) stm_spi->dr;
+
+ /* Set up the receive DMA to capture data */
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ block,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (1 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+ (1 << STM_DMA_CCR_TCIE));
+
+ stm_spi->cr2 = SPI_CR2_DMA;
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+
+ /* Wait until the SPI unit is done */
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+ /* Set up transmit DMA to send data */
+ ao_dma_set_transfer(mosi_dma_index,
+ &stm_spi->dr,
+ out,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (1 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+ (0 << STM_DMA_CCR_TCIE));
+
+ /* Clear RXNE */
+ (void) stm_spi->dr;
+
+ /* Set up the receive DMA to capture data */
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ in,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (1 << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+ (1 << STM_DMA_CCR_TCIE));
+
+ stm_spi->cr2 = SPI_CR2_DMA;
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+
+ /* Wait until the SPI unit is done */
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
+static void
+ao_spi_disable_index(uint8_t spi_index)
+{
+ /* Disable current config
+ */
+ switch (AO_SPI_INDEX(spi_index)) {
+ case STM_SPI_INDEX(1):
+ switch (spi_index) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_gpio_set(&stm_gpioa, 5, 1);
+ stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_gpio_set(&stm_gpiob, 3, 1);
+ stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+ break;
+ }
+ break;
+ case STM_SPI_INDEX(2):
+ switch (spi_index) {
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_gpio_set(&stm_gpiob, 13, 1);
+ stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+ao_spi_enable_index(uint8_t spi_index)
+{
+ switch (AO_SPI_INDEX(spi_index)) {
+ case STM_SPI_INDEX(1):
+ switch (spi_index) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
+ stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
+ stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
+ break;
+ }
+ break;
+ case STM_SPI_INDEX(2):
+ switch (spi_index) {
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+ao_spi_config(uint8_t spi_index, uint32_t speed)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ stm_spi->cr2 = SPI_CR2;
+ stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
+ (0 << STM_SPI_CR1_BIDIOE) |
+ (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
+ (0 << STM_SPI_CR1_CRCNEXT) |
+ (0 << STM_SPI_CR1_CRCL) |
+ (0 << STM_SPI_CR1_RXONLY) |
+ (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
+ (1 << STM_SPI_CR1_SSI) | /* ... */
+ (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
+ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
+ (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
+ (1 << STM_SPI_CR1_MSTR) |
+ (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
+ (0 << STM_SPI_CR1_CPHA));
+
+ if (spi_index != ao_spi_index[id]) {
+
+ /* Disable old config
+ */
+ ao_spi_disable_index(ao_spi_index[id]);
+
+ /* Enable new config
+ */
+ ao_spi_enable_index(spi_index);
+
+ /* Remember current config
+ */
+ ao_spi_index[id] = spi_index;
+ }
+}
+
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
+ return 0;
+ ao_spi_config(spi_index, speed);
+ return 1;
+}
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ ao_mutex_get(&ao_spi_mutex[id]);
+ ao_spi_config(spi_index, speed);
+}
+
+void
+ao_spi_put(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ stm_spi->cr1 = 0;
+ ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ ao_spi_disable_index(spi_index);
+
+ stm_spi->cr1 = 0;
+ (void) stm_spi->sr;
+ stm_spi->cr2 = SPI_CR2_SYNC;
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_1
+# if SPI_1_PA5_PA6_PA7
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+ stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PB3_PB4_PB5
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+ stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
+# endif
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+ ao_spi_index[0] = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(STM_SPI_INDEX(1));
+#endif
+
+#if HAS_SPI_2
+# if SPI_2_PB10_PB13_PB14
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+ stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
+# endif
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+ ao_spi_index[1] = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(STM_SPI_INDEX(2));
+#endif
+}
diff --git a/src/stmf0/ao_timer.c b/src/stmf0/ao_timer.c
index 3aae7e55..e5bf04a3 100644
--- a/src/stmf0/ao_timer.c
+++ b/src/stmf0/ao_timer.c
@@ -50,12 +50,14 @@ void stm_systick_isr(void)
#if AO_DATA_ALL
if (++ao_data_count == ao_data_interval) {
ao_data_count = 0;
+#if HAS_ADC
#if HAS_FAKE_FLIGHT
if (ao_fake_flight_active)
ao_fake_flight_poll();
else
#endif
ao_adc_poll();
+#endif
#if (AO_DATA_ALL & ~(AO_DATA_ADC))
ao_wakeup((void *) &ao_data_count);
#endif
@@ -92,6 +94,7 @@ ao_timer_init(void)
#endif
+#if AO_HSI48
static void
ao_clock_enable_crs(void)
{
@@ -127,15 +130,12 @@ ao_clock_enable_crs(void)
(0 << STM_CRS_CR_ERRIE) |
(0 << STM_CRS_CR_SYNCWARNIE) |
(0 << STM_CRS_CR_SYNCOKIE));
-
}
+#endif
-void
-ao_clock_init(void)
+static void
+ao_clock_hsi(void)
{
- uint32_t cfgr;
-
- /* Switch to HSI while messing about */
stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
ao_arch_nop();
@@ -153,15 +153,17 @@ ao_clock_init(void)
/* reset PLLON, CSSON, HSEBYP, HSEON */
stm_rcc.cr &= 0x0000ffff;
+}
- /* Disable all interrupts */
- stm_rcc.cir = 0;
-
+static void
+ao_clock_normal_start(void)
+{
#if AO_HSE
-#define STM_RCC_CFGR_SWS_TARGET_CLOCK STM_RCC_CFGR_SWS_HSE
-#define STM_RCC_CFGR_SW_TARGET_CLOCK STM_RCC_CFGR_SW_HSE
+ uint32_t cfgr;
+#define STM_RCC_CFGR_SWS_TARGET_CLOCK STM_RCC_CFGR_SWS_PLL
+#define STM_RCC_CFGR_SW_TARGET_CLOCK STM_RCC_CFGR_SW_PLL
#define STM_PLLSRC AO_HSE
-#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK 1
+#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK STM_RCC_CFGR_PLLSRC_HSE
#if AO_HSE_BYPASS
stm_rcc.cr |= (1 << STM_RCC_CR_HSEBYP);
@@ -172,6 +174,33 @@ ao_clock_init(void)
stm_rcc.cr |= (1 << STM_RCC_CR_HSEON);
while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSERDY)))
asm("nop");
+
+#ifdef STM_PLLSRC
+ /* Disable the PLL */
+ stm_rcc.cr &= ~(1 << STM_RCC_CR_PLLON);
+ while (stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY))
+ asm("nop");
+
+ /* PLLVCO to 48MHz (for USB) -> PLLMUL = 3 */
+ cfgr = stm_rcc.cfgr;
+ cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
+ cfgr |= (AO_RCC_CFGR_PLLMUL << STM_RCC_CFGR_PLLMUL);
+
+ /* PLL source */
+ cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
+ cfgr |= (STM_RCC_CFGR_PLLSRC_TARGET_CLOCK << STM_RCC_CFGR_PLLSRC);
+ stm_rcc.cfgr = cfgr;
+
+ /* Disable pre divider */
+ stm_rcc.cfgr2 = (STM_RCC_CFGR2_PREDIV_1 << STM_RCC_CFGR2_PREDIV);
+
+ /* Enable the PLL and wait for it */
+ stm_rcc.cr |= (1 << STM_RCC_CR_PLLON);
+ while (!(stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY)))
+ asm("nop");
+
+#endif
+
#endif
@@ -196,10 +225,50 @@ ao_clock_init(void)
#define STM_PLLSRC STM_HSI
#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK 0
#endif
+}
+
+static void
+ao_clock_normal_switch(void)
+{
+ uint32_t cfgr;
+ cfgr = stm_rcc.cfgr;
+ cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
+ cfgr |= (STM_RCC_CFGR_SW_TARGET_CLOCK << STM_RCC_CFGR_SW);
+ stm_rcc.cfgr = cfgr;
+ for (;;) {
+ uint32_t c, part, mask, val;
+
+ c = stm_rcc.cfgr;
+ mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
+ val = (STM_RCC_CFGR_SWS_TARGET_CLOCK << STM_RCC_CFGR_SWS);
+ part = c & mask;
+ if (part == val)
+ break;
+ }
+#if !AO_HSI && !AO_NEED_HSI
+ /* Turn off the HSI clock */
+ stm_rcc.cr &= ~(1 << STM_RCC_CR_HSION);
+#endif
#ifdef STM_PLLSRC
-#error No code for PLL initialization yet
+ /* USB PLL source */
+ stm_rcc.cfgr3 |= (1 << STM_RCC_CFGR3_USBSW);
#endif
+}
+
+void
+ao_clock_init(void)
+{
+ uint32_t cfgr;
+
+ /* Switch to HSI while messing about */
+ ao_clock_hsi();
+
+ /* Disable all interrupts */
+ stm_rcc.cir = 0;
+
+ /* Start high speed clock */
+ ao_clock_normal_start();
/* Set flash latency to tolerate 48MHz SYSCLK -> 1 wait state */
@@ -228,29 +297,11 @@ ao_clock_init(void)
stm_rcc.cfgr = cfgr;
/* Switch to the desired system clock */
-
- cfgr = stm_rcc.cfgr;
- cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
- cfgr |= (STM_RCC_CFGR_SW_TARGET_CLOCK << STM_RCC_CFGR_SW);
- stm_rcc.cfgr = cfgr;
- for (;;) {
- uint32_t c, part, mask, val;
-
- c = stm_rcc.cfgr;
- mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
- val = (STM_RCC_CFGR_SWS_TARGET_CLOCK << STM_RCC_CFGR_SWS);
- part = c & mask;
- if (part == val)
- break;
- }
+ ao_clock_normal_switch();
/* Clear reset flags */
stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
-#if !AO_HSI && !AO_NEED_HSI
- /* Turn off the HSI clock */
- stm_rcc.cr &= ~(1 << STM_RCC_CR_HSION);
-#endif
#if DEBUG_THE_CLOCK
/* Output SYSCLK on PA8 for measurments */
@@ -264,3 +315,18 @@ ao_clock_init(void)
stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL);
#endif
}
+
+#if AO_POWER_MANAGEMENT
+void
+ao_clock_suspend(void)
+{
+ ao_clock_hsi();
+}
+
+void
+ao_clock_resume(void)
+{
+ ao_clock_normal_start();
+ ao_clock_normal_switch();
+}
+#endif
diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c
index b8146c21..253506d5 100644
--- a/src/stmf0/ao_usb_stm.c
+++ b/src/stmf0/ao_usb_stm.c
@@ -18,8 +18,10 @@
#include "ao.h"
#include "ao_usb.h"
#include "ao_product.h"
+#include "ao_power.h"
#define USB_DEBUG 0
+#define USB_STATUS 0
#define USB_DEBUG_DATA 0
#define USB_ECHO 0
@@ -27,6 +29,10 @@
#error "must define AO_PA11_PA12_RMP"
#endif
+#ifndef AO_POWER_MANAGEMENT
+#define AO_POWER_MANAGEMENT 0
+#endif
+
#ifndef USE_USB_STDIO
#define USE_USB_STDIO 1
#endif
@@ -83,23 +89,42 @@ static uint16_t ao_usb_sram_addr;
static uint16_t *ao_usb_ep0_tx_buffer;
static uint16_t *ao_usb_ep0_rx_buffer;
+#if AO_USB_HAS_INT
/* Pointer to interrupt buffer in USB memory */
static uint16_t ao_usb_int_tx_offset;
+#endif
/* Pointer to bulk data tx/rx buffers in USB memory */
+#if AO_USB_HAS_IN
static uint16_t ao_usb_in_tx_offset;
static uint16_t *ao_usb_in_tx_buffer;
-static uint16_t ao_usb_out_rx_offset;
-static uint16_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;
+#endif
+#if AO_USB_HAS_OUT
+static uint16_t ao_usb_out_rx_offset;
+static uint16_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_rx_buffer[AO_USB_OUT_SIZE];
static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
+#endif
+#if AO_USB_HAS_IN2
+static uint16_t ao_usb_in2_tx_offset;
+static uint16_t *ao_usb_in2_tx_buffer;
+
+/* System ram shadow of USB buffer; writing individual bytes is
+ * too much of a pain (sigh) */
+static uint8_t ao_usb_tx2_buffer[AO_USB_IN_SIZE];
+static uint8_t ao_usb_tx2_count;
+#endif
+
/*
* End point register indices
*/
@@ -108,6 +133,7 @@ static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
#define AO_USB_INT_EPR 1
#define AO_USB_OUT_EPR 2
#define AO_USB_IN_EPR 3
+#define AO_USB_IN2_EPR 4
/* Marks when we don't need to send an IN packet.
* This happens only when the last IN packet is not full,
@@ -122,6 +148,16 @@ static uint8_t ao_usb_in_flushed;
*/
static uint8_t ao_usb_in_pending;
+#if AO_USB_HAS_IN2
+/* 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_in2_pending;
+static uint16_t in2_count;
+static uint8_t ao_usb_in2_flushed;
+#endif
+
/* Marks when an OUT packet has been received by the hardware
* but not pulled to the shadow buffer.
*/
@@ -129,10 +165,9 @@ 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
+#define AO_USB_EP0_GOT_SETUP 1
+#define AO_USB_EP0_GOT_RX_DATA 2
+#define AO_USB_EP0_GOT_TX_ACK 4
static uint8_t ao_usb_ep0_receive;
static uint8_t ao_usb_address;
@@ -338,16 +373,29 @@ ao_usb_alloc_buffers(void)
ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
ao_usb_sram_addr += AO_USB_CONTROL_SIZE;
+
+#if AO_USB_HAS_INT
ao_usb_int_tx_offset = ao_usb_sram_addr;
ao_usb_sram_addr += AO_USB_INT_SIZE;
+#endif
+#if AO_USB_HAS_OUT
ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
ao_usb_out_rx_offset = ao_usb_sram_addr;
ao_usb_sram_addr += AO_USB_OUT_SIZE;
+#endif
+#if AO_USB_HAS_IN
ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
ao_usb_in_tx_offset = ao_usb_sram_addr;
ao_usb_sram_addr += AO_USB_IN_SIZE;
+#endif
+
+#if AO_USB_HAS_IN2
+ ao_usb_in2_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
+ ao_usb_in2_tx_offset = ao_usb_sram_addr;
+ ao_usb_sram_addr += AO_USB_IN_SIZE;
+#endif
}
static void
@@ -396,6 +444,7 @@ ao_usb_set_configuration(void)
{
debug ("ao_usb_set_configuration\n");
+#if AO_USB_HAS_INT
/* Set up the INT end point */
ao_usb_bdt[AO_USB_INT_EPR].single.addr_tx = ao_usb_int_tx_offset;
ao_usb_bdt[AO_USB_INT_EPR].single.count_tx = 0;
@@ -405,7 +454,9 @@ ao_usb_set_configuration(void)
STM_USB_EPR_EP_TYPE_INTERRUPT,
STM_USB_EPR_STAT_RX_DISABLED,
STM_USB_EPR_STAT_TX_NAK);
+#endif
+#if AO_USB_HAS_OUT
/* Set up the OUT end point */
ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_out_rx_offset;
ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) |
@@ -416,7 +467,9 @@ ao_usb_set_configuration(void)
STM_USB_EPR_EP_TYPE_BULK,
STM_USB_EPR_STAT_RX_VALID,
STM_USB_EPR_STAT_TX_DISABLED);
+#endif
+#if AO_USB_HAS_IN
/* Set up the IN end point */
ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_in_tx_offset;
ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0;
@@ -426,6 +479,19 @@ ao_usb_set_configuration(void)
STM_USB_EPR_EP_TYPE_BULK,
STM_USB_EPR_STAT_RX_DISABLED,
STM_USB_EPR_STAT_TX_NAK);
+#endif
+
+#if AO_USB_HAS_IN2
+ /* Set up the IN2 end point */
+ ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in2_tx_offset;
+ ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = 0;
+
+ ao_usb_init_ep(AO_USB_IN2_EPR,
+ AO_USB_IN2_EP,
+ STM_USB_EPR_EP_TYPE_BULK,
+ STM_USB_EPR_STAT_RX_DISABLED,
+ STM_USB_EPR_STAT_TX_NAK);
+#endif
ao_usb_running = 1;
#if AO_USB_DIRECTIO
@@ -559,6 +625,36 @@ ao_usb_ep0_in_start(uint16_t max)
static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+#if AO_USB_DEVICE_ID_SERIAL
+static uint8_t ao_usb_serial[2 + 48];
+
+/* Convert a 32-bit value to 8 hexidecimal UCS2 characters */
+static void
+hex_to_ucs2(uint32_t in, uint8_t *out)
+{
+ int i;
+
+ for (i = 28; i >= 0; i -= 4) {
+ uint8_t bits = (in >> i) & 0xf;
+ *out++ = ((bits < 10) ? '0' : ('a' - 10)) + bits;
+ *out++ = 0;
+ }
+}
+
+/* Encode the device ID (96 bits) in hexidecimal to use as a device
+ * serial number
+ */
+static void
+ao_usb_serial_init(void)
+{
+ ao_usb_serial[0] = 50; /* length */
+ ao_usb_serial[1] = AO_USB_DESC_STRING;
+ hex_to_ucs2(stm_device_id.u_id0, ao_usb_serial + 2 + 0);
+ hex_to_ucs2(stm_device_id.u_id1, ao_usb_serial + 2 + 16);
+ hex_to_ucs2(stm_device_id.u_id2, ao_usb_serial + 2 + 32);
+}
+#endif
+
/* Walk through the list of descriptors and find a match
*/
static void
@@ -576,6 +672,13 @@ ao_usb_get_descriptor(uint16_t value)
len = descriptor[2];
else
len = descriptor[0];
+#if AO_USB_DEVICE_ID_SERIAL
+ /* Slightly hacky - the serial number is string 3 */
+ if (type == AO_USB_DESC_STRING && (value & 0xff) == 3) {
+ descriptor = ao_usb_serial;
+ len = sizeof (ao_usb_serial);
+ }
+#endif
ao_usb_ep0_in_set(descriptor, len);
break;
}
@@ -686,11 +789,6 @@ 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();
@@ -721,6 +819,25 @@ ao_usb_ep0_handle(uint8_t receive)
}
}
+#if AO_POWER_MANAGEMENT
+void
+ao_usb_suspend(void)
+{
+ stm_usb.cntr |= (1 << STM_USB_CNTR_FSUSP);
+ ao_power_suspend();
+ stm_usb.cntr |= (1 << STM_USB_CNTR_LP_MODE);
+ ao_clock_suspend();
+}
+
+void
+ao_usb_wakeup(void)
+{
+ ao_clock_resume();
+ stm_usb.cntr &= ~(1 << STM_USB_CNTR_FSUSP);
+ ao_power_resume();
+}
+#endif
+
void
stm_usb_isr(void)
{
@@ -773,6 +890,16 @@ stm_usb_isr(void)
ao_wakeup(&ao_usb_in_pending);
}
break;
+#if AO_USB_HAS_IN2
+ case AO_USB_IN2_EPR:
+ ++in2_count;
+ _tx_dbg1("TX2 ISR", epr);
+ if (ao_usb_epr_ctr_tx(epr)) {
+ ao_usb_in2_pending = 0;
+ ao_wakeup(&ao_usb_in2_pending);
+ }
+ break;
+#endif
case AO_USB_INT_EPR:
++int_count;
if (ao_usb_epr_ctr_tx(epr))
@@ -784,12 +911,22 @@ stm_usb_isr(void)
if (istr & (1 << STM_USB_ISTR_RESET)) {
++reset_count;
- ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET;
- ao_usb_ep0_handle(ao_usb_ep0_receive);
+ debug ("\treset\n");
+ ao_usb_set_ep0();
}
-
+#if AO_POWER_MANAGEMENT
+ if (istr & (1 << STM_USB_ISTR_SUSP)) {
+ debug ("\tsuspend\n");
+ ao_usb_suspend();
+ }
+ if (istr & (1 << STM_USB_ISTR_WKUP)) {
+ debug ("\twakeup\n");
+ ao_usb_wakeup();
+ }
+#endif
}
+#if AO_USB_HAS_IN
/* Queue the current IN buffer for transmission */
static void
_ao_usb_in_send(void)
@@ -868,7 +1005,90 @@ ao_usb_putchar(char c)
}
ao_arch_release_interrupts();
}
+#endif
+
+#if AO_USB_HAS_IN2
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in2_send(void)
+{
+ _tx_dbg0("in2_send start");
+ debug ("send2 %d\n", ao_usb_tx_count);
+ while (ao_usb_in2_pending)
+ ao_sleep(&ao_usb_in2_pending);
+ ao_usb_in2_pending = 1;
+ if (ao_usb_tx2_count != AO_USB_IN_SIZE)
+ ao_usb_in2_flushed = 1;
+ ao_usb_copy_tx(ao_usb_tx2_buffer, ao_usb_in2_tx_buffer, ao_usb_tx2_count);
+ ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in_tx_offset;
+ ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = ao_usb_tx_count;
+ ao_usb_tx2_count = 0;
+ _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID);
+ _tx_dbg0("in2_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in2_wait(void)
+{
+ for (;;) {
+ /* Check if the current buffer is writable */
+ if (ao_usb_tx2_count < AO_USB_IN_SIZE)
+ break;
+
+ _tx_dbg0("in2_wait top");
+ /* Wait for an IN buffer to be ready */
+ while (ao_usb_in2_pending)
+ ao_sleep(&ao_usb_in2_pending);
+ _tx_dbg0("in_wait bottom");
+ }
+}
+
+void
+ao_usb_flush2(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_in2_flushed) {
+ _tx_dbg0("flush2 top");
+ _ao_usb_in2_send();
+ _tx_dbg0("flush2 end");
+ }
+ ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar2(char c)
+{
+ if (!ao_usb_running)
+ return;
+
+ ao_arch_block_interrupts();
+ _ao_usb_in2_wait();
+ ao_usb_in2_flushed = 0;
+ ao_usb_tx2_buffer[ao_usb_tx2_count++] = (uint8_t) c;
+
+ /* Send the packet when full */
+ if (ao_usb_tx2_count == AO_USB_IN_SIZE) {
+ _tx_dbg0("putchar2 full");
+ _ao_usb_in2_send();
+ _tx_dbg0("putchar2 flushed");
+ }
+ ao_arch_release_interrupts();
+}
+#endif
+
+#if AO_USB_HAS_OUT
static void
_ao_usb_out_recv(void)
{
@@ -925,6 +1145,7 @@ ao_usb_getchar(void)
ao_arch_release_interrupts();
return c;
}
+#endif
#if AO_USB_DIRECTIO
uint16_t *
@@ -979,6 +1200,43 @@ ao_usb_write(uint16_t *buffer, uint16_t len)
_ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID);
ao_arch_release_interrupts();
}
+
+#if AO_USB_HAS_IN2
+void
+ao_usb_write2(uint16_t *buffer, uint16_t len)
+{
+ ao_arch_block_interrupts();
+
+ /* Wait for everything to be ready at the same time */
+ for (;;) {
+ /* Make sure USB is connected */
+ if (!ao_usb_running) {
+ ao_sleep(&ao_usb_running);
+ continue;
+ }
+
+ /* Flush any pending regular I/O */
+ if (ao_usb_tx2_count) {
+ _ao_usb_in2_send();
+ continue;
+ }
+
+ /* Wait for an idle IN buffer */
+ if (ao_usb_in2_pending) {
+ ao_sleep(&ao_usb_in2_pending);
+ continue;
+ }
+ break;
+ }
+
+ ao_usb_in2_pending = 1;
+ ao_usb_in2_flushed = (len != AO_USB_IN_SIZE);
+ ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_packet_buffer_offset(buffer);
+ ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = len;
+ _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID);
+ ao_arch_release_interrupts();
+}
+#endif
#endif
void
@@ -1050,8 +1308,8 @@ ao_usb_enable(void)
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) |
+ (AO_POWER_MANAGEMENT << STM_USB_CNTR_WKUPM) |
+ (AO_POWER_MANAGEMENT << STM_USB_CNTR_SUSPM) |
(1 << STM_USB_CNTR_RESETM) |
(0 << STM_USB_CNTR_SOFM) |
(0 << STM_USB_CNTR_ESOFM) |
@@ -1086,7 +1344,7 @@ ao_usb_echo(void)
}
#endif
-#if USB_DEBUG
+#if USB_STATUS
static void
ao_usb_irq(void)
{
@@ -1109,7 +1367,13 @@ ao_usb_init(void)
/* Set PA11/PA12 remapping bit */
stm_syscfg.cfgr1 |= (AO_PA11_PA12_RMP << STM_SYSCFG_CFGR1_PA11_PA12_RMP);
+#ifndef AO_USB_START_DISABLED
ao_usb_enable();
+#endif
+
+#if AO_USB_DEVICE_ID_SERIAL
+ ao_usb_serial_init();
+#endif
debug ("ao_usb_init\n");
ao_usb_ep0_state = AO_USB_EP0_IDLE;
@@ -1119,7 +1383,7 @@ ao_usb_init(void)
#if USB_ECHO
ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
#endif
-#if USB_DEBUG
+#if USB_STATUS
ao_cmd_register(&ao_usb_cmds[0]);
#endif
#if !USB_ECHO
diff --git a/src/stmf0/registers.ld b/src/stmf0/registers.ld
index 598fc1af..1f9862b1 100644
--- a/src/stmf0/registers.ld
+++ b/src/stmf0/registers.ld
@@ -54,4 +54,4 @@ stm_mpu = 0xe000ed90;
/* calibration data in system memory */
stm_cal = 0x1ffff7b8;
stm_flash_size_04x = 0x1ffff7cc;
-stm_device_id = 0x1ff80050;
+stm_device_id = 0x1ffff7ac;
diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h
index ce8ca456..33eb9c88 100644
--- a/src/stmf0/stm32f0.h
+++ b/src/stmf0/stm32f0.h
@@ -475,6 +475,24 @@ extern struct stm_rcc stm_rcc;
#define STM_RCC_CR2_HSI14RDY 1
#define STM_RCC_CR2_HSI14ON 0
+#define STM_RCC_CFGR2_PREDIV 0
+#define STM_RCC_CFGR2_PREDIV_1 0x0
+#define STM_RCC_CFGR2_PREDIV_2 0x1
+#define STM_RCC_CFGR2_PREDIV_3 0x2
+#define STM_RCC_CFGR2_PREDIV_4 0x3
+#define STM_RCC_CFGR2_PREDIV_5 0x4
+#define STM_RCC_CFGR2_PREDIV_6 0x5
+#define STM_RCC_CFGR2_PREDIV_7 0x6
+#define STM_RCC_CFGR2_PREDIV_8 0x7
+#define STM_RCC_CFGR2_PREDIV_9 0x8
+#define STM_RCC_CFGR2_PREDIV_10 0x9
+#define STM_RCC_CFGR2_PREDIV_11 0xa
+#define STM_RCC_CFGR2_PREDIV_12 0xb
+#define STM_RCC_CFGR2_PREDIV_13 0xc
+#define STM_RCC_CFGR2_PREDIV_14 0xd
+#define STM_RCC_CFGR2_PREDIV_15 0xe
+#define STM_RCC_CFGR2_PREDIV_16 0xf
+
#define STM_RCC_CFGR3_USART3SW 18
#define STM_RCC_CFGR3_USART2SW 16
#define STM_RCC_CFGR3_ADCSW 8
@@ -795,7 +813,7 @@ isr(tim7)
#define STM_ISR_TSC_POS 8
#define STM_ISR_DMA_CH1_POS 9
#define STM_ISR_DMA_CH2_3_DMA2_CH1_2_POS 10
-#define STM_ISR_DMA_CH44_5_6_7_DMA2_CH3_4_5_POS 11
+#define STM_ISR_DMA_CH4_5_6_7_DMA2_CH3_4_5_POS 11
#define STM_ISR_ADC_COMP_POS 12
#define STM_ISR_TIM1_BRK_UP_TRG_COM_POS 13
#define STM_ISR_TIM1_CC_POS 14
@@ -819,8 +837,11 @@ isr(tim7)
struct stm_syscfg {
vuint32_t cfgr1;
+ uint32_t reserved_04;
vuint32_t exticr[4];
vuint32_t cfgr2;
+ uint8_t reserved_1c[0x80-0x1c];
+ vuint32_t itline[31];
};
extern struct stm_syscfg stm_syscfg;
@@ -858,7 +879,13 @@ extern struct stm_syscfg stm_syscfg;
#define STM_SYSCFG_CFGR1_MEM_MODE_SRAM 3
#define STM_SYSCFG_CFGR1_MEM_MODE_MASK 3
-#if 0
+#define STM_SYSCFG_EXTICR_PA 0
+#define STM_SYSCFG_EXTICR_PB 1
+#define STM_SYSCFG_EXTICR_PC 2
+#define STM_SYSCFG_EXTICR_PD 3
+#define STM_SYSCFG_EXTICR_PE 4
+#define STM_SYSCFG_EXTICR_PF 5
+
static inline void
stm_exticr_set(struct stm_gpio *gpio, int pin) {
uint8_t reg = pin >> 2;
@@ -879,8 +906,6 @@ stm_exticr_set(struct stm_gpio *gpio, int pin) {
stm_syscfg.exticr[reg] = (stm_syscfg.exticr[reg] & ~(0xf << shift)) | val << shift;
}
-#endif
-
struct stm_dma_channel {
vuint32_t ccr;
@@ -890,7 +915,7 @@ struct stm_dma_channel {
vuint32_t reserved;
};
-#define STM_NUM_DMA 6
+#define STM_NUM_DMA 5
struct stm_dma {
vuint32_t isr;
@@ -900,7 +925,7 @@ struct stm_dma {
extern struct stm_dma stm_dma;
-/* DMA channels go from 1 to 6, instead of 0 to 5 (sigh)
+/* DMA channels go from 1 to 5, instead of 0 to 4 (sigh)
*/
#define STM_DMA_INDEX(channel) ((channel) - 1)
@@ -1042,7 +1067,7 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
#define STM_SPI_CR1_BIDIOE 14
#define STM_SPI_CR1_CRCEN 13
#define STM_SPI_CR1_CRCNEXT 12
-#define STM_SPI_CR1_DFF 11
+#define STM_SPI_CR1_CRCL 11
#define STM_SPI_CR1_RXONLY 10
#define STM_SPI_CR1_SSM 9
#define STM_SPI_CR1_SSI 8
@@ -1063,17 +1088,43 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
#define STM_SPI_CR1_CPOL 1
#define STM_SPI_CR1_CPHA 0
+#define STM_SPI_CR2_LDMA_TX 14
+#define STM_SPI_CR2_LDMA_RX 13
+#define STM_SPI_CR2_FRXTH 12
+#define STM_SPI_CR2_DS 8
+#define STM_SPI_CR2_DS_4 0x3
+#define STM_SPI_CR2_DS_5 0x4
+#define STM_SPI_CR2_DS_6 0x5
+#define STM_SPI_CR2_DS_7 0x6
+#define STM_SPI_CR2_DS_8 0x7
+#define STM_SPI_CR2_DS_9 0x8
+#define STM_SPI_CR2_DS_10 0x9
+#define STM_SPI_CR2_DS_11 0xa
+#define STM_SPI_CR2_DS_12 0xb
+#define STM_SPI_CR2_DS_13 0xc
+#define STM_SPI_CR2_DS_14 0xd
+#define STM_SPI_CR2_DS_15 0xe
+#define STM_SPI_CR2_DS_16 0xf
#define STM_SPI_CR2_TXEIE 7
#define STM_SPI_CR2_RXNEIE 6
#define STM_SPI_CR2_ERRIE 5
+#define STM_SPI_CR2_FRF 4
+# define STM_SPI_CR2_FRF_MOTOROLA 0
+# define STM_SPI_CR2_FRF_TI 1
+#define STM_SPI_CR2_NSSP 3
#define STM_SPI_CR2_SSOE 2
#define STM_SPI_CR2_TXDMAEN 1
#define STM_SPI_CR2_RXDMAEN 0
+#define STM_SPI_SR_FTLVL 11
+#define STM_SPI_SR_FRLVL 9
+#define STM_SPI_SR_FRE 8
#define STM_SPI_SR_BSY 7
#define STM_SPI_SR_OVR 6
#define STM_SPI_SR_MODF 5
#define STM_SPI_SR_CRCERR 4
+#define STM_SPI_SR_UDR 3
+#define STM_SPI_SR_CHSIDE 2
#define STM_SPI_SR_TXE 1
#define STM_SPI_SR_RXNE 0
@@ -1293,7 +1344,7 @@ extern struct stm_i2c stm_i2c1, stm_i2c2;
#define STM_I2C_CCR_CCR 0
#define STM_I2C_CCR_MASK 0x7ff
-struct stm_tim234 {
+struct stm_tim23 {
vuint32_t cr1;
vuint32_t cr2;
vuint32_t smcr;
@@ -1318,204 +1369,205 @@ struct stm_tim234 {
uint32_t reserved_44;
vuint32_t dcr;
vuint32_t dmar;
-
- uint32_t reserved_50;
};
-extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
-
-#define STM_TIM234_CR1_CKD 8
-#define STM_TIM234_CR1_CKD_1 0
-#define STM_TIM234_CR1_CKD_2 1
-#define STM_TIM234_CR1_CKD_4 2
-#define STM_TIM234_CR1_CKD_MASK 3
-#define STM_TIM234_CR1_ARPE 7
-#define STM_TIM234_CR1_CMS 5
-#define STM_TIM234_CR1_CMS_EDGE 0
-#define STM_TIM234_CR1_CMS_CENTER_1 1
-#define STM_TIM234_CR1_CMS_CENTER_2 2
-#define STM_TIM234_CR1_CMS_CENTER_3 3
-#define STM_TIM234_CR1_CMS_MASK 3
-#define STM_TIM234_CR1_DIR 4
-#define STM_TIM234_CR1_DIR_UP 0
-#define STM_TIM234_CR1_DIR_DOWN 1
-#define STM_TIM234_CR1_OPM 3
-#define STM_TIM234_CR1_URS 2
-#define STM_TIM234_CR1_UDIS 1
-#define STM_TIM234_CR1_CEN 0
-
-#define STM_TIM234_CR2_TI1S 7
-#define STM_TIM234_CR2_MMS 4
-#define STM_TIM234_CR2_MMS_RESET 0
-#define STM_TIM234_CR2_MMS_ENABLE 1
-#define STM_TIM234_CR2_MMS_UPDATE 2
-#define STM_TIM234_CR2_MMS_COMPARE_PULSE 3
-#define STM_TIM234_CR2_MMS_COMPARE_OC1REF 4
-#define STM_TIM234_CR2_MMS_COMPARE_OC2REF 5
-#define STM_TIM234_CR2_MMS_COMPARE_OC3REF 6
-#define STM_TIM234_CR2_MMS_COMPARE_OC4REF 7
-#define STM_TIM234_CR2_MMS_MASK 7
-#define STM_TIM234_CR2_CCDS 3
-
-#define STM_TIM234_SMCR_ETP 15
-#define STM_TIM234_SMCR_ECE 14
-#define STM_TIM234_SMCR_ETPS 12
-#define STM_TIM234_SMCR_ETPS_OFF 0
-#define STM_TIM234_SMCR_ETPS_DIV_2 1
-#define STM_TIM234_SMCR_ETPS_DIV_4 2
-#define STM_TIM234_SMCR_ETPS_DIV_8 3
-#define STM_TIM234_SMCR_ETPS_MASK 3
-#define STM_TIM234_SMCR_ETF 8
-#define STM_TIM234_SMCR_ETF_NONE 0
-#define STM_TIM234_SMCR_ETF_INT_N_2 1
-#define STM_TIM234_SMCR_ETF_INT_N_4 2
-#define STM_TIM234_SMCR_ETF_INT_N_8 3
-#define STM_TIM234_SMCR_ETF_DTS_2_N_6 4
-#define STM_TIM234_SMCR_ETF_DTS_2_N_8 5
-#define STM_TIM234_SMCR_ETF_DTS_4_N_6 6
-#define STM_TIM234_SMCR_ETF_DTS_4_N_8 7
-#define STM_TIM234_SMCR_ETF_DTS_8_N_6 8
-#define STM_TIM234_SMCR_ETF_DTS_8_N_8 9
-#define STM_TIM234_SMCR_ETF_DTS_16_N_5 10
-#define STM_TIM234_SMCR_ETF_DTS_16_N_6 11
-#define STM_TIM234_SMCR_ETF_DTS_16_N_8 12
-#define STM_TIM234_SMCR_ETF_DTS_32_N_5 13
-#define STM_TIM234_SMCR_ETF_DTS_32_N_6 14
-#define STM_TIM234_SMCR_ETF_DTS_32_N_8 15
-#define STM_TIM234_SMCR_ETF_MASK 15
-#define STM_TIM234_SMCR_MSM 7
-#define STM_TIM234_SMCR_TS 4
-#define STM_TIM234_SMCR_TS_ITR0 0
-#define STM_TIM234_SMCR_TS_ITR1 1
-#define STM_TIM234_SMCR_TS_ITR2 2
-#define STM_TIM234_SMCR_TS_ITR3 3
-#define STM_TIM234_SMCR_TS_TI1F_ED 4
-#define STM_TIM234_SMCR_TS_TI1FP1 5
-#define STM_TIM234_SMCR_TS_TI2FP2 6
-#define STM_TIM234_SMCR_TS_ETRF 7
-#define STM_TIM234_SMCR_TS_MASK 7
-#define STM_TIM234_SMCR_OCCS 3
-#define STM_TIM234_SMCR_SMS 0
-#define STM_TIM234_SMCR_SMS_DISABLE 0
-#define STM_TIM234_SMCR_SMS_ENCODER_MODE_1 1
-#define STM_TIM234_SMCR_SMS_ENCODER_MODE_2 2
-#define STM_TIM234_SMCR_SMS_ENCODER_MODE_3 3
-#define STM_TIM234_SMCR_SMS_RESET_MODE 4
-#define STM_TIM234_SMCR_SMS_GATED_MODE 5
-#define STM_TIM234_SMCR_SMS_TRIGGER_MODE 6
-#define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7
-#define STM_TIM234_SMCR_SMS_MASK 7
-
-#define STM_TIM234_SR_CC4OF 12
-#define STM_TIM234_SR_CC3OF 11
-#define STM_TIM234_SR_CC2OF 10
-#define STM_TIM234_SR_CC1OF 9
-#define STM_TIM234_SR_TIF 6
-#define STM_TIM234_SR_CC4IF 4
-#define STM_TIM234_SR_CC3IF 3
-#define STM_TIM234_SR_CC2IF 2
-#define STM_TIM234_SR_CC1IF 1
-#define STM_TIM234_SR_UIF 0
-
-#define STM_TIM234_EGR_TG 6
-#define STM_TIM234_EGR_CC4G 4
-#define STM_TIM234_EGR_CC3G 3
-#define STM_TIM234_EGR_CC2G 2
-#define STM_TIM234_EGR_CC1G 1
-#define STM_TIM234_EGR_UG 0
-
-#define STM_TIM234_CCMR1_OC2CE 15
-#define STM_TIM234_CCMR1_OC2M 12
-#define STM_TIM234_CCMR1_OC2M_FROZEN 0
-#define STM_TIM234_CCMR1_OC2M_SET_HIGH_ON_MATCH 1
-#define STM_TIM234_CCMR1_OC2M_SET_LOW_ON_MATCH 2
-#define STM_TIM234_CCMR1_OC2M_TOGGLE 3
-#define STM_TIM234_CCMR1_OC2M_FORCE_LOW 4
-#define STM_TIM234_CCMR1_OC2M_FORCE_HIGH 5
-#define STM_TIM234_CCMR1_OC2M_PWM_MODE_1 6
-#define STM_TIM234_CCMR1_OC2M_PWM_MODE_2 7
-#define STM_TIM234_CCMR1_OC2M_MASK 7
-#define STM_TIM234_CCMR1_OC2PE 11
-#define STM_TIM234_CCMR1_OC2FE 10
-#define STM_TIM234_CCMR1_CC2S 8
-#define STM_TIM234_CCMR1_CC2S_OUTPUT 0
-#define STM_TIM234_CCMR1_CC2S_INPUT_TI2 1
-#define STM_TIM234_CCMR1_CC2S_INPUT_TI1 2
-#define STM_TIM234_CCMR1_CC2S_INPUT_TRC 3
-#define STM_TIM234_CCMR1_CC2S_MASK 3
-
-#define STM_TIM234_CCMR1_OC1CE 7
-#define STM_TIM234_CCMR1_OC1M 4
-#define STM_TIM234_CCMR1_OC1M_FROZEN 0
-#define STM_TIM234_CCMR1_OC1M_SET_HIGH_ON_MATCH 1
-#define STM_TIM234_CCMR1_OC1M_SET_LOW_ON_MATCH 2
-#define STM_TIM234_CCMR1_OC1M_TOGGLE 3
-#define STM_TIM234_CCMR1_OC1M_FORCE_LOW 4
-#define STM_TIM234_CCMR1_OC1M_FORCE_HIGH 5
-#define STM_TIM234_CCMR1_OC1M_PWM_MODE_1 6
-#define STM_TIM234_CCMR1_OC1M_PWM_MODE_2 7
-#define STM_TIM234_CCMR1_OC1M_MASK 7
-#define STM_TIM234_CCMR1_OC1PE 11
-#define STM_TIM234_CCMR1_OC1FE 2
-#define STM_TIM234_CCMR1_CC1S 0
-#define STM_TIM234_CCMR1_CC1S_OUTPUT 0
-#define STM_TIM234_CCMR1_CC1S_INPUT_TI1 1
-#define STM_TIM234_CCMR1_CC1S_INPUT_TI2 2
-#define STM_TIM234_CCMR1_CC1S_INPUT_TRC 3
-#define STM_TIM234_CCMR1_CC1S_MASK 3
-
-#define STM_TIM234_CCMR2_OC4CE 15
-#define STM_TIM234_CCMR2_OC4M 12
-#define STM_TIM234_CCMR2_OC4M_FROZEN 0
-#define STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH 1
-#define STM_TIM234_CCMR2_OC4M_SET_LOW_ON_MATCH 2
-#define STM_TIM234_CCMR2_OC4M_TOGGLE 3
-#define STM_TIM234_CCMR2_OC4M_FORCE_LOW 4
-#define STM_TIM234_CCMR2_OC4M_FORCE_HIGH 5
-#define STM_TIM234_CCMR2_OC4M_PWM_MODE_1 6
-#define STM_TIM234_CCMR2_OC4M_PWM_MODE_2 7
-#define STM_TIM234_CCMR2_OC4M_MASK 7
-#define STM_TIM234_CCMR2_OC4PE 11
-#define STM_TIM234_CCMR2_OC4FE 10
-#define STM_TIM234_CCMR2_CC4S 8
-#define STM_TIM234_CCMR2_CC4S_OUTPUT 0
-#define STM_TIM234_CCMR2_CC4S_INPUT_TI4 1
-#define STM_TIM234_CCMR2_CC4S_INPUT_TI3 2
-#define STM_TIM234_CCMR2_CC4S_INPUT_TRC 3
-#define STM_TIM234_CCMR2_CC4S_MASK 3
-
-#define STM_TIM234_CCMR2_OC3CE 7
-#define STM_TIM234_CCMR2_OC3M 4
-#define STM_TIM234_CCMR2_OC3M_FROZEN 0
-#define STM_TIM234_CCMR2_OC3M_SET_HIGH_ON_MATCH 1
-#define STM_TIM234_CCMR2_OC3M_SET_LOW_ON_MATCH 2
-#define STM_TIM234_CCMR2_OC3M_TOGGLE 3
-#define STM_TIM234_CCMR2_OC3M_FORCE_LOW 4
-#define STM_TIM234_CCMR2_OC3M_FORCE_HIGH 5
-#define STM_TIM234_CCMR2_OC3M_PWM_MODE_1 6
-#define STM_TIM234_CCMR2_OC3M_PWM_MODE_2 7
-#define STM_TIM234_CCMR2_OC3M_MASK 7
-#define STM_TIM234_CCMR2_OC3PE 11
-#define STM_TIM234_CCMR2_OC3FE 2
-#define STM_TIM234_CCMR2_CC3S 0
-#define STM_TIM234_CCMR2_CC3S_OUTPUT 0
-#define STM_TIM234_CCMR2_CC3S_INPUT_TI3 1
-#define STM_TIM234_CCMR2_CC3S_INPUT_TI4 2
-#define STM_TIM234_CCMR2_CC3S_INPUT_TRC 3
-#define STM_TIM234_CCMR2_CC3S_MASK 3
-
-#define STM_TIM234_CCER_CC4NP 15
-#define STM_TIM234_CCER_CC4P 13
-#define STM_TIM234_CCER_CC4E 12
-#define STM_TIM234_CCER_CC3NP 11
-#define STM_TIM234_CCER_CC3P 9
-#define STM_TIM234_CCER_CC3E 8
-#define STM_TIM234_CCER_CC2NP 7
-#define STM_TIM234_CCER_CC2P 5
-#define STM_TIM234_CCER_CC2E 4
-#define STM_TIM234_CCER_CC1NP 3
-#define STM_TIM234_CCER_CC1P 1
-#define STM_TIM234_CCER_CC1E 0
+extern struct stm_tim23 stm_tim2, stm_tim3;
+
+#define stm_tim3 (*(struct stm_tim23 *) 0x40000400)
+#define stm_tim2 (*(struct stm_tim23 *) 0x40000000)
+
+#define STM_TIM23_CR1_CKD 8
+#define STM_TIM23_CR1_CKD_1 0
+#define STM_TIM23_CR1_CKD_2 1
+#define STM_TIM23_CR1_CKD_4 2
+#define STM_TIM23_CR1_CKD_MASK 3
+#define STM_TIM23_CR1_ARPE 7
+#define STM_TIM23_CR1_CMS 5
+#define STM_TIM23_CR1_CMS_EDGE 0
+#define STM_TIM23_CR1_CMS_CENTER_1 1
+#define STM_TIM23_CR1_CMS_CENTER_2 2
+#define STM_TIM23_CR1_CMS_CENTER_3 3
+#define STM_TIM23_CR1_CMS_MASK 3
+#define STM_TIM23_CR1_DIR 4
+#define STM_TIM23_CR1_DIR_UP 0
+#define STM_TIM23_CR1_DIR_DOWN 1
+#define STM_TIM23_CR1_OPM 3
+#define STM_TIM23_CR1_URS 2
+#define STM_TIM23_CR1_UDIS 1
+#define STM_TIM23_CR1_CEN 0
+
+#define STM_TIM23_CR2_TI1S 7
+#define STM_TIM23_CR2_MMS 4
+#define STM_TIM23_CR2_MMS_RESET 0
+#define STM_TIM23_CR2_MMS_ENABLE 1
+#define STM_TIM23_CR2_MMS_UPDATE 2
+#define STM_TIM23_CR2_MMS_COMPARE_PULSE 3
+#define STM_TIM23_CR2_MMS_COMPARE_OC1REF 4
+#define STM_TIM23_CR2_MMS_COMPARE_OC2REF 5
+#define STM_TIM23_CR2_MMS_COMPARE_OC3REF 6
+#define STM_TIM23_CR2_MMS_COMPARE_OC4REF 7
+#define STM_TIM23_CR2_MMS_MASK 7
+#define STM_TIM23_CR2_CCDS 3
+
+#define STM_TIM23_SMCR_ETP 15
+#define STM_TIM23_SMCR_ECE 14
+#define STM_TIM23_SMCR_ETPS 12
+#define STM_TIM23_SMCR_ETPS_OFF 0
+#define STM_TIM23_SMCR_ETPS_DIV_2 1
+#define STM_TIM23_SMCR_ETPS_DIV_4 2
+#define STM_TIM23_SMCR_ETPS_DIV_8 3
+#define STM_TIM23_SMCR_ETPS_MASK 3
+#define STM_TIM23_SMCR_ETF 8
+#define STM_TIM23_SMCR_ETF_NONE 0
+#define STM_TIM23_SMCR_ETF_INT_N_2 1
+#define STM_TIM23_SMCR_ETF_INT_N_4 2
+#define STM_TIM23_SMCR_ETF_INT_N_8 3
+#define STM_TIM23_SMCR_ETF_DTS_2_N_6 4
+#define STM_TIM23_SMCR_ETF_DTS_2_N_8 5
+#define STM_TIM23_SMCR_ETF_DTS_4_N_6 6
+#define STM_TIM23_SMCR_ETF_DTS_4_N_8 7
+#define STM_TIM23_SMCR_ETF_DTS_8_N_6 8
+#define STM_TIM23_SMCR_ETF_DTS_8_N_8 9
+#define STM_TIM23_SMCR_ETF_DTS_16_N_5 10
+#define STM_TIM23_SMCR_ETF_DTS_16_N_6 11
+#define STM_TIM23_SMCR_ETF_DTS_16_N_8 12
+#define STM_TIM23_SMCR_ETF_DTS_32_N_5 13
+#define STM_TIM23_SMCR_ETF_DTS_32_N_6 14
+#define STM_TIM23_SMCR_ETF_DTS_32_N_8 15
+#define STM_TIM23_SMCR_ETF_MASK 15
+#define STM_TIM23_SMCR_MSM 7
+#define STM_TIM23_SMCR_TS 4
+#define STM_TIM23_SMCR_TS_ITR0 0
+#define STM_TIM23_SMCR_TS_ITR1 1
+#define STM_TIM23_SMCR_TS_ITR2 2
+#define STM_TIM23_SMCR_TS_ITR3 3
+#define STM_TIM23_SMCR_TS_TI1F_ED 4
+#define STM_TIM23_SMCR_TS_TI1FP1 5
+#define STM_TIM23_SMCR_TS_TI2FP2 6
+#define STM_TIM23_SMCR_TS_ETRF 7
+#define STM_TIM23_SMCR_TS_MASK 7
+#define STM_TIM23_SMCR_OCCS 3
+#define STM_TIM23_SMCR_SMS 0
+#define STM_TIM23_SMCR_SMS_DISABLE 0
+#define STM_TIM23_SMCR_SMS_ENCODER_MODE_1 1
+#define STM_TIM23_SMCR_SMS_ENCODER_MODE_2 2
+#define STM_TIM23_SMCR_SMS_ENCODER_MODE_3 3
+#define STM_TIM23_SMCR_SMS_RESET_MODE 4
+#define STM_TIM23_SMCR_SMS_GATED_MODE 5
+#define STM_TIM23_SMCR_SMS_TRIGGER_MODE 6
+#define STM_TIM23_SMCR_SMS_EXTERNAL_CLOCK 7
+#define STM_TIM23_SMCR_SMS_MASK 7
+
+#define STM_TIM23_SR_CC4OF 12
+#define STM_TIM23_SR_CC3OF 11
+#define STM_TIM23_SR_CC2OF 10
+#define STM_TIM23_SR_CC1OF 9
+#define STM_TIM23_SR_TIF 6
+#define STM_TIM23_SR_CC4IF 4
+#define STM_TIM23_SR_CC3IF 3
+#define STM_TIM23_SR_CC2IF 2
+#define STM_TIM23_SR_CC1IF 1
+#define STM_TIM23_SR_UIF 0
+
+#define STM_TIM23_EGR_TG 6
+#define STM_TIM23_EGR_CC4G 4
+#define STM_TIM23_EGR_CC3G 3
+#define STM_TIM23_EGR_CC2G 2
+#define STM_TIM23_EGR_CC1G 1
+#define STM_TIM23_EGR_UG 0
+
+#define STM_TIM23_CCMR1_OC2CE 15
+#define STM_TIM23_CCMR1_OC2M 12
+#define STM_TIM23_CCMR1_OC2M_FROZEN 0
+#define STM_TIM23_CCMR1_OC2M_SET_HIGH_ON_MATCH 1
+#define STM_TIM23_CCMR1_OC2M_SET_LOW_ON_MATCH 2
+#define STM_TIM23_CCMR1_OC2M_TOGGLE 3
+#define STM_TIM23_CCMR1_OC2M_FORCE_LOW 4
+#define STM_TIM23_CCMR1_OC2M_FORCE_HIGH 5
+#define STM_TIM23_CCMR1_OC2M_PWM_MODE_1 6
+#define STM_TIM23_CCMR1_OC2M_PWM_MODE_2 7
+#define STM_TIM23_CCMR1_OC2M_MASK 7
+#define STM_TIM23_CCMR1_OC2PE 11
+#define STM_TIM23_CCMR1_OC2FE 10
+#define STM_TIM23_CCMR1_CC2S 8
+#define STM_TIM23_CCMR1_CC2S_OUTPUT 0
+#define STM_TIM23_CCMR1_CC2S_INPUT_TI2 1
+#define STM_TIM23_CCMR1_CC2S_INPUT_TI1 2
+#define STM_TIM23_CCMR1_CC2S_INPUT_TRC 3
+#define STM_TIM23_CCMR1_CC2S_MASK 3
+
+#define STM_TIM23_CCMR1_OC1CE 7
+#define STM_TIM23_CCMR1_OC1M 4
+#define STM_TIM23_CCMR1_OC1M_FROZEN 0
+#define STM_TIM23_CCMR1_OC1M_SET_HIGH_ON_MATCH 1
+#define STM_TIM23_CCMR1_OC1M_SET_LOW_ON_MATCH 2
+#define STM_TIM23_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM23_CCMR1_OC1M_FORCE_LOW 4
+#define STM_TIM23_CCMR1_OC1M_FORCE_HIGH 5
+#define STM_TIM23_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM23_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM23_CCMR1_OC1M_MASK 7
+#define STM_TIM23_CCMR1_OC1PE 11
+#define STM_TIM23_CCMR1_OC1FE 2
+#define STM_TIM23_CCMR1_CC1S 0
+#define STM_TIM23_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM23_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM23_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM23_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM23_CCMR1_CC1S_MASK 3
+
+#define STM_TIM23_CCMR2_OC4CE 15
+#define STM_TIM23_CCMR2_OC4M 12
+#define STM_TIM23_CCMR2_OC4M_FROZEN 0
+#define STM_TIM23_CCMR2_OC4M_SET_HIGH_ON_MATCH 1
+#define STM_TIM23_CCMR2_OC4M_SET_LOW_ON_MATCH 2
+#define STM_TIM23_CCMR2_OC4M_TOGGLE 3
+#define STM_TIM23_CCMR2_OC4M_FORCE_LOW 4
+#define STM_TIM23_CCMR2_OC4M_FORCE_HIGH 5
+#define STM_TIM23_CCMR2_OC4M_PWM_MODE_1 6
+#define STM_TIM23_CCMR2_OC4M_PWM_MODE_2 7
+#define STM_TIM23_CCMR2_OC4M_MASK 7
+#define STM_TIM23_CCMR2_OC4PE 11
+#define STM_TIM23_CCMR2_OC4FE 10
+#define STM_TIM23_CCMR2_CC4S 8
+#define STM_TIM23_CCMR2_CC4S_OUTPUT 0
+#define STM_TIM23_CCMR2_CC4S_INPUT_TI4 1
+#define STM_TIM23_CCMR2_CC4S_INPUT_TI3 2
+#define STM_TIM23_CCMR2_CC4S_INPUT_TRC 3
+#define STM_TIM23_CCMR2_CC4S_MASK 3
+
+#define STM_TIM23_CCMR2_OC3CE 7
+#define STM_TIM23_CCMR2_OC3M 4
+#define STM_TIM23_CCMR2_OC3M_FROZEN 0
+#define STM_TIM23_CCMR2_OC3M_SET_HIGH_ON_MATCH 1
+#define STM_TIM23_CCMR2_OC3M_SET_LOW_ON_MATCH 2
+#define STM_TIM23_CCMR2_OC3M_TOGGLE 3
+#define STM_TIM23_CCMR2_OC3M_FORCE_LOW 4
+#define STM_TIM23_CCMR2_OC3M_FORCE_HIGH 5
+#define STM_TIM23_CCMR2_OC3M_PWM_MODE_1 6
+#define STM_TIM23_CCMR2_OC3M_PWM_MODE_2 7
+#define STM_TIM23_CCMR2_OC3M_MASK 7
+#define STM_TIM23_CCMR2_OC3PE 11
+#define STM_TIM23_CCMR2_OC3FE 2
+#define STM_TIM23_CCMR2_CC3S 0
+#define STM_TIM23_CCMR2_CC3S_OUTPUT 0
+#define STM_TIM23_CCMR2_CC3S_INPUT_TI3 1
+#define STM_TIM23_CCMR2_CC3S_INPUT_TI4 2
+#define STM_TIM23_CCMR2_CC3S_INPUT_TRC 3
+#define STM_TIM23_CCMR2_CC3S_MASK 3
+
+#define STM_TIM23_CCER_CC4NP 15
+#define STM_TIM23_CCER_CC4P 13
+#define STM_TIM23_CCER_CC4E 12
+#define STM_TIM23_CCER_CC3NP 11
+#define STM_TIM23_CCER_CC3P 9
+#define STM_TIM23_CCER_CC3E 8
+#define STM_TIM23_CCER_CC2NP 7
+#define STM_TIM23_CCER_CC2P 5
+#define STM_TIM23_CCER_CC2E 4
+#define STM_TIM23_CCER_CC1NP 3
+#define STM_TIM23_CCER_CC1P 1
+#define STM_TIM23_CCER_CC1E 0
struct stm_usb {
struct {