summaryrefslogtreecommitdiffstats
path: root/libopencm3/lib
diff options
context:
space:
mode:
authorroot <root@lab2.panaceas.james.local>2014-11-02 10:14:39 +0000
committerroot <root@lab2.panaceas.james.local>2014-11-02 10:14:39 +0000
commit1dc7d758f96dd2b9bd7b03f01ca032d68b696cf0 (patch)
tree1a70fddfcc79c54c863912a3b8b8cecc594f21ae /libopencm3/lib
downloadstm32_usb_kvm-1dc7d758f96dd2b9bd7b03f01ca032d68b696cf0.tar.gz
stm32_usb_kvm-1dc7d758f96dd2b9bd7b03f01ca032d68b696cf0.tar.bz2
stm32_usb_kvm-1dc7d758f96dd2b9bd7b03f01ca032d68b696cf0.zip
fish
Diffstat (limited to 'libopencm3/lib')
-rw-r--r--libopencm3/lib/Makefile.include52
-rw-r--r--libopencm3/lib/cm3/assert.c34
-rw-r--r--libopencm3/lib/cm3/dwt.c77
-rw-r--r--libopencm3/lib/cm3/nvic.c199
-rw-r--r--libopencm3/lib/cm3/scb.c47
-rw-r--r--libopencm3/lib/cm3/sync.c73
-rw-r--r--libopencm3/lib/cm3/systick.c203
-rw-r--r--libopencm3/lib/cm3/vector.c121
-rw-r--r--libopencm3/lib/dispatch/vector_chipset.c12
-rw-r--r--libopencm3/lib/efm32/efm32g/Makefile43
-rw-r--r--libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld106
-rw-r--r--libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld15
-rw-r--r--libopencm3/lib/efm32/efm32gg/Makefile43
-rw-r--r--libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld106
-rw-r--r--libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld15
-rw-r--r--libopencm3/lib/efm32/efm32lg/Makefile43
-rw-r--r--libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld106
-rw-r--r--libopencm3/lib/efm32/efm32tg/Makefile43
-rw-r--r--libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld106
-rw-r--r--libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld15
-rw-r--r--libopencm3/lib/ethernet/mac.c43
-rw-r--r--libopencm3/lib/ethernet/mac_stm32fxx7.c378
-rw-r--r--libopencm3/lib/ethernet/phy.c64
-rw-r--r--libopencm3/lib/ethernet/phy_ksz8051mll.c89
-rw-r--r--libopencm3/lib/lm3s/Makefile40
-rw-r--r--libopencm3/lib/lm3s/gpio.c52
-rw-r--r--libopencm3/lib/lm3s/libopencm3_lm3s.ld106
-rw-r--r--libopencm3/lib/lm4f/Makefile43
-rw-r--r--libopencm3/lib/lm4f/gpio.c598
-rw-r--r--libopencm3/lib/lm4f/libopencm3_lm4f.ld2
-rw-r--r--libopencm3/lib/lm4f/rcc.c499
-rw-r--r--libopencm3/lib/lm4f/systemcontrol.c40
-rw-r--r--libopencm3/lib/lm4f/uart.c627
-rw-r--r--libopencm3/lib/lm4f/usb_lm4f.c651
-rw-r--r--libopencm3/lib/lpc13xx/Makefile40
-rw-r--r--libopencm3/lib/lpc13xx/gpio.c42
-rw-r--r--libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld106
-rw-r--r--libopencm3/lib/lpc17xx/Makefile40
-rw-r--r--libopencm3/lib/lpc17xx/gpio.c48
-rw-r--r--libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld106
-rw-r--r--libopencm3/lib/lpc43xx/gpio.c53
-rw-r--r--libopencm3/lib/lpc43xx/i2c.c102
-rw-r--r--libopencm3/lib/lpc43xx/ipc.c58
-rw-r--r--libopencm3/lib/lpc43xx/m0/Makefile43
-rw-r--r--libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld0
-rw-r--r--libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld96
-rw-r--r--libopencm3/lib/lpc43xx/m4/Makefile50
-rw-r--r--libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld127
-rw-r--r--libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld139
-rw-r--r--libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld128
-rw-r--r--libopencm3/lib/lpc43xx/m4/vector_chipset.c48
-rw-r--r--libopencm3/lib/lpc43xx/scu.c52
-rw-r--r--libopencm3/lib/lpc43xx/ssp.c140
-rw-r--r--libopencm3/lib/lpc43xx/timer.c72
-rw-r--r--libopencm3/lib/lpc43xx/uart.c243
-rw-r--r--libopencm3/lib/sam/3a/Makefile37
-rw-r--r--libopencm3/lib/sam/3a/libopencm3_sam3a.ld106
-rw-r--r--libopencm3/lib/sam/3n/Makefile37
-rw-r--r--libopencm3/lib/sam/3n/libopencm3_sam3n.ld106
-rw-r--r--libopencm3/lib/sam/3s/Makefile38
-rw-r--r--libopencm3/lib/sam/3s/libopencm3_sam3s.ld106
-rw-r--r--libopencm3/lib/sam/3u/Makefile38
-rw-r--r--libopencm3/lib/sam/3u/libopencm3_sam3u.ld106
-rw-r--r--libopencm3/lib/sam/3x/Makefile37
-rw-r--r--libopencm3/lib/sam/3x/libopencm3_sam3x.ld106
-rw-r--r--libopencm3/lib/sam/common/gpio.c64
-rw-r--r--libopencm3/lib/sam/common/pmc.c97
-rw-r--r--libopencm3/lib/sam/common/usart.c110
-rw-r--r--libopencm3/lib/stm32/can.c557
-rw-r--r--libopencm3/lib/stm32/common/adc_common_v1.c755
-rw-r--r--libopencm3/lib/stm32/common/crc_common_all.c81
-rw-r--r--libopencm3/lib/stm32/common/crypto_common_f24.c175
-rw-r--r--libopencm3/lib/stm32/common/dac_common_all.c503
-rw-r--r--libopencm3/lib/stm32/common/dma_common_f24.c794
-rw-r--r--libopencm3/lib/stm32/common/dma_common_l1f013.c435
-rw-r--r--libopencm3/lib/stm32/common/exti_common_all.c154
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f01.c235
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f234.c121
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f24.c416
-rw-r--r--libopencm3/lib/stm32/common/gpio_common_all.c151
-rw-r--r--libopencm3/lib/stm32/common/gpio_common_f0234.c206
-rw-r--r--libopencm3/lib/stm32/common/hash_common_f24.c163
-rw-r--r--libopencm3/lib/stm32/common/i2c_common_all.c419
-rw-r--r--libopencm3/lib/stm32/common/iwdg_common_all.c149
-rw-r--r--libopencm3/lib/stm32/common/pwr_common_all.c205
-rw-r--r--libopencm3/lib/stm32/common/rcc_common_all.c188
-rw-r--r--libopencm3/lib/stm32/common/rtc_common_l1f024.c123
-rw-r--r--libopencm3/lib/stm32/common/spi_common_all.c710
-rw-r--r--libopencm3/lib/stm32/common/spi_common_f03.c177
-rw-r--r--libopencm3/lib/stm32/common/spi_common_l1f124.c137
-rw-r--r--libopencm3/lib/stm32/common/timer_common_all.c2177
-rw-r--r--libopencm3/lib/stm32/common/timer_common_f234.c58
-rw-r--r--libopencm3/lib/stm32/common/timer_common_f24.c53
-rw-r--r--libopencm3/lib/stm32/common/usart_common_all.c367
-rw-r--r--libopencm3/lib/stm32/common/usart_common_f124.c143
-rw-r--r--libopencm3/lib/stm32/desig.c54
-rw-r--r--libopencm3/lib/stm32/f0/Makefile49
-rw-r--r--libopencm3/lib/stm32/f0/adc.c835
-rw-r--r--libopencm3/lib/stm32/f0/comparator.c64
-rw-r--r--libopencm3/lib/stm32/f0/crc.c31
-rw-r--r--libopencm3/lib/stm32/f0/crs.c32
-rw-r--r--libopencm3/lib/stm32/f0/dac.c31
-rw-r--r--libopencm3/lib/stm32/f0/dma.c31
-rw-r--r--libopencm3/lib/stm32/f0/flash.c157
-rw-r--r--libopencm3/lib/stm32/f0/gpio.c31
-rw-r--r--libopencm3/lib/stm32/f0/i2c.c32
-rw-r--r--libopencm3/lib/stm32/f0/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld106
-rw-r--r--libopencm3/lib/stm32/f0/pwr.c38
-rw-r--r--libopencm3/lib/stm32/f0/rcc.c665
-rw-r--r--libopencm3/lib/stm32/f0/rtc.c31
-rw-r--r--libopencm3/lib/stm32/f0/spi.c31
-rw-r--r--libopencm3/lib/stm32/f0/syscfg.c31
-rw-r--r--libopencm3/lib/stm32/f0/timer.c34
-rw-r--r--libopencm3/lib/stm32/f0/usart.c429
-rw-r--r--libopencm3/lib/stm32/f1/Makefile53
-rw-r--r--libopencm3/lib/stm32/f1/adc.c452
-rw-r--r--libopencm3/lib/stm32/f1/crc.c31
-rw-r--r--libopencm3/lib/stm32/f1/dac.c31
-rw-r--r--libopencm3/lib/stm32/f1/dma.c31
-rw-r--r--libopencm3/lib/stm32/f1/ethernet.c52
-rw-r--r--libopencm3/lib/stm32/f1/flash.c306
-rw-r--r--libopencm3/lib/stm32/f1/gpio.c194
-rw-r--r--libopencm3/lib/stm32/f1/i2c.c31
-rw-r--r--libopencm3/lib/stm32/f1/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld106
-rw-r--r--libopencm3/lib/stm32/f1/pwr.c43
-rw-r--r--libopencm3/lib/stm32/f1/rcc.c1106
-rw-r--r--libopencm3/lib/stm32/f1/rtc.c305
-rw-r--r--libopencm3/lib/stm32/f1/spi.c31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100x4.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100x6.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100x8.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100xb.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100xc.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100xd.ld31
-rw-r--r--libopencm3/lib/stm32/f1/stm32f100xe.ld31
-rw-r--r--libopencm3/lib/stm32/f1/timer.c57
-rw-r--r--libopencm3/lib/stm32/f1/usart.c31
-rw-r--r--libopencm3/lib/stm32/f2/Makefile52
-rw-r--r--libopencm3/lib/stm32/f2/crc.c33
-rw-r--r--libopencm3/lib/stm32/f2/crypto.c31
-rw-r--r--libopencm3/lib/stm32/f2/dac.c31
-rw-r--r--libopencm3/lib/stm32/f2/dma.c31
-rw-r--r--libopencm3/lib/stm32/f2/flash.c53
-rw-r--r--libopencm3/lib/stm32/f2/gpio.c31
-rw-r--r--libopencm3/lib/stm32/f2/hash.c31
-rw-r--r--libopencm3/lib/stm32/f2/i2c.c33
-rw-r--r--libopencm3/lib/stm32/f2/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld106
-rw-r--r--libopencm3/lib/stm32/f2/pwr.c39
-rw-r--r--libopencm3/lib/stm32/f2/rcc.c417
-rw-r--r--libopencm3/lib/stm32/f2/rtc.c31
-rw-r--r--libopencm3/lib/stm32/f2/spi.c31
-rw-r--r--libopencm3/lib/stm32/f2/timer.c38
-rw-r--r--libopencm3/lib/stm32/f2/usart.c31
-rw-r--r--libopencm3/lib/stm32/f3/Makefile50
-rw-r--r--libopencm3/lib/stm32/f3/adc.c1150
-rw-r--r--libopencm3/lib/stm32/f3/crc.c33
-rw-r--r--libopencm3/lib/stm32/f3/dac.c31
-rw-r--r--libopencm3/lib/stm32/f3/dma.c31
-rw-r--r--libopencm3/lib/stm32/f3/flash.c63
-rw-r--r--libopencm3/lib/stm32/f3/i2c.c486
-rw-r--r--libopencm3/lib/stm32/f3/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld106
-rw-r--r--libopencm3/lib/stm32/f3/pwr.c40
-rw-r--r--libopencm3/lib/stm32/f3/rcc.c465
-rw-r--r--libopencm3/lib/stm32/f3/rtc.c38
-rw-r--r--libopencm3/lib/stm32/f3/spi.c31
-rw-r--r--libopencm3/lib/stm32/f3/timer.c33
-rw-r--r--libopencm3/lib/stm32/f3/usart.c140
-rw-r--r--libopencm3/lib/stm32/f3/vector_chipset.c27
-rw-r--r--libopencm3/lib/stm32/f4/Makefile59
-rw-r--r--libopencm3/lib/stm32/f4/adc.c437
-rw-r--r--libopencm3/lib/stm32/f4/crc.c33
-rw-r--r--libopencm3/lib/stm32/f4/crypto.c66
-rw-r--r--libopencm3/lib/stm32/f4/dac.c31
-rw-r--r--libopencm3/lib/stm32/f4/dma.c31
-rw-r--r--libopencm3/lib/stm32/f4/flash.c53
-rw-r--r--libopencm3/lib/stm32/f4/fmc.c99
-rw-r--r--libopencm3/lib/stm32/f4/gpio.c31
-rw-r--r--libopencm3/lib/stm32/f4/hash.c31
-rw-r--r--libopencm3/lib/stm32/f4/i2c.c31
-rw-r--r--libopencm3/lib/stm32/f4/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld106
-rw-r--r--libopencm3/lib/stm32/f4/pwr.c46
-rw-r--r--libopencm3/lib/stm32/f4/rcc.c539
-rw-r--r--libopencm3/lib/stm32/f4/rtc.c97
-rw-r--r--libopencm3/lib/stm32/f4/spi.c31
-rw-r--r--libopencm3/lib/stm32/f4/stm32f405x6.ld33
-rw-r--r--libopencm3/lib/stm32/f4/timer.c38
-rw-r--r--libopencm3/lib/stm32/f4/usart.c31
-rw-r--r--libopencm3/lib/stm32/f4/vector_chipset.c27
-rw-r--r--libopencm3/lib/stm32/l1/Makefile52
-rw-r--r--libopencm3/lib/stm32/l1/adc.c201
-rw-r--r--libopencm3/lib/stm32/l1/crc.c33
-rw-r--r--libopencm3/lib/stm32/l1/dac.c31
-rw-r--r--libopencm3/lib/stm32/l1/dma.c31
-rw-r--r--libopencm3/lib/stm32/l1/flash.c208
-rw-r--r--libopencm3/lib/stm32/l1/gpio.c31
-rw-r--r--libopencm3/lib/stm32/l1/i2c.c31
-rw-r--r--libopencm3/lib/stm32/l1/iwdg.c31
-rw-r--r--libopencm3/lib/stm32/l1/lcd.c154
-rw-r--r--libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld106
-rw-r--r--libopencm3/lib/stm32/l1/pwr.c58
-rw-r--r--libopencm3/lib/stm32/l1/rcc.c534
-rw-r--r--libopencm3/lib/stm32/l1/rtc.c31
-rw-r--r--libopencm3/lib/stm32/l1/spi.c31
-rw-r--r--libopencm3/lib/stm32/l1/stm32l15xx6.ld32
-rw-r--r--libopencm3/lib/stm32/l1/stm32l15xx8.ld32
-rw-r--r--libopencm3/lib/stm32/l1/stm32l15xxb.ld32
-rw-r--r--libopencm3/lib/stm32/l1/stm32l15xxc.ld32
-rw-r--r--libopencm3/lib/stm32/l1/stm32l15xxd.ld32
-rw-r--r--libopencm3/lib/stm32/l1/timer.c59
-rw-r--r--libopencm3/lib/stm32/l1/usart.c31
-rw-r--r--libopencm3/lib/usb/usb.c175
-rw-r--r--libopencm3/lib/usb/usb_control.c288
-rw-r--r--libopencm3/lib/usb/usb_f103.c346
-rw-r--r--libopencm3/lib/usb/usb_f107.c91
-rw-r--r--libopencm3/lib/usb/usb_f207.c91
-rw-r--r--libopencm3/lib/usb/usb_fx07_common.c338
-rw-r--r--libopencm3/lib/usb/usb_fx07_common.h39
-rw-r--r--libopencm3/lib/usb/usb_msc.c814
-rw-r--r--libopencm3/lib/usb/usb_private.h163
-rw-r--r--libopencm3/lib/usb/usb_standard.c532
225 files changed, 33291 insertions, 0 deletions
diff --git a/libopencm3/lib/Makefile.include b/libopencm3/lib/Makefile.include
new file mode 100644
index 0000000..70fdd5c
--- /dev/null
+++ b/libopencm3/lib/Makefile.include
@@ -0,0 +1,52 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 Piotr Esden-Tempski <piotr@esden.net>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+# Be silent per default, but 'make V=1' will show all compiler calls.
+ifneq ($(V),1)
+Q := @
+endif
+
+# common objects
+OBJS += vector.o systick.o scb.o nvic.o assert.o sync.o dwt.o
+
+all: $(SRCLIBDIR)/$(LIBNAME).a
+
+$(SRCLIBDIR)/$(LIBNAME).a: $(SRCLIBDIR)/$(LIBNAME).ld $(OBJS)
+ @printf " AR $(LIBNAME).a\n"
+ $(Q)$(AR) $(ARFLAGS) "$@" $(OBJS)
+
+$(SRCLIBDIR)/$(LIBNAME).ld: $(LIBNAME).ld
+ @printf " CP $(LIBNAME).ld\n"
+ $(Q)cp $^ "$@"
+ $(Q)if [ -f $(LIBNAME)_rom_to_ram.ld ]; then cp $(LIBNAME)_rom_to_ram.ld $(SRCLIBDIR); fi
+
+%.o: %.c
+ @printf " CC $(<F)\n"
+ $(Q)$(CC) $(CFLAGS) -o $@ -c $<
+
+clean:
+ $(Q)rm -f *.o *.d ../*.o ../*.d
+ $(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).a
+ $(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).ld
+ $(Q)rm -f $(SRCLIBDIR)/$(LIBNAME)_rom_to_ram.ld
+
+.PHONY: clean
+
+-include $(OBJS:.o=.d)
diff --git a/libopencm3/lib/cm3/assert.c b/libopencm3/lib/cm3/assert.c
new file mode 100644
index 0000000..82def0d
--- /dev/null
+++ b/libopencm3/lib/cm3/assert.c
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Tomaz Solc <tomaz.solc@tablix.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/assert.h>
+
+void __attribute__((weak)) cm3_assert_failed(void)
+{
+ while (1);
+}
+
+void __attribute__((weak)) cm3_assert_failed_verbose(
+ const char *file __attribute__((unused)),
+ int line __attribute__((unused)),
+ const char *func __attribute__((unused)),
+ const char *assert_expr __attribute__((unused)))
+{
+ cm3_assert_failed();
+}
diff --git a/libopencm3/lib/cm3/dwt.c b/libopencm3/lib/cm3/dwt.c
new file mode 100644
index 0000000..fe7c261
--- /dev/null
+++ b/libopencm3/lib/cm3/dwt.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/scs.h>
+#include <libopencm3/cm3/dwt.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief DebugTrace Enable the CPU cycle counter
+ *
+ * This function will try to enable the CPU cycle counter that is intended for
+ * benchmarking performance of the code. If function fails, the cycle counter
+ * isn't available on this architecture.
+ *
+ * @returnd true, if success
+ */
+bool dwt_enable_cycle_counter(void)
+{
+#if defined(__ARM_ARCH_6M__)
+ return false; /* Not supported on ARMv6M */
+#endif /* defined(__ARM_ARCH_6M__) */
+
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+ /* Note TRCENA is for 7M and above*/
+ SCS_DEMCR |= SCS_DEMCR_TRCENA;
+ if (DWT_CTRL & DWT_CTRL_NOCYCCNT) {
+ return false; /* Not supported in implementation */
+ }
+
+ DWT_CYCCNT = 0;
+ DWT_CTRL |= DWT_CTRL_CYCCNTENA;
+ return true;
+#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */
+
+ /* not supported on other architectures */
+ return false;
+}
+/*---------------------------------------------------------------------------*/
+/** @brief DebugTrace Read the CPU cycle counter
+ *
+ * This function reads the core cycle counter if it is enabled. It is the
+ * fastest clock running on the system.
+ *
+ * @note The CPU cycle counter must be enabled by @ref dwt_enable_cycle_counter
+ *
+ * @returns 0 if cycle counter is not supported or enabled, the cycle counter
+ * value otherwise.
+ */
+uint32_t dwt_read_cycle_counter(void)
+{
+#if defined(__ARM_ARCH_6M__)
+ return 0; /* Not supported on ARMv6M */
+#endif /* defined(__ARM_ARCH_6M__) */
+
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+ if (DWT_CTRL & DWT_CTRL_CYCCNTENA) {
+ return DWT_CYCCNT;
+ } else {
+ return 0; /* not supported or enabled */
+ }
+#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */
+}
diff --git a/libopencm3/lib/cm3/nvic.c b/libopencm3/lib/cm3/nvic.c
new file mode 100644
index 0000000..6c2188a
--- /dev/null
+++ b/libopencm3/lib/cm3/nvic.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @defgroup CM3_nvic_file NVIC
+ *
+ * @ingroup CM3_files
+ *
+ * @brief <b>libopencm3 Cortex Nested Vectored Interrupt Controller</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble
+ * <fergusnoble@gmail.com>
+ *
+ * @date 18 August 2012
+ *
+ * Cortex processors provide 14 cortex-defined interrupts (NMI, usage faults,
+ * systicks etc.) and varying numbers of implementation defined interrupts
+ * (typically peripherial interrupts and DMA).
+ *
+ * @see Cortex-M3 Devices Generic User Guide
+ * @see STM32F10xxx Cortex-M3 programming manual
+ *
+ * LGPL License Terms @ref lgpl_license
+*/
+/**@{*/
+
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/scs.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Enable Interrupt
+ *
+ * Enables a user interrupt.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ */
+
+void nvic_enable_irq(uint8_t irqn)
+{
+ NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Disable Interrupt
+ *
+ * Disables a user interrupt.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ */
+
+void nvic_disable_irq(uint8_t irqn)
+{
+ NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Return Pending Interrupt
+ *
+ * True if the interrupt has occurred and is waiting for service.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ * @return Boolean. Interrupt pending.
+ */
+
+uint8_t nvic_get_pending_irq(uint8_t irqn)
+{
+ return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Set Pending Interrupt
+ *
+ * Force a user interrupt to a pending state. This has no effect if the
+ * interrupt is already pending.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ */
+
+void nvic_set_pending_irq(uint8_t irqn)
+{
+ NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Clear Pending Interrupt
+ *
+ * Force remove a user interrupt from a pending state. This has no effect if
+ * the interrupt is actively being serviced.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ */
+
+void nvic_clear_pending_irq(uint8_t irqn)
+{
+ NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Return Enabled Interrupt
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ * @return Boolean. Interrupt enabled.
+ */
+
+uint8_t nvic_get_irq_enabled(uint8_t irqn)
+{
+ return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Set Interrupt Priority
+ *
+ * CM3, CM4:
+ *
+ * There are 16 priority levels only, given by the upper four bits of the
+ * priority byte, as required by ARM standards. The priority levels are
+ * interpreted according to the pre-emptive priority grouping set in the
+ * SCB Application Interrupt and Reset Control Register (SCB_AIRCR), as done
+ * in @ref scb_set_priority_grouping.
+ *
+ * CM0:
+ *
+ * There are 4 priority levels only, given by the upper two bits of the
+ * priority byte, as required by ARM standards. No grouping available.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ * @param[in] priority Unsigned int8. Interrupt priority (0 ... 255 in steps of
+ * 16)
+ */
+
+void nvic_set_priority(uint8_t irqn, uint8_t priority)
+{
+ /* code from lpc43xx/nvic.c -- this is quite a hack and alludes to the
+ * negative interrupt numbers assigned to the system interrupts. better
+ * handling would mean signed integers. */
+ if (irqn >= NVIC_IRQ_COUNT) {
+ /* Cortex-M system interrupts */
+ SCS_SHPR((irqn & 0xF) - 4) = priority;
+ } else {
+ /* Device specific interrupts */
+ NVIC_IPR(irqn) = priority;
+ }
+}
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Return Active Interrupt
+ *
+ * Interrupt has occurred and is currently being serviced.
+ *
+ * @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+ * @return Boolean. Interrupt active.
+ */
+
+uint8_t nvic_get_active_irq(uint8_t irqn)
+{
+ return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief NVIC Software Trigger Interrupt
+ *
+ * Generate an interrupt from software. This has no effect for unprivileged
+ * access unless the privilege level has been elevated through the System
+ * Control Registers.
+ *
+ * @param[in] irqn Unsigned int16. Interrupt number (0 ... 239)
+ */
+
+void nvic_generate_software_interrupt(uint16_t irqn)
+{
+ if (irqn <= 239) {
+ NVIC_STIR |= irqn;
+ }
+}
+#endif
+/**@}*/
diff --git a/libopencm3/lib/cm3/scb.c b/libopencm3/lib/cm3/scb.c
new file mode 100644
index 0000000..8c5a2f3
--- /dev/null
+++ b/libopencm3/lib/cm3/scb.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include <libopencm3/cm3/scb.h>
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+void scb_reset_core(void)
+{
+ SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET;
+
+ while (1);
+}
+#endif
+
+void scb_reset_system(void)
+{
+ SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
+
+ while (1);
+}
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+void scb_set_priority_grouping(uint32_t prigroup)
+{
+ SCB_AIRCR = SCB_AIRCR_VECTKEY | prigroup;
+}
+#endif
diff --git a/libopencm3/lib/cm3/sync.c b/libopencm3/lib/cm3/sync.c
new file mode 100644
index 0000000..906138a
--- /dev/null
+++ b/libopencm3/lib/cm3/sync.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/sync.h>
+
+/* DMB is supported on CM0 */
+void __dmb()
+{
+ __asm__ volatile ("dmb");
+}
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+
+uint32_t __ldrex(volatile uint32_t *addr)
+{
+ uint32_t res;
+ __asm__ volatile ("ldrex %0, [%1]" : "=r" (res) : "r" (addr));
+ return res;
+}
+
+uint32_t __strex(uint32_t val, volatile uint32_t *addr)
+{
+ uint32_t res;
+ __asm__ volatile ("strex %0, %2, [%1]"
+ : "=&r" (res) : "r" (addr), "r" (val));
+ return res;
+}
+
+void mutex_lock(mutex_t *m)
+{
+ uint32_t status = 0;
+
+ do {
+ /* Wait until the mutex is unlocked. */
+ while (__ldrex(m) != MUTEX_UNLOCKED);
+
+ /* Try to acquire it. */
+ status = __strex(MUTEX_LOCKED, m);
+
+ /* Did we get it? If not then try again. */
+ } while (status != 0);
+
+ /* Execute the mysterious Data Memory Barrier instruction! */
+ __dmb();
+}
+
+void mutex_unlock(mutex_t *m)
+{
+ /* Ensure accesses to protected resource are finished */
+ __dmb();
+
+ /* Free the lock. */
+ *m = MUTEX_UNLOCKED;
+}
+
+#endif
diff --git a/libopencm3/lib/cm3/systick.c b/libopencm3/lib/cm3/systick.c
new file mode 100644
index 0000000..a99593b
--- /dev/null
+++ b/libopencm3/lib/cm3/systick.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @defgroup CM3_systick_file SysTick
+ *
+ * @ingroup CM3_files
+ *
+ * @brief <b>libopencm3 Cortex System Tick Timer</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * @date 19 August 2012
+ *
+ * This library supports the System Tick timer in ARM Cortex Microcontrollers.
+ *
+ * The System Tick timer is part of the ARM Cortex core. It is a 24 bit
+ * down counter that can be configured with an automatical reload value.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/**@{*/
+#include <libopencm3/cm3/systick.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief SysTick Set the Automatic Reload Value.
+ *
+ * The counter is set to the reload value when the counter starts and after it
+ * reaches zero.
+ *
+ * @note The systick counter value might be undefined upon startup. To get
+ * predictable behavior, it is a good idea to set or clear the counter after
+ * set reload. @seealso systick_clear
+ *
+ * @param[in] value uint32_t. 24 bit reload value.
+ */
+
+void systick_set_reload(uint32_t value)
+{
+ STK_RVR = (value & STK_RVR_RELOAD);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SysTick Read the Automatic Reload Value.
+ *
+ * @returns 24 bit reload value as uint32_t.
+ */
+
+uint32_t systick_get_reload(void)
+{
+ return STK_RVR & STK_RVR_RELOAD;
+}
+
+/** @brief SysTick Set clock and frequency of overflow
+ *
+ * This function sets the systick to AHB clock source, and the prescaler to
+ * generate interrupts with the desired frequency. The function fails, if
+ * the frequency is too low.
+ *
+ * @param[in] freq uint32_t The desired frequency in Hz
+ * @param[in] ahb uint32_t The current AHB frequency in Hz
+ * @returns true, if success, false if the desired frequency cannot be set.
+ */
+bool systick_set_frequency(uint32_t freq, uint32_t ahb)
+{
+ uint32_t ratio = ahb / freq;
+
+#if defined(__ARM_ARCH_6M__)
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
+#else
+ if (ratio >= (STK_RVR_RELOAD * 8)) {
+ /* This frequency is too slow */
+ return false;
+ } else if (ratio >= STK_RVR_RELOAD) {
+ ratio /= 8;
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
+ } else {
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
+ }
+#endif
+ systick_set_reload(ratio - 1);
+ return true;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get the current SysTick counter value.
+ *
+ * @returns 24 bit current value as uint32_t.
+ */
+
+uint32_t systick_get_value(void)
+{
+ return STK_CVR & STK_CVR_CURRENT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the SysTick Clock Source.
+ *
+ * The clock source can be either the AHB clock or the same clock divided by 8.
+ *
+ * @param[in] clocksource uint8_t. Clock source from @ref systick_clksource.
+ */
+
+void systick_set_clocksource(uint8_t clocksource)
+{
+ STK_CSR = (STK_CSR & ~STK_CSR_CLKSOURCE) |
+ (clocksource & STK_CSR_CLKSOURCE);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable SysTick Interrupt.
+ *
+ */
+
+void systick_interrupt_enable(void)
+{
+ STK_CSR |= STK_CSR_TICKINT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable SysTick Interrupt.
+ *
+ */
+
+void systick_interrupt_disable(void)
+{
+ STK_CSR &= ~STK_CSR_TICKINT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable SysTick Counter.
+ *
+ */
+
+void systick_counter_enable(void)
+{
+ STK_CSR |= STK_CSR_ENABLE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable SysTick Counter.
+ *
+ */
+
+void systick_counter_disable(void)
+{
+ STK_CSR &= ~STK_CSR_ENABLE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SysTick Read the Counter Flag.
+ *
+ * The count flag is set when the timer count becomes zero, and is cleared when
+ * the flag is read.
+ *
+ * @returns Boolean if flag set.
+ */
+
+uint8_t systick_get_countflag(void)
+{
+ return (STK_CSR & STK_CSR_COUNTFLAG) ? 1 : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SysTick Clear counter Value.
+ *
+ * The counter value is cleared. Useful for well defined startup.
+ */
+
+void systick_clear(void)
+{
+ STK_CVR = 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SysTick Get Calibration Value
+ *
+ * @returns Current calibration value
+ */
+uint32_t systick_get_calib(void)
+{
+ return STK_CALIB & STK_CALIB_TENMS;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/cm3/vector.c b/libopencm3/lib/cm3/vector.c
new file mode 100644
index 0000000..4523d31
--- /dev/null
+++ b/libopencm3/lib/cm3/vector.c
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>,
+ * Copyright (C) 2012 chrysn <chrysn@fsfe.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/vector.h>
+
+/* load optional platform dependent initialization routines */
+#include "../dispatch/vector_chipset.c"
+/* load the weak symbols for IRQ_HANDLERS */
+#include "../dispatch/vector_nvic.c"
+
+/* Symbols exported by the linker script(s): */
+extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
+typedef void (*funcp_t) (void);
+extern funcp_t __preinit_array_start, __preinit_array_end;
+extern funcp_t __init_array_start, __init_array_end;
+extern funcp_t __fini_array_start, __fini_array_end;
+
+void main(void);
+void blocking_handler(void);
+void null_handler(void);
+
+__attribute__ ((section(".vectors")))
+vector_table_t vector_table = {
+ .initial_sp_value = &_stack,
+ .reset = reset_handler,
+ .nmi = nmi_handler,
+ .hard_fault = hard_fault_handler,
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+ .memory_manage_fault = mem_manage_handler,
+ .bus_fault = bus_fault_handler,
+ .usage_fault = usage_fault_handler,
+ .debug_monitor = debug_monitor_handler,
+#endif
+
+ .sv_call = sv_call_handler,
+ .pend_sv = pend_sv_handler,
+ .systick = sys_tick_handler,
+ .irq = {
+ IRQ_HANDLERS
+ }
+};
+
+void WEAK __attribute__ ((naked)) reset_handler(void)
+{
+ volatile unsigned *src, *dest;
+ funcp_t *fp;
+
+ for (src = &_data_loadaddr, dest = &_data;
+ dest < &_edata;
+ src++, dest++) {
+ *dest = *src;
+ }
+
+ while (dest < &_ebss) {
+ *dest++ = 0;
+ }
+
+ /* Constructors. */
+ for (fp = &__preinit_array_start; fp < &__preinit_array_end; fp++) {
+ (*fp)();
+ }
+ for (fp = &__init_array_start; fp < &__init_array_end; fp++) {
+ (*fp)();
+ }
+
+ /* might be provided by platform specific vector.c */
+ pre_main();
+
+ /* Call the application's entry point. */
+ main();
+
+ /* Destructors. */
+ for (fp = &__fini_array_start; fp < &__fini_array_end; fp++) {
+ (*fp)();
+ }
+
+}
+
+void blocking_handler(void)
+{
+ while (1);
+}
+
+void null_handler(void)
+{
+ /* Do nothing. */
+}
+
+#pragma weak nmi_handler = null_handler
+#pragma weak hard_fault_handler = blocking_handler
+#pragma weak sv_call_handler = null_handler
+#pragma weak pend_sv_handler = null_handler
+#pragma weak sys_tick_handler = null_handler
+
+/* Those are defined only on CM3 or CM4 */
+#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
+#pragma weak mem_manage_handler = blocking_handler
+#pragma weak bus_fault_handler = blocking_handler
+#pragma weak usage_fault_handler = blocking_handler
+#pragma weak debug_monitor_handler = null_handler
+#endif
+
diff --git a/libopencm3/lib/dispatch/vector_chipset.c b/libopencm3/lib/dispatch/vector_chipset.c
new file mode 100644
index 0000000..c491c2f
--- /dev/null
+++ b/libopencm3/lib/dispatch/vector_chipset.c
@@ -0,0 +1,12 @@
+#if defined(STM32F3)
+# include "../stm32/f3/vector_chipset.c"
+#elif defined(STM32F4)
+# include "../stm32/f4/vector_chipset.c"
+#elif defined(LPC43XX_M4)
+# include "../lpc43xx/m4/vector_chipset.c"
+
+#else
+
+static void pre_main(void) {}
+
+#endif
diff --git a/libopencm3/lib/efm32/efm32g/Makefile b/libopencm3/lib/efm32/efm32g/Makefile
new file mode 100644
index 0000000..7a644b2
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32g/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_efm32g
+SRCLIBDIR ?= ../..
+FAMILY = EFM32G
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -D$(FAMILY)
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS =
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld
new file mode 100644
index 0000000..87d6ee6
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for EFM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld
new file mode 100644
index 0000000..09c6fb0
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32g/libopencm3_efm32g880f128.ld
@@ -0,0 +1,15 @@
+/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from
+ * d0034_efm32tg_reference_manual.pdf figure 5.2.
+ *
+ * the origins and memory structure are constant over all tinygeckos, but the
+ * MEMORY section requires the use of constants, and has thus to be duplicated
+ * over the chip variants.
+ * */
+
+MEMORY
+{
+ rom (rx) : ORIGIN = 0, LENGTH = 128k
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16k
+}
+
+INCLUDE libopencm3_efm32g.ld;
diff --git a/libopencm3/lib/efm32/efm32gg/Makefile b/libopencm3/lib/efm32/efm32gg/Makefile
new file mode 100644
index 0000000..fdfe6e7
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32gg/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_efm32gg
+SRCLIBDIR ?= ../..
+FAMILY = EFM32GG
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -D$(FAMILY)
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS =
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld
new file mode 100644
index 0000000..87d6ee6
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for EFM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld
new file mode 100644
index 0000000..694e17a
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32gg/libopencm3_efm32gg990f1024.ld
@@ -0,0 +1,15 @@
+/* lengths from d046_efm32gg990_datasheet.pdf table 1.1, offset from
+ * d0034_efm32tg_reference_manual.pdf figure 5.2.
+ *
+ * the origins and memory structure are constant over all giantgeckos, but the
+ * MEMORY section requires the use of constants, and has thus to be duplicated
+ * over the chip variants.
+ * */
+
+MEMORY
+{
+ rom (rx) : ORIGIN = 0, LENGTH = 1024k
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128k
+}
+
+INCLUDE libopencm3_efm32gg.ld;
diff --git a/libopencm3/lib/efm32/efm32lg/Makefile b/libopencm3/lib/efm32/efm32lg/Makefile
new file mode 100644
index 0000000..07a8e45
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32lg/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_efm32lg
+SRCLIBDIR ?= ../..
+FAMILY = EFM32LG
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -D$(FAMILY)
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS =
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld b/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld
new file mode 100644
index 0000000..87d6ee6
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32lg/libopencm3_efm32lg.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for EFM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/efm32/efm32tg/Makefile b/libopencm3/lib/efm32/efm32tg/Makefile
new file mode 100644
index 0000000..46de193
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32tg/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_efm32tg
+SRCLIBDIR ?= ../..
+FAMILY = EFM32TG
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -D$(FAMILY)
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS =
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld
new file mode 100644
index 0000000..87d6ee6
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for EFM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld
new file mode 100644
index 0000000..2cb8daf
--- /dev/null
+++ b/libopencm3/lib/efm32/efm32tg/libopencm3_efm32tg840f32.ld
@@ -0,0 +1,15 @@
+/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from
+ * d0034_efm32tg_reference_manual.pdf figure 5.2.
+ *
+ * the origins and memory structure are constant over all tinygeckos, but the
+ * MEMORY section requires the use of constants, and has thus to be duplicated
+ * over the chip variants.
+ * */
+
+MEMORY
+{
+ rom (rx) : ORIGIN = 0, LENGTH = 32k
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4k
+}
+
+INCLUDE libopencm3_efm32tg.ld;
diff --git a/libopencm3/lib/ethernet/mac.c b/libopencm3/lib/ethernet/mac.c
new file mode 100644
index 0000000..3b7db12
--- /dev/null
+++ b/libopencm3/lib/ethernet/mac.c
@@ -0,0 +1,43 @@
+/** @defgroup ethernet_mac_file MAC Generic Drivers
+ *
+ * @ingroup ETH
+ *
+ * @brief <b>Ethernet MAC Generic Drivers</b>
+ *
+ * @version 1.0.0
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * @date 1 September 2013
+ *
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/ethernet/mac.h>
+#include <libopencm3/ethernet/phy.h>
+
+/**@{*/
+
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
diff --git a/libopencm3/lib/ethernet/mac_stm32fxx7.c b/libopencm3/lib/ethernet/mac_stm32fxx7.c
new file mode 100644
index 0000000..16f76a8
--- /dev/null
+++ b/libopencm3/lib/ethernet/mac_stm32fxx7.c
@@ -0,0 +1,378 @@
+/** @defgroup ethernet_mac_stm32fxx7_file MAC STM32Fxx7
+ *
+ * @ingroup ETH
+ *
+ * @brief <b>Ethernet MAC STM32Fxx7 Drivers</b>
+ *
+ * @version 1.0.0
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * @date 1 September 2013
+ *
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/ethernet/mac.h>
+#include <libopencm3/ethernet/phy.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/cm3/nvic.h>
+
+/**@{*/
+
+uint32_t TxBD;
+uint32_t RxBD;
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set MAC to the PHY
+ *
+ * @param[in] mac uint8_t* Desired MAC
+ */
+void eth_set_mac(uint8_t *mac)
+{
+ ETH_MACAHR(0) = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4] |
+ ETH_MACA0HR_MACA0H;
+ ETH_MACALR(0) = ((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) |
+ ((uint32_t)mac[1] << 8) | mac[0];
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Initialize descriptors
+ *
+ * @param[in] buf uint8_t* Buffer for the descriptors
+ * @param[in] nTx uint32_t Count of Transmit Descriptors
+ * @param[in] nRx uint32_t Count of Receive Descriptors
+ * @param[in] cTx uint32_t Bytes in each Transmit Descriptor
+ * @param[in] cRx uint32_t Bytes in each Receive Descriptor
+ * @param[in] isext bool true, if extended descriptors should be used
+ */
+void eth_desc_init(uint8_t *buf, uint32_t nTx, uint32_t nRx, uint32_t cTx,
+ uint32_t cRx, bool isext)
+{
+ memset(buf, 0, nTx * cTx + nRx * cRx);
+
+ uint32_t bd = (uint32_t)buf;
+ uint32_t sz = isext ? ETH_DES_EXT_SIZE : ETH_DES_STD_SIZE;
+
+ /* enable / disable extended frames */
+ if (isext) {
+ ETH_DMABMR |= ETH_DMABMR_EDFE;
+ } else {
+ ETH_DMABMR &= ~ETH_DMABMR_EDFE;
+ }
+
+ TxBD = bd;
+ while (--nTx > 0) {
+ ETH_DES0(bd) = ETH_TDES0_TCH;
+ ETH_DES2(bd) = bd + sz;
+ ETH_DES3(bd) = bd + sz + cTx;
+ bd = ETH_DES3(bd);
+ }
+
+ ETH_DES0(bd) = ETH_TDES0_TCH;
+ ETH_DES2(bd) = bd + sz;
+ ETH_DES3(bd) = TxBD;
+ bd += sz + cTx;
+
+ RxBD = bd;
+ while (--nRx > 0) {
+ ETH_DES0(bd) = ETH_RDES0_OWN;
+ ETH_DES1(bd) = ETH_RDES1_RCH | cRx;
+ ETH_DES2(bd) = bd + sz;
+ ETH_DES3(bd) = bd + sz + cRx;
+ bd = ETH_DES3(bd);
+ }
+
+ ETH_DES0(bd) = ETH_RDES0_OWN;
+ ETH_DES1(bd) = ETH_RDES1_RCH | cRx;
+ ETH_DES2(bd) = bd + sz;
+ ETH_DES3(bd) = RxBD;
+
+ ETH_DMARDLAR = (uint32_t) RxBD;
+ ETH_DMATDLAR = (uint32_t) TxBD;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Transmit packet
+ *
+ * @param[in] ppkt uint8_t* Pointer to the beginning of the packet
+ * @param[in] n uint32_t Size of the packet
+ * @returns bool true, if success
+ */
+bool eth_tx(uint8_t *ppkt, uint32_t n)
+{
+ if (ETH_DES0(TxBD) & ETH_TDES0_OWN) {
+ return false;
+ }
+
+ memcpy((void *)ETH_DES2(TxBD), ppkt, n);
+
+ ETH_DES1(TxBD) = n & ETH_TDES1_TBS1;
+ ETH_DES0(TxBD) |= ETH_TDES0_LS | ETH_TDES0_FS | ETH_TDES0_OWN;
+ TxBD = ETH_DES3(TxBD);
+
+ if (ETH_DMASR & ETH_DMASR_TBUS) {
+ ETH_DMASR = ETH_DMASR_TBUS;
+ ETH_DMATPDR = 0;
+ }
+
+ return true;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Receive packet
+ *
+ * @param[inout] ppkt uint8_t* Pointer to the data buffer where to store data
+ * @param[inout] len uint32_t* Pointer to the variable with the packet length
+ * @param[in] maxlen uint32_t Maximum length of the packet
+ * @returns bool true, if the buffer contains readed packet data
+ */
+bool eth_rx(uint8_t *ppkt, uint32_t *len, uint32_t maxlen)
+{
+ bool fs = false;
+ bool ls = false;
+ bool overrun = false;
+ uint32_t l = 0;
+
+ while (!(ETH_DES0(RxBD) & ETH_RDES0_OWN) && !ls) {
+ l = (ETH_DES0(RxBD) & ETH_RDES0_FL) >> ETH_RDES0_FL_SHIFT;
+
+ fs |= ETH_DES0(RxBD) & ETH_RDES0_FS;
+ ls |= ETH_DES0(RxBD) & ETH_RDES0_LS;
+ /* frame buffer overrun ?*/
+ overrun |= fs && (maxlen < l);
+
+ if (fs && !overrun) {
+ memcpy(ppkt, (void *)ETH_DES2(RxBD), l);
+ ppkt += l;
+ *len += l;
+ maxlen -= l;
+ }
+
+ ETH_DES0(RxBD) = ETH_RDES0_OWN;
+ RxBD = ETH_DES3(RxBD);
+ }
+
+ if (ETH_DMASR & ETH_DMASR_RBUS) {
+ ETH_DMASR = ETH_DMASR_RBUS;
+ ETH_DMARPDR = 0;
+ }
+
+ return fs && ls && !overrun;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Start the Ethernet DMA processing
+ */
+void eth_start(void)
+{
+ ETH_MACCR |= ETH_MACCR_TE;
+ ETH_DMAOMR |= ETH_DMAOMR_FTF;
+ ETH_MACCR |= ETH_MACCR_RE;
+
+ ETH_DMAOMR |= ETH_DMAOMR_ST;
+ ETH_DMAOMR |= ETH_DMAOMR_SR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Initialize ethernet
+ *
+ * This function will initialize ethernet, set up clocks, and initialize DMA.
+ *
+ * @param[in] clock enum eth_clk Core clock speed
+ */
+void eth_init(enum eth_clk clock)
+{
+ ETH_MACMIIAR = clock;
+ phy_reset();
+
+ ETH_MACCR = ETH_MACCR_CSTF | ETH_MACCR_FES | ETH_MACCR_DM |
+ ETH_MACCR_APCS | ETH_MACCR_RD;
+ ETH_MACFFR = ETH_MACFFR_RA | ETH_MACFFR_PM;
+ ETH_MACHTHR = 0; /* pass all frames */
+ ETH_MACHTLR = 0;
+ ETH_MACFCR = (0x100 << ETH_MACFCR_PT_SHIFT);
+ ETH_MACVLANTR = 0;
+ ETH_DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_DFRF |
+ ETH_DMAOMR_TSF | ETH_DMAOMR_FEF | ETH_DMAOMR_OSF;
+ ETH_DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_FB |
+ (32 << ETH_DMABMR_RDP_SHIFT) | (32 << ETH_DMABMR_PBL_SHIFT) |
+ ETH_DMABMR_PM_2_1 | ETH_DMABMR_USP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Ethernet IRQ
+ *
+ * @param[in] reason uint32_t Which irq will be enabled
+ */
+void eth_irq_enable(uint32_t reason)
+{
+ ETH_DMAIER |= reason;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the Ethernet IRQ
+ *
+ * @param[in] reason uint32_t Which irq will be disabled
+ */
+void eth_irq_disable(uint32_t reason)
+{
+ ETH_DMAIER &= ~reason;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Check if IRQ is pending
+ *
+ * @param[in] reason uint32_t Which irq type has to be tested
+ * @returns bool true, if IRQ is pending
+ */
+bool eth_irq_is_pending(uint32_t reason)
+{
+ return (ETH_DMASR & reason) != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Check if IRQ is pending, and acknowledge it
+ *
+ * @param[in] reason uint32_t Which irq type has to be tested
+ * @returns bool true, if IRQ is pending
+ */
+bool eth_irq_ack_pending(uint32_t reason)
+{
+ reason &= ETH_DMASR;
+ ETH_DMASR = reason;
+ return reason != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable checksum offload feature
+ *
+ * This function will enable the Checksum offload feature for all of the
+ * transmit descriptors. Note to use this feature, descriptors must be in
+ * extended format.
+ */
+void eth_enable_checksum_offload(void)
+{
+ uint32_t tab = TxBD;
+ do {
+ ETH_DES0(tab) |= ETH_TDES0_CIC_IPPLPH;
+ tab = ETH_DES3(tab);
+ }
+ while (tab != TxBD);
+
+ ETH_MACCR |= ETH_MACCR_IPCO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Process pending SMI transaction and wait to be done.
+ */
+static void eth_smi_transact(void)
+{
+ /* Begin transaction. */
+ ETH_MACMIIAR |= ETH_MACMIIAR_MB;
+
+ /* Wait for not busy. */
+ while (ETH_MACMIIAR & ETH_MACMIIAR_MB);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Write 16-bit register to the PHY
+ *
+ * @param[in] phy uint8_t ID of the PHY (defaults to 1)
+ * @param[in] reg uint8_t Register address
+ * @param[in] data uint16_t Data to write
+ */
+void eth_smi_write(uint8_t phy, uint8_t reg, uint16_t data)
+{
+ /* Write operation MW=1*/
+ ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */
+ (phy << ETH_MACMIIAR_PA_SHIFT) |
+ (reg << ETH_MACMIIAR_MR_SHIFT) |
+ ETH_MACMIIAR_MW;
+
+ ETH_MACMIIDR = data & ETH_MACMIIDR_MD;
+
+ eth_smi_transact();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read the 16-bit register from the PHY
+ *
+ * @param[in] phy uint8_t ID of the PHY (defaults to 1)
+ * @param[in] reg uint8_t Register address
+ * @returns uint16_t Readed data
+ */
+uint16_t eth_smi_read(uint8_t phy, uint8_t reg)
+{
+ /* Read operation MW=0*/
+ ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */
+ (phy << ETH_MACMIIAR_PA_SHIFT) |
+ (reg << ETH_MACMIIAR_MR_SHIFT);
+
+ eth_smi_transact();
+
+ return (uint16_t)(ETH_MACMIIDR & ETH_MACMIIDR_MD);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Process the bit-operation on PHY register
+ *
+ * @param[in] phy uint8_t ID of the PHY (defaults to 1)
+ * @param[in] reg uint8_t Register address
+ * @param[in] bits uint16_t Bits that have to be set (or'ed)
+ * @param[in] mask uint16_t Bits that have to be clear (and'ed)
+ */
+void eth_smi_bit_op(uint8_t phy, uint8_t reg, uint16_t bits, uint16_t mask)
+{
+ uint16_t val = eth_smi_read(phy, reg);
+ eth_smi_write(phy, reg, (val & mask) | bits);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear bits in the register
+ *
+ * @param[in] phy uint8_t ID of the PHY (defaults to 1)
+ * @param[in] reg uint8_t Register address
+ * @param[in] clearbits uint16_t Bits that have to be cleared
+ */
+void eth_smi_bit_clear(uint8_t phy, uint8_t reg, uint16_t clearbits)
+{
+ uint16_t val = eth_smi_read(phy, reg);
+ eth_smi_write(phy, reg, val & (uint16_t)~(clearbits));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set bits in the register
+ *
+ * @param[in] phy uint8_t ID of the PHY (defaults to 1)
+ * @param[in] reg uint8_t Register address
+ * @param[in] bits uint16_t Bits that have to be set (or'ed)
+ */
+void eth_smi_bit_set(uint8_t phy, uint8_t reg, uint16_t setbits)
+{
+ uint16_t val = eth_smi_read(phy, reg);
+ eth_smi_write(phy, reg, val | setbits);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
diff --git a/libopencm3/lib/ethernet/phy.c b/libopencm3/lib/ethernet/phy.c
new file mode 100644
index 0000000..4866198
--- /dev/null
+++ b/libopencm3/lib/ethernet/phy.c
@@ -0,0 +1,64 @@
+/** @defgroup ethernet_phy_file PHY Generic Drivers
+ *
+ * @ingroup ETH
+ *
+ * @brief <b>Ethernet PHY Generic Drivers</b>
+ *
+ * @version 1.0.0
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * @date 1 September 2013
+ *
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/ethernet/mac.h>
+#include <libopencm3/ethernet/phy.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Is the link up ?
+ *
+ * @returns bool true, if link is up
+ */
+bool phy_link_isup(void)
+{
+ return eth_smi_read(1, PHY_REG_BSR) & PHY_REG_BSR_UP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset the PHY
+ *
+ * Reset the PHY chip and wait for done
+ */
+void phy_reset(void)
+{
+ eth_smi_write(1, PHY_REG_BCR, PHY_REG_BCR_RESET);
+
+ while (eth_smi_read(1, PHY_REG_BCR) & PHY_REG_BCR_RESET);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
diff --git a/libopencm3/lib/ethernet/phy_ksz8051mll.c b/libopencm3/lib/ethernet/phy_ksz8051mll.c
new file mode 100644
index 0000000..1faae4f
--- /dev/null
+++ b/libopencm3/lib/ethernet/phy_ksz8051mll.c
@@ -0,0 +1,89 @@
+/** @defgroup ethernet_phy_ksz8051mll_file PHY KSZ8051MLL
+ *
+ * @ingroup ETH
+ *
+ * @brief <b>Ethernet PHY STM32Fxx7 Drivers</b>
+ *
+ * @version 1.0.0
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * @date 1 September 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/ethernet/mac.h>
+#include <libopencm3/ethernet/phy.h>
+#include <libopencm3/ethernet/phy_ksz8051mll.h>
+
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get the current link status
+ *
+ * Retrieve the link speed and duplex status of the link.
+ *
+ * @returns ::phy_status Link status
+ */
+enum phy_status phy_link_status(void)
+{
+ return eth_smi_read(1, PHY_REG_CR1) & 0x07;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Force autonegotiation
+ *
+ * Force the autonegotiation and set link speed and duplex mode of the link
+ *
+ * @param[in] mode enum phy_status Desired link status
+ */
+void phy_autoneg_force(enum phy_status mode)
+{
+ uint16_t bst = 0;
+
+ if ((mode == LINK_FD_10M) || (mode == LINK_FD_100M) ||
+ (mode == LINK_FD_1000M) || (mode == LINK_FD_10000M)) {
+ bst |= PHY_REG_BCR_FD;
+ }
+
+ if ((mode == LINK_FD_100M) || (mode == LINK_FD_100M)) {
+ bst |= PHY_REG_BCR_100M;
+ }
+
+ eth_smi_bit_op(1, PHY_REG_BCR, bst,
+ ~(PHY_REG_BCR_AN | PHY_REG_BCR_100M | PHY_REG_BCR_FD));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the autonegotiation
+ *
+ * Enable the autonegotiation of the link speed and duplex mode
+ */
+void phy_autoneg_enable(void)
+{
+ eth_smi_bit_set(1, PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
diff --git a/libopencm3/lib/lm3s/Makefile b/libopencm3/lib/lm3s/Makefile
new file mode 100644
index 0000000..353183d
--- /dev/null
+++ b/libopencm3/lib/lm3s/Makefile
@@ -0,0 +1,40 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lm3s
+SRCLIBDIR ?= ..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DLM3S
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o vector.o assert.o
+
+VPATH += ../cm3
+
+include ../Makefile.include
diff --git a/libopencm3/lib/lm3s/gpio.c b/libopencm3/lib/lm3s/gpio.c
new file mode 100644
index 0000000..e0dd264
--- /dev/null
+++ b/libopencm3/lib/lm3s/gpio.c
@@ -0,0 +1,52 @@
+/** @defgroup gpio_file General Purpose I/O
+
+@brief <b>LM3S General Purpose I/O</b>
+
+@ingroup LM3Sxx
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2011
+Gareth McMullin <gareth@blacksphere.co.nz>
+
+@date 10 March 2013
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/lm3s/gpio.h>
+
+void gpio_set(uint32_t gpioport, uint8_t gpios)
+{
+ /* ipaddr[9:2] mask the bits to be set, hence the array index */
+ GPIO_DATA(gpioport)[gpios] = 0xff;
+}
+
+void gpio_clear(uint32_t gpioport, uint8_t gpios)
+{
+ GPIO_DATA(gpioport)[gpios] = 0;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/lm3s/libopencm3_lm3s.ld b/libopencm3/lib/lm3s/libopencm3_lm3s.ld
new file mode 100644
index 0000000..6c8c7f2
--- /dev/null
+++ b/libopencm3/lib/lm3s/libopencm3_lm3s.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LM3S targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/lm4f/Makefile b/libopencm3/lib/lm4f/Makefile
new file mode 100644
index 0000000..6b83b0f
--- /dev/null
+++ b/libopencm3/lib/lm4f/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lm4f
+SRCLIBDIR ?= ..
+
+FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../include -fno-common \
+ -mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DLM4F
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o vector.o assert.o systemcontrol.o rcc.o uart.o \
+ usb_lm4f.o usb.o usb_control.o usb_standard.o
+
+VPATH += ../usb:../cm3
+
+include ../Makefile.include
diff --git a/libopencm3/lib/lm4f/gpio.c b/libopencm3/lib/lm4f/gpio.c
new file mode 100644
index 0000000..22399bd
--- /dev/null
+++ b/libopencm3/lib/lm4f/gpio.c
@@ -0,0 +1,598 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @defgroup gpio_file GPIO
+ *
+ *
+ * @ingroup LM4Fxx
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2011
+ * Gareth McMullin <gareth@blacksphere.co.nz>
+ * @author @htmlonly &copy; @endhtmlonly 2013
+ * Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * @date 16 March 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ *
+ * @brief <b>libopencm3 LM4F General Purpose I/O</b>
+ *
+ * The LM4F GPIO API provides functionality for accessing the GPIO pins of the
+ * LM4F.
+ *
+ * @attention @code An important aspect to consider is that libopencm3 uses the
+ * AHB aperture for accessing the GPIO registers on the LM4F. The AHB must be
+ * explicitly enabled with a call to gpio_enable_ahb_aperture() before accessing
+ * any GPIO functionality.
+ * @endcode
+ *
+ * Please see the individual GPIO modules for more details. To use the GPIO, the
+ * gpio.h header needs to be included:
+ * @code{.c}
+ * #include <libopencm3/lm4f/gpio.h>
+ * @endcode
+ */
+
+/**@{*/
+
+#include <libopencm3/lm4f/gpio.h>
+#include <libopencm3/lm4f/systemcontrol.h>
+
+/* Value we need to write to unlock the GPIO commit register */
+#define GPIO_LOCK_UNLOCK_CODE 0x4C4F434B
+
+
+/** @defgroup gpio_config GPIO pin configuration
+ * @ingroup gpio_file
+ *
+ * \brief <b>Enabling and configuring GPIO pins</b>
+ *
+ * @section gpio_api_enable Enabling GPIO ports
+ * @attention
+ * Before accessing GPIO functionality through this API, the AHB aperture for
+ * GPIO ports must be enabled via a call to @ref gpio_enable_ahb_aperture().
+ * Failing to do so will cause a hard fault.
+ *
+ * @note
+ * Once the AHB aperture is enabled, GPIO registers can no longer be accessed
+ * via the APB aperture. The two apertures are mutually exclusive.
+ *
+ * Enabling the AHB aperture only needs to be done once. However, in order to
+ * access a certain GPIO port, its clock must also be enabled. Enabling the
+ * GPIO clock needs to be done for every port that will be used.
+ *
+ * For example, to enable GPIOA and GPIOD:
+ * @code{.c}
+ * // Make sure we can access the GPIO via the AHB aperture
+ * gpio_enable_ahb_aperture();
+ * ...
+ * // Enable GPIO ports A and D
+ * periph_clock_enable(RCC_GPIOA);
+ * periph_clock_enable(RCC_GPIOD);
+ * @endcode
+ *
+ * On reset all ports are configured as digital floating inputs (no pull-up or
+ * pull-down), except for special function pins.
+ *
+ *
+ * @section gpio_api_in Configuring pins as inputs
+ *
+ * Configuring GPIO pins as inputs is done with @ref gpio_mode_setup(), with
+ * @ref GPIO_MODE_INPUT for the mode parameter. The direction of the pull-up
+ * must be specified with the same call
+ *
+ * For example, PA2, PA3, and PA4 as inputs, with pull-up on PA4:
+ * @code{.c}
+ * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2 | GPIO3);
+ * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO4);
+ * @endcode
+ *
+ *
+ * @section gpio_api_out Configuring pins as outputs
+ *
+ * Output pins have more configuration options than input pins. LM4F pins can be
+ * configured as either push-pull, or open drain. The drive strength of each pin
+ * can be adjusted between 2mA, 4mA, or 8mA. Slew-rate control is available when
+ * the pins are configured to drive 8mA. These extra options can be specified
+ * with @ref gpio_set_output_config().
+ * The default is push-pull configuration with 2mA drive capability.
+ *
+ * @note
+ * @ref gpio_set_output_config() controls different capabilities than the
+ * similar sounding gpio_set_output_options() from the STM GPIO API. They are
+ * intentionally named differently to prevent confusion between the two. They
+ * are API incompatible.
+ *
+ * For example, to set PA2 to output push-pull with a drive strength of 8mA:
+ * @code{.c}
+ * gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2);
+ * gpio_set_output_config(GPIOA, GPIO_OTYPE_PP, GPIO_DRIVE_8MA, GPIO2);
+ * @endcode
+ *
+ *
+ * @section gpio_api_analog Configuring pins as analog function
+ *
+ * Configuring GPIO pins to their analog function is done with
+ * @ref gpio_mode_setup(), with @ref GPIO_MODE_ANALOG for the mode parameter.
+ *
+ * Suppose PD4 and PD5 are the USB pins. To enable their analog functionality
+ * (USB D+ and D- in this case), use:
+ * @code
+ * // Mux USB pins to their analog function
+ * gpio_mode_setup(GPIOD, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4 | GPIO5);
+ * @endcode
+ *
+ * @section gpio_api_alf_func Configuring pins as alternate functions
+ *
+ * Most pins have alternate functions associated with them. When a pin is set to
+ * an alternate function, it is multiplexed to one of the dedicated hardware
+ * peripheral in the chip. The alternate function mapping can be found in the
+ * part's datasheet, and usually varies between arts of the same family.
+ *
+ * Multiplexing a pin, or group of pins to an alternate function is done with
+ * @ref gpio_set_af(). Because AF0 is not used on the LM4F, passing 0 as the
+ * alt_func_num parameter will disable the alternate function of the given pins.
+ *
+ * @code
+ * // Mux PB0 and PB1 to AF1 (UART1 TX/RX in this case)
+ * gpio_set_af(GPIOB, 1, GPIO0 | GPIO1);
+ * @endcode
+ *
+ * @section gpio_api_sfpins Changing configuration of special function pins
+ *
+ * On the LM4F, the NMI and JTAG/SWD default to their alternate function. These
+ * pins cannot normally be committed to GPIO usage. To enable these special
+ * function pins to be used as GPIO, they must be unlocked. This may be achieved
+ * via @ref gpio_unlock_commit. Once a special function pin is unlocked, its
+ * settings may be altered in the usual way.
+ *
+ * For example, to unlock the PF0 pin (NMI on the LM4F120):
+ * @code
+ * // PF0 is an NMI pin, and needs to be unlocked
+ * gpio_unlock_commit(GPIOF, GPIO0);
+ * // Now the pin can be configured
+ * gpio_mode_setup(RGB_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, btnpins);
+ * @endcode
+ */
+/**@{*/
+
+/**
+ * \brief Enable access to GPIO registers via the AHB aperture
+ *
+ * All GPIO registers are accessed in libopencm3 via the AHB aperture. It
+ * provides faster control over the older APB aperture. This aperture must be
+ * enabled before calling any other gpio_*() function.
+ *
+ */
+void gpio_enable_ahb_aperture(void)
+{
+ SYSCTL_GPIOHBCTL = 0xffffffff;
+}
+
+/**
+ * \brief Configure a group of pins
+ *
+ * Sets the Pin direction, analog/digital mode, and pull-up configuration of
+ * or a set of GPIO pins on a given GPIO port.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] mode Pin mode (@ref gpio_mode) \n
+ * - GPIO_MODE_OUTPUT -- Configure pin as output \n
+ * - GPIO_MODE_INPUT -- Configure pin as input \n
+ * - GPIO_MODE_ANALOG -- Configure pin as analog function
+ * @param[in] pullup Pin pullup/pulldown configuration (@ref gpio_pullup) \n
+ * - GPIO_PUPD_NONE -- Do not pull the pin high or low \n
+ * - GPIO_PUPD_PULLUP -- Pull the pin high \n
+ * - GPIO_PUPD_PULLDOWN -- Pull the pin low
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together
+ */
+void gpio_mode_setup(uint32_t gpioport, enum gpio_mode mode,
+ enum gpio_pullup pullup, uint8_t gpios)
+{
+ switch (mode) {
+ case GPIO_MODE_OUTPUT:
+ GPIO_DIR(gpioport) |= gpios;
+ GPIO_DEN(gpioport) |= gpios;
+ GPIO_AMSEL(gpioport) &= ~gpios;
+ break;
+ case GPIO_MODE_INPUT:
+ GPIO_DIR(gpioport) &= ~gpios;
+ GPIO_DEN(gpioport) |= gpios;
+ GPIO_AMSEL(gpioport) &= ~gpios;
+ break;
+ case GPIO_MODE_ANALOG:
+ GPIO_DEN(gpioport) &= ~gpios;
+ GPIO_AMSEL(gpioport) |= gpios;
+ break;
+ default:
+ /* Don't do anything */
+ break;
+ }
+
+ /*
+ * Setting a bit in the GPIO_PDR register clears the corresponding bit
+ * in the GPIO_PUR register, and vice-versa.
+ */
+ switch (pullup) {
+ case GPIO_PUPD_PULLUP:
+ GPIO_PUR(gpioport) |= gpios;
+ break;
+ case GPIO_PUPD_PULLDOWN:
+ GPIO_PDR(gpioport) |= gpios;
+ break;
+ case GPIO_PUPD_NONE: /* Fall through */
+ default:
+ GPIO_PUR(gpioport) &= ~gpios;
+ GPIO_PDR(gpioport) &= ~gpios;
+ break;
+ }
+}
+
+/**
+ * \brief Configure output parameters of a group of pins
+ *
+ * Sets the output configuration and drive strength, of or a set of GPIO pins
+ * for a set of GPIO pins in output mode.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] otype Output driver configuration (@ref gpio_output_type) \n
+ * - GPIO_OTYPE_PP -- Configure pin driver as push-pull \n
+ * - GPIO_OTYPE_OD -- Configure pin driver as open drain
+ * @param[in] drive Pin drive strength (@ref gpio_drive_strength) \n
+ * - GPIO_DRIVE_2MA -- 2mA drive \n
+ * - GPIO_DRIVE_4MA -- 4mA drive \n
+ * - GPIO_DRIVE_8MA -- 8mA drive \n
+ * - GPIO_DRIVE_8MA_SLEW_CTL -- 8mA drive with slew rate
+ * control
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together
+ */
+void gpio_set_output_config(uint32_t gpioport, enum gpio_output_type otype,
+ enum gpio_drive_strength drive, uint8_t gpios)
+{
+ if (otype == GPIO_OTYPE_OD) {
+ GPIO_ODR(gpioport) |= gpios;
+ } else {
+ GPIO_ODR(gpioport) &= ~gpios;
+ }
+
+ /*
+ * Setting a bit in the GPIO_DRxR register clears the corresponding bit
+ * in the other GPIO_DRyR registers, and vice-versa.
+ */
+ switch (drive) {
+ case GPIO_DRIVE_8MA_SLEW_CTL:
+ GPIO_DR8R(gpioport) |= gpios;
+ GPIO_SLR(gpioport) |= gpios;
+ break;
+ case GPIO_DRIVE_8MA:
+ GPIO_DR8R(gpioport) |= gpios;
+ GPIO_SLR(gpioport) &= ~gpios;
+ break;
+ case GPIO_DRIVE_4MA:
+ GPIO_DR4R(gpioport) |= gpios;
+ break;
+ case GPIO_DRIVE_2MA: /* Fall through */
+ default:
+ GPIO_DR2R(gpioport) |= gpios;
+ break;
+ }
+}
+
+#define PCTL_AF(pin, af) (af << (pin << 2))
+#define PCTL_MASK(pin) PCTL_AF(pin, 0xf)
+/**
+ * \brief Multiplex group of pins to the given alternate function
+ *
+ * Mux the pin or group of pins to the given alternate function. Note that a
+ * number of pins may be set but only with a single AF number. This is useful
+ * when one or more of a peripheral's pins are assigned to the same alternate
+ * function.
+ *
+ * Because AF0 is not used on the LM4F, passing 0 as the alt_func_num parameter
+ * will disable the alternate function of the given pins.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] alt_func_num Pin alternate function number or 0 to disable the
+ * alternate function multiplexing.
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together
+ */
+void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint8_t gpios)
+{
+ uint32_t pctl32;
+ uint8_t pin_mask;
+ int i;
+
+ /* Did we mean to disable the alternate function? */
+ if (alt_func_num == 0) {
+ GPIO_AFSEL(gpioport) &= ~gpios;
+ return;
+ }
+
+ /* Enable the alternate function */
+ GPIO_AFSEL(gpioport) |= gpios;
+ /* Alternate functions are digital */
+ GPIO_DEN(gpioport) |= gpios;
+
+ /* Now take care of the actual multiplexing */
+ pctl32 = GPIO_PCTL(gpioport);
+ for (i = 0; i < 8; i++) {
+ pin_mask = (1 << i);
+
+ if (!(gpios & pin_mask)) {
+ continue;
+ }
+
+ pctl32 &= ~PCTL_MASK(i);
+ pctl32 |= PCTL_AF(i, (alt_func_num & 0xf));
+ }
+
+ GPIO_PCTL(gpioport) = pctl32;
+}
+
+/**
+ * \brief Unlock the commit control of a special function pin
+ *
+ * Unlocks the commit control of the given pin or group of pins. If a pin is a
+ * JTAG/SWD or NMI, the pin may then be reconfigured as a GPIO pin. If the pin
+ * is not locked by default, this has no effect.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together.
+ */
+void gpio_unlock_commit(uint32_t gpioport, uint8_t gpios)
+{
+ /* Unlock the GPIO_CR register */
+ GPIO_LOCK(gpioport) = GPIO_LOCK_UNLOCK_CODE;
+ /* Enable committing changes */
+ GPIO_CR(gpioport) |= gpios;
+ /* Lock the GPIO_CR register */
+ GPIO_LOCK(gpioport) = ~GPIO_LOCK_UNLOCK_CODE;
+}
+/**@}*/
+
+/** @defgroup gpio_control GPIO pin control
+ * @ingroup gpio_file
+ *
+ * \brief <b>Controlling GPIO pins</b>
+ *
+ * Each I/O port has 8 individually configurable bits. When reading and writing
+ * data to the GPIO ports, address bits [9:2] mask the pins to be read or
+ * written. This mechanism makes all GPIO port reads and writes on the LM4F
+ * atomic operations. The GPIO API takes full advantage of this fact to preserve
+ * the atomicity of these operations.
+ *
+ * Setting or clearing a group of bits can be accomplished with @ref gpio_set()
+ * and @ref gpio_clear() respectively. These operation use the masking mechanism
+ * described above to only affect the specified pins.
+ *
+ * Sometimes it is more appropriate to read or set the level of a group of pins
+ * on a port, in one atomic operation. Reading the status can be accomplished
+ * with @ref gpio_read(). The result is equivalent to reading all the pins, then
+ * masking only the desired pins; however, the masking is done in hardware, and
+ * does not require an extra hardware operation.
+ *
+ * Writing a group of pins can be accomplished with @ref gpio_write(). The mask
+ * ('gpios' parameter) is applied in hardware, and the masked pins are not
+ * affected, regardless of the value of the respective bits written to the GPIO
+ * port.
+ *
+ * Two extra functions are provided, @ref gpio_port_read() and
+ * @ref gpio_port_write(). They are functionally identical to
+ * @ref gpio_read (port, GPIO_ALL) and @ref gpio_write (port, GPIO_ALL, val)
+ * respectively. Hence, they are also atomic.
+ *
+ * GPIO pins may be toggled with @ref gpio_toggle(). This function does not
+ * translate to an atomic operation.
+ *
+ * @note
+ * The @ref gpio_toggle() operation is the only GPIO port operation which is not
+ * atomic. It involves a read-modify-write cycle.
+ *
+ * Suppose PA0, PA1, PA2, and PA3 are to be modified without affecting the other
+ * pins on port A. This is common when controlling, for example, a 4-bit bus:
+ * @code{.c}
+ * // Pins 4,5,6, and 7 are unaffected, regardless of the bits in val
+ * gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val);
+ * // Wait a bit then send the other 4 bits
+ * wait_a_bit();
+ * gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val >> 4);
+ * @endcode
+ *
+ * Suppose a LED is connected to PD4, and we want to flash the LED for a brief
+ * period of time:
+ * @code
+ * gpio_set(GPIOD, GPIO4);
+ * wait_a_bit();
+ * gpio_set(GPIOD, GPIO4);
+ * @endcode
+ */
+/**@{*/
+/**
+ * \brief Toggle a Group of Pins
+ *
+ * Toggle one or more pins of the given GPIO port.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios Pin identifiers. @ref gpio_pin_id
+ */
+void gpio_toggle(uint32_t gpioport, uint8_t gpios)
+{
+ /* The mask makes sure we only toggle the GPIOs we want to */
+ GPIO_DATA(gpioport)[gpios] ^= GPIO_ALL;
+}
+/**@}*/
+
+
+/** @defgroup gpio_irq GPIO Interrupt control
+ * @ingroup gpio_file
+ *
+ * \brief <b>Configuring interrupts from GPIO pins</b>
+ *
+ * GPIO pins can trigger interrupts on either edges or levels. The type of
+ * trigger can be configured with @ref gpio_configure_int_trigger(). To have an
+ * event on the given pin generate an interrupt, its interrupt source must be
+ * unmasked. This can be achieved with @ref gpio_enable_interrupts(). Interrupts
+ * which are no longer needed can be disabled through
+ * @ref gpio_disable_interrupts().
+ *
+ * In order for the interrupt to generate an IRQ and a call to the interrupt
+ * service routine, the interrupt for the GPIO port must be routed through the
+ * NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
+ * needed:
+ * @code{.c}
+ * #include <libopencm3/lm4f/nvic.h>
+ * @endcode
+ *
+ * Enabling an interrupt is as simple as configuring the desired trigger,
+ * unmasking the desired interrupt, and routing the desired GPIO port's
+ * interrupt through the NVIC.
+ * @code{.c}
+ * // Trigger interrupt on each rising edge
+ * gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, GPIO0 | GPIO4);
+ * // Unmask the interrupt on those pins
+ * gpio_enable_interrupts(GPIOF, GPIO0 | GPIO4);
+ * // Enable the interrupt in the NVIC as well
+ * nvic_enable_irq(NVIC_GPIOF_IRQ);
+ * @endcode
+ *
+ * After interrupts are properly enabled and routed through the NVIC, when an
+ * event occurs, the appropriate IRQ flag is set by hardware, and execution
+ * jumps to the GPIO ISR. The ISR should query the IRQ flags to determine which
+ * event caused the interrupt. For this, use @ref gpio_is_interrupt_source(),
+ * with the desired GPIO flag. After one or more interrupt sources are
+ * serviced, the IRQ flags must be cleared by the ISR. This can be done with
+ * @ref gpio_clear_interrupt_flag().
+ *
+ * A typical GPIO ISR may look like the following:
+ * @code{.c}
+ * void gpiof_isr(void)
+ * {
+ * uint8_t serviced_irqs = 0;
+ *
+ * // Process individual IRQs
+ * if (gpio_is_interrupt_source(GPIOF, GPIO0)) {
+ * process_gpio0_event();
+ * serviced_irq |= GPIO0;
+ * }
+ * if (gpio_is_interrupt_source(GPIOF, GPIO4)) {
+ * process_gpio4_event();
+ * serviced_irq |= GPIO4;
+ * }
+ *
+ * // Clear the interupt flag for the processed IRQs
+ * gpio_clear_interrupt_flag(GPIOF, serviced_irqs);
+ * }
+ * @endcode
+ */
+/**@{*/
+/**
+ * \brief Configure the interrupt trigger on the given GPIO pins
+ *
+ * Sets the Pin direction, analog/digital mode, and pull-up configuration of
+ * or a set of GPIO pins on a given GPIO port.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] trigger Trigger configuration (@ref gpio_trigger) \n
+ * - GPIO_TRIG_LVL_LOW -- Trigger on low level \n
+ * - GPIO_TRIG_LVL_HIGH -- Trigger on high level \n
+ * - GPIO_TRIG_EDGE_FALL -- Trigger on falling edges \n
+ * - GPIO_TRIG_EDGE_RISE -- Trigger on rising edges \n
+ * - GPIO_TRIG_EDGE_BOTH -- Trigger on all edges
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together
+ */
+void gpio_configure_trigger(uint32_t gpioport, enum gpio_trigger trigger,
+ uint8_t gpios)
+{
+ switch (trigger) {
+ case GPIO_TRIG_LVL_LOW:
+ GPIO_IS(gpioport) |= gpios;
+ GPIO_IEV(gpioport) &= ~gpios;
+ break;
+ case GPIO_TRIG_LVL_HIGH:
+ GPIO_IS(gpioport) |= gpios;
+ GPIO_IEV(gpioport) |= gpios;
+ break;
+ case GPIO_TRIG_EDGE_FALL:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) &= ~gpios;
+ GPIO_IEV(gpioport) &= ~gpios;
+ break;
+ case GPIO_TRIG_EDGE_RISE:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) &= ~gpios;
+ GPIO_IEV(gpioport) |= gpios;
+ break;
+ case GPIO_TRIG_EDGE_BOTH:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) |= gpios;
+ break;
+ default:
+ /* Don't do anything */
+ break;
+ }
+}
+
+/**
+ * \brief Enable interrupts on specified GPIO pins
+ *
+ * Enable interrupts on the specified GPIO pins
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to enable. Any
+ * combination of pins may be specified by OR'ing them
+ * together.
+ */
+void gpio_enable_interrupts(uint32_t gpioport, uint8_t gpios)
+{
+ GPIO_IM(gpioport) |= gpios;
+}
+
+/**
+ * \brief Disable interrupts on specified GPIO pins
+ *
+ * Disable interrupts on the specified GPIO pins
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to disable. Any
+ * combination of pins may be specified by OR'ing them
+ * together.
+ */
+void gpio_disable_interrupts(uint32_t gpioport, uint8_t gpios)
+{
+ GPIO_IM(gpioport) |= gpios;
+}
+
+/**@}*/
+
+/**@}*/
+
diff --git a/libopencm3/lib/lm4f/libopencm3_lm4f.ld b/libopencm3/lib/lm4f/libopencm3_lm4f.ld
new file mode 100644
index 0000000..12d939e
--- /dev/null
+++ b/libopencm3/lib/lm4f/libopencm3_lm4f.ld
@@ -0,0 +1,2 @@
+/* Yes, we can simply use the lm3s linker script */
+INCLUDE "libopencm3_lm3s.ld"
diff --git a/libopencm3/lib/lm4f/rcc.c b/libopencm3/lib/lm4f/rcc.c
new file mode 100644
index 0000000..9b051b3
--- /dev/null
+++ b/libopencm3/lib/lm4f/rcc.c
@@ -0,0 +1,499 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * @defgroup rcc_file RCC
+ *
+ * @ingroup LM4Fxx
+ *
+@author @htmlonly &copy; @endhtmlonly 2012
+Alexandru Gagniuc <mr.nuke.me@gmail.com>
+
+ * \brief <b>libopencm3 LM4F Clock control API</b>
+ *
+ * The LM$F clock API provides functionaliity for manipulating the system clock,
+ * oscillator, and PLL. Functions are provided for fine-grained control of clock
+ * control registers, while also providing higher level functionality to easily
+ * configure the main system clock source.
+ *
+ * The following code snippet uses fine-grained mechanisms to configures the
+ * chip to run off an external 16MHz crystal, and use the PLL to derive a clock
+ * frequency of 80MHz.
+ * @code{.c}
+ * // A divisor of 5 gives us a clock of 400/5 = 80MHz
+ * #define PLLDIV_80MHZ 5
+ *
+ * // Enable the main oscillator
+ * rcc_enable_main_osc();
+ *
+ * // Make RCC2 override RCC
+ * rcc_enable_rcc2();
+ *
+ * // Set XTAL value to 16MHz
+ * rcc_configure_xtal(XTAL_16M);
+ * // Set the oscillator source as the main oscillator
+ * rcc_set_osc_source(OSCSRC_MOSC);
+ * // Enable the PLL
+ * rcc_pll_on();
+ *
+ * // Change the clock divisor
+ * rcc_set_pll_divisor(PLLDIV_80MHZ);
+ *
+ * // We cannot use the PLL as a clock source until it locks
+ * rcc_wait_for_pll_ready();
+ * // Disable PLL bypass to derive the system clock from the PLL clock
+ * rcc_pll_bypass_disable();
+ *
+ * // Keep track of frequency
+ * lm4f_rcc_sysclk_freq = 80E6;
+ * @endcode
+ *
+ * The same can be achieved by a simple call to high-level routines:
+ * @code
+ * // A divisor of 5 gives us a clock of 400/5 = 80MHz
+ * #define PLLDIV_80MHZ 5
+ *
+ * rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLLDIV_80MHZ);
+ * @endcode
+ *
+ * @{
+ */
+
+#include <libopencm3/lm4f/rcc.h>
+
+/**
+ * @defgroup rcc_low_level Low-level clock control API
+@ingroup rcc_file
+ * @{
+ */
+/**
+ * \brief System clock frequency
+ *
+ * This variable is provided to keep track of the system clock frequency. It
+ * should be updated every time the system clock is changed via the fine-grained
+ * mechanisms. The initial value is 16MHz, which corresponds to the clock of the
+ * internal 16MHz oscillator.
+ *
+ * High-level routines update the system clock automatically.
+ * For read access, it is recommended to acces this variable via
+ * @code
+ * rcc_get_system_clock_frequency();
+ * @endcode
+ *
+ * If write access is desired (i.e. when changing the system clock via the
+ * fine-grained mechanisms), then include the following line in your code:
+ * @code
+ * extern uint32_t lm4f_rcc_sysclk_freq;
+ * @endcode
+ */
+uint32_t lm4f_rcc_sysclk_freq = 16000000;
+
+
+/**
+ * \brief Configure the crystal type connected to the device.
+ *
+ * Configure the crystal type connected between the OSCO and OSCI pins by
+ * writing the appropriate value to the XTAL field in SYSCTL_RCC. The PLL
+ * parameters are automatically adjusted in hardware to provide a PLL clock of
+ * 400MHz.
+ *
+ * @param[in] xtal predefined crystal type @see xtal_t
+ */
+void rcc_configure_xtal(enum xtal_t xtal)
+{
+ uint32_t reg32;
+
+ reg32 = SYSCTL_RCC;
+ reg32 &= ~SYSCTL_RCC_XTAL_MASK;
+ reg32 |= (xtal & SYSCTL_RCC_XTAL_MASK);
+ SYSCTL_RCC = reg32;
+}
+
+/**
+ * \brief Disable the main oscillator
+ *
+ * Sets the IOSCDIS bit in SYSCTL_RCC, disabling the main oscillator.
+ */
+void rcc_disable_main_osc(void)
+{
+ SYSCTL_RCC |= SYSCTL_RCC_MOSCDIS;
+}
+
+/**
+ * \brief Disable the internal oscillator
+ *
+ * Sets the IOSCDIS bit in SYSCTL_RCC, disabling the internal oscillator.
+ */
+void rcc_disable_interal_osc(void)
+{
+ SYSCTL_RCC |= SYSCTL_RCC_IOSCDIS;
+}
+
+/**
+ * \brief Enable the main oscillator
+ *
+ * Clears the MOSCDIS bit in SYSCTL_RCC, enabling the main oscillator.
+ */
+void rcc_enable_main_osc(void)
+{
+ SYSCTL_RCC &= ~SYSCTL_RCC_MOSCDIS;
+}
+
+/**
+ * \brief Enable the internal oscillator
+ *
+ * Clears the IOSCDIS bit in SYSCTL_RCC, enabling the internal oscillator.
+ */
+void rcc_enable_interal_osc(void)
+{
+ SYSCTL_RCC &= ~SYSCTL_RCC_IOSCDIS;
+}
+
+/**
+ * \brief Enable the use of SYSCTL_RCC2 register for clock control
+ *
+ * Enables the USERCC2 bit in SYSCTTL_RCC2. Settings in SYSCTL_RCC2 will
+ * override settings in SYSCTL_RCC.
+ * This function must be called before other calls to manipulate the clock, as
+ * libopencm3 uses the SYSCTL_RCC2 register.
+ */
+void rcc_enable_rcc2(void)
+{
+ SYSCTL_RCC2 |= SYSCTL_RCC2_USERCC2;
+}
+
+/**
+ * \brief Power down the main PLL
+ *
+ * Sets the SYSCTL_RCC2_PWRDN2 in SYSCTL_RCC2 to power down the PLL.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_pll_off(void)
+{
+ SYSCTL_RCC2 |= SYSCTL_RCC2_PWRDN2;
+}
+
+/**
+ * \brief Power up the main PLL
+ *
+ * Clears the PWRDN2 in SYSCTL_RCC2 to power on the PLL.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_pll_on(void)
+{
+ SYSCTL_RCC2 &= ~SYSCTL_RCC2_PWRDN2;
+}
+
+/**
+ * \brief Set the oscillator source to be used by the system clock
+ *
+ * Set the clock source for the system clock.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_set_osc_source(enum osc_src src)
+{
+ uint32_t reg32;
+
+ reg32 = SYSCTL_RCC2;
+ reg32 &= ~SYSCTL_RCC2_OSCSRC2_MASK;
+ reg32 |= (src & SYSCTL_RCC2_OSCSRC2_MASK);
+ SYSCTL_RCC2 = reg32;
+}
+
+/**
+ * \brief Disable the PLL bypass and use the PLL clock
+ *
+ * Clear BYPASS2 in SYSCTL_RCC2. The system clock is derived from the PLL
+ * clock divided by the divisor specified in SYSDIV2.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_pll_bypass_disable(void)
+{
+ SYSCTL_RCC2 &= ~SYSCTL_RCC2_BYPASS2;
+}
+
+/**
+ * \brief Enable the PLL bypass and use the oscillator clock
+ *
+ * Set BYPASS2 in SYSCTL_RCC2. The system clock is derived from the oscillator
+ * clock divided by the divisor specified in SYSDIV2.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_pll_bypass_enable(void)
+{
+ SYSCTL_RCC2 |= SYSCTL_RCC2_BYPASS2;
+}
+
+/**
+ * \brief Set the PLL clock divisor (from 400MHz)
+ *
+ * Set the binary divisor used to predivide the system clock down for use as the
+ * timing reference for the PWM module. The divisor is expected to be a divisor
+ * from 400MHz, not 200MHz. The DIV400 is also set.
+ *
+ * Specifies the divisor that used to generate the system clock from either the
+ * PLL output or the oscillator source (depending on the BYPASS2 bit in
+ * SYSCTL_RCC2). SYSDIV2 is used for the divisor when both the USESYSDIV bit in
+ * SYSCTL_RCC is set.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ *
+ * @param[in] div clock divisor to apply to the 400MHz PLL clock. It is the
+ * caller's responsibility to ensure that the divisor will not create
+ * a system clock that is out of spec.
+ */
+void rcc_set_pll_divisor(uint8_t div400)
+{
+ uint32_t reg32;
+
+ SYSCTL_RCC |= SYSCTL_RCC_USESYSDIV;
+
+ reg32 = SYSCTL_RCC2;
+ reg32 &= ~SYSCTL_RCC2_SYSDIV400_MASK;
+ reg32 |= ((div400 - 1) << 22) & SYSCTL_RCC2_SYSDIV400_MASK;
+ /* We are expecting a divider from 400MHz */
+ reg32 |= SYSCTL_RCC2_DIV400;
+ SYSCTL_RCC2 = reg32;
+}
+/**
+ * \brief Set the PWM unit clock divisor
+ *
+ * Set the binary divisor used to predivide the system clock down for use as the
+ * timing reference for the PWM module.
+ *
+ * @param[in] div clock divisor to use @see pwm_clkdiv_t
+ */
+void rcc_set_pwm_divisor(enum pwm_clkdiv div)
+{
+ uint32_t reg32;
+
+ reg32 = SYSCTL_RCC;
+ reg32 &= ~SYSCTL_RCC_PWMDIV_MASK;
+ reg32 |= (div & SYSCTL_RCC_PWMDIV_MASK);
+ SYSCTL_RCC = reg32;
+}
+
+/**
+ * \brief Power down the USB PLL
+ *
+ * Sets the USBPWRDN in SYSCTL_RCC2 to power down the USB PLL.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_usb_pll_off(void)
+{
+ SYSCTL_RCC2 |= SYSCTL_RCC2_USBPWRDN;
+}
+
+/**
+ * \brief Power up the USB PLL
+ *
+ * Clears the USBPWRDN in SYSCTL_RCC2 to power on the USB PLL.
+ *
+ * USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
+ * function.
+ */
+void rcc_usb_pll_on(void)
+{
+ SYSCTL_RCC2 &= ~SYSCTL_RCC2_USBPWRDN;
+}
+
+/**
+ * \brief Wait for main PLL to lock
+ *
+ * Waits until the LOCK bit in SYSCTL_PLLSTAT is set. This guarantees that the
+ * PLL is locked, and ready to use.
+ */
+void rcc_wait_for_pll_ready(void)
+{
+ while (!(SYSCTL_PLLSTAT & SYSCTL_PLLSTAT_LOCK));
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup rcc_high_level High-level clock control API
+@ingroup rcc_file
+ * @{
+ */
+
+/**
+ * \brief Change the PLL divisor
+ *
+ * Changes the divisor applied to the 400MHz PLL clock. The PLL must have
+ * previously been configured by selecting an appropriate XTAL value, and
+ * turning on the PLL. This function does not reconfigure the XTAL value or
+ * oscillator source. It only changes the PLL divisor.
+ *
+ * The PLL is bypassed before modifying the divisor, and the function blocks
+ * until the PLL is locked, then the bypass is disabled, before returning.
+ *
+ * @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock.
+ */
+void rcc_change_pll_divisor(uint8_t pll_div400)
+{
+ /* Bypass the PLL while its settings are modified */
+ rcc_pll_bypass_enable();
+ /* Change the clock divisor */
+ rcc_set_pll_divisor(pll_div400);
+ /* We cannot use the PLL as a clock source until it locks */
+ rcc_wait_for_pll_ready();
+ /* Disable PLL bypass to derive the system clock from the PLL clock */
+ rcc_pll_bypass_disable();
+ /* Update the system clock frequency for housekeeping */
+ lm4f_rcc_sysclk_freq = (uint32_t)400E6 / pll_div400;
+}
+
+/**
+ * \brief Get the system clock frequency
+ *
+ * @return System clock frequency in Hz
+ */
+uint32_t rcc_get_system_clock_frequency(void)
+{
+ return lm4f_rcc_sysclk_freq;
+}
+
+/* Get the clock frequency corresponding to a given XTAL value */
+static uint32_t xtal_to_freq(enum xtal_t xtal)
+{
+ const uint32_t freqs[] = {
+ 4000000, /* XTAL_4M */
+ 4096000, /* XTAL_4M_096 */
+ 4915200, /* XTAL_4M_9152 */
+ 5000000, /* ,XTAL_5M */
+ 5120000, /* XTAL_5M_12 */
+ 6000000, /* XTAL_6M */
+ 6144000, /* XTAL_6M_144 */
+ 7372800, /* XTAL_7M_3728 */
+ 8000000, /* XTAL_8M */
+ 8192000, /* XTAL_8M_192 */
+ 10000000, /* XTAL_10M */
+ 12000000, /* XTAL_12M */
+ 12288000, /* XTAL_12M_288 */
+ 13560000, /* XTAL_13M_56 */
+ 14318180, /* XTAL_14M_31818 */
+ 16000000, /* XTAL_16M */
+ 16384000, /* XTAL_16M_384 */
+ 18000000, /* XTAL_18M */
+ 20000000, /* XTAL_20M */
+ 24000000, /* XTAL_24M */
+ 25000000, /* XTAL_25M */
+ };
+
+ return freqs[xtal - XTAL_4M];
+}
+
+/**
+ * \brief Configure the system clock source
+ *
+ * Sets up the system clock, including configuring the oscillator source, and
+ * PLL to acheve the desired system clock frequency. Where applicable, The LM4F
+ * clock API uses the new RCC2 register to configure clock parameters.
+ *
+ * Enables the main oscillator if the clock source is OSCSRC_MOSC. If the main
+ * oscillator was previously enabled, it will not be disabled. If desired, it
+ * can be separately disabled by a call to rcc_disable_main_osc().
+ *
+ * Configures the system clock to run from the 400MHz PLL with a divisor of
+ * pll_div400 applied. If pll_div400 is 0, then the PLL is disabled, and the
+ * system clock is configured to run off a "raw" clock. If the PLL was
+ * previously powered on, it will not be disabled. If desired, it can de powered
+ * off by a call to rcc_pll_off().
+ *
+ * @param [in] osc_src Oscillator from where to derive the system clock.
+ * @param [in] xtal Type of crystal connected to the OSCO/OSCI pins
+ * @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock.
+ * If 0, then the PLL is disabled, and the system runs
+ * off a "raw" clock.
+ *
+ * @return System clock frequency in Hz
+ */
+void rcc_sysclk_config(enum osc_src src, enum xtal_t xtal, uint8_t pll_div400)
+{
+ /*
+ * We could be using the PLL at this point, or we could be running of a
+ * raw clock. Either way, it is safer to bypass the PLL now.
+ */
+ rcc_pll_bypass_enable();
+
+ /* Enable the main oscillator, if needed */
+ if (src == OSCSRC_MOSC) {
+ rcc_enable_main_osc();
+ }
+
+ /* Make RCC2 override RCC */
+ rcc_enable_rcc2();
+
+ /* Set XTAL value to 16MHz */
+ rcc_configure_xtal(xtal);
+ /* Set the oscillator source */
+ rcc_set_osc_source(src);
+ if (pll_div400) {
+ /* Enable the PLL */
+ rcc_pll_on();
+ /* Configure the PLL to the divisor we want */
+ rcc_change_pll_divisor(pll_div400);
+ } else {
+ /* We are running off a raw clock */
+ switch (src) {
+ case OSCSRC_PIOSC:
+ lm4f_rcc_sysclk_freq = 16000000;
+ break;
+ case OSCSRC_PIOSC_D4:
+ lm4f_rcc_sysclk_freq = 4000000;
+ break;
+ case OSCSRC_MOSC:
+ lm4f_rcc_sysclk_freq = xtal_to_freq(xtal);
+ break;
+ case OSCSRC_32K_EXT:
+ lm4f_rcc_sysclk_freq = 32768;
+ break;
+ case OSCSRC_30K_INT: /* Fall through. */
+ default:
+ /*
+ * We either are running off the internal 30KHz
+ * oscillator, which is +- 50% imprecise, or we got a
+ * bad osc_src parameter.
+ */
+ lm4f_rcc_sysclk_freq = 0;
+ }
+ }
+
+}
+
+/**
+ * @}
+ * @}
+ */
diff --git a/libopencm3/lib/lm4f/systemcontrol.c b/libopencm3/lib/lm4f/systemcontrol.c
new file mode 100644
index 0000000..c2993b9
--- /dev/null
+++ b/libopencm3/lib/lm4f/systemcontrol.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/lm4f/systemcontrol.h>
+
+/**
+ * \brief Enable the clock source for the peripheral
+ *
+ * @param[in] periph peripheral and clock type to enable @see lm4f_clken
+ */
+void periph_clock_enable(enum lm4f_clken periph)
+{
+ MMIO32(SYSCTL_BASE + (periph >> 5)) |= 1 << (periph & 0x1f);
+}
+
+/**
+ * \brief Disable the clock source for the peripheral
+ *
+ * @param[in] periph peripheral and clock type to enable @see lm4f_clken
+ */
+void periph_clock_disable(enum lm4f_clken periph)
+{
+ MMIO32(SYSCTL_BASE + (periph >> 5)) &= ~(1 << (periph & 0x1f));
+}
diff --git a/libopencm3/lib/lm4f/uart.c b/libopencm3/lib/lm4f/uart.c
new file mode 100644
index 0000000..c5e3e04
--- /dev/null
+++ b/libopencm3/lib/lm4f/uart.c
@@ -0,0 +1,627 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @defgroup uart_file UART
+ *
+ * @ingroup LM4Fxx
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * \brief <b>libopencm3 LM4F Universal Asynchronous Receiver Transmitter</b>
+ *
+ * The LM4F UART API provides functionality for accessing the UART hardware of
+ * the LM4F.
+ *
+ * Please see the individual UART modules for more details. To use the UART, the
+ * uart.h header needs to be included:
+ * @code{.c}
+ * #include <libopencm3/lm4f/uart.h>
+ * @endcode
+ *
+ * @{
+ */
+
+#include <libopencm3/lm4f/uart.h>
+#include <libopencm3/lm4f/systemcontrol.h>
+#include <libopencm3/lm4f/rcc.h>
+
+/** @defgroup uart_config UART configuration
+ * @ingroup uart_file
+ *
+ * \brief <b>Enabling and configuring the UART</b>
+ *
+ * Enabling the UART is a two step process. The GPIO on which the UART resides
+ * must be enabled, and the UART pins must be configured as alternate function,
+ * digital pins. Pins must also be muxed to the appropriate alternate function.
+ * This is done with the GPIO API.
+ *
+ * The second step involves enabling and the UART itself. The UART should be
+ * disabled while it is being configured.
+ * -# The UART clock must be enabled with @ref periph_clock_enable().
+ * -# The UART must be disabled with @ref uart_disable().
+ * -# The UART clock source should be chosen before setting the baudrate.
+ * -# Baudrate, data bits, stop bit length, and parity can be configured.
+ * -# If needed, enable CTS or RTS lines via the @ref uart_set_flow_control().
+ * -# The UART can now be enabled with @ref uart_enable().
+ *
+ * For example, to enable UART1 at 115200 8n1 with hardware flow control:
+ * @code{.c}
+ * // Enable the UART clock
+ * periph_clock_enable(RCC_UART1);
+ * // We need a brief delay before we can access UART config registers
+ * __asm__("nop"); __asm__("nop"); __asm__("nop");
+ * // Disable the UART while we mess with its settings
+ * uart_disable(UART1);
+ * // Configure the UART clock source as precision internal oscillator
+ * uart_clock_from_piosc();
+ * // Set communication parameters
+ * uart_set_baudrate(UART1, 115200);
+ * uart_set_databits(UART1, 8);
+ * uart_set_parity(UART1, UART_PARITY_NONE);
+ * uart_set_stopbits(UART1, 1);
+ * // Enable RTC and CTS lines
+ * uart_set_flow_control(UART1, UART_FLOWCTL_HARD_RTS_CTS);
+ * // Now that we're done messing with the settings, enable the UART
+ * uart_enable(UART1);
+ * @endcode
+ */
+/**@{*/
+/**
+ * \brief Enable the UART
+ *
+ * Enable the UART. The Rx and Tx lines are also enabled.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable(uint32_t uart)
+{
+ UART_CTL(uart) |= (UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE);
+}
+
+/**
+ * \brief Disable the UART
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable(uint32_t uart)
+{
+ UART_CTL(uart) &= ~UART_CTL_UARTEN;
+}
+
+/**
+ * \brief Set UART baudrate
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] baud Baud rate in bits per second (bps).*
+ */
+void uart_set_baudrate(uint32_t uart, uint32_t baud)
+{
+ uint32_t clock;
+
+ /* Are we running off the internal clock or system clock? */
+ if (UART_CC(uart) == UART_CC_CS_PIOSC) {
+ clock = 16000000;
+ } else {
+ clock = rcc_get_system_clock_frequency();
+ }
+
+ /* Find the baudrate divisor */
+ uint32_t div = (((clock * 8) / baud) + 1) / 2;
+
+ /* Set the baudrate divisors */
+ UART_IBRD(uart) = div / 64;
+ UART_FBRD(uart) = div % 64;
+}
+
+/**
+ * \brief Set UART databits
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] databits number of data bits per transmission.
+ */
+void uart_set_databits(uint32_t uart, uint8_t databits)
+{
+ uint32_t reg32, bitint32_t;
+
+ /* This has the same effect as using UART_LCRH_WLEN_5/6/7/8 directly */
+ bitint32_t = (databits - 5) << 5;
+
+ /* TODO: What about 9 data bits? */
+
+ reg32 = UART_LCRH(uart);
+ reg32 &= ~UART_LCRH_WLEN_MASK;
+ reg32 |= bitint32_t;
+ UART_LCRH(uart) = reg32;
+}
+
+/**
+ * \brief Set UART stopbits
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] bits the requested number of stopbits, either 1 or 2.
+ */
+void uart_set_stopbits(uint32_t uart, uint8_t stopbits)
+{
+ if (stopbits == 2) {
+ UART_LCRH(uart) |= UART_LCRH_STP2;
+ } else {
+ UART_LCRH(uart) &= ~UART_LCRH_STP2;
+ }
+}
+
+/**
+ * \brief Set UART parity
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] bits the requested parity scheme.
+ */
+void uart_set_parity(uint32_t uart, enum uart_parity parity)
+{
+ uint32_t reg32;
+
+ reg32 = UART_LCRH(uart);
+ reg32 |= UART_LCRH_PEN;
+ reg32 &= ~(UART_LCRH_SPS | UART_LCRH_EPS);
+
+ switch (parity) {
+ case UART_PARITY_NONE:
+ /* Once we disable parity the other bits are meaningless */
+ UART_LCRH(uart) &= ~UART_LCRH_PEN;
+ return;
+ case UART_PARITY_ODD:
+ break;
+ case UART_PARITY_EVEN:
+ reg32 |= UART_LCRH_EPS;
+ break;
+ case UART_PARITY_STICK_0:
+ reg32 |= (UART_LCRH_SPS | UART_LCRH_EPS);
+ break;
+ case UART_PARITY_STICK_1:
+ reg32 |= UART_LCRH_SPS;
+ break;
+ }
+
+ UART_LCRH(uart) = reg32;
+}
+
+/**
+ * \brief Set the flow control scheme
+ *
+ * Set the flow control scheme by enabling or disabling RTS and CTS lines. This
+ * will only have effect if the given UART supports the RTS and CTS lines.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] flow The flow control scheme to use (none, RTS, CTS or both) \n
+ * UART_FLOWCTL_RTS -- enable the RTS line \n
+ * UART_FLOWCTL_CTS -- enable the CTS line \n
+ * UART_FLOWCTL_RTS_CTS -- enable both RTS and CTS lines
+ */
+void uart_set_flow_control(uint32_t uart, enum uart_flowctl flow)
+{
+ uint32_t reg32 = UART_CTL(uart);
+
+ reg32 &= ~(UART_CTL_RTSEN | UART_CTL_CTSEN);
+
+ if (flow == UART_FLOWCTL_RTS) {
+ reg32 |= UART_CTL_RTSEN;
+ } else if (flow == UART_FLOWCTL_CTS) {
+ reg32 |= UART_CTL_CTSEN;
+ } else if (flow == UART_FLOWCTL_RTS_CTS) {
+ reg32 |= (UART_CTL_RTSEN | UART_CTL_CTSEN);
+ }
+
+ UART_CTL(uart) = reg32;
+}
+
+/**
+ * \brief Clock the UART module from the internal oscillator
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_clock_from_piosc(uint32_t uart)
+{
+ UART_CC(uart) = UART_CC_CS_PIOSC;
+}
+
+/**
+ * \brief Clock the UART module from the system clock
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_clock_from_sysclk(uint32_t uart)
+{
+ UART_CC(uart) = UART_CC_CS_SYSCLK;
+}
+/**@}*/
+
+/** @defgroup uart_send_recv UART transmission and reception
+ * @ingroup uart_file
+ *
+ * \brief <b>Sending and receiving data through the UART</b>
+ *
+ * Primitives for sending and recieving data are provided, @ref uart_send() and
+ * @ref uart_recv(). These primitives do not check if data can be transmitted
+ * or wait for data. If waiting until data is available or can be transmitted is
+ * desired, blocking primitives are also available, @ref uart_send_blocking()
+ * and @ref uart_recv_blocking().
+ *
+ * These primitives only handle one byte at at time, and thus may be unsuited
+ * for some applications. You may also consider using @ref uart_dma.
+ */
+/**@{*/
+/**
+ * \brief UART Send a Data Word.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] data data to send.
+ */
+void uart_send(uint32_t uart, uint16_t data)
+{
+ data &= 0xFF;
+ UART_DR(uart) = data;
+}
+
+/**
+ * \brief UART Read a Received Data Word.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @return data from the Rx FIFO.
+ */
+uint16_t uart_recv(uint32_t uart)
+{
+ return UART_DR(uart) & UART_DR_DATA_MASK;
+}
+
+/**
+ * \brief UART Wait for Transmit Data Buffer Not Full
+ *
+ * Blocks until the transmit data FIFO is not empty and can accept the next data
+ * word.
+ * \n
+ * Even if the FIFO is not empty, this function will return as long as there is
+ * room for at least one more word.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_wait_send_ready(uint32_t uart)
+{
+ /* Wait until the Tx FIFO is no longer full */
+ while (UART_FR(uart) & UART_FR_TXFF);
+}
+
+/**
+ * \brief UART Wait for Received Data Available
+ *
+ * Blocks until the receive data FIFO holds a at least valid received data word.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_wait_recv_ready(uint32_t uart)
+{
+ /* Wait until the Tx FIFO is no longer empty */
+ while (UART_FR(uart) & UART_FR_RXFE);
+}
+
+/**
+ * \brief UART Send Data Word with Blocking
+ *
+ * Blocks until the transmit data FIFO can accept the next data word for
+ * transmission.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_send_blocking(uint32_t uart, uint16_t data)
+{
+ uart_wait_send_ready(uart);
+ uart_send(uart, data);
+}
+
+/**
+ * \brief UART Read a Received Data Word with Blocking.
+ *
+ * Wait until a data word has been received then return the word.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @return data from the Rx FIFO.
+ */
+uint16_t uart_recv_blocking(uint32_t uart)
+{
+ uart_wait_recv_ready(uart);
+ return uart_recv(uart);
+}
+/**@}*/
+
+/** @defgroup uart_irq UART Interrupt control
+ * @ingroup uart_file
+ *
+ * \brief <b>Configuring interrupts from the UART</b>
+ *
+ * To have an event generate an interrupt, its interrupt source must be
+ * unmasked. This can be achieved with @ref uart_enable_interrupts(). Interrupts
+ * which are no longer needed can be disabled through
+ * @ref uart_disable_interrupts().
+ *
+ * In order for the interrupt to generate an IRQ and a call to the interrupt
+ * service routine, the interrupt for the target UART must be routed through the
+ * NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
+ * needed:
+ * @code{.c}
+ * #include <libopencm3/lm4f/nvic.h>
+ * @endcode
+ *
+ * Enabling an interrupt is as simple as unmasking the desired interrupt, and
+ * routing the desired UART's interrupt through the NVIC.
+ * @code{.c}
+ * // Unmask receive interrupt
+ * uart_enable_rx_interrupt(UART0);
+ * // Make sure the interrupt is routed through the NVIC
+ * nvic_enable_irq(NVIC_UART0_IRQ);
+ * @endcode
+ *
+ * If a more than one interrupt is to be enabled at one time, the interrupts
+ * can be enabled by a single call to @ref uart_enable_interrupts().
+ * For example:
+ * @code{.c}
+ * // Unmask receive, CTS, and RI, interrupts
+ * uart_enable_interrupts(UART0, UART_INT_RX | UART_INT_RI | UART_INT_CTS);
+ * @endcode
+ *
+ * After interrupts are properly enabled and routed through the NVIC, when an
+ * event occurs, the appropriate IRQ flag is set by hardware, and execution
+ * jumps to the UART ISR. The ISR should query the IRQ flags to determine which
+ * event caused the interrupt. For this, use @ref uart_is_interrupt_source(),
+ * with the desired UART_INT flag. After one or more interrupt sources are
+ * serviced, the IRQ flags must be cleared by the ISR. This can be done with
+ * @ref uart_clear_interrupt_flag().
+ *
+ * A typical UART ISR may look like the following:
+ * @code{.c}
+ * void uart0_isr(void)
+ * {
+ * uint32_t serviced_irqs = 0;
+ *
+ * // Process individual IRQs
+ * if (uart_is_interrupt_source(UART0, UART_INT_RX)) {
+ * process_rx_event();
+ * serviced_irq |= UART_INT_RX;
+ * }
+ * if (uart_is_interrupt_source(UART0, UART_INT_CTS)) {
+ * process_cts_event();
+ * serviced_irq |= UART_INT_CTS;
+ * }
+ *
+ * // Clear the interupt flag for the processed IRQs
+ * uart_clear_interrupt_flag(UART0, serviced_irqs);
+ * }
+ * @endcode
+ */
+/**@{*/
+/**
+ * \brief Enable Specific UART Interrupts
+ *
+ * Enable any combination of interrupts. Interrupts may be OR'ed together to
+ * enable them with one call. For example, to enable both the RX and CTS
+ * interrupts, pass (UART_INT_RX | UART_INT_CTS)
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] ints Interrupts which to enable. Any combination of interrupts may
+ * be specified by OR'ing then together
+ */
+void uart_enable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
+{
+ UART_IM(uart) |= ints;
+}
+
+/**
+ * \brief Enable Specific UART Interrupts
+ *
+ * Disabe any combination of interrupts. Interrupts may be OR'ed together to
+ * disable them with one call. For example, to disable both the RX and CTS
+ * interrupts, pass (UART_INT_RX | UART_INT_CTS)
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] ints Interrupts which to disable. Any combination of interrupts
+ * may be specified by OR'ing then together
+ */
+void uart_disable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
+{
+ UART_IM(uart) &= ~ints;
+}
+
+/**
+ * \brief Enable the UART Receive Interrupt.
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable_rx_interrupt(uint32_t uart)
+{
+ uart_enable_interrupts(uart, UART_INT_RX);
+}
+
+/**
+ * \brief Disable the UART Receive Interrupt.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable_rx_interrupt(uint32_t uart)
+{
+ uart_disable_interrupts(uart, UART_INT_RX);
+}
+
+/**
+ * \brief Enable the UART Transmit Interrupt.
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable_tx_interrupt(uint32_t uart)
+{
+ uart_enable_interrupts(uart, UART_INT_TX);
+}
+
+/**
+ * \brief Disable the UART Transmit Interrupt.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable_tx_interrupt(uint32_t uart)
+{
+ uart_disable_interrupts(uart, UART_INT_TX);
+}
+
+/**
+ * \brief Mark interrupt as serviced
+ *
+ * After an interrupt is services, its flag must be cleared. If the flag is not
+ * cleared, then execution will jump back to the start of the ISR after the ISR
+ * returns.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] ints Interrupts which to clear. Any combination of interrupts may
+ * be specified by OR'ing then together
+ */
+void uart_clear_interrupt_flag(uint32_t uart, enum uart_interrupt_flag ints)
+{
+ UART_ICR(uart) |= ints;
+}
+/**@}*/
+
+/** @defgroup uart_dma UART DMA control
+ * @ingroup uart_file
+ *
+ * \brief <b>Enabling Direct Memory Access transfers for the UART</b>
+ *
+ */
+/**@{*/
+
+/**
+ * \brief Enable the UART Receive DMA.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable_rx_dma(uint32_t uart)
+{
+ UART_DMACTL(uart) |= UART_DMACTL_RXDMAE;
+}
+
+/**
+ * \brief Disable the UART Receive DMA.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable_rx_dma(uint32_t uart)
+{
+ UART_DMACTL(uart) &= ~UART_DMACTL_RXDMAE;
+}
+
+/**
+ * \brief Enable the UART Transmit DMA.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable_tx_dma(uint32_t uart)
+{
+ UART_DMACTL(uart) |= UART_DMACTL_TXDMAE;
+}
+
+/**
+ * \brief Disable the UART Transmit DMA.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable_tx_dma(uint32_t uart)
+{
+ UART_DMACTL(uart) &= ~UART_DMACTL_TXDMAE;
+}
+/**@}*/
+
+/** @defgroup uart_fifo UART FIFO control
+ * @ingroup uart_file
+ *
+ * \brief <b>Enabling and controlling UART FIFO</b>
+ *
+ * The UART on the LM4F can either be used with a single character TX and RX
+ * buffer, or with a 8 character TX and RX FIFO. In order to use the FIFO it
+ * must be enabled, this is done with uart_enable_fifo() and can be disabled
+ * again with uart_disable_fifo(). On reset the FIFO is disabled, and it must
+ * be explicitly be enabled.
+ *
+ * When enabling the UART FIFOs, RX and TX interrupts are triggered according
+ * to the amount of data in the FIFOs. For the RX FIFO the trigger level is
+ * defined by how full the FIFO is. The TX FIFO trigger level is defined by
+ * how empty the FIFO is instead.
+ *
+ * For example, to enable the FIFOs and trigger interrupts for a single
+ * received and single transmitted character:
+ * @code{.c}
+ * uart_enable_fifo(UART0);
+ * uart_set_fifo_trigger_levels(UART0, UART_FIFO_RX_TRIG_1_8,
+ * UART_FIFO_TX_TRIG_7_8);
+ * @endcode
+ */
+/**@{*/
+
+/**
+ * \brief Enable FIFO for the UART.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_enable_fifo(uint32_t uart)
+{
+ UART_LCRH(uart) |= UART_LCRH_FEN;
+}
+
+/**
+ * \brief Disable FIFO for the UART.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ */
+void uart_disable_fifo(uint32_t uart)
+{
+ UART_LCRH(uart) &= ~UART_LCRH_FEN;
+}
+
+/**
+ * \brief Set the FIFO trigger levels.
+ *
+ * @param[in] uart UART block register address base @ref uart_reg_base
+ * @param[in] rx_level Trigger level for RX FIFO
+ * @param[in] tx_level Trigger level for TX FIFO
+ */
+void uart_set_fifo_trigger_levels(uint32_t uart,
+ enum uart_fifo_rx_trigger_level rx_level,
+ enum uart_fifo_tx_trigger_level tx_level)
+{
+ UART_IFLS(uart) = rx_level | tx_level;
+}
+/**@}*/
+
+
+/**
+ * @}
+ */
diff --git a/libopencm3/lib/lm4f/usb_lm4f.c b/libopencm3/lib/lm4f/usb_lm4f.c
new file mode 100644
index 0000000..e70e604
--- /dev/null
+++ b/libopencm3/lib/lm4f/usb_lm4f.c
@@ -0,0 +1,651 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @defgroup usb_file USB
+ *
+ * @ingroup LM4Fxx
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013
+ * Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * \brief <b>libopencm3 LM4F Universal Serial Bus controller </b>
+ *
+ * The LM4F USB driver is integrated with the libopencm3 USB stack. You should
+ * use the generic stack.
+ *
+ * To use this driver, tell the linker to look for it:
+ * @code{.c}
+ * extern usbd_driver lm4f_usb_driver;
+ * @endcode
+ *
+ * And pass this driver as an argument when initializing the USB stack:
+ * @code{.c}
+ * usbd_device *usbd_dev;
+ * usbd_dev = usbd_init(&lm4f_usb_driver, ...);
+ * @endcode
+ *
+ * <b>Polling or interrupt-driven? </b>
+ *
+ * The LM4F USB driver will work fine regardless of whether it is called from an
+ * interrupt service routine, or from the main program loop.
+ *
+ * Polling USB from the main loop requires calling @ref usbd_poll() from the
+ * main program loop.
+ * For example:
+ * @code{.c}
+ * // Main program loop
+ * while(1) {
+ * usbd_poll(usb_dev);
+ * do_other_stuff();
+ * ...
+ * @endcode
+ *
+ * Running @ref usbd_poll() from an interrupt has the advantage that it is only
+ * called when needed, saving CPU cycles for the main program.
+ *
+ * RESET, DISCON, RESUME, and SUSPEND interrupts must be enabled, along with the
+ * interrupts for any endpoint that is used. The EP0_TX interrupt must be
+ * enabled for the control endpoint to function correctly.
+ * For example, if EP1IN and EP2OUT are used, then the EP0_TX, EP1_TX, and
+ * EP2_RX interrupts should be enabled:
+ * @code{.c}
+ * // Enable USB interrupts for EP0, EP1IN, and EP2OUT
+ * ints = USB_INT_RESET | USB_INT_DISCON | USB_INT_RESUME |
+ * USB_INT_SUSPEND;
+ * usb_enable_interrupts(ints, USB_EP2_INT, USB_EP0_INT | USB_EP1_INT);
+ * // Route the interrupts through the NVIC
+ * nvic_enable_irq(NVIC_USB0_IRQ);
+ * @endcode
+ *
+ * The USB ISR only has to call @ref usbd_poll().
+ *
+ * @code{.c}
+ * void usb0_isr(void)
+ * {
+ * usbd_poll(usb_dev);
+ * }
+ * @endcode
+ * @{
+ */
+
+/*
+ * TODO list:
+ *
+ * 1) Driver works by reading and writing to the FIFOs one byte at a time. It
+ * has no knowledge of DMA.
+ * 2) Double-buffering is supported. How can we take advantage of it to speed
+ * up endpoint transfers.
+ * 3) No benchmarks as to the endpoint's performance has been done.
+ */
+/*
+ * The following are resources referenced in comments:
+ * [1] http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/238784.aspx
+ */
+
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/lm4f/usb.h>
+#include <libopencm3/lm4f/rcc.h>
+#include <libopencm3/usb/usbd.h>
+#include "../../lib/usb/usb_private.h"
+
+#include <stdbool.h>
+
+
+#define MAX_FIFO_RAM (4 * 1024)
+
+const struct _usbd_driver lm4f_usb_driver;
+
+/**
+ * \brief Enable Specific USB Interrupts
+ *
+ * Enable any combination of interrupts. Interrupts may be OR'ed together to
+ * enable them with one call. For example, to enable both the RESUME and RESET
+ * interrupts, pass (USB_INT_RESUME | USB_INT_RESET)
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] ints Interrupts which to enable. Any combination of interrupts may
+ * be specified by OR'ing then together
+ * @param[in] rx_ints Endpoints for which to generate an interrupt when a packet
+ * packet is received.
+ * @param[in] tx_ints Endpoints for which to generate an interrupt when a packet
+ * packet is finished transmitting.
+ */
+void usb_enable_interrupts(enum usb_interrupt ints,
+ enum usb_ep_interrupt rx_ints,
+ enum usb_ep_interrupt tx_ints)
+{
+ USB_IE |= ints;
+ USB_RXIE |= rx_ints;
+ USB_TXIE |= tx_ints;
+}
+
+/**
+ * \brief Disable Specific USB Interrupts
+ *
+ * Disable any combination of interrupts. Interrupts may be OR'ed together to
+ * enable them with one call. For example, to disable both the RESUME and RESET
+ * interrupts, pass (USB_INT_RESUME | USB_INT_RESET)
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] ints Interrupts which to disable. Any combination of interrupts
+ * may be specified by OR'ing then together
+ * @param[in] rx_ints Endpoints for which to stop generating an interrupt when a
+ * packet packet is received.
+ * @param[in] tx_ints Endpoints for which to stop generating an interrupt when a
+ * packet packet is finished transmitting.
+ */
+void usb_disable_interrupts(enum usb_interrupt ints,
+ enum usb_ep_interrupt rx_ints,
+ enum usb_ep_interrupt tx_ints)
+{
+ USB_IE &= ~ints;
+ USB_RXIE &= ~rx_ints;
+ USB_TXIE &= ~tx_ints;
+}
+
+/**
+ * @cond private
+ */
+static inline void lm4f_usb_soft_disconnect(void)
+{
+ USB_POWER &= ~USB_POWER_SOFTCONN;
+}
+
+static inline void lm4f_usb_soft_connect(void)
+{
+ USB_POWER |= USB_POWER_SOFTCONN;
+}
+
+static void lm4f_set_address(usbd_device *usbd_dev, uint8_t addr)
+{
+ (void)usbd_dev;
+
+ USB_FADDR = addr & USB_FADDR_FUNCADDR_MASK;
+}
+
+static void lm4f_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*callback) (usbd_device *usbd_dev, uint8_t ep))
+{
+ (void)usbd_dev;
+ (void)type;
+
+ uint8_t reg8;
+ uint16_t fifo_size;
+
+ const bool dir_tx = addr & 0x80;
+ const uint8_t ep = addr & 0x0f;
+
+ /*
+ * We do not mess with the maximum packet size, but we can only allocate
+ * the FIFO in power-of-two increments.
+ */
+ if (max_size > 1024) {
+ fifo_size = 2048;
+ reg8 = USB_FIFOSZ_SIZE_2048;
+ } else if (max_size > 512) {
+ fifo_size = 1024;
+ reg8 = USB_FIFOSZ_SIZE_1024;
+ } else if (max_size > 256) {
+ fifo_size = 512;
+ reg8 = USB_FIFOSZ_SIZE_512;
+ } else if (max_size > 128) {
+ fifo_size = 256;
+ reg8 = USB_FIFOSZ_SIZE_256;
+ } else if (max_size > 64) {
+ fifo_size = 128;
+ reg8 = USB_FIFOSZ_SIZE_128;
+ } else if (max_size > 32) {
+ fifo_size = 64;
+ reg8 = USB_FIFOSZ_SIZE_64;
+ } else if (max_size > 16) {
+ fifo_size = 32;
+ reg8 = USB_FIFOSZ_SIZE_32;
+ } else if (max_size > 8) {
+ fifo_size = 16;
+ reg8 = USB_FIFOSZ_SIZE_16;
+ } else {
+ fifo_size = 8;
+ reg8 = USB_FIFOSZ_SIZE_8;
+ }
+
+ /* Endpoint 0 is more special */
+ if (addr == 0) {
+ USB_EPIDX = 0;
+
+ if (reg8 > USB_FIFOSZ_SIZE_64) {
+ reg8 = USB_FIFOSZ_SIZE_64;
+ }
+
+ /* The RX and TX FIFOs are shared for EP0 */
+ USB_RXFIFOSZ = reg8;
+ USB_TXFIFOSZ = reg8;
+
+ /*
+ * Regardless of how much we allocate, the first 64 bytes
+ * are always reserved for EP0.
+ */
+ usbd_dev->fifo_mem_top_ep0 = 64;
+ return;
+ }
+
+ /* Are we out of FIFO space? */
+ if (usbd_dev->fifo_mem_top + fifo_size > MAX_FIFO_RAM) {
+ return;
+ }
+
+ USB_EPIDX = addr & USB_EPIDX_MASK;
+
+ /* FIXME: What about double buffering? */
+ if (dir_tx) {
+ USB_TXMAXP(ep) = max_size;
+ USB_TXFIFOSZ = reg8;
+ USB_TXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3);
+ if (callback) {
+ usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_IN] =
+ (void *)callback;
+ }
+ if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) {
+ USB_TXCSRH(ep) |= USB_TXCSRH_ISO;
+ } else {
+ USB_TXCSRH(ep) &= ~USB_TXCSRH_ISO;
+ }
+ } else {
+ USB_RXMAXP(ep) = max_size;
+ USB_RXFIFOSZ = reg8;
+ USB_RXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3);
+ if (callback) {
+ usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_OUT] =
+ (void *)callback;
+ }
+ if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) {
+ USB_RXCSRH(ep) |= USB_RXCSRH_ISO;
+ } else {
+ USB_RXCSRH(ep) &= ~USB_RXCSRH_ISO;
+ }
+ }
+
+ usbd_dev->fifo_mem_top += fifo_size;
+}
+
+static void lm4f_endpoints_reset(usbd_device *usbd_dev)
+{
+ /*
+ * The core resets the endpoints automatically on reset.
+ * The first 64 bytes are always reserved for EP0
+ */
+ usbd_dev->fifo_mem_top = 64;
+}
+
+static void lm4f_ep_stall_set(usbd_device *usbd_dev, uint8_t addr,
+ uint8_t stall)
+{
+ (void)usbd_dev;
+
+ const uint8_t ep = addr & 0x0f;
+ const bool dir_tx = addr & 0x80;
+
+ if (ep == 0) {
+ if (stall) {
+ USB_CSRL0 |= USB_CSRL0_STALL;
+ } else {
+ USB_CSRL0 &= ~USB_CSRL0_STALL;
+ }
+ return;
+ }
+
+ if (dir_tx) {
+ if (stall) {
+ (USB_TXCSRL(ep)) |= USB_TXCSRL_STALL;
+ } else {
+ (USB_TXCSRL(ep)) &= ~USB_TXCSRL_STALL;
+ }
+ } else {
+ if (stall) {
+ (USB_RXCSRL(ep)) |= USB_RXCSRL_STALL;
+ } else {
+ (USB_RXCSRL(ep)) &= ~USB_RXCSRL_STALL;
+ }
+ }
+}
+
+static uint8_t lm4f_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
+{
+ (void)usbd_dev;
+
+ const uint8_t ep = addr & 0x0f;
+ const bool dir_tx = addr & 0x80;
+
+ if (ep == 0) {
+ return USB_CSRL0 & USB_CSRL0_STALLED;
+ }
+
+ if (dir_tx) {
+ return USB_TXCSRL(ep) & USB_TXCSRL_STALLED;
+ } else {
+ return USB_RXCSRL(ep) & USB_RXCSRL_STALLED;
+ }
+}
+
+static void lm4f_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
+{
+ (void)usbd_dev;
+ (void)addr;
+ (void)nak;
+
+ /* NAK's are handled automatically by hardware. Move along. */
+}
+
+static uint16_t lm4f_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len)
+{
+ const uint8_t ep = addr & 0xf;
+ uint16_t i;
+
+ (void)usbd_dev;
+
+ /* Don't touch the FIFO if there is still a packet being transmitted */
+ if (ep == 0 && (USB_CSRL0 & USB_CSRL0_TXRDY)) {
+ return 0;
+ } else if (USB_TXCSRL(ep) & USB_TXCSRL_TXRDY) {
+ return 0;
+ }
+
+ /*
+ * We don't need to worry about buf not being aligned. If it's not,
+ * the reads are downgraded to 8-bit in hardware. We lose a bit of
+ * performance, but we don't crash.
+ */
+ for (i = 0; i < (len & ~0x3); i += 4) {
+ USB_FIFO32(ep) = *((uint32_t *)(buf + i));
+ }
+ if (len & 0x2) {
+ USB_FIFO16(ep) = *((uint16_t *)(buf + i));
+ i += 2;
+ }
+ if (len & 0x1) {
+ USB_FIFO8(ep) = *((uint8_t *)(buf + i));
+ i += 1;
+ }
+
+ if (ep == 0) {
+ /*
+ * EP0 is very special. We should only set DATAEND when we
+ * transmit the last packet in the transaction. A transaction
+ * that is a multiple of 64 bytes will end with a zero-length
+ * packet, so our check is sane.
+ */
+ if (len != 64) {
+ USB_CSRL0 |= USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
+ } else {
+ USB_CSRL0 |= USB_CSRL0_TXRDY;
+ }
+ } else {
+ USB_TXCSRL(ep) |= USB_TXCSRL_TXRDY;
+ }
+
+ return i;
+}
+
+static uint16_t lm4f_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
+ void *buf, uint16_t len)
+{
+ (void)usbd_dev;
+
+ uint16_t rlen;
+ uint8_t ep = addr & 0xf;
+
+ uint16_t fifoin = USB_RXCOUNT(ep);
+
+ rlen = (fifoin > len) ? len : fifoin;
+
+ /*
+ * We don't need to worry about buf not being aligned. If it's not,
+ * the writes are downgraded to 8-bit in hardware. We lose a bit of
+ * performance, but we don't crash.
+ */
+ for (len = 0; len < (rlen & ~0x3); len += 4) {
+ *((uint32_t *)(buf + len)) = USB_FIFO32(ep);
+ }
+ if (rlen & 0x2) {
+ *((uint16_t *)(buf + len)) = USB_FIFO16(ep);
+ len += 2;
+ }
+ if (rlen & 0x1) {
+ *((uint8_t *)(buf + len)) = USB_FIFO8(ep);
+ }
+
+ if (ep == 0) {
+ /*
+ * Clear RXRDY
+ * Datasheet says that DATAEND must also be set when clearing
+ * RXRDY. We don't do that. If did this when transmitting a
+ * packet larger than 64 bytes, only the first 64 bytes would
+ * be transmitted, followed by a handshake. The host would only
+ * get 64 bytes, seeing it as a malformed packet. Usually, we
+ * would not get past enumeration.
+ */
+ USB_CSRL0 |= USB_CSRL0_RXRDYC;
+
+ } else {
+ USB_RXCSRL(ep) &= ~USB_RXCSRL_RXRDY;
+ }
+
+ return rlen;
+}
+
+static void lm4f_poll(usbd_device *usbd_dev)
+{
+ void (*tx_cb)(usbd_device *usbd_dev, uint8_t ea);
+ void (*rx_cb)(usbd_device *usbd_dev, uint8_t ea);
+ int i;
+
+ /*
+ * The initial state of these registers might change, as we process the
+ * interrupt, but we need the initial state in order to decide how to
+ * handle events.
+ */
+ const uint8_t usb_is = USB_IS;
+ const uint8_t usb_rxis = USB_RXIS;
+ const uint8_t usb_txis = USB_TXIS;
+ const uint8_t usb_csrl0 = USB_CSRL0;
+
+ if ((usb_is & USB_IM_SUSPEND) && (usbd_dev->user_callback_suspend)) {
+ usbd_dev->user_callback_suspend();
+ }
+
+ if ((usb_is & USB_IM_RESUME) && (usbd_dev->user_callback_resume)) {
+ usbd_dev->user_callback_resume();
+ }
+
+ if (usb_is & USB_IM_RESET) {
+ _usbd_reset(usbd_dev);
+ }
+
+ if ((usb_is & USB_IM_SOF) && (usbd_dev->user_callback_sof)) {
+ usbd_dev->user_callback_sof();
+ }
+
+ if (usb_txis & USB_EP0) {
+ /*
+ * The EP0 bit in USB_TXIS is special. It tells us that
+ * something happened on EP0, but does not tell us what. This
+ * bit does not necessarily tell us that a packet was
+ * transmitted, so we have to go through all the possibilities
+ * to figure out exactly what did. Only after we've exhausted
+ * all other possibilities, can we assume this is a EPO
+ * "transmit complete" interrupt.
+ */
+ if (usb_csrl0 & USB_CSRL0_RXRDY) {
+ enum _usbd_transaction type;
+ type = (usbd_dev->control_state.state != DATA_OUT &&
+ usbd_dev->control_state.state != LAST_DATA_OUT)
+ ? USB_TRANSACTION_SETUP :
+ USB_TRANSACTION_OUT;
+
+ if (usbd_dev->user_callback_ctr[0][type]) {
+ usbd_dev->
+ user_callback_ctr[0][type](usbd_dev, 0);
+ }
+
+
+ } else {
+ tx_cb = usbd_dev->user_callback_ctr[0]
+ [USB_TRANSACTION_IN];
+
+ /*
+ * EP0 bit in TXIS is set not only when a packet is
+ * finished transmitting, but also when RXRDY is set, or
+ * when we set TXRDY to transmit a packet. If any of
+ * those are the case, then we do not want to call our
+ * IN callback, since the state machine will be in the
+ * wrong state, and we'll just stall our control
+ * endpoint.
+ * In fact, the only way to know if it's time to call
+ * our TX callback is to know what to expect. The
+ * hardware does not tell us what sort of transaction
+ * this is. We need to work with the state machine to
+ * figure it all out. See [1] for details.
+ */
+ if ((usbd_dev->control_state.state != DATA_IN) &&
+ (usbd_dev->control_state.state != LAST_DATA_IN) &&
+ (usbd_dev->control_state.state != STATUS_IN)) {
+ return;
+ }
+
+ if (tx_cb) {
+ tx_cb(usbd_dev, 0);
+ }
+ }
+ }
+
+ /* See which interrupt occurred */
+ for (i = 1; i < 8; i++) {
+ tx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_IN];
+ rx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_OUT];
+
+ if ((usb_txis & (1 << i)) && tx_cb) {
+ tx_cb(usbd_dev, i);
+ }
+
+ if ((usb_rxis & (1 << i)) && rx_cb) {
+ rx_cb(usbd_dev, i);
+ }
+ }
+
+
+}
+
+static void lm4f_disconnect(usbd_device *usbd_dev, bool disconnected)
+{
+ (void)usbd_dev;
+
+ /*
+ * This is all it takes:
+ * usbd_disconnect(dev, 1) followed by usbd_disconnect(dev, 0)
+ * causes the device to re-enumerate and re-configure properly.
+ */
+ if (disconnected) {
+ lm4f_usb_soft_disconnect();
+ } else {
+ lm4f_usb_soft_connect();
+ }
+}
+
+/*
+ * A static struct works as long as we have only one USB peripheral. If we
+ * meet LM4Fs with more than one USB, then we need to rework this approach.
+ */
+static struct _usbd_device usbd_dev;
+
+/** Initialize the USB device controller hardware of the LM4F. */
+static usbd_device *lm4f_usbd_init(void)
+{
+ int i;
+
+ /* Start the USB clock */
+ periph_clock_enable(RCC_USB0);
+ /* Enable the USB PLL interrupts - used to assert PLL lock */
+ SYSCTL_IMC |= (SYSCTL_IMC_USBPLLLIM | SYSCTL_IMC_PLLLIM);
+ rcc_usb_pll_on();
+
+ /* Make sure we're disconnected. We'll reconnect later */
+ lm4f_usb_soft_disconnect();
+
+ /* Software reset USB */
+ SYSCTL_SRUSB = 1;
+ for (i = 0; i < 1000; i++) {
+ __asm__("nop");
+ }
+ SYSCTL_SRUSB = 0;
+
+ /*
+ * Wait for the PLL to lock before soft connecting
+ * This will result in a deadlock if the system clock is not setup
+ * correctly (clock from main oscillator).
+ */
+ /* Wait for it */
+ i = 0;
+ while ((SYSCTL_RIS & SYSCTL_RIS_USBPLLLRIS) == 0) {
+ i++;
+ if (i > 0xffff) {
+ return 0;
+ }
+ }
+
+ /* Now connect to USB */
+ lm4f_usb_soft_connect();
+
+ /* No FIFO allocated yet, but the first 64 bytes are still reserved */
+ usbd_dev.fifo_mem_top = 64;
+
+ return &usbd_dev;
+}
+
+/* What is this thing even good for */
+#define RX_FIFO_SIZE 512
+
+const struct _usbd_driver lm4f_usb_driver = {
+ .init = lm4f_usbd_init,
+ .set_address = lm4f_set_address,
+ .ep_setup = lm4f_ep_setup,
+ .ep_reset = lm4f_endpoints_reset,
+ .ep_stall_set = lm4f_ep_stall_set,
+ .ep_stall_get = lm4f_ep_stall_get,
+ .ep_nak_set = lm4f_ep_nak_set,
+ .ep_write_packet = lm4f_ep_write_packet,
+ .ep_read_packet = lm4f_ep_read_packet,
+ .poll = lm4f_poll,
+ .disconnect = lm4f_disconnect,
+ .base_address = USB_BASE,
+ .set_address_before_status = false,
+ .rx_fifo_size = RX_FIFO_SIZE,
+};
+/**
+ * @endcond
+ */
+
+/**
+ * @}
+ */
diff --git a/libopencm3/lib/lpc13xx/Makefile b/libopencm3/lib/lpc13xx/Makefile
new file mode 100644
index 0000000..f396d5b
--- /dev/null
+++ b/libopencm3/lib/lpc13xx/Makefile
@@ -0,0 +1,40 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lpc13xx
+SRCLIBDIR ?= ..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DLPC13XX
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o
+
+VPATH += ../cm3
+
+include ../Makefile.include
diff --git a/libopencm3/lib/lpc13xx/gpio.c b/libopencm3/lib/lpc13xx/gpio.c
new file mode 100644
index 0000000..271572b
--- /dev/null
+++ b/libopencm3/lib/lpc13xx/gpio.c
@@ -0,0 +1,42 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup LPC13xx
+
+@brief <b>libopencm3 LPC13xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+LGPL License Terms @ref lgpl_license
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/lpc13xx/gpio.h>
+
+void gpio_set(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_DATA(gpioport) = gpios;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld b/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld
new file mode 100644
index 0000000..bd0005c
--- /dev/null
+++ b/libopencm3/lib/lpc13xx/libopencm3_lpc13xx.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC13XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/lpc17xx/Makefile b/libopencm3/lib/lpc17xx/Makefile
new file mode 100644
index 0000000..4b49df4
--- /dev/null
+++ b/libopencm3/lib/lpc17xx/Makefile
@@ -0,0 +1,40 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lpc17xx
+SRCLIBDIR ?= ..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -O0 -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DLPC17XX
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o
+
+VPATH += ../cm3
+
+include ../Makefile.include
diff --git a/libopencm3/lib/lpc17xx/gpio.c b/libopencm3/lib/lpc17xx/gpio.c
new file mode 100644
index 0000000..4831af7
--- /dev/null
+++ b/libopencm3/lib/lpc17xx/gpio.c
@@ -0,0 +1,48 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup LPC17xx
+
+@brief <b>libopencm3 LPC17xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/lpc17xx/gpio.h>
+
+void gpio_set(uint32_t gpioport, uint32_t gpios)
+{
+ GPIO_SET(gpioport) = gpios;
+}
+
+void gpio_clear(uint32_t gpioport, uint32_t gpios)
+{
+ GPIO_CLR(gpioport) = gpios;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld b/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld
new file mode 100644
index 0000000..bd0005c
--- /dev/null
+++ b/libopencm3/lib/lpc17xx/libopencm3_lpc17xx.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC13XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/lpc43xx/gpio.c b/libopencm3/lib/lpc43xx/gpio.c
new file mode 100644
index 0000000..935feb3
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/gpio.c
@@ -0,0 +1,53 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup LPC43xx
+
+@brief <b>libopencm3 LPC43xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/lpc43xx/gpio.h>
+
+void gpio_set(uint32_t gpioport, uint32_t gpios)
+{
+ GPIO_SET(gpioport) = gpios;
+}
+
+void gpio_clear(uint32_t gpioport, uint32_t gpios)
+{
+ GPIO_CLR(gpioport) = gpios;
+}
+
+void gpio_toggle(uint32_t gpioport, uint32_t gpios)
+{
+ GPIO_NOT(gpioport) = gpios;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc43xx/i2c.c b/libopencm3/lib/lpc43xx/i2c.c
new file mode 100644
index 0000000..0d6c4c6
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/i2c.c
@@ -0,0 +1,102 @@
+/** @defgroup i2c_file I2C
+
+@ingroup LPC43xx
+
+@brief <b>libopencm3 LPC43xx I2C</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Michael Ossmann <mike@ossmann.com>
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This is a very minimal I2C driver just to make sure we can get the
+ * peripheral working.
+ */
+
+/**@{*/
+
+#include <libopencm3/lpc43xx/i2c.h>
+#include <libopencm3/lpc43xx/scu.h>
+#include <libopencm3/lpc43xx/cgu.h>
+
+void i2c0_init(const uint16_t duty_cycle_count)
+{
+ /* enable input on SCL and SDA pins */
+ SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
+
+ I2C0_SCLH = duty_cycle_count;
+ I2C0_SCLL = duty_cycle_count;
+
+ /* clear the control bits */
+ I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC
+ | I2C_CONCLR_STAC | I2C_CONCLR_I2ENC);
+
+ /* enable I2C0 */
+ I2C0_CONSET = I2C_CONSET_I2EN;
+}
+
+/* transmit start bit */
+void i2c0_tx_start(void)
+{
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_STA;
+ while (!(I2C0_CONSET & I2C_CONSET_SI));
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+}
+
+/* transmit data byte */
+void i2c0_tx_byte(uint8_t byte)
+{
+ if (I2C0_CONSET & I2C_CONSET_STA) {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ I2C0_DAT = byte;
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ while (!(I2C0_CONSET & I2C_CONSET_SI));
+}
+
+/* receive data byte */
+uint8_t i2c0_rx_byte(void)
+{
+ if (I2C0_CONSET & I2C_CONSET_STA) {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ while (!(I2C0_CONSET & I2C_CONSET_SI));
+ return I2C0_DAT;
+}
+
+/* transmit stop bit */
+void i2c0_stop(void)
+{
+ if (I2C0_CONSET & I2C_CONSET_STA) {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ I2C0_CONSET = I2C_CONSET_STO;
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc43xx/ipc.c b/libopencm3/lib/lpc43xx/ipc.c
new file mode 100644
index 0000000..c26931f
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/ipc.c
@@ -0,0 +1,58 @@
+/*
+* This file is part of the libopencm3 project.
+*
+* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+*
+* This library is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This library 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libopencm3/lpc43xx/ipc.h>
+#include <libopencm3/lpc43xx/creg.h>
+#include <libopencm3/lpc43xx/rgu.h>
+
+/* Set M0 in reset mode */
+void ipc_halt_m0(void)
+{
+ volatile uint32_t rst_active_status1;
+
+ /* Check if M0 is reset by reading status */
+ rst_active_status1 = RESET_ACTIVE_STATUS1;
+
+ /* If the M0 has reset not asserted, halt it... */
+ while (rst_active_status1 & RESET_CTRL1_M0APP_RST) {
+ RESET_CTRL1 = ((~rst_active_status1) | RESET_CTRL1_M0APP_RST);
+ rst_active_status1 = RESET_ACTIVE_STATUS1;
+ }
+}
+
+void ipc_start_m0(uint32_t cm0_baseaddr)
+{
+ volatile uint32_t rst_active_status1;
+
+ /* Set M0 memory mapping to point to start of M0 image */
+ CREG_M0APPMEMMAP = cm0_baseaddr;
+
+ /* Start/run M0 core */
+
+ /* Release Slave from reset, first read status */
+ rst_active_status1 = RESET_ACTIVE_STATUS1;
+
+ /* If the M0 is being held in reset, release it */
+ /* 1 = no reset, 0 = reset */
+ while (!(rst_active_status1 & RESET_CTRL1_M0APP_RST)) {
+ RESET_CTRL1 = ((~rst_active_status1) & ~RESET_CTRL1_M0APP_RST);
+ rst_active_status1 = RESET_ACTIVE_STATUS1;
+ }
+}
+
diff --git a/libopencm3/lib/lpc43xx/m0/Makefile b/libopencm3/lib/lpc43xx/m0/Makefile
new file mode 100644
index 0000000..65114c2
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m0/Makefile
@@ -0,0 +1,43 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+## Copyright (C) 2012/2013 Benjamin Vernoux <titanmkd@gmail.com>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lpc43xx_m0
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -O2 -g3 -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m0 -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DLPC43XX -DLPC43XX_M0
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+
+# LPC43xx common files for M4 / M0
+OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o
+
+#LPC43xx M0 specific file + Generic LPC43xx M4/M0 files
+OBJS = $(OBJ_LPC43XX)
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
diff --git a/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_m0.ld
diff --git a/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld
new file mode 100644
index 0000000..fedd3e1
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m0/libopencm3_lpc43xx_ram_only_m0.ld
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ * Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC43XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ . = ORIGIN(ram_ahb2);
+
+ .text : {
+ . = ALIGN(0x400);
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >ram_ahb2
+
+ /* exception index - required due to libgcc.a issuing /0 exceptions */
+ __exidx_start = .;
+ .ARM.exidx : {
+ *(.ARM.exidx*)
+ } > ram_ahb2
+ __exidx_end = .;
+
+ _etext = .;
+
+ . = ORIGIN(ram_ahb2);
+
+ .data : {
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ } >ram_ahb2
+
+ _data = .;
+ _edata = .;
+
+ .bss : {
+ _bss = .;
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram_ahb2
+
+ /* exception unwind data - required due to libgcc.a issuing /0 exceptions */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >ram_ahb2
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support - discard it for now.
+ */
+ /DISCARD/ : { *(.ARM.exidx) }
+
+ end = .;
+
+ /* Leave room above stack for IAP to run. */
+ __StackTop = ORIGIN(ram_ahb2) + LENGTH(ram_ahb2) - 32;
+ PROVIDE(_stack = __StackTop);
+}
diff --git a/libopencm3/lib/lpc43xx/m4/Makefile b/libopencm3/lib/lpc43xx/m4/Makefile
new file mode 100644
index 0000000..a3d3b03
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m4/Makefile
@@ -0,0 +1,50 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+## Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_lpc43xx
+SRCLIBDIR ?= ../..
+
+FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -O2 -g3 \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m4 -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD \
+ $(FP_FLAGS) -DLPC43XX -DLPC43XX_M4
+
+ARFLAGS = rcs
+
+# LPC43xx common files for M4 / M0
+OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o
+
+#LPC43xx M4 specific file + Generic LPC43xx M4/M0 files
+OBJS = $(OBJ_LPC43XX) ipc.o
+
+VPATH += ../:../../cm3
+
+include ../../Makefile.include
diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld
new file mode 100644
index 0000000..c289b35
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx.ld
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ * Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC43XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ . = ALIGN(0x400);
+ _text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+
+ /* exception index - required due to libgcc.a issuing /0 exceptions */
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+ _etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+ _etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+
+ . = ORIGIN(ram_local2);
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram_local2 AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ _data_rom = LOADADDR (.data) + ORIGIN(rom);
+ _edata_rom = _data_rom + SIZEOF (.data);
+
+ .bss : {
+ _bss = .;
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram_local2
+
+ /* exception unwind data - required due to libgcc.a issuing /0 exceptions */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >ram_local2
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+
+ /* Leave room above stack for IAP to run. */
+ __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
+ PROVIDE(_stack = __StackTop);
+}
diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld
new file mode 100644
index 0000000..5bcdea6
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_ram_only.ld
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ * Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC43XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ . = ORIGIN(ram_local1);
+
+ .text : {
+ . = ALIGN(0x400);
+ _text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >ram_local1
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >ram_local1
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >ram_local1
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >ram_local1
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >ram_local1
+
+ /* exception index - required due to libgcc.a issuing /0 exceptions */
+ __exidx_start = .;
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } > ram_local1
+
+ . = ALIGN(4);
+ _etext = .;
+ _etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+ _etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
+
+ . = ORIGIN(ram_local2);
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram_local2
+ _data_loadaddr = LOADADDR(.data);
+
+ /* Running from RAM only, loading the .elf will initialize data for us. */
+ _data_rom = .;
+ _edata_rom = .;
+
+ _data = .;
+ _edata = .;
+
+ .bss : {
+ _bss = .;
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram_local2
+
+ /* exception unwind data - required due to libgcc.a issuing /0 exceptions */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >ram_local2
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support - discard it for now.
+ */
+ /DISCARD/ : { *(.ARM.exidx) }
+
+ end = .;
+
+ /* Leave room above stack for IAP to run. */
+ __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
+ PROVIDE(_stack = __StackTop);
+}
diff --git a/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld
new file mode 100644
index 0000000..e50040e
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m4/libopencm3_lpc43xx_rom_to_ram.ld
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ * Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for LPC43XX targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ . = ALIGN(0x400);
+ _text_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1); /* Start of Code in RAM */
+
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+
+ /* exception index - required due to libgcc.a issuing /0 exceptions */
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+ _etext_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1);
+ _etext_rom = (. - ORIGIN(rom)) + ORIGIN(rom_flash);
+
+ . = ORIGIN(ram_local2);
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram_local2 AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ _data_rom = LOADADDR (.data) + ORIGIN(rom_flash);
+ _edata_rom = _data_rom + SIZEOF (.data);
+
+ .bss : {
+ _bss = .;
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram_local2
+
+ /* exception unwind data - required due to libgcc.a issuing /0 exceptions */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >ram_local2
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+
+ /* Leave room above stack for IAP to run. */
+ __StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
+ PROVIDE(_stack = __StackTop);
+}
diff --git a/libopencm3/lib/lpc43xx/m4/vector_chipset.c b/libopencm3/lib/lpc43xx/m4/vector_chipset.c
new file mode 100644
index 0000000..270e30e
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/m4/vector_chipset.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+ * Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/common.h>
+
+extern unsigned _etext_ram, _text_ram, _etext_rom;
+
+#define CREG_M4MEMMAP MMIO32((0x40043000U + 0x100))
+
+static void pre_main(void)
+{
+ volatile unsigned *src, *dest;
+
+ /* Copy the code from ROM to Real RAM (if enabled) */
+ if ((&_etext_ram-&_text_ram) > 0) {
+ src = &_etext_rom-(&_etext_ram-&_text_ram);
+ /* Change Shadow memory to ROM (for Debug Purpose in case Boot
+ * has not set correctly the M4MEMMAP because of debug)
+ */
+ CREG_M4MEMMAP = (unsigned long)src;
+
+ for (dest = &_text_ram; dest < &_etext_ram; ) {
+ *dest++ = *src++;
+ }
+
+ /* Change Shadow memory to Real RAM */
+ CREG_M4MEMMAP = (unsigned long)&_text_ram;
+
+ /* Continue Execution in RAM */
+ }
+}
diff --git a/libopencm3/lib/lpc43xx/scu.c b/libopencm3/lib/lpc43xx/scu.c
new file mode 100644
index 0000000..c20cd84
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/scu.c
@@ -0,0 +1,52 @@
+/** @defgroup scu_file System Control Unit
+
+@ingroup LPC43xx
+
+@brief <b>libopencm3 LPC43xx System Control Unit</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Benjamin Vernoux <titanmkd@gmail.com>
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+* This file is part of the libopencm3 project.
+*
+* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+*
+* This library is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This library 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**@{*/
+
+#include <libopencm3/lpc43xx/scu.h>
+
+/* For pin_conf_normal value see scu.h define SCU_CONF_XXX or Configuration for
+ * different I/O pins types
+ */
+void scu_pinmux(scu_grp_pin_t group_pin, uint32_t scu_conf)
+{
+ MMIO32(group_pin) = scu_conf;
+}
+
+/* For other special SCU register USB1, I2C0, ADC0/1, DAC, EMC clock delay See
+ * scu.h
+ */
+
+/* For Pin interrupt select register see scu.h SCU_PINTSEL0 & SCU_PINTSEL1 */
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc43xx/ssp.c b/libopencm3/lib/lpc43xx/ssp.c
new file mode 100644
index 0000000..b63ec9b
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/ssp.c
@@ -0,0 +1,140 @@
+/** @defgroup ssp_file SSP
+
+@ingroup LPC43xx
+
+@brief <b>libopencm3 LPC43xx SSP</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Benjamin Vernoux <titanmkd@gmail.com>
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/lpc43xx/ssp.h>
+#include <libopencm3/lpc43xx/cgu.h>
+
+/* Disable SSP */
+void ssp_disable(ssp_num_t ssp_num)
+{
+ uint32_t ssp_port;
+
+ if (ssp_num == SSP0_NUM) {
+ ssp_port = SSP0;
+ } else {
+ ssp_port = SSP1;
+ }
+ /* Disable SSP */
+ SSP_CR1(ssp_port) = 0x0;
+}
+
+/*
+* SSP Init function
+*/
+void ssp_init(ssp_num_t ssp_num,
+ ssp_datasize_t data_size,
+ ssp_frame_format_t frame_format,
+ ssp_cpol_cpha_t cpol_cpha_format,
+ uint8_t serial_clock_rate,
+ uint8_t clk_prescale,
+ ssp_mode_t mode,
+ ssp_master_slave_t master_slave,
+ ssp_slave_option_t slave_option)
+{
+ uint32_t ssp_port;
+ uint32_t clock;
+
+ if (ssp_num == SSP0_NUM) {
+ ssp_port = SSP0;
+ } else {
+ ssp_port = SSP1;
+ }
+
+ /* use PLL1 as clock source for SSP1 */
+ CGU_BASE_SSP1_CLK =
+ CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1)
+ | CGU_BASE_SSP1_CLK_AUTOBLOCK;
+
+ /* Disable SSP before to configure it */
+ SSP_CR1(ssp_port) = 0x0;
+
+ /* Configure SSP */
+ clock = serial_clock_rate;
+ SSP_CPSR(ssp_port) = clk_prescale;
+ SSP_CR0(ssp_port) =
+ (data_size | frame_format | cpol_cpha_format | (clock<<8));
+
+ /* Enable SSP */
+ SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option);
+}
+
+static void ssp_wait_until_not_busy(ssp_num_t ssp_num)
+{
+ uint32_t ssp_port;
+
+ if (ssp_num == SSP0_NUM) {
+ ssp_port = SSP0;
+ } else {
+ ssp_port = SSP1;
+ }
+
+ while ((SSP_SR(ssp_port) & SSP_SR_BSY));
+}
+
+/* This Function Wait Data TX Ready, and Write Data to SSP */
+uint16_t ssp_transfer(ssp_num_t ssp_num, uint16_t data)
+{
+ uint32_t ssp_port;
+
+ if (ssp_num == SSP0_NUM) {
+ ssp_port = SSP0;
+ } else {
+ ssp_port = SSP1;
+ }
+
+ /* Wait Until FIFO not full */
+ while ((SSP_SR(ssp_port) & SSP_SR_TNF) == 0);
+
+ SSP_DR(ssp_port) = data;
+
+ /* Wait for not busy, since we're controlling CS# of
+ * devices manually and need to wait for the data to
+ * be sent. It may also be important to wait here
+ * in case we're configuring devices via SPI and also
+ * with GPIO control -- we need to know when SPI
+ * commands are effective before altering a device's
+ * state with GPIO. I'm thinking the MAX2837, for
+ * example...
+ */
+ ssp_wait_until_not_busy(ssp_num);
+
+ /* Wait Until Data Received (Rx FIFO not Empty) */
+ while ((SSP_SR(ssp_port) & SSP_SR_RNE) == 0);
+
+ return SSP_DR(ssp_port);
+}
+
+
+/**@}*/
+
diff --git a/libopencm3/lib/lpc43xx/timer.c b/libopencm3/lib/lpc43xx/timer.c
new file mode 100644
index 0000000..f263c24
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/timer.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Ben Gamari <bgamari@physics.umass.edu>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This provides the code for the "next gen" EXTI block provided in F2/F4/L1
+ * devices. (differences only in the source selection)
+ */
+
+#include <libopencm3/lpc43xx/timer.h>
+
+void timer_reset(uint32_t timer_peripheral)
+{
+ TIMER_TCR(timer_peripheral) |= TIMER_TCR_CRST;
+ TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CRST;
+}
+
+void timer_enable_counter(uint32_t timer_peripheral)
+{
+ TIMER_TCR(timer_peripheral) |= TIMER_TCR_CEN;
+}
+
+void timer_disable_counter(uint32_t timer_peripheral)
+{
+ TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CEN;
+}
+
+void timer_set_counter(uint32_t timer_peripheral, uint32_t count)
+{
+ TIMER_TC(timer_peripheral) = count;
+}
+
+uint32_t timer_get_counter(uint32_t timer_peripheral)
+{
+ return TIMER_TC(timer_peripheral);
+}
+
+uint32_t timer_get_prescaler(uint32_t timer_peripheral)
+{
+ return TIMER_PR(timer_peripheral);
+}
+
+void timer_set_prescaler(uint32_t timer_peripheral, uint32_t prescaler)
+{
+ TIMER_PR(timer_peripheral) = prescaler;
+}
+
+void timer_set_mode(uint32_t timer_peripheral, uint32_t mode)
+{
+ TIMER_CTCR(timer_peripheral) = mode |
+ (TIMER_CTCR(timer_peripheral) & TIMER_CTCR_MODE_MASK);
+}
+
+void timer_set_count_input(uint32_t timer_peripheral, uint32_t input)
+{
+ TIMER_CTCR(timer_peripheral) = input |
+ (TIMER_CTCR(timer_peripheral) & TIMER_CTCR_CINSEL_MASK);
+}
+
diff --git a/libopencm3/lib/lpc43xx/uart.c b/libopencm3/lib/lpc43xx/uart.c
new file mode 100644
index 0000000..3168ce2
--- /dev/null
+++ b/libopencm3/lib/lpc43xx/uart.c
@@ -0,0 +1,243 @@
+/*
+* This file is part of the libopencm3 project.
+*
+* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
+*
+* This library is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This library 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libopencm3/lpc43xx/uart.h>
+#include <libopencm3/lpc43xx/cgu.h>
+
+#define UART_SRC_32K 0x00
+#define UART_SRC_IRC 0x01
+#define UART_SRC_ENET_RX 0x02
+#define UART_SRC_ENET_TX 0x03
+#define UART_SRC_GP_CLKIN 0x04
+#define UART_SRC_XTAL 0x06
+#define UART_SRC_PLL0USB 0x07
+#define UART_SRC_PLL0AUDIO 0x08
+#define UART_SRC_PLL1 0x09
+#define UART_SRC_IDIVA 0x0C
+#define UART_SRC_IDIVB 0x0D
+#define UART_SRC_IDIVC 0x0E
+#define UART_SRC_IDIVD 0x0F
+#define UART_SRC_IDIVE 0x10
+
+#define UART_CGU_AUTOBLOCK_CLOCK_BIT 11
+/* clock source selection (5 bits) */
+#define UART_CGU_BASE_CLK_SEL_SHIFT 24
+
+uint32_t dummy_read;
+
+/*
+* UART Init function
+*/
+void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits,
+ uart_stopbit_t data_nb_stop, uart_parity_t data_parity,
+ uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval)
+{
+ uint32_t lcr_config;
+ uint32_t uart_port;
+
+ uart_port = uart_num;
+
+ switch (uart_num) {
+ case UART0_NUM:
+ /* use PLL1 as clock source for UART0 */
+ CGU_BASE_UART0_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
+ (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
+ break;
+
+ case UART1_NUM:
+ /* use PLL1 as clock source for UART1 */
+ CGU_BASE_UART1_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
+ (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
+ break;
+
+ case UART2_NUM:
+ /* use PLL1 as clock source for UART2 */
+ CGU_BASE_UART2_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
+ (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
+ break;
+
+ case UART3_NUM:
+ /* use PLL1 as clock source for UART3 */
+ CGU_BASE_UART3_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
+ (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
+ break;
+
+ default:
+ return; /* error */
+ }
+
+ /* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared)*/
+ UART_FCR(uart_port) = (UART_FCR_FIFO_EN | UART_FCR_RX_RS |
+ UART_FCR_TX_RS);
+ /* Disable FIFO */
+ UART_FCR(uart_port) = 0;
+
+ /* Dummy read (to clear existing data) */
+ while (UART_LSR(uart_port) & UART_LSR_RDR) {
+ dummy_read = UART_RBR(uart_port);
+ }
+
+ /* Wait end of TX & disable TX */
+ UART_TER(uart_port) = UART_TER_TXEN;
+
+ /* Wait for current transmit complete */
+ while (!(UART_LSR(uart_port) & UART_LSR_THRE));
+
+ /* Disable Tx */
+ UART_TER(uart_port) = 0;
+
+ /* Disable interrupt */
+ UART_IER(uart_port) = 0;
+
+ /* Set LCR to default state */
+ UART_LCR(uart_port) = 0;
+
+ /* Set ACR to default state */
+ UART_ACR(uart_port) = 0;
+
+ /* Dummy Read to Clear Status */
+ dummy_read = UART_LSR(uart_port);
+
+ /*
+ Table 835. USART Fractional Divider Register:
+ UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) )
+ The value of MULVAL and DIVADDVAL should comply to the following
+ conditions:
+ 1. 1 <= MULVAL <= 15
+ 2. 0 <= DIVADDVAL <= 14
+ 3. DIVADDVAL < MULVAL
+ */
+
+ /* Set DLAB Bit */
+ UART_LCR(uart_port) |= UART_LCR_DLAB_EN;
+ UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor);
+ UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor);
+ /* Clear DLAB Bit */
+ UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
+ UART_FDR(uart_port) = UART_FDR_BITMASK &
+ (UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval));
+
+ /* Read LCR config & Force Enable of Divisor Latches Access */
+ lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) &
+ UART_LCR_BITMASK;
+ lcr_config |= data_nb_bits; /* Set Nb Data Bits */
+ lcr_config |= data_nb_stop; /* Set Nb Stop Bits */
+ lcr_config |= data_parity; /* Set Data Parity */
+
+ /* Write LCR (only 8bits) */
+ UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK);
+
+ /* Enable TX */
+ UART_TER(uart_port) = UART_TER_TXEN;
+}
+
+/*
+* This Function return if data are received or not received.
+*/
+uart_rx_data_ready_t uart_rx_data_ready(uart_num_t uart_num)
+{
+ uint32_t uart_port;
+ uint8_t uart_status;
+ uart_rx_data_ready_t data_ready;
+
+ uart_port = uart_num;
+
+ uart_status = UART_LSR(uart_port) & 0xFF;
+
+ /* Check Error */
+ if ((uart_status & UART_LSR_ERROR_MASK) == 0) {
+ /* No errors check if data is ready */
+ if ((uart_status & UART_LSR_RDR) == 0) {
+ data_ready = UART_RX_NO_DATA;
+ } else {
+ data_ready = UART_RX_DATA_READY;
+ }
+ } else {
+ /* UART Error */
+ data_ready = UART_RX_DATA_ERROR;
+ }
+
+ return data_ready;
+}
+
+/*
+* This Function Wait until Data RX Ready, and return Data Read from UART.
+*/
+uint8_t uart_read(uart_num_t uart_num)
+{
+ uint32_t uart_port;
+ uint8_t uart_val;
+
+ uart_port = uart_num;
+
+ /* Wait Until Data Received (Rx Data Not Ready) */
+ while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0);
+
+ uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
+
+ return uart_val;
+}
+
+/*
+* This Function Wait until Data RX Ready, and return Data Read from UART.
+*/
+uint8_t uart_read_timeout(uart_num_t uart_num, uint32_t rx_timeout_nb_cycles,
+ uart_error_t *error)
+{
+ uint32_t uart_port;
+ uint8_t uart_val;
+ uint32_t counter;
+
+ uart_port = uart_num;
+
+ /* Wait Until Data Received (Rx Data Not Ready) */
+ counter = 0;
+ while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0) {
+ if (rx_timeout_nb_cycles > 0) {
+ counter++;
+ if (counter >= rx_timeout_nb_cycles) {
+ *error = UART_TIMEOUT_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
+
+ /* Clear error */
+ *error = UART_NO_ERROR;
+
+ return uart_val;
+}
+
+/* This Function Wait Data TX Ready, and Write Data to UART
+ if rx_timeout_nb_cycles = 0 Infinite wait
+*/
+void uart_write(uart_num_t uart_num, uint8_t data)
+{
+ uint32_t uart_port;
+
+ uart_port = uart_num;
+
+ /* Wait Until FIFO not full */
+ while ((UART_LSR(uart_port) & UART_LSR_THRE) == 0);
+
+ UART_THR(uart_port) = data;
+}
+
diff --git a/libopencm3/lib/sam/3a/Makefile b/libopencm3/lib/sam/3a/Makefile
new file mode 100644
index 0000000..d3e558c
--- /dev/null
+++ b/libopencm3/lib/sam/3a/Makefile
@@ -0,0 +1,37 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_sam3a
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSAM3A
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o pmc.o usart.o
+
+VPATH += ../../usb:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/sam/3a/libopencm3_sam3a.ld b/libopencm3/lib/sam/3a/libopencm3_sam3a.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/sam/3a/libopencm3_sam3a.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/sam/3n/Makefile b/libopencm3/lib/sam/3n/Makefile
new file mode 100644
index 0000000..e6d4ccf
--- /dev/null
+++ b/libopencm3/lib/sam/3n/Makefile
@@ -0,0 +1,37 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_sam3n
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSAM3N
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o pmc.o usart.o
+
+VPATH += ../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/sam/3n/libopencm3_sam3n.ld b/libopencm3/lib/sam/3n/libopencm3_sam3n.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/sam/3n/libopencm3_sam3n.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/sam/3s/Makefile b/libopencm3/lib/sam/3s/Makefile
new file mode 100644
index 0000000..45a8a7a
--- /dev/null
+++ b/libopencm3/lib/sam/3s/Makefile
@@ -0,0 +1,38 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2014 Felix Held <felix-libopencm3@felixheld.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_sam3s
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSAM3S
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o pmc.o usart.o
+
+VPATH += ../../usb:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/sam/3s/libopencm3_sam3s.ld b/libopencm3/lib/sam/3s/libopencm3_sam3s.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/sam/3s/libopencm3_sam3s.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/sam/3u/Makefile b/libopencm3/lib/sam/3u/Makefile
new file mode 100644
index 0000000..e0939f3
--- /dev/null
+++ b/libopencm3/lib/sam/3u/Makefile
@@ -0,0 +1,38 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2014 Felix Held <felix-libopencm3@felixheld.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_sam3u
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSAM3U
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o pmc.o usart.o
+
+VPATH += ../../usb:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/sam/3u/libopencm3_sam3u.ld b/libopencm3/lib/sam/3u/libopencm3_sam3u.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/sam/3u/libopencm3_sam3u.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/sam/3x/Makefile b/libopencm3/lib/sam/3x/Makefile
new file mode 100644
index 0000000..de2fa28
--- /dev/null
+++ b/libopencm3/lib/sam/3x/Makefile
@@ -0,0 +1,37 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_sam3x
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSAM3X
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = gpio.o pmc.o usart.o
+
+VPATH += ../../usb:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/sam/3x/libopencm3_sam3x.ld b/libopencm3/lib/sam/3x/libopencm3_sam3x.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/sam/3x/libopencm3_sam3x.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/sam/common/gpio.c b/libopencm3/lib/sam/common/gpio.c
new file mode 100644
index 0000000..75929f8
--- /dev/null
+++ b/libopencm3/lib/sam/common/gpio.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/sam/gpio.h>
+
+void gpio_init(uint32_t port, uint32_t pins, enum gpio_flags flags)
+{
+ switch (flags & 3) {
+ case GPIO_FLAG_GPINPUT:
+ /* input mode doesn't really exist, so we make a high
+ * output in open-drain mode
+ */
+ PIO_SODR(port) = pins;
+ flags |= GPIO_FLAG_OPEN_DRAIN;
+ /* fall through */
+ case GPIO_FLAG_GPOUTPUT:
+ PIO_OER(port) = pins;
+ PIO_PER(port) = pins;
+ break;
+ case GPIO_FLAG_PERIPHA:
+ PIO_ABSR(port) &= ~pins;
+ PIO_PDR(port) = pins;
+ break;
+ case GPIO_FLAG_PERIPHB:
+ PIO_ABSR(port) |= pins;
+ PIO_PDR(port) = pins;
+ }
+
+ if (flags & GPIO_FLAG_OPEN_DRAIN) {
+ PIO_MDER(port) = pins;
+ } else {
+ PIO_MDDR(port) = pins;
+ }
+
+ if (flags & GPIO_FLAG_PULL_UP) {
+ PIO_PUER(port) = pins;
+ } else {
+ PIO_PUDR(port) = pins;
+ }
+}
+
+void gpio_toggle(uint32_t gpioport, uint32_t gpios)
+{
+ uint32_t odsr = PIO_ODSR(gpioport);
+ PIO_CODR(gpioport) = odsr & gpios;
+ PIO_SODR(gpioport) = ~odsr & gpios;
+}
+
diff --git a/libopencm3/lib/sam/common/pmc.c b/libopencm3/lib/sam/common/pmc.c
new file mode 100644
index 0000000..b4e0d7f
--- /dev/null
+++ b/libopencm3/lib/sam/common/pmc.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/sam/pmc.h>
+#include <libopencm3/sam/eefc.h>
+
+/** Default peripheral clock frequency after reset. */
+uint32_t pmc_mck_frequency = 4000000;
+
+void pmc_xtal_enable(bool en, uint8_t startup_time)
+{
+ if (en) {
+ CKGR_MOR = (CKGR_MOR & ~CKGR_MOR_MOSCXTST_MASK) |
+ CKGR_MOR_KEY | CKGR_MOR_MOSCXTEN |
+ (startup_time << 8);
+ while (!(PMC_SR & PMC_SR_MOSCXTS));
+ } else {
+ CKGR_MOR = CKGR_MOR_KEY | (CKGR_MOR & ~CKGR_MOR_MOSCXTEN);
+ }
+}
+
+void pmc_plla_config(uint8_t mul, uint8_t div)
+{
+ CKGR_PLLAR = CKGR_PLLAR_ONE | ((mul - 1) << 16) |
+ CKGR_PLLAR_PLLACOUNT_MASK | div;
+ while (!(PMC_SR & PMC_SR_LOCKA));
+}
+
+void pmc_peripheral_clock_enable(uint8_t pid)
+{
+ if (pid < 32) {
+ PMC_PCER0 = 1 << pid;
+ } else {
+ PMC_PCER1 = 1 << (pid & 31);
+ }
+}
+
+void pmc_peripheral_clock_disable(uint8_t pid)
+{
+ if (pid < 32) {
+ PMC_PCDR0 = 1 << pid;
+ } else {
+ PMC_PCDR1 = 1 << (pid & 31);
+ }
+}
+
+void pmc_mck_set_source(enum mck_src src)
+{
+ PMC_MCKR = (PMC_MCKR & ~PMC_MCKR_CSS_MASK) | src;
+ while (!(PMC_SR & PMC_SR_MCKRDY));
+}
+
+void pmc_clock_setup_in_xtal_12mhz_out_84mhz(void)
+{
+ eefc_set_latency(4);
+
+ /* 12MHz external xtal, maximum possible startup time */
+ pmc_xtal_enable(true, 0xff);
+ /* Select as main oscillator */
+ CKGR_MOR |= CKGR_MOR_KEY | CKGR_MOR_MOSCSEL;
+ /* Multiply by 7 for 84MHz */
+ pmc_plla_config(7, 1);
+ pmc_mck_set_source(MCK_SRC_PLLA);
+
+ pmc_mck_frequency = 84000000;
+}
+
+void pmc_clock_setup_in_rc_4mhz_out_84mhz(void)
+{
+ eefc_set_latency(4);
+
+ /* Select as main oscillator */
+ CKGR_MOR = CKGR_MOR_KEY |
+ (CKGR_MOR & ~(CKGR_MOR_MOSCSEL | CKGR_MOR_MOSCRCF_MASK));
+ /* Multiply by 21 for 84MHz */
+ pmc_plla_config(21, 1);
+ pmc_mck_set_source(MCK_SRC_PLLA);
+
+ pmc_mck_frequency = 84000000;
+}
+
diff --git a/libopencm3/lib/sam/common/usart.c b/libopencm3/lib/sam/common/usart.c
new file mode 100644
index 0000000..36833f7
--- /dev/null
+++ b/libopencm3/lib/sam/common/usart.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/sam/usart.h>
+#include <libopencm3/sam/pmc.h>
+
+void usart_set_baudrate(uint32_t usart, uint32_t baud)
+{
+ USART_BRGR(usart) = pmc_mck_frequency / (16 * baud);
+}
+
+void usart_set_databits(uint32_t usart, int bits)
+{
+ USART_MR(usart) = (USART_MR(usart) & ~USART_MR_CHRL_MASK) |
+ ((bits - 5) << 6);
+}
+
+void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb)
+{
+ USART_MR(usart) = (USART_MR(usart) & ~USART_MR_NBSTOP_MASK) |
+ (sb << 12);
+}
+
+void usart_set_parity(uint32_t usart, enum usart_parity par)
+{
+ USART_MR(usart) = (USART_MR(usart) & ~USART_MR_PAR_MASK) | (par << 9);
+}
+
+void usart_set_mode(uint32_t usart, enum usart_mode mode)
+{
+ USART_CR(usart) =
+ (mode & USART_MODE_RX) ? USART_CR_RXEN : USART_CR_RXDIS;
+ USART_CR(usart) = (mode & USART_MODE_TX) ? USART_CR_TXEN
+ : USART_CR_TXDIS;
+}
+
+void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc)
+{
+ USART_MR(usart) = (USART_MR(usart) & ~USART_MR_MODE_MASK) |
+ (fc ? USART_MR_MODE_HW_HANDSHAKING : 0);
+}
+
+void usart_enable(uint32_t usart)
+{
+ (void)usart;
+}
+
+void usart_disable(uint32_t usart)
+{
+ (void)usart;
+}
+
+void usart_send(uint32_t usart, uint16_t data)
+{
+ USART_THR(usart) = data;
+}
+
+uint16_t usart_recv(uint32_t usart)
+{
+ return USART_RHR(usart) & 0x1f;
+}
+
+void usart_wait_send_ready(uint32_t usart)
+{
+ while ((USART_CSR(usart) & USART_CSR_TXRDY) == 0);
+}
+
+void usart_wait_recv_ready(uint32_t usart)
+{
+ while ((USART_CSR(usart) & USART_CSR_RXRDY) == 0);
+}
+
+void usart_send_blocking(uint32_t usart, uint16_t data)
+{
+ usart_wait_send_ready(usart);
+ usart_send(usart, data);
+}
+
+uint16_t usart_recv_blocking(uint32_t usart)
+{
+ usart_wait_recv_ready(usart);
+
+ return usart_recv(usart);
+}
+
+void usart_enable_rx_interrupt(uint32_t usart)
+{
+ USART_IER(usart) = USART_CSR_RXRDY;
+}
+
+void usart_disable_rx_interrupt(uint32_t usart)
+{
+ USART_IDR(usart) = USART_CSR_RXRDY;
+}
diff --git a/libopencm3/lib/stm32/can.c b/libopencm3/lib/stm32/can.c
new file mode 100644
index 0000000..d693a97
--- /dev/null
+++ b/libopencm3/lib/stm32/can.c
@@ -0,0 +1,557 @@
+/** @defgroup can_file CAN
+
+@ingroup STM32F_files
+
+@brief <b>libopencm3 STM32Fxxx CAN</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010 Piotr Esden-Tempski <piotr@esden.net>
+
+@date 12 November 2012
+
+Devices can have up to two CAN peripherals. The peripherals support up to 1MBit
+transmission rate. The peripheral has several filters for incoming messages that
+can be distributed between two FIFOs and three transmit mailboxes.
+
+LGPL License Terms @ref lgpl_license
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/can.h>
+
+#if defined(STM32F1)
+# include <libopencm3/stm32/f1/rcc.h>
+#elif defined(STM32F2)
+# include <libopencm3/stm32/f2/rcc.h>
+#elif defined(STM32F4)
+# include <libopencm3/stm32/f4/rcc.h>
+#else
+# error "stm32 family not defined."
+#endif
+
+/* Timeout for CAN INIT acknowledge
+ * this value is difficult to define.
+ * INIT is set latest after finishing the current transfer.
+ * Assuming the lowest CAN speed of 100kbps one CAN frame may take about 1.6ms
+ * WAIT loop timeout varies on compiler switches, optimization, CPU architecture
+ * and CPU speed
+ *
+ * The same timeout value is used for leaving INIT where the longest time is
+ * 11 bits(110 us on 100 kbps).
+ */
+#define CAN_MSR_INAK_TIMEOUT 0x0000FFFF
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Reset
+
+The CAN peripheral and all its associated configuration registers are placed in
+the reset condition. The reset is effective via the RCC peripheral reset
+system.
+
+@param[in] canport Unsigned int32. CAN block register address base @ref
+can_reg_base.
+ */
+void can_reset(uint32_t canport)
+{
+ if (canport == CAN1) {
+ rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST);
+ rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST);
+ } else {
+ rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST);
+ rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Init
+
+Initialize the selected CAN peripheral block.
+
+@param[in] canport Unsigend int32. CAN register base address @ref can_reg_base.
+@param[in] ttcm bool. Time triggered communication mode.
+@param[in] abom bool. Automatic bus-off management.
+@param[in] awum bool. Automatic wakeup mode.
+@param[in] nart bool. No automatic retransmission.
+@param[in] rflm bool. Receive FIFO locked mode.
+@param[in] txfp bool. Transmit FIFO priority.
+@param[in] sjw Unsigned int32. Resynchronization time quanta jump width.
+@param[in] ts1 Unsigned int32. Time segment 1 time quanta width.
+@param[in] ts2 Unsigned int32. Time segment 2 time quanta width.
+@param[in] brp Unsigned int32. Baud rate prescaler.
+@returns int 0 on success, 1 on initialization failure.
+*/
+int can_init(uint32_t canport, bool ttcm, bool abom, bool awum, bool nart,
+ bool rflm, bool txfp, uint32_t sjw, uint32_t ts1, uint32_t ts2,
+ uint32_t brp, bool loopback, bool silent)
+{
+ volatile uint32_t wait_ack;
+ int ret = 0;
+
+ /* Exit from sleep mode. */
+ CAN_MCR(canport) &= ~CAN_MCR_SLEEP;
+
+ /* Request initialization "enter". */
+ CAN_MCR(canport) |= CAN_MCR_INRQ;
+
+ /* Wait for acknowledge. */
+ wait_ack = CAN_MSR_INAK_TIMEOUT;
+ while ((--wait_ack) &&
+ ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK));
+
+ /* Check the acknowledge. */
+ if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK) {
+ return 1;
+ }
+
+ /* clear can timing bits */
+ CAN_BTR(canport) = 0;
+
+ /* Set the automatic bus-off management. */
+ if (ttcm) {
+ CAN_MCR(canport) |= CAN_MCR_TTCM;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_TTCM;
+ }
+
+ if (abom) {
+ CAN_MCR(canport) |= CAN_MCR_ABOM;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_ABOM;
+ }
+
+ if (awum) {
+ CAN_MCR(canport) |= CAN_MCR_AWUM;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_AWUM;
+ }
+
+ if (nart) {
+ CAN_MCR(canport) |= CAN_MCR_NART;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_NART;
+ }
+
+ if (rflm) {
+ CAN_MCR(canport) |= CAN_MCR_RFLM;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_RFLM;
+ }
+
+ if (txfp) {
+ CAN_MCR(canport) |= CAN_MCR_TXFP;
+ } else {
+ CAN_MCR(canport) &= ~CAN_MCR_TXFP;
+ }
+
+ if (silent) {
+ CAN_BTR(canport) |= CAN_BTR_SILM;
+ } else {
+ CAN_BTR(canport) &= ~CAN_BTR_SILM;
+ }
+
+ if (loopback) {
+ CAN_BTR(canport) |= CAN_BTR_LBKM;
+ } else {
+ CAN_BTR(canport) &= ~CAN_BTR_LBKM;
+ }
+
+ /* Set bit timings. */
+ CAN_BTR(canport) |= sjw | ts2 | ts1 |
+ ((brp - 1ul) & CAN_BTR_BRP_MASK);
+
+ /* Request initialization "leave". */
+ CAN_MCR(canport) &= ~CAN_MCR_INRQ;
+
+ /* Wait for acknowledge. */
+ wait_ack = CAN_MSR_INAK_TIMEOUT;
+ while ((--wait_ack) &&
+ ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK));
+
+ if ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK) {
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Filter Init
+
+Initialize incoming message filter and assign to FIFO.
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] nr Unsigned int32. ID number of the filter.
+@param[in] scale_32bit bool. 32-bit scale for the filter?
+@param[in] id_list_mode bool. ID list filter mode?
+@param[in] fr1 Unsigned int32. First filter register content.
+@param[in] fr2 Unsigned int32. Second filter register content.
+@param[in] fifo Unsigned int32. FIFO id.
+@param[in] enable bool. Enable filter?
+ */
+void can_filter_init(uint32_t canport, uint32_t nr, bool scale_32bit,
+ bool id_list_mode, uint32_t fr1, uint32_t fr2,
+ uint32_t fifo, bool enable)
+{
+ uint32_t filter_select_bit = 0x00000001 << nr;
+
+ /* Request initialization "enter". */
+ CAN_FMR(canport) |= CAN_FMR_FINIT;
+
+ /* Deactivate the filter. */
+ CAN_FA1R(canport) &= ~filter_select_bit;
+
+ if (scale_32bit) {
+ /* Set 32-bit scale for the filter. */
+ CAN_FS1R(canport) |= filter_select_bit;
+ } else {
+ /* Set 16-bit scale for the filter. */
+ CAN_FS1R(canport) &= ~filter_select_bit;
+ }
+
+ if (id_list_mode) {
+ /* Set filter mode to ID list mode. */
+ CAN_FM1R(canport) |= filter_select_bit;
+ } else {
+ /* Set filter mode to id/mask mode. */
+ CAN_FM1R(canport) &= ~filter_select_bit;
+ }
+
+ /* Set the first filter register. */
+ CAN_FiR1(canport, nr) = fr1;
+
+ /* Set the second filter register. */
+ CAN_FiR2(canport, nr) = fr2;
+
+ /* Select FIFO0 or FIFO1 as filter assignement. */
+ if (fifo) {
+ CAN_FFA1R(canport) |= filter_select_bit; /* FIFO1 */
+ } else {
+ CAN_FFA1R(canport) &= ~filter_select_bit; /* FIFO0 */
+ }
+
+ if (enable) {
+ CAN_FA1R(canport) |= filter_select_bit; /* Activate filter. */
+ }
+
+ /* Request initialization "leave". */
+ CAN_FMR(canport) &= ~CAN_FMR_FINIT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Initialize a 16bit Message ID Mask Filter
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] nr Unsigned int32. ID number of the filter.
+@param[in] id1 Unsigned int16. First message ID to filter.
+@param[in] mask1 Unsigned int16. First message ID bit mask.
+@param[in] id2 Unsigned int16. Second message ID to filter.
+@param[in] mask2 Unsigned int16. Second message ID bit mask.
+@param[in] fifo Unsigned int32. FIFO id.
+@param[in] enable bool. Enable filter?
+ */
+void can_filter_id_mask_16bit_init(uint32_t canport, uint32_t nr, uint16_t id1,
+ uint16_t mask1, uint16_t id2,
+ uint16_t mask2, uint32_t fifo, bool enable)
+{
+ can_filter_init(canport, nr, false, false,
+ ((uint32_t)id1 << 16) | (uint32_t)mask1,
+ ((uint32_t)id2 << 16) | (uint32_t)mask2, fifo, enable);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Initialize a 32bit Message ID Mask Filter
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] nr Unsigned int32. ID number of the filter.
+@param[in] id Unsigned int32. Message ID to filter.
+@param[in] mask Unsigned int32. Message ID bit mask.
+@param[in] fifo Unsigned int32. FIFO id.
+@param[in] enable bool. Enable filter?
+ */
+void can_filter_id_mask_32bit_init(uint32_t canport, uint32_t nr, uint32_t id,
+ uint32_t mask, uint32_t fifo, bool enable)
+{
+ can_filter_init(canport, nr, true, false, id, mask, fifo, enable);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Initialize a 16bit Message ID List Filter
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] nr Unsigned int32. ID number of the filter.
+@param[in] id1 Unsigned int16. First message ID to match.
+@param[in] id2 Unsigned int16. Second message ID to match.
+@param[in] id3 Unsigned int16. Third message ID to match.
+@param[in] id4 Unsigned int16. Fourth message ID to match.
+@param[in] fifo Unsigned int32. FIFO id.
+@param[in] enable bool. Enable filter?
+ */
+void can_filter_id_list_16bit_init(uint32_t canport, uint32_t nr,
+ uint16_t id1, uint16_t id2,
+ uint16_t id3, uint16_t id4,
+ uint32_t fifo, bool enable)
+{
+ can_filter_init(canport, nr, false, true,
+ ((uint32_t)id1 << 16) | (uint32_t)id2,
+ ((uint32_t)id3 << 16) | (uint32_t)id4, fifo, enable);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Initialize a 32bit Message ID List Filter
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] nr Unsigned int32. ID number of the filter.
+@param[in] id1 Unsigned int32. First message ID to match.
+@param[in] id2 Unsigned int32. Second message ID to match.
+@param[in] fifo Unsigned int32. FIFO id.
+@param[in] enable bool. Enable filter?
+ */
+void can_filter_id_list_32bit_init(uint32_t canport, uint32_t nr,
+ uint32_t id1, uint32_t id2,
+ uint32_t fifo, bool enable)
+{
+ can_filter_init(canport, nr, true, true, id1, id2, fifo, enable);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Enable IRQ
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] irq Unsigned int32. IRQ bit(s).
+ */
+void can_enable_irq(uint32_t canport, uint32_t irq)
+{
+ CAN_IER(canport) |= irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Disable IRQ
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] irq Unsigned int32. IRQ bit(s).
+ */
+void can_disable_irq(uint32_t canport, uint32_t irq)
+{
+ CAN_IER(canport) &= ~irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Transmit Message
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] id Unsigned int32. Message ID.
+@param[in] ext bool. Extended message ID?
+@param[in] rtr bool. Request transmit?
+@param[in] length Unsigned int8. Message payload length.
+@param[in] data Unsigned int8[]. Message payload data.
+@returns int 0, 1 or 2 on success and depending on which outgoing mailbox got
+selected. -1 if no mailbox was available and no transmission got queued.
+ */
+int can_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
+ uint8_t length, uint8_t *data)
+{
+ int ret = 0;
+ uint32_t mailbox = 0;
+ union {
+ uint8_t data8[4];
+ uint32_t data32;
+ } tdlxr, tdhxr;
+
+ /* Check which transmit mailbox is empty if any. */
+ if ((CAN_TSR(canport) & CAN_TSR_TME0) == CAN_TSR_TME0) {
+ ret = 0;
+ mailbox = CAN_MBOX0;
+ } else if ((CAN_TSR(canport) & CAN_TSR_TME1) == CAN_TSR_TME1) {
+ ret = 1;
+ mailbox = CAN_MBOX1;
+ } else if ((CAN_TSR(canport) & CAN_TSR_TME2) == CAN_TSR_TME2) {
+ ret = 2;
+ mailbox = CAN_MBOX2;
+ } else {
+ ret = -1;
+ }
+
+ /* If we have no empty mailbox return with an error. */
+ if (ret == -1) {
+ return ret;
+ }
+
+ if (ext) {
+ /* Set extended ID. */
+ CAN_TIxR(canport, mailbox) = (id << CAN_TIxR_EXID_SHIFT) |
+ CAN_TIxR_IDE;
+ } else {
+ /* Set standard ID. */
+ CAN_TIxR(canport, mailbox) = id << CAN_TIxR_STID_SHIFT;
+ }
+
+ /* Set/clear remote transmission request bit. */
+ if (rtr) {
+ CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; /* Set */
+ }
+
+ /* Set the DLC. */
+ CAN_TDTxR(canport, mailbox) &= ~CAN_TDTxR_DLC_MASK;
+ CAN_TDTxR(canport, mailbox) |= (length & CAN_TDTxR_DLC_MASK);
+
+ switch (length) {
+ case 8:
+ tdhxr.data8[3] = data[7];
+ /* no break */
+ case 7:
+ tdhxr.data8[2] = data[6];
+ /* no break */
+ case 6:
+ tdhxr.data8[1] = data[5];
+ /* no break */
+ case 5:
+ tdhxr.data8[0] = data[4];
+ /* no break */
+ case 4:
+ tdlxr.data8[3] = data[3];
+ /* no break */
+ case 3:
+ tdlxr.data8[2] = data[2];
+ /* no break */
+ case 2:
+ tdlxr.data8[1] = data[1];
+ /* no break */
+ case 1:
+ tdlxr.data8[0] = data[0];
+ /* no break */
+ default:
+ break;
+ }
+ /* Set the data. */
+
+ CAN_TDLxR(canport, mailbox) = tdlxr.data32;
+ CAN_TDHxR(canport, mailbox) = tdhxr.data32;
+
+ /* Request transmission. */
+ CAN_TIxR(canport, mailbox) |= CAN_TIxR_TXRQ;
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Release FIFO
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] fifo Unsigned int8. FIFO id.
+ */
+void can_fifo_release(uint32_t canport, uint8_t fifo)
+{
+ if (fifo == 0) {
+ CAN_RF0R(canport) |= CAN_RF1R_RFOM1;
+ } else {
+ CAN_RF1R(canport) |= CAN_RF1R_RFOM1;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CAN Receive Message
+
+@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
+@param[in] fifo Unsigned int8. FIFO id.
+@param[in] release bool. Release the FIFO automatically after coping data out.
+@param[out] id Unsigned int32 pointer. Message ID.
+@param[out] ext bool pointer. The message ID is extended?
+@param[out] rtr bool pointer. Request of transmission?
+@param[out] fmi Unsigned int32 pointer. ID of the matched filter.
+@param[out] length Unsigned int8 pointer. Length of message payload.
+@param[out] data Unsigned int8[]. Message payload data.
+ */
+void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
+ bool *ext, bool *rtr, uint32_t *fmi, uint8_t *length,
+ uint8_t *data)
+{
+ uint32_t fifo_id = 0;
+ union {
+ uint8_t data8[4];
+ uint32_t data32;
+ } rdlxr, rdhxr;
+ const uint32_t fifoid_array[2] = {CAN_FIFO0, CAN_FIFO1};
+
+ fifo_id = fifoid_array[fifo];
+
+ /* Get type of CAN ID and CAN ID. */
+ if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_IDE) {
+ *ext = true;
+ /* Get extended CAN ID. */
+ *id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_EXID_SHIFT) &
+ CAN_RIxR_EXID_MASK;
+ } else {
+ *ext = false;
+ /* Get standard CAN ID. */
+ *id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_STID_SHIFT) &
+ CAN_RIxR_STID_MASK;
+ }
+
+ /* Get remote transmit flag. */
+ if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_RTR) {
+ *rtr = true;
+ } else {
+ *rtr = false;
+ }
+
+ /* Get filter match ID. */
+ *fmi = ((CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_FMI_MASK) >>
+ CAN_RDTxR_FMI_SHIFT);
+
+ /* Get data length. */
+ *length = CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_DLC_MASK;
+ /* accelerate reception by copying the CAN data from the controller
+ * memory to the fast internal RAM
+ */
+
+ rdlxr.data32 = CAN_RDLxR(canport, fifo_id);
+ rdhxr.data32 = CAN_RDHxR(canport, fifo_id);
+ /* */
+ /* Get data.
+ * Byte wise copy is needed because we do not know the alignment
+ * of the input buffer.
+ * Here copying 8 bytes unconditionally is faster than using loop
+ *
+ * It is OK to copy all 8 bytes because the upper layer must be
+ * prepared for data length bigger expected.
+ * In contrary the driver has no information about the intended size.
+ * This could be different if the max length would be handed over
+ * to the function, but it is not the case
+ */
+ data[0] = rdlxr.data8[0];
+ data[1] = rdlxr.data8[1];
+ data[2] = rdlxr.data8[2];
+ data[3] = rdlxr.data8[3];
+ data[4] = rdhxr.data8[0];
+ data[5] = rdhxr.data8[1];
+ data[6] = rdhxr.data8[2];
+ data[7] = rdhxr.data8[3];
+
+ /* Release the FIFO. */
+ if (release) {
+ can_fifo_release(canport, fifo);
+ }
+}
+
+bool can_available_mailbox(uint32_t canport)
+{
+ return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
+}
diff --git a/libopencm3/lib/stm32/common/adc_common_v1.c b/libopencm3/lib/stm32/common/adc_common_v1.c
new file mode 100644
index 0000000..a4b9257
--- /dev/null
+++ b/libopencm3/lib/stm32/common/adc_common_v1.c
@@ -0,0 +1,755 @@
+/** @addtogroup adc_file
+
+@author @htmlonly &copy; @endhtmlonly
+2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
+@author @htmlonly &copy; @endhtmlonly
+2012 Ken Sarkies <ksarkies@internode.on.net>
+@author @htmlonly &copy; @endhtmlonly
+2014 Karl Palsson <karlp@tweak.net.au>
+
+This library supports one style of the Analog to Digital Conversion System in
+the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The style of ADC Peripheral supported by this code is found in the F1, F2,
+F37x, F38x, F4, and L1 series devices (at the time of writing) but is quite
+different to the style found on the F0 and F30x and F31x.
+Devices can have up to three A/D converters each with their own set of
+registers.
+However all the A/D converters share a common clock. On most devices, this is
+prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum
+of 8, though on the L1 this is always a divider from the HSI. (And therefore HSI
+_must_ be enabled before attempting to enable the ADC)
+
+Each A/D converter has up to ADC_MAX_CHANNELS channels:
+@li On ADC1 the analog channels 16 and 17 are internally connected to the
+temperature sensor and V<sub>REFINT</sub>, respectively.
+@li On ADC2 (if available) the analog channels 16 and 17 are internally
+connected to V<sub>SS</sub>.
+@li On ADC3 (if available) the analog channels 9, 14, 15, 16 and 17 are
+internally connected to V<sub>SS</sub>.
+
+The conversions can occur as a one-off conversion whereby the process stops once
+conversion is complete. The conversions can also be continuous wherein a new
+conversion starts immediately the previous conversion has ended.
+
+Conversion can occur as a single channel conversion or a scan of a group of
+channels in either continuous or one-off mode. If more than one channel is
+converted in a scan group, DMA must be used to transfer the data as there is
+only one result register available. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+A discontinuous mode allows a subgroup of group of a channels to be converted in
+bursts of a given length.
+
+Injected conversions allow a second group of channels to be converted separately
+from the regular group. An interrupt can be set to occur at the end of
+conversion, which occurs after all channels have been scanned.
+
+@section adc_api_ex Basic ADC Handling API.
+
+Example 1: Simple single channel conversion polled. Enable the peripheral clock
+and ADC, reset ADC and set the prescaler divider. Set dual mode to independent
+(default). Enable triggering for a software trigger.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+ adc_off(ADC1);
+ rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
+ adc_set_dual_mode(ADC_CR1_DUALMOD_IND);
+ adc_disable_scan_mode(ADC1);
+ adc_set_single_conversion_mode(ADC1);
+ adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
+ adc_set_single_channel(ADC1, ADC_CHANNEL0);
+ adc_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART);
+ adc_power_on(ADC1);
+ adc_reset_calibration(ADC1);
+ adc_calibration(ADC1);
+ adc_start_conversion_regular(ADC1);
+ while (! adc_eoc(ADC1));
+ reg16 = adc_read_regular(ADC1);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/adc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Off
+
+Turn off the ADC to reduce power consumption to a few microamps.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_off(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_ADON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Regular Conversions
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_enable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_AWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog for Regular Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_disable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Injected Conversions
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JAWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog for Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JAWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Regular Conversions
+
+In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the
+defined regular channel group. The subgroup is defined by the number of
+consecutive channels to be converted. After a subgroup has been converted
+the next trigger will start conversion of the immediately following subgroup
+of the same length or until the whole group has all been converted. When the
+the whole group has been converted, the next trigger will restart conversion
+of the subgroup at the beginning of the whole group.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] length Unsigned int8. Number of channels in the group @ref
+adc_cr1_discnum
+*/
+
+void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length)
+{
+ if ((length-1) > 7) {
+ return;
+ }
+ ADC_CR1(adc) |= ADC_CR1_DISCEN;
+ ADC_CR1(adc) |= ((length-1) << ADC_CR1_DISCNUM_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Regular Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_discontinuous_mode_regular(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_DISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Injected Conversions
+
+In this mode the ADC converts sequentially one channel of the defined group of
+injected channels, cycling back to the first channel in the group once the
+entire group has been converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JDISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JDISCEN;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Automatic Injected Conversions
+
+The ADC converts a defined injected group of channels immediately after the
+regular channels have been converted. The external trigger on the injected
+channels is disabled as required.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_automatic_injected_group_conversion(uint32_t adc)
+{
+ adc_disable_external_trigger_injected(adc);
+ ADC_CR1(adc) |= ADC_CR1_JAUTO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Automatic Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_automatic_injected_group_conversion(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JAUTO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@note The analog watchdog must be enabled for either or both of the regular or
+injected channels. If neither are enabled, the analog watchdog feature will be
+disabled.
+@ref adc_enable_analog_watchdog_injected, @ref
+adc_enable_analog_watchdog_regular.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for a Selected Channel
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@note The analog watchdog must be enabled for either or both of the regular or
+injected channels. If neither are enabled, the analog watchdog feature will be
+disabled. If both are enabled, the same channel number is monitored.
+@ref adc_enable_analog_watchdog_injected, @ref
+adc_enable_analog_watchdog_regular.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] channel Unsigned int8. ADC channel number @ref adc_watchdog_channel
+*/
+
+void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc,
+ uint8_t channel)
+{
+ uint32_t reg32;
+
+ reg32 = (ADC_CR1(adc) & ~ADC_CR1_AWDCH_MASK); /* Clear bits [4:0]. */
+ if (channel <= ADC_CR1_AWDCH_MAX) {
+ reg32 |= channel;
+ }
+ ADC_CR1(adc) = reg32;
+ ADC_CR1(adc) |= ADC_CR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Scan Mode
+
+In this mode a conversion consists of a scan of the predefined set of channels,
+regular and injected, each channel conversion immediately following the
+previous one. It can use single, continuous or discontinuous mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_SCAN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Scan Mode
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_SCAN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Injected End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Injected End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_awd_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_AWDIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_awd_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Regular End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_eoc_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_EOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_eoc_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_EOCIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Left Aligned
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_left_aligned(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Right Aligned
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_right_aligned(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag
+
+This flag is set after all channels of a regular or injected group have been
+converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns bool. End of conversion flag.
+*/
+
+bool adc_eoc(uint32_t adc)
+{
+ return (ADC_SR(adc) & ADC_SR_EOC) != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion
+
+This flag is set after all channels of an injected group have been converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns bool. End of conversion flag.
+*/
+
+bool adc_eoc_injected(uint32_t adc)
+{
+ return (ADC_SR(adc) & ADC_SR_JEOC) != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from the Regular Conversion Result Register
+
+The result read back is 12 bits, right or left aligned within the first 16 bits.
+For ADC1 only, the higher 16 bits will hold the result from ADC2 if
+an appropriate dual mode has been set @see adc_set_dual_mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns Unsigned int32 conversion result.
+*/
+
+uint32_t adc_read_regular(uint32_t adc)
+{
+ return ADC_DR(adc);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from an Injected Conversion Result Register
+
+The result read back from the selected injected result register (one of four)
+is 12 bits, right or left aligned within the first 16 bits. The result can have
+a negative value if the injected channel offset has been set @see
+adc_set_injected_offset.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] reg Unsigned int8. Register number (1 ... 4).
+@returns Unsigned int32 conversion result.
+*/
+
+uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
+{
+ switch (reg) {
+ case 1:
+ return ADC_JDR1(adc);
+ case 2:
+ return ADC_JDR2(adc);
+ case 3:
+ return ADC_JDR3(adc);
+ case 4:
+ return ADC_JDR4(adc);
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Continuous Conversion Mode
+
+In this mode the ADC starts a new conversion of a single channel or a channel
+group immediately following completion of the previous channel group conversion.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_set_continuous_conversion_mode(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_CONT;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Single Conversion Mode
+
+In this mode the ADC performs a conversion of one channel or a channel group
+and stops.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_single_conversion_mode(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Upper Threshold
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] threshold Unsigned int8. Upper threshold value
+*/
+
+void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 = (uint32_t)threshold;
+ reg32 &= ADC_HT_MSK;
+ ADC_HTR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Lower Threshold
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] threshold Unsigned int8. Lower threshold value
+*/
+
+void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 = (uint32_t)threshold;
+ reg32 &= ADC_LT_MSK;
+ ADC_LTR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/** @brief ADC Set a Regular Channel Conversion Sequence
+
+Define a sequence of channels to be converted as a regular group with a length
+from 1 to ADC_REGULAR_SEQUENCE_MAX channels. If this is called during
+conversion, the current conversion is reset and conversion begins again with
+the newly defined group.
+
+@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
+@param[in] length Unsigned int8. Number of channels in the group.
+@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..31.
+ */
+
+void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t fifth6 = 0;
+ uint32_t fourth6 = 0;
+ uint32_t third6 = 0;
+ uint32_t second6 = 0;
+ uint32_t first6 = 0;
+ uint8_t i = 0;
+
+ if (length > ADC_SQR_MAX_CHANNELS_REGULAR) {
+ return;
+ }
+
+ for (i = 1; i <= length; i++) {
+ if (i <= 6) {
+ first6 |= (channel[i - 1] << ((i - 1) * 5));
+ }
+ if ((i > 6) & (i <= 12)) {
+ second6 |= (channel[i - 1] << ((i - 6 - 1) * 5));
+ }
+ if ((i > 12) & (i <= 18)) {
+ third6 |= (channel[i - 1] << ((i - 12 - 1) * 5));
+ }
+ if ((i > 18) & (i <= 24)) {
+ fourth6 |= (channel[i - 1] << ((i - 18 - 1) * 5));
+ }
+ if ((i > 24) & (i <= 28)) {
+ fifth6 |= (channel[i - 1] << ((i - 24 - 1) * 5));
+ }
+ }
+#if defined(ADC_SQR5)
+ ADC_SQR1(adc) = fifth6 | ((length - 1) << ADC_SQR1_L_LSB);
+ ADC_SQR2(adc) = fourth6;
+ ADC_SQR3(adc) = third6;
+ ADC_SQR4(adc) = second6;
+ ADC_SQR5(adc) = first6;
+#else
+ ADC_SQR1(adc) = third6 | ((length - 1) << ADC_SQR1_L_LSB);
+ ADC_SQR2(adc) = second6;
+ ADC_SQR3(adc) = first6;
+#endif
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set an Injected Channel Conversion Sequence
+
+Defines a sequence of channels to be converted as an injected group with a
+length from 1 to 4 channels. If this is called during conversion, the current
+conversion is reset and conversion begins again with the newly defined group.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] length Unsigned int8. Number of channels in the group.
+@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18
+*/
+
+void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t reg32 = 0;
+ uint8_t i = 0;
+
+ /* Maximum sequence length is 4 channels. Minimum sequence is 1.*/
+ if ((length - 1) > 3) {
+ return;
+ }
+
+ for (i = 0; i < length; i++) {
+ reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]);
+ }
+
+ reg32 |= ADC_JSQR_JL_VAL(length);
+
+ ADC_JSQR(adc) = reg32;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Set the Injected Channel Data Offset
+
+This value is subtracted from the injected channel results after conversion is
+complete, and can result in negative results. A separate value can be specified
+for each injected data register.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] reg Unsigned int8. Register number (1 ... 4).
+@param[in] offset Unsigned int32.
+*/
+
+void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset)
+{
+ switch (reg) {
+ case 1:
+ ADC_JOFR1(adc) = offset;
+ break;
+ case 2:
+ ADC_JOFR2(adc) = offset;
+ break;
+ case 3:
+ ADC_JOFR3(adc) = offset;
+ break;
+ case 4:
+ ADC_JOFR4(adc) = offset;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Regular Channels
+
+This starts conversion on a set of defined regular channels if the ADC trigger
+is set to be a software trigger. It is cleared by hardware once conversion
+starts.
+
+Special F1 Note this is a software trigger and requires triggering to be
+enabled and the trigger source to be set appropriately otherwise conversion
+will not start. This is not the same as the ADC start conversion operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_start_conversion_regular(uint32_t adc)
+{
+ /* Start conversion on regular channels. */
+ ADC_CR2(adc) |= ADC_CR2_SWSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR2(adc) & ADC_CR2_SWSTART);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Injected Channels
+
+This starts conversion on a set of defined injected channels if the ADC trigger
+is set to be a software trigger. It is cleared by hardware once conversion
+starts.
+
+Special F1 Note this is a software trigger and requires triggering to be
+enabled and the trigger source to be set appropriately otherwise conversion
+will not start. This is not the same as the ADC start conversion operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_start_conversion_injected(uint32_t adc)
+{
+ /* Start conversion on injected channels. */
+ ADC_CR2(adc) |= ADC_CR2_JSWSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR2(adc) & ADC_CR2_JSWSTART);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable DMA Transfers
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_dma(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_DMA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable DMA Transfers
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_dma(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_DMA;
+}
+
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/crc_common_all.c b/libopencm3/lib/stm32/common/crc_common_all.c
new file mode 100644
index 0000000..5794c8f
--- /dev/null
+++ b/libopencm3/lib/stm32/common/crc_common_all.c
@@ -0,0 +1,81 @@
+/** @addtogroup crc_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@remake.is>
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@remake.is>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Reset.
+
+Reset the CRC unit and forces the data register to all 1s.
+
+*/
+
+void crc_reset(void)
+{
+ CRC_CR |= CRC_CR_RESET;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Calculate.
+
+Writes a data word to the register, the write operation stalling until the
+computation is complete.
+
+@param[in] data Unsigned int32.
+@returns int32 Computed CRC result
+*/
+
+uint32_t crc_calculate(uint32_t data)
+{
+ CRC_DR = data;
+ /* Data sheet says this blocks until it's ready.... */
+ return CRC_DR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Calculate of a Block of Data.
+
+Writes data words consecutively to the register, the write operation stalling
+until the computation of each word is complete.
+
+@param[in] datap Unsigned int32. pointer to an array of 32 bit data words.
+@param[in] size int. Size of the array.
+@returns int32 Final computed CRC result
+*/
+
+uint32_t crc_calculate_block(uint32_t *datap, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ CRC_DR = datap[i];
+ }
+
+ return CRC_DR;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/crypto_common_f24.c b/libopencm3/lib/stm32/common/crypto_common_f24.c
new file mode 100644
index 0000000..46cef6b
--- /dev/null
+++ b/libopencm3/lib/stm32/common/crypto_common_f24.c
@@ -0,0 +1,175 @@
+/** @addtogroup crypto_file
+ *
+ * @brief <b>libopencm3 STM32 Cryptographic controller</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 17 Jun 2013
+ *
+ * This library supports the cryptographic coprocessor system for the
+ * STM32 series of ARM Cortex Microcontrollers
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/crypto.h>
+
+#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE)
+
+/**
+ * @brief Wait, if the Controller is busy
+ */
+void crypto_wait_busy(void)
+{
+ while (CRYP_SR & CRYP_SR_BUSY);
+}
+
+/**
+ * @brief Set key value to the controller
+ * @param[in] keysize enum crypto_keysize Specified size of the key.
+ * @param[in] key uint64_t[] Key value (array of 4 items)
+ */
+void crypto_set_key(enum crypto_keysize keysize, uint64_t key[])
+{
+ int i;
+
+ crypto_wait_busy();
+
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) |
+ (keysize << CRYP_CR_KEYSIZE_SHIFT);
+
+ for (i = 0; i < 4; i++) {
+ CRYP_KR(i) = key[i];
+ }
+}
+
+/**
+ * @brief Set Initialization Vector
+ *
+ * @param[in] iv uint64_t[] Initialization vector (array of 4 items)
+
+ * @note Cryptographic controller must be in disabled state
+ */
+void crypto_set_iv(uint64_t iv[])
+{
+ int i;
+
+ crypto_wait_busy();
+
+ for (i = 0; i < 4; i++) {
+ CRYP_IVR(i) = iv[i];
+ }
+}
+
+/**
+ * @brief Set the order of the data to be crypted
+ *
+ * @param[in] datatype enum crypto_datatype Specified datatype of the key.
+ */
+void crypto_set_datatype(enum crypto_datatype datatype)
+{
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) |
+ (datatype << CRYP_CR_DATATYPE_SHIFT);
+}
+
+/**
+ * @brief Set the algoritm for Encryption/decryption
+ *
+ *@param[in] mode enum crypto_mode Mode of execution
+ */
+void crypto_set_algorithm(enum crypto_mode mode)
+{
+ mode &= ~CRYP_CR_ALGOMODE_MASK;
+
+ if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) {
+ /* Unroll keys for the AES encoder for the user automatically */
+
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) |
+ CRYP_CR_ALGOMODE_AES_PREP;
+
+ crypto_start();
+ crypto_wait_busy();
+ /* module switches to DISABLE automatically */
+ }
+ /* set algo mode */
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode;
+
+ /* flush buffers */
+ CRYP_CR |= CRYP_CR_FFLUSH;
+}
+
+/**
+ * @brief Enable the cryptographic controller and start processing
+ */
+void crypto_start(void)
+{
+ CRYP_CR |= CRYP_CR_CRYPEN;
+}
+
+/**
+ * @brief Disable the cryptographic controller and stop processing
+ */
+
+void crypto_stop(void)
+{
+ CRYP_CR &= ~CRYP_CR_CRYPEN;
+}
+
+/**
+ * @brief Start of encryption or decryption on data buffers
+ *
+ * This blocking method transfers input buffer of specified length to the
+ * cryptographic coprocessor, and instructs him to begin of ciphering or
+ * deciphering. It waits for data to be ready, and then fills the processed
+ * data to output buffer.
+ *
+ * @param[in] inp uint32_t* Input array to crypt/decrypt.
+ * @param[in] outp uint32_t* Output array with crypted/encrypted data.
+ * @param[in] length uint32_t Length of the arrays
+ *
+ * @returns uint32_t Number of written words
+ */
+uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length)
+{
+ uint32_t rd = 0, wr = 0;
+
+ /* Transfer the data */
+ while (rd != length) {
+ if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) {
+ CRYP_DIN = *inp++;
+ wr++;
+ }
+
+ if (CRYP_SR & CRYP_SR_OFNE) {
+ *outp++ = CRYP_DOUT;
+ rd++;
+ }
+ }
+
+ /* Wait to finish - Not needed ? */
+ crypto_wait_busy();
+
+ return wr;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/dac_common_all.c b/libopencm3/lib/stm32/common/dac_common_all.c
new file mode 100644
index 0000000..a8a0daf
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dac_common_all.c
@@ -0,0 +1,503 @@
+/** @addtogroup dac_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
+
+This library supports the Digital to Analog Conversion System in the
+STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The DAC is present only in a limited set of devices, notably some
+of the connection line, high density and XL devices.
+
+Two DAC channels are available, however unlike the ADC channels these
+are separate DAC devices controlled by the same register block.
+
+The DAC is on APB1. Its clock must be enabled in RCC and depending on
+specific family, the GPIO
+ports set to alternate function output before it can be used.
+On most families, the GPIO pins should be configured to Analog IN to
+avoid parasitic consumption.
+The digital output driver is disabled so the output driver mode
+(push-pull/open drain) is arbitrary.
+
+The DAC has a holding (buffer) register and an output register from
+which the analog output is derived. The holding register must be
+loaded first. If triggering is enabled the output register is loaded
+from the holding register after a trigger occurs. If triggering is
+not enabled the holding register contents are transferred directly
+to the output register.
+
+@note To avoid nonlinearities, do not allow outputs to range close
+to zero or V_analog.
+
+@section dac_api_dual Dual Channel Conversion
+
+There are dual modes in which both DACs are used to output data
+simultaneously or independently on both channels. The data must be
+presented according to the formats described in the datasheets. A
+convenience function @ref dac_load_data_buffer_dual is provided
+for software controlled use.
+
+A variety of modes are available depending on whether independent
+or simultaneous output is desired, and whether waveforms are to be
+superimposed. Refer to the datasheets.
+
+If DMA is used, only enable it for one of the channels. The DMA
+requests will then serve data in dual format to the data register
+dedicated to dual mode. The data will then be split and loaded to the
+appropriate DAC following the next trigger. There are three registers
+available, one for each of the formats: 12 bit right-aligned, 12 bit
+left-aligned and 8 bit right-aligned. The desired format is determined
+by specifying the appropriate register to the DMA controller.
+
+@section dac_api_basic_ex Basic DAC handling API.
+
+Set the DAC's GPIO port to Analog IN. Enable the
+DAC clock. Enable the DAC, set a trigger source and load the buffer
+with the first value. After the DAC is triggered, load the buffer with
+the next value. This example uses software triggering and added noise.
+The trigger and further buffer load calls are made when data is to be
+sent out.
+
+@code
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN);
+ dac_disable(CHANNEL_1);
+ dac_set_waveform_characteristics(DAC_CR_MAMP1_8);
+ dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
+ dac_enable(CHANNEL_1);
+ dac_set_trigger_source(DAC_CR_TSEL1_SW);
+ dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1);
+ ....
+ dac_software_trigger(CHANNEL_1);
+ dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1);
+@endcode
+
+@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
+
+This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
+16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
+Both DAC channels are enabled, and both triggers are set to the same timer
+2 input as required for simultaneous operation. DMA is enabled for DAC channel
+1 only to ensure that only one DMA request is generated.
+
+@code
+ dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT);
+ dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT);
+ dma_set_read_from_memory(DMA2,DMA_CHANNEL3);
+ dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD);
+ dma_enable_channel(DMA2,DMA_CHANNEL3);
+ ...
+ dac_trigger_enable(CHANNEL_D);
+ dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
+ dac_dma_enable(CHANNEL_1);
+ dac_enable(CHANNEL_D);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/dac.h>
+
+#define MASK8 0xFF
+#define MASK12 0xFFF
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Enable.
+
+Enable a digital to analog converter channel. After setting this enable, the
+DAC requires a t<sub>wakeup</sub> time typically around 10 microseconds before
+it actually wakes up.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_EN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_EN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Disable.
+
+Disable a digital to analog converter channel.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_EN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_EN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Output Buffer Enable.
+
+Enable a digital to analog converter channel output drive buffer. This is an
+optional amplifying buffer that provides additional drive for the output
+signal. The buffer is enabled by default after a reset and needs to be
+explicitly disabled if required.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_buffer_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_BOFF1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_BOFF2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2);
+ break;
+ }
+}
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Output Buffer Disable.
+
+Disable a digital to analog converter channel output drive buffer. Disabling
+this will reduce power consumption slightly and will increase the output
+impedance of the DAC. The buffers are enabled by default after a reset.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_buffer_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_BOFF1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_BOFF2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
+ break;
+ }
+}
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel DMA Enable.
+
+Enable a digital to analog converter channel DMA mode (connected to DMA2 channel
+3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is
+generated following an external trigger.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_dma_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_DMAEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_DMAEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel DMA Disable.
+
+Disable a digital to analog converter channel DMA mode.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_dma_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_DMAEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_DMAEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Trigger Enable.
+
+Enable a digital to analog converter channel external trigger mode. This allows
+an external trigger to initiate register transfers from the buffer register to
+the DAC output register, followed by a DMA transfer to the buffer register if
+DMA is enabled. The trigger source must also be selected.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_trigger_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_TEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_TEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Trigger Disable.
+
+Disable a digital to analog converter channel external trigger.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_trigger_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_TEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_TEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set DAC Channel Trigger Source.
+
+Sets the digital to analog converter trigger source, which can be taken from
+various timers, an external trigger or a software trigger.
+
+@param[in] dac_trig_src uint32_t. Taken from @ref dac_trig2_sel or @ref
+dac_trig1_sel or a logical OR of one of each of these to set both channels
+simultaneously.
+*/
+
+void dac_set_trigger_source(uint32_t dac_trig_src)
+{
+ DAC_CR |= dac_trig_src;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable and Set DAC Channel Waveform Generation.
+
+Enable the digital to analog converter waveform generation as either
+pseudo-random noise or triangular wave. These signals are superimposed on
+existing output values in the DAC output registers.
+
+@note The DAC trigger must be enabled for this to work.
+
+@param[in] dac_wave_ens uint32_t. Taken from @ref dac_wave1_en or @ref
+dac_wave2_en or a logical OR of one of each of these to set both channels
+simultaneously.
+*/
+
+void dac_set_waveform_generation(uint32_t dac_wave_ens)
+{
+ DAC_CR |= dac_wave_ens;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable DAC Channel Waveform Generation.
+
+Disable a digital to analog converter channel superimposed waveform generation.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_disable_waveform_generation(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_WAVE1_DIS;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_WAVE2_DIS;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude.
+
+Sets the digital to analog converter superimposed waveform generation
+characteristics. @li If the noise generation mode is set, this sets the length
+of the PRBS sequence and hence the amplitude of the output noise signal.
+Default setting is length 1. @li If the triangle wave generation mode is set,
+this sets the amplitude of the output signal as 2^(n)-1 where n is the
+parameter value. Default setting is 1.
+
+@note High amplitude levels of these waveforms can overload the DAC and distort
+the signal output.
+@note This must be called before enabling the DAC as the settings will then
+become read-only.
+@note The DAC trigger must be enabled for this to work.
+
+@param[in] dac_mamp uint32_t. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a
+logical OR of one of each of these to set both channels simultaneously.
+*/
+
+void dac_set_waveform_characteristics(uint32_t dac_mamp)
+{
+ DAC_CR |= dac_mamp;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Load DAC Data Register.
+
+Loads the appropriate digital to analog converter data register with 12 or 8 bit
+data to be converted on a channel. The data can be aligned as follows:
+@li right-aligned 8 bit data in bits 0-7
+@li right-aligned 12 bit data in bits 0-11
+@li left aligned 12 bit data in bits 4-15
+
+@param[in] dac_data uint16_t with appropriate alignment.
+@param[in] dac_data_format enum ::data_align. Alignment and size.
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_load_data_buffer_single(uint16_t dac_data, data_align dac_data_format,
+ data_channel dac_channel)
+{
+ if (dac_channel == CHANNEL_1) {
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8R1 = dac_data;
+ break;
+ case RIGHT12:
+ DAC_DHR12R1 = dac_data;
+ break;
+ case LEFT12:
+ DAC_DHR12L1 = dac_data;
+ break;
+ }
+ } else if (dac_channel == CHANNEL_2) {
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8R2 = dac_data;
+ break;
+ case RIGHT12:
+ DAC_DHR12R2 = dac_data;
+ break;
+ case LEFT12:
+ DAC_DHR12L2 = dac_data;
+ break;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Load DAC Dual Data Register.
+
+Loads the appropriate digital to analog converter dual data register with 12 or
+8 bit data to be converted for both channels. This allows high bandwidth
+simultaneous or independent analog output. The data in both channels are aligned
+identically.
+
+@param[in] dac_data1 uint16_t for channel 1 with appropriate alignment.
+@param[in] dac_data2 uint16_t for channel 2 with appropriate alignment.
+@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or
+12 bit.
+*/
+
+void dac_load_data_buffer_dual(uint16_t dac_data1, uint16_t dac_data2,
+ data_align dac_data_format)
+{
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8));
+ break;
+ case RIGHT12:
+ DAC_DHR12RD = ((dac_data1 & MASK12) |
+ ((dac_data2 & MASK12) << 16));
+ break;
+ case LEFT12:
+ DAC_DHR12LD = ((dac_data1 & MASK12) |
+ ((dac_data2 & MASK12) << 16));
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Trigger the DAC by a Software Trigger.
+
+If the trigger source is set to be a software trigger, cause a trigger to occur.
+The trigger is cleared by hardware after conversion.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_software_trigger(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1;
+ break;
+ case CHANNEL_2:
+ DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2;
+ break;
+ case CHANNEL_D:
+ DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
+ break;
+ }
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/dma_common_f24.c b/libopencm3/lib/stm32/common/dma_common_f24.c
new file mode 100644
index 0000000..6b65563
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dma_common_f24.c
@@ -0,0 +1,794 @@
+/** @addtogroup dma_file
+
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+This library supports the DMA Control System in the STM32F2 and STM32F4
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Up to two DMA controllers are supported each with 8 streams, and each stream
+having up to 8 channels hardware dedicated to various peripheral DMA signals.
+
+DMA transfers can be configured to occur between peripheral and memory in
+either direction, and memory to memory. Peripheral to peripheral transfer
+is not supported. Circular mode transfers are also supported in transfers
+involving a peripheral. An arbiter is provided to resolve priority DMA
+requests. Transfers can be made with 8, 16 or 32 bit words.
+
+Each stream has access to a 4 word deep FIFO and can use double buffering
+by means of two memory pointers. When using the FIFO it is possible to
+configure transfers to occur in indivisible bursts.
+
+It is also possible to select a peripheral instead of the DMA controller to
+control the flow of data. This limits the functionality but is useful when the
+number of transfers is unknown.
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/dma.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Reset
+
+The specified stream is disabled and configuration registers are cleared.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_stream_reset(uint32_t dma, uint8_t stream)
+{
+/* Disable stream (must be done before register is otherwise changed). */
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
+/* Reset all config bits. */
+ DMA_SCR(dma, stream) = 0;
+/* Reset data transfer number. */
+ DMA_SNDTR(dma, stream) = 0;
+/* Reset peripheral and memory addresses. */
+ DMA_SPAR(dma, stream) = 0;
+ DMA_SM0AR(dma, stream) = 0;
+ DMA_SM1AR(dma, stream) = 0;
+/* This is the default setting */
+ DMA_SFCR(dma, stream) = 0x21;
+/* Reset all stream interrupt flags using the interrupt flag clear register. */
+ uint32_t mask = DMA_ISR_MASK(stream);
+ if (stream < 4) {
+ DMA_LIFCR(dma) |= mask;
+ } else {
+ DMA_HIFCR(dma) |= mask;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Clear Interrupt Flag
+
+The interrupt flag for the stream is cleared. More than one interrupt for the
+same stream may be cleared by using the bitwise OR of the interrupt flags.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] interrupts unsigned int32. Bitwise OR of interrupt numbers: @ref
+dma_if_offset
+*/
+
+void dma_clear_interrupt_flags(uint32_t dma, uint8_t stream,
+ uint32_t interrupts)
+{
+ /* Get offset to interrupt flag location in stream field */
+ uint32_t flags = (interrupts << DMA_ISR_OFFSET(stream));
+ /* First four streams are in low register. Flag clear must be set then
+ * reset.
+ */
+ if (stream < 4) {
+ DMA_LIFCR(dma) = flags;
+ } else {
+ DMA_HIFCR(dma) = flags;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Read Interrupt Flag
+
+The interrupt flag for the stream is returned.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
+@returns bool interrupt flag is set.
+*/
+
+bool dma_get_interrupt_flag(uint32_t dma, uint8_t stream, uint32_t interrupt)
+{
+ /* get offset to interrupt flag location in stream field. Assumes
+ * stream and interrupt parameters are integers.
+ */
+ uint32_t flag = (interrupt << DMA_ISR_OFFSET(stream));
+ /* First four streams are in low register */
+ if (stream < 4) {
+ return ((DMA_LISR(dma) & flag) > 0);
+ } else {
+ return ((DMA_HISR(dma) & flag) > 0);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Transfer Direction
+
+Set peripheral to memory, memory to peripheral or memory to memory. If memory
+to memory mode is selected, circular mode and double buffer modes are disabled.
+Ensure that these modes are not enabled at a later time.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] direction unsigned int32. Data transfer direction @ref dma_st_dir
+*/
+
+void dma_set_transfer_mode(uint32_t dma, uint8_t stream, uint32_t direction)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_DIR_MASK);
+ /* Disable circular and double buffer modes if memory to memory
+ * transfers are in effect. (Direct Mode is automatically disabled by
+ * hardware)
+ */
+ if (direction == DMA_SxCR_DIR_MEM_TO_MEM) {
+ reg32 &= ~(DMA_SxCR_CIRC | DMA_SxCR_DBM);
+ }
+
+ DMA_SCR(dma, stream) = (reg32 | direction);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Priority
+
+Stream Priority has four levels: low to very high. This has precedence over the
+hardware priority. In the event of equal software priority the lower numbered
+stream has priority.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] prio unsigned int32. Priority level @ref dma_st_pri.
+*/
+
+void dma_set_priority(uint32_t dma, uint8_t stream, uint32_t prio)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_PL_MASK);
+ DMA_SCR(dma, stream) |= prio;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Memory Word Width
+
+Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
+alignment information if the source and destination widths do not match.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] mem_size unsigned int32. Memory word width @ref dma_st_memwidth.
+*/
+
+void dma_set_memory_size(uint32_t dma, uint8_t stream, uint32_t mem_size)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_MSIZE_MASK);
+ DMA_SCR(dma, stream) |= mem_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Word Width
+
+Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
+for alignment information if the source and destination widths do not match, or
+if the peripheral does not support byte or half-word writes.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] peripheral_size unsigned int32. Peripheral word width @ref
+dma_st_perwidth.
+*/
+
+void dma_set_peripheral_size(uint32_t dma, uint8_t stream,
+ uint32_t peripheral_size)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_PSIZE_MASK);
+ DMA_SCR(dma, stream) |= peripheral_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Memory Increment after Transfer
+
+Following each transfer the current memory address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
+value held by the base memory address register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_memory_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Memory Increment after Transfer
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_memory_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Variable Sized Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
+value held by the base peripheral address register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) | DMA_SxCR_PINC);
+ DMA_SCR(dma, stream) = (reg32 & ~DMA_SxCR_PINCOS);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Peripheral Increment after Transfer
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Fixed Sized Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+4 regardless of the data size. The value held by the base peripheral address
+register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fixed_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= (DMA_SxCR_PINC | DMA_SxCR_PINCOS);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Memory Circular Mode
+
+After the number of bytes/words to be transferred has been completed, the
+original transfer block size, memory and peripheral base addresses are
+reloaded and the process repeats.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@note This cannot be used with memory to memory mode. It is disabled
+automatically if the peripheral is selected as the flow controller.
+It is enabled automatically if double buffered mode is selected.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_circular_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_CIRC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Channel Select
+
+Associate an input channel to the stream. Not every channel is allocated to a
+hardware DMA request signal. The allocations for each stream are given in the
+STM32F4 Reference Manual.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] channel unsigned int8. Channel selection @ref dma_ch_sel
+*/
+
+void dma_channel_select(uint32_t dma, uint8_t stream, uint32_t channel)
+{
+ DMA_SCR(dma, stream) |= channel;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Memory Burst Configuration
+
+Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
+if direct mode is used.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] burst unsigned int8. Memory Burst selection @ref dma_mburst
+*/
+
+void dma_set_memory_burst(uint32_t dma, uint8_t stream, uint32_t burst)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_MBURST_MASK);
+ DMA_SCR(dma, stream) = (reg32 | burst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Burst Configuration
+
+Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
+if direct mode is used.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] burst unsigned int8. Peripheral Burst selection @ref dma_pburst
+*/
+
+void dma_set_peripheral_burst(uint32_t dma, uint8_t stream, uint32_t burst)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_PBURST_MASK);
+ DMA_SCR(dma, stream) = (reg32 | burst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Initial Target Memory
+
+In double buffered mode, set the target memory (M0 or M1) to be used for the
+first transfer.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] memory unsigned int8. Initial memory pointer to use: 0 or 1
+*/
+
+void dma_set_initial_target(uint32_t dma, uint8_t stream, uint8_t memory)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_CT);
+ if (memory == 1) {
+ reg32 |= DMA_SxCR_CT;
+ }
+
+ DMA_SCR(dma, stream) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Read Current Memory Target
+
+In double buffer mode, return the current memory target (M0 or M1). It is
+possible to update the memory pointer in the register that is <b> not </b>
+currently in use. An attempt to change the register currently in use will cause
+the stream to be disabled and the transfer error flag to be set.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@returns unsigned int8. Memory buffer in use: 0 or 1
+*/
+
+uint8_t dma_get_target(uint32_t dma, uint8_t stream)
+{
+ if (DMA_SCR(dma, stream) & DMA_SxCR_CT) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Double Buffer Mode
+
+Double buffer mode is used for memory to/from peripheral transfers only, and in
+circular mode which is automatically enabled. Two memory buffers must be
+established with pointers stored in the memory pointer registers.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@note This cannot be used with memory to memory mode.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_double_buffer_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_DBM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Double Buffer Mode
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_double_buffer_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_DBM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Flow Control
+
+Set the peripheral to control DMA flow. Useful when the number of transfers is
+unknown. This is forced off when memory to memory mode is selected.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_set_peripheral_flow_control(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_PFCTRL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set DMA Flow Control
+
+Set the DMA controller to control DMA flow. This is the default.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_set_dma_flow_control(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_PFCTRL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_TEIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_HTIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_TCIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Direct Mode Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_DMEIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_DMEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Direct Mode Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_DMEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable Interrupt on FIFO Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_FEIF);
+ DMA_SFCR(dma, stream) |= DMA_SxFCR_FEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Disable Interrupt on FIFO Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) &= ~DMA_SxFCR_FEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Get FIFO Status
+
+Status of FIFO (empty. full or partial filled states) is returned. This has no
+meaning if direct mode is enabled (as the FIFO is not used).
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@returns uint32_t FIFO Status @ref dma_fifo_status
+*/
+
+uint32_t dma_fifo_status(uint32_t dma, uint8_t stream)
+{
+ return DMA_SFCR(dma, stream) & DMA_SxFCR_FS_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable Direct Mode
+
+Direct mode is the default. Data is transferred as soon as a DMA request is
+received. The FIFO is not used. This must not be set when memory to memory
+mode is selected.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_direct_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) &= ~DMA_SxFCR_DMDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable FIFO Mode
+
+Data is transferred via a FIFO.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fifo_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) |= DMA_SxFCR_DMDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Set FIFO Threshold
+
+This is the filled level at which data is transferred out of the FIFO to the
+destination.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] threshold unsigned int8. Threshold setting @ref dma_fifo_thresh
+*/
+
+void dma_set_fifo_threshold(uint32_t dma, uint8_t stream, uint32_t threshold)
+{
+ uint32_t reg32 = (DMA_SFCR(dma, stream) & ~DMA_SxFCR_FTH_MASK);
+ DMA_SFCR(dma, stream) = (reg32 | threshold);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_stream(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable
+
+@note The DMA stream registers retain their values when the stream is disabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_stream(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Peripheral Address
+
+Set the address of the peripheral register to or from which data is to be
+transferred. Refer to the documentation for the specific peripheral.
+
+@note The DMA stream must be disabled before setting this address. This function
+has no effect if the stream is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Peripheral Address.
+*/
+
+void dma_set_peripheral_address(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) {
+ DMA_SPAR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Base Memory Address 0
+
+Set the address pointer to the memory location for DMA transfers. The DMA stream
+must normally be disabled before setting this address, however it is possible
+to change this in double buffer mode when the current target is memory area 1
+(see @ref dma_get_target).
+
+This is the default base memory address used in direct mode.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ uint32_t reg32 = DMA_SCR(dma, stream);
+ if (!(reg32 & DMA_SxCR_EN) ||
+ ((reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
+ DMA_SM0AR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Base Memory Address 1
+
+Set the address pointer to the memory location for DMA transfers. The DMA stream
+must normally be disabled before setting this address, however it is possible
+to change this in double buffer mode when the current target is memory area 0
+(see @ref dma_get_target).
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address_1(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ uint32_t reg32 = DMA_SCR(dma, stream);
+ if (!(reg32 & DMA_SxCR_EN) ||
+ (!(reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
+ DMA_SM1AR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Transfer Block Size
+
+@note The DMA stream must be disabled before setting this count value. The count
+is not changed if the stream is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] number unsigned int16. Number of data words to transfer (65535
+maximum).
+*/
+
+void dma_set_number_of_data(uint32_t dma, uint8_t stream, uint16_t number)
+{
+ DMA_SNDTR(dma, stream) = number;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/dma_common_l1f013.c b/libopencm3/lib/stm32/common/dma_common_l1f013.c
new file mode 100644
index 0000000..d705964
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dma_common_l1f013.c
@@ -0,0 +1,435 @@
+/** @addtogroup dma_file
+
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+This library supports the DMA Control System in the STM32 series of ARM Cortex
+Microcontrollers by ST Microelectronics.
+
+Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to
+the first DMA controller and 5 to the second. Each channel is connected to
+between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement.
+
+DMA transfers can be configured to occur between peripheral and memory in
+any combination including memory to memory. Circular mode transfers are
+also supported in transfers involving a peripheral. An arbiter is provided
+to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit
+words.
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/dma.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Reset
+
+The channel is disabled and configuration registers are cleared.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_channel_reset(uint32_t dma, uint8_t channel)
+{
+ /* Disable channel and reset config bits. */
+ DMA_CCR(dma, channel) = 0;
+ /* Reset data transfer number. */
+ DMA_CNDTR(dma, channel) = 0;
+ /* Reset peripheral address. */
+ DMA_CPAR(dma, channel) = 0;
+ /* Reset memory address. */
+ DMA_CMAR(dma, channel) = 0;
+ /* Reset interrupt flags. */
+ DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Clear Interrupt Flag
+
+The interrupt flag for the channel is cleared. More than one interrupt for the
+same channel may be cleared by using the logical OR of the interrupt flags.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: @ref dma_ch
+@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref
+dma_if_offset
+*/
+
+void dma_clear_interrupt_flags(uint32_t dma, uint8_t channel,
+ uint32_t interrupts)
+{
+/* Get offset to interrupt flag location in channel field */
+ uint32_t flags = (interrupts << DMA_FLAG_OFFSET(channel));
+ DMA_IFCR(dma) = flags;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Read Interrupt Flag
+
+The interrupt flag for the channel is returned.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: @ref dma_ch
+@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
+@returns bool interrupt flag is set.
+*/
+
+bool dma_get_interrupt_flag(uint32_t dma, uint8_t channel, uint32_t interrupt)
+{
+/* get offset to interrupt flag location in channel field. */
+ uint32_t flag = (interrupt << DMA_FLAG_OFFSET(channel));
+ return ((DMA_ISR(dma) & flag) > 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory to Memory Transfers
+
+Memory to memory transfers do not require a trigger to activate each transfer.
+Transfers begin immediately the channel has been enabled, and proceed without
+intervention.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_mem2mem_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM;
+ DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Priority
+
+Channel Priority has four levels: low to very high. This has precedence over the
+hardware priority.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] prio unsigned int32. Priority level @ref dma_ch_pri.
+*/
+
+void dma_set_priority(uint32_t dma, uint8_t channel, uint32_t prio)
+{
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK);
+ DMA_CCR(dma, channel) |= prio;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Memory Word Width
+
+Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
+alignment information if the source and destination widths do not match.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth.
+*/
+
+void dma_set_memory_size(uint32_t dma, uint8_t channel, uint32_t mem_size)
+{
+
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_MSIZE_MASK);
+ DMA_CCR(dma, channel) |= mem_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Peripheral Word Width
+
+Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
+for alignment information if the source and destination widths do not match, or
+if the peripheral does not support byte or half-word writes.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] peripheral_size unsigned int32. Peripheral word width @ref
+dma_ch_perwidth.
+*/
+
+void dma_set_peripheral_size(uint32_t dma, uint8_t channel,
+ uint32_t peripheral_size)
+{
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK);
+ DMA_CCR(dma, channel) |= peripheral_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory Increment after Transfer
+
+Following each transfer the current memory address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
+value held by the base memory address register is unchanged.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_memory_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Memory Increment after Transfer
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_memory_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
+value held by the base peripheral address register is unchanged.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Peripheral Increment after Transfer
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory Circular Mode
+
+After the number of bytes/words to be transferred has been completed, the
+original transfer block size, memory and peripheral base addresses are
+reloaded and the process repeats.
+
+@note This cannot be used with memory to memory mode, which is explictly
+disabled here.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_circular_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
+ DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Transfers from a Peripheral
+
+The data direction is set to read from a peripheral.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_set_read_from_peripheral(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Transfers from Memory
+
+The data direction is set to read from memory.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_set_read_from_memory(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_DIR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_channel(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable
+
+@note The DMA channel registers retain their values when the channel is
+disabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_channel(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Peripheral Address
+
+Set the address of the peripheral register to or from which data is to be
+transferred. Refer to the documentation for the specific peripheral.
+
+@note The DMA channel must be disabled before setting this address. This
+function has no effect if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] address unsigned int32. Peripheral Address.
+*/
+
+void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address)
+{
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
+ DMA_CPAR(dma, channel) = (uint32_t) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Base Memory Address
+
+@note The DMA channel must be disabled before setting this address. This
+function has no effect if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address)
+{
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
+ DMA_CMAR(dma, channel) = (uint32_t) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Transfer Block Size
+
+@note The DMA channel must be disabled before setting this count value. The
+count is not changed if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] number unsigned int16. Number of data words to transfer (65535
+maximum).
+*/
+
+void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number)
+{
+ DMA_CNDTR(dma, channel) = number;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/exti_common_all.c b/libopencm3/lib/stm32/common/exti_common_all.c
new file mode 100644
index 0000000..f7b0d0c
--- /dev/null
+++ b/libopencm3/lib/stm32/common/exti_common_all.c
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This provides the code for the "next gen" EXTI block provided in F2/F4/L1
+ * devices. (differences only in the source selection)
+ */
+/**@{*/
+
+
+#include <libopencm3/stm32/exti.h>
+#include <libopencm3/stm32/gpio.h>
+#if !defined(AFIO_BASE)
+# include <libopencm3/stm32/syscfg.h>
+#endif
+
+void exti_set_trigger(uint32_t extis, enum exti_trigger_type trig)
+{
+ switch (trig) {
+ case EXTI_TRIGGER_RISING:
+ EXTI_RTSR |= extis;
+ EXTI_FTSR &= ~extis;
+ break;
+ case EXTI_TRIGGER_FALLING:
+ EXTI_RTSR &= ~extis;
+ EXTI_FTSR |= extis;
+ break;
+ case EXTI_TRIGGER_BOTH:
+ EXTI_RTSR |= extis;
+ EXTI_FTSR |= extis;
+ break;
+ }
+}
+
+void exti_enable_request(uint32_t extis)
+{
+ /* Enable interrupts. */
+ EXTI_IMR |= extis;
+
+ /* Enable events. */
+ EXTI_EMR |= extis;
+}
+
+void exti_disable_request(uint32_t extis)
+{
+ /* Disable interrupts. */
+ EXTI_IMR &= ~extis;
+
+ /* Disable events. */
+ EXTI_EMR &= ~extis;
+}
+
+/*
+ * Reset the interrupt request by writing a 1 to the corresponding
+ * pending bit register.
+ */
+void exti_reset_request(uint32_t extis)
+{
+ EXTI_PR = extis;
+}
+
+/*
+ * Check the flag of a given EXTI interrupt.
+ * */
+uint32_t exti_get_flag_status(uint32_t exti)
+{
+ return EXTI_PR & exti;
+}
+
+/*
+ * Remap an external interrupt line to the corresponding pin on the
+ * specified GPIO port.
+ *
+ * TODO: This could be rewritten in fewer lines of code.
+ */
+void exti_select_source(uint32_t exti, uint32_t gpioport)
+{
+ uint32_t line;
+ for (line = 0; line < 16; line++) {
+ if (!(exti & (1 << line))) {
+ continue;
+ }
+
+ uint32_t bits = 0, mask = 0x0F;
+
+ switch (gpioport) {
+ case GPIOA:
+ bits = 0;
+ break;
+ case GPIOB:
+ bits = 1;
+ break;
+ case GPIOC:
+ bits = 2;
+ break;
+ case GPIOD:
+ bits = 3;
+ break;
+#if defined(GPIOE) && defined(GPIO_PORT_E_BASE)
+ case GPIOE:
+ bits = 4;
+ break;
+#endif
+#if defined(GPIOF) && defined(GPIO_PORT_F_BASE)
+ case GPIOF:
+ bits = 5;
+ break;
+#endif
+#if defined(GPIOG) && defined(GPIO_PORT_G_BASE)
+ case GPIOG:
+ bits = 6;
+ break;
+#endif
+#if defined(GPIOH) && defined(GPIO_PORT_H_BASE)
+ case GPIOH:
+ bits = 7;
+ break;
+#endif
+#if defined(GPIOI) && defined(GPIO_PORT_I_BASE)
+ case GPIOI:
+ bits = 8;
+ break;
+#endif
+ }
+
+ uint8_t shift = (uint8_t)(4 * (line % 4));
+ uint32_t reg = line / 4;
+ bits <<= shift;
+ mask <<= shift;
+
+#if defined(AFIO_BASE)
+ AFIO_EXTICR(reg) = (AFIO_EXTICR(reg) & ~mask) | bits;
+#else
+ SYSCFG_EXTICR(reg) = (SYSCFG_EXTICR(reg) & ~mask) | bits;
+#endif
+ };
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f01.c b/libopencm3/lib/stm32/common/flash_common_f01.c
new file mode 100644
index 0000000..65f64bd
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f01.c
@@ -0,0 +1,235 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the FLASH Prefetch Buffer
+
+This buffer is used for instruction fetches and is enabled by default after
+reset.
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+enabled or disabled. Changes are normally made while the clock is running in
+the power-on low frequency mode before being set to a higher speed mode.
+See the reference manual for details.
+*/
+
+void flash_prefetch_buffer_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_PRFTBE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Prefetch Buffer
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+set to disabled. See the reference manual for details.
+*/
+
+void flash_prefetch_buffer_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_PRFTBE;
+}
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Number of Wait States
+
+Used to match the system clock to the FLASH memory access time. See the
+reference manual for more information on clock speed ranges for each wait state.
+The latency must be changed to the appropriate value <b>before</b> any increase
+in clock speed, or <b>after</b> any decrease in clock speed.
+
+@param[in] uint32_t ws: values from @ref flash_latency.
+*/
+
+void flash_set_ws(uint32_t ws)
+{
+ FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY) | ws;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Flash Program and Erase Controller
+
+This enables write access to the Flash memory. It is locked by default on
+reset.
+*/
+
+void flash_unlock(void)
+{
+ /* Clear the unlock state. */
+ FLASH_CR |= FLASH_CR_LOCK;
+
+ /* Authorize the FPEC access. */
+ FLASH_KEYR = FLASH_KEYR_KEY1;
+ FLASH_KEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Flash Program and Erase Controller
+
+Used to prevent spurious writes to FLASH.
+*/
+
+void flash_lock(void)
+{
+ FLASH_CR |= FLASH_CR_LOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Error Status Flag
+
+*/
+
+void flash_clear_pgerr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the End of Operation Status Flag
+
+*/
+
+void flash_clear_eop_flag(void)
+{
+ FLASH_SR |= FLASH_SR_EOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Write Protect Error Status Flag
+
+*/
+
+void flash_clear_wrprterr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_WRPRTERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Busy Status Flag
+
+*/
+
+void flash_clear_bsy_flag(void)
+{
+ FLASH_SR &= ~FLASH_SR_BSY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait until Last Operation has Ended
+
+This loops indefinitely until an operation (write or erase) has completed by
+testing the busy flag.
+*/
+
+void flash_wait_for_last_operation(void)
+{
+ while ((flash_get_status_flags() & FLASH_SR_BSY) == FLASH_SR_BSY);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 32 bit Word to FLASH
+
+This performs all operations necessary to program a 32 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+Status bit polling is used to detect end of operation.
+
+@param[in] uint32_t address. Full address of flash word to be programmed.
+@param[in] uint32_t data.
+*/
+
+void flash_program_word(uint32_t address, uint32_t data)
+{
+ flash_program_half_word(address,(uint16_t)data);
+ flash_program_half_word(address+2,(uint16_t)(data>>16));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Option Byte Access
+
+This enables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_unlock_option_bytes(void)
+{
+ /* F1 uses same keys for flash and option */
+ FLASH_OPTKEYR = FLASH_KEYR_KEY1;
+ FLASH_OPTKEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All Option Bytes
+
+This performs all operations necessary to erase the option bytes. These must
+first be fully erased before attempting to program them, therefore it is
+recommended to check these after an erase attempt.
+*/
+
+void flash_erase_option_bytes(void)
+{
+ flash_wait_for_last_operation();
+
+ if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_CR |= FLASH_CR_OPTER; /* Enable option byte erase. */
+ FLASH_CR |= FLASH_CR_STRT;
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_OPTER; /* Disable option byte erase. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program the Option Bytes
+
+This performs all operations necessary to program the option bytes.
+The write protect error flag should be checked separately for the event that
+an option byte had not been properly erased before calling this function.
+
+Only the lower 8 bits of the data is significant.
+
+@param[in] uint32_t address. Address of option byte from @ref flash_options.
+@param[in] uint16_t data.
+*/
+
+void flash_program_option_bytes(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+
+ if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_CR |= FLASH_CR_OPTPG; /* Enable option byte programming. */
+ MMIO16(address) = data;
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_OPTPG; /* Disable option byte programming. */
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f234.c b/libopencm3/lib/stm32/common/flash_common_f234.c
new file mode 100644
index 0000000..1d99566
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f234.c
@@ -0,0 +1,121 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Number of Wait States
+
+Used to match the system clock to the FLASH memory access time. See the
+programming manual for more information on clock speed ranges. The latency must
+be changed to the appropriate value <b>before</b> any increase in clock
+speed, or <b>after</b> any decrease in clock speed.
+
+@param[in] uint32_t ws: values from @ref flash_latency.
+*/
+
+void flash_set_ws(uint32_t ws)
+{
+ uint32_t reg32;
+
+ reg32 = FLASH_ACR;
+ reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2));
+ reg32 |= ws;
+ FLASH_ACR = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Flash Program and Erase Controller
+
+This enables write access to the Flash memory. It is locked by default on
+reset.
+*/
+
+void flash_unlock(void)
+{
+ /* Clear the unlock sequence state. */
+ FLASH_CR |= FLASH_CR_LOCK;
+
+ /* Authorize the FPEC access. */
+ FLASH_KEYR = FLASH_KEYR_KEY1;
+ FLASH_KEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Flash Program and Erase Controller
+
+Used to prevent spurious writes to FLASH.
+*/
+
+void flash_lock(void)
+{
+ FLASH_CR |= FLASH_CR_LOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Error Status Flag
+
+*/
+
+void flash_clear_pgperr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGPERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the End of Operation Status Flag
+
+*/
+
+void flash_clear_eop_flag(void)
+{
+ FLASH_SR |= FLASH_SR_EOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Busy Status Flag
+
+*/
+
+void flash_clear_bsy_flag(void)
+{
+ FLASH_SR &= ~FLASH_SR_BSY;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait until Last Operation has Ended
+
+This loops indefinitely until an operation (write or erase) has completed by
+testing the busy flag.
+*/
+
+void flash_wait_for_last_operation(void)
+{
+ while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f24.c b/libopencm3/lib/stm32/common/flash_common_f24.c
new file mode 100644
index 0000000..03883fb
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f24.c
@@ -0,0 +1,416 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Program Parallelism Size
+
+Set the programming word width. Note carefully the power supply voltage
+restrictions under which the different word sizes may be used. See the
+programming manual for more information.
+
+@param psize: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+static inline void flash_set_program_size(uint32_t psize)
+{
+ FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8);
+ FLASH_CR |= psize;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Data Cache
+
+*/
+
+void flash_dcache_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_DCE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the Data Cache
+
+*/
+
+void flash_dcache_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_DCE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Instruction Cache
+
+*/
+
+void flash_icache_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_ICE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the Instruction Cache
+
+*/
+
+void flash_icache_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_ICE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the FLASH Prefetch Buffer
+
+This buffer is used for instruction fetches and is enabled by default after
+reset.
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+enabled or disabled. Changes are normally made while the clock is running in
+the power-on low frequency mode before being set to a higher speed mode.
+See the reference manual for details.
+*/
+
+void flash_prefetch_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Prefetch Buffer
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+set to disabled. See the reference manual for details.
+*/
+
+void flash_prefetch_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset the Data Cache
+
+The data cache must be disabled for this to have effect.
+*/
+
+void flash_dcache_reset(void)
+{
+ FLASH_ACR |= FLASH_ACR_DCRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset the Instruction Cache
+
+The instruction cache must be disabled for this to have effect.
+*/
+
+void flash_icache_reset(void)
+{
+ FLASH_ACR |= FLASH_ACR_ICRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Sequence Error Flag
+
+This flag is set when incorrect programming configuration has been made.
+*/
+
+void flash_clear_pgserr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGSERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Alignment Error Flag
+
+*/
+
+void flash_clear_pgaerr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGAERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Write Protect Error Flag
+
+*/
+
+void flash_clear_wrperr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_WRPERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear All Status Flags
+
+Program error, end of operation, write protect error, busy.
+*/
+
+void flash_clear_status_flags(void)
+{
+ flash_clear_pgserr_flag();
+ flash_clear_pgaerr_flag();
+ flash_clear_wrperr_flag();
+ flash_clear_pgperr_flag();
+ flash_clear_eop_flag();
+ flash_clear_bsy_flag();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Option Byte Access
+
+This enables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_unlock_option_bytes(void)
+{
+ /* Clear the unlock state. */
+ FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
+
+ /* Unlock option bytes. */
+ FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
+ FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Option Byte Access
+
+This disables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_lock_option_bytes(void)
+{
+ FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 64 bit Word to FLASH
+
+This performs all operations necessary to program a 64 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint64_t data.
+*/
+
+void flash_program_double_word(uint32_t address, uint64_t data)
+{
+ /* Ensure that all flash operations are complete. */
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X64);
+
+ /* Enable writes to flash. */
+ FLASH_CR |= FLASH_CR_PG;
+
+ /* Program the double_word. */
+ MMIO64(address) = data;
+
+ /* Wait for the write to complete. */
+ flash_wait_for_last_operation();
+
+ /* Disable writes to flash. */
+ FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 32 bit Word to FLASH
+
+This performs all operations necessary to program a 32 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint32_t data.
+*/
+
+void flash_program_word(uint32_t address, uint32_t data)
+{
+ /* Ensure that all flash operations are complete. */
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X32);
+
+ /* Enable writes to flash. */
+ FLASH_CR |= FLASH_CR_PG;
+
+ /* Program the word. */
+ MMIO32(address) = data;
+
+ /* Wait for the write to complete. */
+ flash_wait_for_last_operation();
+
+ /* Disable writes to flash. */
+ FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Half Word to FLASH
+
+This performs all operations necessary to program a 16 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint16_t data.
+*/
+
+void flash_program_half_word(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X16);
+
+ FLASH_CR |= FLASH_CR_PG;
+
+ MMIO16(address) = data;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program an 8 bit Byte to FLASH
+
+This performs all operations necessary to program an 8 bit byte to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint8_t data.
+*/
+
+void flash_program_byte(uint32_t address, uint8_t data)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X8);
+
+ FLASH_CR |= FLASH_CR_PG;
+
+ MMIO8(address) = data;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Data Block to FLASH
+
+This programs an arbitrary length data block to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address. Starting address in Flash.
+@param[in] uint8_t *data. Pointer to start of data block.
+@param[in] uint32_t len. Length of data block.
+*/
+
+void flash_program(uint32_t address, uint8_t *data, uint32_t len)
+{
+ /* TODO: Use dword and word size program operations where possible for
+ * turbo speed.
+ */
+ uint32_t i;
+ for (i = 0; i < len; i++) {
+ flash_program_byte(address+i, data[i]);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase a Sector of FLASH
+
+This performs all operations necessary to erase a sector in FLASH memory.
+The page should be checked to ensure that it was properly erased. A sector must
+first be fully erased before attempting to program it.
+
+See the reference manual or the FLASH programming manual for details.
+
+@param[in] uint32_t sector (0 - 11).
+@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+void flash_erase_sector(uint8_t sector, uint32_t program_size)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(program_size);
+
+ FLASH_CR &= ~(0xF << 3);
+ FLASH_CR |= (sector << 3) & 0x78;
+ FLASH_CR |= FLASH_CR_SER;
+ FLASH_CR |= FLASH_CR_STRT;
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_SER;
+ FLASH_CR &= ~(0xF << 3);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All FLASH
+
+This performs all operations necessary to erase all sectors in the FLASH
+memory.
+
+@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+void flash_erase_all_sectors(uint32_t program_size)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(program_size);
+
+ FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
+ FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program the Option Bytes
+
+This performs all operations necessary to program the option bytes.
+The option bytes do not need to be erased first.
+
+@param[in] uint32_t data to be programmed.
+*/
+
+void flash_program_option_bytes(uint32_t data)
+{
+ flash_wait_for_last_operation();
+
+ if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_OPTCR = data & ~0x3;
+ FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */
+ flash_wait_for_last_operation();
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/gpio_common_all.c b/libopencm3/lib/stm32/common/gpio_common_all.c
new file mode 100644
index 0000000..3821928
--- /dev/null
+++ b/libopencm3/lib/stm32/common/gpio_common_all.c
@@ -0,0 +1,151 @@
+/** @addtogroup gpio_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define WEAK __attribute__((weak))
+
+#include <libopencm3/stm32/gpio.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set a Group of Pins Atomic
+
+Set one or more pins of the given GPIO port to 1 in an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_set(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_BSRR(gpioport) = gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear a Group of Pins Atomic
+
+Clear one or more pins of the given GPIO port to 0 in an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_clear(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_BSRR(gpioport) = (gpios << 16);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read a Group of Pins.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be read, use logical OR '|' to separate
+ them.
+@return Unsigned int16 value of the pin values. The bit position of the pin
+ value returned corresponds to the pin number.
+*/
+uint16_t gpio_get(uint32_t gpioport, uint16_t gpios)
+{
+ return gpio_port_read(gpioport) & gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Toggle a Group of Pins
+
+Toggle one or more pins of the given GPIO port. This is not an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_toggle(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_ODR(gpioport) ^= gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read from a Port
+
+Read the current value of the given GPIO port. Only the lower 16 bits contain
+valid pin data.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@return Unsigned int16. The value held in the specified GPIO port.
+*/
+uint16_t gpio_port_read(uint32_t gpioport)
+{
+ return (uint16_t)GPIO_IDR(gpioport);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Write to a Port
+
+Write a value to the given GPIO port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] data Unsigned int16. The value to be written to the GPIO port.
+*/
+void gpio_port_write(uint32_t gpioport, uint16_t data)
+{
+ GPIO_ODR(gpioport) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Configuration of a Group of Pins
+
+The configuration of one or more pins of the given GPIO port is locked. There
+is no mechanism to unlock these via software. Unlocking occurs at the next
+reset.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be locked, use logical OR '|' to separate
+ them.
+*/
+void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios)
+{
+ uint32_t reg32;
+
+ /* Special "Lock Key Writing Sequence", see datasheet. */
+ GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
+ GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */
+ GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
+ reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
+ reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
+
+ /* Tell the compiler the variable is actually used. It will get
+ * optimized out anyways.
+ */
+ reg32 = reg32;
+
+ /* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/gpio_common_f0234.c b/libopencm3/lib/stm32/common/gpio_common_f0234.c
new file mode 100644
index 0000000..9d79074
--- /dev/null
+++ b/libopencm3/lib/stm32/common/gpio_common_f0234.c
@@ -0,0 +1,206 @@
+/** @addtogroup gpio_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
+functionality with a number of alternate functions and must be configured to
+the alternate function mode if these are to be accessed. A feature is available
+to remap alternative functions to a limited set of alternative pins in the
+event of a clash of requirements.
+
+The data registers associated with each port for input and output are 32 bit
+with the upper 16 bits unused. The output buffer must be written as a 32 bit
+word, but individual bits may be set or reset separately in atomic operations
+to avoid race conditions during interrupts. Bits may also be individually
+locked to prevent accidental configuration changes. Once locked the
+configuration cannot be changed until after the next reset.
+
+Each port bit can be configured as analog or digital input, the latter can be
+floating or pulled up or down. As outputs they can be configured as either
+push-pull or open drain, digital I/O or alternate function, and with maximum
+output speeds of 2MHz, 10MHz, or 50MHz.
+
+On reset all ports are configured as digital floating input.
+
+@section gpio_api_ex Basic GPIO Handling API.
+
+Example 1: Push-pull digital output actions with pullup on ports C2 and C9
+
+@code
+ gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT,
+ GPIO_PUPD_PULLUP, GPIO2 | GPIO9);
+ gpio_output_options(GPIOC, GPIO_OTYPE_PP,
+ GPIO_OSPEED_25MHZ, GPIO2 | GPIO9);
+ gpio_set(GPIOC, GPIO2 | GPIO9);
+ gpio_clear(GPIOC, GPIO2);
+ gpio_toggle(GPIOC, GPIO2 | GPIO9);
+ gpio_port_write(GPIOC, 0x204);
+@endcode
+
+Example 2: Digital input on port C12 with pullup
+
+@code
+ gpio_mode_setup(GPIOC, GPIO_MODE_INPUT,
+ GPIO_PUPD_PULLUP, GPIO12);
+ reg16 = gpio_port_read(GPIOC);
+@endcode
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/gpio.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Pin Mode
+
+Sets the Pin Direction and Analog/Digital Mode, and Output Pin Pullup,
+for a set of GPIO pins on a given GPIO port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
+@param[in] pull_up_down Unsigned int8. Pin pullup/pulldown configuration @ref
+gpio_pup
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down,
+ uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t moder, pupd;
+
+ /*
+ * We want to set the config only for the pins mentioned in gpios,
+ * but keeping the others, so read out the actual config first.
+ */
+ moder = GPIO_MODER(gpioport);
+ pupd = GPIO_PUPDR(gpioport);
+
+ for (i = 0; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+
+ moder &= ~GPIO_MODE_MASK(i);
+ moder |= GPIO_MODE(i, mode);
+ pupd &= ~GPIO_PUPD_MASK(i);
+ pupd |= GPIO_PUPD(i, pull_up_down);
+ }
+
+ /* Set mode and pull up/down control registers. */
+ GPIO_MODER(gpioport) = moder;
+ GPIO_PUPDR(gpioport) = pupd;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Output Options
+
+When the pin is set to output mode, this sets the configuration (analog/digital
+and open drain/push pull) and speed, for a set of GPIO pins on a given GPIO
+port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] otype Unsigned int8. Pin output type @ref gpio_output_type
+@param[in] speed Unsigned int8. Pin speed @ref gpio_speed
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed,
+ uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t ospeedr;
+
+ if (otype == 0x1) {
+ GPIO_OTYPER(gpioport) |= gpios;
+ } else {
+ GPIO_OTYPER(gpioport) &= ~gpios;
+ }
+
+ ospeedr = GPIO_OSPEEDR(gpioport);
+
+ for (i = 0; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ ospeedr &= ~GPIO_OSPEED_MASK(i);
+ ospeedr |= GPIO_OSPEED(i, speed);
+ }
+
+ GPIO_OSPEEDR(gpioport) = ospeedr;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Alternate Function Selection
+
+Set the alternate function mapping number for each pin. Most pins have
+alternate functions associated with them. When set to AF mode, a pin may be
+used for one of its allocated alternate functions selected by the number given
+here. To determine the number to be used for the desired function refer to the
+individual datasheet for the particular device. A table is given under the Pin
+Selection chapter.
+
+Note that a number of pins may be set but only with a single AF number. In
+practice this would rarely be useful as each pin is likely to require a
+different number.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] alt_func_num Unsigned int8. Pin alternate function number @ref
+gpio_af_num
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t afrl, afrh;
+
+ afrl = GPIO_AFRL(gpioport);
+ afrh = GPIO_AFRH(gpioport);
+
+ for (i = 0; i < 8; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ afrl &= ~GPIO_AFR_MASK(i);
+ afrl |= GPIO_AFR(i, alt_func_num);
+ }
+
+ for (i = 8; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ afrh &= ~GPIO_AFR_MASK(i - 8);
+ afrh |= GPIO_AFR(i - 8, alt_func_num);
+ }
+
+ GPIO_AFRL(gpioport) = afrl;
+ GPIO_AFRH(gpioport) = afrh;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/hash_common_f24.c b/libopencm3/lib/stm32/common/hash_common_f24.c
new file mode 100644
index 0000000..24d489c
--- /dev/null
+++ b/libopencm3/lib/stm32/common/hash_common_f24.c
@@ -0,0 +1,163 @@
+/** @addtogroup hash_file
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013
+ * Mikhail Avkhimenia <mikhail@avkhimenia.net>
+ *
+ * This library supports the HASH processor in the STM32F2 and STM32F4
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ * */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Mikhail Avkhimenia <mikhail@avkhimenia.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/hash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Mode
+
+Sets up the specified mode - either HASH or HMAC.
+
+@param[in] mode unsigned int8. Hash processor mode: @ref hash_mode
+*/
+
+void hash_set_mode(uint8_t mode)
+{
+ HASH_CR &= ~HASH_CR_MODE;
+ HASH_CR |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Algorithm
+
+Sets up the specified algorithm - either MD5 or SHA1.
+
+@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
+*/
+
+void hash_set_algorithm(uint8_t algorithm)
+{
+ HASH_CR &= ~HASH_CR_ALGO;
+ HASH_CR |= algorithm;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Data Type
+
+Sets up the specified data type: 32Bit, 16Bit, 8Bit, Bitstring.
+
+@param[in] datatype unsigned int8. Hash data type: @ref hash_data_type
+*/
+
+void hash_set_data_type(uint8_t datatype)
+{
+ HASH_CR &= ~HASH_CR_DATATYPE;
+ HASH_CR |= datatype;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Key Length
+
+Sets up the specified key length: Long, Short.
+
+@param[in] keylength unsigned int8. Hash data type: @ref hash_key_length
+*/
+
+void hash_set_key_length(uint8_t keylength)
+{
+ HASH_CR &= ~HASH_CR_LKEY;
+ HASH_CR |= keylength;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Last Word Valid Bits
+
+Specifies the number of valid bits in the last word.
+
+@param[in] validbits unsigned int8. Number of valid bits.
+*/
+
+void hash_set_last_word_valid_bits(uint8_t validbits)
+{
+ HASH_STR &= ~(HASH_STR_NBW);
+ HASH_STR |= validbits;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Init
+
+Initializes the HASH processor.
+
+*/
+
+void hash_init()
+{
+ HASH_CR |= HASH_CR_INIT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Add data
+
+Puts data into the HASH processor's queue.
+
+@param[in] data unsigned int32. Hash input data.
+*/
+
+void hash_add_data(uint32_t data)
+{
+ HASH_DIN = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Digest
+
+Starts the processing of the last data block.
+
+*/
+
+void hash_digest()
+{
+ HASH_STR |= HASH_STR_DCAL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Get Hash Result
+
+Makes a copy of the resulting hash.
+
+@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm.
+@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
+*/
+
+void hash_get_result(uint32_t *data)
+{
+ data[0] = HASH_HR[0];
+ data[1] = HASH_HR[1];
+ data[2] = HASH_HR[2];
+ data[3] = HASH_HR[3];
+
+ if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) {
+ data[4] = HASH_HR[4];
+ }
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/i2c_common_all.c b/libopencm3/lib/stm32/common/i2c_common_all.c
new file mode 100644
index 0000000..886f594
--- /dev/null
+++ b/libopencm3/lib/stm32/common/i2c_common_all.c
@@ -0,0 +1,419 @@
+/** @addtogroup i2c_file
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Thomas Otto <tommi@viadmin.org>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three I2C peripherals. The peripherals support SMBus and
+PMBus variants.
+
+A peripheral begins after reset in Slave mode. To become a Master a start
+condition must be generated. The peripheral will remain in Master mode unless
+a multimaster contention is lost or a stop condition is generated.
+
+@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status
+register access, Error conditions
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/rcc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Reset.
+
+The I2C peripheral and all its associated configuration registers are placed in
+the reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base.
+*/
+
+void i2c_reset(uint32_t i2c)
+{
+ switch (i2c) {
+ case I2C1:
+ rcc_periph_reset_pulse(RST_I2C1);
+ break;
+#if defined(I2C2_BASE)
+ case I2C2:
+ rcc_periph_reset_pulse(RST_I2C2);
+ break;
+#endif
+#if defined(I2C3_BASE)
+ case I2C3:
+ rcc_periph_reset_pulse(RST_I2C3);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Enable.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_peripheral_enable(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Disable.
+
+This must not be reset while in Master mode until a communication has finished.
+In Slave mode, the peripheral is disabled only after communication has ended.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_peripheral_disable(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Start Condition.
+
+If in Master mode this will cause a restart condition to occur at the end of the
+current transmission. If in Slave mode, this will initiate a start condition
+when the current bus activity is completed.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_send_start(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_START;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Stop Condition.
+
+After the current byte transfer this will initiate a stop condition if in Master
+mode, or simply release the bus if in Slave mode.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_send_stop(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Clear Stop Flag.
+
+Clear the "Send Stop" flag in the I2C config register
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_stop(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_STOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
+
+This sets an address for Slave mode operation, in 7 bit form.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int8. Slave address 0...127.
+*/
+
+void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(slave << 1);
+ I2C_OAR1(i2c) &= ~I2C_OAR1_ADDMODE;
+ I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
+
+This sets an address for Slave mode operation, in 10 bit form.
+
+@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int16. Slave address 0...1023.
+*/
+
+void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Peripheral Clock Frequency.
+
+Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note
+that this is <b> not </b> the I2C bus clock. This is set in conjunction with
+the Clock Control register to generate the Master bus clock, see @ref
+i2c_set_ccr
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] freq Unsigned int8. Clock Frequency Setting @ref i2c_clock.
+*/
+
+void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq)
+{
+ uint16_t reg16;
+ reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */
+ reg16 |= freq;
+ I2C_CR2(i2c) = reg16;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Data.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] data Unsigned int8. Byte to send.
+*/
+
+void i2c_send_data(uint32_t i2c, uint8_t data)
+{
+ I2C_DR(i2c) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Fast Mode.
+
+Set the clock frequency to the high clock rate mode (up to 400kHz). The actual
+clock frequency must be set with @ref i2c_set_clock_frequency
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_set_fast_mode(uint32_t i2c)
+{
+ I2C_CCR(i2c) |= I2C_CCR_FS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Standard Mode.
+
+Set the clock frequency to the standard clock rate mode (up to 100kHz). The
+actual clock frequency must be set with @ref i2c_set_clock_frequency
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_set_standard_mode(uint32_t i2c)
+{
+ I2C_CCR(i2c) &= ~I2C_CCR_FS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Bus Clock Frequency.
+
+Set the bus clock frequency. This is a 12 bit number (0...4095) calculated
+from the formulae given in the STM32F1 reference manual in the description
+of the CCR field. It is a divisor of the peripheral clock frequency
+@ref i2c_set_clock_frequency modified by the fast mode setting
+@ref i2c_set_fast_mode
+
+@todo provide additional API assitance to set the clock, eg macros
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095.
+*/
+
+void i2c_set_ccr(uint32_t i2c, uint16_t freq)
+{
+ uint16_t reg16;
+ reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */
+ reg16 |= freq;
+ I2C_CCR(i2c) = reg16;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the Rise Time.
+
+Set the maximum rise time on the bus according to the I2C specification, as 1
+more than the specified rise time in peripheral clock cycles. This is a 6 bit
+number.
+
+@todo provide additional APIP assistance.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] trise Unsigned int16. Rise Time Setting 0...63.
+*/
+
+void i2c_set_trise(uint32_t i2c, uint16_t trise)
+{
+ I2C_TRISE(i2c) = trise;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send the 7-bit Slave Address.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int16. Slave address 0...1023.
+@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or
+send @ref i2c_rw.
+*/
+
+void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite)
+{
+ I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Get Data.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+uint8_t i2c_get_data(uint32_t i2c)
+{
+ return I2C_DR(i2c) & 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to enable.
+*/
+void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR2(i2c) |= interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to disable.
+*/
+void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR2(i2c) &= ~interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable ACK
+
+Enables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_ack(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_ACK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable ACK
+
+Disables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_ack(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the next byte
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_next(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_POS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the current byte
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_current(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_POS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set clock duty cycle
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
+*/
+void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle)
+{
+ if (dutycycle == I2C_CCR_DUTY_DIV2) {
+ I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
+ } else {
+ I2C_CCR(i2c) |= I2C_CCR_DUTY;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_dma(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_dma(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_set_dma_last_transfer(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_LAST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Clear DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_dma_last_transfer(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_LAST;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/iwdg_common_all.c b/libopencm3/lib/stm32/common/iwdg_common_all.c
new file mode 100644
index 0000000..d9aca5a
--- /dev/null
+++ b/libopencm3/lib/stm32/common/iwdg_common_all.c
@@ -0,0 +1,149 @@
+/** @addtogroup iwdg_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
+
+This library supports the Independent Watchdog Timer System in the STM32F1xx
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The watchdog timer uses the LSI (low speed internal) clock which is low power
+and continues to operate during stop and standby modes. Its frequency is
+nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low
+as 17kHz up to 60kHz (refer to datasheet electrical characteristics).
+
+Note that the User Configuration option byte provides a means of automatically
+enabling the IWDG timer at power on (with counter value 0xFFF). If the
+relevant bit is not set, the IWDG timer must be enabled by software.
+
+@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/iwdg.h>
+
+#define LSI_FREQUENCY 32000
+#define COUNT_LENGTH 12
+#define COUNT_MASK ((1 << COUNT_LENGTH)-1)
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Enable Watchdog Timer
+
+The watchdog timer is started. The timeout period defaults to 512 milliseconds
+unless it has been previously defined.
+
+*/
+
+void iwdg_start(void)
+{
+ IWDG_KR = IWDG_KR_START;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Set Period in Milliseconds
+
+The countdown period is converted into count and prescale values. The maximum
+period is 32.76 seconds; values above this are truncated. Periods less than 1ms
+are not supported by this library.
+
+A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds)
+can occasionally occur if the prescale or preload registers are currently busy
+loading a previous value.
+
+@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog
+reset until a system reset is issued.
+*/
+
+void iwdg_set_period_ms(uint32_t period)
+{
+ uint32_t count, prescale, reload, exponent;
+
+ /* Set the count to represent ticks of the 32kHz LSI clock */
+ count = (period << 5);
+
+ /* Strip off the first 12 bits to get the prescale value required */
+ prescale = (count >> 12);
+ if (prescale > 256) {
+ exponent = IWDG_PR_DIV256; reload = COUNT_MASK;
+ } else if (prescale > 128) {
+ exponent = IWDG_PR_DIV256; reload = (count >> 8);
+ } else if (prescale > 64) {
+ exponent = IWDG_PR_DIV128; reload = (count >> 7);
+ } else if (prescale > 32) {
+ exponent = IWDG_PR_DIV64; reload = (count >> 6);
+ } else if (prescale > 16) {
+ exponent = IWDG_PR_DIV32; reload = (count >> 5);
+ } else if (prescale > 8) {
+ exponent = IWDG_PR_DIV16; reload = (count >> 4);
+ } else if (prescale > 4) {
+ exponent = IWDG_PR_DIV8; reload = (count >> 3);
+ } else {
+ exponent = IWDG_PR_DIV4; reload = (count >> 2);
+ }
+
+ /* Avoid the undefined situation of a zero count */
+ if (count == 0) {
+ count = 1;
+ }
+
+ while (iwdg_prescaler_busy());
+ IWDG_KR = IWDG_KR_UNLOCK;
+ IWDG_PR = exponent;
+ while (iwdg_reload_busy());
+ IWDG_KR = IWDG_KR_UNLOCK;
+ IWDG_RLR = (reload & COUNT_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Get Reload Register Status
+
+@returns boolean: TRUE if the reload register is busy and unavailable for
+loading a new count value.
+*/
+
+bool iwdg_reload_busy(void)
+{
+ return IWDG_SR & IWDG_SR_RVU;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Get Prescaler Register Status
+
+@returns boolean: TRUE if the prescaler register is busy and unavailable for
+loading a new period value.
+*/
+
+bool iwdg_prescaler_busy(void)
+{
+ return IWDG_SR & IWDG_SR_PVU;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG reset Watchdog Timer
+
+The watchdog timer is reset. The counter restarts from the value in the reload
+register.
+*/
+
+void iwdg_reset(void)
+{
+ IWDG_KR = IWDG_KR_RESET;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/pwr_common_all.c b/libopencm3/lib/stm32/common/pwr_common_all.c
new file mode 100644
index 0000000..53e6b42
--- /dev/null
+++ b/libopencm3/lib/stm32/common/pwr_common_all.c
@@ -0,0 +1,205 @@
+/** @addtogroup pwr_file PWR
+
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/pwr.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Backup Domain Write Protection.
+
+This allows backup domain registers to be changed. These registers are write
+protected after a reset.
+*/
+
+void pwr_disable_backup_domain_write_protect(void)
+{
+ PWR_CR |= PWR_CR_DBP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Re-enable Backup Domain Write Protection.
+
+This protects backup domain registers from inadvertent change.
+*/
+
+void pwr_enable_backup_domain_write_protect(void)
+{
+ PWR_CR &= ~PWR_CR_DBP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Power Voltage Detector.
+
+This provides voltage level threshold detection. The result of detection is
+provided in the power voltage detector output flag (see @ref pwr_voltage_high)
+or by setting the EXTI16 interrupt (see datasheet for configuration details).
+
+@param[in] pvd_level uint32_t. Taken from @ref pwr_pls.
+*/
+
+void pwr_enable_power_voltage_detect(uint32_t pvd_level)
+{
+ PWR_CR &= ~PWR_CR_PLS_MASK;
+ PWR_CR |= (PWR_CR_PVDE | pvd_level);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Power Voltage Detector.
+
+*/
+
+void pwr_disable_power_voltage_detect(void)
+{
+ PWR_CR &= ~PWR_CR_PVDE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Standby Flag.
+
+This is set when the processor returns from a standby mode.
+*/
+
+void pwr_clear_standby_flag(void)
+{
+ PWR_CR |= PWR_CR_CSBF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Wakeup Flag.
+
+This is set when the processor receives a wakeup signal.
+*/
+
+void pwr_clear_wakeup_flag(void)
+{
+ PWR_CR |= PWR_CR_CWUF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Standby Mode in Deep Sleep.
+
+*/
+
+void pwr_set_standby_mode(void)
+{
+ PWR_CR |= PWR_CR_PDDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Stop Mode in Deep Sleep.
+
+*/
+
+void pwr_set_stop_mode(void)
+{
+ PWR_CR &= ~PWR_CR_PDDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Voltage Regulator On in Stop Mode.
+
+*/
+
+void pwr_voltage_regulator_on_in_stop(void)
+{
+ PWR_CR &= ~PWR_CR_LPDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Voltage Regulator Low Power in Stop Mode.
+
+*/
+
+void pwr_voltage_regulator_low_power_in_stop(void)
+{
+ PWR_CR |= PWR_CR_LPDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Wakeup Pin.
+
+The wakeup pin is used for waking the processor from standby mode.
+*/
+
+void pwr_enable_wakeup_pin(void)
+{
+ PWR_CSR |= PWR_CSR_EWUP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Release Wakeup Pin.
+
+The wakeup pin is used for general purpose I/O.
+*/
+
+void pwr_disable_wakeup_pin(void)
+{
+ PWR_CSR &= ~PWR_CSR_EWUP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Voltage Detector Output.
+
+The voltage detector threshold must be set when the power voltage detector is
+enabled, see @ref pwr_enable_power_voltage_detect.
+
+@returns boolean: TRUE if the power voltage is above the preset voltage
+threshold.
+*/
+
+bool pwr_voltage_high(void)
+{
+ return PWR_CSR & PWR_CSR_PVDO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Standby Flag.
+
+The standby flag is set when the processor returns from a standby state. It is
+cleared by software (see @ref pwr_clear_standby_flag).
+
+@returns boolean: TRUE if the processor was in standby state.
+*/
+
+bool pwr_get_standby_flag(void)
+{
+ return PWR_CSR & PWR_CSR_SBF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Wakeup Flag.
+
+The wakeup flag is set when a wakeup event has been received. It is
+cleared by software (see @ref pwr_clear_wakeup_flag).
+
+@returns boolean: TRUE if a wakeup event was received.
+*/
+
+bool pwr_get_wakeup_flag(void)
+{
+ return PWR_CSR & PWR_CSR_WUF;
+}
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/rcc_common_all.c b/libopencm3/lib/stm32/common/rcc_common_all.c
new file mode 100644
index 0000000..41cb814
--- /dev/null
+++ b/libopencm3/lib/stm32/common/rcc_common_all.c
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <bufran@seznam.cz>
+ * .. file is merged from many other copyrighted files of stm32 family
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**@{*/
+
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable Peripheral Clocks.
+ *
+ * Enable the clock on particular peripherals. There are three registers
+ * involved, each one controlling the enabling of clocks associated with the
+ * AHB, APB1 and APB2 respectively. Several peripherals could be enabled
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ *
+ * @param[in] en Unsigned int32. Logical OR of all enables to be set
+ * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en
+ * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
+ * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
+ */
+
+void rcc_peripheral_enable_clock(volatile uint32_t *reg, uint32_t en)
+{
+ *reg |= en;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable Peripheral Clocks.
+ *
+ * Enable the clock on particular peripherals. There are three registers
+ * involved, each one controlling the enabling of clocks associated with
+ * the AHB, APB1 and APB2 respectively. Several peripherals could be disabled
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] en Unsigned int32. Logical OR of all enables to be used for
+ * disabling.
+ * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en
+ * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
+ * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
+ */
+void rcc_peripheral_disable_clock(volatile uint32_t *reg, uint32_t en)
+{
+ *reg &= ~en;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Reset Peripherals.
+ *
+ * Reset particular peripherals. There are three registers involved, each one
+ * controlling reset of peripherals associated with the AHB, APB1 and APB2
+ * respectively. Several peripherals could be reset simultaneously <em>only if
+ * they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Reset Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] reset Unsigned int32. Logical OR of all resets.
+ * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
+ * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
+ * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
+ */
+void rcc_peripheral_reset(volatile uint32_t *reg, uint32_t reset)
+{
+ *reg |= reset;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Remove Reset on Peripherals.
+ *
+ * Remove the reset on particular peripherals. There are three registers
+ * involved, each one controlling reset of peripherals associated with the AHB,
+ * APB1 and APB2 respectively. Several peripherals could have the reset removed
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Reset Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] clear_reset Unsigned int32. Logical OR of all resets to be
+ * removed:
+ * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
+ * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
+ * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
+ */
+void rcc_peripheral_clear_reset(volatile uint32_t *reg, uint32_t clear_reset)
+{
+ *reg &= ~clear_reset;
+}
+
+#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5))
+#define _RCC_BIT(i) (1 << ((i) & 0x1f))
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Peripheral Clock in running mode.
+ *
+ * Enable the clock on particular peripheral.
+ *
+ * @param[in] clken rcc_periph_clken Peripheral RCC
+ *
+ * For available constants, see #rcc_periph_clken (RCC_UART1 for example)
+ */
+
+void rcc_periph_clock_enable(enum rcc_periph_clken clken)
+{
+ _RCC_REG(clken) |= _RCC_BIT(clken);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Peripheral Clock in running mode.
+ * Disable the clock on particular peripheral.
+ *
+ * @param[in] clken rcc_periph_clken Peripheral RCC
+ *
+ * For available constants, see #rcc_periph_clken (RCC_UART1 for example)
+ */
+
+void rcc_periph_clock_disable(enum rcc_periph_clken clken)
+{
+ _RCC_REG(clken) &= ~_RCC_BIT(clken);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, pulsed
+ *
+ * Reset particular peripheral, and restore to working state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_pulse(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) |= _RCC_BIT(rst);
+ _RCC_REG(rst) &= ~_RCC_BIT(rst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, hold
+ *
+ * Reset particular peripheral, and hold in reset state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_hold(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) |= _RCC_BIT(rst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, release
+ *
+ * Restore peripheral from reset state to working state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_release(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) &= ~_RCC_BIT(rst);
+}
+/**@}*/
+
+#undef _RCC_REG
+#undef _RCC_BIT
diff --git a/libopencm3/lib/stm32/common/rtc_common_l1f024.c b/libopencm3/lib/stm32/common/rtc_common_l1f024.c
new file mode 100644
index 0000000..7579dfd
--- /dev/null
+++ b/libopencm3/lib/stm32/common/rtc_common_l1f024.c
@@ -0,0 +1,123 @@
+/** @addtogroup rtc_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/rtc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set RTC prescalars.
+
+This sets the RTC synchronous and asynchronous prescalars.
+*/
+
+void rtc_set_prescaler(uint32_t sync, uint32_t async)
+{
+ /*
+ * Even if only one of the two fields needs to be changed,
+ * 2 separate write accesses must be performed to the RTC_PRER register.
+ */
+ RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK);
+ RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait for RTC registers to be synchronised with the APB1 bus
+
+ Time and Date are accessed through shadow registers which must be synchronized
+*/
+
+void rtc_wait_for_synchro(void)
+{
+ /* Unlock RTC registers */
+ RTC_WPR = 0xca;
+ RTC_WPR = 0x53;
+
+ RTC_ISR &= ~(RTC_ISR_RSF);
+
+ while (!(RTC_ISR & RTC_ISR_RSF));
+
+ /* disable write protection again */
+ RTC_WPR = 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock write access to the RTC registers
+
+*/
+void rtc_unlock(void)
+{
+ RTC_WPR = 0xca;
+ RTC_WPR = 0x53;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock write access to the RTC registers
+
+*/
+void rtc_lock(void)
+{
+ RTC_WPR = 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Sets the wakeup time auto-reload value
+
+*/
+void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel)
+{
+ /* FTFM:
+ * The following sequence is required to configure or change the wakeup
+ * timer auto-reload value (WUT[15:0] in RTC_WUTR):
+ * 1. Clear WUTE in RTC_CR to disable the wakeup timer.
+ */
+ RTC_CR &= ~RTC_CR_WUTE;
+ /* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to
+ * wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
+ * It takes around 2 RTCCLK clock cycles (due to clock
+ * synchronization).
+ */
+ while (!((RTC_ISR) & (RTC_ISR_WUTWF)));
+ /* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup
+ * clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR
+ * to enable the timer again. The wakeup timer restarts
+ * down-counting.
+ */
+ RTC_WUTR = wkup_time;
+ RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT);
+ RTC_CR |= RTC_CR_WUTE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clears the wakeup flag
+
+@details This function should be called first in the rtc_wkup_isr()
+*/
+void rtc_clear_wakeup_flag(void)
+{
+ RTC_ISR &= ~RTC_ISR_WUTF;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_all.c b/libopencm3/lib/stm32/common/spi_common_all.c
new file mode 100644
index 0000000..6572233
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_all.c
@@ -0,0 +1,710 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Reset.
+
+The SPI peripheral and all its associated configuration registers are placed in
+the reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] spi_peripheral Unsigned int32. SPI peripheral identifier @ref
+spi_reg_base.
+*/
+
+void spi_reset(uint32_t spi_peripheral)
+{ switch (spi_peripheral) {
+#if defined(SPI1_BASE)
+ case SPI1_BASE:
+ rcc_periph_reset_pulse(RST_SPI1);
+ break;
+#endif
+#if defined(SPI2_I2S_BASE)
+ case SPI2_I2S_BASE:
+ rcc_periph_reset_pulse(RST_SPI2);
+ break;
+#endif
+#if defined(SPI3_I2S_BASE)
+ case SPI3_I2S_BASE:
+ rcc_periph_reset_pulse(RST_SPI3);
+ break;
+#endif
+#if defined(SPI4_BASE)
+ case SPI4_BASE:
+ rcc_periph_reset_pulse(RST_SPI4);
+ break;
+#endif
+#if defined(SPI5_BASE)
+ case SPI5_BASE:
+ rcc_periph_reset_pulse(RST_SPI5);
+ break;
+#endif
+#if defined(SPI6_BASE)
+ case SPI6_BASE:
+ rcc_periph_reset_pulse(RST_SPI6);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+/* TODO: Error handling? */
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable.
+
+The SPI peripheral is enabled.
+
+@todo Error handling?
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */
+}
+
+/* TODO: Error handling? */
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable.
+
+The SPI peripheral is disabled.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable(uint32_t spi)
+{
+ uint32_t reg32;
+
+ reg32 = SPI_CR1(spi);
+ reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */
+ SPI_CR1(spi) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Clean Disable.
+
+Disable the SPI peripheral according to the procedure in section 23.3.8 of the
+reference manual. This prevents corruption of any ongoing transfers and
+prevents the BSY flag from becoming unreliable.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@returns data Unsigned int16. 8 or 16 bit data from final read.
+*/
+
+uint16_t spi_clean_disable(uint32_t spi)
+{
+ /* Wait to receive last data */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ uint16_t data = SPI_DR(spi);
+
+ /* Wait to transmit last data */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Wait until not busy */
+ while (SPI_SR(spi) & SPI_SR_BSY);
+
+ SPI_CR1(spi) &= ~SPI_CR1_SPE;
+
+ return data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write.
+
+Data is written to the SPI interface.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+*/
+
+void spi_write(uint32_t spi, uint16_t data)
+{
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR(spi) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write with Blocking.
+
+Data is written to the SPI interface after the previous write transfer has
+finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+*/
+
+void spi_send(uint32_t spi, uint16_t data)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR(spi) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Read.
+
+Data is read from the SPI interface after the incoming transfer has finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@returns data Unsigned int16. 8 or 16 bit data.
+*/
+
+uint16_t spi_read(uint32_t spi)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write and Read Exchange.
+
+Data is written to the SPI interface, then a read is done after the incoming
+transfer has finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+@returns data Unsigned int16. 8 or 16 bit data.
+*/
+
+uint16_t spi_xfer(uint32_t spi, uint16_t data)
+{
+ spi_write(spi, data);
+
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire).
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Unidirectional Mode.
+
+The SPI peripheral is set for unidirectional transfers. This is used in full
+duplex mode or when the SPI is placed in two-wire simplex mode that uses a
+clock wire and a unidirectional data wire.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_unidirectional_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire), and is placed in a receive
+state.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_receive_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+ SPI_CR1(spi) &= ~SPI_CR1_BIDIOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire), and is placed in a transmit
+state.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_transmit_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+ SPI_CR1(spi) |= SPI_CR1_BIDIOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the CRC.
+
+The SPI peripheral is set to use a CRC field for transmit and receive.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_crc(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the CRC.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_crc(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Next Transmit is a Data Word
+
+The next transmission to take place is a data word from the transmit buffer.
+This must be called before transmission to distinguish between sending
+of a data or CRC word.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_next_tx_from_buffer(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Next Transmit is a CRC Word
+
+The next transmission to take place is a crc word from the hardware crc unit.
+This must be called before transmission to distinguish between sending
+of a data or CRC word.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_next_tx_from_crc(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCNEXT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Full Duplex (3-wire) Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_full_duplex_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_RXONLY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional
+Transfers
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_receive_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_RXONLY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Slave Management by Hardware
+
+In slave mode the NSS hardware input is used as a select enable for the slave.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_software_slave_management(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_SSM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Slave Management by Software
+
+In slave mode the NSS hardware input is replaced by an internal software
+enable/disable of the slave (@ref spi_set_nss_high).
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_software_slave_management(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SSM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Software NSS Signal High
+
+In slave mode, and only when software slave management is used, this replaces
+the NSS signal with a slave select enable signal.
+
+@todo these should perhaps be combined with an SSM enable as it is meaningless
+otherwise
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_nss_high(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SSI;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Software NSS Signal Low
+
+In slave mode, and only when software slave management is used, this replaces
+the NSS signal with a slave select disable signal.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_nss_low(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_SSI;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Send LSB First
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_send_lsb_first(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_LSBFIRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Send MSB First
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_send_msb_first(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Baudrate Prescaler
+
+@todo Why is this specification different to the spi_init_master baudrate
+values?
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre.
+*/
+
+void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate)
+{
+ uint32_t reg32;
+
+ if (baudrate > 7) {
+ return;
+ }
+
+ reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */
+ reg32 |= (baudrate << 3);
+ SPI_CR1(spi) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Master Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_master_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_MSTR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Slave Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_slave_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_MSTR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Polarity to High when Idle
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_polarity_1(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CPOL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Polarity to Low when Idle
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_polarity_0(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CPOL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Phase to Capture on Trailing Edge
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_phase_1(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CPHA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Phase to Capture on Leading Edge
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_phase_0(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CPHA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Transmit Buffer Empty Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_tx_buffer_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Transmit Buffer Empty Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_tx_buffer_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Receive Buffer Ready Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Receive Buffer Ready Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Error Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_error_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_ERRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Error Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_error_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_ERRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the NSS Pin as an Output
+
+Normally used in master mode to allows the master to place all devices on the
+SPI bus into slave mode. Multimaster mode is not possible.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_ss_output(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_SSOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the NSS Pin as an Input
+
+In master mode this allows the master to sense the presence of other masters. If
+NSS is then pulled low the master is placed into slave mode. In slave mode NSS
+becomes a slave enable.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_ss_output(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_SSOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Transmit Transfers via DMA
+
+This allows transmissions to proceed unattended using DMA to move data to the
+transmit buffer as it becomes available. The DMA channels provided for each
+SPI peripheral are given in the Technical Manual DMA section.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_tx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_TXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable Transmit Transfers via DMA
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_tx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Receive Transfers via DMA
+
+This allows received data streams to proceed unattended using DMA to move data
+from the receive buffer as data becomes available. The DMA channels provided
+for each SPI peripheral are given in the Technical Manual DMA section.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_rx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_RXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable Receive Transfers via DMA
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_rx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_f03.c b/libopencm3/lib/stm32/common/spi_common_f03.c
new file mode 100644
index 0000000..5713653
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_f03.c
@@ -0,0 +1,177 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Configure the SPI as Master.
+
+The SPI peripheral is configured as a master with communication parameters
+baudrate, crc length 8/16 bits, frame format lsb/msb first, clock polarity
+and phase. The SPI enable, CRC enable and CRC next controls are not affected.
+These must be controlled separately.
+
+@todo NSS pin handling.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
+@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
+@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
+@param[in] crcl Unsigned int32. CRC length 8/16 bits @ref spi_crcl.
+@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
+spi_lsbfirst.
+@returns int. Error code.
+*/
+
+int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
+ uint32_t crcl, uint32_t lsbfirst)
+{
+ uint32_t reg32 = SPI_CR1(spi);
+
+ /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
+ reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
+
+ reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
+
+ reg32 |= br; /* Set baud rate bits. */
+ reg32 |= cpol; /* Set CPOL value. */
+ reg32 |= cpha; /* Set CPHA value. */
+ reg32 |= crcl; /* Set crc length (8 or 16 bits). */
+ reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
+
+ /* TODO: NSS pin handling. */
+
+ SPI_CR1(spi) = reg32;
+
+ return 0; /* TODO */
+}
+
+void spi_send8(uint32_t spi, uint8_t data)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR8(spi) = data;
+}
+
+uint8_t spi_read8(uint32_t spi)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR8(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set CRC length to 8 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_crcl_8bit(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set CRC length to 16 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_crcl_16bit(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCL;
+}
+
+void spi_set_data_size(uint32_t spi, uint16_t data_s)
+{
+ SPI_CR2(spi) = (SPI_CR2(spi) & ~SPI_CR2_DS_MASK) |
+ (data_s & SPI_CR2_DS_MASK);
+}
+
+void spi_fifo_reception_threshold_8bit(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_FRXTH;
+}
+
+void spi_fifo_reception_threshold_16bit(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_FRXTH;
+}
+
+void spi_i2s_mode_spi_mode(uint32_t spi)
+{
+ SPI_I2SCFGR(spi) &= ~SPI_I2SCFGR_I2SMOD;
+}
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_l1f124.c b/libopencm3/lib/stm32/common/spi_common_l1f124.c
new file mode 100644
index 0000000..6345350
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_l1f124.c
@@ -0,0 +1,137 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Configure the SPI as Master.
+
+The SPI peripheral is configured as a master with communication parameters
+baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity
+and phase. The SPI enable, CRC enable and CRC next controls are not affected.
+These must be controlled separately.
+
+@todo NSS pin handling.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
+@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
+@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
+@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff.
+@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
+spi_lsbfirst.
+@returns int. Error code.
+*/
+
+int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
+ uint32_t dff, uint32_t lsbfirst)
+{
+ uint32_t reg32 = SPI_CR1(spi);
+
+ /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
+ reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
+
+ reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
+
+ reg32 |= br; /* Set baud rate bits. */
+ reg32 |= cpol; /* Set CPOL value. */
+ reg32 |= cpha; /* Set CPHA value. */
+ reg32 |= dff; /* Set data format (8 or 16 bits). */
+ reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
+
+ /* TODO: NSS pin handling. */
+
+ SPI_CR1(spi) = reg32;
+
+ return 0; /* TODO */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Data Frame Format to 8 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_dff_8bit(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_DFF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Data Frame Format to 16 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_dff_16bit(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_DFF;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/timer_common_all.c b/libopencm3/lib/stm32/common/timer_common_all.c
new file mode 100644
index 0000000..a1a4380
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_all.c
@@ -0,0 +1,2177 @@
+/** @addtogroup timer_file
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Edward Cheeseman <evbuilder@users.sourceforge.org>
+@author @htmlonly &copy; @endhtmlonly 2011
+Stephen Caudle <scaudle@doceme.com>
+
+@section tim_common Notes for All Timers
+
+This library supports the General Purpose and Advanced Control Timers for
+the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The STM32 series have four general purpose timers (2-5), while some have
+an additional two advanced timers (1,8), and some have two basic timers (6,7).
+Some of the larger devices have additional general purpose timers (9-14).
+
+@todo Add timer DMA burst settings
+
+@section tim_api_ex Basic TIMER handling API.
+
+Enable the timer clock first. The timer mode sets the clock division ratio, the
+count alignment (edge or centred) and count direction. Finally enable the
+timer.
+
+The timer output compare block produces a signal that can be configured for
+output to a pin or passed to other peripherals for use as a trigger. In all
+cases the output compare mode must be set to define how the output responds to
+a compare match, and the output must be enabled. If output to a pin is
+required, enable the appropriate GPIO clock and set the pin to alternate output
+mode.
+
+Example: Timer 2 with 2x clock divide, edge aligned and up counting.
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM2EN);
+ timer_reset(TIM2);
+ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT_MUL_2,
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ ...
+ timer_set_period(TIM2, 1000);
+ timer_enable_counter(TIM2);
+@endcode
+Example: Timer 1 with PWM output, no clock divide and centre alignment. Set the
+Output Compare mode to PWM and enable the output of channel 1. Note that for
+the advanced timers the break functionality must be enabled before the signal
+will appear at the output, even though break is not being used. This is in
+addition to the normal output enable. Enable the alternate function clock (APB2
+only) and port A clock. Set ports A8 and A9 (timer 1 channel 1 compare outputs)
+to alternate function push-pull outputs where the PWM output will appear.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN |
+ RCC_APB2ENR_AFIOEN);
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8 | GPIO9);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN);
+ timer_reset(TIM1);
+ timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_CENTER_1,
+ TIM_CR1_DIR_UP);
+ timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM2);
+ timer_enable_oc_output(TIM1, TIM_OC1);
+ timer_enable_break_main_output(TIM1);
+ timer_set_oc_value(TIM1, TIM_OC1, 200);
+ timer_set_period(TIM1, 1000);
+ timer_enable_counter(TIM1);
+@endcode
+
+@todo input capture example
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Basic TIMER handling API.
+ *
+ * Examples:
+ * timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT_MUL_2,
+ * TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP);
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/rcc.h>
+
+#define ADVANCED_TIMERS (defined(TIM1_BASE) || defined(TIM8_BASE))
+
+#if defined(TIM8)
+#define TIMER_IS_ADVANCED(periph) ((periph == TIM1) || (periph == TIM8))
+#else
+#define TIMER_IS_ADVANCED(periph) (periph == TIM1)
+#endif
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset a Timer.
+
+The counter and all its associated configuration registers are placed in the
+reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+ tim_reg_base (TIM9 .. TIM14 not yet supported here).
+*/
+
+void timer_reset(uint32_t timer_peripheral)
+{
+ switch (timer_peripheral) {
+#if defined(TIM1_BASE)
+ case TIM1:
+ rcc_periph_reset_pulse(RST_TIM1);
+ break;
+#endif
+ case TIM2:
+ rcc_periph_reset_pulse(RST_TIM2);
+ break;
+ case TIM3:
+ rcc_periph_reset_pulse(RST_TIM3);
+ break;
+#if defined(TIM4_BASE)
+ case TIM4:
+ rcc_periph_reset_pulse(RST_TIM4);
+ break;
+#endif
+#if defined(TIM5_BASE)
+ case TIM5:
+ rcc_periph_reset_pulse(RST_TIM5);
+ break;
+#endif
+ case TIM6:
+ rcc_periph_reset_pulse(RST_TIM6);
+ break;
+ case TIM7:
+ rcc_periph_reset_pulse(RST_TIM7);
+ break;
+#if defined(TIM8_BASE)
+ case TIM8:
+ rcc_periph_reset_pulse(RST_TIM8);
+ break;
+#endif
+/* These timers are not supported in libopencm3 yet */
+/*
+ case TIM9:
+ rcc_periph_reset_pulse(RST_TIM9);
+ break;
+ case TIM10:
+ rcc_periph_reset_pulse(RST_TIM10);
+ break;
+ case TIM11:
+ rcc_periph_reset_pulse(RST_TIM11);
+ break;
+ case TIM12:
+ rcc_periph_reset_pulse(RST_TIM12);
+ break;
+ case TIM13:
+ rcc_periph_reset_pulse(RST_TIM13);
+ break;
+ case TIM14:
+ rcc_periph_reset_pulse(RST_TIM14);
+ break;
+*/
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Interrupts for a Timer
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt
+enable bits to be set
+*/
+
+void timer_enable_irq(uint32_t timer_peripheral, uint32_t irq)
+{
+ TIM_DIER(timer_peripheral) |= irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Interrupts for a Timer.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt
+enable bits to be cleared
+*/
+
+void timer_disable_irq(uint32_t timer_peripheral, uint32_t irq)
+{
+ TIM_DIER(timer_peripheral) &= ~irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Return Interrupt Source.
+
+Returns true if the specified interrupt flag (UIF, TIF or CCxIF, with BIF or
+COMIF for advanced timers) was set and the interrupt was enabled. If the
+specified flag is not an interrupt flag, the function returns false.
+
+@todo Timers 6-7, 9-14 have fewer interrupts, but invalid flags are not caught
+here.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values.
+@returns boolean: flag set.
+*/
+
+bool timer_interrupt_source(uint32_t timer_peripheral, uint32_t flag)
+{
+/* flag not set or interrupt disabled or not an interrupt source */
+ if (((TIM_SR(timer_peripheral) &
+ TIM_DIER(timer_peripheral) & flag) == 0) ||
+ (flag > TIM_SR_BIF)) {
+ return false;
+ }
+/* Only an interrupt source for advanced timers */
+#if ADVANCED_TIMERS
+ if ((flag == TIM_SR_BIF) || (flag == TIM_SR_COMIF)) {
+ return TIMER_IS_ADVANCED(timer_peripheral);
+ }
+#endif
+ return true;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read a Status Flag.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values.
+@returns boolean: flag set.
+*/
+
+bool timer_get_flag(uint32_t timer_peripheral, uint32_t flag)
+{
+ if ((TIM_SR(timer_peripheral) & flag) != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear a Status Flag.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. @ref tim_sr_values. Status register flag.
+*/
+
+void timer_clear_flag(uint32_t timer_peripheral, uint32_t flag)
+{
+ TIM_SR(timer_peripheral) &= ~flag;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer Mode.
+
+The modes are:
+
+@li Clock divider ratio (to form the sampling clock for the input filters,
+and the dead-time clock in the advanced timers 1 and 8)
+@li Edge/centre alignment
+@li Count direction
+
+The alignment and count direction are effective only for timers 1 to 5 and 8
+while the clock divider ratio is effective for all timers except 6,7
+The remaining timers are limited hardware timers which do not support these mode
+settings.
+
+@note: When center alignment mode is selected, count direction is controlled by
+hardware and cannot be written. The count direction setting has no effect
+in this case.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base (TIM1, TIM2 ... TIM5, TIM8)
+@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref
+tim_x_cr1_cdr
+@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms
+@param[in] direction Unsigned int32. Count direction in bit 4,: @ref
+tim_x_cr1_dir
+*/
+
+void timer_set_mode(uint32_t timer_peripheral, uint32_t clock_div,
+ uint32_t alignment, uint32_t direction)
+{
+ uint32_t cr1;
+
+ cr1 = TIM_CR1(timer_peripheral);
+
+ cr1 &= ~(TIM_CR1_CKD_CK_INT_MASK | TIM_CR1_CMS_MASK | TIM_CR1_DIR_DOWN);
+
+ cr1 |= clock_div | alignment | direction;
+
+ TIM_CR1(timer_peripheral) = cr1;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Filter and Dead-time Clock Divider Ratio.
+
+This forms the sampling clock for the input filters and the dead-time clock
+in the advanced timers 1 and 8, by division from the timer clock.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref
+tim_x_cr1_cdr
+*/
+
+void timer_set_clock_division(uint32_t timer_peripheral, uint32_t clock_div)
+{
+ clock_div &= TIM_CR1_CKD_CK_INT_MASK;
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CKD_CK_INT_MASK;
+ TIM_CR1(timer_peripheral) |= clock_div;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Auto-Reload Buffering.
+
+During counter operation this causes the counter to be loaded from its
+auto-reload register only at the next update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_preload(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_ARPE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Auto-Reload Buffering.
+
+This causes the counter to be loaded immediately with a new count value when the
+auto-reload register is written, so that the new value becomes effective for the
+current count cycle rather than for the cycle following an update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_preload(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_ARPE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Specify the counter alignment mode.
+
+The mode can be edge aligned or centered.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms
+*/
+
+void timer_set_alignment(uint32_t timer_peripheral, uint32_t alignment)
+{
+ alignment &= TIM_CR1_CMS_MASK;
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CMS_MASK;
+ TIM_CR1(timer_peripheral) |= alignment;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Count Up.
+
+This has no effect if the timer is set to center aligned.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_direction_up(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_DIR_DOWN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Count Down.
+
+This has no effect if the timer is set to center aligned.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_direction_down(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_DIR_DOWN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Timer for One Cycle and Stop.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_one_shot_mode(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_OPM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Timer to Run Continuously.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_continuous_mode(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_OPM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Generate Update IRQ or DMA on any Event.
+
+The events which will generate an interrupt or DMA request can be
+@li a counter underflow/overflow,
+@li a forced update,
+@li an event from the slave mode controller.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_update_on_any(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_URS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Generate Update IRQ or DMA only from Under/Overflow
+Events.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_update_on_overflow(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_URS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Update Events.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_UDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Update Events.
+
+Update events are not generated and the shadow registers keep their values.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_UDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the timer to start counting.
+
+This should be called after the timer initial configuration has been completed.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_counter(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_CEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Stop the timer from counting.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_counter(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Output Idle States High.
+
+This determines the value of the timer output compare when it enters idle state.
+
+@sa @ref timer_set_oc_idle_state_set
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref
+tim_x_cr2_ois. If several settings are to be made, use the logical OR of the
+output control values.
+*/
+
+void timer_set_output_idle_state(uint32_t timer_peripheral, uint32_t outputs)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
+ }
+#else
+ (void)timer_peripheral;
+ (void)outputs;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Output Idle States Low.
+
+This determines the value of the timer output compare when it enters idle state.
+
+@sa @ref timer_set_oc_idle_state_unset
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref
+tim_x_cr2_ois
+*/
+
+void timer_reset_output_idle_state(uint32_t timer_peripheral, uint32_t outputs)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
+ }
+#else
+ (void)timer_peripheral;
+ (void)outputs;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer 1 Input to XOR of Three Channels.
+
+The first timer capture input is formed from the XOR of the first three timer
+input channels 1, 2, 3.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_ti1_ch123_xor(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) |= TIM_CR2_TI1S;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer 1 Input to Channel 1.
+
+The first timer capture input is taken from the timer input channel 1 only.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_ti1_ch1(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_TI1S;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Master Mode
+
+This sets the Trigger Output TRGO for synchronizing with slave timers or
+passing as an internal trigger to the ADC or DAC.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] mode Unsigned int32. Master Mode @ref tim_mastermode
+*/
+
+void timer_set_master_mode(uint32_t timer_peripheral, uint32_t mode)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_MMS_MASK;
+ TIM_CR2(timer_peripheral) |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer DMA Requests on Capture/Compare Events.
+
+Capture/compare events will cause DMA requests to be generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_dma_on_compare_event(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer DMA Requests on Update Events.
+
+Update events will cause DMA requests to be generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_dma_on_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Capture/Compare Control Update with Trigger.
+
+If the capture/compare control bits CCxE, CCxNE and OCxM are set to be
+preloaded, they are updated by software generating the COMG event (@ref
+timer_generate_event) or when a rising edge occurs on the trigger input TRGI.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_compare_control_update_on_trigger(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Capture/Compare Control Update with Trigger.
+
+If the capture/compare control bits CCxE, CCxNE and OCxM are set to be
+preloaded, they are updated by software generating the COMG event (@ref
+timer_generate_event).
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_compare_control_update_on_trigger(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Capture/Compare Control Preload.
+
+The capture/compare control bits CCxE, CCxNE and OCxM are set to be preloaded
+when a COM event occurs.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_preload_complementry_enable_bits(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Capture/Compare Control Preload.
+
+The capture/compare control bits CCxE, CCxNE and OCxM preload is disabled.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_preload_complementry_enable_bits(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Value for the Timer Prescaler.
+
+The timer clock is prescaled by the 16 bit scale value plus 1.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] value Unsigned int32. Prescaler values 0...0xFFFF.
+*/
+
+void timer_set_prescaler(uint32_t timer_peripheral, uint32_t value)
+{
+ TIM_PSC(timer_peripheral) = value;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Value for the Timer Repetition Counter.
+
+A timer update event is generated only after the specified number of repeat
+count cycles have been completed.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] value Unsigned int32. Repetition values 0...0xFF.
+*/
+
+void timer_set_repetition_counter(uint32_t timer_peripheral, uint32_t value)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_RCR(timer_peripheral) = value;
+ }
+#else
+ (void)timer_peripheral;
+ (void)value;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Period
+
+Specify the timer period in the auto-reload register.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] period Unsigned int32. Period in counter clock ticks.
+*/
+
+void timer_set_period(uint32_t timer_peripheral, uint32_t period)
+{
+ TIM_ARR(timer_peripheral) = period;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Clear Function
+
+When this is enabled, the output compare signal is cleared when a high is
+detected on the external trigger input. This works in the output compare and
+PWM modes only (not forced mode).
+The output compare signal remains off until the next update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_enable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1CE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2CE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3CE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4CE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as oc clear enable only applies to the whole
+ * channel.
+ */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare Clear Function
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_disable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1CE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2CE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3CE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4CE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as oc clear enable only applies to the whole
+ * channel.
+ */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Fast Mode
+
+When this is enabled, the output compare signal is forced to the compare state
+by a trigger input, independently of the compare match. This speeds up the
+setting of the output compare to 3 clock cycles as opposed to at least 5 in the
+slow mode. This works in the PWM1 and PWM2 modes only.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_set_oc_fast_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1FE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2FE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3FE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4FE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as fast enable only applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Slow Mode
+
+This disables the fast compare mode and the output compare depends on the
+counter and compare register values.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_set_oc_slow_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1FE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2FE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3FE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4FE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Mode
+
+Specifies how the comparator output will respond to a compare match. The mode
+can be:
+@li Frozen - the output does not respond to a match.
+@li Active - the output assumes the active state on the first match.
+@li Inactive - the output assumes the inactive state on the first match.
+@li Toggle - The output switches between active and inactive states on each
+match.
+@li Force inactive. The output is forced low regardless of the compare state.
+@li Force active. The output is forced high regardless of the compare state.
+@li PWM1 - The output is active when the counter is less than the compare
+register contents and inactive otherwise.
+@li PWM2 - The output is inactive when the counter is less than the compare
+register contents and active otherwise.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+@param[in] oc_mode enum ::tim_oc_mode. OC mode designators.
+ TIM_OCM_FROZEN, TIM_OCM_ACTIVE, TIM_OCM_INACTIVE,
+ TIM_OCM_TOGGLE, TIM_OCM_FORCE_LOW, TIM_OCM_FORCE_HIGH,
+ TIM_OCM_PWM1, TIM_OCM_PWM2
+*/
+
+void timer_set_oc_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id,
+ enum tim_oc_mode oc_mode)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC1S_OUT;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR1(timer_peripheral) |=
+ TIM_CCMR1_OC1M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC2S_OUT;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR1(timer_peripheral) |=
+ TIM_CCMR1_OC2M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC3S_OUT;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR2(timer_peripheral) |=
+ TIM_CCMR2_OC3M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC4S_OUT;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR2(timer_peripheral) |=
+ TIM_CCMR2_OC4M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Preload Register
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_enable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1PE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2PE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3PE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4PE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare Preload Register
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action)
+*/
+
+void timer_disable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1PE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2PE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3PE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4PE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set the Output Polarity High
+
+The polarity of the channel output is set active high.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_polarity_high(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1P;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2P;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3P;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4P;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NP;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NP;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NP;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set the Output Polarity Low
+
+The polarity of the channel output is set active low.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_polarity_low(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1P;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2P;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3P;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC4P;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NP;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NP;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NP;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare
+
+The channel output compare functionality is enabled.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_enable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1E;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2E;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3E;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC4E;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NE;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NE;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NE;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare
+
+The channel output compare functionality is disabled.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_disable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1E;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2E;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3E;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4E;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NE;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NE;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NE;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer set Output Compare Idle State High
+
+@sa Similar function suitable for multiple OC idle state settings
+@ref timer_set_output_idle_state
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_idle_state_set(uint32_t timer_peripheral,
+ enum tim_oc_id oc_id)
+{
+#if ADVANCED_TIMERS
+ /* Acting for TIM1 and TIM8 only. */
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1;
+ break;
+ case TIM_OC1N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1N;
+ break;
+ case TIM_OC2:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2;
+ break;
+ case TIM_OC2N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2N;
+ break;
+ case TIM_OC3:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3;
+ break;
+ case TIM_OC3N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3N;
+ break;
+ case TIM_OC4:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS4;
+ break;
+ }
+#else
+ (void)timer_peripheral;
+ (void)oc_id;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Idle State Low
+
+@sa Similar function suitable for multiple OC idle state settings
+@ref timer_reset_output_idle_state
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_idle_state_unset(uint32_t timer_peripheral,
+ enum tim_oc_id oc_id)
+{
+#if ADVANCED_TIMERS
+ /* Acting for TIM1 and TIM8 only. */
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1;
+ break;
+ case TIM_OC1N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1N;
+ break;
+ case TIM_OC2:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2;
+ break;
+ case TIM_OC2N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2N;
+ break;
+ case TIM_OC3:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3;
+ break;
+ case TIM_OC3N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3N;
+ break;
+ case TIM_OC4:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS4;
+ break;
+ }
+#else
+ (void)timer_peripheral;
+ (void)oc_id;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Value
+
+This is a convenience function to set the OC preload register value for loading
+to the compare register.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+ tim_reg_base (TIM9 .. TIM14 not yet supported here).
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+@param[in] value Unsigned int32. Compare value.
+*/
+
+void timer_set_oc_value(uint32_t timer_peripheral, enum tim_oc_id oc_id,
+ uint32_t value)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCR1(timer_peripheral) = value;
+ break;
+ case TIM_OC2:
+ TIM_CCR2(timer_peripheral) = value;
+ break;
+ case TIM_OC3:
+ TIM_CCR3(timer_peripheral) = value;
+ break;
+ case TIM_OC4:
+ TIM_CCR4(timer_peripheral) = value;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Output in Break
+
+Enables the output in the Break feature of an advanced timer. This does not
+enable the break functionality itself but only sets the Master Output Enable in
+the Break and Deadtime Register.
+
+@note This setting is only valid for the advanced timers.
+
+@note It is necessary to call this function to enable the output on an advanced
+timer <b>even if break or deadtime features are not being used</b>.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break_main_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Output in Break
+
+Disables the output in the Break feature of an advanced timer. This clears
+the Master Output Enable in the Break and Deadtime Register.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break_main_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Automatic Output in Break
+
+Enables the automatic output feature of the Break function of an advanced
+timer so that the output is re-enabled at the next update event following a
+break event.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break_automatic_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Automatic Output in Break
+
+Disables the automatic output feature of the Break function of an advanced
+timer so that the output is re-enabled at the next update event following a
+break event.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break_automatic_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Activate Break when Input High
+
+Sets the break function to activate when the break input becomes high.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_break_polarity_high(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Activate Break when Input Low
+
+Sets the break function to activate when the break input becomes low.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_break_polarity_low(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Break
+
+Enables the break function of an advanced timer.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Break
+
+Disables the break function of an advanced timer.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Off-State in Run Mode
+
+Enables the off-state in run mode for the break function of an advanced
+timer in which the complementary outputs have been configured. It has no effect
+if no complementary output is present. When the capture-compare output is
+disabled while the complementary output is enabled, the output is set to its
+inactive level as defined by the output polarity.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_enabled_off_state_in_run_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Off-State in Run Mode
+
+Disables the off-state in run mode for the break function of an advanced
+timer in which the complementary outputs have been configured. It has no effect
+if no complementary output is present. When the capture-compare output is
+disabled, the output is also disabled.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_disabled_off_state_in_run_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Off-State in Idle Mode
+
+Enables the off-state in idle mode for the break function of an advanced
+timer. When the master output is disabled the output is set to its
+inactive level as defined by the output polarity.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_enabled_off_state_in_idle_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Off-State in Idle Mode
+
+Disables the off-state in idle mode for the break function of an advanced
+timer. When the master output is disabled the output is also disabled.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_disabled_off_state_in_idle_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Lock Bits
+
+Set the lock bits for an advanced timer. Three levels of lock providing
+protection against software errors. Once written they cannot be changed until a
+timer reset has occurred.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+@param[in] lock Unsigned int32. Lock specification @ref tim_lock
+*/
+
+void timer_set_break_lock(uint32_t timer_peripheral, uint32_t lock)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= lock;
+ }
+#else
+ (void)timer_peripheral;
+ (void)lock;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Deadtime
+
+The deadtime and sampling clock (DTSC) is set in the clock division ratio part
+of the timer mode settings. The deadtime count is an 8 bit value defined in
+terms of the number of DTSC cycles:
+
+@li Bit 7 = 0, deadtime = bits(6:0)
+@li Bits 7:6 = 10, deadtime = 2x(64+bits(5:0))
+@li Bits 7:5 = 110, deadtime = 8x(32+bits(5:0))
+@li Bits 7:5 = 111, deadtime = 16x(32+bits(5:0))
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+@param[in] deadtime Unsigned int32. Deadtime count specification as defined
+above.
+*/
+
+void timer_set_deadtime(uint32_t timer_peripheral, uint32_t deadtime)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= deadtime;
+ }
+#else
+ (void)timer_peripheral;
+ (void)deadtime;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Force generate a timer event.
+
+The event specification consists of 8 possible events that can be forced on the
+timer. The forced events are automatically cleared by hardware. The UG event is
+useful to cause shadow registers to be preloaded before the timer is started to
+avoid uncertainties in the first cycle in case an update event may never be
+generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] event Unsigned int32. Event specification @ref tim_event_gen
+*/
+
+void timer_generate_event(uint32_t timer_peripheral, uint32_t event)
+{
+ TIM_EGR(timer_peripheral) |= event;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read Counter
+
+Read back the value of a timer's counter register contents
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@returns Unsigned int32. Counter value.
+*/
+
+uint32_t timer_get_counter(uint32_t timer_peripheral)
+{
+ return TIM_CNT(timer_peripheral);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Counter
+
+Set the value of a timer's counter register contents.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] count Unsigned int32. Counter value.
+*/
+
+void timer_set_counter(uint32_t timer_peripheral, uint32_t count)
+{
+ TIM_CNT(timer_peripheral) = count;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Capture Filter Parameters
+
+Set the input filter parameters for an input channel, specifying:
+@li the frequency of sampling from the Deadtime and Sampling clock
+(@see @ref timer_set_clock_division)
+@li the number of events that must occur before a transition is considered
+valid.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] flt ::tim_ic_filter. Input Capture Filter identifier.
+*/
+
+void timer_ic_set_filter(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_filter flt)
+{
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 4;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 12;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 4;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 12;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Capture Prescaler
+
+Set the number of events between each capture.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler.
+*/
+
+void timer_ic_set_prescaler(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_psc psc)
+{
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 2;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 10;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 2;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 10;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Capture/Compare Channel Direction/Input
+
+The Capture/Compare channel is defined as output (compare) or input with the
+input mapping specified:
+
+@li channel is configured as output
+@li channel is configured as input and mapped on corresponding input
+@li channel is configured as input and mapped on alternate input
+(TI2 for channel 1, TI1 for channel 2, TI4 for channel 3, TI3 for channel 4)
+@li channel is configured as input and is mapped on TRC (requires an
+internal trigger input selected through TS bit
+
+@note not all combinations of the input and channel are valid, see datasheets.
+@note these parameters are writable only when the channel is off.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] in ::tim_ic_input. Input Capture channel direction and source input.
+*/
+
+void timer_ic_set_input(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_input in)
+{
+ in &= 3;
+
+ if (((ic == TIM_IC2) || (ic == TIM_IC4)) &&
+ ((in == TIM_IC_IN_TI1) || (in == TIM_IC_IN_TI2))) {
+ /* Input select bits are flipped for these combinations */
+ in ^= 3;
+ }
+
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in << 8;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in << 8;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Input Capture
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+*/
+
+void timer_ic_enable(uint32_t timer_peripheral, enum tim_ic_id ic)
+{
+ TIM_CCER(timer_peripheral) |= (0x1 << (ic * 4));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Input Capture
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+*/
+
+void timer_ic_disable(uint32_t timer_peripheral, enum tim_ic_id ic)
+{
+ TIM_CCER(timer_peripheral) &= ~(0x1 << (ic * 4));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Filter Parameters for Slave
+
+Set the input filter parameters for the external trigger, specifying:
+@li the frequency of sampling from the Deadtime and Sampling clock
+(@see @ref timer_set_clock_division)
+@li the number of events that must occur before a transition is considered
+valid.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] flt ::tim_ic_filter. Input Capture Filter identifier.
+*/
+
+void timer_slave_set_filter(uint32_t timer_peripheral, enum tim_ic_filter flt)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETF_MASK;
+ TIM_SMCR(timer_peripheral) |= flt << 8;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Prescaler for Slave
+
+Set the external trigger frequency division ratio.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler.
+*/
+
+void timer_slave_set_prescaler(uint32_t timer_peripheral, enum tim_ic_psc psc)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETPS_MASK;
+ TIM_SMCR(timer_peripheral) |= psc << 12;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Polarity for Slave
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] pol ::tim_et_pol. Slave External Trigger polarity.
+*/
+
+void timer_slave_set_polarity(uint32_t timer_peripheral, enum tim_et_pol pol)
+{
+ if (pol) {
+ TIM_SMCR(timer_peripheral) |= TIM_SMCR_ETP;
+ } else {
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETP;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Slave Mode
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] mode Unsigned int8. Slave mode @ref tim_sms
+*/
+
+void timer_slave_set_mode(uint32_t timer_peripheral, uint8_t mode)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_SMS_MASK;
+ TIM_SMCR(timer_peripheral) |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Slave Trigger Source
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] trigger Unsigned int8. Slave trigger source @ref tim_ts
+*/
+
+void timer_slave_set_trigger(uint32_t timer_peripheral, uint8_t trigger)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_TS_MASK;
+ TIM_SMCR(timer_peripheral) |= trigger;
+}
+
+/* TODO Timer DMA burst */
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/timer_common_f234.c b/libopencm3/lib/stm32/common/timer_common_f234.c
new file mode 100644
index 0000000..1506408
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_f234.c
@@ -0,0 +1,58 @@
+/** @addtogroup timer_file
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/timer.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Polarity
+
+The timer channel must be set to input capture mode.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] pol ::tim_ic_pol. Input Capture polarity control.
+*/
+
+void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_pol pol)
+{
+ /* Clear CCxP and CCxNP to zero. For both edge trigger both fields are
+ * set. Case 10 is invalid.
+ */
+ TIM_CCER(timer_peripheral) &= ~(0xa << (ic * 4));
+ switch (pol) {
+ case TIM_IC_RISING: /* 00 */
+ break;
+ case TIM_IC_BOTH: /* 11 */
+ TIM_CCER(timer_peripheral) |= (0xa << (ic * 4));
+ break;
+ case TIM_IC_FALLING: /* 01 */
+ TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
+ }
+}
+/**@}*/
+
+
diff --git a/libopencm3/lib/stm32/common/timer_common_f24.c b/libopencm3/lib/stm32/common/timer_common_f24.c
new file mode 100644
index 0000000..ce1c1e3
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_f24.c
@@ -0,0 +1,53 @@
+/** @addtogroup timer_file
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/timer.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Option
+
+Set timer options register on TIM2 or TIM5, used for trigger remapping on TIM2,
+and similarly for TIM5 for oscillator calibration purposes.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM5:
+@ref tim5_opt_trigger_remap.
+*/
+
+void timer_set_option(uint32_t timer_peripheral, uint32_t option)
+{
+ if (timer_peripheral == TIM2) {
+ TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
+ TIM_OR(timer_peripheral) |= option;
+ } else if (timer_peripheral == TIM5) {
+ TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
+ TIM_OR(timer_peripheral) |= option;
+ }
+}
+
+/**@}*/
+
+
diff --git a/libopencm3/lib/stm32/common/usart_common_all.c b/libopencm3/lib/stm32/common/usart_common_all.c
new file mode 100644
index 0000000..43fd199
--- /dev/null
+++ b/libopencm3/lib/stm32/common/usart_common_all.c
@@ -0,0 +1,367 @@
+/** @addtogroup usart_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+This library supports the USART/UART in the STM32F series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to 3 USARTs and 2 UARTs.
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Baudrate.
+
+The baud rate is computed from the APB high-speed prescaler clock (for
+USART1/6) or the APB low-speed prescaler clock (for other USARTs). These values
+must be correctly set before calling this function (refer to the
+rcc_clock_setup-* functions in RCC).
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] baud unsigned 32 bit. Baud rate specified in Hz.
+*/
+
+void usart_set_baudrate(uint32_t usart, uint32_t baud)
+{
+ uint32_t clock = rcc_ppre1_frequency;
+
+#if defined STM32F2 || defined STM32F4
+ if ((usart == USART1) ||
+ (usart == USART6)) {
+ clock = rcc_ppre2_frequency;
+ }
+#else
+ if (usart == USART1) {
+ clock = rcc_ppre2_frequency;
+ }
+#endif
+
+ /*
+ * Yes it is as simple as that. The reference manual is
+ * talking about fractional calculation but it seems to be only
+ * marketting babble to sound awesome. It is nothing else but a
+ * simple divider to generate the correct baudrate.
+ *
+ * Note: We round() the value rather than floor()ing it, for more
+ * accurate divisor selection.
+ */
+ USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Word Length.
+
+The word length is set to 8 or 9 bits. Note that the last bit will be a parity
+bit if parity is enabled, in which case the data length will be 7 or 8 bits
+respectively.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
+*/
+
+void usart_set_databits(uint32_t usart, uint32_t bits)
+{
+ if (bits == 8) {
+ USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
+ } else {
+ USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Stop Bit(s).
+
+The stop bits are specified as 0.5, 1, 1.5 or 2.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
+*/
+
+void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR2(usart);
+ reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits;
+ USART_CR2(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Parity.
+
+The parity bit can be selected as none, even or odd.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
+*/
+
+void usart_set_parity(uint32_t usart, uint32_t parity)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR1(usart);
+ reg32 = (reg32 & ~USART_PARITY_MASK) | parity;
+ USART_CR1(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Rx/Tx Mode.
+
+The mode can be selected as Rx only, Tx only or Rx+Tx.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
+*/
+
+void usart_set_mode(uint32_t usart, uint32_t mode)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR1(usart);
+ reg32 = (reg32 & ~USART_MODE_MASK) | mode;
+ USART_CR1(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Hardware Flow Control.
+
+The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol.
+*/
+
+void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR3(usart);
+ reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol;
+ USART_CR3(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Disable.
+
+At the end of the current frame, the USART is disabled to reduce power.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send Data Word with Blocking
+
+Blocks until the transmit data buffer becomes empty then writes the next data
+word for transmission.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] data unsigned 16 bit.
+*/
+
+void usart_send_blocking(uint32_t usart, uint16_t data)
+{
+ usart_wait_send_ready(usart);
+ usart_send(usart, data);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word with Blocking.
+
+Wait until a data word has been received then return the word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@returns unsigned 16 bit data word.
+*/
+
+uint16_t usart_recv_blocking(uint32_t usart)
+{
+ usart_wait_recv_ready(usart);
+
+ return usart_recv(usart);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Enable.
+
+DMA is available on:
+@li USART1 Rx DMA1 channel 5.
+@li USART2 Rx DMA1 channel 6.
+@li USART3 Rx DMA1 channel 3.
+@li UART4 Rx DMA2 channel 3.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Enable.
+
+DMA is available on:
+@li USART1 Tx DMA1 channel 4.
+@li USART2 Tx DMA1 channel 7.
+@li USART3 Tx DMA1 channel 2.
+@li UART4 Tx DMA2 channel 5.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_RXNEIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_EIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_EIE;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/usart_common_f124.c b/libopencm3/lib/stm32/common/usart_common_f124.c
new file mode 100644
index 0000000..ea5b4ee
--- /dev/null
+++ b/libopencm3/lib/stm32/common/usart_common_f124.c
@@ -0,0 +1,143 @@
+/** @addtogroup usart_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+This library supports the USART/UART in the STM32F series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to 3 USARTs and 2 UARTs.
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send a Data Word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] data unsigned 16 bit.
+*/
+
+void usart_send(uint32_t usart, uint16_t data)
+{
+ /* Send data. */
+ USART_DR(usart) = (data & USART_DR_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word.
+
+If parity is enabled the MSB (bit 7 or 8 depending on the word length) is the
+parity bit.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@returns unsigned 16 bit data word.
+*/
+
+uint16_t usart_recv(uint32_t usart)
+{
+ /* Receive data. */
+ return USART_DR(usart) & USART_DR_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Transmit Data Buffer Empty
+
+Blocks until the transmit data buffer becomes empty and is ready to accept the
+next data word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_wait_send_ready(uint32_t usart)
+{
+ /* Wait until the data has been transferred into the shift register. */
+ while ((USART_SR(usart) & USART_SR_TXE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Received Data Available
+
+Blocks until the receive data buffer holds a valid received data word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_wait_recv_ready(uint32_t usart)
+{
+ /* Wait until the data is ready to be received. */
+ while ((USART_SR(usart) & USART_SR_RXNE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Status Flag.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+@returns boolean: flag set.
+*/
+
+bool usart_get_flag(uint32_t usart, uint32_t flag)
+{
+ return ((USART_SR(usart) & flag) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Return Interrupt Source.
+
+Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
+set and the interrupt was enabled. If the specified flag is not an interrupt
+flag, the function returns false.
+
+@todo These are the most important interrupts likely to be used. Others
+relating to LIN break, and error conditions in multibuffer communication, need
+to be added for completeness.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+@returns boolean: flag and interrupt enable both set.
+*/
+
+bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
+{
+ uint32_t flag_set = (USART_SR(usart) & flag);
+ /* IDLE, RXNE, TC, TXE interrupts */
+ if ((flag >= USART_SR_IDLE) && (flag <= USART_SR_TXE)) {
+ return ((flag_set & USART_CR1(usart)) != 0);
+ /* Overrun error */
+ } else if (flag == USART_SR_ORE) {
+ return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
+ }
+
+ return false;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/desig.c b/libopencm3/lib/stm32/desig.c
new file mode 100644
index 0000000..b610e66
--- /dev/null
+++ b/libopencm3/lib/stm32/desig.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@ŧweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/desig.h>
+
+uint16_t desig_get_flash_size(void)
+{
+ return DESIG_FLASH_SIZE;
+}
+
+void desig_get_unique_id(uint32_t result[])
+{
+ result[0] = DESIG_UNIQUE_ID2;
+ result[1] = DESIG_UNIQUE_ID1;
+ result[2] = DESIG_UNIQUE_ID0;
+}
+
+void desig_get_unique_id_as_string(char *string,
+ unsigned int string_len)
+{
+ int i, len;
+ uint8_t device_id[12];
+ static const char chars[] = "0123456789ABCDEF";
+
+ desig_get_unique_id((uint32_t *)device_id);
+
+ /* Each byte produces two characters */
+ len = (2 * sizeof(device_id) < string_len) ?
+ 2 * sizeof(device_id) : string_len - 1;
+
+ for (i = 0; i < len; i += 2) {
+ string[i] = chars[(device_id[i / 2] >> 0) & 0x0F];
+ string[i + 1] = chars[(device_id[i / 2] >> 4) & 0x0F];
+ }
+
+ string[len] = '\0';
+}
+
diff --git a/libopencm3/lib/stm32/f0/Makefile b/libopencm3/lib/stm32/f0/Makefile
new file mode 100644
index 0000000..156171c
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/Makefile
@@ -0,0 +1,49 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32f0
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+#PREFIX ?= arm-elf
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m0 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32F0
+
+ARFLAGS = rcs
+
+OBJS = flash.o rcc.o usart.o dma.o rtc.o comparator.o crc.o \
+ dac.o i2c.o iwdg.o pwr.o gpio.o timer.o adc.o
+
+OBJS += gpio_common_all.o gpio_common_f0234.o crc_common_all.o \
+ pwr_common_all.o iwdg_common_all.o rtc_common_l1f024.o \
+ dma_common_l1f013.o exti_common_all.o spi_common_all.o \
+ spi_common_f03.o flash_common_f01.o dac_common_all.o \
+ timer_common_all.o
+
+VPATH += ../../usb:../:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/stm32/f0/adc.c b/libopencm3/lib/stm32/f0/adc.c
new file mode 100644
index 0000000..7dbf84a
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/adc.c
@@ -0,0 +1,835 @@
+/** @defgroup adc_file ADC
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Analog to Digital Converters</b>
+ *
+ * based on F3 file
+ *
+ * @date 14 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/adc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_opmode ADC Operation mode API
+ * @ingroup adc_file
+ *
+ * @brief ADC Result API
+ *
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Continuous Conversion Mode
+ *
+ * In this mode the ADC starts a new conversion of a single channel or a channel
+ * group immediately following completion of the previous channel group
+ * conversion.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_set_continuous_conversion_mode(uint32_t adc)
+{
+ ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Single Conversion Mode
+ *
+ * In this mode the ADC performs a conversion of one channel or a channel group
+ * and stops.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_set_single_conversion_mode(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Regular Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_discontinuous_mode(uint32_t adc)
+{
+ ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Regular Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_discontinuous_mode(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** ADC Set operation mode
+ *
+ * There are some operation modes, common for entire stm32 branch. In the text
+ * the braces are describing result to single trigger event. The trigger event
+ * is described by character T in the description. The ADC is configured to
+ * convert list of inputs [0, 1, 2, 3]. In Grouped modes, there is used group
+ * size of 2 conversions in the examples
+ *
+ * @li @c ADC_MODE_SEQUENTIAL: T(0) T(1) T(2) T(3)[EOSEQ] T(0) T(1) T(2) ...
+ *
+ * In this mode, after the trigger event a single channel is converted and the
+ * next channel in the list is prepared to convert on next trigger edge.
+ *
+ * @note This mode can be emulated by ADC_MODE_GROUPED with group size
+ * of 1. @par
+ *
+ * @li @c ADC_MODE_SCAN: T(0123)[EOSEQ] T(0123)[EOSEQ] T(0123)[EOSEQ]
+ *
+ * In this mode, after the trigger event, all channels will be converted once,
+ * storing results sequentially.
+ *
+ * @note The DMA must be configured properly for more than single channel to
+ * convert. @par
+ *
+ * @li @c ADC_MODE_SCAN_INFINITE: T(0123[EOSEQ]0123[EOSEQ]0123[EOSEQ]...)
+ *
+ * In this mode, after the trigger event, all channels from the list are
+ * converted. At the end of list, the conversion continues from the beginning.
+ *
+ * @note The DMA must be configured properly to operate in this mode.@par
+ *
+ * @li @c ADC_MODE_GROUPED: T(12) T(34)[EOSEQ] T(12) T(34)[EOSEQ] T(12)
+ *
+ * In this mode, after the trigger event, a specified group size of channels
+ * are converted. If the end of channel list occurs, the EOSEQ is generated
+ * and on the next trigger it wraps to the beginning.
+ *
+ * @note The DMA must be configured properly to operate on more than single
+ * channel conversion groups.@par
+ *
+ * @warning not all families supports all modes of operation of ADC.
+ *
+ * @par
+ *
+ */
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set conversion operation mode
+ *
+ * @note on SEQUENTIAL mode, the trigger event is neccesary to start conversion.
+ * @par
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] adc ::adc_opmode. ADC operation mode (@ref adc_opmode)
+ */
+
+void adc_set_operation_mode(uint32_t adc, enum adc_opmode opmode)
+{
+ switch (opmode) {
+ case ADC_MODE_SEQUENTIAL:
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
+ ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
+ break;
+
+ case ADC_MODE_SCAN:
+ ADC_CFGR1(adc) &= ~(ADC_CFGR1_CONT | ADC_CFGR1_DISCEN);
+ break;
+
+ case ADC_MODE_SCAN_INFINITE:
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
+ ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
+ break;
+ }
+}
+
+/**@}*/
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_result ADC Result API
+ * @ingroup adc_file
+ *
+ * @brief ADC Result API
+ *
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Regular Channels
+ *
+ * This starts conversion on a set of defined regular channels. It is cleared
+ * by hardware once conversion starts.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_start_conversion_regular(uint32_t adc)
+{
+ /* Start conversion on regular channels. */
+ ADC_CR(adc) |= ADC_CR_ADSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR(adc) & ADC_CR_ADSTART);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag
+ *
+ * This flag is set after all channels of a regular or injected group have been
+ * converted.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @returns bool. End of conversion flag.
+ */
+
+bool adc_eoc(uint32_t adc)
+{
+ return ((ADC_ISR(adc) & ADC_ISR_EOC) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from the Regular Conversion Result Register
+ *
+ * The result read back is 12 bits, right or left aligned within the first
+ * 16 bits. For ADC1 only, the higher 16 bits will hold the result from ADC2 if
+ * an appropriate dual mode has been set @see adc_set_dual_mode.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @returns Unsigned int32 conversion result.
+ */
+
+uint32_t adc_read_regular(uint32_t adc)
+{
+ return ADC_DR(adc);
+}
+
+/**@}*/
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_trigger ADC Trigger API
+ * @ingroup adc_file
+ *
+ * @brief ADC Trigger API
+ *
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+ *
+ * This enables an external trigger for set of defined regular channels, and
+ * sets the polarity of the trigger event: rising or falling edge or both. Note
+ * that if the trigger polarity is zero, triggering is disabled.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] trigger Unsigned int32. Trigger identifier
+ * @ref adc_trigger_regular
+ * @param[in] polarity Unsigned int32. Trigger polarity @ref
+ * adc_trigger_polarity_regular
+ */
+
+void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTSEL) | trigger;
+ ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTEN) | polarity;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_external_trigger_regular(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_EXTEN;
+}
+
+/**@}*/
+
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_interrupts ADC Interrupt configuration API
+ * @ingroup adc_file
+ *
+ * @brief ADC Interrupt configuration API
+ *
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_watchdog_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_AWDIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_watchdog_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_AWDIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Analog Watchdog Flag
+ *
+ * This flag is set when the converted voltage crosses the high or low
+ * thresholds.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @returns bool true, if the signal is out of defined analog range.
+ */
+
+bool adc_get_watchdog_flag(uint32_t adc)
+{
+ return ADC_ISR(adc) & ADC_ISR_AWD;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Clear Analog Watchdog Flag
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_clear_watchdog_flag(uint32_t adc)
+{
+ ADC_ISR(adc) = ADC_ISR_AWD;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable the Overrun Interrupt
+ *
+ * The overrun interrupt is generated when data is not read from a result
+ * register before the next conversion is written. If DMA is enabled, all
+ * transfers are terminated and any conversion sequence is aborted.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_overrun_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable the Overrun Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_overrun_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Overrun Flag
+ *
+ * The overrun flag is set when data is not read from a result register before
+ * the next conversion is written. If DMA is enabled, all transfers are
+ * terminated and any conversion sequence is aborted.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+bool adc_get_overrun_flag(uint32_t adc)
+{
+ return ADC_ISR(adc) & ADC_ISR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Clear Overrun Flags
+ *
+ * The overrun flag is cleared. Note that if an overrun occurs, DMA is
+ * terminated.
+ * The flag must be cleared and the DMA stream and ADC reinitialised to resume
+ * conversions (see the reference manual).
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_clear_overrun_flag(uint32_t adc)
+{
+ ADC_ISR(adc) = ADC_ISR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Regular End-Of-Conversion Sequence Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_eoc_sequence_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_EOSEQIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Sequence Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_eoc_sequence_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_EOSEQIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Regular End-Of-Conversion Sequence Flag
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+bool adc_get_eoc_sequence_flag(uint32_t adc)
+{
+ return ADC_ISR(adc) & ADC_ISR_EOSEQ;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Regular End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_eoc_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_EOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_eoc_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_EOCIE;
+}
+
+/**@}*/
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_config ADC Basic configuration API
+ * @ingroup adc_file
+ *
+ * @brief ADC Basic configuration API
+ *
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power Off
+ *
+ * Turn off the ADC to reduce power consumption to a few microamps.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_power_off(uint32_t adc)
+{
+ ADC_CR(adc) &= ~ADC_CR_ADEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+ *
+ * If the ADC is in power-down mode then it is powered up. The application
+ * needs to wait a time of about 3 microseconds for stabilization before using
+ * the ADC. If the ADC is already on this function call will have no effect.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_power_on(uint32_t adc)
+{
+ ADC_CR(adc) |= ADC_CR_ADEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Clock Prescale
+ *
+ * The ADC clock taken from the many sources.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] prescale Unsigned int32. Prescale value (@ref adc_api_clksource)
+ */
+
+void adc_set_clk_source(uint32_t adc, uint32_t source)
+{
+ ADC_CFGR2(adc) = ((ADC_CFGR2(adc) & ~ADC_CFGR2_CKMODE) | source);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set a Regular Channel Conversion Sequence
+ *
+ * Define a sequence of channels to be converted as a regular group with a
+ * length from 1 to 18 channels. If this is called during conversion, the
+ * current conversion is reset and conversion begins again with the newly
+ * defined group.
+ *
+ * @warning This core doesn't support the random order of ADC conversions.
+ * The channel list must be ordered by channel number.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] length Unsigned int8. Number of channels in the group.
+ * @param[in] channel Unsigned int8[]. Set of channels to convert, integers
+ * 0..18.
+ */
+
+void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t reg32 = 0;
+ uint8_t i = 0;
+ bool stepup = false, stepdn = false;
+
+ if (length == 0) {
+ ADC_CHSELR(adc) = 0;
+ return;
+ }
+
+ reg32 |= (1 << channel[0]);
+
+ for (i = 1; i < length; i++) {
+ reg32 |= (1 << channel[i]);
+ stepup |= channel[i-1] < channel[i];
+ stepdn |= channel[i-1] > channel[i];
+ }
+
+ /* Check, if the channel list is in order */
+ if (stepup && stepdn) {
+ cm3_assert_not_reached();
+ }
+
+ /* Update the scan direction flag */
+ if (stepdn) {
+ ADC_CFGR1(adc) |= ADC_CFGR1_SCANDIR;
+ } else {
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_SCANDIR;
+ }
+
+ ADC_CHSELR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+ *
+ * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5,
+ * same for all channels.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] time Unsigned int8. Sampling time selection (@ref adc_api_smptime)
+ */
+
+void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
+{
+ ADC_SMPR(adc) = time & ADC_SMPR_SMP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Resolution
+ *
+ * ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
+ * corresponding reduction in conversion time.
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] resolution Unsigned int16. Resolution value (@ref adc_api_res)
+ */
+
+void adc_set_resolution(uint32_t adc, uint16_t resolution)
+{
+ ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_RES) | resolution;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Left Aligned
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_set_left_aligned(uint32_t adc)
+{
+ ADC_CFGR1(adc) |= ADC_CFGR1_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Right Aligned
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_set_right_aligned(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable DMA Transfers
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_dma(uint32_t adc)
+{
+ ADC_CFGR1(adc) |= ADC_CFGR1_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable DMA Transfers
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_disable_dma(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+ *
+ * This enables the sensor on channel 16
+ */
+
+void adc_enable_temperature_sensor(void)
+{
+ ADC_CCR |= ADC_CCR_TSEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+ *
+ * Disabling this will reduce power consumption from the temperature sensor
+ * measurement.
+ */
+
+void adc_disable_temperature_sensor(void)
+{
+ ADC_CCR &= ~ADC_CCR_TSEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The VRef Sensor
+ *
+ * This enables the reference voltage measurements on channel 17.
+ */
+
+void adc_enable_vref_sensor(void)
+{
+ ADC_CCR |= ADC_CCR_VREFEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The VRef Sensor
+ *
+ * Disabling this will reduce power consumption from the reference voltage
+ * measurement.
+ */
+
+void adc_disable_vref_sensor(void)
+{
+ ADC_CCR &= ~ADC_CCR_VREFEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The VBat Sensor
+ *
+ * This enables the battery voltage measurements on channel 17.
+ */
+
+void adc_enable_vbat_sensor(void)
+{
+ ADC_CCR |= ADC_CCR_VBATEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The VBat Sensor
+ *
+ * Disabling this will reduce power consumption from the battery voltage
+ * measurement.
+ */
+
+void adc_disable_vbat_sensor(void)
+{
+ ADC_CCR &= ~ADC_CCR_VBATEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Start the calibration procedure
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_calibrate_start(uint32_t adc)
+{
+ ADC_CR(adc) = ADC_CR_ADCAL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Wait to finish the ADC calibration procedure
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_calibrate_wait_finish(uint32_t adc)
+{
+ while (ADC_CR(adc) & ADC_CR_ADCAL);
+}
+
+/**@}*/
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+/**
+ * @defgroup adc_api_wdg ADC Analog watchdog API
+ * @ingroup adc_file
+ *
+ * @brief ADC analog watchdog API definitions.
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Analog watchdog is disabled
+ * by default.
+ *
+ * @warning Comparison is done before data alignment takes place, so the
+ * thresholds are left-aligned.
+ *
+ * Example 1: Enable watchdog checking on all channels
+ *
+ * @code
+ * // in configuration
+ * adc_enable_analog_watchdog_on_all_channels(ADC1);
+ * adc_set_watchdog_high_threshold(ADC1, 0xE00);
+ * adc_set_watchdog_low_threshold(ADC1, 0x200);
+ *
+ * // in the main application thread
+ * if (adc_get_watchdog_flag(ADC1)) {
+ * // the converted signal is out of AWD ranges
+ * adc_clear_watchdog_flag(ADC1);
+ * }
+ * @endcode
+ *
+ * Example 2: Enable watchdog checking on channel 5
+ *
+ * @code
+ * // in configuration
+ * adc_enable_analog_watchdog_on_selected_channel(ADC1,5);
+ * adc_set_watchdog_high_threshold(ADC1, 0xE00);
+ * adc_set_watchdog_low_threshold(ADC1, 0x200);
+ *
+ * // in the main application thread
+ * if (adc_get_watchdog_flag(ADC1)) {
+ * // the converted signal is out of AWD ranges
+ * adc_clear_watchdog_flag(ADC1);
+ * }
+ * @endcode
+ *@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for All Channels
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+
+void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
+{
+ ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN;
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for a Selected Channel
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] chan Unsigned int8. ADC channel number @ref adc_api_channel
+ */
+
+void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, uint8_t chan)
+{
+ ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_AWDCH) |
+ ADC_CFGR1_AWDCH_VAL(chan);
+
+ ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN | ADC_CFGR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ */
+void adc_disable_analog_watchdog(uint32_t adc)
+{
+ ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Upper Threshold
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] threshold Unsigned int8. Upper threshold value
+ */
+
+void adc_set_watchdog_high_threshold(uint32_t adc, uint8_t threshold)
+{
+ ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_HT) | ADC_TR_HT_VAL(threshold);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Lower Threshold
+ *
+ * @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
+ * @param[in] threshold Unsigned int8. Lower threshold value
+ */
+
+void adc_set_watchdog_low_threshold(uint32_t adc, uint8_t threshold)
+{
+ ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_LT) | ADC_TR_LT_VAL(threshold);
+}
+
+/**@}*/
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f0/comparator.c b/libopencm3/lib/stm32/f0/comparator.c
new file mode 100644
index 0000000..51bd0f2
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/comparator.c
@@ -0,0 +1,64 @@
+/** @defgroup comp_file COMP
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx COMP</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 10 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**@{*/
+
+#include <libopencm3/stm32/comparator.h>
+
+void comp_enable(uint8_t id)
+{
+ COMP_CSR(id) |= COMP_CSR_EN;
+}
+
+void comp_disable(uint8_t id)
+{
+ COMP_CSR(id) &= ~COMP_CSR_EN;
+}
+
+void comp_select_input(uint8_t id, uint32_t input)
+{
+ COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_INSEL) | input;
+}
+
+void comp_select_output(uint8_t id, uint32_t output)
+{
+ COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_OUTSEL) | output;
+}
+
+void comp_select_hyst(uint8_t id, uint32_t hyst)
+{
+ COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_HYST) | hyst;
+}
+
+void comp_select_speed(uint8_t id, uint32_t speed)
+{
+ COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_SPEED) | speed;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f0/crc.c b/libopencm3/lib/stm32/f0/crc.c
new file mode 100644
index 0000000..2519b22
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/crc.c
@@ -0,0 +1,31 @@
+/** @defgroup crc_file CRC
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx CRC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
diff --git a/libopencm3/lib/stm32/f0/crs.c b/libopencm3/lib/stm32/f0/crs.c
new file mode 100644
index 0000000..db45168
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/crs.c
@@ -0,0 +1,32 @@
+/** @defgroup crs_file CRS
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Clock Recovery Subsystem</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 5 Feb 2014
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crs.h>
+
diff --git a/libopencm3/lib/stm32/f0/dac.c b/libopencm3/lib/stm32/f0/dac.c
new file mode 100644
index 0000000..55cdd62
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx DAC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/f0/dma.c b/libopencm3/lib/stm32/f0/dma.c
new file mode 100644
index 0000000..8f158a8
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx DMA</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 10 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/f0/flash.c b/libopencm3/lib/stm32/f0/flash.c
new file mode 100644
index 0000000..618405b
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/flash.c
@@ -0,0 +1,157 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F05x FLASH</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013
+ * Frantisek Burian <BuFran@seznam.cz>
+ *
+ * @date 14 January 2014
+ *
+ * For the STM32F05x, accessing FLASH memory is described in
+ * section 3 of the STM32F05x Reference Manual.
+ *
+ * FLASH memory may be used for data storage as well as code, and may be
+ * programmatically modified. Note that for firmware upload the STM32F1xx
+ * provides a built-in bootloader in system memory that can be entered from a
+ * running program.
+ *
+ * FLASH must first be unlocked before programming. In this module a write to
+ * FLASH is a blocking operation until the end-of-operation flag is asserted.
+ *
+ * @note: don't forget to lock it again when all operations are complete.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear All Status Flags
+
+Program error, end of operation, write protect error, busy.
+*/
+
+void flash_clear_status_flags(void)
+{
+ flash_clear_pgerr_flag();
+ flash_clear_eop_flag();
+ flash_clear_wrprterr_flag();
+ flash_clear_bsy_flag();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read All Status Flags
+
+The programming error, end of operation, write protect error and busy flags
+are returned in the order of appearance in the status register.
+
+@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect
+error, bit 5: end of operation.
+*/
+
+uint32_t flash_get_status_flags(void)
+{
+ return (FLASH_SR & (FLASH_SR_PGERR |
+ FLASH_SR_EOP |
+ FLASH_SR_WRPRTERR |
+ FLASH_SR_BSY));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Half Word to FLASH
+
+This performs all operations necessary to program a 16 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+Status bit polling is used to detect end of operation.
+
+@param[in] uint32_t address. Full address of flash half word to be programmed.
+@param[in] uint16_t data.
+*/
+
+void flash_program_half_word(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+
+ FLASH_CR |= FLASH_CR_PG;
+
+ MMIO16(address) = data;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase a Page of FLASH
+
+This performs all operations necessary to erase a page in FLASH memory.
+The page should be checked to ensure that it was properly erased. A page must
+first be fully erased before attempting to program it.
+
+Note that the page sizes differ between devices. See the reference manual or
+the FLASH programming manual for details.
+
+@param[in] uint32_t page_address. Full address of flash page to be erased.
+*/
+
+void flash_erase_page(uint32_t page_address)
+{
+ flash_wait_for_last_operation();
+
+ FLASH_CR |= FLASH_CR_PER;
+ FLASH_AR = page_address;
+ FLASH_CR |= FLASH_CR_STRT;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PER;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All FLASH
+
+This performs all operations necessary to erase all user pages in the FLASH
+memory. The information block is unaffected.
+*/
+
+void flash_erase_all_pages(void)
+{
+ flash_wait_for_last_operation();
+
+ FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
+ FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
+
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f0/gpio.c b/libopencm3/lib/stm32/f0/gpio.c
new file mode 100644
index 0000000..f60b428
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/gpio.c
@@ -0,0 +1,31 @@
+/** @defgroup gpio_file GPIO
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx General Purpose I/O</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 18 August 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/gpio.h>
diff --git a/libopencm3/lib/stm32/f0/i2c.c b/libopencm3/lib/stm32/f0/i2c.c
new file mode 100644
index 0000000..a39c4be
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/i2c.c
@@ -0,0 +1,32 @@
+/** @defgroup i2c_file I2C
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx I2C</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
+
diff --git a/libopencm3/lib/stm32/f0/iwdg.c b/libopencm3/lib/stm32/f0/iwdg.c
new file mode 100644
index 0000000..b34a652
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Independent Watchdog Timer</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld b/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/libopencm3_stm32f0.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/f0/pwr.c b/libopencm3/lib/stm32/f0/pwr.c
new file mode 100644
index 0000000..8a3ffd2
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/pwr.c
@@ -0,0 +1,38 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Power Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * This library supports the power control system for the
+ * STM32F0 series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/pwr.h>
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f0/rcc.c b/libopencm3/lib/stm32/f0/rcc.c
new file mode 100644
index 0000000..1f37133
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/rcc.c
@@ -0,0 +1,665 @@
+/** @defgroup STM32F0xx-rcc-file RCC
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Reset and Clock Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 29 Jun 2013
+ *
+ * This library supports the Reset and Clock Control System in the STM32F0xx
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+
+uint32_t rcc_core_frequency = 8000000; /* 8MHz after reset */
+uint32_t rcc_ppre_frequency = 8000000; /* 8MHz after reset */
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Clear the Oscillator Ready Interrupt Flag
+ *
+ * Clear the interrupt flag that was set when a clock oscillator became ready
+ * to use.
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_osc_ready_int_clear(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ RCC_CIR |= RCC_CIR_HSI48RDYC;
+ break;
+ case HSI14:
+ RCC_CIR |= RCC_CIR_HSI14RDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable the Oscillator Ready Interrupt
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_osc_ready_int_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ RCC_CIR |= RCC_CIR_HSI48RDYIE;
+ break;
+ case HSI14:
+ RCC_CIR |= RCC_CIR_HSI14RDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable the Oscillator Ready Interrupt
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_osc_ready_int_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ RCC_CIR &= ~RCC_CIR_HSI48RDYC;
+ break;
+ case HSI14:
+ RCC_CIR &= ~RCC_CIR_HSI14RDYC;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYC;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYC;
+ break;
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYC;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Read the Oscillator Ready Interrupt Flag
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ * @returns int. Boolean value for flag set.
+ */
+
+int rcc_osc_ready_int_flag(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ return (RCC_CIR & RCC_CIR_HSI48RDYF) != 0;
+ break;
+ case HSI14:
+ return (RCC_CIR & RCC_CIR_HSI14RDYF) != 0;
+ break;
+ case HSI:
+ return (RCC_CIR & RCC_CIR_HSIRDYF) != 0;
+ break;
+ case HSE:
+ return (RCC_CIR & RCC_CIR_HSERDYF) != 0;
+ break;
+ case PLL:
+ return (RCC_CIR & RCC_CIR_PLLRDYF) != 0;
+ break;
+ case LSE:
+ return (RCC_CIR & RCC_CIR_LSERDYF) != 0;
+ break;
+ case LSI:
+ return (RCC_CIR & RCC_CIR_LSIRDYF) != 0;
+ break;
+ }
+
+ cm3_assert_not_reached();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Clear the Clock Security System Interrupt Flag
+*/
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Read the Clock Security System Interrupt Flag
+ *
+ * @returns int. Boolean value for flag set.
+ */
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Wait for Oscillator Ready.
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_wait_for_osc_ready(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ while ((RCC_CIR & RCC_CIR_HSI48RDYF) != 0);
+ break;
+ case HSI14:
+ while ((RCC_CIR & RCC_CIR_HSI14RDYF) != 0);
+ break;
+ case HSI:
+ while ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case HSE:
+ while ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case PLL:
+ while ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case LSE:
+ while ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ while ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Turn on an Oscillator.
+ *
+ * Enable an oscillator and power on. Each oscillator requires an amount of
+ * time to settle to a usable state. Refer to datasheets for time delay
+ * information. A status flag is available to indicate when the oscillator
+ * becomes ready (see @ref rcc_osc_ready_int_flag and @ref
+ * rcc_wait_for_osc_ready).
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_osc_on(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ RCC_CR2 |= RCC_CR2_HSI48ON;
+ break;
+ case HSI14:
+ RCC_CR2 |= RCC_CR2_HSI14ON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Turn off an Oscillator.
+ *
+ * Disable an oscillator and power off.
+ *
+ * @note An oscillator cannot be turned off if it is selected as the system
+ * clock.
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID
+ */
+
+void rcc_osc_off(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSI48:
+ RCC_CR2 &= ~RCC_CR2_HSI48ON;
+ break;
+ case HSI14:
+ RCC_CR2 &= ~RCC_CR2_HSI14ON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ case PLL:
+ /* don't do anything */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable the Clock Security System.
+ */
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable the Clock Security System.
+ */
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable Bypass.
+ *
+ * Enable an external clock to bypass the internal clock (high speed and low
+ * speed clocks only). The external clock must be enabled (see @ref rcc_osc_on)
+ * and the internal clock must be disabled (see @ref rcc_osc_off) for this to
+ * have effect.
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+ */
+
+void rcc_osc_bypass_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEBYP;
+ break;
+ case HSI48:
+ case HSI14:
+ case HSI:
+ case LSI:
+ case PLL:
+ /* Do nothing */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable Bypass.
+ *
+ * Re-enable the internal clock (high speed and low speed clocks only). The
+ * internal clock must be disabled (see @ref rcc_osc_off) for this to have
+ * effect.
+ *
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+ */
+
+void rcc_osc_bypass_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEBYP;
+ break;
+ case HSI48:
+ case HSI14:
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the Source for the System Clock.
+ *
+ * @param[in] osc enum ::osc_t. Oscillator ID. Only HSE, LSE and PLL have
+ * effect.
+ */
+
+void rcc_set_sysclk_source(enum rcc_osc clk)
+{
+ switch (clk) {
+ case HSI:
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
+ break;
+ case HSE:
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE;
+ break;
+ case PLL:
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
+ break;
+ case HSI48:
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI48;
+ break;
+ case LSI:
+ case LSE:
+ case HSI14:
+ /* do nothing */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL Multiplication Factor.
+ *
+ * @note This only has effect when the PLL is disabled.
+ *
+ * @param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+ */
+
+void rcc_set_pll_multiplication_factor(uint32_t mul)
+{
+ RCC_CFGR = (RCC_CFGR & RCC_CFGR_PLLMUL) | mul;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the APB Prescale Factor.
+ *
+ * @note The APB1 clock frequency must not exceed 36MHz.
+ *
+ * @param[in] ppre1 Unsigned int32. APB prescale factor @ref rcc_cfgr_apb1pre
+ */
+
+void rcc_set_ppre(uint32_t ppre)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE) | ppre;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the AHB Prescale Factor.
+ *
+ * @param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
+ */
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) | hpre;
+}
+
+
+void rcc_set_prediv(uint32_t prediv)
+{
+ RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv;
+}
+
+
+void rcc_set_mco(uint32_t mcosrc)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_MCO) | mcosrc;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Get the System Clock Source.
+ *
+ * @returns ::osc_t System clock source:
+ */
+
+enum rcc_osc rcc_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ switch (RCC_CFGR & RCC_CFGR_SWS) {
+ case RCC_CFGR_SWS_HSI:
+ return HSI;
+ case RCC_CFGR_SWS_HSE:
+ return HSE;
+ case RCC_CFGR_SWS_PLL:
+ return PLL;
+ case RCC_CFGR_SWS_HSI48:
+ return HSI48;
+ }
+
+ cm3_assert_not_reached();
+}
+
+void rcc_clock_setup_in_hsi_out_8mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
+
+ rcc_ppre_frequency = 8000000;
+ rcc_core_frequency = 8000000;
+}
+
+void rcc_clock_setup_in_hsi_out_16mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
+
+ /* 8MHz * 4 / 2 = 16MHz */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL4);
+
+ RCC_CFGR &= ~RCC_CFGR_PLLSRC;
+
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ rcc_set_sysclk_source(PLL);
+
+ rcc_ppre_frequency = 16000000;
+ rcc_core_frequency = 16000000;
+}
+
+
+void rcc_clock_setup_in_hsi_out_24mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
+
+ /* 8MHz * 6 / 2 = 24MHz */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL6);
+
+ RCC_CFGR &= ~RCC_CFGR_PLLSRC;
+
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ rcc_set_sysclk_source(PLL);
+
+ rcc_ppre_frequency = 24000000;
+ rcc_core_frequency = 24000000;
+}
+
+void rcc_clock_setup_in_hsi_out_32mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
+
+ /* 8MHz * 8 / 2 = 32MHz */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL8);
+
+ RCC_CFGR &= ~RCC_CFGR_PLLSRC;
+
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ rcc_set_sysclk_source(PLL);
+
+ rcc_ppre_frequency = 32000000;
+ rcc_core_frequency = 32000000;
+}
+
+void rcc_clock_setup_in_hsi_out_40mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
+
+ /* 8MHz * 10 / 2 = 40MHz */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL10);
+
+ RCC_CFGR &= ~RCC_CFGR_PLLSRC;
+
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ rcc_set_sysclk_source(PLL);
+
+ rcc_ppre_frequency = 40000000;
+ rcc_core_frequency = 40000000;
+}
+
+void rcc_clock_setup_in_hsi_out_48mhz(void)
+{
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ rcc_set_sysclk_source(HSI);
+
+ rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
+ rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
+
+ flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
+
+ /* 8MHz * 12 / 2 = 48MHz */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL12);
+
+ RCC_CFGR &= ~RCC_CFGR_PLLSRC;
+
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ rcc_set_sysclk_source(PLL);
+
+ rcc_ppre_frequency = 48000000;
+ rcc_core_frequency = 48000000;
+}
+
+
+#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5))
+#define _RCC_BIT(i) (1 << ((i) & 0x1f))
+
+void rcc_periph_clock_enable(enum rcc_periph_clken periph)
+{
+ _RCC_REG(periph) |= _RCC_BIT(periph);
+}
+
+void rcc_periph_clock_disable(enum rcc_periph_clken periph)
+{
+ _RCC_REG(periph) &= ~_RCC_BIT(periph);
+}
+
+void rcc_periph_reset_pulse(enum rcc_periph_rst periph)
+{
+ _RCC_REG(periph) |= _RCC_BIT(periph);
+ _RCC_REG(periph) &= ~_RCC_BIT(periph);
+}
+
+void rcc_periph_reset_hold(enum rcc_periph_rst periph)
+{
+ _RCC_REG(periph) |= _RCC_BIT(periph);
+}
+
+void rcc_periph_reset_release(enum rcc_periph_rst periph)
+{
+ _RCC_REG(periph) &= ~_RCC_BIT(periph);
+}
+
+#undef _RCC_REG
+#undef _RCC_BIT
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f0/rtc.c b/libopencm3/lib/stm32/f0/rtc.c
new file mode 100644
index 0000000..6d55cc7
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/rtc.c
@@ -0,0 +1,31 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx RTC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 10 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/rtc.h>
diff --git a/libopencm3/lib/stm32/f0/spi.c b/libopencm3/lib/stm32/f0/spi.c
new file mode 100644
index 0000000..c341001
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32F0xx
+
+@brief <b>libopencm3 STM32F0xx SPI</b>
+
+@version 1.0.0
+
+@date 20 February 2014
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/f0/syscfg.c b/libopencm3/lib/stm32/f0/syscfg.c
new file mode 100644
index 0000000..5067d96
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/syscfg.c
@@ -0,0 +1,31 @@
+/** @defgroup syscfg_file SYSCFG
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx SYSCFG</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 10 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/syscfg.h>
diff --git a/libopencm3/lib/stm32/f0/timer.c b/libopencm3/lib/stm32/f0/timer.c
new file mode 100644
index 0000000..8800683
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/timer.c
@@ -0,0 +1,34 @@
+/** @defgroup timer_file Timers
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx Timers</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/timer.h>
+
diff --git a/libopencm3/lib/stm32/f0/usart.c b/libopencm3/lib/stm32/f0/usart.c
new file mode 100644
index 0000000..3788926
--- /dev/null
+++ b/libopencm3/lib/stm32/f0/usart.c
@@ -0,0 +1,429 @@
+/** @defgroup usart_file USART
+ *
+ * @ingroup STM32F0xx
+ *
+ * @brief <b>libopencm3 STM32F0xx USART</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 7 Jul 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Baudrate.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] baud unsigned 32 bit. Baud rate specified in Hz.
+ */
+
+void usart_set_baudrate(uint32_t usart, uint32_t baud)
+{
+ uint32_t clock = rcc_ppre_frequency;
+
+ if (usart == USART1) {
+ clock = rcc_ppre_frequency;
+ /* TODO selective PCLK, SYSCLK, HSI or LSE */
+ }
+
+ /* TODO check oversampling 16 */
+ USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Word Length.
+ *
+ * The word length is set to 8 or 9 bits. Note that the last bit will be a
+ * parity bit if parity is enabled, in which case the data length will be 7
+ * or 8 bits respectively.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
+ */
+
+void usart_set_databits(uint32_t usart, uint32_t bits)
+{
+ if (bits == 8) {
+ USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
+ } else {
+ USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Stop Bit(s).
+ *
+ * The stop bits are specified as 0.5, 1, 1.5 or 2.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
+ */
+
+void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
+{
+ USART_CR2(usart) = (USART_CR2(usart) & ~USART_CR2_STOP) | stopbits;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Parity.
+ *
+ * The parity bit can be selected as none, even or odd.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
+ */
+
+void usart_set_parity(uint32_t usart, uint32_t parity)
+{
+ USART_CR1(usart) = (USART_CR1(usart) & ~USART_PARITY) | parity;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Rx/Tx Mode.
+ *
+ * The mode can be selected as Rx only, Tx only or Rx+Tx.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
+ */
+
+void usart_set_mode(uint32_t usart, uint32_t mode)
+{
+ USART_CR1(usart) = (USART_CR1(usart) & ~USART_MODE) | mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Hardware Flow Control.
+ *
+ * The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref
+ * usart_cr3_flowcontrol.
+ */
+
+void usart_set_flow_control(uint32_t usart, uint32_t flowctrl)
+{
+ USART_CR3(usart) = (USART_CR3(usart) & ~USART_FLOWCONTROL) | flowctrl;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Enable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_enable(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Disable.
+ *
+ * At the end of the current frame, the USART is disabled to reduce power.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send a Data Word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] data unsigned 16 bit.
+ */
+
+void usart_send(uint32_t usart, uint8_t data)
+{
+ USART_TDR(usart) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word.
+ *
+ * If parity is enabled the MSB (bit 7 or 8 depending on the word length) is
+ * the parity bit.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @returns unsigned 16 bit data word.
+ */
+
+uint8_t usart_recv(uint32_t usart)
+{
+ /* Receive data. */
+ return USART_RDR(usart);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Transmit Data Buffer Empty
+ *
+ * Blocks until the transmit data buffer becomes empty and is ready to accept
+ * the next data word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_wait_send_ready(uint32_t usart)
+{
+ /* Wait until the data has been transferred into the shift register. */
+ while ((USART_ISR(usart) & USART_ISR_TXE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Received Data Available
+ *
+ * Blocks until the receive data buffer holds a valid received data word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_wait_recv_ready(uint32_t usart)
+{
+ /* Wait until the data is ready to be received. */
+ while ((USART_ISR(usart) & USART_ISR_RXNE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send Data Word with Blocking
+ *
+ * Blocks until the transmit data buffer becomes empty then writes the next
+ * data word for transmission.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] data unsigned 16 bit.
+ */
+
+void usart_send_blocking(uint32_t usart, uint8_t data)
+{
+ usart_wait_send_ready(usart);
+ usart_send(usart, data);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word with Blocking.
+ *
+ * Wait until a data word has been received then return the word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @returns unsigned 16 bit data word.
+ */
+
+uint8_t usart_recv_blocking(uint32_t usart)
+{
+ usart_wait_recv_ready(usart);
+
+ return usart_recv(usart);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Enable.
+ *
+ * DMA is available on:
+ * @li USART1 Rx DMA1 channel 3 or 5.
+ * @li USART2 Rx DMA1 channel 5.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_enable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Disable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Enable.
+ *
+ * DMA is available on:
+ * @li USART1 Tx DMA1 channel 2 or 4.
+ * @li USART2 Tx DMA1 channel 4.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_enable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Disable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_RXNEIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Disable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Enable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_enable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Disable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Enable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_enable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_EIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Disable.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_disable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_EIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Status Flag.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+ * @returns boolean: flag set.
+ */
+
+bool usart_get_flag(uint32_t usart, uint32_t flag)
+{
+ return ((USART_ISR(usart) & flag) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Return Interrupt Source.
+ *
+ * Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
+ * set and the interrupt was enabled. If the specified flag is not an interrupt
+ * flag, the function returns false.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+ * @returns boolean: flag and interrupt enable both set.
+ */
+
+bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
+{
+ uint32_t flag_set = (USART_ISR(usart) & flag);
+ /* IDLE, RXNE, TC, TXE interrupts */
+ if ((flag >= USART_ISR_IDLE) && (flag <= USART_ISR_TXE)) {
+ return ((flag_set & USART_CR1(usart)) != 0);
+ /* Overrun error */
+ } else if (flag == USART_ISR_ORE) {
+ return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
+ }
+
+ return false;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/Makefile b/libopencm3/lib/stm32/f1/Makefile
new file mode 100644
index 0000000..a4ee7a1
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/Makefile
@@ -0,0 +1,53 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32f1
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32F1
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+
+OBJS = adc.o adc_common_v1.o can.o desig.o ethernet.o flash.o gpio.o \
+ rcc.o rtc.o timer.o
+
+OBJS += crc_common_all.o dac_common_all.o dma_common_l1f013.o \
+ gpio_common_all.o i2c_common_all.o iwdg_common_all.o \
+ pwr_common_all.o spi_common_all.o spi_common_l1f124.o \
+ timer_common_all.o usart_common_all.o usart_common_f124.o \
+ rcc_common_all.o exti_common_all.o \
+ flash_common_f01.o
+
+OBJS += usb.o usb_control.o usb_standard.o usb_f103.o usb_f107.o \
+ usb_fx07_common.o usb_msc.o
+
+VPATH += ../../usb:../:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/stm32/f1/adc.c b/libopencm3/lib/stm32/f1/adc.c
new file mode 100644
index 0000000..e8be6f9
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/adc.c
@@ -0,0 +1,452 @@
+/** @defgroup adc_file ADC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Analog to Digital Converters</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Edward Cheeseman <evbuilder@users.sourceforge.net>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+@date 18 August 2012
+
+This library supports the A/D Converter Control System in the STM32F1xx series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to three A/D converters each with their own set of
+registers. However all the A/D converters share a common clock which is
+prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum
+of 8.
+
+Each A/D converter has up to 18 channels:
+@li On ADC1 the analog channels 16 and 17 are internally connected to the
+temperature
+sensor and V<sub>REFINT</sub>, respectively.
+@li On ADC2 the analog channels 16 and 17 are internally connected to
+V<sub>SS</sub>.
+@li On ADC3 the analog channels 9, 14, 15, 16 and 17 are internally connected
+to V<sub>SS</sub>.
+
+The conversions can occur as a one-off conversion whereby the process stops
+once conversion is complete. The conversions can also be continuous wherein a
+new conversion starts immediately the previous conversion has ended.
+
+Conversion can occur as a single channel conversion or a scan of a group of
+channels in either continuous or one-off mode. If more than one channel is
+converted in a scan group, DMA must be used to transfer the data as there is
+only one result register available. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+A discontinuous mode allows a subgroup of group of a channels to be converted
+in bursts of a given length.
+
+Injected conversions allow a second group of channels to be converted
+separately from the regular group. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+@section adc_api_ex Basic ADC Handling API.
+
+Example 1: Simple single channel conversion polled. Enable the peripheral clock
+and ADC, reset ADC and set the prescaler divider. Set dual mode to independent
+(default). Enable triggering for a software trigger.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+ adc_off(ADC1);
+ rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
+ adc_set_dual_mode(ADC_CR1_DUALMOD_IND);
+ adc_disable_scan_mode(ADC1);
+ adc_set_single_conversion_mode(ADC1);
+ adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
+ adc_set_single_channel(ADC1, ADC_CHANNEL0);
+ adc_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART);
+ adc_power_on(ADC1);
+ adc_reset_calibration(ADC1);
+ adc_calibration(ADC1);
+ adc_start_conversion_regular(ADC1);
+ while (! adc_eoc(ADC1));
+ reg16 = adc_read_regular(ADC1);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Basic ADC handling API.
+ *
+ * Examples:
+ * rcc_peripheral_enable_clock(&RCC_APB2ENR, ADC1EN);
+ * rcc_peripheral_disable_clock(&RCC_APB2ENR, ADC1EN);
+ * rcc_peripheral_reset(&RCC_APB2RSTR, ADC1RST);
+ * rcc_peripheral_clear_reset(&RCC_APB2RSTR, ADC1RST);
+ *
+ * rcc_set_adc_clk(ADC_PRE_PLCK2_DIV2);
+ * adc_set_dual_mode(ADC1, TODO);
+ * reg16 = adc_read(ADC1, ADC_CH_0);
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/adc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+
+If the ADC is in power-down mode then it is powered up. The application needs
+to wait a time of about 3 microseconds for stabilization before using the ADC.
+If the ADC is already on this function call has no effect.
+ * NOTE Common with F37x
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_power_on(uint32_t adc)
+{
+ if (!(ADC_CR2(adc) & ADC_CR2_ADON)) {
+ ADC_CR2(adc) |= ADC_CR2_ADON;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Start a Conversion Without Trigger
+
+This initiates a conversion by software without a trigger. The ADC needs to be
+powered on before this is called, otherwise this function has no effect.
+
+Note that this is not available in other STM32F families. To ensure code
+compatibility, enable triggering and use a software trigger source @see
+adc_start_conversion_regular.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_start_conversion_direct(uint32_t adc)
+{
+ if (ADC_CR2(adc) & ADC_CR2_ADON) {
+ ADC_CR2(adc) |= ADC_CR2_ADON;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Dual A/D Mode
+
+The dual mode uses ADC1 as master and ADC2 in a slave arrangement. This setting
+is applied to ADC1 only. Start of conversion when triggered can cause
+simultaneous conversion with ADC2, or alternate conversion. Regular and
+injected conversions can be configured, each one being separately simultaneous
+or alternate.
+
+Fast interleaved mode starts ADC1 immediately on trigger, and ADC2 seven clock
+cycles later.
+
+Slow interleaved mode starts ADC1 immediately on trigger, and ADC2 fourteen
+clock cycles later, followed by ADC1 fourteen cycles later again. This can only
+be used on a single channel.
+
+Alternate trigger mode must occur on an injected channel group, and alternates
+between the ADCs on each trigger.
+
+Note that sampling must not overlap between ADCs on the same channel.
+
+Dual A/D converter modes possible:
+
+@li IND: Independent mode.
+@li CRSISM: Combined regular simultaneous + injected simultaneous mode.
+@li CRSATM: Combined regular simultaneous + alternate trigger mode.
+@li CISFIM: Combined injected simultaneous + fast interleaved mode.
+@li CISSIM: Combined injected simultaneous + slow interleaved mode.
+@li ISM: Injected simultaneous mode only.
+@li RSM: Regular simultaneous mode only.
+@li FIM: Fast interleaved mode only.
+@li SIM: Slow interleaved mode only.
+@li ATM: Alternate trigger mode only.
+
+@param[in] mode Unsigned int32. Dual mode selection from @ref adc_cr1_dualmod
+*/
+
+void adc_set_dual_mode(uint32_t mode)
+{
+ ADC1_CR1 |= mode;
+}
+
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+
+This enables both the sensor and the reference voltage measurements on channels
+16 and 17.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_enable_temperature_sensor(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_TSVREFE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+
+Disabling this will reduce power consumption from the sensor and the reference
+voltage measurements.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_disable_temperature_sensor(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_TSVREFE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+
+This enables an external trigger for set of defined regular channels.
+
+For ADC1 and ADC2
+@li Timer 1 CC1 event
+@li Timer 1 CC2 event
+@li Timer 1 CC3 event
+@li Timer 2 CC2 event
+@li Timer 3 TRGO event
+@li Timer 4 CC4 event
+@li EXTI (TIM8_TRGO is also possible on some devices, see datasheet)
+@li Software Start
+
+For ADC3
+@li Timer 3 CC1 event
+@li Timer 2 CC3 event
+@li Timer 1 CC3 event
+@li Timer 8 CC1 event
+@li Timer 8 TRGO event
+@li Timer 5 CC1 event
+@li Timer 5 CC3 event
+@li Software Start
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_regular_12
+for ADC1 and ADC2, or @ref adc_trigger_regular_3 for ADC3.
+*/
+
+void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger)
+{
+ uint32_t reg32;
+
+ reg32 = (ADC_CR2(adc) & ~(ADC_CR2_EXTSEL_MASK));
+ reg32 |= (trigger);
+ ADC_CR2(adc) = reg32;
+ ADC_CR2(adc) |= ADC_CR2_EXTTRIG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_disable_external_trigger_regular(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_EXTTRIG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Injected Channels
+
+This enables an external trigger for set of defined injected channels.
+
+For ADC1 and ADC2
+@li Timer 1 TRGO event
+@li Timer 1 CC4 event
+@li Timer 2 TRGO event
+@li Timer 2 CC1 event
+@li Timer 3 CC4 event
+@li Timer 4 TRGO event
+@li EXTI (TIM8 CC4 is also possible on some devices, see datasheet)
+@li Software Start
+
+For ADC3
+@li Timer 1 TRGO event
+@li Timer 1 CC4 event
+@li Timer 4 CC3 event
+@li Timer 8 CC2 event
+@li Timer 8 CC4 event
+@li Timer 5 TRGO event
+@li Timer 5 CC4 event
+@li Software Start
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+@param[in] trigger Unsigned int8. Trigger identifier @ref
+adc_trigger_injected_12 for ADC1 and ADC2, or @ref adc_trigger_injected_3 for
+ADC3.
+*/
+void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger)
+{
+ uint32_t reg32;
+
+ reg32 = (ADC_CR2(adc) & ~(ADC_CR2_JEXTSEL_MASK)); /* Clear bits [12:14]
+ */
+ reg32 |= (trigger);
+ ADC_CR2(adc) = reg32;
+ ADC_CR2(adc) |= ADC_CR2_JEXTTRIG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Injected Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_disable_external_trigger_injected(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_JEXTTRIG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Initialize Calibration Registers
+
+This resets the calibration registers. It is not clear if this is required to be
+done before every calibration operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_reset_calibration(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_RSTCAL;
+ while (ADC_CR2(adc) & ADC_CR2_RSTCAL);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Calibration
+
+The calibration data for the ADC is recomputed. The hardware clears the
+calibration status flag when calibration is complete. This function does not
+return until this happens and the ADC is ready for use.
+
+The ADC must have been powered down for at least 2 ADC clock cycles, then
+powered on. before calibration starts
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_calibration(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_CAL;
+ while (ADC_CR2(adc) & ADC_CR2_CAL);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+
+If the ADC is in power-down mode then it is powered up. The application needs
+to wait a time of about 3 microseconds for stabilization before using the ADC.
+If the ADC is already on this function call will initiate a conversion.
+
+@deprecated to be removed in a later release
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_on(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_ADON;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for a Single Channel
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref
+adc_channel.
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
+ * * NOTE Common with f2 and f37x and f4
+*/
+
+void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
+{
+ uint32_t reg32;
+
+ if (channel < 10) {
+ reg32 = ADC_SMPR2(adc);
+ reg32 &= ~(0x7 << (channel * 3));
+ reg32 |= (time << (channel * 3));
+ ADC_SMPR2(adc) = reg32;
+ } else {
+ reg32 = ADC_SMPR1(adc);
+ reg32 &= ~(0x7 << ((channel - 10) * 3));
+ reg32 |= (time << ((channel - 10) * 3));
+ ADC_SMPR1(adc) = reg32;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same
+for all channels.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
+ * * NOTE Common with f2 and f37x and f4
+*/
+
+void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
+{
+ uint8_t i;
+ uint32_t reg32 = 0;
+
+ for (i = 0; i <= 9; i++) {
+ reg32 |= (time << (i * 3));
+ }
+ ADC_SMPR2(adc) = reg32;
+
+ for (i = 10; i <= 17; i++) {
+ reg32 |= (time << ((i - 10) * 3));
+ }
+ ADC_SMPR1(adc) = reg32;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/crc.c b/libopencm3/lib/stm32/f1/crc.c
new file mode 100644
index 0000000..027052d
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/crc.c
@@ -0,0 +1,31 @@
+/** @defgroup crc_file CRC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx CRC</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
diff --git a/libopencm3/lib/stm32/f1/dac.c b/libopencm3/lib/stm32/f1/dac.c
new file mode 100644
index 0000000..fa599bb
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx DAC</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/f1/dma.c b/libopencm3/lib/stm32/f1/dma.c
new file mode 100644
index 0000000..7019365
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx DMA</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/f1/ethernet.c b/libopencm3/lib/stm32/f1/ethernet.c
new file mode 100644
index 0000000..8b65780
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/ethernet.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/f1/ethernet.h>
+
+void eth_smi_write(uint8_t phy, uint8_t reg, uint16_t data)
+{
+ /* Set PHY and register addresses for write access. */
+ ETH_MACMIIAR &= ~(ETH_MACMIIAR_MR | ETH_MACMIIAR_PA);
+ ETH_MACMIIAR |= (phy << 11) | (reg << 6) | ETH_MACMIIAR_MW;
+
+ /* Set register value. */
+ ETH_MACMIIDR = data;
+
+ /* Begin transaction. */
+ ETH_MACMIIAR |= ETH_MACMIIAR_MB;
+
+ /* Wait for not busy. */
+ while (ETH_MACMIIAR & ETH_MACMIIAR_MB);
+}
+
+uint16_t eth_smi_read(uint8_t phy, uint8_t reg)
+{
+ /* Set PHY and register addresses for write access. */
+ ETH_MACMIIAR &= ~(ETH_MACMIIAR_MR | ETH_MACMIIAR_PA | ETH_MACMIIAR_MW);
+ ETH_MACMIIAR |= (phy << 11) | (reg << 6);
+
+ /* Begin transaction. */
+ ETH_MACMIIAR |= ETH_MACMIIAR_MB;
+
+ /* Wait for not busy. */
+ while (ETH_MACMIIAR & ETH_MACMIIAR_MB);
+
+ /* Set register value. */
+ return (uint16_t)(ETH_MACMIIDR);
+}
diff --git a/libopencm3/lib/stm32/f1/flash.c b/libopencm3/lib/stm32/f1/flash.c
new file mode 100644
index 0000000..5712e1c
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/flash.c
@@ -0,0 +1,306 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32F1xx
+ *
+ * @brief <b>libopencm3 STM32F1xx FLASH Memory</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * @date 14 January 2014
+ *
+ * For the STM32F1xx, accessing FLASH memory is described briefly in
+ * section 3.3.3 of the STM32F10x Reference Manual.
+ * For detailed programming information see:
+ * PM0075 programming manual: STM32F10xxx Flash programming
+ * August 2010, Doc ID 17863 Rev 1
+ * https://github.com/libopencm3/libopencm3-archive/blob/master/st_micro/CD00283419.pdf
+ *
+ * FLASH memory may be used for data storage as well as code, and may be
+ * programmatically modified. Note that for firmware upload the STM32F1xx
+ * provides a built-in bootloader in system memory that can be entered from a
+ * running program.
+ *
+ * FLASH must first be unlocked before programming. In this module a write to
+ * FLASH is a blocking operation until the end-of-operation flag is asserted.
+ *
+ * @note: don't forget to lock it again when all operations are complete.
+ *
+ * For the large memory XL series, with two banks of FLASH, the upper bank is
+ * accessed with a second set of registers. In principle both banks can be
+ * written simultaneously, or one read while the other is written. This module
+ * does not support the simultaneous write feature.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/* Memory Size Register */
+#define MEMORY_SIZE_REG MMIO32(DESIG_FLASH_SIZE_BASE)
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the FLASH Half Cycle Mode
+
+This mode is used for power saving during read access. It is disabled by default
+on reset.
+
+Note carefully the clock restrictions under which the half cycle mode may be
+enabled or disabled. This mode may only be used while the clock is running at
+8MHz. See the reference manual for details.
+*/
+
+void flash_halfcycle_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_HLFCYA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Half Cycle Mode
+
+*/
+
+void flash_halfcycle_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_HLFCYA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Flash Program and Erase Controller, upper Bank
+
+This enables write access to the upper bank of the Flash memory in XL devices.
+It is locked by default on reset.
+*/
+
+void flash_unlock_upper(void)
+{
+ if (MEMORY_SIZE_REG > 512) {
+
+ /* Clear the unlock state. */
+ FLASH_CR2 |= FLASH_CR_LOCK;
+
+ /* Authorize the FPEC access. */
+ FLASH_KEYR2 = FLASH_KEYR_KEY1;
+ FLASH_KEYR2 = FLASH_KEYR_KEY2;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Flash Program and Erase Controller, upper Bank
+
+Used to prevent spurious writes to FLASH.
+*/
+
+void flash_lock_upper(void)
+{
+ FLASH_CR2 |= FLASH_CR_LOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Error Status Flag, upper Bank
+
+*/
+
+void flash_clear_pgerr_flag_upper(void)
+{
+ if (MEMORY_SIZE_REG > 512)
+ FLASH_SR2 |= FLASH_SR_PGERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the End of Operation Status Flag, upper Bank
+
+*/
+
+void flash_clear_eop_flag_upper(void)
+{
+ if (MEMORY_SIZE_REG > 512)
+ FLASH_SR2 |= FLASH_SR_EOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Write Protect Error Status Flag, upper Bank
+
+*/
+
+void flash_clear_wrprterr_flag_upper(void)
+{
+ if (MEMORY_SIZE_REG > 512)
+ FLASH_SR2 |= FLASH_SR_WRPRTERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Busy Status Flag, upper Bank
+
+*/
+
+void flash_clear_bsy_flag_upper(void)
+{
+ if (MEMORY_SIZE_REG > 512)
+ FLASH_SR2 &= ~FLASH_SR_BSY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear All Status Flags
+
+Program error, end of operation, write protect error, busy. Both banks cleared.
+*/
+
+void flash_clear_status_flags(void)
+{
+ flash_clear_pgerr_flag();
+ flash_clear_eop_flag();
+ flash_clear_wrprterr_flag();
+ flash_clear_bsy_flag();
+ if (MEMORY_SIZE_REG > 512) {
+ flash_clear_pgerr_flag_upper();
+ flash_clear_eop_flag_upper();
+ flash_clear_wrprterr_flag_upper();
+ flash_clear_bsy_flag_upper();
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read All Status Flags
+
+The programming error, end of operation, write protect error and busy flags
+are returned in the order of appearance in the status register.
+
+Flags for the upper bank, where appropriate, are combined with those for
+the lower bank using bitwise OR, without distinction.
+
+@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect
+error, bit 5: end of operation.
+*/
+
+uint32_t flash_get_status_flags(void)
+{
+ uint32_t flags = (FLASH_SR & (FLASH_SR_PGERR |
+ FLASH_SR_EOP |
+ FLASH_SR_WRPRTERR |
+ FLASH_SR_BSY));
+ if (MEMORY_SIZE_REG > 512)
+ flags |= (FLASH_SR2 & (FLASH_SR_PGERR |
+ FLASH_SR_EOP |
+ FLASH_SR_WRPRTERR |
+ FLASH_SR_BSY));
+ return flags;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Half Word to FLASH
+
+This performs all operations necessary to program a 16 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+Status bit polling is used to detect end of operation.
+
+@param[in] uint32_t address. Full address of flash half word to be programmed.
+@param[in] uint16_t data.
+*/
+
+void flash_program_half_word(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+
+ if ((MEMORY_SIZE_REG > 512) && (address >= FLASH_BASE+0x00080000))
+ FLASH_CR2 |= FLASH_CR_PG;
+ else FLASH_CR |= FLASH_CR_PG;
+
+ MMIO16(address) = data;
+
+ flash_wait_for_last_operation();
+
+ if ((MEMORY_SIZE_REG > 512) && (address >= FLASH_BASE+0x00080000))
+ FLASH_CR2 &= ~FLASH_CR_PG;
+ else FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase a Page of FLASH
+
+This performs all operations necessary to erase a page in FLASH memory.
+The page should be checked to ensure that it was properly erased. A page must
+first be fully erased before attempting to program it.
+
+Note that the page sizes differ between devices. See the reference manual or
+the FLASH programming manual for details.
+
+@param[in] uint32_t page_address. Full address of flash page to be erased.
+*/
+
+void flash_erase_page(uint32_t page_address)
+{
+ flash_wait_for_last_operation();
+
+ if ((MEMORY_SIZE_REG > 512) && (page_address >= FLASH_BASE+0x00080000)) {
+ FLASH_CR2 |= FLASH_CR_PER;
+ FLASH_AR2 = page_address;
+ FLASH_CR2 |= FLASH_CR_STRT;
+ } else {
+ FLASH_CR |= FLASH_CR_PER;
+ FLASH_AR = page_address;
+ FLASH_CR |= FLASH_CR_STRT;
+ }
+
+ flash_wait_for_last_operation();
+
+ if ((MEMORY_SIZE_REG > 512) && (page_address >= FLASH_BASE+0x00080000))
+ FLASH_CR2 &= ~FLASH_CR_PER;
+ else
+ FLASH_CR &= ~FLASH_CR_PER;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All FLASH
+
+This performs all operations necessary to erase all user pages in the FLASH
+memory. The information block is unaffected.
+*/
+
+void flash_erase_all_pages(void)
+{
+ flash_wait_for_last_operation();
+
+ FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
+ FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
+
+/* Repeat for bank 2 */
+ FLASH_CR2 |= FLASH_CR_MER;
+ FLASH_CR2 |= FLASH_CR_STRT;
+
+ flash_wait_for_last_operation();
+ FLASH_CR2 &= ~FLASH_CR_MER;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/gpio.c b/libopencm3/lib/stm32/f1/gpio.c
new file mode 100644
index 0000000..76cbd5b
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/gpio.c
@@ -0,0 +1,194 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+@date 18 August 2012
+
+Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
+functionality with a number of alternate functions and must be configured to
+the alternate function mode if these are to be accessed. A feature is available
+to remap alternative functions to a limited set of alternative pins in the
+event of a clash of requirements.
+
+The data registers associated with each port for input and output are 32 bit
+with the upper 16 bits unused. The output buffer must be written as a 32 bit
+word, but individual bits may be set or reset separately in atomic operations
+to avoid race conditions during interrupts. Bits may also be individually
+locked to prevent accidental configuration changes. Once locked the
+configuration cannot be changed until after the next reset.
+
+Each port bit can be configured as analog or digital input, the latter can be
+floating or pulled up or down. As outputs they can be configured as either
+push-pull or open drain, digital I/O or alternate function, and with maximum
+output speeds of 2MHz, 10MHz, or 50MHz.
+
+On reset all ports are configured as digital floating input.
+
+@section gpio_api_ex Basic GPIO Handling API.
+
+Example 1: Push-pull digital output actions on ports C2 and C9
+
+@code
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2 | GPIO9);
+ gpio_set(GPIOC, GPIO2 | GPIO9);
+ gpio_clear(GPIOC, GPIO2);
+ gpio_toggle(GPIOC, GPIO2 | GPIO9);
+ gpio_port_write(GPIOC, 0x204);
+@endcode
+
+Example 1: Digital input on port C12
+
+@code
+ gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT, GPIO12);
+ reg16 = gpio_port_read(GPIOC);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/gpio.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Pin Mode
+
+Sets the mode (input/output) and configuration (analog/digitial and
+open drain/push pull), for a set of GPIO pins on a given GPIO port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
+@param[in] cnf Unsigned int8. Pin configuration @ref gpio_cnf
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use logical OR '|' to separate
+ them.
+*/
+
+void gpio_set_mode(uint32_t gpioport, uint8_t mode, uint8_t cnf, uint16_t gpios)
+{
+ uint16_t i, offset = 0;
+ uint32_t crl = 0, crh = 0, tmp32 = 0;
+
+ /*
+ * We want to set the config only for the pins mentioned in gpios,
+ * but keeping the others, so read out the actual config first.
+ */
+ crl = GPIO_CRL(gpioport);
+ crh = GPIO_CRH(gpioport);
+
+ /* Iterate over all bits, use i as the bitnumber. */
+ for (i = 0; i < 16; i++) {
+ /* Only set the config if the bit is set in gpios. */
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+
+ /* Calculate bit offset. */
+ offset = (i < 8) ? (i * 4) : ((i - 8) * 4);
+
+ /* Use tmp32 to either modify crl or crh. */
+ tmp32 = (i < 8) ? crl : crh;
+
+ /* Modify bits are needed. */
+ tmp32 &= ~(0xf << offset); /* Clear the bits first. */
+ tmp32 |= (mode << offset) | (cnf << (offset + 2));
+
+ /* Write tmp32 into crl or crh, leave the other unchanged. */
+ crl = (i < 8) ? tmp32 : crl;
+ crh = (i >= 8) ? tmp32 : crh;
+ }
+
+ GPIO_CRL(gpioport) = crl;
+ GPIO_CRH(gpioport) = crh;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Map the EVENTOUT signal
+
+Enable the EVENTOUT signal and select the port and pin to be used.
+
+@param[in] evoutport Unsigned int8. Port for EVENTOUT signal @ref afio_evcr_port
+@param[in] evoutpin Unsigned int8. Pin for EVENTOUT signal @ref afio_evcr_pin
+*/
+void gpio_set_eventout(uint8_t evoutport, uint8_t evoutpin)
+{
+ AFIO_EVCR = AFIO_EVCR_EVOE | evoutport | evoutpin;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Map Alternate Function Port Bits (Main Set)
+
+A number of alternate function ports can be remapped to defined alternative
+port bits to avoid clashes in cases where multiple alternate functions are
+present. Refer to the datasheets for the particular mapping desired. This
+provides the main set of remap functionality. See @ref gpio_secondary_remap for
+a number of lesser used remaps.
+
+The AFIO remapping feature is used only with the STM32F10x series.
+
+@note The Serial Wire JTAG disable controls allow certain GPIO ports to become
+available in place of some of the SWJ signals. Full SWJ capability is obtained
+by setting this to zero. The value of this must be specified for every call to
+this function as its current value cannot be ascertained from the hardware.
+
+@param[in] swjdisable Unsigned int8. Disable parts of the SWJ capability @ref
+afio_swj_disable.
+@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref
+afio_remap, @ref afio_remap_can1, @ref afio_remap_tim3, @ref afio_remap_tim2,
+@ref afio_remap_tim1, @ref afio_remap_usart3. For connectivity line devices
+only @ref afio_remap_cld are also available.
+*/
+void gpio_primary_remap(uint32_t swjdisable, uint32_t maps)
+{
+ AFIO_MAPR |= (swjdisable & AFIO_MAPR_SWJ_MASK) | (maps & 0x1FFFFF);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Map Alternate Function Port Bits (Secondary Set)
+
+A number of alternate function ports can be remapped to defined alternative
+port bits to avoid clashes in cases where multiple alternate functions are
+present. Refer to the datasheets for the particular mapping desired. This
+provides the second smaller and less used set of remap functionality. See @ref
+gpio_primary_remap for the main set of remaps.
+
+The AFIO remapping feature is used only with the STM32F10x series.
+
+@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref
+afio_remap2
+*/
+void gpio_secondary_remap(uint32_t maps)
+{
+ AFIO_MAPR2 |= maps;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/i2c.c b/libopencm3/lib/stm32/f1/i2c.c
new file mode 100644
index 0000000..d961736
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/i2c.c
@@ -0,0 +1,31 @@
+/** @defgroup i2c_file I2C
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx I2C</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
diff --git a/libopencm3/lib/stm32/f1/iwdg.c b/libopencm3/lib/stm32/f1/iwdg.c
new file mode 100644
index 0000000..2d9bc3c
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Independent Watchdog Timer</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld b/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/libopencm3_stm32f1.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/f1/pwr.c b/libopencm3/lib/stm32/f1/pwr.c
new file mode 100644
index 0000000..167f920
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/pwr.c
@@ -0,0 +1,43 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32F1xx
+ *
+ * @brief <b>libopencm3 STM32F1xx Power Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2012
+ * Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * @date 18 August 2012
+ *
+ * This library supports the power control system for the
+ * STM32F1 series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/pwr.h>
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/rcc.c b/libopencm3/lib/stm32/f1/rcc.c
new file mode 100644
index 0000000..c69ba15
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/rcc.c
@@ -0,0 +1,1106 @@
+/** @defgroup STM32F1xx-rcc-file RCC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Reset and Clock Control</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Federico Ruiz-Ugalde \<memeruiz at gmail dot com\>
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+@date 18 August 2012
+
+This library supports the Reset and Clock Control System in the STM32F1xx
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+@note Full support for connection line devices is not yet provided.
+
+Clock settings and resets for many peripherals are given here rather than in
+the corresponding peripheral library.
+
+The library also provides a number of common configurations for the processor
+system clock. Not all possible configurations are included.
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+
+/** Default ppre1 peripheral clock frequency after reset. */
+uint32_t rcc_ppre1_frequency = 8000000;
+/** Default ppre2 peripheral clock frequency after reset. */
+uint32_t rcc_ppre2_frequency = 8000000;
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Clear the Oscillator Ready Interrupt Flag
+
+Clear the interrupt flag that was set when a clock oscillator became ready to
+use.
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_osc_ready_int_clear(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case PLL2:
+ RCC_CIR |= RCC_CIR_PLL2RDYC;
+ break;
+ case PLL3:
+ RCC_CIR |= RCC_CIR_PLL3RDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable the Oscillator Ready Interrupt
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_osc_ready_int_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case PLL2:
+ RCC_CIR |= RCC_CIR_PLL2RDYIE;
+ break;
+ case PLL3:
+ RCC_CIR |= RCC_CIR_PLL3RDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable the Oscillator Ready Interrupt
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_osc_ready_int_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYIE;
+ break;
+ case PLL2:
+ RCC_CIR &= ~RCC_CIR_PLL2RDYIE;
+ break;
+ case PLL3:
+ RCC_CIR &= ~RCC_CIR_PLL3RDYIE;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Read the Oscillator Ready Interrupt Flag
+
+@param[in] osc enum ::osc_t. Oscillator ID
+@returns int. Boolean value for flag set.
+*/
+
+int rcc_osc_ready_int_flag(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case PLL2:
+ return ((RCC_CIR & RCC_CIR_PLL2RDYF) != 0);
+ break;
+ case PLL3:
+ return ((RCC_CIR & RCC_CIR_PLL3RDYF) != 0);
+ break;
+ case HSE:
+ return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case HSI:
+ return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case LSE:
+ return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ }
+
+ cm3_assert_not_reached();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Clear the Clock Security System Interrupt Flag
+
+*/
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Read the Clock Security System Interrupt Flag
+
+@returns int. Boolean value for flag set.
+*/
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Wait for Oscillator Ready.
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_wait_for_osc_ready(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) == 0);
+ break;
+ case PLL2:
+ while ((RCC_CR & RCC_CR_PLL2RDY) == 0);
+ break;
+ case PLL3:
+ while ((RCC_CR & RCC_CR_PLL3RDY) == 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) == 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) == 0);
+ break;
+ case LSE:
+ while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Turn on an Oscillator.
+
+Enable an oscillator and power on. Each oscillator requires an amount of time
+to settle to a usable state. Refer to datasheets for time delay information. A
+status flag is available to indicate when the oscillator becomes ready (see
+@ref rcc_osc_ready_int_flag and @ref rcc_wait_for_osc_ready).
+
+@note The LSE clock is in the backup domain and cannot be enabled until the
+backup domain write protection has been removed (see @ref
+pwr_disable_backup_domain_write_protect).
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_osc_on(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ case PLL2:
+ RCC_CR |= RCC_CR_PLL2ON;
+ break;
+ case PLL3:
+ RCC_CR |= RCC_CR_PLL3ON;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Turn off an Oscillator.
+
+Disable an oscillator and power off.
+
+@note An oscillator cannot be turned off if it is selected as the system clock.
+@note The LSE clock is in the backup domain and cannot be disabled until the
+backup domain write protection has been removed (see
+@ref pwr_disable_backup_domain_write_protect) or the backup domain has been
+(see reset @ref rcc_backupdomain_reset).
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
+void rcc_osc_off(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR &= ~RCC_CR_PLLON;
+ break;
+ case PLL2:
+ RCC_CR &= ~RCC_CR_PLL2ON;
+ break;
+ case PLL3:
+ RCC_CR &= ~RCC_CR_PLL3ON;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable the Clock Security System.
+
+*/
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable the Clock Security System.
+
+*/
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable Bypass.
+
+Enable an external clock to bypass the internal clock (high speed and low speed
+clocks only). The external clock must be enabled (see @ref rcc_osc_on) and the
+internal clock must be disabled (see @ref rcc_osc_off) for this to have effect.
+
+@note The LSE clock is in the backup domain and cannot be bypassed until the
+backup domain write protection has been removed (see @ref
+pwr_disable_backup_domain_write_protect).
+
+@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+*/
+
+void rcc_osc_bypass_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case PLL2:
+ case PLL3:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable Bypass.
+
+Re-enable the internal clock (high speed and low speed clocks only). The
+internal clock must be disabled (see @ref rcc_osc_off) for this to have effect.
+
+@note The LSE clock is in the backup domain and cannot have bypass removed
+until the backup domain write protection has been removed (see @ref
+pwr_disable_backup_domain_write_protect) or the backup domain has been reset
+(see @ref rcc_backupdomain_reset).
+
+@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+*/
+
+void rcc_osc_bypass_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case PLL2:
+ case PLL3:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the Source for the System Clock.
+
+@param[in] clk Unsigned int32. System Clock Selection @ref rcc_cfgr_scs
+*/
+
+void rcc_set_sysclk_source(uint32_t clk)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) |
+ (clk << RCC_CFGR_SW_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
+void rcc_set_pll_multiplication_factor(uint32_t mul)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLMUL) |
+ (mul << RCC_CFGR_PLLMUL_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL2 Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
+void rcc_set_pll2_multiplication_factor(uint32_t mul)
+{
+ RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PLL2MUL) |
+ (mul << RCC_CFGR2_PLL2MUL_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL3 Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
+void rcc_set_pll3_multiplication_factor(uint32_t mul)
+{
+ RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PLL3MUL) |
+ (mul << RCC_CFGR2_PLL3MUL_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL Clock Source.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] pllsrc Unsigned int32. PLL clock source @ref rcc_cfgr_pcs
+*/
+
+void rcc_set_pll_source(uint32_t pllsrc)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLSRC) |
+ (pllsrc << 16);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the HSE Frequency Divider used as PLL Clock Source.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] pllxtpre Unsigned int32. HSE division factor @ref rcc_cfgr_hsepre
+*/
+
+void rcc_set_pllxtpre(uint32_t pllxtpre)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLXTPRE) |
+ (pllxtpre << 17);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Setup the A/D Clock
+
+The ADC's have a common clock prescale setting.
+
+@param[in] adcpre uint32_t. Prescale divider taken from @ref rcc_cfgr_adcpre
+*/
+
+void rcc_set_adcpre(uint32_t adcpre)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_ADCPRE) |
+ (adcpre << RCC_CFGR_ADCPRE_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the APB2 Prescale Factor.
+
+@param[in] ppre2 Unsigned int32. APB2 prescale factor @ref rcc_cfgr_apb2pre
+*/
+
+void rcc_set_ppre2(uint32_t ppre2)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE2) |
+ (ppre2 << RCC_CFGR_PPRE2_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the APB1 Prescale Factor.
+
+@note The APB1 clock frequency must not exceed 36MHz.
+
+@param[in] ppre1 Unsigned int32. APB1 prescale factor @ref rcc_cfgr_apb1pre
+*/
+
+void rcc_set_ppre1(uint32_t ppre1)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE1) |
+ (ppre1 << RCC_CFGR_PPRE1_SHIFT);
+
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the AHB Prescale Factor.
+
+@param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
+*/
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) |
+ (hpre << RCC_CFGR_HPRE_SHIFT);
+
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set the USB Prescale Factor.
+
+The prescale factor can be set to 1 (no prescale) for use when the PLL clock is
+48MHz, or 1.5 to generate the 48MHz USB clock from a 64MHz PLL clock.
+
+@note This bit cannot be reset while the USB clock is enabled.
+
+@param[in] usbpre Unsigned int32. USB prescale factor @ref rcc_cfgr_usbpre
+*/
+
+void rcc_set_usbpre(uint32_t usbpre)
+{
+ if (usbpre)
+ RCC_CFGR |= RCC_CFGR_USBPRE;
+ else
+ RCC_CFGR &= ~RCC_CFGR_USBPRE;
+}
+
+void rcc_set_prediv1(uint32_t prediv)
+{
+ RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV1) |
+ (prediv << RCC_CFGR2_PREDIV1_SHIFT);
+}
+
+void rcc_set_prediv2(uint32_t prediv)
+{
+ RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV2) |
+ (prediv << RCC_CFGR2_PREDIV2_SHIFT);
+}
+
+void rcc_set_prediv1_source(uint32_t rccsrc)
+{
+ if (rccsrc)
+ RCC_CFGR2 |= RCC_CFGR2_PREDIV1SRC;
+ else
+ RCC_CFGR2 &= ~RCC_CFGR2_PREDIV1SRC;
+}
+
+void rcc_set_mco(uint32_t mcosrc)
+{
+ RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_MCO) |
+ (mcosrc << RCC_CFGR_MCO_SHIFT);
+
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Get the System Clock Source.
+
+@returns Unsigned int32. System clock source:
+@li 00 indicates HSE
+@li 01 indicates LSE
+@li 02 indicates PLL
+*/
+
+uint32_t rcc_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ return (RCC_CFGR & RCC_CFGR_SWS) >> RCC_CFGR_SWS_SHIFT;
+}
+
+/*---------------------------------------------------------------------------*/
+/*
+ * These functions are setting up the whole clock system for the most common
+ * input clock and output clock configurations.
+ */
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 64MHz from HSI
+
+*/
+
+void rcc_clock_setup_in_hsi_out_64mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 64MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /* Set. 8MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 32MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 64MHz Max. 72MHz */
+
+ /*
+ * Sysclk is running with 64MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_2WS);
+
+ /*
+ * Set the PLL multiplication factor to 16.
+ * 8MHz (internal) * 16 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 64MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL16);
+
+ /* Select HSI/2 as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 32000000;
+ rcc_ppre2_frequency = 64000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 48MHz from HSI
+
+*/
+
+void rcc_clock_setup_in_hsi_out_48mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /*Set.48MHz Max.72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /*Set. 6MHz Max.14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /*Set.24MHz Max.36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /*Set.48MHz Max.72MHz */
+ rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_CLK_NODIV); /*Set.48MHz Max.48MHz */
+
+ /*
+ * Sysclk runs with 48MHz -> 1 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_1WS);
+
+ /*
+ * Set the PLL multiplication factor to 12.
+ * 8MHz (internal) * 12 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 48MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL12);
+
+ /* Select HSI/2 as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 24000000;
+ rcc_ppre2_frequency = 48000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSI
+
+*/
+
+void rcc_clock_setup_in_hsi_out_24mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 12MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+
+ /*
+ * Sysclk is (will be) running with 24MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_0WS);
+
+ /*
+ * Set the PLL multiplication factor to 6.
+ * 8MHz (internal) * 6 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 24MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6);
+
+ /* Select HSI/2 as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 24000000;
+ rcc_ppre2_frequency = 24000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 8MHz
+
+*/
+
+void rcc_clock_setup_in_hse_8mhz_out_24mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /* Enable external high-speed oscillator 8MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 72MHz */
+
+ /*
+ * Sysclk runs with 24MHz -> 0 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_0WS);
+
+ /*
+ * Set the PLL multiplication factor to 3.
+ * 8MHz (external) * 3 (multiplier) = 24MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL3);
+
+ /* Select HSE as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
+
+ /*
+ * External frequency undivided before entering PLL
+ * (only valid/needed for HSE).
+ */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 24000000;
+ rcc_ppre2_frequency = 24000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 72MHz from HSE at 8MHz
+
+*/
+
+void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /* Enable external high-speed oscillator 8MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /* Set. 9MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+
+ /*
+ * Sysclk runs with 72MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_2WS);
+
+ /*
+ * Set the PLL multiplication factor to 9.
+ * 8MHz (external) * 9 (multiplier) = 72MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9);
+
+ /* Select HSE as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
+
+ /*
+ * External frequency undivided before entering PLL
+ * (only valid/needed for HSE).
+ */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 36000000;
+ rcc_ppre2_frequency = 72000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 12MHz
+
+*/
+
+void rcc_clock_setup_in_hse_12mhz_out_72mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /* Enable external high-speed oscillator 16MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+
+ /*
+ * Sysclk runs with 72MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_2WS);
+
+ /*
+ * Set the PLL multiplication factor to 9.
+ * 12MHz (external) * 6 (multiplier) / 1 (PLLXTPRE_HSE_CLK) = 72MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6);
+
+ /* Select HSI as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
+
+ /*
+ * Divide external frequency by 2 before entering PLL
+ * (only valid/needed for HSE).
+ */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 36000000;
+ rcc_ppre2_frequency = 72000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 16MHz
+
+*/
+
+void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /* Enable external high-speed oscillator 16MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+
+ /*
+ * Sysclk runs with 72MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_2WS);
+
+ /*
+ * Set the PLL multiplication factor to 9.
+ * 16MHz (external) * 9 (multiplier) / 2 (PLLXTPRE_HSE_CLK_DIV2) = 72MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9);
+
+ /* Select HSI as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
+
+ /*
+ * Divide external frequency by 2 before entering PLL
+ * (only valid/needed for HSE).
+ */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK_DIV2);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 36000000;
+ rcc_ppre2_frequency = 72000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 72MHz from HSE at 25MHz
+
+*/
+
+void rcc_clock_setup_in_hse_25mhz_out_72mhz(void)
+{
+ /* Enable external high-speed oscillator 25MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
+
+ /*
+ * Sysclk runs with 72MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_ACR_LATENCY_2WS);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV6); /* Set. 12MHz Max. 14MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /* Set. 36MHz Max. 36MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 72MHz Max. 72MHz */
+
+ /* Set pll2 prediv and multiplier */
+ rcc_set_prediv2(RCC_CFGR2_PREDIV2_DIV5);
+ rcc_set_pll2_multiplication_factor(RCC_CFGR2_PLL2MUL_PLL2_CLK_MUL8);
+
+ /* Enable PLL2 oscillator and wait for it to stabilize */
+ rcc_osc_on(PLL2);
+ rcc_wait_for_osc_ready(PLL2);
+
+ /* Set pll1 prediv/multiplier, prediv1 src, and usb predivider */
+ rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
+ rcc_set_prediv1_source(RCC_CFGR2_PREDIV1SRC_PLL2_CLK);
+ rcc_set_prediv1(RCC_CFGR2_PREDIV_DIV5);
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9);
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_PREDIV1_CLK);
+ rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3);
+
+ /* enable PLL1 and wait for it to stabilize */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 36000000;
+ rcc_ppre2_frequency = 72000000;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Reset the backup domain
+
+The backup domain register is reset to disable all controls.
+*/
+
+void rcc_backupdomain_reset(void)
+{
+ /* Set the backup domain software reset. */
+ RCC_BDCR |= RCC_BDCR_BDRST;
+
+ /* Clear the backup domain software reset. */
+ RCC_BDCR &= ~RCC_BDCR_BDRST;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/rtc.c b/libopencm3/lib/stm32/f1/rtc.c
new file mode 100644
index 0000000..b2d7b83
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/rtc.c
@@ -0,0 +1,305 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32F1xx
+ *
+ * @brief <b>libopencm3 STM32F1xx RTC</b>
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ * @author @htmlonly &copy; @endhtmlonly 2010 Lord James <lordjames@y7mail.com>
+ *
+ * @version 1.0.0
+ *
+ * @date 4 March 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Lord James <lordjames@y7mail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**@{*/
+
+
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/rtc.h>
+#include <libopencm3/stm32/pwr.h>
+
+void rtc_awake_from_off(enum rcc_osc clock_source)
+{
+ uint32_t reg32;
+
+ /* Enable power and backup interface clocks. */
+ RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
+
+ /* Enable access to the backup registers and the RTC. */
+ PWR_CR |= PWR_CR_DBP;
+
+ /*
+ * Reset the backup domain, clears everything RTC related.
+ * If not wanted use the rtc_awake_from_standby() function.
+ */
+ rcc_backupdomain_reset();
+
+ switch (clock_source) {
+ case LSE:
+ /* Turn the LSE on and wait while it stabilises. */
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ while ((reg32 = (RCC_BDCR & RCC_BDCR_LSERDY)) == 0);
+
+ /* Choose LSE as the RTC clock source. */
+ RCC_BDCR &= ~((1 << 8) | (1 << 9));
+ RCC_BDCR |= (1 << 8);
+ break;
+ case LSI:
+ /* Turn the LSI on and wait while it stabilises. */
+ RCC_CSR |= RCC_CSR_LSION;
+ while ((reg32 = (RCC_CSR & RCC_CSR_LSIRDY)) == 0);
+
+ /* Choose LSI as the RTC clock source. */
+ RCC_BDCR &= ~((1 << 8) | (1 << 9));
+ RCC_BDCR |= (1 << 9);
+ break;
+ case HSE:
+ /* Turn the HSE on and wait while it stabilises. */
+ RCC_CR |= RCC_CR_HSEON;
+ while ((reg32 = (RCC_CR & RCC_CR_HSERDY)) == 0);
+
+ /* Choose HSE as the RTC clock source. */
+ RCC_BDCR &= ~((1 << 8) | (1 << 9));
+ RCC_BDCR |= (1 << 9) | (1 << 8);
+ break;
+ case PLL:
+ case PLL2:
+ case PLL3:
+ case HSI:
+ /* Unusable clock source, here to prevent warnings. */
+ /* Turn off clock sources to RTC. */
+ RCC_BDCR &= ~((1 << 8) | (1 << 9));
+ break;
+ }
+
+ /* Enable the RTC. */
+ RCC_BDCR |= RCC_BDCR_RTCEN;
+
+ /* Wait for the RSF bit in RTC_CRL to be set by hardware. */
+ RTC_CRL &= ~RTC_CRL_RSF;
+ while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0);
+
+ /* Wait for the last write operation to finish. */
+ /* TODO: Necessary? */
+ while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
+}
+
+void rtc_enter_config_mode(void)
+{
+ uint32_t reg32;
+
+ /* Wait until the RTOFF bit is 1 (no RTC register writes ongoing). */
+ while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
+
+ /* Enter configuration mode. */
+ RTC_CRL |= RTC_CRL_CNF;
+}
+
+void rtc_exit_config_mode(void)
+{
+ uint32_t reg32;
+
+ /* Exit configuration mode. */
+ RTC_CRL &= ~RTC_CRL_CNF;
+
+ /* Wait until the RTOFF bit is 1 (our RTC register write finished). */
+ while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
+}
+
+void rtc_set_alarm_time(uint32_t alarm_time)
+{
+ rtc_enter_config_mode();
+ RTC_ALRL = (alarm_time & 0x0000ffff);
+ RTC_ALRH = (alarm_time & 0xffff0000) >> 16;
+ rtc_exit_config_mode();
+}
+
+void rtc_enable_alarm(void)
+{
+ rtc_enter_config_mode();
+ RTC_CRH |= RTC_CRH_ALRIE;
+ rtc_exit_config_mode();
+}
+
+void rtc_disable_alarm(void)
+{
+ rtc_enter_config_mode();
+ RTC_CRH &= ~RTC_CRH_ALRIE;
+ rtc_exit_config_mode();
+}
+
+void rtc_set_prescale_val(uint32_t prescale_val)
+{
+ rtc_enter_config_mode();
+ RTC_PRLL = prescale_val & 0x0000ffff; /* PRL[15:0] */
+ RTC_PRLH = (prescale_val & 0x000f0000) >> 16; /* PRL[19:16] */
+ rtc_exit_config_mode();
+}
+
+uint32_t rtc_get_counter_val(void)
+{
+ return (RTC_CNTH << 16) | RTC_CNTL;
+}
+
+uint32_t rtc_get_prescale_div_val(void)
+{
+ return (RTC_DIVH << 16) | RTC_DIVL;
+}
+
+uint32_t rtc_get_alarm_val(void)
+{
+ return (RTC_ALRH << 16) | RTC_ALRL;
+}
+
+void rtc_set_counter_val(uint32_t counter_val)
+{
+ rtc_enter_config_mode();
+ RTC_CNTH = (counter_val & 0xffff0000) >> 16; /* CNT[31:16] */
+ RTC_CNTL = counter_val & 0x0000ffff; /* CNT[15:0] */
+ rtc_exit_config_mode();
+}
+
+void rtc_interrupt_enable(rtcflag_t flag_val)
+{
+ rtc_enter_config_mode();
+
+ /* Set the correct interrupt enable. */
+ switch (flag_val) {
+ case RTC_SEC:
+ RTC_CRH |= RTC_CRH_SECIE;
+ break;
+ case RTC_ALR:
+ RTC_CRH |= RTC_CRH_ALRIE;
+ break;
+ case RTC_OW:
+ RTC_CRH |= RTC_CRH_OWIE;
+ break;
+ }
+
+ rtc_exit_config_mode();
+}
+
+void rtc_interrupt_disable(rtcflag_t flag_val)
+{
+ rtc_enter_config_mode();
+
+ /* Disable the correct interrupt enable. */
+ switch (flag_val) {
+ case RTC_SEC:
+ RTC_CRH &= ~RTC_CRH_SECIE;
+ break;
+ case RTC_ALR:
+ RTC_CRH &= ~RTC_CRH_ALRIE;
+ break;
+ case RTC_OW:
+ RTC_CRH &= ~RTC_CRH_OWIE;
+ break;
+ }
+
+ rtc_exit_config_mode();
+}
+
+void rtc_clear_flag(rtcflag_t flag_val)
+{
+ /* Configuration mode not needed. */
+
+ /* Clear the correct flag. */
+ switch (flag_val) {
+ case RTC_SEC:
+ RTC_CRL &= ~RTC_CRL_SECF;
+ break;
+ case RTC_ALR:
+ RTC_CRL &= ~RTC_CRL_ALRF;
+ break;
+ case RTC_OW:
+ RTC_CRL &= ~RTC_CRL_OWF;
+ break;
+ }
+}
+
+uint32_t rtc_check_flag(rtcflag_t flag_val)
+{
+ uint32_t reg32;
+
+ /* Read correct flag. */
+ switch (flag_val) {
+ case RTC_SEC:
+ reg32 = RTC_CRL & RTC_CRL_SECF;
+ break;
+ case RTC_ALR:
+ reg32 = RTC_CRL & RTC_CRL_ALRF;
+ break;
+ case RTC_OW:
+ reg32 = RTC_CRL & RTC_CRL_OWF;
+ break;
+ default:
+ reg32 = 0;
+ break;
+ }
+
+ return reg32;
+}
+
+void rtc_awake_from_standby(void)
+{
+ uint32_t reg32;
+
+ /* Enable power and backup interface clocks. */
+ RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
+
+ /* Enable access to the backup registers and the RTC. */
+ PWR_CR |= PWR_CR_DBP;
+
+ /* Wait for the RSF bit in RTC_CRL to be set by hardware. */
+ RTC_CRL &= ~RTC_CRL_RSF;
+ while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0);
+
+ /* Wait for the last write operation to finish. */
+ /* TODO: Necessary? */
+ while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
+}
+
+void rtc_auto_awake(enum rcc_osc clock_source, uint32_t prescale_val)
+{
+ uint32_t reg32;
+
+ /* Enable power and backup interface clocks. */
+ RCC_APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN);
+
+ /* Enable access to the backup registers and the RTC. */
+ /* TODO: Not sure if this is necessary to just read the flag. */
+ PWR_CR |= PWR_CR_DBP;
+
+ reg32 = RCC_BDCR & RCC_BDCR_RTCEN;
+
+ if (reg32 != 0) {
+ rtc_awake_from_standby();
+ } else {
+ rtc_awake_from_off(clock_source);
+ rtc_set_prescale_val(prescale_val);
+ }
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f1/spi.c b/libopencm3/lib/stm32/f1/spi.c
new file mode 100644
index 0000000..757f2ae
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx SPI</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/f1/stm32f100x4.ld b/libopencm3/lib/stm32/f1/stm32f100x4.ld
new file mode 100644
index 0000000..4c86aee
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100x4.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100x6.ld b/libopencm3/lib/stm32/f1/stm32f100x6.ld
new file mode 100644
index 0000000..23f77f3
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100x6.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100x6, 32K flash, 4K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100x8.ld b/libopencm3/lib/stm32/f1/stm32f100x8.ld
new file mode 100644
index 0000000..e0aa041
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100x8.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100x8, 64K flash, 8K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100xb.ld b/libopencm3/lib/stm32/f1/stm32f100xb.ld
new file mode 100644
index 0000000..83d64fd
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100xb.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100xB, 128K flash, 8K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100xc.ld b/libopencm3/lib/stm32/f1/stm32f100xc.ld
new file mode 100644
index 0000000..30a894a
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100xc.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100xC, 256K flash, 24K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 24K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100xd.ld b/libopencm3/lib/stm32/f1/stm32f100xd.ld
new file mode 100644
index 0000000..b507435
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100xd.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100xD, 384K flash, 32K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/stm32f100xe.ld b/libopencm3/lib/stm32/f1/stm32f100xe.ld
new file mode 100644
index 0000000..a12d1ff
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/stm32f100xe.ld
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32F100xE, 512K flash, 32K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/libopencm3/lib/stm32/f1/timer.c b/libopencm3/lib/stm32/f1/timer.c
new file mode 100644
index 0000000..fd46742
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/timer.c
@@ -0,0 +1,57 @@
+/* This file is used for documentation purposes. It does not need
+to be compiled. All source code is in the common area.
+If there is any device specific code required it can be included here,
+in which case this file must be added to the compile list. */
+
+/** @defgroup timer_file Timers
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Timers</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/timer.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Polarity
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] pol ::tim_ic_pol. Input Capture polarity.
+*/
+
+void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_pol pol)
+{
+ if (pol) {
+ TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
+ } else {
+ TIM_CCER(timer_peripheral) &= ~(0x2 << (ic * 4));
+ }
+}
+
diff --git a/libopencm3/lib/stm32/f1/usart.c b/libopencm3/lib/stm32/f1/usart.c
new file mode 100644
index 0000000..84ae505
--- /dev/null
+++ b/libopencm3/lib/stm32/f1/usart.c
@@ -0,0 +1,31 @@
+/** @defgroup usart_file USART
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx USART</b>
+
+@version 1.0.0
+
+@date 30 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
diff --git a/libopencm3/lib/stm32/f2/Makefile b/libopencm3/lib/stm32/f2/Makefile
new file mode 100644
index 0000000..9291668
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/Makefile
@@ -0,0 +1,52 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32f2
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32F2
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+
+OBJS = gpio.o rcc.o
+
+OBJS += crc_common_all.o dac_common_all.o dma_common_f24.o \
+ gpio_common_all.o gpio_common_f0234.o i2c_common_all.o \
+ iwdg_common_all.o rtc_common_l1f024.o spi_common_all.o \
+ spi_common_l1f124.o timer_common_all.o timer_common_f234.o \
+ timer_common_f24.o usart_common_all.o usart_common_f124.o \
+ flash_common_f234.o flash_common_f24.o hash_common_f24.o \
+ crypto_common_f24.o exti_common_all.o rcc_common_all.o
+
+OBJS += usb.o usb_standard.o usb_control.o usb_fx07_common.o \
+ usb_f107.o usb_f207.o usb_msc.o
+
+VPATH += ../../usb:../:../../cm3:../common
+
+include ../../Makefile.include
diff --git a/libopencm3/lib/stm32/f2/crc.c b/libopencm3/lib/stm32/f2/crc.c
new file mode 100644
index 0000000..c5ae5d3
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/crc.c
@@ -0,0 +1,33 @@
+/** @defgroup crc_file CRC
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx CRC</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
+
+
diff --git a/libopencm3/lib/stm32/f2/crypto.c b/libopencm3/lib/stm32/f2/crypto.c
new file mode 100644
index 0000000..e44fb63
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/crypto.c
@@ -0,0 +1,31 @@
+/** @defgroup crypto_file CRYPTO
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx Cryptographic controller</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 14 January 2014
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crypto.h>
diff --git a/libopencm3/lib/stm32/f2/dac.c b/libopencm3/lib/stm32/f2/dac.c
new file mode 100644
index 0000000..635e142
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx DAC</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/f2/dma.c b/libopencm3/lib/stm32/f2/dma.c
new file mode 100644
index 0000000..285f1fe
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx DMA</b>
+
+@version 1.0.0
+
+@date 30 November 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/f2/flash.c b/libopencm3/lib/stm32/f2/flash.c
new file mode 100644
index 0000000..7f8255d
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/flash.c
@@ -0,0 +1,53 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx FLASH</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * @date 14 January 2014
+ *
+ * This library supports the FLASH memory controller in the STM32F2
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * For the STM32F2xx, accessing FLASH memory is described briefly in
+ * section 2.3.3 of the STM32F2xx Reference Manual.
+ * For detailed programming information see:
+ * PM0059 programming manual: STM32F10xxx Flash programming
+ * June 2013, Doc ID DocID15687 Rev 5
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f2/gpio.c b/libopencm3/lib/stm32/f2/gpio.c
new file mode 100644
index 0000000..052e306
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/gpio.c
@@ -0,0 +1,31 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/gpio.h>
diff --git a/libopencm3/lib/stm32/f2/hash.c b/libopencm3/lib/stm32/f2/hash.c
new file mode 100644
index 0000000..ca48d8b
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/hash.c
@@ -0,0 +1,31 @@
+/** @defgroup hash_file HASH
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx Hash Processor</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 14 January 2014
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/hash.h>
diff --git a/libopencm3/lib/stm32/f2/i2c.c b/libopencm3/lib/stm32/f2/i2c.c
new file mode 100644
index 0000000..ea0c99d
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/i2c.c
@@ -0,0 +1,33 @@
+/** @defgroup i2c_file I2C
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx I2C</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 15 October 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/common/i2c_common_all.h>
+
diff --git a/libopencm3/lib/stm32/f2/iwdg.c b/libopencm3/lib/stm32/f2/iwdg.c
new file mode 100644
index 0000000..2d9dc4a
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx Independent Watchdog Timer</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld b/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/libopencm3_stm32f2.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/f2/pwr.c b/libopencm3/lib/stm32/f2/pwr.c
new file mode 100644
index 0000000..0e5641e
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/pwr.c
@@ -0,0 +1,39 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx Power Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2014
+ * Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * @date 13 January 2014
+ *
+ * This library supports the power control system for the
+ * STM32F4 series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/pwr.h>
+
diff --git a/libopencm3/lib/stm32/f2/rcc.c b/libopencm3/lib/stm32/f2/rcc.c
new file mode 100644
index 0000000..4b6195b
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/rcc.c
@@ -0,0 +1,417 @@
+/** @defgroup rcc_file RCC
+ *
+ * @ingroup STM32F2xx
+ *
+ * @section rcc_f2_api_ex Reset and Clock Control API.
+ *
+ * @brief <b>libopencm3 STM32F2xx Reset and Clock Control</b>
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran at seznam.cz>
+ *
+ * @date 18 Jun 2013
+ *
+ * This library supports the Reset and Clock Control System in the STM32 series
+ * of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+
+/**@{*/
+
+/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
+uint32_t rcc_ppre1_frequency = 16000000;
+uint32_t rcc_ppre2_frequency = 16000000;
+
+const clock_scale_t hse_8mhz_3v3[CLOCK_3V3_END] = {
+ { /* 120MHz */
+ .pllm = 8,
+ .plln = 240,
+ .pllp = 2,
+ .pllq = 5,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 30000000,
+ .apb2_frequency = 60000000,
+ },
+};
+
+void rcc_osc_ready_int_clear(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_enable(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_disable(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+int rcc_osc_ready_int_flag(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case HSE:
+ return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case HSI:
+ return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case LSE:
+ return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ }
+
+ cm3_assert_not_reached();
+}
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+void rcc_wait_for_osc_ready(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) == 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) == 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) == 0);
+ break;
+ case LSE:
+ while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
+ break;
+ }
+}
+
+void rcc_wait_for_sysclk_status(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL);
+ break;
+ case HSE:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE);
+ break;
+ case HSI:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI);
+ break;
+ default:
+ /* Shouldn't be reached. */
+ break;
+ }
+}
+
+void rcc_osc_on(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_osc_off(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR &= ~RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+void rcc_osc_bypass_enable(osc_t osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_osc_bypass_disable(osc_t osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_set_sysclk_source(uint32_t clk)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 1) | (1 << 0));
+ RCC_CFGR = (reg32 | clk);
+}
+
+void rcc_set_pll_source(uint32_t pllsrc)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_PLLCFGR;
+ reg32 &= ~(1 << 22);
+ RCC_PLLCFGR = (reg32 | (pllsrc << 22));
+}
+
+void rcc_set_ppre2(uint32_t ppre2)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15));
+ RCC_CFGR = (reg32 | (ppre2 << 13));
+}
+
+void rcc_set_ppre1(uint32_t ppre1)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12));
+ RCC_CFGR = (reg32 | (ppre1 << 10));
+}
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
+ RCC_CFGR = (reg32 | (hpre << 4));
+}
+
+void rcc_set_rtcpre(uint32_t rtcpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20));
+ RCC_CFGR = (reg32 | (rtcpre << 16));
+}
+
+void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp,
+ uint32_t pllq)
+{
+ RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
+ (plln << RCC_PLLCFGR_PLLN_SHIFT) |
+ (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
+ (pllq << RCC_PLLCFGR_PLLQ_SHIFT);
+}
+
+void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp,
+ uint32_t pllq)
+{
+ RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
+ (plln << RCC_PLLCFGR_PLLN_SHIFT) |
+ (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
+ RCC_PLLCFGR_PLLSRC |
+ (pllq << RCC_PLLCFGR_PLLQ_SHIFT);
+}
+
+uint32_t rcc_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ return (RCC_CFGR & 0x000c) >> 2;
+}
+
+void rcc_clock_setup_hse_3v3(const clock_scale_t *clock)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_HSI);
+
+ /* Enable external high-speed oscillator 8MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre1(clock->ppre1);
+ rcc_set_ppre2(clock->ppre2);
+
+ rcc_set_main_pll_hse(clock->pllm, clock->plln,
+ clock->pllp, clock->pllq);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
+
+ /* Wait for PLL clock to be selected. */
+ rcc_wait_for_sysclk_status(PLL);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+}
+
+void rcc_backupdomain_reset(void)
+{
+ /* Set the backup domain software reset. */
+ RCC_BDCR |= RCC_BDCR_BDRST;
+
+ /* Clear the backup domain software reset. */
+ RCC_BDCR &= ~RCC_BDCR_BDRST;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f2/rtc.c b/libopencm3/lib/stm32/f2/rtc.c
new file mode 100644
index 0000000..06666ab
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/rtc.c
@@ -0,0 +1,31 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32F2xx
+ *
+ * @brief <b>libopencm3 STM32F2xx RTC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 4 March 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/rtc.h>
diff --git a/libopencm3/lib/stm32/f2/spi.c b/libopencm3/lib/stm32/f2/spi.c
new file mode 100644
index 0000000..8fb70cd
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx SPI</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/f2/timer.c b/libopencm3/lib/stm32/f2/timer.c
new file mode 100644
index 0000000..6600705
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/timer.c
@@ -0,0 +1,38 @@
+/* This file is used for documentation purposes. It does not need
+to be compiled. All source code is in the common area.
+If there is any device specific code required it can be included here,
+in which case this file must be added to the compile list. */
+
+/** @defgroup timer_file Timers
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx Timers</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/timer.h>
diff --git a/libopencm3/lib/stm32/f2/usart.c b/libopencm3/lib/stm32/f2/usart.c
new file mode 100644
index 0000000..f6de5a8
--- /dev/null
+++ b/libopencm3/lib/stm32/f2/usart.c
@@ -0,0 +1,31 @@
+/** @defgroup usart_file USART
+
+@ingroup STM32F2xx
+
+@brief <b>libopencm3 STM32F2xx USART</b>
+
+@version 1.0.0
+
+@date 30 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
diff --git a/libopencm3/lib/stm32/f3/Makefile b/libopencm3/lib/stm32/f3/Makefile
new file mode 100644
index 0000000..5ef282a
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/Makefile
@@ -0,0 +1,50 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32f3
+SRCLIBDIR ?= ../..
+
+FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32F3
+
+ARFLAGS = rcs
+
+OBJS = rcc.o adc.o i2c.o usart.o dma.o flash.o
+
+OBJS += gpio_common_all.o gpio_common_f0234.o \
+ dac_common_all.o usart_common_all.o crc_common_all.o\
+ iwdg_common_all.o spi_common_all.o dma_common_l1f013.o\
+ timer_common_all.o timer_common_f234.o flash_common_f234.o \
+ flash.o exti_common_all.o rcc_common_all.o spi_common_f03.o
+
+OBJS += usb.o usb_control.o usb_standard.o usb_f103.o
+
+VPATH += ../../usb:../:../../cm3:../common
+
+include ../../Makefile.include
diff --git a/libopencm3/lib/stm32/f3/adc.c b/libopencm3/lib/stm32/f3/adc.c
new file mode 100644
index 0000000..805bf2e
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/adc.c
@@ -0,0 +1,1150 @@
+/** @defgroup adc_file ADC
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Analog to Digital Converters</b>
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2012
+ * Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * @date 30 August 2012
+ *
+ * This library supports the A/D Converter Control System in the STM32 series
+ * of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * Devices can have up to three A/D converters each with their own set of
+ * registers. However all the A/D converters share a common clock which is
+ * prescaled from the APB2 clock by default by a minimum factor of 2 to a
+ * maximum of 8. The ADC resolution can be set to 12, 10, 8 or 6 bits.
+ *
+ * Each A/D converter has up to 19 channels:
+ * @li On ADC1 the analog channels 16 is internally connected to the
+ * temperature sensor, channel 17 to V<sub>REFINT</sub>, and channel 18
+ * to V<sub>BATT</sub>.
+ * @li On ADC2 and ADC3 the analog channels 16 - 18 are not used.
+ *
+ * The conversions can occur as a one-off conversion whereby the process stops
+ * once conversion is complete. The conversions can also be continuous wherein
+ * a new conversion starts immediately the previous conversion has ended.
+ *
+ * Conversion can occur as a single channel conversion or a scan of a group of
+ * channels in either continuous or one-off mode. If more than one channel is
+ * converted in a scan group, DMA must be used to transfer the data as there is
+ * only one result register available. An interrupt can be set to occur at the
+ * end*
+ * of conversion, which occurs after all channels have been scanned.
+ *
+ * A discontinuous mode allows a subgroup of group of a channels to be
+ * converted in bursts of a given length.
+ *
+ * Injected conversions allow a second group of channels to be converted
+ * separately from the regular group. An interrupt can be set to occur at the
+ * end of conversion, which occurs after all channels have been scanned.
+ *
+ * @section adc_f3_api_ex Basic ADC Handling API.
+ *
+ * Example 1: Simple single channel conversion polled. Enable the peripheral
+ * clock and ADC, reset ADC and set the prescaler divider. Set multiple mode to
+ * independent.
+ *
+ * @code
+ * gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
+ * rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+ * adc_set_clk_prescale(RCC_CFGR_ADCPRE_BY2);
+ * adc_disable_scan_mode(ADC1);
+ * adc_set_single_conversion_mode(ADC1);
+ * adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
+ * uint8_t channels[] = ADC_CHANNEL0;
+ * adc_set_regular_sequence(ADC1, 1, channels);
+ * adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
+ * adc_power_on(ADC1);
+ * adc_start_conversion_regular(ADC1);
+ * while (! adc_eoc(ADC1));
+ * reg16 = adc_read_regular(ADC1);
+ * @endcode
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/adc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Off
+ *
+ * Turn off the ADC to reduce power consumption to a few microamps.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+*/
+
+void adc_off(uint32_t adc)
+{
+ ADC_CR(adc) &= ~ADC_CR_ADEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Regular Conversions
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Comparison is done before
+ * data alignment takes place, so the thresholds are left-aligned.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_AWD1EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Regular Conversions
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Comparison is done before
+ * data alignment takes place, so the thresholds are left-aligned.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+void adc_disable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_AWD1EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Injected Conversions
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Comparison is done before
+ * data alignment takes place, so the thresholds are left-aligned.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_JAWD1EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog for Injected Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_JAWD1EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Regular Conversions
+ *
+ * In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the
+ * defined regular channel group. The subgroup is defined by the number of
+ * consecutive channels to be converted. After a subgroup has been converted
+ * the next trigger will start conversion of the immediately following subgroup
+ * of the same length or until the whole group has all been converted. When the
+ * whole group has been converted, the next trigger will restart conversion of
+ * the subgroup at the beginning of the whole group.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base @param[in] length Unsigned int8. Number of channels in the
+ * group @ref adc_cr1_discnum
+ */
+
+void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length)
+{
+ if ((length-1) > 7) {
+ return;
+ }
+ ADC_CFGR(adc) |= ADC_CFGR_DISCEN;
+ ADC_CFGR(adc) |= ((length-1) << ADC_CFGR_DISCNUM_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Regular Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_discontinuous_mode_regular(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_DISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Injected Conversions
+ *
+ * In this mode the ADC converts sequentially one channel of the defined group
+ * of injected channels, cycling back to the first channel in the group once
+ * the entire group has been converted.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_JDISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Injected Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_JDISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Automatic Injected Conversions
+ *
+ * The ADC converts a defined injected group of channels immediately after the
+ * regular channels have been converted. The external trigger on the injected
+ * channels is disabled as required.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_automatic_injected_group_conversion(uint32_t adc)
+{
+ adc_disable_external_trigger_injected(adc);
+ ADC_CFGR(adc) |= ADC_CFGR_JAUTO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Automatic Injected Conversions
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_automatic_injected_group_conversion(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_JAUTO;
+}
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Comparison is done before
+ * data alignment takes place, so the thresholds are left-aligned.
+ *
+ * @note The analog watchdog must be enabled for either or both of the regular
+ * or injected channels. If neither are enabled, the analog watchdog feature
+ * will be disabled.
+ *
+ * @ref adc_enable_analog_watchdog_injected, @ref
+ * adc_enable_analog_watchdog_regular.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_AWD1SGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for a Selected Channel
+ *
+ * The analog watchdog allows the monitoring of an analog signal between two
+ * threshold levels. The thresholds must be preset. Comparison is done before
+ * data alignment takes place, so the thresholds are left-aligned.
+ *
+ * @note The analog watchdog must be enabled for either or both of the regular
+ * or injected channels. If neither are enabled, the analog watchdog feature
+ * will be disabled. If both are enabled, the same channel number is monitored
+ * @ref adc_enable_analog_watchdog_injected, @ref
+ * adc_enable_analog_watchdog_regular.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ * @param[in] channel Unsigned int8. ADC channel numbe
+ * @ref adc_watchdog_channel
+ */
+
+void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc,
+ uint8_t channel)
+{
+ uint32_t reg32;
+
+ reg32 = (ADC_CFGR(adc) & ~ADC_CFGR_AWD1CH_MASK); /* Clear bit [4:0]. */
+ if (channel < 18) {
+ reg32 |= channel;
+ }
+ ADC_CFGR(adc) = reg32;
+ ADC_CFGR(adc) |= ADC_CFGR_AWD1SGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Scan Mode
+ *
+ * In this mode a conversion consists of a scan of the predefined set of
+ * channels, regular and injected, each channel conversion immediately
+ * following the previous one. It can use single, continuous or discontinuous
+ * mode.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+/*
+void adc_enable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_SCAN;
+}
+*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Scan Mode
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+/*
+void adc_disable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_SCAN;
+}
+*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Injected End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Injected End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_all_awd_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_AWD1IE;
+ ADC_IER(adc) |= ADC_IER_AWD2IE;
+ ADC_IER(adc) |= ADC_IER_AWD3IE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_all_awd_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_AWD1IE;
+ ADC_IER(adc) &= ~ADC_IER_AWD2IE;
+ ADC_IER(adc) &= ~ADC_IER_AWD3IE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Regular End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_eoc_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_EOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_eoc_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_EOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Regular Channels
+ *
+ * This starts conversion on a set of defined regular channels. It is cleared
+ * by hardware once conversion starts.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_start_conversion_regular(uint32_t adc)
+{
+ /* Start conversion on regular channels. */
+ ADC_CR(adc) |= ADC_CR_ADSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR(adc) & ADC_CR_ADSTART);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Injected Channels
+ *
+ * This starts conversion on a set of defined injected channels. It is cleared
+ * by hardware once conversion starts.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_start_conversion_injected(uint32_t adc)
+{
+ /* Start conversion on injected channels. */
+ ADC_CR(adc) |= ADC_CR_JADSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR(adc) & ADC_CR_JADSTART);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Left Aligned
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_set_left_aligned(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Right Aligned
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_set_right_aligned(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable DMA Transfers
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_enable_dma(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable DMA Transfers
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_disable_dma(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Continuous Conversion Mode
+ *
+ * In this mode the ADC starts a new conversion of a single channel or a channel
+ * group immediately following completion of the previous channel group
+ * conversion.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_set_continuous_conversion_mode(uint32_t adc)
+{
+ ADC_CFGR(adc) |= ADC_CFGR_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Single Conversion Mode
+ *
+ * In this mode the ADC performs a conversion of one channel or a channel group
+ * and stops.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_set_single_conversion_mode(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for a Single Channel
+ *
+ * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] channel Unsigned int8. ADC Channel integer 0..18 or from
+ * @ref adc_channel
+ * @param[in] time Unsigned int8. Sampling time selection from
+ * @ref adc_sample_rg
+ */
+
+void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
+{
+ uint32_t reg32;
+
+ if (channel < 10) {
+ reg32 = ADC_SMPR2(adc);
+ reg32 &= ~(0x7 << (channel * 3));
+ reg32 |= (time << (channel * 3));
+ ADC_SMPR2(adc) = reg32;
+ } else {
+ reg32 = ADC_SMPR1(adc);
+ reg32 &= ~(0x7 << ((channel - 10) * 3));
+ reg32 |= (time << ((channel - 10) * 3));
+ ADC_SMPR1(adc) = reg32;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+ *
+ * The sampling time can be selected in ADC clock cycles from 1.5 to 239.5,
+ * same for all channels.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] time Unsigned int8. Sampling time selection from
+ * @ref adc_sample_rg
+ */
+
+void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
+{
+ uint8_t i;
+ uint32_t reg32 = 0;
+
+ for (i = 0; i <= 9; i++) {
+ reg32 |= (time << (i * 3));
+ }
+ ADC_SMPR2(adc) = reg32;
+
+ for (i = 10; i <= 17; i++) {
+ reg32 |= (time << ((i - 10) * 3));
+ }
+ ADC_SMPR1(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Upper Threshold
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] threshold Unsigned int8. Upper threshold value
+ */
+
+void adc_set_watchdog_high_threshold(uint32_t adc, uint8_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 |= (threshold << 16);
+ reg32 &= ~0xff00ffff; /* Clear all bits above 8. */
+ ADC_TR1(adc) = reg32;
+ ADC_TR2(adc) = reg32;
+ ADC_TR3(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Lower Threshold
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] threshold Unsigned int8. Lower threshold value
+ */
+
+void adc_set_watchdog_low_threshold(uint32_t adc, uint8_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 = (uint32_t)threshold;
+ reg32 &= ~0xffffff00; /* Clear all bits above 8. */
+ ADC_TR1(adc) = reg32;
+ ADC_TR2(adc) = reg32;
+ ADC_TR3(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set a Regular Channel Conversion Sequence
+ *
+ * Define a sequence of channels to be converted as a regular group with a
+ * length from 1 to 16 channels. If this is called during conversion, the
+ * current conversion is reset and conversion begins again with the newly
+ * defined group.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] length Unsigned int8. Number of channels in the group.
+ * @param[in] channel Unsigned int8[]. Set of channels in sequence, integers
+ * 0..18.
+ */
+
+void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t reg32_1 = 0, reg32_2 = 0, reg32_3 = 0, reg32_4 = 0;
+ uint8_t i = 0;
+
+ /* Maximum sequence length is 16 channels. */
+ if (length > 16) {
+ return;
+ }
+
+ for (i = 1; i <= length; i++) {
+ if (i <= 4) {
+ reg32_1 |= (channel[i - 1] << (i * 6));
+ }
+ if ((i > 4) & (i <= 9)) {
+ reg32_2 |= (channel[i - 1] << ((i - 4 - 1) * 6));
+ }
+ if ((i > 9) & (i <= 14)) {
+ reg32_3 |= (channel[i - 1] << ((i - 9 - 1) * 6));
+ }
+ if ((i > 14) & (i <= 16)) {
+ reg32_4 |= (channel[i - 1] << ((i - 14 - 1) * 6));
+ }
+ }
+ reg32_1 |= ((length - 1) << ADC_SQR1_L_LSB);
+
+ ADC_SQR1(adc) = reg32_1;
+ ADC_SQR2(adc) = reg32_2;
+ ADC_SQR3(adc) = reg32_3;
+ ADC_SQR4(adc) = reg32_4;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set an Injected Channel Conversion Sequence
+ *
+ * Defines a sequence of channels to be converted as an injected group with a
+ * length from 1 to 4 channels. If this is called during conversion, the current
+ * conversion is reset and conversion begins again with the newly defined group.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] length Unsigned int8. Number of channels in the group.
+ * @param[in] channel Unsigned int8[]. Set of channels in sequence, integers
+ * 0..18
+ */
+
+void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t reg32 = 0;
+ uint8_t i = 0;
+
+ /* Maximum sequence length is 4 channels. Minimum sequence is 1.*/
+ if ((length - 1) > 3) {
+ return;
+ }
+
+ for (i = 0; i < length; i++) {
+ reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]);
+ }
+
+ reg32 |= ADC_JSQR_JL_VAL(length);
+
+ ADC_JSQR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag
+ *
+ * This flag is set after all channels of a regular or injected group have been
+ * converted.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @returns bool. End of conversion flag.
+ */
+
+bool adc_eoc(uint32_t adc)
+{
+ return ((ADC_ISR(adc) & ADC_ISR_EOC) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion
+ *
+ * This flag is set after all channels of an injected group have been
+ * converted.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @returns bool. End of conversion flag.
+ */
+
+bool adc_eoc_injected(uint32_t adc)
+{
+ return ((ADC_ISR(adc) & ADC_ISR_JEOC) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from the Regular Conversion Result Register
+ *
+ * The result read back is 12 bits, right or left aligned within the first
+ * 16 bits. For ADC1 only, the higher 16 bits will hold the result from ADC2 if
+ * an appropriate dual mode has been set @see adc_set_dual_mode.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @returns Unsigned int32 conversion result.
+ */
+
+uint32_t adc_read_regular(uint32_t adc)
+{
+ return ADC_DR(adc);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from an Injected Conversion Result Register
+ *
+ * The result read back from the selected injected result register (one of four)
+ * is 12 bits, right or left aligned within the first 16 bits. The result can
+ * have a negative value if the injected channel offset has been set @see
+ * adc_set_injected_offset.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ * @param[in] reg Unsigned int8. Register number (1 ... 4).
+ * @returns Unsigned int32 conversion result.
+ */
+
+uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
+{
+ switch (reg) {
+ case 1:
+ return ADC_JDR1(adc);
+ case 2:
+ return ADC_JDR2(adc);
+ case 3:
+ return ADC_JDR3(adc);
+ case 4:
+ return ADC_JDR4(adc);
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Injected Channel Data Offset
+ *
+ * This value is subtracted from the injected channel results after conversion
+ * is complete, and can result in negative results. A separate value can be
+ * specified for each injected data register.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] reg Unsigned int8. Register number (1 ... 4).
+ * @param[in] offset Unsigned int32.
+*/
+
+void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset)
+{
+ switch (reg) {
+ case 1:
+ ADC_OFR1(adc) |= ADC_OFR1_OFFSET1_EN;
+ ADC_OFR1(adc) |= offset;
+ break;
+ case 2:
+ ADC_OFR2(adc) |= ADC_OFR2_OFFSET2_EN;
+ ADC_OFR2(adc) |= offset;
+ break;
+ case 3:
+ ADC_OFR3(adc) |= ADC_OFR3_OFFSET3_EN;
+ ADC_OFR3(adc) |= offset;
+ break;
+ case 4:
+ ADC_OFR4(adc) |= ADC_OFR4_OFFSET4_EN;
+ ADC_OFR4(adc) |= offset;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+ *
+ * If the ADC is in power-down mode then it is powered up. The application
+ * needs to wait a time of about 3 microseconds for stabilization before using
+ * the ADC. If the ADC is already on this function call will have no effect.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_power_on(uint32_t adc)
+{
+ ADC_CR(adc) |= ADC_CR_ADEN;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Clock Prescale
+ *
+ * The ADC clock taken from the APB2 clock can be scaled down by 2, 4, 6 or 8.
+ *
+ * @param[in] prescale Unsigned int32. Prescale value for ADC Clock @ref
+ * adc_ccr_adcpre
+*/
+
+void adc_set_clk_prescale(uint32_t prescale)
+{
+ uint32_t reg32 = ((ADC_CCR & ~ADC_CCR_CKMODE_MASK) | prescale);
+ ADC_CCR = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Dual/Triple Mode
+ *
+ * The multiple mode uses ADC1 as master, ADC2 and optionally ADC3 in a slave
+ * arrangement. This setting is applied to ADC1 only.
+ *
+ * The various modes possible are described in the reference manual.
+ *
+ * @param[in] mode Unsigned int32. Multiple mode selection from @ref
+ * adc_multi_mode
+*/
+
+void adc_set_multi_mode(uint32_t mode)
+{
+ ADC_CCR |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+ *
+ * This enables an external trigger for set of defined regular channels, and
+ * sets the polarity of the trigger event: rising or falling edge or both. Note
+ * that if the trigger polarity is zero, triggering is disabled.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ * @param[in] trigger Unsigned int32. Trigger identifier
+ * @ref adc_trigger_regular
+ * @param[in] polarity Unsigned int32. Trigger polarity @ref
+ * adc_trigger_polarity_regular
+ */
+
+void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_CFGR(adc);
+
+ reg32 &= ~(ADC_CFGR_EXTSEL_MASK | ADC_CFGR_EXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_CFGR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_disable_external_trigger_regular(uint32_t adc)
+{
+ ADC_CFGR(adc) &= ~ADC_CFGR_EXTEN_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Injected Channels
+ *
+ * This enables an external trigger for set of defined injected channels, and
+ * sets the polarity of the trigger event: rising or falling edge or both.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @param[in] trigger Unsigned int8. Trigger identifier
+ * @ref adc_trigger_injected
+ * @param[in] polarity Unsigned int32. Trigger polarity
+ * @ref adc_trigger_polarity_injected
+*/
+
+void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_JSQR(adc);
+
+ reg32 &= ~(ADC_JSQR_JEXTSEL_MASK | ADC_JSQR_JEXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_JSQR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Injected Channels
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_external_trigger_injected(uint32_t adc)
+{
+ ADC_JSQR(adc) &= ~ADC_JSQR_JEXTEN_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Resolution
+ *
+ * ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
+ * corresponding reduction in conversion time (resolution + 3 ADC clock cycles).
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ * @param[in] resolution Unsigned int8. Resolution value @ref adc_cr1_res
+ */
+
+void adc_set_resolution(uint32_t adc, uint16_t resolution)
+{
+ uint32_t reg32 = ADC_CFGR(adc);
+
+ reg32 &= ~ADC_CFGR_RES_MASK;
+ reg32 |= resolution;
+ ADC_CFGR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable the Overrun Interrupt
+ *
+ * The overrun interrupt is generated when data is not read from a result
+ * register before the next conversion is written. If DMA is enabled, all
+ * transfers are terminated and any conversion sequence is aborted.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_overrun_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) |= ADC_IER_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable the Overrun Interrupt
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_overrun_interrupt(uint32_t adc)
+{
+ ADC_IER(adc) &= ~ADC_IER_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Overrun Flag
+ *
+ * The overrun flag is set when data is not read from a result register before
+ * the next conversion is written. If DMA is enabled, all transfers are
+ * terminated and any conversion sequence is aborted.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ * @returns Unsigned int32 conversion result.
+ */
+
+bool adc_get_overrun_flag(uint32_t adc)
+{
+ return ADC_ISR(adc) & ADC_ISR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Clear Overrun Flags
+ *
+ * The overrun flag is cleared. Note that if an overrun occurs, DMA is
+ * terminated.
+ * The flag must be cleared and the DMA stream and ADC reinitialised to resume
+ * conversions (see the reference manual).
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @returns Unsigned int32 conversion result.
+ */
+
+void adc_clear_overrun_flag(uint32_t adc)
+{
+/* need to write zero to clear this */
+ ADC_ISR(adc) &= ~ADC_ISR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an EOC for Each Conversion
+ *
+ * The EOC is set after each conversion in a sequence rather than at the end of
+ * the sequence. Overrun detection is enabled only if DMA is enabled.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+void adc_eoc_after_each(uint32_t adc)
+{
+ ADC_ISR(adc) |= ADC_ISR_EOS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable the EOC for Each Conversion
+ *
+ * The EOC is set at the end of each sequence rather than after each conversion
+ * in the sequence. Overrun detection is enabled always.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_eoc_after_group(uint32_t adc)
+{
+ ADC_ISR(adc) &= ~ADC_ISR_EOS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set DMA to Continue
+ *
+ * This must be set to allow DMA to continue to operate after the last
+ * conversion in the DMA sequence. This allows DMA to be used in continuous
+ * circular mode.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+/*
+void adc_set_dma_continue(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_DDS;
+}
+*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set DMA to Terminate
+ *
+ * This must be set to allow DMA to terminate after the last conversion in the
+ * DMA sequence. This can avoid overrun errors.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ */
+
+/*
+void adc_set_dma_terminate(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_DDS;
+}
+*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Analog Watchdog Flag
+ *
+ * This flag is set when the converted voltage crosses the high or low
+ * thresholds.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base
+ * @ref adc_reg_base
+ * @returns bool. AWD flag.
+ */
+
+bool adc_awd(uint32_t adc)
+{
+ return (ADC_ISR(adc) & ADC_ISR_AWD1) &&
+ (ADC_ISR(adc) & ADC_ISR_AWD2) &&
+ (ADC_ISR(adc) & ADC_ISR_AWD3);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+ *
+ * This enables both the sensor and the reference voltage measurements on
+ * channels
+ * 16 and 17. These are only available on ADC1 channel 16 and 17 respectively.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_enable_temperature_sensor()
+{
+ ADC_CCR |= ADC_CCR_TSEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+ *
+ * Disabling this will reduce power consumption from the sensor and the
+ * reference voltage measurements.
+ *
+ * @param[in] adc Unsigned int32. ADC block register address base @ref
+ * adc_reg_base
+ */
+
+void adc_disable_temperature_sensor()
+{
+ ADC_CCR &= ~ADC_CCR_TSEN;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f3/crc.c b/libopencm3/lib/stm32/f3/crc.c
new file mode 100644
index 0000000..eb3c14b
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/crc.c
@@ -0,0 +1,33 @@
+/** @defgroup crc_file CRC
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx CRC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 15 October 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
+
+
diff --git a/libopencm3/lib/stm32/f3/dac.c b/libopencm3/lib/stm32/f3/dac.c
new file mode 100644
index 0000000..2d8021e
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx DAC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 18 August 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/f3/dma.c b/libopencm3/lib/stm32/f3/dma.c
new file mode 100644
index 0000000..c5d82b1
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Direct Memory Access</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/f3/flash.c b/libopencm3/lib/stm32/f3/flash.c
new file mode 100644
index 0000000..d157aca
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/flash.c
@@ -0,0 +1,63 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx FLASH</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * @date 14 January 2014
+ *
+ * This library supports the FLASH memory controller in the STM32F3
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * For the STM32F3xx, accessing FLASH memory is described in
+ * section 3 of the STM32F3xx Reference Manual.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**@{*/
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear All Status Flags
+
+Clears program error, end of operation, busy flags.
+*/
+
+void flash_clear_status_flags(void)
+{
+ flash_clear_pgperr_flag();
+ flash_clear_eop_flag();
+ flash_clear_bsy_flag();
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f3/i2c.c b/libopencm3/lib/stm32/f3/i2c.c
new file mode 100644
index 0000000..b5d39cf
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/i2c.c
@@ -0,0 +1,486 @@
+/** @defgroup i2c_file I2C
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx I2C</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 15 October 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/rcc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Reset.
+ *
+ * The I2C peripheral and all its associated configuration registers are placed
+ * in the reset condition. The reset is effected via the RCC peripheral reset
+ * system.
+ *
+ * @param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base.
+ */
+
+void i2c_reset(uint32_t i2c)
+{
+ switch (i2c) {
+ case I2C1:
+ rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
+ rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
+ break;
+ case I2C2:
+ rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
+ rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Enable.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+
+void i2c_peripheral_enable(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Disable.
+ *
+ * This must not be reset while in Master mode until a communication has
+ * finished. In Slave mode, the peripheral is disabled only after communication
+ * has ended.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+
+void i2c_peripheral_disable(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Start Condition.
+ *
+ * If in Master mode this will cause a restart condition to occur at the end of
+ * the current transmission. If in Slave mode, this will initiate a start
+ * condition when the current bus activity is completed.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+
+void i2c_send_start(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_START;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Stop Condition.
+ *
+ * After the current byte transfer this will initiate a stop condition if in
+ * Master mode, or simply release the bus if in Slave mode.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+
+void i2c_send_stop(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_STOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Clear Stop Flag.
+ *
+ * Clear the "Send Stop" flag in the I2C config register
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+void i2c_clear_stop(uint32_t i2c)
+{
+ I2C_ICR(i2c) |= I2C_ICR_STOPCF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
+ *
+ * This sets an address for Slave mode operation, in 7 bit form.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ * @param[in] slave Unsigned int8. Slave address 0...127.
+ */
+
+void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(slave << 1);
+ I2C_OAR1(i2c) &= ~I2C_OAR1_OA1MODE;
+ I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
+ *
+ * This sets an address for Slave mode operation, in 10 bit form.
+ *
+ * @todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ * @param[in] slave Unsigned int16. Slave address 0...1023.
+ */
+
+void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_OA1MODE | slave);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Data.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ * @param[in] data Unsigned int8. Byte to send.
+ */
+
+void i2c_send_data(uint32_t i2c, uint8_t data)
+{
+ I2C_TXDR(i2c) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Get Data.
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+uint8_t i2c_get_data(uint32_t i2c)
+{
+ return I2C_RXDR(i2c) & 0xff;
+}
+
+void i2c_enable_analog_filter(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_ANFOFF;
+}
+
+void i2c_disable_analog_filter(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_ANFOFF;
+}
+
+void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting)
+{
+ I2C_CR1(i2c) = (I2C_CR1(i2c) & ~I2C_CR1_DNF_MASK) | dnf_setting;
+}
+
+/* t_presc= (presc+1)*t_i2cclk */
+void i2c_set_prescaler(uint32_t i2c, uint8_t presc)
+{
+ I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_PRESC_MASK) |
+ (presc << I2C_TIMINGR_PRESC_SHIFT);
+}
+
+void i2c_set_data_setup_time(uint32_t i2c, uint8_t s_time)
+{
+ I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLDEL_MASK) |
+ (s_time << I2C_TIMINGR_SCLDEL_SHIFT);
+}
+
+void i2c_set_data_hold_time(uint32_t i2c, uint8_t h_time)
+{
+ I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SDADEL_MASK) |
+ (h_time << I2C_TIMINGR_SDADEL_SHIFT);
+}
+
+void i2c_set_scl_high_period(uint32_t i2c, uint8_t period)
+{
+ I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLH_MASK) |
+ (period << I2C_TIMINGR_SCLH_SHIFT);
+}
+
+void i2c_set_scl_low_period(uint32_t i2c, uint8_t period)
+{
+ I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLL_MASK) |
+ (period << I2C_TIMINGR_SCLL_SHIFT);
+}
+
+void i2c_enable_stretching(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_NOSTRETCH;
+}
+
+void i2c_disable_stretching(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_NOSTRETCH;
+}
+
+void i2c_100khz_i2cclk8mhz(uint32_t i2c)
+{
+ i2c_set_prescaler(i2c, 1);
+ i2c_set_scl_low_period(i2c, 0x13);
+ i2c_set_scl_high_period(i2c, 0xF);
+ i2c_set_data_hold_time(i2c, 0x2);
+ i2c_set_data_setup_time(i2c, 0x4);
+}
+
+void i2c_set_7bit_addr_mode(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_ADD10;
+}
+
+void i2c_set_10bit_addr_mode(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_ADD10;
+}
+
+void i2c_set_7bit_address(uint32_t i2c, uint8_t addr)
+{
+ I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_7BIT_MASK) |
+ ((addr & 0x7F) << I2C_CR2_SADD_7BIT_SHIFT);
+}
+
+void i2c_set_10bit_address(uint32_t i2c, uint16_t addr)
+{
+ I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_10BIT_MASK) |
+ ((addr & 0x3FF) << I2C_CR2_SADD_10BIT_SHIFT);
+}
+
+void i2c_set_write_transfer_dir(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_RD_WRN;
+}
+
+void i2c_set_read_transfer_dir(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_RD_WRN;
+}
+
+void i2c_set_bytes_to_transfer(uint32_t i2c, uint32_t n_bytes)
+{
+ I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_NBYTES_MASK) |
+ (n_bytes << I2C_CR2_NBYTES_SHIFT);
+}
+
+uint8_t i2c_is_start(uint32_t i2c)
+{
+ if ((I2C_CR2(i2c) & I2C_CR2_START) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void i2c_enable_autoend(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_AUTOEND;
+}
+
+void i2c_disable_autoend(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_AUTOEND;
+}
+
+uint8_t i2c_nack(uint32_t i2c)
+{
+ if ((I2C_ISR(i2c) & I2C_ISR_NACKF) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+uint8_t i2c_busy(uint32_t i2c)
+{
+ if ((I2C_ISR(i2c) & I2C_ISR_BUSY) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+uint8_t i2c_transmit_int_status(uint32_t i2c)
+{
+ if ((I2C_ISR(i2c) & I2C_ISR_TXIS) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+uint8_t i2c_transfer_complete(uint32_t i2c)
+{
+ if ((I2C_ISR(i2c) & I2C_ISR_TC) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+uint8_t i2c_received_data(uint32_t i2c)
+{
+ if ((I2C_ISR(i2c) & I2C_ISR_RXNE) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable Interrupt
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ * @param[in] interrupt Unsigned int32. Interrupt to enable.
+ */
+void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR1(i2c) |= interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable Interrupt
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ * @param[in] interrupt Unsigned int32. Interrupt to disable.
+ */
+void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR1(i2c) &= ~interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable reception DMA
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+void i2c_enable_rxdma(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_RXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable reception DMA
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+void i2c_disable_rxdma(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_RXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable transmission DMA
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+void i2c_enable_txdma(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_TXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable transmission DMA
+ *
+ * @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+ */
+void i2c_disable_txdma(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_TXDMAEN;
+}
+
+void write_i2c(uint32_t i2c, uint8_t i2c_addr, uint8_t reg, uint8_t size,
+ uint8_t *data)
+{
+ int wait;
+ int i;
+ while (i2c_busy(i2c) == 1);
+ while (i2c_is_start(i2c) == 1);
+ /*Setting transfer properties*/
+ i2c_set_bytes_to_transfer(i2c, size + 1);
+ i2c_set_7bit_address(i2c, (i2c_addr & 0x7F));
+ i2c_set_write_transfer_dir(i2c);
+ i2c_enable_autoend(i2c);
+ /*start transfer*/
+ i2c_send_start(i2c);
+
+ wait = true;
+ while (wait) {
+ if (i2c_transmit_int_status(i2c)) {
+ wait = false;
+ }
+ while (i2c_nack(i2c));
+ }
+
+ i2c_send_data(i2c, reg);
+ for (i = 0; i < size; i++) {
+ wait = true;
+ while (wait) {
+ if (i2c_transmit_int_status(i2c)) {
+ wait = false;
+ }
+ while (i2c_nack(i2c));
+ }
+ i2c_send_data(i2c, data[i]);
+ }
+}
+
+void read_i2c(uint32_t i2c, uint8_t i2c_addr, uint8_t reg, uint8_t size,
+ uint8_t *data)
+{
+ int wait;
+ int i;
+ while (i2c_busy(i2c) == 1);
+ while (i2c_is_start(i2c) == 1);
+ /*Setting transfer properties*/
+ i2c_set_bytes_to_transfer(i2c, 1);
+ i2c_set_7bit_address(i2c, i2c_addr);
+ i2c_set_write_transfer_dir(i2c);
+ i2c_disable_autoend(i2c);
+ /*start transfer*/
+ i2c_send_start(i2c);
+
+ wait = true;
+ while (wait) {
+ if (i2c_transmit_int_status(i2c)) {
+ wait = false;
+ }
+ while (i2c_nack(i2c)); /* Some error */
+ }
+ i2c_send_data(i2c, reg);
+
+ while (i2c_is_start(i2c) == 1);
+ /*Setting transfer properties*/
+ i2c_set_bytes_to_transfer(i2c, size);
+ i2c_set_7bit_address(i2c, i2c_addr);
+ i2c_set_read_transfer_dir(i2c);
+ i2c_enable_autoend(i2c);
+ /*start transfer*/
+ i2c_send_start(i2c);
+
+ for (i = 0; i < size; i++) {
+ while (i2c_received_data(i2c) == 0);
+ data[i] = i2c_get_data(i2c);
+ }
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f3/iwdg.c b/libopencm3/lib/stm32/f3/iwdg.c
new file mode 100644
index 0000000..cf0045c
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Independent Watchdog Timer</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 18 August 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld b/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/libopencm3_stm32f3.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/f3/pwr.c b/libopencm3/lib/stm32/f3/pwr.c
new file mode 100644
index 0000000..3c1a84b
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/pwr.c
@@ -0,0 +1,40 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Power Control</b>
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2014
+ * Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * @date 13 January 2014
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/pwr.h>
+
+
diff --git a/libopencm3/lib/stm32/f3/rcc.c b/libopencm3/lib/stm32/f3/rcc.c
new file mode 100644
index 0000000..8291a2b
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/rcc.c
@@ -0,0 +1,465 @@
+/** @defgroup rcc_file RCC
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Reset and Clock Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Modified by 2013 Fernando Cortes <fernando.corcam@gmail.com> (stm32f3)
+ * Modified by 2013 Guillermo Rivera <memogrg@gmail.com> (stm32f3)
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**@{*/
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+#include <libopencm3/stm32/i2c.h>
+
+/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
+uint32_t rcc_ppre1_frequency = 8000000;
+uint32_t rcc_ppre2_frequency = 8000000;
+
+const clock_scale_t hsi_8mhz[CLOCK_END] = {
+ { /* 44MHz */
+ .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X11,
+ .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE1_DIV_2,
+ .ppre2 = RCC_CFGR_PPRE2_DIV_NONE,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1WS,
+ .apb1_frequency = 22000000,
+ .apb2_frequency = 44000000,
+ },
+ { /* 48MHz */
+ .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X12,
+ .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE1_DIV_2,
+ .ppre2 = RCC_CFGR_PPRE2_DIV_NONE,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1WS,
+ .apb1_frequency = 24000000,
+ .apb2_frequency = 48000000,
+ },
+ { /* 64MHz */
+ .pll = RCC_CFGR_PLLMUL_PLL_IN_CLK_X16,
+ .pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE1_DIV_2,
+ .ppre2 = RCC_CFGR_PPRE2_DIV_NONE,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2WS,
+ .apb1_frequency = 32000000,
+ .apb2_frequency = 64000000,
+ }
+};
+
+void rcc_osc_ready_int_clear(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_enable(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_disable(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+int rcc_osc_ready_int_flag(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case HSE:
+ return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case HSI:
+ return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case LSE:
+ return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ }
+
+ cm3_assert_not_reached();
+}
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+void rcc_wait_for_osc_ready(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) == 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) == 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) == 0);
+ break;
+ case LSE:
+ while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
+ break;
+ }
+}
+
+
+void rcc_wait_for_osc_not_ready(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) != 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) != 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) != 0);
+ break;
+ case LSE:
+ while ((RCC_BDCR & RCC_BDCR_LSERDY) != 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) != 0);
+ break;
+ }
+}
+
+void rcc_wait_for_sysclk_status(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL);
+ break;
+ case HSE:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE);
+ break;
+ case HSI:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI);
+ break;
+ default:
+ /* Shouldn't be reached. */
+ break;
+ }
+}
+
+void rcc_osc_on(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_osc_off(enum osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR &= ~RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+void rcc_osc_bypass_enable(enum osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_osc_bypass_disable(enum osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_set_sysclk_source(uint32_t clk)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 1) | (1 << 0));
+ RCC_CFGR = (reg32 | clk);
+}
+
+void rcc_set_pll_source(uint32_t pllsrc)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~RCC_CFGR_PLLSRC;
+ RCC_CFGR = (reg32 | (pllsrc << 16));
+}
+
+void rcc_set_ppre2(uint32_t ppre2)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15));
+ RCC_CFGR = (reg32 | (ppre2 << 11));
+}
+
+void rcc_set_ppre1(uint32_t ppre1)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12));
+ RCC_CFGR = (reg32 | (ppre1 << 8));
+}
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
+ RCC_CFGR = (reg32 | (hpre << 4));
+}
+
+
+void rcc_set_main_pll_hsi(uint32_t pll)
+{
+ RCC_CFGR = (~RCC_CFGR_PLLMUL_MASK & RCC_CFGR) |
+ (pll << RCC_CFGR_PLLMUL_SHIFT);
+}
+
+
+uint32_t rcc_get_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ return (RCC_CFGR & 0x000c) >> 2;
+}
+
+
+void rcc_clock_setup_hsi(const clock_scale_t *clock)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_HSI); /* XXX: se cayo */
+ rcc_wait_for_sysclk_status(HSI);
+
+ rcc_osc_off(PLL);
+ rcc_wait_for_osc_not_ready(PLL);
+ rcc_set_pll_source(clock->pllsrc);
+ rcc_set_main_pll_hsi(clock->pll);
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre2(clock->ppre2);
+ rcc_set_ppre1(clock->ppre1);
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_PLL); /* XXX: se cayo */
+ /* Wait for PLL clock to be selected. */
+ rcc_wait_for_sysclk_status(PLL);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+}
+
+
+void rcc_backupdomain_reset(void)
+{
+ /* Set the backup domain software reset. */
+ RCC_BDCR |= RCC_BDCR_BDRST;
+
+ /* Clear the backup domain software reset. */
+ RCC_BDCR &= ~RCC_BDCR_BDRST;
+}
+
+void rcc_set_i2c_clock_hsi(uint32_t i2c)
+{
+ if (i2c == I2C1) {
+ RCC_CFGR3 &= ~RCC_CFGR3_I2C1SW;
+ }
+ if (i2c == I2C2) {
+ RCC_CFGR3 &= ~RCC_CFGR3_I2C2SW;
+ }
+}
+
+void rcc_set_i2c_clock_sysclk(uint32_t i2c)
+{
+ if (i2c == I2C1) {
+ RCC_CFGR3 |= RCC_CFGR3_I2C1SW;
+ }
+ if (i2c == I2C2) {
+ RCC_CFGR3 |= RCC_CFGR3_I2C2SW;
+ }
+}
+
+uint32_t rcc_get_i2c_clocks(void)
+{
+ return RCC_CFGR3 & (RCC_CFGR3_I2C1SW | RCC_CFGR3_I2C2SW);
+}
+
+void rcc_usb_prescale_1_5(void)
+{
+ RCC_CFGR &= ~RCC_CFGR_USBPRES;
+}
+
+void rcc_usb_prescale_1(void)
+{
+ RCC_CFGR |= RCC_CFGR_USBPRES;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f3/rtc.c b/libopencm3/lib/stm32/f3/rtc.c
new file mode 100644
index 0000000..f332765
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/rtc.c
@@ -0,0 +1,38 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Real Time Clock</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2014
+ * Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * @date 13 January 2014
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/rtc.h>
+
+
diff --git a/libopencm3/lib/stm32/f3/spi.c b/libopencm3/lib/stm32/f3/spi.c
new file mode 100644
index 0000000..3dcc524
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32F3xx
+
+@brief <b>libopencm3 STM32F3xx SPI</b>
+
+@version 1.0.0
+
+@date 20 February 2014
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/f3/timer.c b/libopencm3/lib/stm32/f3/timer.c
new file mode 100644
index 0000000..0e9ac3d
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/timer.c
@@ -0,0 +1,33 @@
+/** @defgroup timer_file TIMER
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx Timers</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 11 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/timer.h>
+
+
diff --git a/libopencm3/lib/stm32/f3/usart.c b/libopencm3/lib/stm32/f3/usart.c
new file mode 100644
index 0000000..305ae72
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/usart.c
@@ -0,0 +1,140 @@
+/** @defgroup usart_file USART
+ *
+ * @ingroup STM32F3xx
+ *
+ * @brief <b>libopencm3 STM32F3xx USART</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 30 August 2012
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send a Data Word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] data unsigned 16 bit.
+ */
+
+void usart_send(uint32_t usart, uint16_t data)
+{
+ /* Send data. */
+ USART_TDR(usart) = (data & USART_TDR_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word.
+ *
+ * If parity is enabled the MSB (bit 7 or 8 depending on the word length) is
+ * the parity bit.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @returns unsigned 16 bit data word.
+ */
+
+uint16_t usart_recv(uint32_t usart)
+{
+ /* Receive data. */
+ return USART_RDR(usart) & USART_RDR_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Transmit Data Buffer Empty
+ *
+ * Blocks until the transmit data buffer becomes empty and is ready to accept
+ * the next data word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_wait_send_ready(uint32_t usart)
+{
+ /* Wait until the data has been transferred into the shift register. */
+ while ((USART_ISR(usart) & USART_ISR_TXE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Received Data Available
+ *
+ * Blocks until the receive data buffer holds a valid received data word.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ */
+
+void usart_wait_recv_ready(uint32_t usart)
+{
+ /* Wait until the data is ready to be received. */
+ while ((USART_ISR(usart) & USART_ISR_RXNE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Status Flag.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+ * @returns boolean: flag set.
+ */
+
+bool usart_get_flag(uint32_t usart, uint32_t flag)
+{
+ return ((USART_ISR(usart) & flag) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Return Interrupt Source.
+ *
+ * Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
+ * set and the interrupt was enabled. If the specified flag is not an interrupt
+ * flag, the function returns false.
+ *
+ * @todo These are the most important interrupts likely to be used. Others
+ * relating to LIN break, and error conditions in multibuffer communication,
+ * need to be added for completeness.
+ *
+ * @param[in] usart unsigned 32 bit. USART block register address base @ref
+ * usart_reg_base
+ * @param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+ * @returns boolean: flag and interrupt enable both set.
+ */
+
+bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
+{
+ uint32_t flag_set = (USART_ISR(usart) & flag);
+ /* IDLE, RXNE, TC, TXE interrupts */
+ if ((flag >= USART_ISR_IDLE) && (flag <= USART_ISR_TXE)) {
+ return ((flag_set & USART_CR1(usart)) != 0);
+ /* Overrun error */
+ } else if (flag == USART_ISR_ORE) {
+ return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
+ }
+
+ return false;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f3/vector_chipset.c b/libopencm3/lib/stm32/f3/vector_chipset.c
new file mode 100644
index 0000000..145be05
--- /dev/null
+++ b/libopencm3/lib/stm32/f3/vector_chipset.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+ * Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/scb.h>
+
+static void pre_main(void)
+{
+ /* Enable access to Floating-Point coprocessor. */
+ SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
+}
diff --git a/libopencm3/lib/stm32/f4/Makefile b/libopencm3/lib/stm32/f4/Makefile
new file mode 100644
index 0000000..475d917
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/Makefile
@@ -0,0 +1,59 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32f4
+SRCLIBDIR ?= ../..
+
+FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m4 -mthumb $(FP_FLAGS) \
+ -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32F4
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+
+OBJS = adc.o adc_common_v1.o can.o gpio.o pwr.o rcc.o rtc.o crypto.o
+
+OBJS += crc_common_all.o dac_common_all.o dma_common_f24.o \
+ gpio_common_all.o gpio_common_f0234.o i2c_common_all.o \
+ iwdg_common_all.o pwr_common_all.o rtc_common_l1f024.o \
+ spi_common_all.o spi_common_l1f124.o timer_common_all.o \
+ timer_common_f234.o timer_common_f24.o usart_common_all.o \
+ usart_common_f124.o flash_common_f234.o flash_common_f24.o \
+ hash_common_f24.o crypto_common_f24.o exti_common_all.o \
+ rcc_common_all.o
+
+OBJS += usb.o usb_standard.o usb_control.o usb_fx07_common.o \
+ usb_f107.o usb_f207.o usb_msc.o
+
+OBJS += mac.o phy.o mac_stm32fxx7.o phy_ksz8051mll.o fmc.o
+
+VPATH += ../../usb:../:../../cm3:../common
+VPATH += ../../ethernet
+
+include ../../Makefile.include
diff --git a/libopencm3/lib/stm32/f4/adc.c b/libopencm3/lib/stm32/f4/adc.c
new file mode 100644
index 0000000..fba88de
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/adc.c
@@ -0,0 +1,437 @@
+/** @defgroup adc_file ADC
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx Analog to Digital Converters</b>
+
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+@date 30 August 2012
+
+This library supports the A/D Converter Control System in the STM32 series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to three A/D converters each with their own set of
+registers. However all the A/D converters share a common clock which is
+prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum
+of 8. The ADC resolution can be set to 12, 10, 8 or 6 bits.
+
+Each A/D converter has up to 19 channels:
+@li On ADC1 the analog channels 16 is internally connected to the temperature
+sensor, channel 17 to V<sub>REFINT</sub>, and channel 18 to V<sub>BATT</sub>.
+@li On ADC2 and ADC3 the analog channels 16 - 18 are not used.
+
+The conversions can occur as a one-off conversion whereby the process stops
+once conversion is complete. The conversions can also be continuous wherein a
+new conversion starts immediately the previous conversion has ended.
+
+Conversion can occur as a single channel conversion or a scan of a group of
+channels in either continuous or one-off mode. If more than one channel is
+converted in a scan group, DMA must be used to transfer the data as there is
+only one result register available. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+A discontinuous mode allows a subgroup of group of a channels to be converted
+in bursts of a given length.
+
+Injected conversions allow a second group of channels to be converted
+separately from the regular group. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+@section adc_f4_api_ex Basic ADC Handling API.
+
+Example 1: Simple single channel conversion polled. Enable the peripheral clock
+and ADC, reset ADC and set the prescaler divider. Set multiple mode to
+independent.
+
+@code
+gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
+rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+adc_set_clk_prescale(RCC_CFGR_ADCPRE_BY2);
+adc_disable_scan_mode(ADC1);
+adc_set_single_conversion_mode(ADC1);
+adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
+uint8_t channels[] = ADC_CHANNEL0;
+adc_set_regular_sequence(ADC1, 1, channels);
+adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
+adc_power_on(ADC1);
+adc_start_conversion_regular(ADC1);
+while (! adc_eoc(ADC1));
+reg16 = adc_read_regular(ADC1);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/adc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for a Single Channel
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref
+adc_channel
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
+ * NOTE Common with f1, f2 and f37x
+*/
+
+void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
+{
+ uint32_t reg32;
+
+ if (channel < 10) {
+ reg32 = ADC_SMPR2(adc);
+ reg32 &= ~(0x7 << (channel * 3));
+ reg32 |= (time << (channel * 3));
+ ADC_SMPR2(adc) = reg32;
+ } else {
+ reg32 = ADC_SMPR1(adc);
+ reg32 &= ~(0x7 << ((channel - 10) * 3));
+ reg32 |= (time << ((channel - 10) * 3));
+ ADC_SMPR1(adc) = reg32;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same
+for all channels.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
+ * NOTE Common with f1, f2 and f37x
+*/
+
+void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
+{
+ uint8_t i;
+ uint32_t reg32 = 0;
+
+ for (i = 0; i <= 9; i++) {
+ reg32 |= (time << (i * 3));
+ }
+ ADC_SMPR2(adc) = reg32;
+
+ for (i = 10; i <= 17; i++) {
+ reg32 |= (time << ((i - 10) * 3));
+ }
+ ADC_SMPR1(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+
+If the ADC is in power-down mode then it is powered up. The application needs
+to wait a time of about 3 microseconds for stabilization before using the ADC.
+If the ADC is already on this function call will have no effect.
+ * NOTE Common with L1 and F2
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_power_on(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_ADON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Clock Prescale
+
+The ADC clock taken from the APB2 clock can be scaled down by 2, 4, 6 or 8.
+
+@param[in] prescale Unsigned int32. Prescale value for ADC Clock @ref
+adc_ccr_adcpre
+*/
+
+void adc_set_clk_prescale(uint32_t prescale)
+{
+ uint32_t reg32 = ((ADC_CCR & ~ADC_CCR_ADCPRE_MASK) | prescale);
+ ADC_CCR = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Dual/Triple Mode
+
+The multiple mode uses ADC1 as master, ADC2 and optionally ADC3 in a slave
+arrangement. This setting is applied to ADC1 only.
+
+The various modes possible are described in the reference manual.
+
+@param[in] mode Unsigned int32. Multiple mode selection from @ref adc_multi_mode
+*/
+
+void adc_set_multi_mode(uint32_t mode)
+{
+ ADC_CCR |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+
+This enables an external trigger for set of defined regular channels, and sets
+the polarity of the trigger event: rising or falling edge or both. Note that if
+the trigger polarity is zero, triggering is disabled.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int32. Trigger identifier @ref adc_trigger_regular
+@param[in] polarity Unsigned int32. Trigger polarity @ref
+adc_trigger_polarity_regular
+*/
+
+void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_CR2(adc);
+
+ reg32 &= ~(ADC_CR2_EXTSEL_MASK | ADC_CR2_EXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_CR2(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_external_trigger_regular(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_EXTEN_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Injected Channels
+
+This enables an external trigger for set of defined injected channels, and sets
+the polarity of the trigger event: rising or falling edge or both.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected
+@param[in] polarity Unsigned int32. Trigger polarity @ref
+adc_trigger_polarity_injected
+*/
+
+void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_CR2(adc);
+
+ reg32 &= ~(ADC_CR2_JEXTSEL_MASK | ADC_CR2_JEXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_CR2(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Injected Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_external_trigger_injected(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_JEXTEN_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Resolution
+
+ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
+corresponding reduction in conversion time (resolution + 3 ADC clock cycles).
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] resolution Unsigned int32. Resolution value @ref adc_cr1_res
+*/
+
+void adc_set_resolution(uint32_t adc, uint32_t resolution)
+{
+ uint32_t reg32 = ADC_CR1(adc);
+
+ reg32 &= ~ADC_CR1_RES_MASK;
+ reg32 |= resolution;
+ ADC_CR1(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable the Overrun Interrupt
+
+The overrun interrupt is generated when data is not read from a result register
+before the next conversion is written. If DMA is enabled, all transfers are
+terminated and any conversion sequence is aborted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_overrun_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable the Overrun Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_overrun_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_OVRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Overrun Flag
+
+The overrun flag is set when data is not read from a result register before the
+next conversion is written. If DMA is enabled, all transfers are terminated and
+any conversion sequence is aborted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns Unsigned int32 conversion result.
+*/
+
+bool adc_get_overrun_flag(uint32_t adc)
+{
+ return ADC_SR(adc) & ADC_SR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Clear Overrun Flags
+
+The overrun flag is cleared. Note that if an overrun occurs, DMA is terminated.
+The flag must be cleared and the DMA stream and ADC reinitialised to resume
+conversions (see the reference manual).
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns Unsigned int32 conversion result.
+*/
+
+void adc_clear_overrun_flag(uint32_t adc)
+{
+/* need to write zero to clear this */
+ ADC_SR(adc) &= ~ADC_SR_OVR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an EOC for Each Conversion
+
+The EOC is set after each conversion in a sequence rather than at the end of the
+sequence. Overrun detection is enabled only if DMA is enabled.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_eoc_after_each(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_EOCS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable the EOC for Each Conversion
+
+The EOC is set at the end of each sequence rather than after each conversion in
+the sequence. Overrun detection is enabled always.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_eoc_after_group(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_EOCS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set DMA to Continue
+
+This must be set to allow DMA to continue to operate after the last conversion
+in the DMA sequence. This allows DMA to be used in continuous circular mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_set_dma_continue(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_DDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set DMA to Terminate
+
+This must be set to allow DMA to terminate after the last conversion in the DMA
+sequence. This can avoid overrun errors.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_set_dma_terminate(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_DDS;
+}
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the Analog Watchdog Flag
+
+This flag is set when the converted voltage crosses the high or low thresholds.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns bool. AWD flag.
+*/
+
+bool adc_awd(uint32_t adc)
+{
+ return ADC_SR(adc) & ADC_SR_AWD;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+
+This enables both the sensor and the reference voltage measurements on channels
+16 and 17. These are only available on ADC1 channel 16 and 17 respectively.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_temperature_sensor()
+{
+ ADC_CCR |= ADC_CCR_TSVREFE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+
+Disabling this will reduce power consumption from the sensor and the reference
+voltage measurements.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_temperature_sensor()
+{
+ ADC_CCR &= ~ADC_CCR_TSVREFE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f4/crc.c b/libopencm3/lib/stm32/f4/crc.c
new file mode 100644
index 0000000..6bc9456
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/crc.c
@@ -0,0 +1,33 @@
+/** @defgroup crc_file CRC
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx CRC</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
+
+
diff --git a/libopencm3/lib/stm32/f4/crypto.c b/libopencm3/lib/stm32/f4/crypto.c
new file mode 100644
index 0000000..651f365
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/crypto.c
@@ -0,0 +1,66 @@
+/** @defgroup crypto_file CRYPTO
+ *
+ * @ingroup STM32F4xx
+ *
+ * @brief <b>libopencm3 STM32F4xx CRYPTO</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 18 Jun 2013
+ *
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crypto.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+
+/** @brief Set the MAC algorithm
+ */
+void crypto_set_mac_algorithm(enum crypto_mode_mac mode)
+{
+ crypto_set_algorithm((enum crypto_mode) mode);
+}
+
+/**
+ * @brief Swap context
+ *
+ *@param[in] buf uint32_t Memory space for swap (16 items length)
+ */
+void crypto_context_swap(uint32_t *buf)
+{
+ int i;
+ /* Apply exact order of ? */
+ for (i = 0; i < 8; i++) {
+ uint32_t save = *buf;
+ *buf++ = CRYP_CSGCMCCMR(i);
+ CRYP_CSGCMCCMR(i) = save;
+ };
+
+ for (i = 0; i < 8; i++) {
+ uint32_t save = *buf;
+ *buf++ = CRYP_CSGCMR(i);
+ CRYP_CSGCMCCMR(i) = save;
+ };
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f4/dac.c b/libopencm3/lib/stm32/f4/dac.c
new file mode 100644
index 0000000..c5397b6
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx DAC</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/f4/dma.c b/libopencm3/lib/stm32/f4/dma.c
new file mode 100644
index 0000000..6616621
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx DMA</b>
+
+@version 1.0.0
+
+@date 30 November 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/f4/flash.c b/libopencm3/lib/stm32/f4/flash.c
new file mode 100644
index 0000000..5353605
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/flash.c
@@ -0,0 +1,53 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32F4xx
+ *
+ * @brief <b>libopencm3 STM32F4xx FLASH</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * @date 14 January 2014
+ *
+ * This library supports the FLASH memory controller in the STM32F4
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * For the STM32F4xx, accessing FLASH memory is described briefly in
+ * section 2.3.3 of the STM32F4xx Reference Manual.
+ * For detailed programming information see:
+ * PM0081 programming manual: STM32F10xxx Flash programming
+ * September 2011, Doc ID 018520 Rev 1
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/f4/fmc.c b/libopencm3/lib/stm32/f4/fmc.c
new file mode 100644
index 0000000..0de8a4a
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/fmc.c
@@ -0,0 +1,99 @@
+/*
+ *
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Utility functions for the SDRAM component of the FMC */
+
+#include <stdint.h>
+#include <libopencm3/stm32/fsmc.h>
+
+/*
+ * Install various timing values into the correct place in the
+ * SDRAM Timing Control Register format.
+ *
+ * Note that the register is 'zero' based to save bits so 1 cycle
+ * is stored as '0'. This command takes actual cycles and adjusts
+ * by subtracting 1.
+ */
+uint32_t
+sdram_timing(struct sdram_timing *t) {
+ uint32_t result;
+
+ result = 0;
+ result |= ((t->trcd - 1) & 0xf) * FMC_SDTR_TRCD_SHIFT;
+ result |= ((t->trp - 1) & 0xf) * FMC_SDTR_TRP_SHIFT;
+ result |= ((t->twr - 1) & 0xf) * FMC_SDTR_TWR_SHIFT;
+ result |= ((t->trc - 1) & 0xf) * FMC_SDTR_TRC_SHIFT;
+ result |= ((t->tras - 1) & 0xf) * FMC_SDTR_TRAS_SHIFT;
+ result |= ((t->txsr - 1) & 0xf) * FMC_SDTR_TXSR_SHIFT;
+ result |= ((t->tmrd - 1) & 0xf) * FMC_SDTR_TMRD_SHIFT;
+ return result;
+}
+
+/*
+ * Send a command to the SDRAM controller, wait until it is not
+ * busy before sending. This allows you to chain sending commands
+ * and the code will pause as needed between them.
+ */
+void
+sdram_command(enum fmc_sdram_bank bank,
+ enum fmc_sdram_command cmd, int autorefresh, int modereg) {
+ uint32_t tmp_reg = 0;
+
+ switch (bank) {
+ case SDRAM_BANK1:
+ tmp_reg = FMC_SDCMR_CTB1;
+ break;
+ case SDRAM_BANK2:
+ tmp_reg = FMC_SDCMR_CTB2;
+ break;
+ case SDRAM_BOTH_BANKS:
+ tmp_reg = FMC_SDCMR_CTB1 | FMC_SDCMR_CTB2;
+ break;
+ }
+ tmp_reg |= autorefresh * FMC_SDCMR_NRFS_SHIFT;
+ tmp_reg |= modereg * FMC_SDCMR_MRD_SHIFT;
+ switch (cmd) {
+ case SDRAM_CLK_CONF:
+ tmp_reg |= FMC_SDCMR_MODE_CLOCK_CONFIG_ENA;
+ break;
+ case SDRAM_AUTO_REFRESH:
+ tmp_reg |= FMC_SDCMR_MODE_AUTO_REFRESH;
+ break;
+ case SDRAM_LOAD_MODE:
+ tmp_reg |= FMC_SDCMR_MODE_LOAD_MODE_REGISTER;
+ break;
+ case SDRAM_PALL:
+ tmp_reg |= FMC_SDCMR_MODE_PALL;
+ break;
+ case SDRAM_SELF_REFRESH:
+ tmp_reg |= FMC_SDCMR_MODE_SELF_REFRESH;
+ break;
+ case SDRAM_POWER_DOWN:
+ tmp_reg |= FMC_SDCMR_MODE_POWER_DOWN;
+ break;
+ case SDRAM_NORMAL:
+ default:
+ break;
+ }
+
+ /* Wait for the next chance to talk to the controller */
+ while (FMC_SDSR & FMC_SDSR_BUSY) ;
+
+ /* Send the next command */
+ FMC_SDCMR = tmp_reg;
+}
diff --git a/libopencm3/lib/stm32/f4/gpio.c b/libopencm3/lib/stm32/f4/gpio.c
new file mode 100644
index 0000000..ea59ae7
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/gpio.c
@@ -0,0 +1,31 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/gpio.h>
diff --git a/libopencm3/lib/stm32/f4/hash.c b/libopencm3/lib/stm32/f4/hash.c
new file mode 100644
index 0000000..cd791bf
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/hash.c
@@ -0,0 +1,31 @@
+/** @defgroup hash_file HASH
+ *
+ * @ingroup STM32F4xx
+ *
+ * @brief <b>libopencm3 STM32F4xx Hash Processor</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 13 January 2014
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/hash.h>
diff --git a/libopencm3/lib/stm32/f4/i2c.c b/libopencm3/lib/stm32/f4/i2c.c
new file mode 100644
index 0000000..67df9b1
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/i2c.c
@@ -0,0 +1,31 @@
+/** @defgroup i2c_file I2C
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx I2C</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
diff --git a/libopencm3/lib/stm32/f4/iwdg.c b/libopencm3/lib/stm32/f4/iwdg.c
new file mode 100644
index 0000000..3985657
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx Independent Watchdog Timer</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld b/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/libopencm3_stm32f4.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/f4/pwr.c b/libopencm3/lib/stm32/f4/pwr.c
new file mode 100644
index 0000000..9b9e579
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/pwr.c
@@ -0,0 +1,46 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32F4xx
+ *
+ * @brief <b>libopencm3 STM32F4xx Power Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * @date 4 March 2013
+ *
+ * This library supports the power control system for the
+ * STM32F4 series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/pwr.h>
+
+void pwr_set_vos_scale(vos_scale_t scale)
+{
+ if (scale == SCALE1) {
+ PWR_CR |= PWR_CR_VOS;
+ } else if (scale == SCALE2) {
+ PWR_CR &= PWR_CR_VOS;
+ }
+}
diff --git a/libopencm3/lib/stm32/f4/rcc.c b/libopencm3/lib/stm32/f4/rcc.c
new file mode 100644
index 0000000..d862691
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/rcc.c
@@ -0,0 +1,539 @@
+/** @defgroup rcc_file RCC
+ *
+ * @ingroup STM32F4xx
+ *
+ * @section rcc_f4_api_ex Reset and Clock Control API.
+ *
+ * @brief <b>libopencm3 STM32F4xx Reset and Clock Control</b>
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran at seznam.cz>
+ *
+ * @date 18 Jun 2013
+ *
+ * This library supports the Reset and Clock Control System in the STM32 series
+ * of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/assert.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/pwr.h>
+#include <libopencm3/stm32/flash.h>
+
+/**@{*/
+
+/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
+uint32_t rcc_ppre1_frequency = 16000000;
+uint32_t rcc_ppre2_frequency = 16000000;
+
+const clock_scale_t hse_8mhz_3v3[CLOCK_3V3_END] = {
+ { /* 48MHz */
+ .pllm = 8,
+ .plln = 96,
+ .pllp = 2,
+ .pllq = 2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 12000000,
+ .apb2_frequency = 24000000,
+ },
+ { /* 120MHz */
+ .pllm = 8,
+ .plln = 240,
+ .pllp = 2,
+ .pllq = 5,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 30000000,
+ .apb2_frequency = 60000000,
+ },
+ { /* 168MHz */
+ .pllm = 8,
+ .plln = 336,
+ .pllp = 2,
+ .pllq = 7,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_5WS,
+ .apb1_frequency = 42000000,
+ .apb2_frequency = 84000000,
+ },
+};
+
+const clock_scale_t hse_12mhz_3v3[CLOCK_3V3_END] = {
+ { /* 48MHz */
+ .pllm = 12,
+ .plln = 96,
+ .pllp = 2,
+ .pllq = 2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 12000000,
+ .apb2_frequency = 24000000,
+ },
+ { /* 120MHz */
+ .pllm = 12,
+ .plln = 240,
+ .pllp = 2,
+ .pllq = 5,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 30000000,
+ .apb2_frequency = 60000000,
+ },
+ { /* 168MHz */
+ .pllm = 12,
+ .plln = 336,
+ .pllp = 2,
+ .pllq = 7,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_5WS,
+ .apb1_frequency = 42000000,
+ .apb2_frequency = 84000000,
+ },
+};
+
+const clock_scale_t hse_16mhz_3v3[CLOCK_3V3_END] = {
+ { /* 48MHz */
+ .pllm = 16,
+ .plln = 96,
+ .pllp = 2,
+ .pllq = 2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 12000000,
+ .apb2_frequency = 24000000,
+ },
+ { /* 120MHz */
+ .pllm = 16,
+ .plln = 240,
+ .pllp = 2,
+ .pllq = 5,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 30000000,
+ .apb2_frequency = 60000000,
+ },
+ { /* 168MHz */
+ .pllm = 16,
+ .plln = 336,
+ .pllp = 2,
+ .pllq = 7,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_5WS,
+ .apb1_frequency = 42000000,
+ .apb2_frequency = 84000000,
+ },
+};
+
+void rcc_osc_ready_int_clear(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYIE;
+ break;
+ }
+}
+
+int rcc_osc_ready_int_flag(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case HSE:
+ return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case HSI:
+ return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case LSE:
+ return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ }
+
+ cm3_assert_not_reached();
+}
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+void rcc_wait_for_osc_ready(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) == 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) == 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) == 0);
+ break;
+ case LSE:
+ while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
+ break;
+ }
+}
+
+void rcc_wait_for_sysclk_status(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_PLL);
+ break;
+ case HSE:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSE);
+ break;
+ case HSI:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_HSI);
+ break;
+ default:
+ /* Shouldn't be reached. */
+ break;
+ }
+}
+
+void rcc_osc_on(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_osc_off(enum rcc_osc osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR &= ~RCC_CR_PLLON;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+void rcc_osc_bypass_enable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR |= RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_osc_bypass_disable(enum rcc_osc osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_BDCR &= ~RCC_BDCR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+
+
+void rcc_set_sysclk_source(uint32_t clk)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 1) | (1 << 0));
+ RCC_CFGR = (reg32 | clk);
+}
+
+void rcc_set_pll_source(uint32_t pllsrc)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_PLLCFGR;
+ reg32 &= ~(1 << 22);
+ RCC_PLLCFGR = (reg32 | (pllsrc << 22));
+}
+
+void rcc_set_ppre2(uint32_t ppre2)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15));
+ RCC_CFGR = (reg32 | (ppre2 << 13));
+}
+
+void rcc_set_ppre1(uint32_t ppre1)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12));
+ RCC_CFGR = (reg32 | (ppre1 << 10));
+}
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
+ RCC_CFGR = (reg32 | (hpre << 4));
+}
+
+void rcc_set_rtcpre(uint32_t rtcpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20));
+ RCC_CFGR = (reg32 | (rtcpre << 16));
+}
+
+void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp,
+ uint32_t pllq)
+{
+ RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
+ (plln << RCC_PLLCFGR_PLLN_SHIFT) |
+ (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
+ (pllq << RCC_PLLCFGR_PLLQ_SHIFT);
+}
+
+void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp,
+ uint32_t pllq)
+{
+ RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
+ (plln << RCC_PLLCFGR_PLLN_SHIFT) |
+ (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
+ RCC_PLLCFGR_PLLSRC |
+ (pllq << RCC_PLLCFGR_PLLQ_SHIFT);
+}
+
+uint32_t rcc_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ return (RCC_CFGR & 0x000c) >> 2;
+}
+
+void rcc_clock_setup_hse_3v3(const clock_scale_t *clock)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_HSI);
+
+ /* Enable external high-speed oscillator 8MHz. */
+ rcc_osc_on(HSE);
+ rcc_wait_for_osc_ready(HSE);
+
+ /* Enable/disable high performance mode */
+ if (!clock->power_save) {
+ pwr_set_vos_scale(SCALE1);
+ } else {
+ pwr_set_vos_scale(SCALE2);
+ }
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre1(clock->ppre1);
+ rcc_set_ppre2(clock->ppre2);
+
+ rcc_set_main_pll_hse(clock->pllm, clock->plln,
+ clock->pllp, clock->pllq);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
+
+ /* Wait for PLL clock to be selected. */
+ rcc_wait_for_sysclk_status(PLL);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+
+ /* Disable internal high-speed oscillator. */
+ rcc_osc_off(HSI);
+}
+
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/f4/rtc.c b/libopencm3/lib/stm32/f4/rtc.c
new file mode 100644
index 0000000..f08ac2b
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/rtc.c
@@ -0,0 +1,97 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32F4xx
+ *
+ * @brief <b>libopencm3 STM32F4xx RTC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 4 March 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/exti.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/rtc.h>
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the wakeup timer
+ @warning You must unlock the registers before using this function
+
+*/
+void rtc_enable_wakeup_timer(void)
+{
+ RTC_CR |= RTC_CR_WUTE | (RTC_CR_OSEL_WAKEUP << RTC_CR_OSEL_SHIFT);
+ rtc_enable_wakeup_timer_interrupt();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the wakeup timer
+ @warning You must unlock the registers before using this function
+
+*/
+void rtc_disable_wakeup_timer(void)
+{
+ RTC_CR &= ~RTC_CR_WUTE;
+ rtc_disable_wakeup_timer_interrupt();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the wakeup timer interrupt
+ @warning You must unlock the registers before using this function
+
+*/
+void rtc_enable_wakeup_timer_interrupt(void)
+{
+ /* FTFM:
+ * To enable the RTC Wakeup interrupt, the following sequence is
+ * required:
+ * 1. Configure and enable the EXTI Line 22 in interrupt mode and
+ * select the rising edge sensitivity.
+ */
+ exti_enable_request(EXTI22);
+ exti_set_trigger(EXTI22, EXTI_TRIGGER_RISING);
+
+ /* 2. Configure and enable the RTC_WKUP IRQ channel in the NVIC. */
+ nvic_enable_irq(NVIC_RTC_WKUP_IRQ);
+ nvic_set_priority(NVIC_RTC_WKUP_IRQ, 1);
+
+ /* 3. Configure the RTC to generate the RTC wakeup timer event. */
+ RTC_CR |= RTC_CR_WUTIE; /* Enable the interrupt */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the wakeup timer interrupt
+ @warning You must unlock the registers before using this function
+
+*/
+void rtc_disable_wakeup_timer_interrupt(void)
+{
+ /* 1. Disable EXTI Line 22 */
+ exti_disable_request(EXTI22);
+
+ /* 2. Disable RTC_WKUP IRQ channel in the NVIC. */
+ nvic_disable_irq(NVIC_RTC_WKUP_IRQ);
+
+ /* 3. Disable RTC wakeup timer event. */
+ RTC_CR &= ~RTC_CR_WUTIE;
+}
diff --git a/libopencm3/lib/stm32/f4/spi.c b/libopencm3/lib/stm32/f4/spi.c
new file mode 100644
index 0000000..c8a6b41
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx SPI</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/f4/stm32f405x6.ld b/libopencm3/lib/stm32/f4/stm32f405x6.ld
new file mode 100644
index 0000000..a8733f3
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/stm32f405x6.ld
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ * Copyright (C) 2013 Sergey Krukowski <softsr@yahoo.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for the STM32F405RGT6 chip (1024K flash, 128K RAM). */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f4.ld
+
diff --git a/libopencm3/lib/stm32/f4/timer.c b/libopencm3/lib/stm32/f4/timer.c
new file mode 100644
index 0000000..72ecd8d
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/timer.c
@@ -0,0 +1,38 @@
+/* This file is used for documentation purposes. It does not need
+to be compiled. All source code is in the common area.
+If there is any device specific code required it can be included here,
+in which case this file must be added to the compile list. */
+
+/** @defgroup timer_file Timers
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx Timers</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/timer.h>
diff --git a/libopencm3/lib/stm32/f4/usart.c b/libopencm3/lib/stm32/f4/usart.c
new file mode 100644
index 0000000..06254c9
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/usart.c
@@ -0,0 +1,31 @@
+/** @defgroup usart_file USART
+
+@ingroup STM32F4xx
+
+@brief <b>libopencm3 STM32F4xx USART</b>
+
+@version 1.0.0
+
+@date 30 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
diff --git a/libopencm3/lib/stm32/f4/vector_chipset.c b/libopencm3/lib/stm32/f4/vector_chipset.c
new file mode 100644
index 0000000..145be05
--- /dev/null
+++ b/libopencm3/lib/stm32/f4/vector_chipset.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+ * Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/scb.h>
+
+static void pre_main(void)
+{
+ /* Enable access to Floating-Point coprocessor. */
+ SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
+}
diff --git a/libopencm3/lib/stm32/l1/Makefile b/libopencm3/lib/stm32/l1/Makefile
new file mode 100644
index 0000000..00f4ba1
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/Makefile
@@ -0,0 +1,52 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+LIBNAME = libopencm3_stm32l1
+SRCLIBDIR ?= ../..
+
+PREFIX ?= arm-none-eabi
+
+CC = $(PREFIX)-gcc
+AR = $(PREFIX)-ar
+CFLAGS = -Os -g \
+ -Wall -Wextra -Wimplicit-function-declaration \
+ -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
+ -Wundef -Wshadow \
+ -I../../../include -fno-common \
+ -mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
+ -ffunction-sections -fdata-sections -MD -DSTM32L1
+# ARFLAGS = rcsv
+ARFLAGS = rcs
+OBJS = crc.o desig.o flash.o rcc.o usart.o dma.o lcd.o
+OBJS += crc_common_all.o dac_common_all.o
+OBJS += dma_common_l1f013.o
+OBJS += gpio_common_all.o gpio_common_f0234.o
+OBJS += i2c_common_all.o iwdg_common_all.o
+OBJS += pwr_common_all.o pwr.o rtc_common_l1f024.o
+OBJS += spi_common_all.o spi_common_l1f124.o timer_common_all.o
+OBJS += usart_common_all.o usart_common_f124.o
+OBJS += exti_common_all.o
+OBJS += rcc_common_all.o
+OBJS += usb.o usb_control.o usb_standard.o usb_f103.o
+OBJS += adc.o adc_common_v1.o
+
+VPATH += ../../usb:../:../../cm3:../common
+
+include ../../Makefile.include
+
diff --git a/libopencm3/lib/stm32/l1/adc.c b/libopencm3/lib/stm32/l1/adc.c
new file mode 100644
index 0000000..b3ca8a6
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/adc.c
@@ -0,0 +1,201 @@
+/** @defgroup adc_file ADC
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx Analog to Digital Converters</b>
+
+@author @htmlonly &copy; @endhtmlonly 2014 Karl Palsson <karlp@tweak.net.au>
+
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/adc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Power On
+
+If the ADC is in power-down mode then it is powered up. The application needs
+to wait a time of about 3 microseconds for stabilization before using the ADC.
+If the ADC is already on this function call will have no effect.
+ * NOTE Common with F4 and F2
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_power_on(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_ADON;
+}
+
+
+/*----------------------------------------------------------------------------*/
+
+/** @brief ADC Set the Sample Time for a Single Channel
+
+The sampling time can be selected in ADC clock cycles from 4 to 384.
+
+@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
+@param[in] channel uint8. ADC Channel integer 0..18 or from @ref adc_channel.
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
+ */
+void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
+{
+ uint32_t reg32;
+
+ if (channel < 10) {
+ reg32 = ADC_SMPR3(adc);
+ reg32 &= ~(0x7 << (channel * 3));
+ reg32 |= (time << (channel * 3));
+ ADC_SMPR3(adc) = reg32;
+ } else if (channel < 20) {
+ reg32 = ADC_SMPR2(adc);
+ reg32 &= ~(0x7 << ((channel - 10) * 3));
+ reg32 |= (time << ((channel - 10) * 3));
+ ADC_SMPR2(adc) = reg32;
+ } else {
+ reg32 = ADC_SMPR1(adc);
+ reg32 &= ~(0x7 << ((channel - 20) * 3));
+ reg32 |= (time << ((channel - 20) * 3));
+ ADC_SMPR1(adc) = reg32;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+
+The sampling time can be selected in ADC clock cycles, same for
+all channels.
+
+@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
+*/
+
+void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
+{
+ uint8_t i;
+ uint32_t reg32 = 0;
+
+ for (i = 0; i <= 9; i++) {
+ reg32 |= (time << (i * 3));
+ }
+ ADC_SMPR0(adc) = reg32;
+ ADC_SMPR1(adc) = reg32;
+ ADC_SMPR2(adc) = reg32;
+ ADC_SMPR3(adc) = reg32;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+
+This enables both the sensor and the reference voltage measurements on channels
+16 and 17.
+
+*/
+void adc_enable_temperature_sensor()
+{
+ ADC_CCR |= ADC_CCR_TSVREFE;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+
+Disabling this will reduce power consumption from the sensor and the reference
+voltage measurements.
+
+*/
+void adc_disable_temperature_sensor()
+{
+ ADC_CCR &= ~ADC_CCR_TSVREFE;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_external_trigger_regular(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_EXTEN_MASK;
+}
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Injected Channels
+
+@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
+*/
+
+void adc_disable_external_trigger_injected(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_JEXTEN_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+
+This enables an external trigger for set of defined regular channels, and sets
+the polarity of the trigger event: rising or falling edge or both. Note that if
+the trigger polarity is zero, triggering is disabled.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int32. Trigger identifier @ref adc_trigger_regular
+@param[in] polarity Unsigned int32. Trigger polarity @ref
+adc_trigger_polarity_regular
+*/
+
+void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_CR2(adc);
+
+ reg32 &= ~(ADC_CR2_EXTSEL_MASK | ADC_CR2_EXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_CR2(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Injected Channels
+
+This enables an external trigger for set of defined injected channels, and sets
+the polarity of the trigger event: rising or falling edge or both.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected
+@param[in] polarity Unsigned int32. Trigger polarity @ref
+adc_trigger_polarity_injected
+*/
+
+void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger,
+ uint32_t polarity)
+{
+ uint32_t reg32 = ADC_CR2(adc);
+
+ reg32 &= ~(ADC_CR2_JEXTSEL_MASK | ADC_CR2_JEXTEN_MASK);
+ reg32 |= (trigger | polarity);
+ ADC_CR2(adc) = reg32;
+}
+
+/**@}*/
+
+
diff --git a/libopencm3/lib/stm32/l1/crc.c b/libopencm3/lib/stm32/l1/crc.c
new file mode 100644
index 0000000..8a71c89
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/crc.c
@@ -0,0 +1,33 @@
+/** @defgroup crc_file CRC
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx CRC</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/crc.h>
+
+
diff --git a/libopencm3/lib/stm32/l1/dac.c b/libopencm3/lib/stm32/l1/dac.c
new file mode 100644
index 0000000..ed118b4
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/dac.c
@@ -0,0 +1,31 @@
+/** @defgroup dac_file DAC
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx DAC</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dac.h>
diff --git a/libopencm3/lib/stm32/l1/dma.c b/libopencm3/lib/stm32/l1/dma.c
new file mode 100644
index 0000000..6f4622d
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/dma.c
@@ -0,0 +1,31 @@
+/** @defgroup dma_file DMA
+ *
+ * @ingroup STM32L1xx
+ *
+ * @brief <b>libopencm3 STM32L1xx DMA</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 10 July 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/dma.h>
diff --git a/libopencm3/lib/stm32/l1/flash.c b/libopencm3/lib/stm32/l1/flash.c
new file mode 100644
index 0000000..fdd2cca
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/flash.c
@@ -0,0 +1,208 @@
+/** @defgroup flash_file FLASH
+ *
+ * @ingroup STM32L1xx
+ *
+ * @brief <b>libopencm3 STM32L1xx FLASH</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Thomas Otto <tommi@viadmin.org>
+ * @author @htmlonly &copy; @endhtmlonly 2010
+ * Mark Butler <mbutler@physics.otago.ac.nz>
+ * @author @htmlonly &copy; @endhtmlonly 2012
+ * Karl Palsson <karlp@tweak.net.au>
+ *
+ * @date 14 January 2014
+ *
+ * For the STM32L1xx, accessing FLASH memory is described briefly in
+ * section 2.3.3 of the STM32L1xx Reference Manual.
+ * For detailed programming information see:
+ * PM0062 programming manual: STM32L1xxxx Flash and EEPROM programming
+ * March 2012, Doc ID 16024 Rev 5
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ * Copyright (C) 2012-13 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/flash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable 64 Bit Programming Mode
+
+*/
+
+void flash_64bit_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_ACC64;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable 32 Bit Programming Mode
+
+This mode is a low power mode. It must be used at low frequencies and does not
+allow prefetch or wait states to be used.
+*/
+
+void flash_64bit_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_ACC64;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the FLASH Prefetch Buffer
+
+This buffer is used for instruction fetches and is enabled by default after
+reset.
+
+Note carefully the restrictions under which the prefetch buffer may be
+enabled or disabled. Prefetch is only available when 64-bit
+access is enabled.
+*/
+
+void flash_prefetch_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Prefetch Buffer
+
+Note carefully the restrictions under which the prefetch buffer may be
+set to disabled. See the reference and programming manuals for details.
+*/
+
+void flash_prefetch_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Number of Wait States
+
+Used to match the system clock to the FLASH memory access time. See the
+programming manual for more information on clock speed and voltage ranges. The
+latency must be changed to the appropriate value <b>before</b> any increase in
+clock speed, or <b>after</b> any decrease in clock speed. A latency setting of
+zero only applies if 64-bit mode is not used.
+
+@param[in] uint32_t ws: values from @ref flash_latency.
+*/
+
+void flash_set_ws(uint32_t ws)
+{
+ uint32_t reg32;
+
+ reg32 = FLASH_ACR;
+ reg32 &= ~(1 << 0);
+ reg32 |= ws;
+ FLASH_ACR = reg32;
+}
+
+void flash_unlock_pecr(void) {
+ FLASH_PEKEYR = FLASH_PEKEYR_PEKEY1;
+ FLASH_PEKEYR = FLASH_PEKEYR_PEKEY2;
+}
+
+void flash_lock_pecr(void) {
+ FLASH_PECR |= FLASH_PECR_PELOCK;
+}
+
+void flash_unlock_progmem(void) {
+ flash_unlock_pecr();
+ FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY1;
+ FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY2;
+}
+
+void flash_lock_progmem(void) {
+ FLASH_PECR |= FLASH_PECR_PRGLOCK;
+}
+
+void flash_unlock_option_bytes(void) {
+ flash_unlock_pecr();
+ FLASH_OPTKEYR = FLASH_OPTKEYR_OPTKEY1;
+ FLASH_OPTKEYR = FLASH_OPTKEYR_OPTKEY2;
+}
+
+void flash_lock_option_bytes(void) {
+ FLASH_PECR |= FLASH_PECR_OPTLOCK;
+}
+
+/** @brief Unlock all segments of flash
+ *
+ */
+void flash_unlock(void) {
+ flash_unlock_pecr();
+ flash_unlock_progmem();
+ flash_unlock_option_bytes();
+}
+
+/** @brief Lock all segments of flash
+ *
+ */
+void flash_lock(void) {
+ flash_lock_option_bytes();
+ flash_lock_progmem();
+ flash_lock_pecr();
+}
+
+/** @brief Write a word to eeprom
+ *
+ * @param address assumed to be in the eeprom space, no checking
+ * @param data word to write
+ */
+void eeprom_program_word(uint32_t address, uint32_t data) {
+ flash_unlock_pecr();
+ /* erase only if needed */
+ FLASH_PECR &= ~FLASH_PECR_FTDW;
+ MMIO32(address) = data;
+ flash_lock_pecr();
+}
+
+/** @brief Write a block of words to eeprom
+ *
+ * Writes a block of words to EEPROM at the requested address, erasing if necessary,
+ * and locking afterwards. Only wordwise writing is safe for writing any value
+ *
+ * @param[in] address must point to EEPROM space, no checking!
+ * @param[in] data pointer to data to write
+ * @param[in] length size of of data in WORDS!
+ * */
+void eeprom_program_words(uint32_t address, uint32_t *data, int length_in_words)
+{
+ int i;
+ flash_unlock_pecr();
+ while (FLASH_SR & FLASH_SR_BSY);
+ /* erase only if needed */
+ FLASH_PECR &= ~FLASH_PECR_FTDW;
+ for (i = 0; i < length_in_words; i++) {
+ MMIO32(address + (i * sizeof(uint32_t))) = *(data+i);
+ while (FLASH_SR & FLASH_SR_BSY);
+ }
+ flash_lock_pecr();
+}
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/l1/gpio.c b/libopencm3/lib/stm32/l1/gpio.c
new file mode 100644
index 0000000..46ea658
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/gpio.c
@@ -0,0 +1,31 @@
+/** @defgroup gpio_file GPIO
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/gpio.h>
diff --git a/libopencm3/lib/stm32/l1/i2c.c b/libopencm3/lib/stm32/l1/i2c.c
new file mode 100644
index 0000000..2390c96
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/i2c.c
@@ -0,0 +1,31 @@
+/** @defgroup i2c_file I2C
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx I2C</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/i2c.h>
diff --git a/libopencm3/lib/stm32/l1/iwdg.c b/libopencm3/lib/stm32/l1/iwdg.c
new file mode 100644
index 0000000..1f37fe8
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/iwdg.c
@@ -0,0 +1,31 @@
+/** @defgroup iwdg_file IWDG
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx Independent Watchdog Timer</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/iwdg.h>
diff --git a/libopencm3/lib/stm32/l1/lcd.c b/libopencm3/lib/stm32/l1/lcd.c
new file mode 100644
index 0000000..68173ab
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/lcd.c
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Nikolay Merinov <nikolay.merinov@member.fsf.org>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/l1/lcd.h>
+#include <libopencm3/stm32/rcc.h>
+
+void lcd_enable(void)
+{
+ LCD_CR |= LCD_CR_LCDEN;
+}
+
+void lcd_update(void)
+{
+ LCD_SR |= LCD_SR_UDR;
+}
+
+void lcd_wait_for_lcd_enabled(void)
+{
+ while ((LCD_SR & LCD_SR_ENS) == 0);
+}
+
+void lcd_wait_for_step_up_ready(void)
+{
+ while ((LCD_SR & LCD_SR_RDY) == 0);
+}
+
+void lcd_wait_for_update_ready(void)
+{
+ while ((LCD_SR & LCD_SR_UDR) != 0);
+}
+
+int lcd_is_enabled(void)
+{
+ return ((LCD_SR & LCD_SR_ENS) != 0);
+}
+
+int lcd_is_step_up_ready(void)
+{
+ return ((LCD_SR & LCD_SR_RDY) != 0);
+}
+
+int lcd_is_for_update_ready(void)
+{
+ return ((LCD_SR & LCD_SR_UDR) == 0);
+}
+
+void lcd_set_contrast(uint8_t contrast)
+{
+ LCD_FCR &= ~(LCD_FCR_CC_MASK << LCD_FCR_CC_SHIFT);
+ LCD_FCR |= contrast << LCD_FCR_CC_SHIFT;
+}
+
+void lcd_set_bias(uint8_t bias)
+{
+ LCD_CR &= ~(LCD_CR_BIAS_MASK << LCD_CR_BIAS_SHIFT);
+ LCD_CR |= bias << LCD_CR_BIAS_SHIFT;
+}
+
+void lcd_set_duty(uint8_t duty)
+{
+ LCD_CR &= ~(LCD_CR_DUTY_MASK << LCD_CR_DUTY_SHIFT);
+ LCD_CR |= duty << LCD_CR_DUTY_SHIFT;
+}
+
+void lcd_set_prescaler(uint8_t ps)
+{
+ LCD_FCR &= ~(LCD_FCR_PS_MASK << LCD_FCR_PS_SHIFT);
+ LCD_FCR |= ps << LCD_FCR_PS_SHIFT;
+}
+
+void lcd_set_divider(uint8_t div)
+{
+ LCD_FCR &= ~(LCD_FCR_DIV_MASK << LCD_FCR_DIV_SHIFT);
+ LCD_FCR |= div << LCD_FCR_DIV_SHIFT;
+}
+
+void lcd_enable_segment_multiplexing(void)
+{
+ LCD_CR |= LCD_CR_MUX_SEG;
+}
+
+void lcd_disable_segment_multiplexing(void)
+{
+ LCD_CR &= ~LCD_CR_MUX_SEG;
+}
+
+void lcd_set_refresh_frequency(uint32_t frequency)
+{
+ uint32_t duty, lcd_clock;
+ switch ((LCD_CR >> LCD_CR_DUTY_SHIFT) & LCD_CR_DUTY_MASK) {
+ case LCD_CR_DUTY_STATIC:
+ duty = 1;
+ break;
+ case LCD_CR_DUTY_1_2:
+ duty = 2;
+ break;
+ case LCD_CR_DUTY_1_3:
+ duty = 3;
+ break;
+ case LCD_CR_DUTY_1_4:
+ duty = 4;
+ break;
+ case LCD_CR_DUTY_1_8:
+ duty = 8;
+ break;
+ default:
+ /* Incorrect duty */
+ return;
+ }
+
+ switch ((RCC_CSR >> RCC_CSR_RTCSEL_SHIFT) & RCC_CSR_RTCSEL_MASK) {
+ case RCC_CSR_RTCSEL_LSE:
+ lcd_clock = 32786;
+ break;
+ case RCC_CSR_RTCSEL_LSI:
+ lcd_clock = 37000;
+ break;
+ case RCC_CSR_RTCSEL_HSI:
+ lcd_clock = 16000000;
+ break;
+ default:
+ /* RCC Clock not selected */
+ return;
+ }
+
+ /* PS * DIV = lcd_clock/(duty * freq) */
+ uint32_t ps_mul_div = lcd_clock / (duty * frequency);
+
+ int div, ps = 0;
+ while (ps_mul_div > 32) {
+ ps_mul_div >>= 1;
+ ps++;
+ }
+ div = ps_mul_div - 16;
+
+ lcd_set_prescaler(ps);
+ lcd_set_divider(div);
+}
diff --git a/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld b/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld
new file mode 100644
index 0000000..3fc2ccb
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/libopencm3_stm32l1.ld
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Generic linker script for STM32 targets using libopencm3. */
+
+/* Memory regions must be defined in the ld script which includes this one. */
+
+/* Enforce emmition of the vector table. */
+EXTERN (vector_table)
+
+/* Define the entry point of the output file. */
+ENTRY(reset_handler)
+
+/* Define sections. */
+SECTIONS
+{
+ .text : {
+ *(.vectors) /* Vector table */
+ *(.text*) /* Program code */
+ . = ALIGN(4);
+ *(.rodata*) /* Read-only data */
+ . = ALIGN(4);
+ } >rom
+
+ /* C++ Static constructors/destructors, also used for __attribute__
+ * ((constructor)) and the likes */
+ .preinit_array : {
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ } >rom
+ .init_array : {
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ } >rom
+ .fini_array : {
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } >rom
+
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*) /* Read-write initialized data */
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*) /* Read-write zero initialized data */
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
+
diff --git a/libopencm3/lib/stm32/l1/pwr.c b/libopencm3/lib/stm32/l1/pwr.c
new file mode 100644
index 0000000..64210d5
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/pwr.c
@@ -0,0 +1,58 @@
+/** @defgroup pwr_file PWR
+ *
+ * @ingroup STM32L1xx
+ *
+ * @brief <b>libopencm3 STM32L1xx Power Control</b>
+ *
+ * @version 1.0.0
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * @date 4 March 2013
+ *
+ * This library supports the power control system for the
+ * STM32L1 series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/pwr.h>
+#include <libopencm3/stm32/rcc.h>
+
+void pwr_set_vos_scale(vos_scale_t scale)
+{
+ /* You are not allowed to write zeros here, don't try and optimize! */
+ uint32_t reg = PWR_CR;
+ reg &= ~(PWR_CR_VOS_MASK);
+ switch (scale) {
+ case RANGE1:
+ reg |= PWR_CR_VOS_RANGE1;
+ break;
+ case RANGE2:
+ reg |= PWR_CR_VOS_RANGE2;
+ break;
+ case RANGE3:
+ reg |= PWR_CR_VOS_RANGE3;
+ break;
+ }
+ PWR_CR = reg;
+}
+
diff --git a/libopencm3/lib/stm32/l1/rcc.c b/libopencm3/lib/stm32/l1/rcc.c
new file mode 100644
index 0000000..4efd789
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/rcc.c
@@ -0,0 +1,534 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * Based on the F4 code...
+ */
+
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+#include <libopencm3/stm32/pwr.h>
+
+/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
+uint32_t rcc_ppre1_frequency = 2097000;
+uint32_t rcc_ppre2_frequency = 2097000;
+
+const clock_scale_t clock_config[CLOCK_CONFIG_END] = {
+ { /* 24MHz PLL from HSI */
+ .pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
+ .pll_mul = RCC_CFGR_PLLMUL_MUL3,
+ .pll_div = RCC_CFGR_PLLDIV_DIV2,
+ .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_1WS,
+ .apb1_frequency = 24000000,
+ .apb2_frequency = 24000000,
+ },
+ { /* 32MHz PLL from HSI */
+ .pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
+ .pll_mul = RCC_CFGR_PLLMUL_MUL6,
+ .pll_div = RCC_CFGR_PLLDIV_DIV3,
+ .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_1WS,
+ .apb1_frequency = 32000000,
+ .apb2_frequency = 32000000,
+ },
+ { /* 16MHz HSI raw */
+ .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_0WS,
+ .apb1_frequency = 16000000,
+ .apb2_frequency = 16000000,
+ },
+ { /* 4MHz HSI raw */
+ .hpre = RCC_CFGR_HPRE_SYSCLK_DIV4,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_0WS,
+ .apb1_frequency = 4000000,
+ .apb2_frequency = 4000000,
+ },
+ { /* 4MHz MSI raw */
+ .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_0WS,
+ .apb1_frequency = 4194000,
+ .apb2_frequency = 4194000,
+ .msi_range = RCC_ICSCR_MSIRANGE_4MHZ,
+ },
+ { /* 2MHz MSI raw */
+ .hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
+ .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
+ .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
+ .voltage_scale = RANGE1,
+ .flash_config = FLASH_ACR_LATENCY_0WS,
+ .apb1_frequency = 2097000,
+ .apb2_frequency = 2097000,
+ .msi_range = RCC_ICSCR_MSIRANGE_2MHZ,
+ },
+};
+
+void rcc_osc_ready_int_clear(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYC;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYC;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYC;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYC;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYC;
+ break;
+ case MSI:
+ RCC_CIR |= RCC_CIR_MSIRDYC;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_enable(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR |= RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR |= RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR |= RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR |= RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR |= RCC_CIR_LSIRDYIE;
+ break;
+ case MSI:
+ RCC_CIR |= RCC_CIR_MSIRDYIE;
+ break;
+ }
+}
+
+void rcc_osc_ready_int_disable(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CIR &= ~RCC_CIR_PLLRDYIE;
+ break;
+ case HSE:
+ RCC_CIR &= ~RCC_CIR_HSERDYIE;
+ break;
+ case HSI:
+ RCC_CIR &= ~RCC_CIR_HSIRDYIE;
+ break;
+ case LSE:
+ RCC_CIR &= ~RCC_CIR_LSERDYIE;
+ break;
+ case LSI:
+ RCC_CIR &= ~RCC_CIR_LSIRDYIE;
+ break;
+ case MSI:
+ RCC_CIR &= ~RCC_CIR_MSIRDYIE;
+ break;
+ }
+}
+
+int rcc_osc_ready_int_flag(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
+ break;
+ case HSE:
+ return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
+ break;
+ case HSI:
+ return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
+ break;
+ case LSE:
+ return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
+ break;
+ case LSI:
+ return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
+ break;
+ case MSI:
+ return ((RCC_CIR & RCC_CIR_MSIRDYF) != 0);
+ break;
+ }
+
+ /* Shouldn't be reached. */
+ return -1;
+}
+
+void rcc_css_int_clear(void)
+{
+ RCC_CIR |= RCC_CIR_CSSC;
+}
+
+int rcc_css_int_flag(void)
+{
+ return ((RCC_CIR & RCC_CIR_CSSF) != 0);
+}
+
+void rcc_wait_for_osc_ready(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CR & RCC_CR_PLLRDY) == 0);
+ break;
+ case HSE:
+ while ((RCC_CR & RCC_CR_HSERDY) == 0);
+ break;
+ case HSI:
+ while ((RCC_CR & RCC_CR_HSIRDY) == 0);
+ break;
+ case MSI:
+ while ((RCC_CR & RCC_CR_MSIRDY) == 0);
+ break;
+ case LSE:
+ while ((RCC_CSR & RCC_CSR_LSERDY) == 0);
+ break;
+ case LSI:
+ while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
+ break;
+ }
+}
+
+void rcc_wait_for_sysclk_status(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) !=
+ RCC_CFGR_SWS_SYSCLKSEL_PLLCLK);
+ break;
+ case HSE:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) !=
+ RCC_CFGR_SWS_SYSCLKSEL_HSECLK);
+ break;
+ case HSI:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) !=
+ RCC_CFGR_SWS_SYSCLKSEL_HSICLK);
+ break;
+ case MSI:
+ while ((RCC_CFGR & ((1 << 1) | (1 << 0))) !=
+ RCC_CFGR_SWS_SYSCLKSEL_MSICLK);
+ break;
+ default:
+ /* Shouldn't be reached. */
+ break;
+ }
+}
+
+void rcc_osc_on(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR |= RCC_CR_PLLON;
+ break;
+ case MSI:
+ RCC_CR |= RCC_CR_MSION;
+ break;
+ case HSE:
+ RCC_CR |= RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR |= RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_CSR |= RCC_CSR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR |= RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_osc_off(osc_t osc)
+{
+ switch (osc) {
+ case PLL:
+ RCC_CR &= ~RCC_CR_PLLON;
+ break;
+ case MSI:
+ RCC_CR &= ~RCC_CR_MSION;
+ break;
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEON;
+ break;
+ case HSI:
+ RCC_CR &= ~RCC_CR_HSION;
+ break;
+ case LSE:
+ RCC_CSR &= ~RCC_CSR_LSEON;
+ break;
+ case LSI:
+ RCC_CSR &= ~RCC_CSR_LSION;
+ break;
+ }
+}
+
+void rcc_css_enable(void)
+{
+ RCC_CR |= RCC_CR_CSSON;
+}
+
+void rcc_css_disable(void)
+{
+ RCC_CR &= ~RCC_CR_CSSON;
+}
+
+void rcc_osc_bypass_enable(osc_t osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR |= RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_CSR |= RCC_CSR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ case MSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_osc_bypass_disable(osc_t osc)
+{
+ switch (osc) {
+ case HSE:
+ RCC_CR &= ~RCC_CR_HSEBYP;
+ break;
+ case LSE:
+ RCC_CSR &= ~RCC_CSR_LSEBYP;
+ break;
+ case PLL:
+ case HSI:
+ case LSI:
+ case MSI:
+ /* Do nothing, only HSE/LSE allowed here. */
+ break;
+ }
+}
+
+void rcc_set_sysclk_source(uint32_t clk)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 1) | (1 << 0));
+ RCC_CFGR = (reg32 | clk);
+}
+
+void rcc_set_pll_configuration(uint32_t source, uint32_t multiplier,
+ uint32_t divisor)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~(RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT);
+ reg32 &= ~(RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT);
+ reg32 &= ~(1 << 16);
+ reg32 |= (source << 16);
+ reg32 |= (multiplier << RCC_CFGR_PLLMUL_SHIFT);
+ reg32 |= (divisor << RCC_CFGR_PLLDIV_SHIFT);
+ RCC_CFGR = reg32;
+}
+
+void rcc_set_pll_source(uint32_t pllsrc)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~(1 << 16);
+ RCC_CFGR = (reg32 | (pllsrc << 16));
+}
+
+void rcc_set_ppre2(uint32_t ppre2)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 13) | (1 << 12) | (1 << 11));
+ RCC_CFGR = (reg32 | (ppre2 << 11));
+}
+
+void rcc_set_ppre1(uint32_t ppre1)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 10) | (1 << 9) | (1 << 8));
+ RCC_CFGR = (reg32 | (ppre1 << 8));
+}
+
+void rcc_set_hpre(uint32_t hpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CFGR;
+ reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
+ RCC_CFGR = (reg32 | (hpre << 4));
+}
+
+void rcc_set_rtcpre(uint32_t rtcpre)
+{
+ uint32_t reg32;
+
+ reg32 = RCC_CR;
+ reg32 &= ~((1 << 30) | (1 << 29));
+ RCC_CR = (reg32 | (rtcpre << 29));
+}
+
+uint32_t rcc_system_clock_source(void)
+{
+ /* Return the clock source which is used as system clock. */
+ return (RCC_CFGR & 0x000c) >> 2;
+}
+
+void rcc_rtc_select_clock(uint32_t clock)
+{
+ RCC_CSR &= ~(RCC_CSR_RTCSEL_MASK << RCC_CSR_RTCSEL_SHIFT);
+ RCC_CSR |= (clock << RCC_CSR_RTCSEL_SHIFT);
+}
+
+void rcc_clock_setup_msi(const clock_scale_t *clock)
+{
+ /* Enable internal multi-speed oscillator. */
+
+ uint32_t reg = RCC_ICSCR;
+ reg &= ~(RCC_ICSCR_MSIRANGE_MASK << RCC_ICSCR_MSIRANGE_SHIFT);
+ reg |= (clock->msi_range << RCC_ICSCR_MSIRANGE_SHIFT);
+ RCC_ICSCR = reg;
+
+ rcc_osc_on(MSI);
+ rcc_wait_for_osc_ready(MSI);
+
+ /* Select MSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_MSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre1(clock->ppre1);
+ rcc_set_ppre2(clock->ppre2);
+
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
+ pwr_set_vos_scale(clock->voltage_scale);
+
+ /* I guess this should be in the settings? */
+ flash_64bit_enable();
+ flash_prefetch_enable();
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+}
+
+void rcc_clock_setup_hsi(const clock_scale_t *clock)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre1(clock->ppre1);
+ rcc_set_ppre2(clock->ppre2);
+
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
+ pwr_set_vos_scale(clock->voltage_scale);
+
+ /* I guess this should be in the settings? */
+ flash_64bit_enable();
+ flash_prefetch_enable();
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+}
+
+void rcc_clock_setup_pll(const clock_scale_t *clock)
+{
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(clock->hpre);
+ rcc_set_ppre1(clock->ppre1);
+ rcc_set_ppre2(clock->ppre2);
+
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
+ pwr_set_vos_scale(clock->voltage_scale);
+
+ /* I guess this should be in the settings? */
+ flash_64bit_enable();
+ flash_prefetch_enable();
+ /* Configure flash settings. */
+ flash_set_ws(clock->flash_config);
+
+ rcc_set_pll_configuration(clock->pll_source, clock->pll_mul,
+ clock->pll_div);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_ppre1_frequency = clock->apb1_frequency;
+ rcc_ppre2_frequency = clock->apb2_frequency;
+}
diff --git a/libopencm3/lib/stm32/l1/rtc.c b/libopencm3/lib/stm32/l1/rtc.c
new file mode 100644
index 0000000..5628aa7
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/rtc.c
@@ -0,0 +1,31 @@
+/** @defgroup rtc_file RTC
+ *
+ * @ingroup STM32L1xx
+ *
+ * @brief <b>libopencm3 STM32L1xx RTC</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 4 March 2013
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/rtc.h>
diff --git a/libopencm3/lib/stm32/l1/spi.c b/libopencm3/lib/stm32/l1/spi.c
new file mode 100644
index 0000000..05969fb
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/spi.c
@@ -0,0 +1,31 @@
+/** @defgroup spi_file SPI
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx SPI</b>
+
+@version 1.0.0
+
+@date 15 October 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
diff --git a/libopencm3/lib/stm32/l1/stm32l15xx6.ld b/libopencm3/lib/stm32/l1/stm32l15xx6.ld
new file mode 100644
index 0000000..a72a5d8
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/stm32l15xx6.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32L15xx6, 32K flash, 10K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K
+ eep (r) : ORIGIN = 0x08080000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32l1.ld
+
diff --git a/libopencm3/lib/stm32/l1/stm32l15xx8.ld b/libopencm3/lib/stm32/l1/stm32l15xx8.ld
new file mode 100644
index 0000000..656779b
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/stm32l15xx8.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32L15xx8, 64K flash, 10K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K
+ eep (r) : ORIGIN = 0x08080000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32l1.ld
+
diff --git a/libopencm3/lib/stm32/l1/stm32l15xxb.ld b/libopencm3/lib/stm32/l1/stm32l15xxb.ld
new file mode 100644
index 0000000..be81f37
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/stm32l15xxb.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32L15xxB, 128K flash, 16K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
+ eep (r) : ORIGIN = 0x08080000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32l1.ld
+
diff --git a/libopencm3/lib/stm32/l1/stm32l15xxc.ld b/libopencm3/lib/stm32/l1/stm32l15xxc.ld
new file mode 100644
index 0000000..651aed3
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/stm32l15xxc.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32L15xxC, 256k flash, 32K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
+ eep (r) : ORIGIN = 0x08080000, LENGTH = 8K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32l1.ld
+
diff --git a/libopencm3/lib/stm32/l1/stm32l15xxd.ld b/libopencm3/lib/stm32/l1/stm32l15xxd.ld
new file mode 100644
index 0000000..4b93c9b
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/stm32l15xxd.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Karl Palsson <karlp@tweak.net.au>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for STM32L15xxD, 384K flash, 38K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
+ eep (r) : ORIGIN = 0x08080000, LENGTH = 12K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32l1.ld
+
diff --git a/libopencm3/lib/stm32/l1/timer.c b/libopencm3/lib/stm32/l1/timer.c
new file mode 100644
index 0000000..ab69c62
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/timer.c
@@ -0,0 +1,59 @@
+/** @defgroup timer_file Timers
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx Timers</b>
+
+@version 1.0.0
+
+@date 18 August 2012
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+ * Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/timer.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Option
+
+Set timer options register on TIM2 or TIM3, used for trigger remapping.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM3:
+@ref tim3_opt_trigger_remap.
+*/
+
+void timer_set_option(uint32_t timer_peripheral, uint32_t option)
+{
+ if (timer_peripheral == TIM2) {
+ TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
+ TIM_OR(timer_peripheral) |= option;
+ } else if (timer_peripheral == TIM3) {
+ TIM_OR(timer_peripheral) &= ~TIM3_OR_ITR2_RMP_MASK;
+ TIM_OR(timer_peripheral) |= option;
+ }
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/l1/usart.c b/libopencm3/lib/stm32/l1/usart.c
new file mode 100644
index 0000000..5e357bf
--- /dev/null
+++ b/libopencm3/lib/stm32/l1/usart.c
@@ -0,0 +1,31 @@
+/** @defgroup usart_file USART
+
+@ingroup STM32L1xx
+
+@brief <b>libopencm3 STM32L1xx USART</b>
+
+@version 1.0.0
+
+@date 30 August 2012
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/usart.h>
diff --git a/libopencm3/lib/usb/usb.c b/libopencm3/lib/usb/usb.c
new file mode 100644
index 0000000..7863736
--- /dev/null
+++ b/libopencm3/lib/usb/usb.c
@@ -0,0 +1,175 @@
+/** @defgroup usb_drivers_file Generic USB Drivers
+
+@ingroup USB
+
+@brief <b>Generic USB Drivers</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Gareth McMullin <gareth@blacksphere.co.nz>
+
+@date 10 March 2013
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <string.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+
+/**
+ * Main initialization entry point.
+ *
+ * Initialize the USB firmware library to implement the USB device described
+ * by the descriptors provided.
+ *
+ * It is required that the 48MHz USB clock is already available.
+ *
+ * @param driver TODO
+ * @param dev Pointer to USB device descriptor. This must not be changed while
+ * the device is in use.
+ * @param conf Pointer to array of USB configuration descriptors. These must
+ * not be changed while the device is in use. The length of this
+ * array is determined by the bNumConfigurations field in the
+ * device descriptor.
+ * @param strings TODO
+ * @param control_buffer Pointer to array that would hold the data
+ * received during control requests with DATA
+ * stage
+ * @param control_buffer_size Size of control_buffer
+ * @return Zero on success (currently cannot fail).
+ */
+usbd_device *usbd_init(const usbd_driver *driver,
+ const struct usb_device_descriptor *dev,
+ const struct usb_config_descriptor *conf,
+ const char **strings, int num_strings,
+ uint8_t *control_buffer, uint16_t control_buffer_size)
+{
+ usbd_device *usbd_dev;
+
+ usbd_dev = driver->init();
+
+ usbd_dev->driver = driver;
+ usbd_dev->desc = dev;
+ usbd_dev->config = conf;
+ usbd_dev->strings = strings;
+ usbd_dev->num_strings = num_strings;
+ usbd_dev->ctrl_buf = control_buffer;
+ usbd_dev->ctrl_buf_len = control_buffer_size;
+
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_SETUP] =
+ _usbd_control_setup;
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_OUT] =
+ _usbd_control_out;
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_IN] =
+ _usbd_control_in;
+
+ return usbd_dev;
+}
+
+void usbd_register_reset_callback(usbd_device *usbd_dev, void (*callback)(void))
+{
+ usbd_dev->user_callback_reset = callback;
+}
+
+void usbd_register_suspend_callback(usbd_device *usbd_dev,
+ void (*callback)(void))
+{
+ usbd_dev->user_callback_suspend = callback;
+}
+
+void usbd_register_resume_callback(usbd_device *usbd_dev,
+ void (*callback)(void))
+{
+ usbd_dev->user_callback_resume = callback;
+}
+
+void usbd_register_sof_callback(usbd_device *usbd_dev, void (*callback)(void))
+{
+ usbd_dev->user_callback_sof = callback;
+}
+
+void _usbd_reset(usbd_device *usbd_dev)
+{
+ usbd_dev->current_address = 0;
+ usbd_dev->current_config = 0;
+ usbd_ep_setup(usbd_dev, 0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL);
+ usbd_dev->driver->set_address(usbd_dev, 0);
+
+ if (usbd_dev->user_callback_reset) {
+ usbd_dev->user_callback_reset();
+ }
+}
+
+/* Functions to wrap the low-level driver */
+void usbd_poll(usbd_device *usbd_dev)
+{
+ usbd_dev->driver->poll(usbd_dev);
+}
+
+void usbd_disconnect(usbd_device *usbd_dev, bool disconnected)
+{
+ /* not all drivers support disconnection */
+ if (usbd_dev->driver->disconnect) {
+ usbd_dev->driver->disconnect(usbd_dev, disconnected);
+ }
+}
+
+void usbd_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*callback)(usbd_device *usbd_dev, uint8_t ep))
+{
+ usbd_dev->driver->ep_setup(usbd_dev, addr, type, max_size, callback);
+}
+
+uint16_t usbd_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len)
+{
+ return usbd_dev->driver->ep_write_packet(usbd_dev, addr, buf, len);
+}
+
+uint16_t usbd_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf,
+ uint16_t len)
+{
+ return usbd_dev->driver->ep_read_packet(usbd_dev, addr, buf, len);
+}
+
+void usbd_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall)
+{
+ usbd_dev->driver->ep_stall_set(usbd_dev, addr, stall);
+}
+
+uint8_t usbd_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
+{
+ return usbd_dev->driver->ep_stall_get(usbd_dev, addr);
+}
+
+void usbd_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
+{
+ usbd_dev->driver->ep_nak_set(usbd_dev, addr, nak);
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/usb/usb_control.c b/libopencm3/lib/usb/usb_control.c
new file mode 100644
index 0000000..1b87057
--- /dev/null
+++ b/libopencm3/lib/usb/usb_control.c
@@ -0,0 +1,288 @@
+/** @defgroup usb_control_file Generic USB Control Requests
+
+@ingroup USB
+
+@brief <b>Generic USB Control Requests</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Gareth McMullin <gareth@blacksphere.co.nz>
+
+@date 10 March 2013
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <stdlib.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+
+/*
+ * According to the USB 2.0 specification, section 8.5.3, when a control
+ * transfer is stalled, the pipe becomes idle. We provide one utility to stall
+ * a transaction to reduce boilerplate code.
+ */
+static void stall_transaction(usbd_device *usbd_dev)
+{
+ usbd_ep_stall_set(usbd_dev, 0, 1);
+ usbd_dev->control_state.state = IDLE;
+}
+
+/* Register application callback function for handling USB control requests. */
+int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type,
+ uint8_t type_mask,
+ usbd_control_callback callback)
+{
+ int i;
+
+ for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
+ if (usbd_dev->user_control_callback[i].cb) {
+ continue;
+ }
+
+ usbd_dev->user_control_callback[i].type = type;
+ usbd_dev->user_control_callback[i].type_mask = type_mask;
+ usbd_dev->user_control_callback[i].cb = callback;
+ return 0;
+ }
+
+ return -1;
+}
+
+static void usb_control_send_chunk(usbd_device *usbd_dev)
+{
+ if (usbd_dev->desc->bMaxPacketSize0 <
+ usbd_dev->control_state.ctrl_len) {
+ /* Data stage, normal transmission */
+ usbd_ep_write_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf,
+ usbd_dev->desc->bMaxPacketSize0);
+ usbd_dev->control_state.state = DATA_IN;
+ usbd_dev->control_state.ctrl_buf +=
+ usbd_dev->desc->bMaxPacketSize0;
+ usbd_dev->control_state.ctrl_len -=
+ usbd_dev->desc->bMaxPacketSize0;
+ } else {
+ /* Data stage, end of transmission */
+ usbd_ep_write_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf,
+ usbd_dev->control_state.ctrl_len);
+ usbd_dev->control_state.state = LAST_DATA_IN;
+ usbd_dev->control_state.ctrl_len = 0;
+ usbd_dev->control_state.ctrl_buf = NULL;
+ }
+}
+
+static int usb_control_recv_chunk(usbd_device *usbd_dev)
+{
+ uint16_t packetsize = MIN(usbd_dev->desc->bMaxPacketSize0,
+ usbd_dev->control_state.req.wLength -
+ usbd_dev->control_state.ctrl_len);
+ uint16_t size = usbd_ep_read_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf +
+ usbd_dev->control_state.ctrl_len,
+ packetsize);
+
+ if (size != packetsize) {
+ stall_transaction(usbd_dev);
+ return -1;
+ }
+
+ usbd_dev->control_state.ctrl_len += size;
+
+ return packetsize;
+}
+
+static int usb_control_request_dispatch(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
+{
+ int i, result = 0;
+ struct user_control_callback *cb = usbd_dev->user_control_callback;
+
+ /* Call user command hook function. */
+ for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
+ if (cb[i].cb == NULL) {
+ break;
+ }
+
+ if ((req->bmRequestType & cb[i].type_mask) == cb[i].type) {
+ result = cb[i].cb(usbd_dev, req,
+ &(usbd_dev->control_state.ctrl_buf),
+ &(usbd_dev->control_state.ctrl_len),
+ &(usbd_dev->control_state.complete));
+ if (result == USBD_REQ_HANDLED ||
+ result == USBD_REQ_NOTSUPP) {
+ return result;
+ }
+ }
+ }
+
+ /* Try standard request if not already handled. */
+ return _usbd_standard_request(usbd_dev, req,
+ &(usbd_dev->control_state.ctrl_buf),
+ &(usbd_dev->control_state.ctrl_len));
+}
+
+/* Handle commands and read requests. */
+static void usb_control_setup_read(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
+{
+ usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
+ usbd_dev->control_state.ctrl_len = req->wLength;
+
+ if (usb_control_request_dispatch(usbd_dev, req)) {
+ if (usbd_dev->control_state.ctrl_len) {
+ /* Go to data out stage if handled. */
+ usb_control_send_chunk(usbd_dev);
+ } else {
+ /* Go to status stage if handled. */
+ usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = STATUS_IN;
+ }
+ } else {
+ /* Stall endpoint on failure. */
+ stall_transaction(usbd_dev);
+ }
+}
+
+static void usb_control_setup_write(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
+{
+ if (req->wLength > usbd_dev->ctrl_buf_len) {
+ stall_transaction(usbd_dev);
+ return;
+ }
+
+ /* Buffer into which to write received data. */
+ usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
+ usbd_dev->control_state.ctrl_len = 0;
+ /* Wait for DATA OUT stage. */
+ if (req->wLength > usbd_dev->desc->bMaxPacketSize0) {
+ usbd_dev->control_state.state = DATA_OUT;
+ } else {
+ usbd_dev->control_state.state = LAST_DATA_OUT;
+ }
+}
+
+/* Do not appear to belong to the API, so are omitted from docs */
+/**@}*/
+
+void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea)
+{
+ struct usb_setup_data *req = &usbd_dev->control_state.req;
+ (void)ea;
+
+ usbd_dev->control_state.complete = NULL;
+
+ if (usbd_ep_read_packet(usbd_dev, 0, req, 8) != 8) {
+ stall_transaction(usbd_dev);
+ return;
+ }
+
+ if (req->wLength == 0) {
+ usb_control_setup_read(usbd_dev, req);
+ } else if (req->bmRequestType & 0x80) {
+ usb_control_setup_read(usbd_dev, req);
+ } else {
+ usb_control_setup_write(usbd_dev, req);
+ }
+}
+
+void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea)
+{
+ (void)ea;
+
+ switch (usbd_dev->control_state.state) {
+ case DATA_OUT:
+ if (usb_control_recv_chunk(usbd_dev) < 0) {
+ break;
+ }
+ if ((usbd_dev->control_state.req.wLength -
+ usbd_dev->control_state.ctrl_len) <=
+ usbd_dev->desc->bMaxPacketSize0) {
+ usbd_dev->control_state.state = LAST_DATA_OUT;
+ }
+ break;
+ case LAST_DATA_OUT:
+ if (usb_control_recv_chunk(usbd_dev) < 0) {
+ break;
+ }
+ /*
+ * We have now received the full data payload.
+ * Invoke callback to process.
+ */
+ if (usb_control_request_dispatch(usbd_dev,
+ &(usbd_dev->control_state.req))) {
+ /* Got to status stage on success. */
+ usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = STATUS_IN;
+ } else {
+ stall_transaction(usbd_dev);
+ }
+ break;
+ case STATUS_OUT:
+ usbd_ep_read_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = IDLE;
+ if (usbd_dev->control_state.complete) {
+ usbd_dev->control_state.complete(usbd_dev,
+ &(usbd_dev->control_state.req));
+ }
+ usbd_dev->control_state.complete = NULL;
+ break;
+ default:
+ stall_transaction(usbd_dev);
+ }
+}
+
+void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea)
+{
+ (void)ea;
+ struct usb_setup_data *req = &(usbd_dev->control_state.req);
+
+ switch (usbd_dev->control_state.state) {
+ case DATA_IN:
+ usb_control_send_chunk(usbd_dev);
+ break;
+ case LAST_DATA_IN:
+ usbd_dev->control_state.state = STATUS_OUT;
+ break;
+ case STATUS_IN:
+ if (usbd_dev->control_state.complete) {
+ usbd_dev->control_state.complete(usbd_dev,
+ &(usbd_dev->control_state.req));
+ }
+
+ /* Exception: Handle SET ADDRESS function here... */
+ if ((req->bmRequestType == 0) &&
+ (req->bRequest == USB_REQ_SET_ADDRESS)) {
+ usbd_dev->driver->set_address(usbd_dev, req->wValue);
+ }
+ usbd_dev->control_state.state = IDLE;
+ break;
+ default:
+ stall_transaction(usbd_dev);
+ }
+}
+
diff --git a/libopencm3/lib/usb/usb_f103.c b/libopencm3/lib/usb/usb_f103.c
new file mode 100644
index 0000000..2985650
--- /dev/null
+++ b/libopencm3/lib/usb/usb_f103.c
@@ -0,0 +1,346 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/usb.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+
+static usbd_device *stm32f103_usbd_init(void);
+static void stm32f103_set_address(usbd_device *usbd_dev, uint8_t addr);
+static void stm32f103_ep_setup(usbd_device *usbd_dev, uint8_t addr,
+ uint8_t type, uint16_t max_size,
+ void (*callback) (usbd_device *usbd_dev,
+ uint8_t ep));
+static void stm32f103_endpoints_reset(usbd_device *usbd_dev);
+static void stm32f103_ep_stall_set(usbd_device *usbd_dev, uint8_t addr,
+ uint8_t stall);
+static uint8_t stm32f103_ep_stall_get(usbd_device *usbd_dev, uint8_t addr);
+static void stm32f103_ep_nak_set(usbd_device *usbd_dev, uint8_t addr,
+ uint8_t nak);
+static uint16_t stm32f103_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len);
+static uint16_t stm32f103_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
+ void *buf, uint16_t len);
+static void stm32f103_poll(usbd_device *usbd_dev);
+
+static uint8_t force_nak[8];
+static struct _usbd_device usbd_dev;
+
+const struct _usbd_driver stm32f103_usb_driver = {
+ .init = stm32f103_usbd_init,
+ .set_address = stm32f103_set_address,
+ .ep_setup = stm32f103_ep_setup,
+ .ep_reset = stm32f103_endpoints_reset,
+ .ep_stall_set = stm32f103_ep_stall_set,
+ .ep_stall_get = stm32f103_ep_stall_get,
+ .ep_nak_set = stm32f103_ep_nak_set,
+ .ep_write_packet = stm32f103_ep_write_packet,
+ .ep_read_packet = stm32f103_ep_read_packet,
+ .poll = stm32f103_poll,
+};
+
+/** Initialize the USB device controller hardware of the STM32. */
+static usbd_device *stm32f103_usbd_init(void)
+{
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
+ SET_REG(USB_CNTR_REG, 0);
+ SET_REG(USB_BTABLE_REG, 0);
+ SET_REG(USB_ISTR_REG, 0);
+
+ /* Enable RESET, SUSPEND, RESUME and CTR interrupts. */
+ SET_REG(USB_CNTR_REG, USB_CNTR_RESETM | USB_CNTR_CTRM |
+ USB_CNTR_SUSPM | USB_CNTR_WKUPM);
+ return &usbd_dev;
+}
+
+static void stm32f103_set_address(usbd_device *dev, uint8_t addr)
+{
+ (void)dev;
+ /* Set device address and enable. */
+ SET_REG(USB_DADDR_REG, (addr & USB_DADDR_ADDR) | USB_DADDR_ENABLE);
+}
+
+/**
+ * Set the receive buffer size for a given USB endpoint.
+ *
+ * @param ep Index of endpoint to configure.
+ * @param size Size in bytes of the RX buffer.
+ */
+static void usb_set_ep_rx_bufsize(usbd_device *dev, uint8_t ep, uint32_t size)
+{
+ (void)dev;
+ if (size > 62) {
+ if (size & 0x1f) {
+ size -= 32;
+ }
+ USB_SET_EP_RX_COUNT(ep, (size << 5) | 0x8000);
+ } else {
+ if (size & 1) {
+ size++;
+ }
+ USB_SET_EP_RX_COUNT(ep, size << 10);
+ }
+}
+
+static void stm32f103_ep_setup(usbd_device *dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*callback) (usbd_device *usbd_dev,
+ uint8_t ep))
+{
+ /* Translate USB standard type codes to STM32. */
+ const uint16_t typelookup[] = {
+ [USB_ENDPOINT_ATTR_CONTROL] = USB_EP_TYPE_CONTROL,
+ [USB_ENDPOINT_ATTR_ISOCHRONOUS] = USB_EP_TYPE_ISO,
+ [USB_ENDPOINT_ATTR_BULK] = USB_EP_TYPE_BULK,
+ [USB_ENDPOINT_ATTR_INTERRUPT] = USB_EP_TYPE_INTERRUPT,
+ };
+ uint8_t dir = addr & 0x80;
+ addr &= 0x7f;
+
+ /* Assign address. */
+ USB_SET_EP_ADDR(addr, addr);
+ USB_SET_EP_TYPE(addr, typelookup[type]);
+
+ if (dir || (addr == 0)) {
+ USB_SET_EP_TX_ADDR(addr, dev->pm_top);
+ if (callback) {
+ dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
+ (void *)callback;
+ }
+ USB_CLR_EP_TX_DTOG(addr);
+ USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_NAK);
+ dev->pm_top += max_size;
+ }
+
+ if (!dir) {
+ USB_SET_EP_RX_ADDR(addr, dev->pm_top);
+ usb_set_ep_rx_bufsize(dev, addr, max_size);
+ if (callback) {
+ dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
+ (void *)callback;
+ }
+ USB_CLR_EP_RX_DTOG(addr);
+ USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
+ dev->pm_top += max_size;
+ }
+}
+
+static void stm32f103_endpoints_reset(usbd_device *dev)
+{
+ int i;
+
+ /* Reset all endpoints. */
+ for (i = 1; i < 8; i++) {
+ USB_SET_EP_TX_STAT(i, USB_EP_TX_STAT_DISABLED);
+ USB_SET_EP_RX_STAT(i, USB_EP_RX_STAT_DISABLED);
+ }
+ dev->pm_top = 0x40 + (2 * dev->desc->bMaxPacketSize0);
+}
+
+static void stm32f103_ep_stall_set(usbd_device *dev, uint8_t addr,
+ uint8_t stall)
+{
+ (void)dev;
+ if (addr == 0) {
+ USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
+ USB_EP_TX_STAT_NAK);
+ }
+
+ if (addr & 0x80) {
+ addr &= 0x7F;
+
+ USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
+ USB_EP_TX_STAT_NAK);
+
+ /* Reset to DATA0 if clearing stall condition. */
+ if (!stall) {
+ USB_CLR_EP_TX_DTOG(addr);
+ }
+ } else {
+ /* Reset to DATA0 if clearing stall condition. */
+ if (!stall) {
+ USB_CLR_EP_RX_DTOG(addr);
+ }
+
+ USB_SET_EP_RX_STAT(addr, stall ? USB_EP_RX_STAT_STALL :
+ USB_EP_RX_STAT_VALID);
+ }
+}
+
+static uint8_t stm32f103_ep_stall_get(usbd_device *dev, uint8_t addr)
+{
+ (void)dev;
+ if (addr & 0x80) {
+ if ((*USB_EP_REG(addr & 0x7F) & USB_EP_TX_STAT) ==
+ USB_EP_TX_STAT_STALL) {
+ return 1;
+ }
+ } else {
+ if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) ==
+ USB_EP_RX_STAT_STALL) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void stm32f103_ep_nak_set(usbd_device *dev, uint8_t addr, uint8_t nak)
+{
+ (void)dev;
+ /* It does not make sence to force NAK on IN endpoints. */
+ if (addr & 0x80) {
+ return;
+ }
+
+ force_nak[addr] = nak;
+
+ if (nak) {
+ USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_NAK);
+ } else {
+ USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
+ }
+}
+
+/**
+ * Copy a data buffer to packet memory.
+ *
+ * @param vPM Destination pointer into packet memory.
+ * @param buf Source pointer to data buffer.
+ * @param len Number of bytes to copy.
+ */
+static void usb_copy_to_pm(volatile void *vPM, const void *buf, uint16_t len)
+{
+ const uint16_t *lbuf = buf;
+ volatile uint16_t *PM = vPM;
+
+ for (len = (len + 1) >> 1; len; PM += 2, lbuf++, len--) {
+ *PM = *lbuf;
+ }
+}
+
+static uint16_t stm32f103_ep_write_packet(usbd_device *dev, uint8_t addr,
+ const void *buf, uint16_t len)
+{
+ (void)dev;
+ addr &= 0x7F;
+
+ if ((*USB_EP_REG(addr) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID) {
+ return 0;
+ }
+
+ usb_copy_to_pm(USB_GET_EP_TX_BUFF(addr), buf, len);
+ USB_SET_EP_TX_COUNT(addr, len);
+ USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID);
+
+ return len;
+}
+
+/**
+ * Copy a data buffer from packet memory.
+ *
+ * @param buf Source pointer to data buffer.
+ * @param vPM Destination pointer into packet memory.
+ * @param len Number of bytes to copy.
+ */
+static void usb_copy_from_pm(void *buf, const volatile void *vPM, uint16_t len)
+{
+ uint16_t *lbuf = buf;
+ const volatile uint16_t *PM = vPM;
+ uint8_t odd = len & 1;
+
+ for (len >>= 1; len; PM += 2, lbuf++, len--) {
+ *lbuf = *PM;
+ }
+
+ if (odd) {
+ *(uint8_t *) lbuf = *(uint8_t *) PM;
+ }
+}
+
+static uint16_t stm32f103_ep_read_packet(usbd_device *dev, uint8_t addr,
+ void *buf, uint16_t len)
+{
+ (void)dev;
+ if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == USB_EP_RX_STAT_VALID) {
+ return 0;
+ }
+
+ len = MIN(USB_GET_EP_RX_COUNT(addr) & 0x3ff, len);
+ usb_copy_from_pm(buf, USB_GET_EP_RX_BUFF(addr), len);
+ USB_CLR_EP_RX_CTR(addr);
+
+ if (!force_nak[addr]) {
+ USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
+ }
+
+ return len;
+}
+
+static void stm32f103_poll(usbd_device *dev)
+{
+ uint16_t istr = *USB_ISTR_REG;
+
+ if (istr & USB_ISTR_RESET) {
+ dev->pm_top = 0x40;
+ _usbd_reset(dev);
+ USB_CLR_ISTR_RESET();
+ return;
+ }
+
+ if (istr & USB_ISTR_CTR) {
+ uint8_t ep = istr & USB_ISTR_EP_ID;
+ uint8_t type = (istr & USB_ISTR_DIR) ? 1 : 0;
+
+ if (type) { /* OUT or SETUP transaction */
+ type += (*USB_EP_REG(ep) & USB_EP_SETUP) ? 1 : 0;
+ } else { /* IN transaction */
+ USB_CLR_EP_TX_CTR(ep);
+ }
+
+ if (dev->user_callback_ctr[ep][type]) {
+ dev->user_callback_ctr[ep][type] (dev, ep);
+ } else {
+ USB_CLR_EP_RX_CTR(ep);
+ }
+ }
+
+ if (istr & USB_ISTR_SUSP) {
+ USB_CLR_ISTR_SUSP();
+ if (dev->user_callback_suspend) {
+ dev->user_callback_suspend();
+ }
+ }
+
+ if (istr & USB_ISTR_WKUP) {
+ USB_CLR_ISTR_WKUP();
+ if (dev->user_callback_resume) {
+ dev->user_callback_resume();
+ }
+ }
+
+ if (istr & USB_ISTR_SOF) {
+ if (dev->user_callback_sof) {
+ dev->user_callback_sof();
+ }
+ USB_CLR_ISTR_SOF();
+ }
+}
diff --git a/libopencm3/lib/usb/usb_f107.c b/libopencm3/lib/usb/usb_f107.c
new file mode 100644
index 0000000..32aecab
--- /dev/null
+++ b/libopencm3/lib/usb/usb_f107.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+#include "usb_fx07_common.h"
+
+/* Receive FIFO size in 32-bit words. */
+#define RX_FIFO_SIZE 128
+
+static usbd_device *stm32f107_usbd_init(void);
+
+static struct _usbd_device usbd_dev;
+
+const struct _usbd_driver stm32f107_usb_driver = {
+ .init = stm32f107_usbd_init,
+ .set_address = stm32fx07_set_address,
+ .ep_setup = stm32fx07_ep_setup,
+ .ep_reset = stm32fx07_endpoints_reset,
+ .ep_stall_set = stm32fx07_ep_stall_set,
+ .ep_stall_get = stm32fx07_ep_stall_get,
+ .ep_nak_set = stm32fx07_ep_nak_set,
+ .ep_write_packet = stm32fx07_ep_write_packet,
+ .ep_read_packet = stm32fx07_ep_read_packet,
+ .poll = stm32fx07_poll,
+ .disconnect = stm32fx07_disconnect,
+ .base_address = USB_OTG_FS_BASE,
+ .set_address_before_status = 1,
+ .rx_fifo_size = RX_FIFO_SIZE,
+};
+
+/** Initialize the USB device controller hardware of the STM32. */
+static usbd_device *stm32f107_usbd_init(void)
+{
+ OTG_FS_GINTSTS = OTG_FS_GINTSTS_MMIS;
+
+ OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_PHYSEL;
+ /* Enable VBUS sensing in device mode and power down the PHY. */
+ OTG_FS_GCCFG |= OTG_FS_GCCFG_VBUSBSEN | OTG_FS_GCCFG_PWRDWN;
+
+ /* Wait for AHB idle. */
+ while (!(OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_AHBIDL));
+ /* Do core soft reset. */
+ OTG_FS_GRSTCTL |= OTG_FS_GRSTCTL_CSRST;
+ while (OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_CSRST);
+
+ /* Force peripheral only mode. */
+ OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_FDMOD | OTG_FS_GUSBCFG_TRDT_MASK;
+
+ /* Full speed device. */
+ OTG_FS_DCFG |= OTG_FS_DCFG_DSPD;
+
+ /* Restart the PHY clock. */
+ OTG_FS_PCGCCTL = 0;
+
+ OTG_FS_GRXFSIZ = stm32f107_usb_driver.rx_fifo_size;
+ usbd_dev.fifo_mem_top = stm32f107_usb_driver.rx_fifo_size;
+
+ /* Unmask interrupts for TX and RX. */
+ OTG_FS_GAHBCFG |= OTG_FS_GAHBCFG_GINT;
+ OTG_FS_GINTMSK = OTG_FS_GINTMSK_ENUMDNEM |
+ OTG_FS_GINTMSK_RXFLVLM |
+ OTG_FS_GINTMSK_IEPINT |
+ OTG_FS_GINTMSK_USBSUSPM |
+ OTG_FS_GINTMSK_WUIM |
+ OTG_FS_GINTMSK_SOFM;
+ OTG_FS_DAINTMSK = 0xF;
+ OTG_FS_DIEPMSK = OTG_FS_DIEPMSK_XFRCM;
+
+ return &usbd_dev;
+}
diff --git a/libopencm3/lib/usb/usb_f207.c b/libopencm3/lib/usb/usb_f207.c
new file mode 100644
index 0000000..b27d3cd
--- /dev/null
+++ b/libopencm3/lib/usb/usb_f207.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/otg_hs.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+#include "usb_fx07_common.h"
+
+/* Receive FIFO size in 32-bit words. */
+#define RX_FIFO_SIZE 512
+
+static usbd_device *stm32f207_usbd_init(void);
+
+static struct _usbd_device usbd_dev;
+
+const struct _usbd_driver stm32f207_usb_driver = {
+ .init = stm32f207_usbd_init,
+ .set_address = stm32fx07_set_address,
+ .ep_setup = stm32fx07_ep_setup,
+ .ep_reset = stm32fx07_endpoints_reset,
+ .ep_stall_set = stm32fx07_ep_stall_set,
+ .ep_stall_get = stm32fx07_ep_stall_get,
+ .ep_nak_set = stm32fx07_ep_nak_set,
+ .ep_write_packet = stm32fx07_ep_write_packet,
+ .ep_read_packet = stm32fx07_ep_read_packet,
+ .poll = stm32fx07_poll,
+ .disconnect = stm32fx07_disconnect,
+ .base_address = USB_OTG_HS_BASE,
+ .set_address_before_status = 1,
+ .rx_fifo_size = RX_FIFO_SIZE,
+};
+
+/** Initialize the USB device controller hardware of the STM32. */
+static usbd_device *stm32f207_usbd_init(void)
+{
+ OTG_HS_GINTSTS = OTG_HS_GINTSTS_MMIS;
+
+ OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_PHYSEL;
+ /* Enable VBUS sensing in device mode and power down the PHY. */
+ OTG_HS_GCCFG |= OTG_HS_GCCFG_VBUSBSEN | OTG_HS_GCCFG_PWRDWN;
+
+ /* Wait for AHB idle. */
+ while (!(OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_AHBIDL));
+ /* Do core soft reset. */
+ OTG_HS_GRSTCTL |= OTG_HS_GRSTCTL_CSRST;
+ while (OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_CSRST);
+
+ /* Force peripheral only mode. */
+ OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_FDMOD | OTG_HS_GUSBCFG_TRDT_MASK;
+
+ /* Full speed device. */
+ OTG_HS_DCFG |= OTG_HS_DCFG_DSPD;
+
+ /* Restart the PHY clock. */
+ OTG_HS_PCGCCTL = 0;
+
+ OTG_HS_GRXFSIZ = stm32f207_usb_driver.rx_fifo_size;
+ usbd_dev.fifo_mem_top = stm32f207_usb_driver.rx_fifo_size;
+
+ /* Unmask interrupts for TX and RX. */
+ OTG_HS_GAHBCFG |= OTG_HS_GAHBCFG_GINT;
+ OTG_HS_GINTMSK = OTG_HS_GINTMSK_ENUMDNEM |
+ OTG_HS_GINTMSK_RXFLVLM |
+ OTG_HS_GINTMSK_IEPINT |
+ OTG_HS_GINTMSK_USBSUSPM |
+ OTG_HS_GINTMSK_WUIM |
+ OTG_HS_GINTMSK_SOFM;
+ OTG_HS_DAINTMSK = 0xF;
+ OTG_HS_DIEPMSK = OTG_HS_DIEPMSK_XFRCM;
+
+ return &usbd_dev;
+}
diff --git a/libopencm3/lib/usb/usb_fx07_common.c b/libopencm3/lib/usb/usb_fx07_common.c
new file mode 100644
index 0000000..c54c7a3
--- /dev/null
+++ b/libopencm3/lib/usb/usb_fx07_common.c
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/stm32/otg_hs.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+#include "usb_fx07_common.h"
+
+/* The FS core and the HS core have the same register layout.
+ * As the code can be used on both cores, the registers offset is modified
+ * according to the selected cores base address. */
+#define dev_base_address (usbd_dev->driver->base_address)
+#define REBASE(x) MMIO32((x) + (dev_base_address))
+#define REBASE_FIFO(x) (&MMIO32((dev_base_address) + (OTG_FIFO(x))))
+
+void stm32fx07_set_address(usbd_device *usbd_dev, uint8_t addr)
+{
+ REBASE(OTG_DCFG) = (REBASE(OTG_DCFG) & ~OTG_FS_DCFG_DAD) | (addr << 4);
+}
+
+void stm32fx07_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*callback) (usbd_device *usbd_dev, uint8_t ep))
+{
+ /*
+ * Configure endpoint address and type. Allocate FIFO memory for
+ * endpoint. Install callback funciton.
+ */
+ uint8_t dir = addr & 0x80;
+ addr &= 0x7f;
+
+ if (addr == 0) { /* For the default control endpoint */
+ /* Configure IN part. */
+ if (max_size >= 64) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_64;
+ } else if (max_size >= 32) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_32;
+ } else if (max_size >= 16) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_16;
+ } else {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_8;
+ }
+
+ REBASE(OTG_DIEPTSIZ0) =
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DIEPCTL0) |=
+ OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
+
+ /* Configure OUT part. */
+ usbd_dev->doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 |
+ OTG_FS_DIEPSIZ0_PKTCNT |
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DOEPTSIZ(0)) = usbd_dev->doeptsiz[0];
+ REBASE(OTG_DOEPCTL(0)) |=
+ OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
+
+ REBASE(OTG_GNPTXFSIZ) = ((max_size / 4) << 16) |
+ usbd_dev->driver->rx_fifo_size;
+ usbd_dev->fifo_mem_top += max_size / 4;
+ usbd_dev->fifo_mem_top_ep0 = usbd_dev->fifo_mem_top;
+
+ return;
+ }
+
+ if (dir) {
+ REBASE(OTG_DIEPTXF(addr)) = ((max_size / 4) << 16) |
+ usbd_dev->fifo_mem_top;
+ usbd_dev->fifo_mem_top += max_size / 4;
+
+ REBASE(OTG_DIEPTSIZ(addr)) =
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DIEPCTL(addr)) |=
+ OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18)
+ | OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID
+ | (addr << 22) | max_size;
+
+ if (callback) {
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
+ (void *)callback;
+ }
+ }
+
+ if (!dir) {
+ usbd_dev->doeptsiz[addr] = OTG_FS_DIEPSIZ0_PKTCNT |
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
+ OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK |
+ OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size;
+
+ if (callback) {
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
+ (void *)callback;
+ }
+ }
+}
+
+void stm32fx07_endpoints_reset(usbd_device *usbd_dev)
+{
+ /* The core resets the endpoints automatically on reset. */
+ usbd_dev->fifo_mem_top = usbd_dev->fifo_mem_top_ep0;
+}
+
+void stm32fx07_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall)
+{
+ if (addr == 0) {
+ if (stall) {
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
+ } else {
+ REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
+ }
+ }
+
+ if (addr & 0x80) {
+ addr &= 0x7F;
+
+ if (stall) {
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
+ } else {
+ REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTLX_SD0PID;
+ }
+ } else {
+ if (stall) {
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_STALL;
+ } else {
+ REBASE(OTG_DOEPCTL(addr)) &= ~OTG_FS_DOEPCTL0_STALL;
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTLX_SD0PID;
+ }
+ }
+}
+
+uint8_t stm32fx07_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
+{
+ /* Return non-zero if STALL set. */
+ if (addr & 0x80) {
+ return (REBASE(OTG_DIEPCTL(addr & 0x7f)) &
+ OTG_FS_DIEPCTL0_STALL) ? 1 : 0;
+ } else {
+ return (REBASE(OTG_DOEPCTL(addr)) &
+ OTG_FS_DOEPCTL0_STALL) ? 1 : 0;
+ }
+}
+
+void stm32fx07_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
+{
+ /* It does not make sence to force NAK on IN endpoints. */
+ if (addr & 0x80) {
+ return;
+ }
+
+ usbd_dev->force_nak[addr] = nak;
+
+ if (nak) {
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_SNAK;
+ } else {
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_CNAK;
+ }
+}
+
+uint16_t stm32fx07_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len)
+{
+ const uint32_t *buf32 = buf;
+ int i;
+
+ addr &= 0x7F;
+
+ /* Return if endpoint is already enabled. */
+ if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_FS_DIEPSIZ0_PKTCNT) {
+ return 0;
+ }
+
+ /* Enable endpoint for transmission. */
+ REBASE(OTG_DIEPTSIZ(addr)) = OTG_FS_DIEPSIZ0_PKTCNT | len;
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_EPENA |
+ OTG_FS_DIEPCTL0_CNAK;
+ volatile uint32_t *fifo = REBASE_FIFO(addr);
+
+ /* Copy buffer to endpoint FIFO, note - memcpy does not work */
+ for (i = len; i > 0; i -= 4) {
+ *fifo++ = *buf32++;
+ }
+
+ return len;
+}
+
+uint16_t stm32fx07_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
+ void *buf, uint16_t len)
+{
+ int i;
+ uint32_t *buf32 = buf;
+ uint32_t extra;
+
+ len = MIN(len, usbd_dev->rxbcnt);
+ usbd_dev->rxbcnt -= len;
+
+ volatile uint32_t *fifo = REBASE_FIFO(addr);
+ for (i = len; i >= 4; i -= 4) {
+ *buf32++ = *fifo++;
+ }
+
+ if (i) {
+ extra = *fifo++;
+ memcpy(buf32, &extra, i);
+ }
+
+ REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
+ (usbd_dev->force_nak[addr] ?
+ OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK);
+
+ return len;
+}
+
+void stm32fx07_poll(usbd_device *usbd_dev)
+{
+ /* Read interrupt status register. */
+ uint32_t intsts = REBASE(OTG_GINTSTS);
+ int i;
+
+ if (intsts & OTG_FS_GINTSTS_ENUMDNE) {
+ /* Handle USB RESET condition. */
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_ENUMDNE;
+ usbd_dev->fifo_mem_top = usbd_dev->driver->rx_fifo_size;
+ _usbd_reset(usbd_dev);
+ return;
+ }
+
+ /* Note: RX and TX handled differently in this device. */
+ if (intsts & OTG_FS_GINTSTS_RXFLVL) {
+ /* Receive FIFO non-empty. */
+ uint32_t rxstsp = REBASE(OTG_GRXSTSP);
+ uint32_t pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK;
+ if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) &&
+ (pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP)) {
+ return;
+ }
+
+ uint8_t ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK;
+ uint8_t type;
+ if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP) {
+ type = USB_TRANSACTION_SETUP;
+ } else {
+ type = USB_TRANSACTION_OUT;
+ }
+
+ /* Save packet size for stm32f107_ep_read_packet(). */
+ usbd_dev->rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4;
+
+ /*
+ * FIXME: Why is a delay needed here?
+ * This appears to fix a problem where the first 4 bytes
+ * of the DATA OUT stage of a control transaction are lost.
+ */
+ for (i = 0; i < 1000; i++) {
+ __asm__("nop");
+ }
+
+ if (usbd_dev->user_callback_ctr[ep][type]) {
+ usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
+ }
+
+ /* Discard unread packet data. */
+ for (i = 0; i < usbd_dev->rxbcnt; i += 4) {
+ (void)*REBASE_FIFO(ep);
+ }
+
+ usbd_dev->rxbcnt = 0;
+ }
+
+ /*
+ * There is no global interrupt flag for transmit complete.
+ * The XFRC bit must be checked in each OTG_FS_DIEPINT(x).
+ */
+ for (i = 0; i < 4; i++) { /* Iterate over endpoints. */
+ if (REBASE(OTG_DIEPINT(i)) & OTG_FS_DIEPINTX_XFRC) {
+ /* Transfer complete. */
+ if (usbd_dev->user_callback_ctr[i]
+ [USB_TRANSACTION_IN]) {
+ usbd_dev->user_callback_ctr[i]
+ [USB_TRANSACTION_IN](usbd_dev, i);
+ }
+
+ REBASE(OTG_DIEPINT(i)) = OTG_FS_DIEPINTX_XFRC;
+ }
+ }
+
+ if (intsts & OTG_FS_GINTSTS_USBSUSP) {
+ if (usbd_dev->user_callback_suspend) {
+ usbd_dev->user_callback_suspend();
+ }
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_USBSUSP;
+ }
+
+ if (intsts & OTG_FS_GINTSTS_WKUPINT) {
+ if (usbd_dev->user_callback_resume) {
+ usbd_dev->user_callback_resume();
+ }
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_WKUPINT;
+ }
+
+ if (intsts & OTG_FS_GINTSTS_SOF) {
+ if (usbd_dev->user_callback_sof) {
+ usbd_dev->user_callback_sof();
+ }
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_SOF;
+ }
+}
+
+void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected)
+{
+ if (disconnected) {
+ REBASE(OTG_DCTL) |= OTG_FS_DCTL_SDIS;
+ } else {
+ REBASE(OTG_DCTL) &= ~OTG_FS_DCTL_SDIS;
+ }
+}
diff --git a/libopencm3/lib/usb/usb_fx07_common.h b/libopencm3/lib/usb/usb_fx07_common.h
new file mode 100644
index 0000000..31c4030
--- /dev/null
+++ b/libopencm3/lib/usb/usb_fx07_common.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USB_FX07_COMMON_H_
+#define __USB_FX07_COMMON_H_
+
+void stm32fx07_set_address(usbd_device *usbd_dev, uint8_t addr);
+void stm32fx07_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*callback)(usbd_device *usbd_dev, uint8_t ep));
+void stm32fx07_endpoints_reset(usbd_device *usbd_dev);
+void stm32fx07_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall);
+uint8_t stm32fx07_ep_stall_get(usbd_device *usbd_dev, uint8_t addr);
+void stm32fx07_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak);
+uint16_t stm32fx07_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len);
+uint16_t stm32fx07_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
+ void *buf, uint16_t len);
+void stm32fx07_poll(usbd_device *usbd_dev);
+void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected);
+
+
+#endif /* __USB_FX07_COMMON_H_ */
diff --git a/libopencm3/lib/usb/usb_msc.c b/libopencm3/lib/usb/usb_msc.c
new file mode 100644
index 0000000..573590d
--- /dev/null
+++ b/libopencm3/lib/usb/usb_msc.c
@@ -0,0 +1,814 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Weston Schmidt <weston_schmidt@alumni.purdue.edu>
+ * Copyright (C) 2013 Pavol Rusnak <stick@gk2.sk>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/msc.h>
+#include "usb_private.h"
+
+/* Definitions of Mass Storage Class from:
+ *
+ * (A) "Universal Serial Bus Mass Storage Class Bulk-Only Transport
+ * Revision 1.0"
+ *
+ * (B) "Universal Serial Bus Mass Storage Class Specification Overview
+ * Revision 1.0"
+ */
+
+/* Command Block Wrapper */
+#define CBW_SIGNATURE 0x43425355
+#define CBW_STATUS_SUCCESS 0
+#define CBW_STATUS_FAILED 1
+#define CBW_STATUS_PHASE_ERROR 2
+
+/* Command Status Wrapper */
+#define CSW_SIGNATURE 0x53425355
+#define CSW_STATUS_SUCCESS 0
+#define CSW_STATUS_FAILED 1
+#define CSW_STATUS_PHASE_ERROR 2
+
+/* Implemented SCSI Commands */
+#define SCSI_TEST_UNIT_READY 0x00
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_FORMAT_UNIT 0x04
+#define SCSI_READ_6 0x08
+#define SCSI_WRITE_6 0x0A
+#define SCSI_INQUIRY 0x12
+#define SCSI_MODE_SENSE_6 0x1A
+#define SCSI_SEND_DIAGNOSTIC 0x1D
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ_10 0x28
+
+
+/* Required SCSI Commands */
+
+/* Optional SCSI Commands */
+#define SCSI_REPORT_LUNS 0xA0
+#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
+#define SCSI_MODE_SELECT_6 0x15
+#define SCSI_MODE_SELECT_10 0x55
+#define SCSI_MODE_SENSE_10 0x5A
+#define SCSI_READ_12 0xA8
+#define SCSI_READ_FORMAT_CAPACITIES 0x23
+#define SCSI_READ_TOC_PMA_ATIP 0x43
+#define SCSI_START_STOP_UNIT 0x1B
+#define SCSI_SYNCHRONIZE_CACHE 0x35
+#define SCSI_VERIFY 0x2F
+#define SCSI_WRITE_10 0x2A
+#define SCSI_WRITE_12 0xAA
+
+/* The sense codes */
+enum sbc_sense_key {
+ SBC_SENSE_KEY_NO_SENSE = 0x00,
+ SBC_SENSE_KEY_RECOVERED_ERROR = 0x01,
+ SBC_SENSE_KEY_NOT_READY = 0x02,
+ SBC_SENSE_KEY_MEDIUM_ERROR = 0x03,
+ SBC_SENSE_KEY_HARDWARE_ERROR = 0x04,
+ SBC_SENSE_KEY_ILLEGAL_REQUEST = 0x05,
+ SBC_SENSE_KEY_UNIT_ATTENTION = 0x06,
+ SBC_SENSE_KEY_DATA_PROTECT = 0x07,
+ SBC_SENSE_KEY_BLANK_CHECK = 0x08,
+ SBC_SENSE_KEY_VENDOR_SPECIFIC = 0x09,
+ SBC_SENSE_KEY_COPY_ABORTED = 0x0A,
+ SBC_SENSE_KEY_ABORTED_COMMAND = 0x0B,
+ SBC_SENSE_KEY_VOLUME_OVERFLOW = 0x0D,
+ SBC_SENSE_KEY_MISCOMPARE = 0x0E
+};
+
+enum sbc_asc {
+ SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
+ SBC_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03,
+ SBC_ASC_LOGICAL_UNIT_NOT_READY = 0x04,
+ SBC_ASC_UNRECOVERED_READ_ERROR = 0x11,
+ SBC_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20,
+ SBC_ASC_LBA_OUT_OF_RANGE = 0x21,
+ SBC_ASC_INVALID_FIELD_IN_CDB = 0x24,
+ SBC_ASC_WRITE_PROTECTED = 0x27,
+ SBC_ASC_NOT_READY_TO_READY_CHANGE = 0x28,
+ SBC_ASC_FORMAT_ERROR = 0x31,
+ SBC_ASC_MEDIUM_NOT_PRESENT = 0x3A
+};
+
+enum sbc_ascq {
+ SBC_ASCQ_NA = 0x00,
+ SBC_ASCQ_FORMAT_COMMAND_FAILED = 0x01,
+ SBC_ASCQ_INITIALIZING_COMMAND_REQUIRED = 0x02,
+ SBC_ASCQ_OPERATION_IN_PROGRESS = 0x07
+};
+
+enum trans_event {
+ EVENT_CBW_VALID,
+ EVENT_NEED_STATUS
+};
+
+struct usb_msc_cbw {
+ uint32_t dCBWSignature;
+ uint32_t dCBWTag;
+ uint32_t dCBWDataTransferLength;
+ uint8_t bmCBWFlags;
+ uint8_t bCBWLUN;
+ uint8_t bCBWCBLength;
+ uint8_t CBWCB[16];
+} __attribute__((packed));
+
+struct usb_msc_csw {
+ uint32_t dCSWSignature;
+ uint32_t dCSWTag;
+ uint32_t dCSWDataResidue;
+ uint8_t bCSWStatus;
+} __attribute__((packed));
+
+struct sbc_sense_info {
+ uint8_t key;
+ uint8_t asc;
+ uint8_t ascq;
+};
+
+struct usb_msc_trans {
+ uint8_t cbw_cnt; /* Read until 31 bytes */
+ union {
+ struct usb_msc_cbw cbw;
+ uint8_t buf[1];
+ } cbw;
+
+ uint32_t bytes_to_read;
+ uint32_t bytes_to_write;
+ uint32_t byte_count; /* Either read until equal to bytes_to_read or
+ write until equal to bytes_to_write. */
+ uint32_t lba_start;
+ uint32_t block_count;
+ uint32_t current_block;
+
+ uint8_t msd_buf[512];
+
+ bool csw_valid;
+ uint8_t csw_sent; /* Write until 13 bytes */
+ union {
+ struct usb_msc_csw csw;
+ uint8_t buf[1];
+ } csw;
+};
+
+struct _usbd_mass_storage {
+ usbd_device *usbd_dev;
+ uint8_t ep_in;
+ uint8_t ep_in_size;
+ uint8_t ep_out;
+ uint8_t ep_out_size;
+
+ const char *vendor_id;
+ const char *product_id;
+ const char *product_revision_level;
+ uint32_t block_count;
+
+ int (*read_block)(uint32_t lba, uint8_t *copy_to);
+ int (*write_block)(uint32_t lba, const uint8_t *copy_from);
+
+ void (*lock)(void);
+ void (*unlock)(void);
+
+ struct usb_msc_trans trans;
+ struct sbc_sense_info sense;
+};
+
+static usbd_mass_storage _mass_storage;
+
+/*-- SCSI Base Responses -----------------------------------------------------*/
+
+static const uint8_t _spc3_inquiry_response[36] = {
+ 0x00, /* Byte 0: Peripheral Qualifier = 0, Peripheral Device Type = 0 */
+ 0x80, /* Byte 1: RMB = 1, Reserved = 0 */
+ 0x04, /* Byte 2: Version = 0 */
+ 0x02, /* Byte 3: Obsolete = 0, NormACA = 0, HiSup = 0, Response Data Format = 2 */
+ 0x20, /* Byte 4: Additional Length (n-4) = 31 + 4 */
+ 0x00, /* Byte 5: SCCS = 0, ACC = 0, TPGS = 0, 3PC = 0, Reserved = 0, Protect = 0 */
+ 0x00, /* Byte 6: BQue = 0, EncServ = 0, VS = 0, MultiP = 0, MChngr = 0, Obsolete = 0, Addr16 = 0 */
+ 0x00, /* Byte 7: Obsolete = 0, Wbus16 = 0, Sync = 0, Linked = 0, CmdQue = 0, VS = 0 */
+ /* Byte 8 - Byte 15: Vendor Identification */
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ /* Byte 16 - Byte 31: Product Identification */
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ /* Byte 32 - Byte 35: Product Revision Level */
+ 0x20, 0x20, 0x20, 0x20
+};
+
+static const uint8_t _spc3_request_sense[18] = {
+ 0x70, /* Byte 0: VALID = 0, Response Code = 112 */
+ 0x00, /* Byte 1: Obsolete = 0 */
+ 0x00, /* Byte 2: Filemark = 0, EOM = 0, ILI = 0, Reserved = 0, Sense Key = 0 */
+ /* Byte 3 - Byte 6: Information = 0 */
+ 0, 0, 0, 0,
+ 0x0a, /* Byte 7: Additional Sense Length = 10 */
+ /* Byte 8 - Byte 11: Command Specific Info = 0 */
+ 0, 0, 0, 0,
+ 0x00, /* Byte 12: Additional Sense Code (ASC) = 0 */
+ 0x00, /* Byte 13: Additional Sense Code Qualifier (ASCQ) = 0 */
+ 0x00, /* Byte 14: Field Replaceable Unit Code (FRUC) = 0 */
+ 0x00, /* Byte 15: SKSV = 0, SenseKeySpecific[0] = 0 */
+ 0x00, /* Byte 16: SenseKeySpecific[0] = 0 */
+ 0x00 /* Byte 17: SenseKeySpecific[0] = 0 */
+};
+
+/*-- SCSI Layer --------------------------------------------------------------*/
+
+static void set_sbc_status(usbd_mass_storage *ms,
+ enum sbc_sense_key key,
+ enum sbc_asc asc,
+ enum sbc_ascq ascq)
+{
+ ms->sense.key = (uint8_t) key;
+ ms->sense.asc = (uint8_t) asc;
+ ms->sense.ascq = (uint8_t) ascq;
+}
+
+static void set_sbc_status_good(usbd_mass_storage *ms)
+{
+ set_sbc_status(ms,
+ SBC_SENSE_KEY_NO_SENSE,
+ SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION,
+ SBC_ASCQ_NA);
+}
+
+static uint8_t *get_cbw_buf(struct usb_msc_trans *trans)
+{
+ return &trans->cbw.cbw.CBWCB[0];
+}
+
+static void scsi_read_6(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ uint8_t *buf;
+
+ buf = get_cbw_buf(trans);
+
+ trans->lba_start = (buf[2] << 8) | buf[3];
+ trans->block_count = buf[4];
+ trans->current_block = 0;
+
+ /* TODO: Check the lba & block_count for range. */
+
+ /* both are in terms of 512 byte blocks, so shift by 9 */
+ trans->bytes_to_write = trans->block_count << 9;
+
+ set_sbc_status_good(ms);
+ }
+}
+
+static void scsi_write_6(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ (void) ms;
+
+ if (EVENT_CBW_VALID == event) {
+ uint8_t *buf;
+
+ buf = get_cbw_buf(trans);
+
+ trans->lba_start = ((0x1f & buf[1]) << 16) | (buf[2] << 8) | buf[3];
+ trans->block_count = buf[4];
+ trans->current_block = 0;
+
+ trans->bytes_to_read = trans->block_count << 9;
+ }
+}
+
+static void scsi_write_10(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ (void) ms;
+
+ if (EVENT_CBW_VALID == event) {
+ uint8_t *buf;
+
+ buf = get_cbw_buf(trans);
+
+ trans->lba_start = (buf[2] << 24) | (buf[3] << 16) |
+ (buf[4] << 8) | buf[5];
+ trans->block_count = (buf[7] << 8) | buf[8];
+ trans->current_block = 0;
+
+ trans->bytes_to_read = trans->block_count << 9;
+ }
+}
+
+static void scsi_read_10(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ uint8_t *buf;
+
+ buf = get_cbw_buf(trans);
+
+ trans->lba_start = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
+ trans->block_count = (buf[7] << 8) | buf[8];
+
+ /* TODO: Check the lba & block_count for range. */
+
+ /* both are in terms of 512 byte blocks, so shift by 9 */
+ trans->bytes_to_write = trans->block_count << 9;
+
+ set_sbc_status_good(ms);
+ }
+}
+
+static void scsi_read_capacity(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ trans->msd_buf[0] = ms->block_count >> 24;
+ trans->msd_buf[1] = 0xff & (ms->block_count >> 16);
+ trans->msd_buf[2] = 0xff & (ms->block_count >> 8);
+ trans->msd_buf[3] = 0xff & ms->block_count;
+
+ /* Block size: 512 */
+ trans->msd_buf[4] = 0;
+ trans->msd_buf[5] = 0;
+ trans->msd_buf[6] = 2;
+ trans->msd_buf[7] = 0;
+ trans->bytes_to_write = 8;
+ set_sbc_status_good(ms);
+ }
+}
+
+static void scsi_format_unit(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ uint32_t i;
+
+ memset(trans->msd_buf, 0, 512);
+
+ for (i = 0; i < ms->block_count; i++) {
+ (*ms->write_block)(i, trans->msd_buf);
+ }
+
+ set_sbc_status_good(ms);
+ }
+}
+
+static void scsi_request_sense(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ uint8_t *buf;
+
+ buf = &trans->cbw.cbw.CBWCB[0];
+
+ trans->bytes_to_write = buf[4]; /* allocation length */
+ memcpy(trans->msd_buf, _spc3_request_sense, sizeof(_spc3_request_sense));
+
+ trans->msd_buf[2] = ms->sense.key;
+ trans->msd_buf[12] = ms->sense.asc;
+ trans->msd_buf[13] = ms->sense.ascq;
+ }
+}
+
+static void scsi_mode_sense_6(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ (void) ms;
+
+ if (EVENT_CBW_VALID == event) {
+#if 0
+ uint8_t *buf;
+ uint8_t page_code;
+ uint8_t allocation_length;
+
+ buf = &trans->cbw.cbw.CBWCB[0];
+ page_code = buf[2];
+ allocation_length = buf[4];
+
+ if (0x1C == page_code) { /* Informational Exceptions */
+#endif
+ trans->bytes_to_write = 4;
+
+ trans->msd_buf[0] = 3; /* Num bytes that follow */
+ trans->msd_buf[1] = 0; /* Medium Type */
+ trans->msd_buf[2] = 0; /* Device specific param */
+ trans->csw.csw.dCSWDataResidue = 4;
+#if 0
+ } else if (0x01 == page_code) { /* Error recovery */
+ } else if (0x3F == page_code) { /* All */
+ } else {
+ /* Error */
+ trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
+ set_sbc_status(ms,
+ SBC_SENSE_KEY_ILLEGAL_REQUEST,
+ SBC_ASC_INVALID_FIELD_IN_CDB,
+ SBC_ASCQ_NA);
+ }
+#endif
+ }
+}
+
+static void scsi_inquiry(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ uint8_t evpd;
+ uint8_t *buf;
+
+ buf = get_cbw_buf(trans);
+ evpd = 1 & buf[1];
+
+ if (0 == evpd) {
+ size_t len;
+ trans->bytes_to_write = sizeof(_spc3_inquiry_response);
+ memcpy(trans->msd_buf, _spc3_inquiry_response, sizeof(_spc3_inquiry_response));
+
+ len = strlen(ms->vendor_id);
+ len = MIN(len, 8);
+ memcpy(&trans->msd_buf[8], ms->vendor_id, len);
+
+ len = strlen(ms->product_id);
+ len = MIN(len, 16);
+ memcpy(&trans->msd_buf[16], ms->product_id, len);
+
+ len = strlen(ms->product_revision_level);
+ len = MIN(len, 4);
+ memcpy(&trans->msd_buf[32], ms->product_revision_level, len);
+
+ trans->csw.csw.dCSWDataResidue = sizeof(_spc3_inquiry_response);
+
+ set_sbc_status_good(ms);
+ } else {
+ /* TODO: Add VPD 0x83 support */
+ /* TODO: Add VPD 0x00 support */
+ }
+ }
+}
+
+static void scsi_command(usbd_mass_storage *ms,
+ struct usb_msc_trans *trans,
+ enum trans_event event)
+{
+ if (EVENT_CBW_VALID == event) {
+ /* Setup the default success */
+ trans->csw_sent = 0;
+ trans->csw.csw.dCSWSignature = CSW_SIGNATURE;
+ trans->csw.csw.dCSWTag = trans->cbw.cbw.dCBWTag;
+ trans->csw.csw.dCSWDataResidue = 0;
+ trans->csw.csw.bCSWStatus = CSW_STATUS_SUCCESS;
+
+ trans->bytes_to_write = 0;
+ trans->bytes_to_read = 0;
+ trans->byte_count = 0;
+ }
+
+ switch (trans->cbw.cbw.CBWCB[0]) {
+ case SCSI_TEST_UNIT_READY:
+ case SCSI_SEND_DIAGNOSTIC:
+ /* Do nothing, just send the success. */
+ set_sbc_status_good(ms);
+ break;
+ case SCSI_FORMAT_UNIT:
+ scsi_format_unit(ms, trans, event);
+ break;
+ case SCSI_REQUEST_SENSE:
+ scsi_request_sense(ms, trans, event);
+ break;
+ case SCSI_MODE_SENSE_6:
+ scsi_mode_sense_6(ms, trans, event);
+ break;
+ case SCSI_READ_6:
+ scsi_read_6(ms, trans, event);
+ break;
+ case SCSI_INQUIRY:
+ scsi_inquiry(ms, trans, event);
+ break;
+ case SCSI_READ_CAPACITY:
+ scsi_read_capacity(ms, trans, event);
+ break;
+ case SCSI_READ_10:
+ scsi_read_10(ms, trans, event);
+ break;
+ case SCSI_WRITE_6:
+ scsi_write_6(ms, trans, event);
+ break;
+ case SCSI_WRITE_10:
+ scsi_write_10(ms, trans, event);
+ break;
+ default:
+ set_sbc_status(ms, SBC_SENSE_KEY_ILLEGAL_REQUEST,
+ SBC_ASC_INVALID_COMMAND_OPERATION_CODE,
+ SBC_ASCQ_NA);
+
+ trans->bytes_to_write = 0;
+ trans->bytes_to_read = 0;
+ trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
+ break;
+ }
+}
+
+/*-- USB Mass Storage Layer --------------------------------------------------*/
+
+/** @brief Handle the USB 'OUT' requests. */
+static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
+{
+ usbd_mass_storage *ms;
+ struct usb_msc_trans *trans;
+ int len, max_len, left;
+ void *p;
+
+ ms = &_mass_storage;
+ trans = &ms->trans;
+
+ /* RX only */
+ left = sizeof(struct usb_msc_cbw) - trans->cbw_cnt;
+ if (0 < left) {
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->cbw.buf[0x1ff & trans->cbw_cnt];
+ len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
+ trans->cbw_cnt += len;
+
+ if (sizeof(struct usb_msc_cbw) == trans->cbw_cnt) {
+ scsi_command(ms, trans, EVENT_CBW_VALID);
+ if (trans->byte_count < trans->bytes_to_read) {
+ /* We must wait until there is something to
+ * read again. */
+ return;
+ }
+ }
+ }
+
+ if (trans->byte_count < trans->bytes_to_read) {
+ if (0 < trans->block_count) {
+ if ((0 == trans->byte_count) && (NULL != ms->lock)){
+ (*ms->lock)();
+ }
+ }
+
+ left = trans->bytes_to_read - trans->byte_count;
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->msd_buf[0x1ff & trans->byte_count];
+ len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
+ trans->byte_count += len;
+
+ if (0 < trans->block_count) {
+ if (0 == (0x1ff & trans->byte_count)) {
+ uint32_t lba;
+
+ lba = trans->lba_start + trans->current_block;
+ if (0 != (*ms->write_block)(lba, trans->msd_buf)) {
+ /* Error */
+ }
+ trans->current_block++;
+ }
+ }
+ } else if (trans->byte_count < trans->bytes_to_write) {
+ if (0 < trans->block_count) {
+ if ((0 == trans->byte_count) && (NULL != ms->lock)) {
+ (*ms->lock)();
+ }
+
+ if (0 == (0x1ff & trans->byte_count)) {
+ uint32_t lba;
+
+ lba = trans->lba_start + trans->current_block;
+ if (0 != (*ms->read_block)(lba, trans->msd_buf)) {
+ /* Error */
+ }
+ trans->current_block++;
+ }
+ }
+
+ left = trans->bytes_to_write - trans->byte_count;
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->msd_buf[0x1ff & trans->byte_count];
+ len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len);
+ trans->byte_count += len;
+ } else {
+ if (0 < trans->block_count) {
+ if (trans->current_block == trans->block_count) {
+ uint32_t lba;
+
+ lba = trans->lba_start + trans->current_block;
+ if (0 != (*ms->write_block)(lba, trans->msd_buf)) {
+ /* Error */
+ }
+
+ trans->current_block = 0;
+ if (NULL != ms->unlock){
+ (*ms->unlock)();
+ }
+ }
+ }
+ if (false == trans->csw_valid) {
+ scsi_command(ms, trans, EVENT_NEED_STATUS);
+ trans->csw_valid = true;
+ }
+
+ left = sizeof(struct usb_msc_csw) - trans->csw_sent;
+ if (0 < left) {
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->csw.buf[trans->csw_sent];
+ len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len);
+ trans->csw_sent += len;
+ }
+ }
+}
+
+/** @brief Handle the USB 'IN' requests. */
+static void msc_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
+{
+ usbd_mass_storage *ms;
+ struct usb_msc_trans *trans;
+ int len, max_len, left;
+ void *p;
+
+ ms = &_mass_storage;
+ trans = &ms->trans;
+
+ if (trans->byte_count < trans->bytes_to_write) {
+ if (0 < trans->block_count) {
+ if (0 == (0x1ff & trans->byte_count)) {
+ uint32_t lba;
+
+ lba = trans->lba_start + trans->current_block;
+ if (0 != (*ms->read_block)(lba, trans->msd_buf)) {
+ /* Error */
+ }
+ trans->current_block++;
+ }
+ }
+
+ left = trans->bytes_to_write - trans->byte_count;
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->msd_buf[0x1ff & trans->byte_count];
+ len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
+ trans->byte_count += len;
+ } else {
+ if (0 < trans->block_count) {
+ if (trans->current_block == trans->block_count) {
+ trans->current_block = 0;
+ if (NULL != ms->unlock){
+ (*ms->unlock)();
+ }
+ }
+ }
+ if (false == trans->csw_valid) {
+ scsi_command(ms, trans, EVENT_NEED_STATUS);
+ trans->csw_valid = true;
+ }
+
+ left = sizeof(struct usb_msc_csw) - trans->csw_sent;
+ if (0 < left) {
+ max_len = MIN(ms->ep_out_size, left);
+ p = &trans->csw.buf[trans->csw_sent];
+ len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
+ trans->csw_sent += len;
+ } else if (sizeof(struct usb_msc_csw) == trans->csw_sent) {
+ /* End of transaction */
+ trans->lba_start = 0xffffffff;
+ trans->block_count = 0;
+ trans->current_block = 0;
+ trans->cbw_cnt = 0;
+ trans->bytes_to_read = 0;
+ trans->bytes_to_write = 0;
+ trans->byte_count = 0;
+ trans->csw_sent = 0;
+ trans->csw_valid = false;
+ }
+ }
+}
+
+/** @brief Handle various control requests related to the msc storage
+ * interface.
+ */
+static int msc_control_request(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+ void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
+{
+ (void)complete;
+ (void)usbd_dev;
+
+ switch (req->bRequest) {
+ case USB_MSC_REQ_BULK_ONLY_RESET:
+ /* Do any special reset code here. */
+ return USBD_REQ_HANDLED;
+ case USB_MSC_REQ_GET_MAX_LUN:
+ /* Return the number of LUNs. We use 0. */
+ *buf[0] = 0;
+ *len = 1;
+ return USBD_REQ_HANDLED;
+ }
+
+ return USBD_REQ_NOTSUPP;
+}
+
+/** @brief Setup the endpoints to be bulk & register the callbacks. */
+static void msc_set_config(usbd_device *usbd_dev, uint16_t wValue)
+{
+ usbd_mass_storage *ms = &_mass_storage;
+
+ (void)wValue;
+
+ usbd_ep_setup(usbd_dev, ms->ep_in, USB_ENDPOINT_ATTR_BULK,
+ ms->ep_in_size, msc_data_tx_cb);
+ usbd_ep_setup(usbd_dev, ms->ep_out, USB_ENDPOINT_ATTR_BULK,
+ ms->ep_out_size, msc_data_rx_cb);
+
+ usbd_register_control_callback(
+ usbd_dev,
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ msc_control_request);
+}
+
+/** @addtogroup usb_msc */
+/** @{ */
+
+/** @brief Initializes the USB Mass Storage subsystem.
+
+@note Currently you can only have this profile active.
+
+@param[in] usbd_dev The USB device to associate the Mass Storage with.
+@param[in] ep_in The USB 'IN' endpoint.
+@param[in] ep_in_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
+@param[in] ep_out The USB 'OUT' endpoint.
+@param[in] ep_out_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
+@param[in] vendor_id The SCSI vendor ID to return. Maximum used length is 8.
+@param[in] product_id The SCSI product ID to return. Maximum used length is 16.
+@param[in] product_revision_level The SCSI product revision level to return.
+ Maximum used length is 4.
+@param[in] block_count The number of 512-byte blocks available.
+@param[in] read_block The function called when the host requests to read a LBA
+ block. Must _NOT_ be NULL.
+@param[in] write_block The function called when the host requests to write a
+ LBA block. Must _NOT_ be NULL.
+
+@return Pointer to the usbd_mass_storage struct.
+*/
+usbd_mass_storage *usb_msc_init(usbd_device *usbd_dev,
+ uint8_t ep_in, uint8_t ep_in_size,
+ uint8_t ep_out, uint8_t ep_out_size,
+ const char *vendor_id,
+ const char *product_id,
+ const char *product_revision_level,
+ const uint32_t block_count,
+ int (*read_block)(uint32_t lba, uint8_t *copy_to),
+ int (*write_block)(uint32_t lba, const uint8_t *copy_from))
+{
+ _mass_storage.usbd_dev = usbd_dev;
+ _mass_storage.ep_in = ep_in;
+ _mass_storage.ep_in_size = ep_in_size;
+ _mass_storage.ep_out = ep_out;
+ _mass_storage.ep_out_size = ep_out_size;
+ _mass_storage.vendor_id = vendor_id;
+ _mass_storage.product_id = product_id;
+ _mass_storage.product_revision_level = product_revision_level;
+ _mass_storage.block_count = block_count - 1;
+ _mass_storage.read_block = read_block;
+ _mass_storage.write_block = write_block;
+ _mass_storage.lock = NULL;
+ _mass_storage.unlock = NULL;
+
+ _mass_storage.trans.lba_start = 0xffffffff;
+ _mass_storage.trans.block_count = 0;
+ _mass_storage.trans.current_block = 0;
+ _mass_storage.trans.cbw_cnt = 0;
+ _mass_storage.trans.bytes_to_read = 0;
+ _mass_storage.trans.bytes_to_write = 0;
+ _mass_storage.trans.byte_count = 0;
+ _mass_storage.trans.csw_valid = false;
+ _mass_storage.trans.csw_sent = 0;
+
+ set_sbc_status_good(&_mass_storage);
+
+ usbd_register_set_config_callback(usbd_dev, msc_set_config);
+
+ return &_mass_storage;
+}
+
+/** @} */
diff --git a/libopencm3/lib/usb/usb_private.h b/libopencm3/lib/usb/usb_private.h
new file mode 100644
index 0000000..81466df
--- /dev/null
+++ b/libopencm3/lib/usb/usb_private.h
@@ -0,0 +1,163 @@
+/** @defgroup usb_private_defines USB Private Structures
+
+@brief <b>Defined Constants and Types for the USB Private Structures</b>
+
+@ingroup USB_defines
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Gareth McMullin <gareth@blacksphere.co.nz>
+
+@date 10 March 2013
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#ifndef __USB_PRIVATE_H
+#define __USB_PRIVATE_H
+
+#define MAX_USER_CONTROL_CALLBACK 4
+#define MAX_USER_SET_CONFIG_CALLBACK 4
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/** Internal collection of device information. */
+struct _usbd_device {
+ const struct usb_device_descriptor *desc;
+ const struct usb_config_descriptor *config;
+ const char **strings;
+ int num_strings;
+
+ uint8_t *ctrl_buf; /**< Internal buffer used for control transfers */
+ uint16_t ctrl_buf_len;
+
+ uint8_t current_address;
+ uint8_t current_config;
+
+ uint16_t pm_top; /**< Top of allocated endpoint buffer memory */
+
+ /* User callback functions for various USB events */
+ void (*user_callback_reset)(void);
+ void (*user_callback_suspend)(void);
+ void (*user_callback_resume)(void);
+ void (*user_callback_sof)(void);
+
+ struct usb_control_state {
+ enum {
+ IDLE, STALLED,
+ DATA_IN, LAST_DATA_IN, STATUS_IN,
+ DATA_OUT, LAST_DATA_OUT, STATUS_OUT,
+ } state;
+ struct usb_setup_data req __attribute__((aligned(4)));
+ uint8_t *ctrl_buf;
+ uint16_t ctrl_len;
+ void (*complete)(usbd_device *usbd_dev,
+ struct usb_setup_data *req);
+ } control_state;
+
+ struct user_control_callback {
+ usbd_control_callback cb;
+ uint8_t type;
+ uint8_t type_mask;
+ } user_control_callback[MAX_USER_CONTROL_CALLBACK];
+
+ void (*user_callback_ctr[8][3])(usbd_device *usbd_dev, uint8_t ea);
+
+ /* User callback function for some standard USB function hooks */
+ void (*user_callback_set_config[MAX_USER_SET_CONFIG_CALLBACK])
+ (usbd_device *usbd_dev, uint16_t wValue);
+
+ const struct _usbd_driver *driver;
+
+ /* private driver data */
+
+ uint16_t fifo_mem_top;
+ uint16_t fifo_mem_top_ep0;
+ uint8_t force_nak[4];
+ /*
+ * We keep a backup copy of the out endpoint size registers to restore
+ * them after a transaction.
+ */
+ uint32_t doeptsiz[4];
+ /*
+ * Received packet size for each endpoint. This is assigned in
+ * stm32f107_poll() which reads the packet status push register GRXSTSP
+ * for use in stm32f107_ep_read_packet().
+ */
+ uint16_t rxbcnt;
+};
+
+enum _usbd_transaction {
+ USB_TRANSACTION_IN,
+ USB_TRANSACTION_OUT,
+ USB_TRANSACTION_SETUP,
+};
+
+/* Do not appear to belong to the API, so are omitted from docs */
+/**@}*/
+
+void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea);
+void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea);
+void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea);
+
+int _usbd_standard_request_device(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len);
+int _usbd_standard_request_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len);
+int _usbd_standard_request_endpoint(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len);
+int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len);
+
+void _usbd_reset(usbd_device *usbd_dev);
+
+/* Functions provided by the hardware abstraction. */
+struct _usbd_driver {
+ usbd_device *(*init)(void);
+ void (*set_address)(usbd_device *usbd_dev, uint8_t addr);
+ void (*ep_setup)(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
+ uint16_t max_size,
+ void (*cb)(usbd_device *usbd_dev, uint8_t ep));
+ void (*ep_reset)(usbd_device *usbd_dev);
+ void (*ep_stall_set)(usbd_device *usbd_dev, uint8_t addr,
+ uint8_t stall);
+ void (*ep_nak_set)(usbd_device *usbd_dev, uint8_t addr, uint8_t nak);
+ uint8_t (*ep_stall_get)(usbd_device *usbd_dev, uint8_t addr);
+ uint16_t (*ep_write_packet)(usbd_device *usbd_dev, uint8_t addr,
+ const void *buf, uint16_t len);
+ uint16_t (*ep_read_packet)(usbd_device *usbd_dev, uint8_t addr,
+ void *buf, uint16_t len);
+ void (*poll)(usbd_device *usbd_dev);
+ void (*disconnect)(usbd_device *usbd_dev, bool disconnected);
+ uint32_t base_address;
+ bool set_address_before_status;
+ uint16_t rx_fifo_size;
+};
+
+#endif
+
diff --git a/libopencm3/lib/usb/usb_standard.c b/libopencm3/lib/usb/usb_standard.c
new file mode 100644
index 0000000..3b0dac9
--- /dev/null
+++ b/libopencm3/lib/usb/usb_standard.c
@@ -0,0 +1,532 @@
+/** @defgroup usb_standard_file Generic USB Standard Request Interface
+
+@ingroup USB
+
+@brief <b>Generic USB Standard Request Interface</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Gareth McMullin <gareth@blacksphere.co.nz>
+
+@date 10 March 2013
+
+LGPL License Terms @ref lgpl_license
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <string.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+
+int usbd_register_set_config_callback(usbd_device *usbd_dev,
+ void (*callback)(usbd_device *usbd_dev,
+ uint16_t wValue))
+{
+ int i;
+
+ for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) {
+ if (usbd_dev->user_callback_set_config[i])
+ continue;
+
+ usbd_dev->user_callback_set_config[i] = callback;
+ return 0;
+ }
+
+ return -1;
+}
+
+static uint16_t build_config_descriptor(usbd_device *usbd_dev,
+ uint8_t index, uint8_t *buf, uint16_t len)
+{
+ uint8_t *tmpbuf = buf;
+ const struct usb_config_descriptor *cfg = &usbd_dev->config[index];
+ uint16_t count, total = 0, totallen = 0;
+ uint16_t i, j, k;
+
+ memcpy(buf, cfg, count = MIN(len, cfg->bLength));
+ buf += count;
+ len -= count;
+ total += count;
+ totallen += cfg->bLength;
+
+ /* For each interface... */
+ for (i = 0; i < cfg->bNumInterfaces; i++) {
+ /* Interface Association Descriptor, if any */
+ if (cfg->interface[i].iface_assoc) {
+ const struct usb_iface_assoc_descriptor *assoc =
+ cfg->interface[i].iface_assoc;
+ memcpy(buf, assoc, count = MIN(len, assoc->bLength));
+ buf += count;
+ len -= count;
+ total += count;
+ totallen += assoc->bLength;
+ }
+ /* For each alternate setting... */
+ for (j = 0; j < cfg->interface[i].num_altsetting; j++) {
+ const struct usb_interface_descriptor *iface =
+ &cfg->interface[i].altsetting[j];
+ /* Copy interface descriptor. */
+ memcpy(buf, iface, count = MIN(len, iface->bLength));
+ buf += count;
+ len -= count;
+ total += count;
+ totallen += iface->bLength;
+ /* Copy extra bytes (function descriptors). */
+ memcpy(buf, iface->extra,
+ count = MIN(len, iface->extralen));
+ buf += count;
+ len -= count;
+ total += count;
+ totallen += iface->extralen;
+ /* For each endpoint... */
+ for (k = 0; k < iface->bNumEndpoints; k++) {
+ const struct usb_endpoint_descriptor *ep =
+ &iface->endpoint[k];
+ memcpy(buf, ep, count = MIN(len, ep->bLength));
+ buf += count;
+ len -= count;
+ total += count;
+ totallen += ep->bLength;
+ }
+ }
+ }
+
+ /* Fill in wTotalLength. */
+ *(uint16_t *)(tmpbuf + 2) = totallen;
+
+ return total;
+}
+
+static int usb_descriptor_type(uint16_t wValue)
+{
+ return wValue >> 8;
+}
+
+static int usb_descriptor_index(uint16_t wValue)
+{
+ return wValue & 0xFF;
+}
+
+static int usb_standard_get_descriptor(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ int i, array_idx, descr_idx;
+ struct usb_string_descriptor *sd;
+
+ descr_idx = usb_descriptor_index(req->wValue);
+
+ switch (usb_descriptor_type(req->wValue)) {
+ case USB_DT_DEVICE:
+ *buf = (uint8_t *) usbd_dev->desc;
+ *len = MIN(*len, usbd_dev->desc->bLength);
+ return USBD_REQ_HANDLED;
+ case USB_DT_CONFIGURATION:
+ *buf = usbd_dev->ctrl_buf;
+ *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len);
+ return USBD_REQ_HANDLED;
+ case USB_DT_STRING:
+ sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf;
+
+ if (descr_idx == 0) {
+ /* Send sane Language ID descriptor... */
+ sd->wData[0] = USB_LANGID_ENGLISH_US;
+ sd->bLength = sizeof(sd->bLength) +
+ sizeof(sd->bDescriptorType) +
+ sizeof(sd->wData[0]);
+
+ *len = MIN(*len, sd->bLength);
+ } else {
+ array_idx = descr_idx - 1;
+
+ if (!usbd_dev->strings) {
+ /* Device doesn't support strings. */
+ return USBD_REQ_NOTSUPP;
+ }
+
+ /* Check that string index is in range. */
+ if (array_idx >= usbd_dev->num_strings) {
+ return USBD_REQ_NOTSUPP;
+ }
+
+ /* Strings with Language ID differnet from
+ * USB_LANGID_ENGLISH_US are not supported */
+ if (req->wIndex != USB_LANGID_ENGLISH_US) {
+ return USBD_REQ_NOTSUPP;
+ }
+
+ /* Ths string is returned as UTF16, hence the
+ * multiplication
+ */
+ sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 +
+ sizeof(sd->bLength) +
+ sizeof(sd->bDescriptorType);
+
+ *len = MIN(*len, sd->bLength);
+
+ for (i = 0; i < (*len / 2) - 1; i++) {
+ sd->wData[i] =
+ usbd_dev->strings[array_idx][i];
+ }
+ }
+
+ sd->bDescriptorType = USB_DT_STRING;
+ *buf = (uint8_t *)sd;
+
+ return USBD_REQ_HANDLED;
+ }
+ return USBD_REQ_NOTSUPP;
+}
+
+static int usb_standard_set_address(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len)
+{
+ (void)req;
+ (void)buf;
+ (void)len;
+
+ /* The actual address is only latched at the STATUS IN stage. */
+ if ((req->bmRequestType != 0) || (req->wValue >= 128)) {
+ return 0;
+ }
+
+ usbd_dev->current_address = req->wValue;
+
+ /*
+ * Special workaround for STM32F10[57] that require the address
+ * to be set here. This is undocumented!
+ */
+ if (usbd_dev->driver->set_address_before_status) {
+ usbd_dev->driver->set_address(usbd_dev, req->wValue);
+ }
+
+ return 1;
+}
+
+static int usb_standard_set_configuration(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ int i;
+
+ (void)req;
+ (void)buf;
+ (void)len;
+
+ /* Is this correct, or should we reset alternate settings. */
+ if (req->wValue == usbd_dev->current_config) {
+ return 1;
+ }
+
+ usbd_dev->current_config = req->wValue;
+
+ /* Reset all endpoints. */
+ usbd_dev->driver->ep_reset(usbd_dev);
+
+ if (usbd_dev->user_callback_set_config) {
+ /*
+ * Flush control callbacks. These will be reregistered
+ * by the user handler.
+ */
+ for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
+ usbd_dev->user_control_callback[i].cb = NULL;
+ }
+
+ for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) {
+ if (usbd_dev->user_callback_set_config[i]) {
+ usbd_dev->user_callback_set_config[i](usbd_dev,
+ req->wValue);
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int usb_standard_get_configuration(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)req;
+
+ if (*len > 1) {
+ *len = 1;
+ }
+ (*buf)[0] = usbd_dev->current_config;
+
+ return 1;
+}
+
+static int usb_standard_set_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)usbd_dev;
+ (void)req;
+ (void)buf;
+
+ /* FIXME: Adapt if we have more than one interface. */
+ if (req->wValue != 0) {
+ return 0;
+ }
+ *len = 0;
+
+ return 1;
+}
+
+static int usb_standard_get_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)usbd_dev;
+ (void)req;
+ (void)buf;
+
+ /* FIXME: Adapt if we have more than one interface. */
+ *len = 1;
+ (*buf)[0] = 0;
+
+ return 1;
+}
+
+static int usb_standard_device_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)usbd_dev;
+ (void)req;
+
+ /* bit 0: self powered */
+ /* bit 1: remote wakeup */
+ if (*len > 2) {
+ *len = 2;
+ }
+ (*buf)[0] = 0;
+ (*buf)[1] = 0;
+
+ return 1;
+}
+
+static int usb_standard_interface_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)usbd_dev;
+ (void)req;
+ /* not defined */
+
+ if (*len > 2) {
+ *len = 2;
+ }
+ (*buf)[0] = 0;
+ (*buf)[1] = 0;
+
+ return 1;
+}
+
+static int usb_standard_endpoint_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)req;
+
+ if (*len > 2) {
+ *len = 2;
+ }
+ (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0;
+ (*buf)[1] = 0;
+
+ return 1;
+}
+
+static int usb_standard_endpoint_stall(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)buf;
+ (void)len;
+
+ usbd_ep_stall_set(usbd_dev, req->wIndex, 1);
+
+ return 1;
+}
+
+static int usb_standard_endpoint_unstall(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ (void)buf;
+ (void)len;
+
+ usbd_ep_stall_set(usbd_dev, req->wIndex, 0);
+
+ return 1;
+}
+
+/* Do not appear to belong to the API, so are omitted from docs */
+/**@}*/
+
+int _usbd_standard_request_device(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len)
+{
+ int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len) = NULL;
+
+ switch (req->bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ if (req->wValue == USB_FEAT_DEVICE_REMOTE_WAKEUP) {
+ /* Device wakeup code goes here. */
+ }
+
+ if (req->wValue == USB_FEAT_TEST_MODE) {
+ /* Test mode code goes here. */
+ }
+
+ break;
+ case USB_REQ_SET_ADDRESS:
+ /*
+ * SET ADDRESS is an exception.
+ * It is only processed at STATUS stage.
+ */
+ command = usb_standard_set_address;
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ command = usb_standard_set_configuration;
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ command = usb_standard_get_configuration;
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ command = usb_standard_get_descriptor;
+ break;
+ case USB_REQ_GET_STATUS:
+ /*
+ * GET_STATUS always responds with zero reply.
+ * The application may override this behaviour.
+ */
+ command = usb_standard_device_get_status;
+ break;
+ case USB_REQ_SET_DESCRIPTOR:
+ /* SET_DESCRIPTOR is optional and not implemented. */
+ break;
+ }
+
+ if (!command) {
+ return 0;
+ }
+
+ return command(usbd_dev, req, buf, len);
+}
+
+int _usbd_standard_request_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len)
+{
+ int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len) = NULL;
+
+ switch (req->bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ /* not defined */
+ break;
+ case USB_REQ_GET_INTERFACE:
+ command = usb_standard_get_interface;
+ break;
+ case USB_REQ_SET_INTERFACE:
+ command = usb_standard_set_interface;
+ break;
+ case USB_REQ_GET_STATUS:
+ command = usb_standard_interface_get_status;
+ break;
+ }
+
+ if (!command) {
+ return 0;
+ }
+
+ return command(usbd_dev, req, buf, len);
+}
+
+int _usbd_standard_request_endpoint(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len)
+{
+ int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len) = NULL;
+
+ switch (req->bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ if (req->wValue == USB_FEAT_ENDPOINT_HALT) {
+ command = usb_standard_endpoint_unstall;
+ }
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (req->wValue == USB_FEAT_ENDPOINT_HALT) {
+ command = usb_standard_endpoint_stall;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ command = usb_standard_endpoint_get_status;
+ break;
+ case USB_REQ_SET_SYNCH_FRAME:
+ /* FIXME: SYNCH_FRAME is not implemented. */
+ /*
+ * SYNCH_FRAME is used for synchronization of isochronous
+ * endpoints which are not yet implemented.
+ */
+ break;
+ }
+
+ if (!command) {
+ return 0;
+ }
+
+ return command(usbd_dev, req, buf, len);
+}
+
+int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len)
+{
+ /* FIXME: Have class/vendor requests as well. */
+ if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) {
+ return 0;
+ }
+
+ switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) {
+ case USB_REQ_TYPE_DEVICE:
+ return _usbd_standard_request_device(usbd_dev, req, buf, len);
+ case USB_REQ_TYPE_INTERFACE:
+ return _usbd_standard_request_interface(usbd_dev, req,
+ buf, len);
+ case USB_REQ_TYPE_ENDPOINT:
+ return _usbd_standard_request_endpoint(usbd_dev, req, buf, len);
+ default:
+ return 0;
+ }
+}
+