summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2016-07-25 15:18:40 +0200
committerNicolas Schodet2019-10-09 23:05:44 +0200
commit4695b47da68a5b2f75270bea21e15b8f1b9fd6ff (patch)
tree6e5ef4d34ee69bcd6c6627f25a0ca3aa902d47e3
parentd7df91926bdb529e68eff9a215aef72072803b6e (diff)
Switch to CMSIS
-rw-r--r--.gitmodules3
-rw-r--r--build/stm32.mk30
-rw-r--r--build/stm32f1.mk2
-rw-r--r--build/stm32f4.mk2
m---------lib/libopencm30
-rw-r--r--ucoo/arch/Module2
-rw-r--r--ucoo/arch/arch.arm.hh37
-rw-r--r--ucoo/arch/arch.hh16
-rw-r--r--ucoo/arch/arch.host.hh35
-rw-r--r--ucoo/arch/arch.stm32.cc4
-rw-r--r--ucoo/arch/arch.stm32f1.cc13
-rw-r--r--ucoo/arch/arch.stm32f4.cc16
-rw-r--r--ucoo/arch/arch_common.arm.hh4
-rw-r--r--ucoo/arch/arch_common.hh8
-rw-r--r--ucoo/arch/arch_common.host.hh4
-rw-r--r--ucoo/arch/interrupt.arm.hh107
-rw-r--r--ucoo/arch/interrupt.stm32f1.hh104
-rw-r--r--ucoo/arch/interrupt.stm32f4.hh127
-rw-r--r--ucoo/arch/ld/common.ld67
-rw-r--r--ucoo/arch/ld/stm32f1.ld (renamed from ucoo/arch/stm32f1/stm32f1.ld)2
-rw-r--r--ucoo/arch/ld/stm32f4.ld (renamed from ucoo/arch/stm32f4/stm32f4.ld)2
-rw-r--r--ucoo/arch/rcc.stm32.hh36
-rw-r--r--ucoo/arch/rcc.stm32f1.cc134
-rw-r--r--ucoo/arch/rcc.stm32f1.hh143
-rw-r--r--ucoo/arch/rcc.stm32f4.cc125
-rw-r--r--ucoo/arch/rcc.stm32f4.hh193
-rw-r--r--ucoo/arch/reg.hh35
-rw-r--r--ucoo/arch/reg.stm32.hh80
-rw-r--r--ucoo/arch/reg.stm32f1.hh180
-rw-r--r--ucoo/arch/reg.stm32f4.hh347
-rw-r--r--ucoo/arch/vector.arm.cc136
-rw-r--r--ucoo/arch/vector.stm32f1.hh220
-rw-r--r--ucoo/arch/vector.stm32f4.hh307
-rw-r--r--ucoo/base/fs/romfs/test/Makefile2
-rw-r--r--ucoo/base/proto/test/Makefile2
-rw-r--r--ucoo/base/test/Config10
-rw-r--r--ucoo/base/test/test.stm32.cc31
-rw-r--r--ucoo/base/test/test/Makefile2
-rw-r--r--ucoo/common.hh4
-rw-r--r--ucoo/dev/avrisp/test/test_avrisp.cc10
-rw-r--r--ucoo/dev/lcd/test/test_lcd.cc16
-rw-r--r--ucoo/hal/adc/adc_hard.stm32f4.cc36
-rw-r--r--ucoo/hal/adc/adc_hard.stm32f4.hh67
-rw-r--r--ucoo/hal/adc/test/Makefile2
-rw-r--r--ucoo/hal/adc/test/test_adc.cc9
-rw-r--r--ucoo/hal/exti/exti.stm32.cc209
-rw-r--r--ucoo/hal/exti/exti.stm32.hh17
-rw-r--r--ucoo/hal/exti/test/test_exti.stm32.cc16
-rw-r--r--ucoo/hal/gpio/gpio.stm32f1.cc60
-rw-r--r--ucoo/hal/gpio/gpio.stm32f1.hh67
-rw-r--r--ucoo/hal/gpio/gpio.stm32f4.cc104
-rw-r--r--ucoo/hal/gpio/gpio.stm32f4.hh74
-rw-r--r--ucoo/hal/gpio/test/test_gpio.stm32f1.cc14
-rw-r--r--ucoo/hal/gpio/test/test_gpio.stm32f4.cc20
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.cc187
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.hh26
-rw-r--r--ucoo/hal/i2c/test/Makefile2
-rw-r--r--ucoo/hal/i2c/test/test_i2c.cc28
-rw-r--r--ucoo/hal/sdram/sdram.stm32f4.cc94
-rw-r--r--ucoo/hal/sdram/sdram.stm32f4.hh3
-rw-r--r--ucoo/hal/sdram/test/test_sdram.stm32f4.cc39
-rw-r--r--ucoo/hal/self_programming/self_programming.stm32f1.cc42
-rw-r--r--ucoo/hal/self_programming/self_programming.stm32f4.cc38
-rw-r--r--ucoo/hal/spi/spi_hard.stm32.cc86
-rw-r--r--ucoo/hal/spi/spi_hard.stm32.hh21
-rw-r--r--ucoo/hal/spi/test/test_spi.cc19
-rw-r--r--ucoo/hal/timer/test/Makefile2
-rw-r--r--ucoo/hal/timer/test/test_timer.cc22
-rw-r--r--ucoo/hal/timer/timer.stm32.hh29
-rw-r--r--ucoo/hal/timer/timer.stm32.tcc428
-rw-r--r--ucoo/hal/uart/test/Makefile2
-rw-r--r--ucoo/hal/uart/test/test_uart.cc17
-rw-r--r--ucoo/hal/uart/test/test_uart_disc.cc23
-rw-r--r--ucoo/hal/uart/uart.stm32.cc121
-rw-r--r--ucoo/hal/uart/uart.stm32.hh18
-rw-r--r--ucoo/hal/usb/Config13
-rw-r--r--ucoo/hal/usb/Module6
-rw-r--r--ucoo/hal/usb/test/Config2
-rw-r--r--ucoo/hal/usb/test/Makefile2
-rw-r--r--ucoo/hal/usb/test/test_usb.cc59
-rw-r--r--ucoo/hal/usb/usb.hh4
-rw-r--r--ucoo/hal/usb/usb.stm32.cc311
-rw-r--r--ucoo/hal/usb/usb.stm32.hh106
-rw-r--r--ucoo/hal/usb/usb_application.cc222
-rw-r--r--ucoo/hal/usb/usb_application.hh158
-rw-r--r--ucoo/hal/usb/usb_cdc.cc235
-rw-r--r--ucoo/hal/usb/usb_cdc.hh81
-rw-r--r--ucoo/hal/usb/usb_cdc_def.hh75
-rw-r--r--ucoo/hal/usb/usb_cdc_desc.hh174
-rw-r--r--ucoo/hal/usb/usb_def.hh71
-rw-r--r--ucoo/hal/usb/usb_desc.hh406
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.c303
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.h33
-rw-r--r--ucoo/hal/usb/usb_driver.cc130
-rw-r--r--ucoo/hal/usb/usb_driver.hh120
-rw-r--r--ucoo/hal/usb/usb_dwc_otg.stm32.cc412
-rw-r--r--ucoo/hal/usb/usb_dwc_otg.stm32.hh94
-rw-r--r--ucoo/math/test/Makefile2
-rw-r--r--ucoo/utils/bits.hh45
-rw-r--r--ucoo/utils/buffer.hh74
-rw-r--r--ucoo/utils/buffer.tcc125
-rw-r--r--ucoo/utils/delay.arm.cc33
-rw-r--r--ucoo/utils/irq_locked.hh45
-rw-r--r--ucoo/utils/rate_limit.tcc2
-rw-r--r--ucoo/utils/table_lookup.hh51
-rw-r--r--ucoo/utils/test/Makefile2
-rw-r--r--ucoo/utils/test/test_delay.cc30
-rw-r--r--ucoo/utils/trace.hh2
-rw-r--r--ucoo/utils/trace.tcc4
109 files changed, 6189 insertions, 1783 deletions
diff --git a/.gitmodules b/.gitmodules
index f5fdeb9..24de4ec 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "lib/libopencm3"]
- path = lib/libopencm3
- url = https://github.com/libopencm3/libopencm3.git
[submodule "lib/cmsis"]
path = lib/cmsis
url = http://git.ni.fr.eu.org/nicolas/cmsis.git
diff --git a/build/stm32.mk b/build/stm32.mk
index 3a3311b..46c7b8c 100644
--- a/build/stm32.mk
+++ b/build/stm32.mk
@@ -6,19 +6,15 @@ ifndef stm32_once
stm32_once := 1
-# Check for libopencm3.
-LIBOPENCM3_PATH ?= $(UCOO_BASE)/lib/libopencm3
-define stm32_libopencm3
-ifneq ($$(LIBOPENCM3_PATH),)
- $1_LIBOPENCM3_LIB := $$(LIBOPENCM3_PATH)/lib/libopencm3_$(if $2,$2,$1).a
- ifeq ($$(wildcard $$($1_LIBOPENCM3_LIB)),)
- $$(error Can not find libopencm3 library, please run "make lib" in \
- $$(LIBOPENCM3_PATH) or change LIBOPENCM3_PATH (you can set it to \
- empty string to use system library))
- endif
- $1_LIBOPENCM3_CPPFLAGS = -I$$(LIBOPENCM3_PATH)/include
- $1_LIBOPENCM3_LDFLAGS = -L$$(LIBOPENCM3_PATH)/lib
+# Check for cmsis.
+CMSIS_PATH ?= $(UCOO_BASE)/lib/cmsis
+define stm32_cmsis
+$1_CMSIS_LIB := $$(CMSIS_PATH)/Include/cmsis_gcc.h
+ifeq ($$(wildcard $$($1_CMSIS_LIB)),)
+ $$(error Can not find CMSIS library, please put it in $$(CMSIS_PATH) or \
+ change CMSIS_PATH)
endif
+$1_CMSIS_CPPFLAGS = -I$$(CMSIS_PATH)/Include -I$$(CMSIS_PATH)/Device
endef
@@ -29,21 +25,19 @@ stm32_cortex-m4_CPU_CFLAGS = \
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
define stm32_flags
$1_CPPFLAGS = $$(CPPFLAGS) $$($1_DEFS) \
- $$($1_STM32_DEFS) $$($1_LIBOPENCM3_CPPFLAGS)
+ $$($1_STM32_DEFS) $$($1_CMSIS_CPPFLAGS)
$1_CFLAGS = $$(CFLAGS) \
$$(stm32_$$($1_CPU)_CPU_CFLAGS) \
-Wl,--gc-sections -ffunction-sections
$1_CXXFLAGS = $$(sort $$($1_CFLAGS) $$(CXXFLAGS))
$1_ASFLAGS = $$(ASFLAGS)
$1_LDSCRIPT ?= $(if $2,$2,$1).ld
-$1_LDSCRIPT_PATH ?= $$(UCOO_BASE)/ucoo/arch/$(if $2,$2,$1)
+$1_LDSCRIPT_PATH ?= $$(UCOO_BASE)/ucoo/arch/ld
$1_START_ADDRESS ?= $$(if $$(filter y,$$($1_BOOTLOADED)),0x8010000)
$1_SECTION_START = -Wl,--section-start=.text=$$($1_START_ADDRESS)
$1_LDFLAGS = $$(LDFLAGS) -T$$($1_LDSCRIPT) -L$$($1_LDSCRIPT_PATH) \
- $$(if $$($1_START_ADDRESS),$$($1_SECTION_START)) \
- $$($1_LIBOPENCM3_LDFLAGS)
-$1_LDLIBS = -nostartfiles $$(LDLIBS) $$($1_LIBS) \
- -lopencm3_$(if $2,$2,$1)
+ $$(if $$($1_START_ADDRESS),$$($1_SECTION_START))
+$1_LDLIBS = -nostartfiles $$(LDLIBS) $$($1_LIBS)
endef
diff --git a/build/stm32f1.mk b/build/stm32f1.mk
index cb9410f..32209de 100644
--- a/build/stm32f1.mk
+++ b/build/stm32f1.mk
@@ -4,7 +4,7 @@
include $(UCOO_BASE)/build/stm32.mk
-$(eval $(call stm32_libopencm3,stm32f1))
+$(eval $(call stm32_cmsis,stm32f1))
stm32f1_SUBTARGETS = stm32 arm newlib
diff --git a/build/stm32f4.mk b/build/stm32f4.mk
index 8d0aa67..4a73247 100644
--- a/build/stm32f4.mk
+++ b/build/stm32f4.mk
@@ -4,7 +4,7 @@
include $(UCOO_BASE)/build/stm32.mk
-$(eval $(call stm32_libopencm3,stm32f4))
+$(eval $(call stm32_cmsis,stm32f4))
stm32f4_SUBTARGETS = stm32 arm newlib
diff --git a/lib/libopencm3 b/lib/libopencm3
deleted file mode 160000
-Subproject 9b8d44e8a3cc52d83aba3b5547c2bb56cdbd8b6
diff --git a/ucoo/arch/Module b/ucoo/arch/Module
index 9a4989e..625cfd3 100644
--- a/ucoo/arch/Module
+++ b/ucoo/arch/Module
@@ -1,3 +1,5 @@
ucoo_arch_SOURCES := arch.host.cc \
arch.stm32.cc arch.stm32f1.cc arch.stm32f4.cc \
+ rcc.stm32f1.cc rcc.stm32f4.cc \
+ vector.arm.cc \
syscalls.newlib.cc syscalls.cc
diff --git a/ucoo/arch/arch.arm.hh b/ucoo/arch/arch.arm.hh
new file mode 100644
index 0000000..65c835d
--- /dev/null
+++ b/ucoo/arch/arch.arm.hh
@@ -0,0 +1,37 @@
+#ifndef ucoo_arch_arch_arm_hh
+#define ucoo_arch_arch_arm_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+static inline void
+arch_dsb ()
+{
+ __asm__ __volatile__ ("dsb" : : : "memory");
+}
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_arm_hh
diff --git a/ucoo/arch/arch.hh b/ucoo/arch/arch.hh
index e0889bd..2401868 100644
--- a/ucoo/arch/arch.hh
+++ b/ucoo/arch/arch.hh
@@ -24,6 +24,14 @@
//
// }}}
+#if defined (TARGET_arm)
+# include "arch.arm.hh"
+#elif defined (TARGET_host)
+# include "arch.host.hh"
+#else
+# error "not implemented for this target"
+#endif
+
namespace ucoo {
/// Initialise arch, take program arguments.
@@ -34,14 +42,6 @@ arch_init (int argc, const char **argv);
void
arch_reset ();
-#ifdef TARGET_host
-
-/// Retrieve program arguments.
-void
-arch_get_args (int &argc, const char **&argv);
-
-#endif
-
} // namespace ucoo
#endif // ucoo_arch_arch_hh
diff --git a/ucoo/arch/arch.host.hh b/ucoo/arch/arch.host.hh
new file mode 100644
index 0000000..b08864e
--- /dev/null
+++ b/ucoo/arch/arch.host.hh
@@ -0,0 +1,35 @@
+#ifndef ucoo_arch_arch_host_hh
+#define ucoo_arch_arch_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Retrieve program arguments.
+void
+arch_get_args (int &argc, const char **&argv);
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_host_hh
diff --git a/ucoo/arch/arch.stm32.cc b/ucoo/arch/arch.stm32.cc
index aa07575..f48f9fc 100644
--- a/ucoo/arch/arch.stm32.cc
+++ b/ucoo/arch/arch.stm32.cc
@@ -24,14 +24,14 @@
#include "ucoo/arch/arch.hh"
#include "ucoo/common.hh"
-#include <libopencm3/cm3/scb.h>
+#include "ucoo/arch/reg.hh"
namespace ucoo {
void
arch_reset ()
{
- SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
+ NVIC_SystemReset ();
}
void
diff --git a/ucoo/arch/arch.stm32f1.cc b/ucoo/arch/arch.stm32f1.cc
index a2d659c..ca6664b 100644
--- a/ucoo/arch/arch.stm32f1.cc
+++ b/ucoo/arch/arch.stm32f1.cc
@@ -22,17 +22,20 @@
//
// }}}
#include "ucoo/arch/arch.hh"
-#include "ucoo/common.hh"
-
-#include <libopencm3/stm32/rcc.h>
+#include "ucoo/arch/rcc.stm32.hh"
namespace ucoo {
void
arch_init (int argc, const char **argv)
{
- rcc_clock_setup_in_hse_12mhz_out_72mhz ();
- rcc_periph_clock_enable (RCC_AFIO);
+ rcc_sys_clock_setup_pll (72000000, 12000000,
+ 1, // prediv1 => 12 MHz / 1 = 12 MHz
+ 6, // pllmul => 12 MHz * 6 = 72 MHz
+ 2, // apb1_pre => 36 MHz
+ 1, // apb2_pre => 72 MHz
+ 6); // adc_pre => 12 MHz
+ rcc_peripheral_clock_enable (Rcc::AFIO);
}
} // namespace ucoo
diff --git a/ucoo/arch/arch.stm32f4.cc b/ucoo/arch/arch.stm32f4.cc
index 74c7306..c569c65 100644
--- a/ucoo/arch/arch.stm32f4.cc
+++ b/ucoo/arch/arch.stm32f4.cc
@@ -22,18 +22,22 @@
//
// }}}
#include "ucoo/arch/arch.hh"
-#include "ucoo/common.hh"
-
-#include <libopencm3/stm32/rcc.h>
+#include "ucoo/arch/rcc.stm32.hh"
namespace ucoo {
void
arch_init (int argc, const char **argv)
{
- rcc_clock_setup_hse_3v3 (&hse_8mhz_3v3[CLOCK_3V3_120MHZ]);
- rcc_ahb_frequency = 120000000;
- rcc_periph_clock_enable (RCC_SYSCFG);
+ rcc_sys_clock_setup_pll (120000000, 8000000,
+ 4, // pllm => 8 MHz / 4 = 2 MHz
+ 120, // plln => 2 MHz * 120 = 240 MHz
+ 2, // pllp => 240 MHz / 2 = 120 MHz
+ 5, // pllq => 240 MHz / 5 = 48 MHz
+ 4, // apb1_pre => 30 MHz
+ 2, // apb2_pre => 60 MHz
+ SupplyRange::V2_7);
+ rcc_peripheral_clock_enable (Rcc::SYSCFG);
}
} // namespace ucoo
diff --git a/ucoo/arch/arch_common.arm.hh b/ucoo/arch/arch_common.arm.hh
index 7b4abfd..b1c7138 100644
--- a/ucoo/arch/arch_common.arm.hh
+++ b/ucoo/arch/arch_common.arm.hh
@@ -29,6 +29,7 @@ namespace ucoo {
/// Type used to save irq state.
typedef unsigned int irq_flags_t;
+/// Lock interrupts and return previous state.
static inline irq_flags_t
irq_lock (void)
{
@@ -40,7 +41,8 @@ irq_lock (void)
return flags;
}
-inline void
+/// Restore interrupts lock state after an irq_lock.
+static inline void
irq_restore (irq_flags_t flags)
{
__asm__ __volatile__ ("msr PRIMASK, %0"
diff --git a/ucoo/arch/arch_common.hh b/ucoo/arch/arch_common.hh
index ac70e62..dd8458c 100644
--- a/ucoo/arch/arch_common.hh
+++ b/ucoo/arch/arch_common.hh
@@ -32,12 +32,4 @@
# error "not implemented for this target"
#endif
-namespace ucoo {
-
-/// Give some time to other tasks when running in a tight loop.
-void
-yield ();
-
-} // namespace ucoo
-
#endif // ucoo_arch_arch_common_hh
diff --git a/ucoo/arch/arch_common.host.hh b/ucoo/arch/arch_common.host.hh
index 0ee2553..7130a0d 100644
--- a/ucoo/arch/arch_common.host.hh
+++ b/ucoo/arch/arch_common.host.hh
@@ -29,6 +29,7 @@ namespace ucoo {
/// Type used to save irq state.
typedef unsigned int irq_flags_t;
+/// Lock interrupts and return previous state.
static inline irq_flags_t
irq_lock (void)
{
@@ -36,7 +37,8 @@ irq_lock (void)
return 0;
}
-inline void
+/// Restore interrupts lock state after an irq_lock.
+static inline void
irq_restore (irq_flags_t)
{
// Nothing on host, there is no interrupts.
diff --git a/ucoo/arch/interrupt.arm.hh b/ucoo/arch/interrupt.arm.hh
new file mode 100644
index 0000000..10ef261
--- /dev/null
+++ b/ucoo/arch/interrupt.arm.hh
@@ -0,0 +1,107 @@
+#ifndef ucoo_arch_interrupt_arm_hh
+#define ucoo_arch_interrupt_arm_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/reg.hh"
+
+#if defined (TARGET_stm32f4)
+# include "ucoo/arch/interrupt.stm32f4.hh"
+#elif defined (TARGET_stm32f1)
+# include "ucoo/arch/interrupt.stm32f1.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+namespace ucoo {
+
+/// Standard ARM Cortex exceptions.
+enum class Exception
+{
+ RESET = 1,
+ NMI = 2,
+ HARD_FAULT = 3,
+ MEMORY_MANAGEMENT_FAULT = 4,
+ BUS_FAULT = 5,
+ USAGE_FAULT = 6,
+ SV_CALL = 11,
+ PEND_SV = 14,
+ SYSTICK = 15,
+ COUNT
+};
+
+/// Exception vectors are a specialisation of this template.
+template<Exception>
+void
+interrupt ();
+
+/// IRQ vectors are a specialisation of this template.
+template<Irq>
+void
+interrupt ();
+
+/// Enable interrupt source.
+static inline void
+interrupt_enable (Irq irq)
+{
+ const unsigned int n = static_cast<unsigned int> (irq);
+ NVIC->ISER[n / 32] = 1 << (n % 32);
+}
+
+/// Disable interrupt source.
+static inline void
+interrupt_disable (Irq irq)
+{
+ const unsigned int n = static_cast<unsigned int> (irq);
+ NVIC->ICER[n / 32] = 1 << (n % 32);
+}
+
+/// Test if a interrupt source is enabled.
+static inline bool
+interrupt_is_enabled (Irq irq)
+{
+ const unsigned int n = static_cast<unsigned int> (irq);
+ return NVIC->ISER[n / 32] & (1 << (n % 32));
+}
+
+/// Set interrupt priority. Warning: a limited number of MSB bits are used
+/// depending on the hardware implementation.
+static inline void
+interrupt_set_priority (Irq irq, uint8_t priority)
+{
+ const unsigned int n = static_cast<unsigned int> (irq);
+ NVIC->IP[n] = priority;
+}
+
+/// Set exception priority. Warning: a limited number of MSB bits are used
+/// depending on the hardware implementation.
+static inline void
+interrupt_set_priority (Exception ex, uint8_t priority)
+{
+ const unsigned int n = static_cast<unsigned int> (ex);
+ SCB->SHP[n - 4] = priority;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_arch_interrupt_arm_hh
diff --git a/ucoo/arch/interrupt.stm32f1.hh b/ucoo/arch/interrupt.stm32f1.hh
new file mode 100644
index 0000000..74316ce
--- /dev/null
+++ b/ucoo/arch/interrupt.stm32f1.hh
@@ -0,0 +1,104 @@
+#ifndef ucoo_arch_interrupt_stm32f1_hh
+#define ucoo_arch_interrupt_stm32f1_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+enum class Irq
+{
+ WWDG,
+ PVD,
+ TAMPER,
+ RTC,
+ FLASH,
+ RCC,
+ EXTI0,
+ EXTI1,
+ EXTI2,
+ EXTI3,
+ EXTI4,
+ DMA1_Channel1,
+ DMA1_Channel2,
+ DMA1_Channel3,
+ DMA1_Channel4,
+ DMA1_Channel5,
+ DMA1_Channel6,
+ DMA1_Channel7,
+ ADC1_2,
+ CAN1_TX,
+ CAN1_RX0,
+ CAN1_RX1,
+ CAN1_SCE,
+ EXTI9_5,
+ TIM1_BRK,
+ TIM1_UP,
+ TIM1_TRG_COM,
+ TIM1_CC,
+ TIM2,
+ TIM3,
+ TIM4,
+ I2C1_EV,
+ I2C1_ER,
+ I2C2_EV,
+ I2C2_ER,
+ SPI1,
+ SPI2,
+ USART1,
+ USART2,
+ USART3,
+ EXTI15_10,
+ RTC_Alarm,
+ OTG_FS_WKUP,
+ RESERVED_43,
+ RESERVED_44,
+ RESERVED_45,
+ RESERVED_46,
+ RESERVED_47,
+ RESERVED_48,
+ RESERVED_49,
+ TIM5,
+ SPI3,
+ UART4,
+ UART5,
+ TIM6,
+ TIM7,
+ DMA2_Channel1,
+ DMA2_Channel2,
+ DMA2_Channel3,
+ DMA2_Channel4,
+ DMA2_Channel5,
+ RESERVED_61,
+ RESERVED_62,
+ CAN2_TX,
+ CAN2_RX0,
+ CAN2_RX1,
+ CAN2_SCE,
+ OTG_FS,
+ COUNT
+};
+
+} // namespace ucoo
+
+#endif // ucoo_arch_interrupt_stm32f1_hh
diff --git a/ucoo/arch/interrupt.stm32f4.hh b/ucoo/arch/interrupt.stm32f4.hh
new file mode 100644
index 0000000..ffd3912
--- /dev/null
+++ b/ucoo/arch/interrupt.stm32f4.hh
@@ -0,0 +1,127 @@
+#ifndef ucoo_arch_interrupt_stm32f4_hh
+#define ucoo_arch_interrupt_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+enum class Irq
+{
+ WWDG,
+ PVD,
+ TAMP_STAMP,
+ RTC_WKUP,
+ FLASH,
+ RCC,
+ EXTI0,
+ EXTI1,
+ EXTI2,
+ EXTI3,
+ EXTI4,
+ DMA1_Stream0,
+ DMA1_Stream1,
+ DMA1_Stream2,
+ DMA1_Stream3,
+ DMA1_Stream4,
+ DMA1_Stream5,
+ DMA1_Stream6,
+ ADC,
+ CAN1_TX,
+ CAN1_RX0,
+ CAN1_RX1,
+ CAN1_SCE,
+ EXTI9_5,
+ TIM1_BRK_TIM9,
+ TIM1_UP_TIM10,
+ TIM1_TRG_COM_TIM11,
+ TIM1_CC,
+ TIM2,
+ TIM3,
+ TIM4,
+ I2C1_EV,
+ I2C1_ER,
+ I2C2_EV,
+ I2C2_ER,
+ SPI1,
+ SPI2,
+ USART1,
+ USART2,
+ USART3,
+ EXTI15_10,
+ RTC_Alarm,
+ OTG_FS_WKUP,
+ TIM8_BRK_TIM12,
+ TIM8_UP_TIM13,
+ TIM8_TRG_COM_TIM14,
+ TIM8_CC,
+ DMA1_Stream7,
+ FMC,
+ SDIO,
+ TIM5,
+ SPI3,
+ UART4,
+ UART5,
+ TIM6_DAC,
+ TIM7,
+ DMA2_Stream0,
+ DMA2_Stream1,
+ DMA2_Stream2,
+ DMA2_Stream3,
+ DMA2_Stream4,
+ ETH,
+ ETH_WKUP,
+ CAN2_TX,
+ CAN2_RX0,
+ CAN2_RX1,
+ CAN2_SCE,
+ OTG_FS,
+ DMA2_Stream5,
+ DMA2_Stream6,
+ DMA2_Stream7,
+ USART6,
+ I2C3_EV,
+ I2C3_ER,
+ OTG_HS_EP1_OUT,
+ OTG_HS_EP1_IN,
+ OTG_HS_WKUP,
+ OTG_HS,
+ DCMI,
+ CRYP,
+ HASH_RNG,
+ FPU,
+ UART7,
+ UART8,
+ SPI4,
+ SPI5,
+ SPI6,
+ SAI1,
+ LTDC,
+ LTDC_ER,
+ DMA2D,
+ COUNT
+};
+
+} // namespace ucoo
+
+#endif // ucoo_arch_interrupt_stm32f4_hh
diff --git a/ucoo/arch/ld/common.ld b/ucoo/arch/ld/common.ld
new file mode 100644
index 0000000..8b5efb2
--- /dev/null
+++ b/ucoo/arch/ld/common.ld
@@ -0,0 +1,67 @@
+ENTRY(entry)
+
+SECTIONS
+{
+ .text : {
+ KEEP(*(.vectors))
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+ } >rom
+
+ .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
+
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
+ .ARM.exidx : {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .data : {
+ _data = .;
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
+
+ .bss : {
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >ram
+
+ /DISCARD/ : { *(.eh_frame) }
+
+ . = ALIGN(4);
+ end = .;
+}
+
+PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
diff --git a/ucoo/arch/stm32f1/stm32f1.ld b/ucoo/arch/ld/stm32f1.ld
index de413c4..2231ccb 100644
--- a/ucoo/arch/stm32f1/stm32f1.ld
+++ b/ucoo/arch/ld/stm32f1.ld
@@ -3,4 +3,4 @@ MEMORY
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE common.ld
diff --git a/ucoo/arch/stm32f4/stm32f4.ld b/ucoo/arch/ld/stm32f4.ld
index ceef7af..f752426 100644
--- a/ucoo/arch/stm32f4/stm32f4.ld
+++ b/ucoo/arch/ld/stm32f4.ld
@@ -3,4 +3,4 @@ MEMORY
rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
-INCLUDE libopencm3_stm32f4.ld
+INCLUDE common.ld
diff --git a/ucoo/arch/rcc.stm32.hh b/ucoo/arch/rcc.stm32.hh
new file mode 100644
index 0000000..ac8f76c
--- /dev/null
+++ b/ucoo/arch/rcc.stm32.hh
@@ -0,0 +1,36 @@
+#ifndef ucoo_arch_rcc_stm32_hh
+#define ucoo_arch_rcc_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_stm32f4)
+# include "rcc.stm32f4.hh"
+#elif defined (TARGET_stm32f1)
+# include "rcc.stm32f1.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+
+#endif // ucoo_arch_rcc_stm32_hh
diff --git a/ucoo/arch/rcc.stm32f1.cc b/ucoo/arch/rcc.stm32f1.cc
new file mode 100644
index 0000000..3b88e9b
--- /dev/null
+++ b/ucoo/arch/rcc.stm32f1.cc
@@ -0,0 +1,134 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/rcc.stm32f1.hh"
+#include "ucoo/common.hh"
+#include "ucoo/utils/table_lookup.hh"
+
+namespace ucoo {
+
+static const int hsi_freq_hz = 8000000;
+
+int rcc_sys_freq_hz = hsi_freq_hz;
+int rcc_ahb_freq_hz = hsi_freq_hz;
+int rcc_apb1_freq_hz = hsi_freq_hz;
+int rcc_apb2_freq_hz = hsi_freq_hz;
+int rcc_apb1_timer_freq_hz = hsi_freq_hz;
+int rcc_apb2_timer_freq_hz = hsi_freq_hz;
+int rcc_usb_freq_hz = 0;
+
+void
+rcc_sys_clock_setup_pll (int sys_freq_hz, int hse_freq_hz,
+ int prediv1, int pllmul,
+ int apb1_pre, int apb2_pre, int adc_pre)
+{
+ // Switch to HSI as a safe fall back.
+ reg::RCC->CR |= RCC_CR_HSION;
+ while (!(reg::RCC->CR & RCC_CR_HSIRDY))
+ ;
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
+ while ((reg::RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
+ ;
+ // Start HSE if needed.
+ uint32_t pllsrc = 0;
+ int pll_in_freq_hz = hsi_freq_hz / 2;
+ if (hse_freq_hz)
+ {
+ pll_in_freq_hz = hse_freq_hz;
+ pllsrc = RCC_CFGR_PLLSRC;
+ reg::RCC->CR |= RCC_CR_HSEON;
+ while (!(reg::RCC->CR & RCC_CR_HSERDY))
+ ;
+ // May divide by 2.
+ assert (prediv1 == 1 || prediv1 == 2);
+ if (prediv1 == 2)
+ {
+ pllsrc |= RCC_CFGR_PLLXTPRE;
+ pll_in_freq_hz /= 2;
+ }
+ }
+ // Change buses and ADC prescalers.
+ static const LookupTable<int, uint32_t> adc_pre_table[] =
+ {
+ { 2, RCC_CFGR_ADCPRE_DIV2 },
+ { 4, RCC_CFGR_ADCPRE_DIV4 },
+ { 6, RCC_CFGR_ADCPRE_DIV6 },
+ { 8, RCC_CFGR_ADCPRE_DIV8 },
+ };
+ static const LookupTable<int, uint32_t> apb1_pre_table[] =
+ {
+ { 1, RCC_CFGR_PPRE1_DIV1 },
+ { 2, RCC_CFGR_PPRE1_DIV2 },
+ { 4, RCC_CFGR_PPRE1_DIV4 },
+ { 8, RCC_CFGR_PPRE1_DIV8 },
+ { 16, RCC_CFGR_PPRE1_DIV16 },
+ };
+ static const LookupTable<int, uint32_t> apb2_pre_table[] =
+ {
+ { 1, RCC_CFGR_PPRE2_DIV1 },
+ { 2, RCC_CFGR_PPRE2_DIV2 },
+ { 4, RCC_CFGR_PPRE2_DIV4 },
+ { 8, RCC_CFGR_PPRE2_DIV8 },
+ { 16, RCC_CFGR_PPRE2_DIV16 },
+ };
+ uint32_t pre = simple_table_lookup (adc_pre_table, adc_pre)
+ | simple_table_lookup (apb1_pre_table, apb1_pre)
+ | simple_table_lookup (apb2_pre_table, apb2_pre);
+ // Start PLL.
+ static const LookupTable<int, uint32_t> pllmul_table[] =
+ {
+ { 4, RCC_CFGR_PLLMULL4 },
+ { 5, RCC_CFGR_PLLMULL5 },
+ { 6, RCC_CFGR_PLLMULL6 },
+ { 7, RCC_CFGR_PLLMULL7 },
+ { 8, RCC_CFGR_PLLMULL8 },
+ { 9, RCC_CFGR_PLLMULL9 },
+ // Other values (2, 3, 10...16 or 6.5 on connectivity line) not
+ // handled.
+ };
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~(
+ RCC_CFGR_PLLMULL | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC
+ | RCC_CFGR_ADCPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk))
+ | pllsrc | pre | simple_table_lookup (pllmul_table, pllmul);
+ reg::RCC->CR |= RCC_CR_PLLON;
+ while (!(reg::RCC->CR & RCC_CR_PLLRDY))
+ ;
+ // Setup flash.
+ int mhz_per_ws = 24;
+ int ws = (sys_freq_hz - 1) / 1000000 / mhz_per_ws;
+ reg::FLASH->ACR = (reg::FLASH->ACR & ~FLASH_ACR_LATENCY) | ws;
+ // Switch to PLL.
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
+ while ((reg::RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
+ ;
+ // Update frequencies.
+ assert (pll_in_freq_hz * pllmul == sys_freq_hz);
+ rcc_ahb_freq_hz = rcc_sys_freq_hz = sys_freq_hz;
+ rcc_apb1_freq_hz = sys_freq_hz / apb1_pre;
+ rcc_apb2_freq_hz = sys_freq_hz / apb2_pre;
+ rcc_apb1_timer_freq_hz = rcc_apb1_freq_hz * (apb1_pre == 1 ? 1 : 2);
+ rcc_apb2_timer_freq_hz = rcc_apb2_freq_hz * (apb2_pre == 1 ? 1 : 2);
+ rcc_usb_freq_hz = sys_freq_hz * 2 / 3;
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/rcc.stm32f1.hh b/ucoo/arch/rcc.stm32f1.hh
new file mode 100644
index 0000000..3896752
--- /dev/null
+++ b/ucoo/arch/rcc.stm32f1.hh
@@ -0,0 +1,143 @@
+#ifndef ucoo_arch_rcc_stm32f1_hh
+#define ucoo_arch_rcc_stm32f1_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/arch.hh"
+#include "ucoo/arch/reg.hh"
+
+namespace ucoo {
+
+enum class Bus
+{
+ AHB = 0,
+ APB1 = 2,
+ APB2 = 1,
+};
+
+namespace details {
+
+constexpr uint32_t
+rcc_enum (Bus bus, uint32_t bit, int pos = 0)
+{
+ return bit == 1
+ ? (static_cast<uint32_t> (bus) << 5) | pos
+ : rcc_enum (bus, (bit >> 1) | (bit << 31), pos + 1);
+}
+
+} // namespace details
+
+/// Constants to handle reset and clock for each peripheral.
+enum class Rcc
+{
+ DMA1 = details::rcc_enum (Bus::AHB, RCC_AHBENR_DMA1EN),
+ DMA2 = details::rcc_enum (Bus::AHB, RCC_AHBENR_DMA2EN),
+ SRAM = details::rcc_enum (Bus::AHB, RCC_AHBENR_SRAMEN),
+ FLITF = details::rcc_enum (Bus::AHB, RCC_AHBENR_FLITFEN),
+ CRC = details::rcc_enum (Bus::AHB, RCC_AHBENR_CRCEN),
+ OTGFS = details::rcc_enum (Bus::AHB, RCC_AHBENR_OTGFSEN),
+ AFIO = details::rcc_enum (Bus::APB2, RCC_APB2ENR_AFIOEN),
+ GPIOA = details::rcc_enum (Bus::APB2, RCC_APB2ENR_IOPAEN),
+ GPIOB = details::rcc_enum (Bus::APB2, RCC_APB2ENR_IOPBEN),
+ GPIOC = details::rcc_enum (Bus::APB2, RCC_APB2ENR_IOPCEN),
+ GPIOD = details::rcc_enum (Bus::APB2, RCC_APB2ENR_IOPDEN),
+ GPIOE = details::rcc_enum (Bus::APB2, RCC_APB2ENR_IOPEEN),
+ ADC1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_ADC1EN),
+ ADC2 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_ADC2EN),
+ TIM1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM1EN),
+ SPI1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SPI1EN),
+ USART1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_USART1EN),
+ TIM2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM2EN),
+ TIM3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM3EN),
+ TIM4 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM4EN),
+ TIM5 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM5EN),
+ TIM6 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM6EN),
+ TIM7 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM7EN),
+ WWDG = details::rcc_enum (Bus::APB1, RCC_APB1ENR_WWDGEN),
+ SPI2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_SPI2EN),
+ SPI3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_SPI3EN),
+ USART2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_USART2EN),
+ USART3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_USART3EN),
+ UART4 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART4EN),
+ UART5 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART5EN),
+ I2C1 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_I2C1EN),
+ I2C2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_I2C2EN),
+ CAN1 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_CAN1EN),
+ CAN2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_CAN2EN),
+ BKP = details::rcc_enum (Bus::APB1, RCC_APB1ENR_BKPEN),
+ PWR = details::rcc_enum (Bus::APB1, RCC_APB1ENR_PWREN),
+ DAC = details::rcc_enum (Bus::APB1, RCC_APB1ENR_DACEN),
+};
+
+/// Enable clock for given peripheral.
+static inline void
+rcc_peripheral_clock_enable (Rcc rcc)
+{
+ int bus_index = static_cast<uint32_t> (rcc) >> 5;
+ int bit_index = static_cast<uint32_t> (rcc) & 0x1f;
+ (&reg::RCC->AHBENR)[bus_index] |= 1 << bit_index;
+ arch_dsb ();
+}
+
+/// Disable clock for given peripheral.
+static inline void
+rcc_peripheral_clock_disable (Rcc rcc)
+{
+ int bus_index = static_cast<uint32_t> (rcc) >> 5;
+ int bit_index = static_cast<uint32_t> (rcc) & 0x1f;
+ (&reg::RCC->AHBENR)[bus_index] &= ~(1 << bit_index);
+ arch_dsb ();
+}
+
+/// Frequency of the main system clock.
+extern int rcc_sys_freq_hz;
+
+/// Frequency of AHB bus.
+extern int rcc_ahb_freq_hz;
+
+/// Frequency of APB1 bus.
+extern int rcc_apb1_freq_hz;
+
+/// Frequency of APB2 bus.
+extern int rcc_apb2_freq_hz;
+
+/// Frequency of timers on APB1 bus.
+extern int rcc_apb1_timer_freq_hz;
+
+/// Frequency of timers on APB2 bus.
+extern int rcc_apb2_timer_freq_hz;
+
+/// Frequency of the USB clock.
+extern int rcc_usb_freq_hz;
+
+/// Setup system clock using PLL, from HSE clock if not 0, else HSI clock.
+/// Also setup flash access. Only support configuration common to all F1
+/// lines.
+void
+rcc_sys_clock_setup_pll (int sys_freq_hz, int hse_freq_hz,
+ int prediv1, int pllmul,
+ int apb1_pre, int apb2_pre, int adc_pre);
+
+} // namespace ucoo
+
+#endif // ucoo_arch_rcc_stm32f1_hh
diff --git a/ucoo/arch/rcc.stm32f4.cc b/ucoo/arch/rcc.stm32f4.cc
new file mode 100644
index 0000000..36e31b6
--- /dev/null
+++ b/ucoo/arch/rcc.stm32f4.cc
@@ -0,0 +1,125 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/rcc.stm32f4.hh"
+#include "ucoo/common.hh"
+#include "ucoo/utils/table_lookup.hh"
+
+namespace ucoo {
+
+static const int hsi_freq_hz = 16000000;
+
+int rcc_sys_freq_hz = hsi_freq_hz;
+int rcc_ahb_freq_hz = hsi_freq_hz;
+int rcc_apb1_freq_hz = hsi_freq_hz;
+int rcc_apb2_freq_hz = hsi_freq_hz;
+int rcc_apb1_timer_freq_hz = hsi_freq_hz;
+int rcc_apb2_timer_freq_hz = hsi_freq_hz;
+int rcc_pll48_freq_hz = 0;
+
+void
+rcc_sys_clock_setup_pll (int sys_freq_hz, int hse_freq_hz,
+ int pllm, int plln, int pllp, int pllq,
+ int apb1_pre, int apb2_pre,
+ SupplyRange vrange)
+{
+ // Switch to HSI as a safe fall back.
+ reg::RCC->CR |= RCC_CR_HSION;
+ while (!(reg::RCC->CR & RCC_CR_HSIRDY))
+ ;
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
+ while ((reg::RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
+ ;
+ // Start HSE if needed.
+ uint32_t pllsrc = RCC_PLLCFGR_PLLSRC_HSI;
+ int pll_in_freq_hz = hsi_freq_hz;
+ if (hse_freq_hz)
+ {
+ pll_in_freq_hz = hse_freq_hz;
+ pllsrc = RCC_PLLCFGR_PLLSRC_HSE;
+ reg::RCC->CR |= RCC_CR_HSEON;
+ while (!(reg::RCC->CR & RCC_CR_HSERDY))
+ ;
+ }
+ // Adapt voltage regulator scale.
+ if (sys_freq_hz <= 120000000)
+ reg::PWR->CR = (reg::PWR->CR & ~PWR_CR_VOS) | PWR_CR_VOS_Scale3;
+ else if (sys_freq_hz <= 144000000)
+ reg::PWR->CR = (reg::PWR->CR & ~PWR_CR_VOS) | PWR_CR_VOS_Scale2;
+ else
+ reg::PWR->CR = (reg::PWR->CR & ~PWR_CR_VOS) | PWR_CR_VOS_Scale1;
+ // Change buses prescalers.
+ uint32_t ppre = 0;
+ static const LookupTable<int, uint32_t> apb1_pre_table[] =
+ {
+ { 1, RCC_CFGR_PPRE1_DIV1 },
+ { 2, RCC_CFGR_PPRE1_DIV2 },
+ { 4, RCC_CFGR_PPRE1_DIV4 },
+ { 8, RCC_CFGR_PPRE1_DIV8 },
+ { 16, RCC_CFGR_PPRE1_DIV16 },
+ };
+ ppre |= simple_table_lookup (apb1_pre_table, apb1_pre);
+ static const LookupTable<int, uint32_t> apb2_pre_table[] =
+ {
+ { 1, RCC_CFGR_PPRE2_DIV1 },
+ { 2, RCC_CFGR_PPRE2_DIV2 },
+ { 4, RCC_CFGR_PPRE2_DIV4 },
+ { 8, RCC_CFGR_PPRE2_DIV8 },
+ { 16, RCC_CFGR_PPRE2_DIV16 },
+ };
+ ppre |= simple_table_lookup (apb2_pre_table, apb2_pre);
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~(RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2))
+ | ppre;
+ // Start PLL.
+ reg::RCC->PLLCFGR = pllsrc
+ | pllm << RCC_PLLCFGR_PLLM_Pos
+ | plln << RCC_PLLCFGR_PLLN_Pos
+ | (pllp / 2 - 1) << RCC_PLLCFGR_PLLP_Pos
+ | pllq << RCC_PLLCFGR_PLLQ_Pos;
+ reg::RCC->CR |= RCC_CR_PLLON;
+ while (!(reg::RCC->CR & RCC_CR_PLLRDY))
+ ;
+ // Setup flash.
+ int mhz_per_ws_per_vrange[] = { 20, 22, 24, 30 };
+ int mhz_per_ws = mhz_per_ws_per_vrange[static_cast<int> (vrange)];
+ int ws = (sys_freq_hz - 1) / 1000000 / mhz_per_ws;
+ reg::FLASH->ACR = ws
+ | FLASH_ACR_ICEN | FLASH_ACR_DCEN
+ | (ws ? FLASH_ACR_PRFTEN : 0); // XXX not for buggy F40x!
+ // Switch to PLL.
+ reg::RCC->CFGR = (reg::RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
+ while ((reg::RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
+ ;
+ // Disable unused HSI.
+ reg::RCC->CR &= ~RCC_CR_HSION;
+ // Update frequencies.
+ assert (pll_in_freq_hz / pllm * plln / pllp == sys_freq_hz);
+ rcc_ahb_freq_hz = rcc_sys_freq_hz = sys_freq_hz;
+ rcc_apb1_freq_hz = sys_freq_hz / apb1_pre;
+ rcc_apb2_freq_hz = sys_freq_hz / apb2_pre;
+ rcc_apb1_timer_freq_hz = rcc_apb1_freq_hz * (apb1_pre == 1 ? 1 : 2);
+ rcc_apb2_timer_freq_hz = rcc_apb2_freq_hz * (apb2_pre == 1 ? 1 : 2);
+ rcc_pll48_freq_hz = pll_in_freq_hz / pllm * plln / pllq;
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/rcc.stm32f4.hh b/ucoo/arch/rcc.stm32f4.hh
new file mode 100644
index 0000000..64c46b5
--- /dev/null
+++ b/ucoo/arch/rcc.stm32f4.hh
@@ -0,0 +1,193 @@
+#ifndef ucoo_arch_rcc_stm32f4_hh
+#define ucoo_arch_rcc_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/arch.hh"
+#include "ucoo/arch/reg.hh"
+
+namespace ucoo {
+
+enum class Bus
+{
+ AHB1 = 0,
+ AHB2 = 1,
+ AHB3 = 2,
+ APB1 = 4,
+ APB2 = 5,
+};
+
+/// Supply range.
+enum class SupplyRange
+{
+ /// 1.8 V to 2.1 V.
+ V1_8,
+ /// 2.1 V to 2.4 V.
+ V2_1,
+ /// 2.4 V to 2.7 V.
+ V2_4,
+ /// 2.7 V to 3.6 V.
+ V2_7,
+};
+
+namespace details {
+
+constexpr uint32_t
+rcc_enum (Bus bus, uint32_t bit, int pos = 0)
+{
+ return bit == 1
+ ? (static_cast<uint32_t> (bus) << 5) | pos
+ : rcc_enum (bus, (bit >> 1) | (bit << 31), pos + 1);
+}
+
+} // namespace details
+
+/// Constants to handle reset and clock for each peripheral.
+enum class Rcc
+{
+ GPIOA = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOAEN),
+ GPIOB = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOBEN),
+ GPIOC = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOCEN),
+ GPIOD = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIODEN),
+ GPIOE = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOEEN),
+ GPIOF = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOFEN),
+ GPIOG = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOGEN),
+ GPIOH = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOHEN),
+ GPIOI = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOIEN),
+ GPIOJ = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOJEN),
+ GPIOK = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_GPIOKEN),
+ CRC = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_CRCEN),
+ BKPSRAM = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_BKPSRAMEN),
+ CCMDATARAM = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_CCMDATARAMEN),
+ DMA1 = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_DMA1EN),
+ DMA2 = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_DMA2EN),
+ DMA2D = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_DMA2DEN),
+ ETHMAC = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_ETHMACEN),
+ ETHMACTX = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_ETHMACTXEN),
+ ETHMACRX = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_ETHMACRXEN),
+ ETHMACPTP = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_ETHMACPTPEN),
+ OTGHS = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_OTGHSEN),
+ OTGHSULPI = details::rcc_enum (Bus::AHB1, RCC_AHB1ENR_OTGHSULPIEN),
+ DCMI = details::rcc_enum (Bus::AHB2, RCC_AHB2ENR_DCMIEN),
+ CRYP = details::rcc_enum (Bus::AHB2, RCC_AHB2ENR_CRYPEN),
+ HASH = details::rcc_enum (Bus::AHB2, RCC_AHB2ENR_HASHEN),
+ RNG = details::rcc_enum (Bus::AHB2, RCC_AHB2ENR_RNGEN),
+ OTGFS = details::rcc_enum (Bus::AHB2, RCC_AHB2ENR_OTGFSEN),
+ FMC = details::rcc_enum (Bus::AHB3, RCC_AHB3ENR_FMCEN),
+ TIM2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM2EN),
+ TIM3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM3EN),
+ TIM4 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM4EN),
+ TIM5 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM5EN),
+ TIM6 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM6EN),
+ TIM7 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM7EN),
+ TIM12 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM12EN),
+ TIM13 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM13EN),
+ TIM14 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_TIM14EN),
+ WWDG = details::rcc_enum (Bus::APB1, RCC_APB1ENR_WWDGEN),
+ SPI2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_SPI2EN),
+ SPI3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_SPI3EN),
+ USART2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_USART2EN),
+ USART3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_USART3EN),
+ UART4 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART4EN),
+ UART5 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART5EN),
+ I2C1 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_I2C1EN),
+ I2C2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_I2C2EN),
+ I2C3 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_I2C3EN),
+ CAN1 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_CAN1EN),
+ CAN2 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_CAN2EN),
+ PWR = details::rcc_enum (Bus::APB1, RCC_APB1ENR_PWREN),
+ DAC = details::rcc_enum (Bus::APB1, RCC_APB1ENR_DACEN),
+ UART7 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART7EN),
+ UART8 = details::rcc_enum (Bus::APB1, RCC_APB1ENR_UART8EN),
+ TIM1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM1EN),
+ TIM8 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM8EN),
+ USART1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_USART1EN),
+ USART6 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_USART6EN),
+ ADC1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_ADC1EN),
+ ADC2 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_ADC2EN),
+ ADC3 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_ADC3EN),
+ SDIO = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SDIOEN),
+ SPI1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SPI1EN),
+ SPI4 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SPI4EN),
+ SYSCFG = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SYSCFGEN),
+ TIM9 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM9EN),
+ TIM10 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM10EN),
+ TIM11 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_TIM11EN),
+ SPI5 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SPI5EN),
+ SPI6 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SPI6EN),
+ SAI1 = details::rcc_enum (Bus::APB2, RCC_APB2ENR_SAI1EN),
+ LTDC = details::rcc_enum (Bus::APB2, RCC_APB2ENR_LTDCEN),
+};
+
+/// Enable clock for given peripheral.
+static inline void
+rcc_peripheral_clock_enable (Rcc rcc)
+{
+ int bus_index = static_cast<uint32_t> (rcc) >> 5;
+ int bit_index = static_cast<uint32_t> (rcc) & 0x1f;
+ (&reg::RCC->AHB1ENR)[bus_index] |= 1 << bit_index;
+ arch_dsb ();
+}
+
+/// Disable clock for given peripheral.
+static inline void
+rcc_peripheral_clock_disable (Rcc rcc)
+{
+ int bus_index = static_cast<uint32_t> (rcc) >> 5;
+ int bit_index = static_cast<uint32_t> (rcc) & 0x1f;
+ (&reg::RCC->AHB1ENR)[bus_index] &= ~(1 << bit_index);
+ arch_dsb ();
+}
+
+/// Frequency of the main system clock.
+extern int rcc_sys_freq_hz;
+
+/// Frequency of AHB bus.
+extern int rcc_ahb_freq_hz;
+
+/// Frequency of APB1 bus.
+extern int rcc_apb1_freq_hz;
+
+/// Frequency of APB2 bus.
+extern int rcc_apb2_freq_hz;
+
+/// Frequency of timers on APB1 bus.
+extern int rcc_apb1_timer_freq_hz;
+
+/// Frequency of timers on APB2 bus.
+extern int rcc_apb2_timer_freq_hz;
+
+/// Frequency of the should-be-48-MHz clock (used for USB, RNG & SDIO).
+extern int rcc_pll48_freq_hz;
+
+/// Setup system clock using PLL, from HSE clock if not 0, else HSI clock.
+/// Also setup flash access and voltage regulator scale.
+void
+rcc_sys_clock_setup_pll (int sys_freq_hz, int hse_freq_hz,
+ int pllm, int plln, int pllp, int pllq,
+ int apb1_pre, int apb2_pre,
+ SupplyRange vrange);
+
+} // namespace ucoo
+
+#endif // ucoo_arch_rcc_stm32f4_hh
diff --git a/ucoo/arch/reg.hh b/ucoo/arch/reg.hh
new file mode 100644
index 0000000..d913511
--- /dev/null
+++ b/ucoo/arch/reg.hh
@@ -0,0 +1,35 @@
+#ifndef ucoo_arch_reg_hh
+#define ucoo_arch_reg_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_stm32f4)
+# include "reg.stm32f4.hh"
+#elif defined (TARGET_stm32f1)
+# include "reg.stm32f1.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_arch_reg_hh
diff --git a/ucoo/arch/reg.stm32.hh b/ucoo/arch/reg.stm32.hh
new file mode 100644
index 0000000..4d46354
--- /dev/null
+++ b/ucoo/arch/reg.stm32.hh
@@ -0,0 +1,80 @@
+#ifndef ucoo_arch_reg_stm32_hh
+#define ucoo_arch_reg_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#define TIM_SMCR_SMS_TM (6 << 0)
+
+#define TIM_SMCR_TS_TI1FP1 (5 << 4)
+#define TIM_SMCR_TS_TI1FP2 (6 << 4)
+
+#define TIM_CCMR1_OC1M_PWM1 (6 << 4)
+#define TIM_CCMR1_OC2M_PWM1 (6 << 12)
+
+#define TIM_CCMR2_OC3M_PWM1 (6 << 4)
+#define TIM_CCMR2_OC4M_PWM1 (6 << 12)
+
+#define USART_CR2_STOP_Bits_1 0
+#define USART_CR2_STOP_Bits_0_5 USART_CR2_STOP_0
+#define USART_CR2_STOP_Bits_2 USART_CR2_STOP_1
+#define USART_CR2_STOP_Bits_1_5 (USART_CR2_STOP_1 | USART_CR2_STOP_0)
+
+#define USB_OTG_GRXSTSP_PKTSTS_GlobalOutNak (1 << 17)
+#define USB_OTG_GRXSTSP_PKTSTS_Out (2 << 17)
+#define USB_OTG_GRXSTSP_PKTSTS_OutCompleted (3 << 17)
+#define USB_OTG_GRXSTSP_PKTSTS_SetupCompleted (4 << 17)
+#define USB_OTG_GRXSTSP_PKTSTS_Setup (6 << 17)
+
+#define FLASH_KEYR_KEY1 0x45670123
+#define FLASH_KEYR_KEY2 0xcdef89ab
+
+namespace ucoo {
+
+struct USB_OTG_FIFOTypeDef
+{
+ __IO uint32_t FIFO;
+ uint32_t reserved[(0x1000 - sizeof (uint32_t)) / 4];
+};
+
+/// USB OTG registers, only define device registers.
+struct USB_OTG_TypeDef
+{
+ USB_OTG_GlobalTypeDef global;
+ uint32_t reserved0[(USB_OTG_DEVICE_BASE - USB_OTG_GLOBAL_BASE
+ - sizeof (USB_OTG_GlobalTypeDef)) / 4];
+ USB_OTG_DeviceTypeDef device;
+ uint32_t reserved1[(USB_OTG_IN_ENDPOINT_BASE - USB_OTG_DEVICE_BASE
+ - sizeof (USB_OTG_DeviceTypeDef)) / 4];
+ USB_OTG_INEndpointTypeDef ep_in[4];
+ uint32_t reserved2[(USB_OTG_OUT_ENDPOINT_BASE - USB_OTG_IN_ENDPOINT_BASE
+ - sizeof (USB_OTG_INEndpointTypeDef[4])) / 4];
+ USB_OTG_OUTEndpointTypeDef ep_out[4];
+ uint32_t reserved3[(USB_OTG_FIFO_BASE - USB_OTG_OUT_ENDPOINT_BASE
+ - sizeof (USB_OTG_OUTEndpointTypeDef[4])) / 4];
+ USB_OTG_FIFOTypeDef fifo[4];
+};
+
+} // namespace ucoo
+
+#endif // ucoo_arch_reg_stm32_hh
diff --git a/ucoo/arch/reg.stm32f1.hh b/ucoo/arch/reg.stm32f1.hh
new file mode 100644
index 0000000..47855cf
--- /dev/null
+++ b/ucoo/arch/reg.stm32f1.hh
@@ -0,0 +1,180 @@
+#ifndef ucoo_arch_reg_stm32f1_hh
+#define ucoo_arch_reg_stm32f1_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ST/STM32F1xx/Include/stm32f105xc.h"
+#include "ucoo/arch/reg.stm32.hh"
+
+#define GPIO_CNF_Input_Analog 0
+#define GPIO_CNF_Input_Float 1
+#define GPIO_CNF_Input_PullUpDown 2
+
+#define GPIO_CNF_Output_PushPull 0
+#define GPIO_CNF_Output_OpenDrain 1
+#define GPIO_CNF_Output_AFPushPull 2
+#define GPIO_CNF_Output_AFOpenDrain 3
+
+#define GPIO_MODE_Input 0
+#define GPIO_MODE_Output_2MHz 1
+#define GPIO_MODE_Output_10MHz 2
+#define GPIO_MODE_Output_50MHz 3
+
+#define DESIG_BASE 0x1ffff7e0
+
+struct DESIG_TypeDef
+{
+ __IO uint16_t FLASH_SIZE;
+ uint16_t reserved1;
+ uint32_t reserved2;
+ __IO uint32_t U_ID[3];
+};
+
+#undef SysTick
+
+#undef TIM2
+#undef TIM3
+#undef TIM4
+#undef TIM5
+#undef TIM6
+#undef TIM7
+#undef RTC
+#undef WWDG
+#undef IWDG
+#undef SPI2
+#undef SPI3
+#undef USART2
+#undef USART3
+#undef UART4
+#undef UART5
+#undef I2C1
+#undef I2C2
+#undef CAN1
+#undef CAN2
+#undef BKP
+#undef PWR
+#undef DAC
+#undef AFIO
+#undef EXTI
+#undef GPIOA
+#undef GPIOB
+#undef GPIOC
+#undef GPIOD
+#undef GPIOE
+#undef ADC1
+#undef ADC2
+#undef ADC12_COMMON
+#undef TIM1
+#undef SPI1
+#undef USART1
+#undef SDIO
+#undef DMA1
+#undef DMA2
+#undef DMA1_Channel1
+#undef DMA1_Channel2
+#undef DMA1_Channel3
+#undef DMA1_Channel4
+#undef DMA1_Channel5
+#undef DMA1_Channel6
+#undef DMA1_Channel7
+#undef DMA2_Channel1
+#undef DMA2_Channel2
+#undef DMA2_Channel3
+#undef DMA2_Channel4
+#undef DMA2_Channel5
+#undef RCC
+#undef CRC
+#undef FLASH
+#undef OB
+#undef DBGMCU
+#undef USB_OTG_FS
+
+namespace ucoo {
+
+namespace reg {
+
+constexpr auto SysTick = reinterpret_cast<SysTick_Type *> (SysTick_BASE);
+
+constexpr auto TIM2 = reinterpret_cast<TIM_TypeDef *> (TIM2_BASE);
+constexpr auto TIM3 = reinterpret_cast<TIM_TypeDef *> (TIM3_BASE);
+constexpr auto TIM4 = reinterpret_cast<TIM_TypeDef *> (TIM4_BASE);
+constexpr auto TIM5 = reinterpret_cast<TIM_TypeDef *> (TIM5_BASE);
+constexpr auto TIM6 = reinterpret_cast<TIM_TypeDef *> (TIM6_BASE);
+constexpr auto TIM7 = reinterpret_cast<TIM_TypeDef *> (TIM7_BASE);
+constexpr auto RTC = reinterpret_cast<RTC_TypeDef *> (RTC_BASE);
+constexpr auto WWDG = reinterpret_cast<WWDG_TypeDef *> (WWDG_BASE);
+constexpr auto IWDG = reinterpret_cast<IWDG_TypeDef *> (IWDG_BASE);
+constexpr auto SPI2 = reinterpret_cast<SPI_TypeDef *> (SPI2_BASE);
+constexpr auto SPI3 = reinterpret_cast<SPI_TypeDef *> (SPI3_BASE);
+constexpr auto USART2 = reinterpret_cast<USART_TypeDef *> (USART2_BASE);
+constexpr auto USART3 = reinterpret_cast<USART_TypeDef *> (USART3_BASE);
+constexpr auto UART4 = reinterpret_cast<USART_TypeDef *> (UART4_BASE);
+constexpr auto UART5 = reinterpret_cast<USART_TypeDef *> (UART5_BASE);
+constexpr auto I2C1 = reinterpret_cast<I2C_TypeDef *> (I2C1_BASE);
+constexpr auto I2C2 = reinterpret_cast<I2C_TypeDef *> (I2C2_BASE);
+constexpr auto CAN1 = reinterpret_cast<CAN_TypeDef *> (CAN1_BASE);
+constexpr auto CAN2 = reinterpret_cast<CAN_TypeDef *> (CAN2_BASE);
+constexpr auto BKP = reinterpret_cast<BKP_TypeDef *> (BKP_BASE);
+constexpr auto PWR = reinterpret_cast<PWR_TypeDef *> (PWR_BASE);
+constexpr auto DAC = reinterpret_cast<DAC_TypeDef *> (DAC_BASE);
+constexpr auto AFIO = reinterpret_cast<AFIO_TypeDef *> (AFIO_BASE);
+constexpr auto EXTI = reinterpret_cast<EXTI_TypeDef *> (EXTI_BASE);
+constexpr auto GPIOA = reinterpret_cast<GPIO_TypeDef *> (GPIOA_BASE);
+constexpr auto GPIOB = reinterpret_cast<GPIO_TypeDef *> (GPIOB_BASE);
+constexpr auto GPIOC = reinterpret_cast<GPIO_TypeDef *> (GPIOC_BASE);
+constexpr auto GPIOD = reinterpret_cast<GPIO_TypeDef *> (GPIOD_BASE);
+constexpr auto GPIOE = reinterpret_cast<GPIO_TypeDef *> (GPIOE_BASE);
+constexpr auto ADC1 = reinterpret_cast<ADC_TypeDef *> (ADC1_BASE);
+constexpr auto ADC2 = reinterpret_cast<ADC_TypeDef *> (ADC2_BASE);
+constexpr auto ADC12_COMMON = reinterpret_cast<ADC_Common_TypeDef *> (ADC1_BASE);
+constexpr auto TIM1 = reinterpret_cast<TIM_TypeDef *> (TIM1_BASE);
+constexpr auto SPI1 = reinterpret_cast<SPI_TypeDef *> (SPI1_BASE);
+constexpr auto USART1 = reinterpret_cast<USART_TypeDef *> (USART1_BASE);
+constexpr auto SDIO = reinterpret_cast<SDIO_TypeDef *> (SDIO_BASE);
+constexpr auto DMA1 = reinterpret_cast<DMA_TypeDef *> (DMA1_BASE);
+constexpr auto DMA2 = reinterpret_cast<DMA_TypeDef *> (DMA2_BASE);
+constexpr auto DMA1_Channel1 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel1_BASE);
+constexpr auto DMA1_Channel2 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel2_BASE);
+constexpr auto DMA1_Channel3 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel3_BASE);
+constexpr auto DMA1_Channel4 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel4_BASE);
+constexpr auto DMA1_Channel5 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel5_BASE);
+constexpr auto DMA1_Channel6 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel6_BASE);
+constexpr auto DMA1_Channel7 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA1_Channel7_BASE);
+constexpr auto DMA2_Channel1 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA2_Channel1_BASE);
+constexpr auto DMA2_Channel2 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA2_Channel2_BASE);
+constexpr auto DMA2_Channel3 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA2_Channel3_BASE);
+constexpr auto DMA2_Channel4 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA2_Channel4_BASE);
+constexpr auto DMA2_Channel5 = reinterpret_cast<DMA_Channel_TypeDef *> (DMA2_Channel5_BASE);
+constexpr auto RCC = reinterpret_cast<RCC_TypeDef *> (RCC_BASE);
+constexpr auto CRC = reinterpret_cast<CRC_TypeDef *> (CRC_BASE);
+constexpr auto FLASH = reinterpret_cast<FLASH_TypeDef *> (FLASH_R_BASE);
+constexpr auto OB = reinterpret_cast<OB_TypeDef *> (OB_BASE);
+constexpr auto DBGMCU = reinterpret_cast<DBGMCU_TypeDef *> (DBGMCU_BASE);
+constexpr auto USB_OTG_FS = reinterpret_cast<USB_OTG_TypeDef *> (USB_OTG_FS_PERIPH_BASE);
+constexpr auto DESIG = reinterpret_cast<DESIG_TypeDef *> (DESIG_BASE);
+
+} // namespace reg
+
+} // namespace ucoo
+
+#endif // ucoo_arch_reg_stm32f1_hh
diff --git a/ucoo/arch/reg.stm32f4.hh b/ucoo/arch/reg.stm32f4.hh
new file mode 100644
index 0000000..31ad39d
--- /dev/null
+++ b/ucoo/arch/reg.stm32f4.hh
@@ -0,0 +1,347 @@
+#ifndef ucoo_arch_reg_stm32f4_hh
+#define ucoo_arch_reg_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+// Use a superset of all supported chips.
+#include "ST/STM32F4xx/Include/stm32f439xx.h"
+#include "ucoo/arch/reg.stm32.hh"
+
+#define SCB_CPACR_CP10_Pos 20
+#define SCB_CPACR_CP10_Denied (0 << SCB_CPACR_CP10_Pos)
+#define SCB_CPACR_CP10_Privileged (1 << SCB_CPACR_CP10_Pos)
+#define SCB_CPACR_CP10_Full (3 << SCB_CPACR_CP10_Pos)
+#define SCB_CPACR_CP10_Msk (3 << SCB_CPACR_CP10_Pos)
+
+#define SCB_CPACR_CP11_Pos 22
+#define SCB_CPACR_CP11_Denied (0 << SCB_CPACR_CP11_Pos)
+#define SCB_CPACR_CP11_Privileged (1 << SCB_CPACR_CP11_Pos)
+#define SCB_CPACR_CP11_Full (3 << SCB_CPACR_CP11_Pos)
+#define SCB_CPACR_CP11_Msk (3 << SCB_CPACR_CP11_Pos)
+
+#define PWR_CR_VOS_Scale3 (PWR_CR_VOS_0)
+#define PWR_CR_VOS_Scale2 (PWR_CR_VOS_1)
+#define PWR_CR_VOS_Scale1 (PWR_CR_VOS_1 | PWR_CR_VOS_0)
+
+#define RCC_PLLCFGR_PLLM_Pos 0
+#define RCC_PLLCFGR_PLLN_Pos 6
+#define RCC_PLLCFGR_PLLP_Pos 16
+#define RCC_PLLCFGR_PLLQ_Pos 24
+
+#define GPIO_MODER_Input 0
+#define GPIO_MODER_Output 1
+#define GPIO_MODER_AF 2
+#define GPIO_MODER_Analog 3
+
+#define SPI_CR1_BR_Pos 3
+
+#define USB_OTG_GRXSTSP_BCNT_Pos 4
+#define USB_OTG_GRXSTSP_PKTSTS_Pos 17
+#define USB_OTG_DOEPTSIZ_PKTCNT_Pos 19
+#define USB_OTG_DIEPTSIZ_PKTCNT_Pos 19
+
+#define FLASH_CR_PSIZE_x32 FLASH_CR_PSIZE_1
+
+#define FMC_SDCR_RPIPE_None 0
+#define FMC_SDCR_RPIPE_1Clk FMC_SDCR1_RPIPE_0
+#define FMC_SDCR_RPIPE_2Clk FMC_SDCR1_RPIPE_1
+#define FMC_SDCR_RBURST FMC_SDCR1_RBURST
+#define FMC_SDCR_SDCLK_Disabled 0
+#define FMC_SDCR_SDCLK_2Hclk FMC_SDCR1_SDCLK_1
+#define FMC_SDCR_SDCLK_3Hclk (FMC_SDCR1_SDCLK_1 | FMC_SDCR1_SDCLK_0)
+#define FMC_SDCR_CAS_Pos 7
+#define FMC_SDCR_NB FMC_SDCR1_NB
+#define FMC_SDCR_MWID_8B 0
+#define FMC_SDCR_MWID_16B FMC_SDCR1_MWID_0
+#define FMC_SDCR_MWID_32B FMC_SDCR1_MWID_1
+#define FMC_SDCR_NR_Pos 2
+#define FMC_SDCR_NC_Pos 0
+
+#define FMC_SDTR_TRCD_Pos 24
+#define FMC_SDTR_TRP_Pos 20
+#define FMC_SDTR_TWR_Pos 16
+#define FMC_SDTR_TRC_Pos 12
+#define FMC_SDTR_TRAS_Pos 8
+#define FMC_SDTR_TXSR_Pos 4
+#define FMC_SDTR_TMRD_Pos 0
+
+#define FMC_SDCR_DNC_Mask (FMC_SDCR1_SDCLK | FMC_SDCR1_RPIPE \
+ | FMC_SDCR1_RBURST)
+#define FMC_SDTR_DNC_Mask (FMC_SDTR1_TRP | FMC_SDTR1_TRC)
+
+#define FMC_SDCMR_MODE_Normal 0
+#define FMC_SDCMR_MODE_ClockConfigEna 1
+#define FMC_SDCMR_MODE_Pall 2
+#define FMC_SDCMR_MODE_AutoRefresh 3
+#define FMC_SDCMR_MODE_LoadModeRegister 4
+#define FMC_SDCMR_MODE_SelfRefresh 5
+#define FMC_SDCMR_MODE_PowerDown 6
+
+#define FMC_SDCMR_NRFS_Pos 5
+#define FMC_SDCMR_MRD_Pos 9
+
+#define SDRAM_MODE_BURST_LENGTH_1 0x0000
+#define SDRAM_MODE_BURST_LENGTH_2 0x0001
+#define SDRAM_MODE_BURST_LENGTH_4 0x0002
+#define SDRAM_MODE_BURST_LENGTH_8 0x0004
+#define SDRAM_MODE_BURST_TYPE_SEQUENTIAL 0x0000
+#define SDRAM_MODE_BURST_TYPE_INTERLEAVED 0x0008
+#define SDRAM_MODE_CAS_LATENCY_2 0x0020
+#define SDRAM_MODE_CAS_LATENCY_3 0x0030
+#define SDRAM_MODE_OPERATING_MODE_STANDARD 0x0000
+#define SDRAM_MODE_WRITEBURST_MODE_PROGRAMMED 0x0000
+#define SDRAM_MODE_WRITEBURST_MODE_SINGLE 0x0200
+
+#define FMC_BANK5_BASE 0xc0000000
+#define FMC_BANK6_BASE 0xd0000000
+
+#define DESIG_BASE 0x1fff7a10
+#define DESIG_FLASH_SIZE_BASE 0x1fff7a22
+#define DESIG_UNIQUE_ID_BASE 0x1fff7a10
+
+struct DESIG_TypeDef
+{
+ __IO uint32_t U_ID[3];
+ uint32_t reserved0x1c;
+ uint16_t reserved0x20;
+ __IO uint16_t FLASH_SIZE;
+};
+
+#undef FPU
+#undef SysTick
+
+#undef TIM2
+#undef TIM3
+#undef TIM4
+#undef TIM5
+#undef TIM6
+#undef TIM7
+#undef TIM12
+#undef TIM13
+#undef TIM14
+#undef RTC
+#undef WWDG
+#undef IWDG
+#undef I2S2ext
+#undef SPI2
+#undef SPI3
+#undef I2S3ext
+#undef USART2
+#undef USART3
+#undef UART4
+#undef UART5
+#undef I2C1
+#undef I2C2
+#undef I2C3
+#undef CAN1
+#undef CAN2
+#undef PWR
+#undef DAC
+#undef UART7
+#undef UART8
+#undef TIM1
+#undef TIM8
+#undef USART1
+#undef USART6
+#undef ADC
+#undef ADC1
+#undef ADC2
+#undef ADC3
+#undef SDIO
+#undef SPI1
+#undef SPI4
+#undef SYSCFG
+#undef EXTI
+#undef TIM9
+#undef TIM10
+#undef TIM11
+#undef SPI5
+#undef SPI6
+#undef SAI1
+#undef SAI1_Block_A
+#undef SAI1_Block_B
+#undef LTDC
+#undef LTDC_Layer1
+#undef LTDC_Layer2
+#undef GPIOA
+#undef GPIOB
+#undef GPIOC
+#undef GPIOD
+#undef GPIOE
+#undef GPIOF
+#undef GPIOG
+#undef GPIOH
+#undef GPIOI
+#undef GPIOJ
+#undef GPIOK
+#undef CRC
+#undef RCC
+#undef FLASH
+#undef DMA1
+#undef DMA1_Stream0
+#undef DMA1_Stream1
+#undef DMA1_Stream2
+#undef DMA1_Stream3
+#undef DMA1_Stream4
+#undef DMA1_Stream5
+#undef DMA1_Stream6
+#undef DMA1_Stream7
+#undef DMA2
+#undef DMA2_Stream0
+#undef DMA2_Stream1
+#undef DMA2_Stream2
+#undef DMA2_Stream3
+#undef DMA2_Stream4
+#undef DMA2_Stream5
+#undef DMA2_Stream6
+#undef DMA2_Stream7
+#undef ETH
+#undef DMA2D
+#undef DCMI
+#undef CRYP
+#undef HASH
+#undef HASH_DIGEST
+#undef RNG
+#undef FMC_Bank1
+#undef FMC_Bank1E
+#undef FMC_Bank2_3
+#undef FMC_Bank4
+#undef FMC_Bank5_6
+#undef DBGMCU
+#undef USB_OTG_FS
+#undef USB_OTG_HS
+
+namespace ucoo {
+
+namespace reg {
+
+constexpr auto FPU = reinterpret_cast<FPU_Type *> (FPU_BASE);
+constexpr auto SysTick = reinterpret_cast<SysTick_Type *> (SysTick_BASE);
+
+constexpr auto TIM2 = reinterpret_cast<TIM_TypeDef *> (TIM2_BASE);
+constexpr auto TIM3 = reinterpret_cast<TIM_TypeDef *> (TIM3_BASE);
+constexpr auto TIM4 = reinterpret_cast<TIM_TypeDef *> (TIM4_BASE);
+constexpr auto TIM5 = reinterpret_cast<TIM_TypeDef *> (TIM5_BASE);
+constexpr auto TIM6 = reinterpret_cast<TIM_TypeDef *> (TIM6_BASE);
+constexpr auto TIM7 = reinterpret_cast<TIM_TypeDef *> (TIM7_BASE);
+constexpr auto TIM12 = reinterpret_cast<TIM_TypeDef *> (TIM12_BASE);
+constexpr auto TIM13 = reinterpret_cast<TIM_TypeDef *> (TIM13_BASE);
+constexpr auto TIM14 = reinterpret_cast<TIM_TypeDef *> (TIM14_BASE);
+constexpr auto RTC = reinterpret_cast<RTC_TypeDef *> (RTC_BASE);
+constexpr auto WWDG = reinterpret_cast<WWDG_TypeDef *> (WWDG_BASE);
+constexpr auto IWDG = reinterpret_cast<IWDG_TypeDef *> (IWDG_BASE);
+constexpr auto I2S2ext = reinterpret_cast<SPI_TypeDef *> (I2S2ext_BASE);
+constexpr auto SPI2 = reinterpret_cast<SPI_TypeDef *> (SPI2_BASE);
+constexpr auto SPI3 = reinterpret_cast<SPI_TypeDef *> (SPI3_BASE);
+constexpr auto I2S3ext = reinterpret_cast<SPI_TypeDef *> (I2S3ext_BASE);
+constexpr auto USART2 = reinterpret_cast<USART_TypeDef *> (USART2_BASE);
+constexpr auto USART3 = reinterpret_cast<USART_TypeDef *> (USART3_BASE);
+constexpr auto UART4 = reinterpret_cast<USART_TypeDef *> (UART4_BASE);
+constexpr auto UART5 = reinterpret_cast<USART_TypeDef *> (UART5_BASE);
+constexpr auto I2C1 = reinterpret_cast<I2C_TypeDef *> (I2C1_BASE);
+constexpr auto I2C2 = reinterpret_cast<I2C_TypeDef *> (I2C2_BASE);
+constexpr auto I2C3 = reinterpret_cast<I2C_TypeDef *> (I2C3_BASE);
+constexpr auto CAN1 = reinterpret_cast<CAN_TypeDef *> (CAN1_BASE);
+constexpr auto CAN2 = reinterpret_cast<CAN_TypeDef *> (CAN2_BASE);
+constexpr auto PWR = reinterpret_cast<PWR_TypeDef *> (PWR_BASE);
+constexpr auto DAC = reinterpret_cast<DAC_TypeDef *> (DAC_BASE);
+constexpr auto UART7 = reinterpret_cast<USART_TypeDef *> (UART7_BASE);
+constexpr auto UART8 = reinterpret_cast<USART_TypeDef *> (UART8_BASE);
+constexpr auto TIM1 = reinterpret_cast<TIM_TypeDef *> (TIM1_BASE);
+constexpr auto TIM8 = reinterpret_cast<TIM_TypeDef *> (TIM8_BASE);
+constexpr auto USART1 = reinterpret_cast<USART_TypeDef *> (USART1_BASE);
+constexpr auto USART6 = reinterpret_cast<USART_TypeDef *> (USART6_BASE);
+constexpr auto ADC = reinterpret_cast<ADC_Common_TypeDef *> (ADC_BASE);
+constexpr auto ADC1 = reinterpret_cast<ADC_TypeDef *> (ADC1_BASE);
+constexpr auto ADC2 = reinterpret_cast<ADC_TypeDef *> (ADC2_BASE);
+constexpr auto ADC3 = reinterpret_cast<ADC_TypeDef *> (ADC3_BASE);
+constexpr auto SDIO = reinterpret_cast<SDIO_TypeDef *> (SDIO_BASE);
+constexpr auto SPI1 = reinterpret_cast<SPI_TypeDef *> (SPI1_BASE) ;
+constexpr auto SPI4 = reinterpret_cast<SPI_TypeDef *> (SPI4_BASE);
+constexpr auto SYSCFG = reinterpret_cast<SYSCFG_TypeDef *> (SYSCFG_BASE);
+constexpr auto EXTI = reinterpret_cast<EXTI_TypeDef *> (EXTI_BASE);
+constexpr auto TIM9 = reinterpret_cast<TIM_TypeDef *> (TIM9_BASE);
+constexpr auto TIM10 = reinterpret_cast<TIM_TypeDef *> (TIM10_BASE);
+constexpr auto TIM11 = reinterpret_cast<TIM_TypeDef *> (TIM11_BASE);
+constexpr auto SPI5 = reinterpret_cast<SPI_TypeDef *> (SPI5_BASE);
+constexpr auto SPI6 = reinterpret_cast<SPI_TypeDef *> (SPI6_BASE);
+constexpr auto SAI1 = reinterpret_cast<SAI_TypeDef *> (SAI1_BASE);
+constexpr auto SAI1_Block_A = reinterpret_cast<SAI_Block_TypeDef *> (SAI1_Block_A_BASE);
+constexpr auto SAI1_Block_B = reinterpret_cast<SAI_Block_TypeDef *> (SAI1_Block_B_BASE);
+constexpr auto LTDC = reinterpret_cast<LTDC_TypeDef *> (LTDC_BASE);
+constexpr auto LTDC_Layer1 = reinterpret_cast<LTDC_Layer_TypeDef *> (LTDC_Layer1_BASE);
+constexpr auto LTDC_Layer2 = reinterpret_cast<LTDC_Layer_TypeDef *> (LTDC_Layer2_BASE);
+constexpr auto GPIOA = reinterpret_cast<GPIO_TypeDef *> (GPIOA_BASE);
+constexpr auto GPIOB = reinterpret_cast<GPIO_TypeDef *> (GPIOB_BASE);
+constexpr auto GPIOC = reinterpret_cast<GPIO_TypeDef *> (GPIOC_BASE);
+constexpr auto GPIOD = reinterpret_cast<GPIO_TypeDef *> (GPIOD_BASE);
+constexpr auto GPIOE = reinterpret_cast<GPIO_TypeDef *> (GPIOE_BASE);
+constexpr auto GPIOF = reinterpret_cast<GPIO_TypeDef *> (GPIOF_BASE);
+constexpr auto GPIOG = reinterpret_cast<GPIO_TypeDef *> (GPIOG_BASE);
+constexpr auto GPIOH = reinterpret_cast<GPIO_TypeDef *> (GPIOH_BASE);
+constexpr auto GPIOI = reinterpret_cast<GPIO_TypeDef *> (GPIOI_BASE);
+constexpr auto GPIOJ = reinterpret_cast<GPIO_TypeDef *> (GPIOJ_BASE);
+constexpr auto GPIOK = reinterpret_cast<GPIO_TypeDef *> (GPIOK_BASE);
+constexpr auto CRC = reinterpret_cast<CRC_TypeDef *> (CRC_BASE);
+constexpr auto RCC = reinterpret_cast<RCC_TypeDef *> (RCC_BASE);
+constexpr auto FLASH = reinterpret_cast<FLASH_TypeDef *> (FLASH_R_BASE);
+constexpr auto DMA1 = reinterpret_cast<DMA_TypeDef *> (DMA1_BASE);
+constexpr auto DMA1_Stream0 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream0_BASE);
+constexpr auto DMA1_Stream1 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream1_BASE);
+constexpr auto DMA1_Stream2 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream2_BASE);
+constexpr auto DMA1_Stream3 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream3_BASE);
+constexpr auto DMA1_Stream4 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream4_BASE);
+constexpr auto DMA1_Stream5 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream5_BASE);
+constexpr auto DMA1_Stream6 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream6_BASE);
+constexpr auto DMA1_Stream7 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA1_Stream7_BASE);
+constexpr auto DMA2 = reinterpret_cast<DMA_TypeDef *> (DMA2_BASE);
+constexpr auto DMA2_Stream0 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream0_BASE);
+constexpr auto DMA2_Stream1 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream1_BASE);
+constexpr auto DMA2_Stream2 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream2_BASE);
+constexpr auto DMA2_Stream3 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream3_BASE);
+constexpr auto DMA2_Stream4 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream4_BASE);
+constexpr auto DMA2_Stream5 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream5_BASE);
+constexpr auto DMA2_Stream6 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream6_BASE);
+constexpr auto DMA2_Stream7 = reinterpret_cast<DMA_Stream_TypeDef *> (DMA2_Stream7_BASE);
+constexpr auto ETH = reinterpret_cast<ETH_TypeDef *> (ETH_BASE) ;
+constexpr auto DMA2D = reinterpret_cast<DMA2D_TypeDef *> (DMA2D_BASE);
+constexpr auto DCMI = reinterpret_cast<DCMI_TypeDef *> (DCMI_BASE);
+constexpr auto CRYP = reinterpret_cast<CRYP_TypeDef *> (CRYP_BASE);
+constexpr auto HASH = reinterpret_cast<HASH_TypeDef *> (HASH_BASE);
+constexpr auto HASH_DIGEST = reinterpret_cast<HASH_DIGEST_TypeDef *> (HASH_DIGEST_BASE);
+constexpr auto RNG = reinterpret_cast<RNG_TypeDef *> (RNG_BASE);
+constexpr auto FMC_Bank1 = reinterpret_cast<FMC_Bank1_TypeDef *> (FMC_Bank1_R_BASE);
+constexpr auto FMC_Bank1E = reinterpret_cast<FMC_Bank1E_TypeDef *> (FMC_Bank1E_R_BASE);
+constexpr auto FMC_Bank2_3 = reinterpret_cast<FMC_Bank2_3_TypeDef *> (FMC_Bank2_3_R_BASE);
+constexpr auto FMC_Bank4 = reinterpret_cast<FMC_Bank4_TypeDef *> (FMC_Bank4_R_BASE);
+constexpr auto FMC_Bank5_6 = reinterpret_cast<FMC_Bank5_6_TypeDef *> (FMC_Bank5_6_R_BASE);
+constexpr auto DBGMCU = reinterpret_cast<DBGMCU_TypeDef *> (DBGMCU_BASE);
+constexpr auto USB_OTG_FS = reinterpret_cast<USB_OTG_TypeDef *> (USB_OTG_FS_PERIPH_BASE);
+constexpr auto USB_OTG_HS = reinterpret_cast<USB_OTG_TypeDef *> (USB_OTG_HS_PERIPH_BASE);
+constexpr auto DESIG = reinterpret_cast<DESIG_TypeDef *> (DESIG_BASE);
+
+} // namespace reg
+
+} // namespace ucoo
+
+#endif // ucoo_arch_reg_stm32f4_hh
diff --git a/ucoo/arch/vector.arm.cc b/ucoo/arch/vector.arm.cc
new file mode 100644
index 0000000..3e0922a
--- /dev/null
+++ b/ucoo/arch/vector.arm.cc
@@ -0,0 +1,136 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+#include "ucoo/arch/interrupt.arm.hh"
+
+#if defined (TARGET_stm32f4)
+# include "ucoo/arch/vector.stm32f4.hh"
+#elif defined (TARGET_stm32f1)
+# include "ucoo/arch/vector.stm32f1.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+extern uint32_t _stack;
+
+extern "C" void entry ();
+
+namespace ucoo {
+
+typedef void (*vector_t) (void);
+
+struct vector_table_t
+{
+ uint32_t *initial_stack;
+ vector_t exception[static_cast<int> (Exception::COUNT) - 1];
+ vector_t irq[static_cast<int> (Irq::COUNT)];
+};
+
+template<> void interrupt<Exception::NMI> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::HARD_FAULT> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::MEMORY_MANAGEMENT_FAULT> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::BUS_FAULT> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::USAGE_FAULT> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::SV_CALL> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::PEND_SV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Exception::SYSTICK> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+
+vector_table_t vector_table __attribute__ ((section (".vectors"))) =
+{
+ .initial_stack = &_stack,
+ {
+ entry,
+ interrupt<Exception::NMI>,
+ interrupt<Exception::HARD_FAULT>,
+ interrupt<Exception::MEMORY_MANAGEMENT_FAULT>,
+ interrupt<Exception::BUS_FAULT>,
+ interrupt<Exception::USAGE_FAULT>,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ interrupt<Exception::SV_CALL>,
+ nullptr,
+ nullptr,
+ interrupt<Exception::PEND_SV>,
+ interrupt<Exception::SYSTICK>
+ },
+ {
+ UCOO_VECTOR_IRQ
+ }
+};
+
+extern "C" void
+undefined_handler ()
+{
+ halt ();
+}
+
+} // namespace ucoo
+
+int main ();
+
+extern uint32_t _data_loadaddr;
+extern uint32_t _data;
+extern uint32_t _edata;
+extern uint32_t _ebss;
+extern uint32_t __preinit_array_start;
+extern uint32_t __preinit_array_end;
+extern uint32_t __init_array_start;
+extern uint32_t __init_array_end;
+extern uint32_t __fini_array_start;
+extern uint32_t __fini_array_end;
+
+extern "C" void __attribute__ ((naked))
+entry ()
+{
+ uint32_t *src = &_data_loadaddr, *dst = &_data;
+ while (dst < &_edata)
+ *dst++ = *src++;
+ while (dst < &_ebss)
+ *dst++ = 0;
+ SCB->CCR |= SCB_CCR_STKALIGN_Msk;
+#if __FPU_USED
+ SCB->CPACR |= SCB_CPACR_CP10_Full | SCB_CPACR_CP11_Full;
+#endif
+ uint32_t *fp;
+ fp = &__preinit_array_start;
+ while (fp < &__preinit_array_end)
+ reinterpret_cast<void (*) ()> (*fp++) ();
+ fp = &__init_array_start;
+ while (fp < &__init_array_end)
+ reinterpret_cast<void (*) ()> (*fp++) ();
+ main ();
+ fp = &__fini_array_start;
+ while (fp < &__fini_array_end)
+ reinterpret_cast<void (*) ()> (*fp++) ();
+}
diff --git a/ucoo/arch/vector.stm32f1.hh b/ucoo/arch/vector.stm32f1.hh
new file mode 100644
index 0000000..39d3fd4
--- /dev/null
+++ b/ucoo/arch/vector.stm32f1.hh
@@ -0,0 +1,220 @@
+#ifndef ucoo_arch_vector_stm32f1_hh
+#define ucoo_arch_vector_stm32f1_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#define UCOO_VECTOR_IRQ \
+ interrupt<Irq::WWDG>, \
+ interrupt<Irq::PVD>, \
+ interrupt<Irq::TAMPER>, \
+ interrupt<Irq::RTC>, \
+ interrupt<Irq::FLASH>, \
+ interrupt<Irq::RCC>, \
+ interrupt<Irq::EXTI0>, \
+ interrupt<Irq::EXTI1>, \
+ interrupt<Irq::EXTI2>, \
+ interrupt<Irq::EXTI3>, \
+ interrupt<Irq::EXTI4>, \
+ interrupt<Irq::DMA1_Channel1>, \
+ interrupt<Irq::DMA1_Channel2>, \
+ interrupt<Irq::DMA1_Channel3>, \
+ interrupt<Irq::DMA1_Channel4>, \
+ interrupt<Irq::DMA1_Channel5>, \
+ interrupt<Irq::DMA1_Channel6>, \
+ interrupt<Irq::DMA1_Channel7>, \
+ interrupt<Irq::ADC1_2>, \
+ interrupt<Irq::CAN1_TX>, \
+ interrupt<Irq::CAN1_RX0>, \
+ interrupt<Irq::CAN1_RX1>, \
+ interrupt<Irq::CAN1_SCE>, \
+ interrupt<Irq::EXTI9_5>, \
+ interrupt<Irq::TIM1_BRK>, \
+ interrupt<Irq::TIM1_UP>, \
+ interrupt<Irq::TIM1_TRG_COM>, \
+ interrupt<Irq::TIM1_CC>, \
+ interrupt<Irq::TIM2>, \
+ interrupt<Irq::TIM3>, \
+ interrupt<Irq::TIM4>, \
+ interrupt<Irq::I2C1_EV>, \
+ interrupt<Irq::I2C1_ER>, \
+ interrupt<Irq::I2C2_EV>, \
+ interrupt<Irq::I2C2_ER>, \
+ interrupt<Irq::SPI1>, \
+ interrupt<Irq::SPI2>, \
+ interrupt<Irq::USART1>, \
+ interrupt<Irq::USART2>, \
+ interrupt<Irq::USART3>, \
+ interrupt<Irq::EXTI15_10>, \
+ interrupt<Irq::RTC_Alarm>, \
+ interrupt<Irq::OTG_FS_WKUP>, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ interrupt<Irq::TIM5>, \
+ interrupt<Irq::SPI3>, \
+ interrupt<Irq::UART4>, \
+ interrupt<Irq::UART5>, \
+ interrupt<Irq::TIM6>, \
+ interrupt<Irq::TIM7>, \
+ interrupt<Irq::DMA2_Channel1>, \
+ interrupt<Irq::DMA2_Channel2>, \
+ interrupt<Irq::DMA2_Channel3>, \
+ interrupt<Irq::DMA2_Channel4>, \
+ interrupt<Irq::DMA2_Channel5>, \
+ nullptr, \
+ nullptr, \
+ interrupt<Irq::CAN2_TX>, \
+ interrupt<Irq::CAN2_RX0>, \
+ interrupt<Irq::CAN2_RX1>, \
+ interrupt<Irq::CAN2_SCE>, \
+ interrupt<Irq::OTG_FS>
+
+namespace ucoo {
+
+template<> void interrupt<Irq::WWDG> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::PVD> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TAMPER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RTC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::FLASH> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RCC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Channel7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::ADC1_2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_TX> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_RX0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_RX1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_SCE> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI9_5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_BRK> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_UP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_TRG_COM> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_CC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C1_EV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C1_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C2_EV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C2_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI15_10> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RTC_Alarm> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_FS_WKUP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Channel1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Channel2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Channel3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Channel4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Channel5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_TX> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_RX0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_RX1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_SCE> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_FS> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+
+} // namespace ucoo
+
+#endif // ucoo_arch_vector_stm32f1_hh
diff --git a/ucoo/arch/vector.stm32f4.hh b/ucoo/arch/vector.stm32f4.hh
new file mode 100644
index 0000000..5fe1bae
--- /dev/null
+++ b/ucoo/arch/vector.stm32f4.hh
@@ -0,0 +1,307 @@
+#ifndef ucoo_arch_vector_stm32f4_hh
+#define ucoo_arch_vector_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#define UCOO_VECTOR_IRQ \
+ interrupt<Irq::WWDG>, \
+ interrupt<Irq::PVD>, \
+ interrupt<Irq::TAMP_STAMP>, \
+ interrupt<Irq::RTC_WKUP>, \
+ interrupt<Irq::FLASH>, \
+ interrupt<Irq::RCC>, \
+ interrupt<Irq::EXTI0>, \
+ interrupt<Irq::EXTI1>, \
+ interrupt<Irq::EXTI2>, \
+ interrupt<Irq::EXTI3>, \
+ interrupt<Irq::EXTI4>, \
+ interrupt<Irq::DMA1_Stream0>, \
+ interrupt<Irq::DMA1_Stream1>, \
+ interrupt<Irq::DMA1_Stream2>, \
+ interrupt<Irq::DMA1_Stream3>, \
+ interrupt<Irq::DMA1_Stream4>, \
+ interrupt<Irq::DMA1_Stream5>, \
+ interrupt<Irq::DMA1_Stream6>, \
+ interrupt<Irq::ADC>, \
+ interrupt<Irq::CAN1_TX>, \
+ interrupt<Irq::CAN1_RX0>, \
+ interrupt<Irq::CAN1_RX1>, \
+ interrupt<Irq::CAN1_SCE>, \
+ interrupt<Irq::EXTI9_5>, \
+ interrupt<Irq::TIM1_BRK_TIM9>, \
+ interrupt<Irq::TIM1_UP_TIM10>, \
+ interrupt<Irq::TIM1_TRG_COM_TIM11>, \
+ interrupt<Irq::TIM1_CC>, \
+ interrupt<Irq::TIM2>, \
+ interrupt<Irq::TIM3>, \
+ interrupt<Irq::TIM4>, \
+ interrupt<Irq::I2C1_EV>, \
+ interrupt<Irq::I2C1_ER>, \
+ interrupt<Irq::I2C2_EV>, \
+ interrupt<Irq::I2C2_ER>, \
+ interrupt<Irq::SPI1>, \
+ interrupt<Irq::SPI2>, \
+ interrupt<Irq::USART1>, \
+ interrupt<Irq::USART2>, \
+ interrupt<Irq::USART3>, \
+ interrupt<Irq::EXTI15_10>, \
+ interrupt<Irq::RTC_Alarm>, \
+ interrupt<Irq::OTG_FS_WKUP>, \
+ interrupt<Irq::TIM8_BRK_TIM12>, \
+ interrupt<Irq::TIM8_UP_TIM13>, \
+ interrupt<Irq::TIM8_TRG_COM_TIM14>, \
+ interrupt<Irq::TIM8_CC>, \
+ interrupt<Irq::DMA1_Stream7>, \
+ interrupt<Irq::FMC>, \
+ interrupt<Irq::SDIO>, \
+ interrupt<Irq::TIM5>, \
+ interrupt<Irq::SPI3>, \
+ interrupt<Irq::UART4>, \
+ interrupt<Irq::UART5>, \
+ interrupt<Irq::TIM6_DAC>, \
+ interrupt<Irq::TIM7>, \
+ interrupt<Irq::DMA2_Stream0>, \
+ interrupt<Irq::DMA2_Stream1>, \
+ interrupt<Irq::DMA2_Stream2>, \
+ interrupt<Irq::DMA2_Stream3>, \
+ interrupt<Irq::DMA2_Stream4>, \
+ interrupt<Irq::ETH>, \
+ interrupt<Irq::ETH_WKUP>, \
+ interrupt<Irq::CAN2_TX>, \
+ interrupt<Irq::CAN2_RX0>, \
+ interrupt<Irq::CAN2_RX1>, \
+ interrupt<Irq::CAN2_SCE>, \
+ interrupt<Irq::OTG_FS>, \
+ interrupt<Irq::DMA2_Stream5>, \
+ interrupt<Irq::DMA2_Stream6>, \
+ interrupt<Irq::DMA2_Stream7>, \
+ interrupt<Irq::USART6>, \
+ interrupt<Irq::I2C3_EV>, \
+ interrupt<Irq::I2C3_ER>, \
+ interrupt<Irq::OTG_HS_EP1_OUT>, \
+ interrupt<Irq::OTG_HS_EP1_IN>, \
+ interrupt<Irq::OTG_HS_WKUP>, \
+ interrupt<Irq::OTG_HS>, \
+ interrupt<Irq::DCMI>, \
+ interrupt<Irq::CRYP>, \
+ interrupt<Irq::HASH_RNG>, \
+ interrupt<Irq::FPU>, \
+ interrupt<Irq::UART7>, \
+ interrupt<Irq::UART8>, \
+ interrupt<Irq::SPI4>, \
+ interrupt<Irq::SPI5>, \
+ interrupt<Irq::SPI6>, \
+ interrupt<Irq::SAI1>, \
+ interrupt<Irq::LTDC>, \
+ interrupt<Irq::LTDC_ER>, \
+ interrupt<Irq::DMA2D>
+
+namespace ucoo {
+
+template<> void interrupt<Irq::WWDG> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::PVD> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TAMP_STAMP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RTC_WKUP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::FLASH> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RCC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::ADC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_TX> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_RX0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_RX1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN1_SCE> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI9_5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_BRK_TIM9> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_UP_TIM10> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_TRG_COM_TIM11> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM1_CC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C1_EV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C1_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C2_EV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C2_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::EXTI15_10> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::RTC_Alarm> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_FS_WKUP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM8_BRK_TIM12> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM8_UP_TIM13> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM8_TRG_COM_TIM14> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM8_CC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA1_Stream7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::FMC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SDIO> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM6_DAC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::TIM7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream2> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream3> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::ETH> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::ETH_WKUP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_TX> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_RX0> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_RX1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CAN2_SCE> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_FS> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2_Stream7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::USART6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C3_EV> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::I2C3_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_HS_EP1_OUT> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_HS_EP1_IN> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_HS_WKUP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::OTG_HS> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DCMI> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::CRYP> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::HASH_RNG> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::FPU> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART7> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::UART8> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI4> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI5> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SPI6> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::SAI1> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::LTDC> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::LTDC_ER> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+template<> void interrupt<Irq::DMA2D> ()
+ __attribute__ ((weak, alias ("undefined_handler")));
+
+} // namespace ucoo
+
+#endif // ucoo_arch_vector_stm32f4_hh
diff --git a/ucoo/base/fs/romfs/test/Makefile b/ucoo/base/fs/romfs/test/Makefile
index c4ec6bc..3a99d3d 100644
--- a/ucoo/base/fs/romfs/test/Makefile
+++ b/ucoo/base/fs/romfs/test/Makefile
@@ -4,7 +4,7 @@ TARGETS = host stm32f4
PROGS = test_romfs
test_romfs_SOURCES = test_romfs.cc
-MODULES = ucoo/base/test ucoo/base/fs/romfs ucoo/hal/usb
+MODULES = ucoo/base/test ucoo/base/fs/romfs ucoo/hal/usb ucoo/hal/gpio
COMPILE_DEPS = $(OBJDIR)/test_fs.h
EXTRA_CLEAN = $(OBJDIR)/test_fs.h
diff --git a/ucoo/base/proto/test/Makefile b/ucoo/base/proto/test/Makefile
index 8c093f0..40469ac 100644
--- a/ucoo/base/proto/test/Makefile
+++ b/ucoo/base/proto/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = host stm32f4
PROGS = test_proto
test_proto_SOURCES = test_proto.cc
-MODULES = ucoo/base/proto ucoo/base/test ucoo/hal/usb
+MODULES = ucoo/base/proto ucoo/base/test ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/base/test/Config b/ucoo/base/test/Config
index 703bbee..e7ec1b9 100644
--- a/ucoo/base/test/Config
+++ b/ucoo/base/test/Config
@@ -1,9 +1,13 @@
[ucoo/base/test]
+# Before test startup, wait for a key to be pressed.
wait = false
-test_stream_uart = -1
+# Use USB or UART as test stream?
+test_stream_use_usb = true
+test_stream_uart_instance = Uart::Instance::USART1
test_stream_uart_speed = 115200
-test_stream_vendor = "APBTeam"
-test_stream_product = "test"
+test_stream_usb_instance = UsbDriverDwcOtg::Instance::OTG_FS
+test_stream_usb_vendor = u"APBTeam"
+test_stream_usb_product = u"test"
[ucoo/base/test:stm32]
wait = true
diff --git a/ucoo/base/test/test.stm32.cc b/ucoo/base/test/test.stm32.cc
index cb47db3..3d7a9fa 100644
--- a/ucoo/base/test/test.stm32.cc
+++ b/ucoo/base/test/test.stm32.cc
@@ -24,8 +24,9 @@
#include "test.hh"
#include "config/ucoo/base/test.hh"
-#if CONFIG_UCOO_BASE_TEST_TEST_STREAM_UART == -1
+#if CONFIG_UCOO_BASE_TEST_TEST_STREAM_USE_USB
# include "ucoo/hal/usb/usb.hh"
+# include "ucoo/hal/usb/usb_cdc.hh"
#else
# include "ucoo/hal/uart/uart.hh"
#endif
@@ -37,15 +38,27 @@ namespace ucoo {
Stream &
test_stream (void)
{
-#if CONFIG_UCOO_BASE_TEST_TEST_STREAM_UART == -1
- static UsbStreamControl usc (CONFIG_UCOO_BASE_TEST_TEST_STREAM_VENDOR,
- CONFIG_UCOO_BASE_TEST_TEST_STREAM_PRODUCT);
- static UsbStream us (usc, 0);
- usc.enable ();
- return us;
-#else
- static Uart u (CONFIG_UCOO_BASE_TEST_TEST_STREAM_UART);
static bool enabled = false;
+#if CONFIG_UCOO_BASE_TEST_TEST_STREAM_USE_USB
+ static const auto string_descs_pack = usb_descs_pack (
+ usb_string_desc (USB_LANGUAGE_EN_US),
+ usb_string_desc (CONFIG_UCOO_BASE_TEST_TEST_STREAM_USB_VENDOR),
+ usb_string_desc (CONFIG_UCOO_BASE_TEST_TEST_STREAM_USB_PRODUCT));
+ static const auto string_descs = ucoo::usb_descs (string_descs_pack);
+ static UsbDriverDwcOtg driver (
+ CONFIG_UCOO_BASE_TEST_TEST_STREAM_USB_INSTANCE,
+ usb_cdc_default_device_desc (),
+ usb_cdc_default_configuration_desc (),
+ string_descs);
+ static UsbApplicationCdcAcm cdc (driver);
+ if (!enabled)
+ {
+ enabled = true;
+ driver.enable ();
+ }
+ return cdc;
+#else
+ static Uart u (CONFIG_UCOO_BASE_TEST_TEST_STREAM_UART_INSTANCE);
if (!enabled)
{
enabled = true;
diff --git a/ucoo/base/test/test/Makefile b/ucoo/base/test/test/Makefile
index 64e5021..b4293ec 100644
--- a/ucoo/base/test/test/Makefile
+++ b/ucoo/base/test/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = host stm32f4
PROGS = test_test
test_test_SOURCES = test_test.cc
-MODULES = ucoo/utils ucoo/base/test ucoo/hal/usb
+MODULES = ucoo/utils ucoo/base/test ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/common.hh b/ucoo/common.hh
index 708b9a1..5e982d8 100644
--- a/ucoo/common.hh
+++ b/ucoo/common.hh
@@ -100,6 +100,10 @@ assert_perror (bool condition)
halt_perror ();
}
+/// Give some time to other tasks when running in a tight loop.
+void
+yield ();
+
/// Get array length at compile time.
template<class T, int N>
constexpr int
diff --git a/ucoo/dev/avrisp/test/test_avrisp.cc b/ucoo/dev/avrisp/test/test_avrisp.cc
index f38cf52..319a6b8 100644
--- a/ucoo/dev/avrisp/test/test_avrisp.cc
+++ b/ucoo/dev/avrisp/test/test_avrisp.cc
@@ -29,8 +29,6 @@
#include "ucoo/hal/spi/spi_soft.hh"
#include "ucoo/utils/delay.hh"
-#include <libopencm3/stm32/f4/rcc.h>
-
class TestAvrIspIntf : public ucoo::AvrIspIntf
{
public:
@@ -76,10 +74,10 @@ main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
ucoo::Stream &ts = ucoo::test_stream ();
- rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN
- | RCC_AHB1ENR_IOPEEN);
- ucoo::Gpio reset (GPIOD, 10), sck (GPIOE, 7), mosi (GPIOD, 8),
- miso (GPIOD, 9);
+ ucoo::GPIOD.enable ();
+ ucoo::GPIOE.enable ();
+ ucoo::Gpio reset (ucoo::GPIOD[10]), sck (ucoo::GPIOE[7]),
+ mosi (ucoo::GPIOD[8]), miso (ucoo::GPIOD[9]);
TestAvrIspIntf intf (reset, sck, mosi, miso);
ucoo::AvrIsp isp (intf);
ucoo::AvrIspProto proto (isp);
diff --git a/ucoo/dev/lcd/test/test_lcd.cc b/ucoo/dev/lcd/test/test_lcd.cc
index c654287..d4c0f79 100644
--- a/ucoo/dev/lcd/test/test_lcd.cc
+++ b/ucoo/dev/lcd/test/test_lcd.cc
@@ -29,19 +29,17 @@
#include "ucoo/arch/arch.hh"
-#include <libopencm3/stm32/rcc.h>
-
int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- rcc_periph_clock_enable (RCC_GPIOB);
- ucoo::Gpio rw (GPIOB, 10);
- ucoo::Gpio rs (GPIOB, 11);
- ucoo::Gpio cs (GPIOB, 12);
- ucoo::Gpio sck (GPIOB, 13);
- ucoo::Gpio miso (GPIOB, 14);
- ucoo::Gpio mosi (GPIOB, 15);
+ ucoo::GPIOB.enable ();
+ ucoo::Gpio rw (ucoo::GPIOB[10]);
+ ucoo::Gpio rs (ucoo::GPIOB[11]);
+ ucoo::Gpio cs (ucoo::GPIOB[12]);
+ ucoo::Gpio sck (ucoo::GPIOB[13]);
+ ucoo::Gpio miso (ucoo::GPIOB[14]);
+ ucoo::Gpio mosi (ucoo::GPIOB[15]);
ucoo::SpiSoftMaster spi (sck, mosi, miso);
rw.reset ();
rw.output ();
diff --git a/ucoo/hal/adc/adc_hard.stm32f4.cc b/ucoo/hal/adc/adc_hard.stm32f4.cc
index c89d610..ef56fd3 100644
--- a/ucoo/hal/adc/adc_hard.stm32f4.cc
+++ b/ucoo/hal/adc/adc_hard.stm32f4.cc
@@ -21,23 +21,17 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include "adc_hard.stm32f4.hh"
-
-#include <libopencm3/stm32/adc.h>
-#include <libopencm3/stm32/rcc.h>
+#include "ucoo/hal/adc/adc_hard.stm32f4.hh"
namespace ucoo {
-static const enum rcc_periph_clken adc_clken[] = {
- RCC_ADC1, RCC_ADC2, RCC_ADC3
-};
+static ADC_TypeDef * const bases[] = { reg::ADC1, reg::ADC2, reg::ADC3 };
+static const Rcc rccs[] = { Rcc::ADC1, Rcc::ADC2, Rcc::ADC3 };
-AdcHard::AdcHard (int n)
- : n_ (n)
+AdcHard::AdcHard (AdcHard::Instance inst)
+ : base_ (bases[static_cast<int> (inst)]),
+ rcc_ (rccs[static_cast<int> (inst)])
{
- static const uint32_t bases[] = { ADC1, ADC2, ADC3 };
- assert (n < (int) lengthof (bases));
- base_ = bases[n];
}
AdcHard::~AdcHard ()
@@ -48,26 +42,26 @@ AdcHard::~AdcHard ()
void
AdcHard::enable ()
{
- rcc_periph_clock_enable (adc_clken[n_]);
- ADC_CR2 (base_) = ADC_CR2_ADON;
+ rcc_peripheral_clock_enable (rcc_);
+ base_->CR2 = ADC_CR2_ADON;
}
void
AdcHard::disable ()
{
- ADC_CR2 (base_) = 0;
- rcc_periph_clock_disable (adc_clken[n_]);
+ base_->CR2 = 0;
+ rcc_peripheral_clock_disable (rcc_);
}
int
AdcHard::read (int channel)
{
- ADC_SQR3 (base_) = channel;
- ADC_CR2 (base_) |= ADC_CR2_SWSTART;
- while (!(ADC_SR (base_) & ADC_SR_EOC))
+ base_->SQR3 = channel;
+ base_->CR2 |= ADC_CR2_SWSTART;
+ while (!(base_->SR & ADC_SR_EOC))
yield ();
- ADC_SR (base_) = ~ADC_SR_EOC;
- return ADC_DR (base_);
+ base_->SR = ~ADC_SR_EOC;
+ return base_->DR;
}
} // namespace ucoo
diff --git a/ucoo/hal/adc/adc_hard.stm32f4.hh b/ucoo/hal/adc/adc_hard.stm32f4.hh
index 7ab0d7f..3947b7c 100644
--- a/ucoo/hal/adc/adc_hard.stm32f4.hh
+++ b/ucoo/hal/adc/adc_hard.stm32f4.hh
@@ -26,17 +26,47 @@
#include "ucoo/intf/adc.hh"
#include "ucoo/common.hh"
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
+
namespace ucoo {
+class AdcHard;
+
+/// Single ADC channel.
+class AdcHardChannel : public Adc
+{
+ public:
+ /// See Adc::read.
+ inline int read ();
+ /// See Adc::get_resolution.
+ inline int get_resolution () const;
+ private:
+ /// Constructor.
+ AdcHardChannel (AdcHard &adc, int channel)
+ : adc_ (adc), channel_ (channel) { }
+ friend AdcHard;
+ private:
+ AdcHard &adc_;
+ int channel_;
+};
+
/// ADC interface. This control a full ADC, use AdcHardChannel for a single
/// channel.
class AdcHard
{
public:
static const int resolution = 1 << 12;
+ /// Available ADC.
+ enum class Instance
+ {
+ ADC1,
+ ADC2,
+ ADC3,
+ };
public:
- /// Constructor for the Nth ADC.
- AdcHard (int n);
+ /// Constructor for an ADC instance.
+ AdcHard (Instance inst);
/// Shutdown.
~AdcHard ();
/// Enable, power on.
@@ -45,28 +75,27 @@ class AdcHard
void disable ();
/// Make a single measure.
int read (int channel);
+ /// Return an ADC channel.
+ AdcHardChannel operator[] (int channel)
+ { return AdcHardChannel (*this, channel); }
private:
- /// ADC index.
- int n_;
/// ADC base address.
- uint32_t base_;
+ ADC_TypeDef * const base_;
+ /// ADC RCC identifier.
+ const Rcc rcc_;
};
-/// Single ADC channel.
-class AdcHardChannel : public Adc
+inline int
+AdcHardChannel::read ()
{
- public:
- /// Constructor.
- AdcHardChannel (AdcHard &adc, int channel)
- : adc_ (adc), channel_ (channel) { }
- /// See Adc::read.
- int read () { return adc_.read (channel_); }
- /// See Adc::get_resolution.
- int get_resolution () const { return AdcHard::resolution; }
- private:
- AdcHard &adc_;
- int channel_;
-};
+ return adc_.read (channel_);
+}
+
+inline int
+AdcHardChannel::get_resolution () const
+{
+ return AdcHard::resolution;
+}
} // namespace ucoo
diff --git a/ucoo/hal/adc/test/Makefile b/ucoo/hal/adc/test/Makefile
index c6c8a3c..603093d 100644
--- a/ucoo/hal/adc/test/Makefile
+++ b/ucoo/hal/adc/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = stm32f4
stm32f4_PROGS = test_adc
test_adc_SOURCES = test_adc.cc
-MODULES = ucoo/hal/adc ucoo/base/test ucoo/hal/usb ucoo/utils
+MODULES = ucoo/hal/adc ucoo/base/test ucoo/hal/usb ucoo/hal/gpio ucoo/utils
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/adc/test/test_adc.cc b/ucoo/hal/adc/test/test_adc.cc
index 58cca96..03825da 100644
--- a/ucoo/hal/adc/test/test_adc.cc
+++ b/ucoo/hal/adc/test/test_adc.cc
@@ -26,9 +26,8 @@
#include "ucoo/arch/arch.hh"
#include "ucoo/base/test/test.hh"
#include "ucoo/utils/delay.hh"
-
-#include <libopencm3/stm32/adc.h>
#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/arch/reg.hh"
#include <cstdio>
@@ -38,10 +37,10 @@ main (int argc, const char **argv)
ucoo::arch_init (argc, argv);
ucoo::test_stream_setup ();
// Have fun with temperature sensor.
- ucoo::AdcHard adc (0);
+ ucoo::AdcHard adc (ucoo::AdcHard::Instance::ADC1);
adc.enable ();
- ADC_CCR = ADC_CCR_TSVREFE;
- ucoo::AdcHardChannel c (adc, 16);
+ ucoo::reg::ADC->CCR = ADC_CCR_TSVREFE;
+ ucoo::AdcHardChannel c = adc[16];
while (1)
{
int r = c.read ();
diff --git a/ucoo/hal/exti/exti.stm32.cc b/ucoo/hal/exti/exti.stm32.cc
index 120b25e..c3e6064 100644
--- a/ucoo/hal/exti/exti.stm32.cc
+++ b/ucoo/hal/exti/exti.stm32.cc
@@ -22,13 +22,8 @@
//
// }}}
#include "ucoo/hal/exti/exti.stm32.hh"
-#include "ucoo/common.hh"
-#include <libopencm3/cm3/nvic.h>
-#include <libopencm3/stm32/gpio.h>
-#if !defined AFIO_BASE
-# include <libopencm3/stm32/syscfg.h>
-#endif
+#include "ucoo/arch/interrupt.arm.hh"
namespace ucoo {
@@ -36,7 +31,7 @@ namespace ucoo {
struct exti_hardware_t
{
/// Corresponding IRQ.
- int irq;
+ Irq irq;
/// Pointer to number of enabled EXTI for shared vectors, or NULL.
int *enabled;
};
@@ -48,109 +43,101 @@ static int exti_vector_9_5_enabled;
static int exti_vector_15_10_enabled;
/// Information on EXTI hardware array.
-struct exti_hardware_t exti_hardware[] =
-{
- { NVIC_EXTI0_IRQ, nullptr },
- { NVIC_EXTI1_IRQ, nullptr },
- { NVIC_EXTI2_IRQ, nullptr },
- { NVIC_EXTI3_IRQ, nullptr },
- { NVIC_EXTI4_IRQ, nullptr },
- { NVIC_EXTI9_5_IRQ, &exti_vector_9_5_enabled },
- { NVIC_EXTI9_5_IRQ, &exti_vector_9_5_enabled },
- { NVIC_EXTI9_5_IRQ, &exti_vector_9_5_enabled },
- { NVIC_EXTI9_5_IRQ, &exti_vector_9_5_enabled },
- { NVIC_EXTI9_5_IRQ, &exti_vector_9_5_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
- { NVIC_EXTI15_10_IRQ, &exti_vector_15_10_enabled },
+static const exti_hardware_t exti_hardware[] =
+{
+ { Irq::EXTI0, nullptr },
+ { Irq::EXTI1, nullptr },
+ { Irq::EXTI2, nullptr },
+ { Irq::EXTI3, nullptr },
+ { Irq::EXTI4, nullptr },
+ { Irq::EXTI9_5, &exti_vector_9_5_enabled },
+ { Irq::EXTI9_5, &exti_vector_9_5_enabled },
+ { Irq::EXTI9_5, &exti_vector_9_5_enabled },
+ { Irq::EXTI9_5, &exti_vector_9_5_enabled },
+ { Irq::EXTI9_5, &exti_vector_9_5_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
+ { Irq::EXTI15_10, &exti_vector_15_10_enabled },
};
static ExtiHard *exti_instances[lengthof (exti_hardware)];
-} // namespace ucoo
-
-extern "C" {
-
// If the interrupt is triggered again after being cleared, the interrupt
// handler will be reentered. There is no need to loop.
-void
-exti0_isr ()
+template<>
+void interrupt<Irq::EXTI0> ()
{
- EXTI_PR = 1u << 0;
- assert (ucoo::exti_instances[0]);
- ucoo::exti_instances[0]->isr ();
+ reg::EXTI->PR = 1u << 0;
+ assert (exti_instances[0]);
+ exti_instances[0]->isr ();
}
-void
-exti1_isr ()
+template<>
+void interrupt<Irq::EXTI1> ()
{
- EXTI_PR = 1u << 1;
- assert (ucoo::exti_instances[1]);
- ucoo::exti_instances[1]->isr ();
+ reg::EXTI->PR = 1u << 1;
+ assert (exti_instances[1]);
+ exti_instances[1]->isr ();
}
-void
-exti2_isr ()
+template<>
+void interrupt<Irq::EXTI2> ()
{
- EXTI_PR = 1u << 2;
- assert (ucoo::exti_instances[2]);
- ucoo::exti_instances[2]->isr ();
+ reg::EXTI->PR = 1u << 2;
+ assert (exti_instances[2]);
+ exti_instances[2]->isr ();
}
-void
-exti3_isr ()
+template<>
+void interrupt<Irq::EXTI3> ()
{
- EXTI_PR = 1u << 3;
- assert (ucoo::exti_instances[3]);
- ucoo::exti_instances[3]->isr ();
+ reg::EXTI->PR = 1u << 3;
+ assert (exti_instances[3]);
+ exti_instances[3]->isr ();
}
-void
-exti4_isr ()
+template<>
+void interrupt<Irq::EXTI4> ()
{
- EXTI_PR = 1u << 4;
- assert (ucoo::exti_instances[4]);
- ucoo::exti_instances[4]->isr ();
+ reg::EXTI->PR = 1u << 4;
+ assert (exti_instances[4]);
+ exti_instances[4]->isr ();
}
-void
-exti9_5_isr ()
+template<>
+void interrupt<Irq::EXTI9_5> ()
{
- uint32_t pending = EXTI_PR & 0x3e0;
- EXTI_PR = pending;
+ uint32_t pending = reg::EXTI->PR & 0x3e0;
+ reg::EXTI->PR = pending;
for (int i = 5; i <= 9; i++)
{
if (pending & (1u << i))
{
- assert (ucoo::exti_instances[i]);
- ucoo::exti_instances[i]->isr ();
+ assert (exti_instances[i]);
+ exti_instances[i]->isr ();
}
}
}
-void
-exti15_10_isr ()
+template<>
+void interrupt<Irq::EXTI15_10> ()
{
- uint32_t pending = EXTI_PR & 0xfc00;
- EXTI_PR = pending;
+ uint32_t pending = reg::EXTI->PR & 0xfc00;
+ reg::EXTI->PR = pending;
for (int i = 10; i <= 15; i++)
{
if (pending & (1u << i))
{
- assert (ucoo::exti_instances[i]);
- ucoo::exti_instances[i]->isr ();
+ assert (exti_instances[i]);
+ exti_instances[i]->isr ();
}
}
}
-}
-
-namespace ucoo {
-
ExtiHard::ExtiHard (int n)
: n_ (n)
{
@@ -169,14 +156,14 @@ void
ExtiHard::enable ()
{
assert (handler_);
- EXTI_IMR |= 1u << n_;
+ reg::EXTI->IMR |= 1u << n_;
if (exti_hardware[n_].enabled)
{
if (!(*exti_hardware[n_].enabled)++)
- nvic_enable_irq (exti_hardware[n_].irq);
+ interrupt_enable (exti_hardware[n_].irq);
}
else
- nvic_enable_irq (exti_hardware[n_].irq);
+ interrupt_enable (exti_hardware[n_].irq);
}
void
@@ -185,20 +172,20 @@ ExtiHard::disable ()
if (exti_hardware[n_].enabled)
{
if (!--*exti_hardware[n_].enabled)
- nvic_disable_irq (exti_hardware[n_].irq);
+ interrupt_disable (exti_hardware[n_].irq);
}
else
- nvic_disable_irq (exti_hardware[n_].irq);
- EXTI_IMR &= ~(1u << n_);
- EXTI_PR = 1u << n_;
+ interrupt_disable (exti_hardware[n_].irq);
+ reg::EXTI->IMR &= ~(1u << n_);
+ reg::EXTI->PR = 1u << n_;
}
bool
ExtiHard::mask ()
{
- bool irq_enabled = nvic_get_irq_enabled (exti_hardware[n_].irq);
+ bool irq_enabled = interrupt_is_enabled (exti_hardware[n_].irq);
if (irq_enabled)
- nvic_disable_irq (exti_hardware[n_].irq);
+ interrupt_disable (exti_hardware[n_].irq);
return irq_enabled;
}
@@ -206,7 +193,7 @@ void
ExtiHard::unmask (bool saved_state)
{
if (saved_state)
- nvic_enable_irq (exti_hardware[n_].irq);
+ interrupt_enable (exti_hardware[n_].irq);
}
void
@@ -215,74 +202,32 @@ ExtiHard::set_trigger (Edge edge)
switch (edge)
{
case Edge::RISING:
- EXTI_RTSR |= 1u << n_;
- EXTI_FTSR &= ~(1u << n_);
+ reg::EXTI->RTSR |= 1u << n_;
+ reg::EXTI->FTSR &= ~(1u << n_);
break;
case Edge::FALLING:
- EXTI_RTSR &= ~(1u << n_);
- EXTI_FTSR |= 1u << n_;
+ reg::EXTI->RTSR &= ~(1u << n_);
+ reg::EXTI->FTSR |= 1u << n_;
break;
case Edge::BOTH:
- EXTI_RTSR |= (1u << n_);
- EXTI_FTSR |= (1u << n_);
+ reg::EXTI->RTSR |= (1u << n_);
+ reg::EXTI->FTSR |= (1u << n_);
break;
}
}
void
-ExtiHard::set_source (uint32_t gpio_port)
+ExtiHard::set_source (const GpioPort &gpio_port)
{
- int port;
- switch (gpio_port)
- {
- case GPIOA:
- port = 0;
- break;
- case GPIOB:
- port = 1;
- break;
- case GPIOC:
- port = 2;
- break;
- case GPIOD:
- port = 3;
- break;
-#if defined GPIOE
- case GPIOE:
- port = 4;
- break;
-#endif
-#if defined GPIOF
- case GPIOF:
- port = 5;
- break;
-#endif
-#if defined GPIOG
- case GPIOG:
- port = 6;
- break;
-#endif
-#if defined GPIOH
- case GPIOH:
- port = 7;
- break;
-#endif
-#if defined GPIOI
- case GPIOI:
- port = 8;
- break;
-#endif
- default:
- assert_unreachable ();
- }
+ int port = gpio_port.get_port_index ();
int shift = (n_ % 4) * 4;
int reg = n_ / 4;
uint32_t mask = 0xf << shift;
uint32_t bits = port << shift;
#if defined AFIO_BASE
- AFIO_EXTICR (reg) = (AFIO_EXTICR (reg) & ~mask) | bits;
+ reg::AFIO->EXTICR[reg] = (reg::AFIO->EXTICR[reg] & ~mask) | bits;
#else
- SYSCFG_EXTICR (reg) = (SYSCFG_EXTICR (reg) & ~mask) | bits;
+ reg::SYSCFG->EXTICR[reg] = (reg::SYSCFG->EXTICR[reg] & ~mask) | bits;
#endif
}
diff --git a/ucoo/hal/exti/exti.stm32.hh b/ucoo/hal/exti/exti.stm32.hh
index 90a8098..3ac20d2 100644
--- a/ucoo/hal/exti/exti.stm32.hh
+++ b/ucoo/hal/exti/exti.stm32.hh
@@ -24,8 +24,8 @@
//
// }}}
#include "ucoo/intf/exti.hh"
-
-#include <libopencm3/stm32/exti.h>
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/arch/interrupt.arm.hh"
namespace ucoo {
@@ -43,9 +43,9 @@ class ExtiHard : public Exti
/// Constructor, take the EXTI number.
ExtiHard (int n);
/// Constructor, shortcut to set source.
- ExtiHard (uint32_t gpio_port, int n);
+ ExtiHard (const GpioPort &gpio_port, int n);
/// Constructor, shortcut to set source and trigger.
- ExtiHard (uint32_t gpio_port, int n, Edge edge);
+ ExtiHard (const GpioPort &gpio_port, int n, Edge edge);
/// Destructor.
~ExtiHard ();
/// See Exti::enable.
@@ -59,23 +59,26 @@ class ExtiHard : public Exti
/// Set trigger edge.
void set_trigger (Edge edge);
/// Select source, take GPIO port address.
- void set_source (uint32_t gpio_port);
+ void set_source (const GpioPort &gpio_port);
+ private:
/// Handle interrupts.
void isr ();
+ template<Irq>
+ friend void interrupt ();
private:
/// EXTI line number.
int n_;
};
inline
-ExtiHard::ExtiHard (uint32_t gpio_port, int n)
+ExtiHard::ExtiHard (const GpioPort &gpio_port, int n)
: ExtiHard (n)
{
set_source (gpio_port);
}
inline
-ExtiHard::ExtiHard (uint32_t gpio_port, int n, Edge edge)
+ExtiHard::ExtiHard (const GpioPort &gpio_port, int n, Edge edge)
: ExtiHard (gpio_port, n)
{
set_trigger (edge);
diff --git a/ucoo/hal/exti/test/test_exti.stm32.cc b/ucoo/hal/exti/test/test_exti.stm32.cc
index 57b80a5..3aee1b0 100644
--- a/ucoo/hal/exti/test/test_exti.stm32.cc
+++ b/ucoo/hal/exti/test/test_exti.stm32.cc
@@ -26,8 +26,6 @@
#include "ucoo/hal/exti/exti.hh"
#include "ucoo/utils/delay.hh"
-#include <libopencm3/stm32/rcc.h>
-
ucoo::Gpio *led4p;
void
@@ -40,16 +38,16 @@ int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- rcc_periph_clock_enable (RCC_GPIOB);
- rcc_periph_clock_enable (RCC_GPIOD);
+ ucoo::GPIOB.enable ();
+ ucoo::GPIOD.enable ();
// For this test, shorten B6 & B7 to have loopback.
- ucoo::Gpio loop_out (GPIOB, 6);
- ucoo::Gpio loop_in (GPIOB, 7);
- ucoo::Gpio led3 (GPIOD, 13);
- ucoo::Gpio led4 (GPIOD, 12);
+ ucoo::Gpio loop_out (ucoo::GPIOB[6]);
+ ucoo::Gpio loop_in (ucoo::GPIOB[7]);
+ ucoo::Gpio led3 (ucoo::GPIOD[13]);
+ ucoo::Gpio led4 (ucoo::GPIOD[12]);
led4p = &led4;
ucoo::ExtiHard exti (7);
- exti.set_source (GPIOB);
+ exti.set_source (ucoo::GPIOB);
exti.set_trigger (ucoo::ExtiHard::Edge::RISING);
exti.register_event (led4_handler);
exti.enable ();
diff --git a/ucoo/hal/gpio/gpio.stm32f1.cc b/ucoo/hal/gpio/gpio.stm32f1.cc
index 0e6c7ee..4927b4e 100644
--- a/ucoo/hal/gpio/gpio.stm32f1.cc
+++ b/ucoo/hal/gpio/gpio.stm32f1.cc
@@ -21,30 +21,37 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include "gpio.stm32f1.hh"
+#include "ucoo/hal/gpio/gpio.stm32f1.hh"
+#include "ucoo/common.hh"
namespace ucoo {
+GpioPort GPIOA (reg::GPIOA, Rcc::GPIOA);
+GpioPort GPIOB (reg::GPIOB, Rcc::GPIOB);
+GpioPort GPIOC (reg::GPIOC, Rcc::GPIOC);
+GpioPort GPIOD (reg::GPIOD, Rcc::GPIOD);
+GpioPort GPIOE (reg::GPIOE, Rcc::GPIOE);
+
void
Gpio::set ()
{
- GPIO_BSRR (port_) = mask_;
+ port_->BSRR = mask_;
}
void
Gpio::reset ()
{
- GPIO_BRR (port_) = mask_;
+ port_->BRR = mask_;
}
/// Helper to avoid virtual dance.
static inline void
-Gpio_set (uint32_t port, uint16_t mask, bool state)
+Gpio_set (GPIO_TypeDef *port, uint16_t mask, bool state)
{
if (state)
- GPIO_BSRR (port) = mask;
+ port->BSRR = mask;
else
- GPIO_BRR (port) = mask;
+ port->BRR = mask;
}
void
@@ -57,13 +64,13 @@ void
Gpio::toggle ()
{
// Avoid read/modify/write ODR, to achieve atomic operation.
- Gpio_set (port_, mask_, !(GPIO_ODR (port_) & mask_));
+ Gpio_set (port_, mask_, !(port_->ODR & mask_));
}
bool
Gpio::get () const
{
- return GPIO_IDR (port_) & mask_;
+ return port_->IDR & mask_;
}
/// Set four bits in a register for the corresponding one-bit mask.
@@ -81,11 +88,11 @@ qmask_set (uint32_t mask, uint32_t reg, uint32_t bits)
void
Gpio::input ()
{
- uint32_t cnf_mode = static_cast<uint8_t> (input_cnf_) | GPIO_MODE_INPUT;
+ uint32_t cnf_mode = static_cast<uint8_t> (input_cnf_) | GPIO_MODE_Input;
if (mask_ & 0xff)
- GPIO_CRL (port_) = qmask_set (mask_, GPIO_CRL (port_), cnf_mode);
+ port_->CRL = qmask_set (mask_, port_->CRL, cnf_mode);
else
- GPIO_CRH (port_) = qmask_set (mask_ >> 8, GPIO_CRH (port_), cnf_mode);
+ port_->CRH = qmask_set (mask_ >> 8, port_->CRH, cnf_mode);
output_ = false;
}
@@ -95,9 +102,9 @@ Gpio::output ()
uint32_t cnf_mode = static_cast<uint8_t> (output_cnf_)
| static_cast<uint8_t> (speed_);
if (mask_ & 0xff)
- GPIO_CRL (port_) = qmask_set (mask_, GPIO_CRL (port_), cnf_mode);
+ port_->CRL = qmask_set (mask_, port_->CRL, cnf_mode);
else
- GPIO_CRH (port_) = qmask_set (mask_ >> 8, GPIO_CRH (port_), cnf_mode);
+ port_->CRH = qmask_set (mask_ >> 8, port_->CRH, cnf_mode);
output_ = true;
}
@@ -125,4 +132,31 @@ Gpio::speed (Speed s)
output ();
}
+int
+GpioPort::get_port_index () const
+{
+ int port;
+ switch (rcc_)
+ {
+ case Rcc::GPIOA:
+ port = 0;
+ break;
+ case Rcc::GPIOB:
+ port = 1;
+ break;
+ case Rcc::GPIOC:
+ port = 2;
+ break;
+ case Rcc::GPIOD:
+ port = 3;
+ break;
+ case Rcc::GPIOE:
+ port = 4;
+ break;
+ default:
+ assert_unreachable ();
+ }
+ return port;
+}
+
} // namespace ucoo
diff --git a/ucoo/hal/gpio/gpio.stm32f1.hh b/ucoo/hal/gpio/gpio.stm32f1.hh
index 7673998..0cc9bf1 100644
--- a/ucoo/hal/gpio/gpio.stm32f1.hh
+++ b/ucoo/hal/gpio/gpio.stm32f1.hh
@@ -24,38 +24,38 @@
//
// }}}
#include "ucoo/intf/io.hh"
-
-#include <libopencm3/stm32/gpio.h>
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
namespace ucoo {
+class GpioPort;
+
/// General purpose input/output on STM32F1.
class Gpio : public Io
{
public:
enum class InputCnf : uint8_t
{
- ANALOG = GPIO_CNF_INPUT_ANALOG << 2,
- FLOAT = GPIO_CNF_INPUT_FLOAT << 2,
+ ANALOG = GPIO_CNF_Input_Analog << 2,
+ FLOAT = GPIO_CNF_Input_Float << 2,
// Up/Down is selected using output register.
- PULL_UPDOWN = GPIO_CNF_INPUT_PULL_UPDOWN << 2,
+ PULL_UPDOWN = GPIO_CNF_Input_PullUpDown << 2,
};
enum class OutputCnf : uint8_t
{
- PUSHPULL = GPIO_CNF_OUTPUT_PUSHPULL << 2,
- OPENDRAIN = GPIO_CNF_OUTPUT_OPENDRAIN << 2,
- ALTFN_PUSH_PULL = GPIO_CNF_OUTPUT_ALTFN_PUSHPULL << 2,
- ALTFN_OPENDRAIN = GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN << 2,
+ PUSHPULL = GPIO_CNF_Output_PushPull << 2,
+ OPENDRAIN = GPIO_CNF_Output_OpenDrain << 2,
+ AF_PUSH_PULL = GPIO_CNF_Output_AFPushPull << 2,
+ AF_OPENDRAIN = GPIO_CNF_Output_AFOpenDrain << 2,
};
enum class Speed : uint8_t
{
- SPEED_2MHZ = GPIO_MODE_OUTPUT_2_MHZ,
- SPEED_10MHZ = GPIO_MODE_OUTPUT_10_MHZ,
- SPEED_50MHZ = GPIO_MODE_OUTPUT_50_MHZ,
+ SPEED_2MHZ = GPIO_MODE_Output_2MHz,
+ SPEED_10MHZ = GPIO_MODE_Output_10MHz,
+ SPEED_50MHZ = GPIO_MODE_Output_50MHz,
};
public:
- /// Constructor, take the PORT base address, and pin BIT number.
- Gpio (uint32_t port, int bit);
/// See Io::set.
void set ();
/// See Io::reset.
@@ -77,8 +77,12 @@ class Gpio : public Io
/// Set output speed.
void speed (Speed s);
private:
+ /// Constructor, take a port, and pin BIT number.
+ Gpio (GpioPort &port, int bit);
+ friend GpioPort;
+ private:
/// Port register base address.
- const uint32_t port_;
+ GPIO_TypeDef * const port_;
/// IO bitmask.
const uint16_t mask_;
/// Configuration for input.
@@ -91,9 +95,32 @@ class Gpio : public Io
bool output_;
};
+/// General purpose input/output port on STM32F1.
+class GpioPort
+{
+ GPIO_TypeDef * const port_;
+ const Rcc rcc_;
+ friend class Gpio;
+ public:
+ /// Constructor.
+ GpioPort (GPIO_TypeDef *port, Rcc rcc)
+ : port_ (port), rcc_ (rcc) { }
+ /// Enable port.
+ void enable ()
+ { rcc_peripheral_clock_enable (rcc_); }
+ /// Disable port.
+ void disable ()
+ { rcc_peripheral_clock_disable (rcc_); }
+ /// Return a port GPIO.
+ Gpio operator[] (int bit)
+ { return Gpio (*this, bit); }
+ /// Get the index of the port, used with Exti.
+ int get_port_index () const;
+};
+
inline
-Gpio::Gpio (uint32_t port, int bit)
- : port_ (port), mask_ (1u << bit),
+Gpio::Gpio (GpioPort &port, int bit)
+ : port_ (port.port_), mask_ (1u << bit),
input_cnf_ (InputCnf::FLOAT),
output_cnf_ (OutputCnf::PUSHPULL),
speed_ (Speed::SPEED_10MHZ),
@@ -101,6 +128,12 @@ Gpio::Gpio (uint32_t port, int bit)
{
}
+extern GpioPort GPIOA;
+extern GpioPort GPIOB;
+extern GpioPort GPIOC;
+extern GpioPort GPIOD;
+extern GpioPort GPIOE;
+
} // namespace ucoo
#endif // ucoo_hal_gpio_gpio_stm32f1_hh
diff --git a/ucoo/hal/gpio/gpio.stm32f4.cc b/ucoo/hal/gpio/gpio.stm32f4.cc
index 60e3231..1640b03 100644
--- a/ucoo/hal/gpio/gpio.stm32f4.cc
+++ b/ucoo/hal/gpio/gpio.stm32f4.cc
@@ -21,30 +21,43 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include "gpio.stm32f4.hh"
+#include "ucoo/hal/gpio/gpio.stm32f4.hh"
+#include "ucoo/common.hh"
namespace ucoo {
+GpioPort GPIOA (reg::GPIOA, Rcc::GPIOA);
+GpioPort GPIOB (reg::GPIOB, Rcc::GPIOB);
+GpioPort GPIOC (reg::GPIOC, Rcc::GPIOC);
+GpioPort GPIOD (reg::GPIOD, Rcc::GPIOD);
+GpioPort GPIOE (reg::GPIOE, Rcc::GPIOE);
+GpioPort GPIOF (reg::GPIOF, Rcc::GPIOF);
+GpioPort GPIOG (reg::GPIOG, Rcc::GPIOG);
+GpioPort GPIOH (reg::GPIOH, Rcc::GPIOH);
+GpioPort GPIOI (reg::GPIOI, Rcc::GPIOI);
+GpioPort GPIOJ (reg::GPIOJ, Rcc::GPIOJ);
+GpioPort GPIOK (reg::GPIOK, Rcc::GPIOK);
+
void
Gpio::set ()
{
- GPIO_BSRR (port_) = mask_;
+ port_->BSRR = mask_;
}
void
Gpio::reset ()
{
- GPIO_BSRR (port_) = mask_ << 16;
+ port_->BSRR = mask_ << 16;
}
/// Helper to avoid virtual dance.
static inline void
-Gpio_set (uint32_t port, uint16_t mask, bool state)
+Gpio_set (GPIO_TypeDef *port, uint16_t mask, bool state)
{
if (state)
- GPIO_BSRR (port) = mask;
+ port->BSRR = mask;
else
- GPIO_BSRR (port) = mask << 16;
+ port->BSRR = mask << 16;
}
void
@@ -57,13 +70,13 @@ void
Gpio::toggle ()
{
// Avoid read/modify/write ODR, to achieve atomic operation.
- Gpio_set (port_, mask_, !(GPIO_ODR (port_) & mask_));
+ Gpio_set (port_, mask_, !(port_->ODR & mask_));
}
bool
Gpio::get () const
{
- return GPIO_IDR (port_) & mask_;
+ return port_->IDR & mask_;
}
/// Set two bits in a register for the corresponding one-bit mask.
@@ -92,46 +105,95 @@ qmask_set (uint32_t mask, uint32_t reg, uint32_t bits)
void
Gpio::input ()
{
- GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_),
- GPIO_MODE_INPUT);
+ port_->MODER = dmask_set (mask_, port_->MODER, GPIO_MODER_Input);
}
void
Gpio::output ()
{
- GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_),
- GPIO_MODE_OUTPUT);
+ port_->MODER = dmask_set (mask_, port_->MODER, GPIO_MODER_Output);
}
void
Gpio::pull (Pull dir)
{
- GPIO_PUPDR (port_) = dmask_set (mask_, GPIO_PUPDR (port_),
- static_cast<uint32_t> (dir));
+ port_->PUPDR = dmask_set (mask_, port_->PUPDR,
+ static_cast<uint32_t> (dir));
}
void
Gpio::speed (Speed s)
{
- GPIO_OSPEEDR (port_) = dmask_set (mask_, GPIO_OSPEEDR (port_),
- static_cast<uint32_t> (s));
+ port_->OSPEEDR = dmask_set (mask_, port_->OSPEEDR,
+ static_cast<uint32_t> (s));
+}
+
+void
+Gpio::type (Type t)
+{
+ port_->OTYPER = (port_->OTYPER & ~mask_)
+ | (mask_ * static_cast<uint32_t> (t));
}
void
Gpio::af (int num)
{
- GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_), GPIO_MODE_AF);
+ port_->MODER = dmask_set (mask_, port_->MODER, GPIO_MODER_AF);
if (mask_ & 0xff)
- GPIO_AFRL (port_) = qmask_set (mask_, GPIO_AFRL (port_), num);
+ port_->AFR[0] = qmask_set (mask_, port_->AFR[0], num);
else
- GPIO_AFRH (port_) = qmask_set (mask_ >> 8, GPIO_AFRH (port_), num);
+ port_->AFR[1] = qmask_set (mask_ >> 8, port_->AFR[1], num);
}
void
Gpio::analog ()
{
- GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_),
- GPIO_MODE_ANALOG);
+ port_->MODER = dmask_set (mask_, port_->MODER, GPIO_MODER_Analog);
+}
+
+int
+GpioPort::get_port_index () const
+{
+ int port;
+ switch (rcc_)
+ {
+ case Rcc::GPIOA:
+ port = 0;
+ break;
+ case Rcc::GPIOB:
+ port = 1;
+ break;
+ case Rcc::GPIOC:
+ port = 2;
+ break;
+ case Rcc::GPIOD:
+ port = 3;
+ break;
+ case Rcc::GPIOE:
+ port = 4;
+ break;
+ case Rcc::GPIOF:
+ port = 5;
+ break;
+ case Rcc::GPIOG:
+ port = 6;
+ break;
+ case Rcc::GPIOH:
+ port = 7;
+ break;
+ case Rcc::GPIOI:
+ port = 8;
+ break;
+ case Rcc::GPIOJ:
+ port = 9;
+ break;
+ case Rcc::GPIOK:
+ port = 10;
+ break;
+ default:
+ assert_unreachable ();
+ }
+ return port;
}
} // namespace ucoo
diff --git a/ucoo/hal/gpio/gpio.stm32f4.hh b/ucoo/hal/gpio/gpio.stm32f4.hh
index fa73fa2..356a575 100644
--- a/ucoo/hal/gpio/gpio.stm32f4.hh
+++ b/ucoo/hal/gpio/gpio.stm32f4.hh
@@ -24,31 +24,36 @@
//
// }}}
#include "ucoo/intf/io.hh"
-
-#include <libopencm3/stm32/gpio.h>
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
namespace ucoo {
+class GpioPort;
+
/// General purpose input/output on STM32F4.
class Gpio : public Io
{
public:
enum class Pull : uint32_t
{
- NONE = GPIO_PUPD_NONE,
- UP = GPIO_PUPD_PULLUP,
- DOWN = GPIO_PUPD_PULLDOWN,
+ NONE,
+ UP,
+ DOWN,
};
enum class Speed : uint32_t
{
- SPEED_2MHZ = GPIO_OSPEED_2MHZ,
- SPEED_25MHZ = GPIO_OSPEED_25MHZ,
- SPEED_50MHZ = GPIO_OSPEED_50MHZ,
- SPEED_100MHZ = GPIO_OSPEED_100MHZ,
+ SPEED_2MHZ,
+ SPEED_25MHZ,
+ SPEED_50MHZ,
+ SPEED_100MHZ,
+ };
+ enum class Type : uint32_t
+ {
+ PUSH_PULL,
+ OPEN_DRAIN,
};
public:
- /// Constructor, take the PORT base address, and pin BIT number.
- Gpio (uint32_t port, int bit);
/// See Io::set.
void set ();
/// See Io::reset.
@@ -67,23 +72,64 @@ class Gpio : public Io
void pull (Pull dir);
/// Set output speed.
void speed (Speed s);
+ /// Set output type.
+ void type (Type t);
/// Set alternate function.
void af (int num);
/// Set as analog.
void analog ();
private:
+ /// Constructor, take a port, and pin BIT number.
+ Gpio (GpioPort &port, int bit);
+ friend GpioPort;
+ private:
/// Port register base address.
- const uint32_t port_;
+ GPIO_TypeDef * const port_;
/// IO bitmask.
const uint16_t mask_;
};
+/// General purpose input/output port on STM32F4.
+class GpioPort
+{
+ GPIO_TypeDef * const port_;
+ const Rcc rcc_;
+ friend class Gpio;
+ public:
+ /// Constructor.
+ GpioPort (GPIO_TypeDef *port, Rcc rcc)
+ : port_ (port), rcc_ (rcc) { }
+ /// Enable port.
+ void enable ()
+ { rcc_peripheral_clock_enable (rcc_); }
+ /// Disable port.
+ void disable ()
+ { rcc_peripheral_clock_disable (rcc_); }
+ /// Return a port GPIO.
+ Gpio operator[] (int bit)
+ { return Gpio (*this, bit); }
+ /// Get the index of the port, used with Exti.
+ int get_port_index () const;
+};
+
inline
-Gpio::Gpio (uint32_t port, int bit)
- : port_ (port), mask_ (1u << bit)
+Gpio::Gpio (GpioPort &port, int bit)
+ : port_ (port.port_), mask_ (1u << bit)
{
}
+extern GpioPort GPIOA;
+extern GpioPort GPIOB;
+extern GpioPort GPIOC;
+extern GpioPort GPIOD;
+extern GpioPort GPIOE;
+extern GpioPort GPIOF;
+extern GpioPort GPIOG;
+extern GpioPort GPIOH;
+extern GpioPort GPIOI;
+extern GpioPort GPIOJ;
+extern GpioPort GPIOK;
+
} // namespace ucoo
#endif // ucoo_hal_gpio_gpio_stm32f4_hh
diff --git a/ucoo/hal/gpio/test/test_gpio.stm32f1.cc b/ucoo/hal/gpio/test/test_gpio.stm32f1.cc
index 0135a32..d3fe1c2 100644
--- a/ucoo/hal/gpio/test/test_gpio.stm32f1.cc
+++ b/ucoo/hal/gpio/test/test_gpio.stm32f1.cc
@@ -25,8 +25,6 @@
#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/utils/delay.hh"
-#include <libopencm3/stm32/rcc.h>
-
void
test (ucoo::Io &loop_in, ucoo::Io &led1, ucoo::Io &led2, ucoo::Io &led3,
ucoo::Io &led4)
@@ -54,12 +52,12 @@ int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- rcc_periph_clock_enable (RCC_GPIOC);
- ucoo::Gpio loop_in (GPIOC, 5);
- ucoo::Gpio led1 (GPIOC, 6);
- ucoo::Gpio led2 (GPIOC, 7);
- ucoo::Gpio led3 (GPIOC, 8);
- ucoo::Gpio led4 (GPIOC, 9);
+ ucoo::GPIOC.enable ();
+ ucoo::Gpio loop_in (ucoo::GPIOC[5]);
+ ucoo::Gpio led1 (ucoo::GPIOC[6]);
+ ucoo::Gpio led2 (ucoo::GPIOC[7]);
+ ucoo::Gpio led3 (ucoo::GPIOC[8]);
+ ucoo::Gpio led4 (ucoo::GPIOC[9]);
test (loop_in, led1, led2, led3, led4);
return 0;
}
diff --git a/ucoo/hal/gpio/test/test_gpio.stm32f4.cc b/ucoo/hal/gpio/test/test_gpio.stm32f4.cc
index a51017c..6932a05 100644
--- a/ucoo/hal/gpio/test/test_gpio.stm32f4.cc
+++ b/ucoo/hal/gpio/test/test_gpio.stm32f4.cc
@@ -25,8 +25,6 @@
#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/utils/delay.hh"
-#include <libopencm3/stm32/rcc.h>
-
void
test (ucoo::Io &loop_out, ucoo::Io &loop_in, ucoo::Io &led3, ucoo::Io &led4,
ucoo::Io &led5, ucoo::Io &led6)
@@ -56,16 +54,16 @@ int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- rcc_periph_clock_enable (RCC_GPIOB);
- rcc_periph_clock_enable (RCC_GPIOD);
+ ucoo::GPIOB.enable ();
+ ucoo::GPIOD.enable ();
// For this test, shorten B6 & B7 to have loopback.
- gpio_mode_setup (GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO7);
- ucoo::Gpio loop_out (GPIOB, 6);
- ucoo::Gpio loop_in (GPIOB, 7);
- ucoo::Gpio led3 (GPIOD, 13);
- ucoo::Gpio led4 (GPIOD, 12);
- ucoo::Gpio led5 (GPIOD, 14);
- ucoo::Gpio led6 (GPIOD, 15);
+ ucoo::Gpio loop_out (ucoo::GPIOB[6]);
+ ucoo::Gpio loop_in (ucoo::GPIOB[7]);
+ loop_in.pull (ucoo::Gpio::Pull::UP);
+ ucoo::Gpio led3 (ucoo::GPIOD[13]);
+ ucoo::Gpio led4 (ucoo::GPIOD[12]);
+ ucoo::Gpio led5 (ucoo::GPIOD[14]);
+ ucoo::Gpio led6 (ucoo::GPIOD[15]);
test (loop_out, loop_in, led3, led4, led5, led6);
return 0;
}
diff --git a/ucoo/hal/i2c/i2c_hard.stm32.cc b/ucoo/hal/i2c/i2c_hard.stm32.cc
index 14a4486..5e767d6 100644
--- a/ucoo/hal/i2c/i2c_hard.stm32.cc
+++ b/ucoo/hal/i2c/i2c_hard.stm32.cc
@@ -21,11 +21,9 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include "i2c_hard.stm32.hh"
-
-#include <libopencm3/stm32/i2c.h>
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/cm3/nvic.h>
+#include "ucoo/hal/i2c/i2c_hard.stm32.hh"
+#include "ucoo/arch/interrupt.arm.hh"
+#include "ucoo/arch/rcc.stm32.hh"
#include "ucoo/utils/trace.hh"
@@ -38,53 +36,56 @@ static Trace<CONFIG_UCOO_HAL_I2C_TRACE> i2c_trace;
struct i2c_hardware_t
{
/// I2C base address.
- uint32_t base;
- /// Clock enable identifier.
- enum rcc_periph_clken clken;
- /// Corresponding event IRQ (error IRQ is next one).
- int ev_irq;
+ I2C_TypeDef *base;
+ /// RCC identifier, to enable clock.
+ Rcc rcc;
+ /// Corresponding event IRQ.
+ Irq ev_irq;
+ /// Corresponding error IRQ.
+ Irq er_irq;
};
/// Information on I2C hardware array, this is zero indexed, I2C1 is at index
/// 0.
static const i2c_hardware_t i2c_hardware[] =
{
- { I2C1_BASE, RCC_I2C1, NVIC_I2C1_EV_IRQ },
- { I2C2_BASE, RCC_I2C2, NVIC_I2C2_EV_IRQ },
+ { reg::I2C1, Rcc::I2C1, Irq::I2C1_EV, Irq::I2C1_ER },
+ { reg::I2C2, Rcc::I2C2, Irq::I2C2_EV, Irq::I2C2_ER },
#ifdef I2C3_BASE
- { I2C3_BASE, RCC_I2C3, NVIC_I2C3_EV_IRQ },
+ { reg::I2C3, Rcc::I2C3, Irq::I2C3_EV, Irq::I2C3_ER },
#endif
};
static I2cHard *i2c_instances[lengthof (i2c_hardware)];
-} // namespace ucoo
-
-extern "C" {
-
-void i2c1_ev_isr () { ucoo::I2cHard::ev_isr (0); }
+template<>
+void interrupt<Irq::I2C1_EV> () { I2cHard::ev_isr (0); }
-void i2c1_er_isr () { ucoo::I2cHard::er_isr (0); }
+template<>
+void interrupt<Irq::I2C1_ER> () { I2cHard::er_isr (0); }
-void i2c2_ev_isr () { ucoo::I2cHard::ev_isr (1); }
+template<>
+void interrupt<Irq::I2C2_EV> () { I2cHard::ev_isr (1); }
-void i2c2_er_isr () { ucoo::I2cHard::er_isr (1); }
+template<>
+void interrupt<Irq::I2C2_ER> () { I2cHard::er_isr (1); }
-void i2c3_ev_isr () { ucoo::I2cHard::ev_isr (2); }
+#ifdef I2C3_BASE
-void i2c3_er_isr () { ucoo::I2cHard::er_isr (2); }
+template<>
+void interrupt<Irq::I2C3_EV> () { I2cHard::ev_isr (2); }
-}
+template<>
+void interrupt<Irq::I2C3_ER> () { I2cHard::er_isr (2); }
-namespace ucoo {
+#endif
-I2cHard::I2cHard (int n)
- : n_ (n), enabled_ (false), slave_addr_ (0), slave_data_handler_ (0),
- master_ (false), master_status_ (STATUS_ERROR), master_buf_ (0)
+I2cHard::I2cHard (Instance inst)
+ : n_ (static_cast<int> (inst))
{
- assert (n < lengthof (i2c_instances));
- assert (!i2c_instances[n]);
- i2c_instances[n] = this;
+ assert (n_ < lengthof (i2c_instances));
+ assert (!i2c_instances[n_]);
+ i2c_instances[n_] = this;
}
I2cHard::~I2cHard ()
@@ -97,38 +98,38 @@ void
I2cHard::enable (int speed)
{
enabled_ = true;
- uint32_t base = i2c_hardware[n_].base;
+ auto base = i2c_hardware[n_].base;
// Turn on.
- rcc_periph_clock_enable (i2c_hardware[n_].clken);
+ rcc_peripheral_clock_enable (i2c_hardware[n_].rcc);
// Reset.
- I2C_CR1 (base) = I2C_CR1_SWRST;
+ base->CR1 = I2C_CR1_SWRST;
// TODO: make sure the bus is free!!! How!
- I2C_CR1 (base) = 0;
+ base->CR1 = 0;
// Compute clock parameters.
- int pclk = rcc_apb1_frequency;
- int pclk_mhz = pclk / 1000000;
+ int pclk_hz = rcc_apb1_freq_hz;
+ int pclk_mhz = pclk_hz / 1000000;
uint16_t ccr, tris;
if (speed <= 100000)
{
- ccr = pclk / speed / 2;
+ ccr = pclk_hz / speed / 2;
tris = pclk_mhz + 1;
}
else
{
assert (speed <= 400000);
- ccr = I2C_CCR_FS | I2C_CCR_DUTY | (pclk / speed / 25);
+ ccr = I2C_CCR_FS | I2C_CCR_DUTY | (pclk_hz / speed / 25);
tris = pclk_mhz * 3 / 10 + 1;
}
// Set all parameters.
- I2C_CCR (base) = ccr;
- I2C_TRISE (base) = tris;
- I2C_OAR1 (base) = slave_addr_ | (1 << 14);
- I2C_OAR2 (base) = 0;
- I2C_CR2 (base) = I2C_CR2_ITEVTEN | I2C_CR2_ITERREN | pclk_mhz;
+ base->CCR = ccr;
+ base->TRISE = tris;
+ base->OAR1 = slave_addr_ | (1 << 14);
+ base->OAR2 = 0;
+ base->CR2 = I2C_CR2_ITEVTEN | I2C_CR2_ITERREN | pclk_mhz;
// Enable.
- nvic_enable_irq (i2c_hardware[n_].ev_irq);
- nvic_enable_irq (i2c_hardware[n_].ev_irq + 1);
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE;
+ interrupt_enable (i2c_hardware[n_].ev_irq);
+ interrupt_enable (i2c_hardware[n_].er_irq);
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_PE;
}
@@ -138,14 +139,14 @@ I2cHard::disable ()
if (enabled_)
{
enabled_ = false;
- uint32_t base = i2c_hardware[n_].base;
+ auto base = i2c_hardware[n_].base;
// TODO: wait for end of transfer?
// Disable.
- nvic_disable_irq (i2c_hardware[n_].ev_irq);
- nvic_disable_irq (i2c_hardware[n_].ev_irq + 1);
- I2C_CR1 (base) = 0;
+ interrupt_disable (i2c_hardware[n_].ev_irq);
+ interrupt_disable (i2c_hardware[n_].er_irq);
+ base->CR1 = 0;
// Turn off.
- rcc_periph_clock_disable (i2c_hardware[n_].clken);
+ rcc_peripheral_clock_disable (i2c_hardware[n_].rcc);
}
}
@@ -155,9 +156,9 @@ I2cHard::transfer (uint8_t addr, char *buf, int count)
assert (enabled_ && count);
// No need to lock, master is not busy.
assert (master_status_ != STATUS_BUSY);
- uint32_t base = i2c_hardware[n_].base;
+ auto base = i2c_hardware[n_].base;
// Wait until STOP condition terminated, polling is the only way.
- while (I2C_CR1 (base) & I2C_CR1_STOP)
+ while (base->CR1 & I2C_CR1_STOP)
barrier ();
// Now, program next transfer.
master_status_ = STATUS_BUSY;
@@ -165,7 +166,7 @@ I2cHard::transfer (uint8_t addr, char *buf, int count)
master_buf_ = buf;
master_count_ = count;
// TODO: multimaster: about ACK, may have to lock IRQ for multimaster.
- I2C_CR1 (base) |= I2C_CR1_START;
+ base->CR1 |= I2C_CR1_START;
}
void
@@ -204,24 +205,24 @@ I2cHard::register_data (uint8_t addr, DataHandler &data_handler)
slave_data_handler_ = &data_handler;
if (enabled_)
{
- uint32_t base = i2c_hardware[n_].base;
+ auto base = i2c_hardware[n_].base;
// Just in case a transfer is triggered right now.
barrier ();
// According to datasheet, bit 14 should be 1!
- I2C_OAR1 (base) = addr | (1 << 14);
+ base->OAR1 = addr | (1 << 14);
}
}
void
I2cHard::ev_isr (int n)
{
- uint32_t base = i2c_hardware[n].base;
+ auto base = i2c_hardware[n].base;
assert (i2c_instances[n]);
I2cHard &i2c = *i2c_instances[n];
i2c_trace ("<%d> event isr", n);
while (1)
{
- uint16_t sr1 = I2C_SR1 (base);
+ uint16_t sr1 = base->SR1;
i2c_trace ("<%d> sr1=%04x", n, sr1);
// Can not read SR2 because doing so would clear the ADDR bit.
if (i2c.master_)
@@ -233,42 +234,42 @@ I2cHard::ev_isr (int n)
// before reading SR2, and STOP after... Crappy hardware!
if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 1)
{
- I2C_CR1 (base) = I2C_CR1_PE;
- sr2 = I2C_SR2 (base);
- I2C_CR1 (base) = I2C_CR1_STOP | I2C_CR1_PE;
+ base->CR1 = I2C_CR1_PE;
+ sr2 = base->SR2;
+ base->CR1 = I2C_CR1_STOP | I2C_CR1_PE;
// TODO: what to wait now? Unsupported for now.
}
else if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 2)
{
- I2C_CR1 (base) = I2C_CR1_POS | I2C_CR1_PE;
- sr2 = I2C_SR2 (base);
+ base->CR1 = I2C_CR1_POS | I2C_CR1_PE;
+ sr2 = base->SR2;
// Wait for BTF.
}
else
{
- sr2 = I2C_SR2 (base);
- I2C_CR2 (base) |= I2C_CR2_ITBUFEN;
+ sr2 = base->SR2;
+ base->CR2 |= I2C_CR2_ITBUFEN;
}
i2c_trace ("<%d> master sr2=%04x", n, sr2);
}
- else if (sr1 & I2C_SR1_TxE
+ else if (sr1 & I2C_SR1_TXE
&& i2c.buf_index_ < i2c.buf_count_)
{
i2c_trace ("<%d> master tx index=%d", n, i2c.buf_index_);
// Send next byte.
- I2C_DR (base) = i2c.master_buf_[i2c.buf_index_++];
+ base->DR = i2c.master_buf_[i2c.buf_index_++];
// Wait for BTF if last one.
if (i2c.buf_index_ == i2c.buf_count_)
- I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ base->CR2 &= ~I2C_CR2_ITBUFEN;
}
- else if (sr1 & I2C_SR1_RxNE
+ else if (sr1 & I2C_SR1_RXNE
&& i2c.buf_count_ - i2c.buf_index_ > 3)
{
i2c_trace ("<%d> master rx index=%d", n, i2c.buf_index_);
- i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ i2c.master_buf_[i2c.buf_index_++] = base->DR;
if (i2c.buf_count_ - i2c.buf_index_ == 3)
// Wait for BTF.
- I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ base->CR2 &= ~I2C_CR2_ITBUFEN;
}
else if (sr1 & I2C_SR1_BTF)
{
@@ -276,7 +277,7 @@ I2cHard::ev_isr (int n)
if (!(i2c.master_slave_addr_ & 1))
{
// End of transmission.
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
i2c.master_ = false;
i2c.master_status_ = i2c.buf_index_;
if (i2c.finished_handler_)
@@ -285,17 +286,17 @@ I2cHard::ev_isr (int n)
else if (i2c.buf_count_ - i2c.buf_index_ == 3)
{
// Near end of reception.
- I2C_CR1 (base) = I2C_CR1_PE;
- i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ base->CR1 = I2C_CR1_PE;
+ i2c.master_buf_[i2c.buf_index_++] = base->DR;
// Wait for BTF.
}
else
{
// End of reception.
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
if (i2c.buf_count_ - i2c.buf_index_ == 2)
- i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
- i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ i2c.master_buf_[i2c.buf_index_++] = base->DR;
+ i2c.master_buf_[i2c.buf_index_++] = base->DR;
i2c.master_ = false;
i2c.master_status_ = i2c.buf_index_;
if (i2c.finished_handler_)
@@ -309,7 +310,7 @@ I2cHard::ev_isr (int n)
{
if (sr1 & I2C_SR1_ADDR)
{
- uint16_t sr2 = I2C_SR2 (base);
+ uint16_t sr2 = base->SR2;
i2c_trace ("<%d> slave sr2=%04x", n, sr2);
// Initiate new slave transfer.
if (sr2 & I2C_SR2_TRA)
@@ -320,20 +321,20 @@ I2cHard::ev_isr (int n)
else
i2c.buf_count_ = sizeof (i2c.slave_buf_);
i2c.buf_index_ = 0;
- I2C_CR2 (base) |= I2C_CR2_ITBUFEN;
+ base->CR2 |= I2C_CR2_ITBUFEN;
}
- else if (sr1 & I2C_SR1_TxE)
+ else if (sr1 & I2C_SR1_TXE)
{
i2c_trace ("<%d> slave tx index=%d", n, i2c.buf_index_);
uint8_t b = 0xff;
if (i2c.buf_index_ < i2c.buf_count_)
b = i2c.slave_buf_[i2c.buf_index_++];
- I2C_DR (base) = b;
+ base->DR = b;
}
- else if (sr1 & I2C_SR1_RxNE)
+ else if (sr1 & I2C_SR1_RXNE)
{
i2c_trace ("<%d> slave rx index=%d", n, i2c.buf_index_);
- uint8_t b = I2C_DR (base);
+ uint8_t b = base->DR;
if (i2c.buf_index_ < i2c.buf_count_)
i2c.slave_buf_[i2c.buf_index_++] = b;
}
@@ -343,14 +344,14 @@ I2cHard::ev_isr (int n)
i2c.slave_data_handler_->to_recv (i2c.slave_buf_, i2c.buf_index_);
// TODO: multimaster: there is no way to write in this
// register if a START was requested to switch to master mode!
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE;
- I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_PE;
+ base->CR2 &= ~I2C_CR2_ITBUFEN;
}
else if (sr1 & I2C_SR1_SB)
{
i2c_trace ("<%d> master start", n);
// Starting master mode.
- I2C_DR (base) = i2c.master_slave_addr_;
+ base->DR = i2c.master_slave_addr_;
i2c.master_ = true;
i2c.buf_count_ = i2c.master_count_;
i2c.buf_index_ = 0;
@@ -365,30 +366,30 @@ I2cHard::ev_isr (int n)
void
I2cHard::er_isr (int n)
{
- uint32_t base = i2c_hardware[n].base;
+ auto base = i2c_hardware[n].base;
assert (i2c_instances[n]);
I2cHard &i2c = *i2c_instances[n];
- uint16_t sr1 = I2C_SR1 (base);
- I2C_SR1 (base) = 0;
+ uint16_t sr1 = base->SR1;
+ base->SR1 = 0;
i2c_trace ("<%d> error isr sr1=%04x", n, sr1);
if (i2c.master_)
{
if (sr1 & I2C_SR1_ARLO)
{
// Try again.
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_START | I2C_CR1_PE;
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_START | I2C_CR1_PE;
i2c.master_ = false;
}
else if (sr1 & I2C_SR1_AF)
{
- I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ base->CR1 = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
i2c.master_ = false;
i2c.master_status_ = i2c.buf_index_;
if (i2c.finished_handler_)
i2c.finished_handler_->finished (i2c.master_status_);
}
}
- I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ base->CR2 &= ~I2C_CR2_ITBUFEN;
// TODO: handle misplaced STOP errata.
}
diff --git a/ucoo/hal/i2c/i2c_hard.stm32.hh b/ucoo/hal/i2c/i2c_hard.stm32.hh
index 98e4930..81c5deb 100644
--- a/ucoo/hal/i2c/i2c_hard.stm32.hh
+++ b/ucoo/hal/i2c/i2c_hard.stm32.hh
@@ -27,14 +27,26 @@
#include "config/ucoo/hal/i2c.hh"
+#include "ucoo/arch/reg.hh"
+
namespace ucoo {
/// I2C interface, using dedicated hardware.
class I2cHard : public I2c
{
public:
+ /// Available instances.
+ enum class Instance
+ {
+ I2C1,
+ I2C2,
+#ifdef I2C3_BASE
+ I2C3,
+#endif
+ };
+ public:
/// Constructor for the Nth I2C.
- I2cHard (int n);
+ I2cHard (Instance inst);
/// Shutdown.
~I2cHard ();
/// Enable and setup
@@ -62,11 +74,11 @@ class I2cHard : public I2c
/// I2C number.
int n_;
/// Is it enabled?
- bool enabled_;
+ bool enabled_ = false;
/// Slave address.
- uint8_t slave_addr_;
+ uint8_t slave_addr_ = 0;
/// Handler called to source or sink data for slave exchanges.
- DataHandler *slave_data_handler_;
+ DataHandler *slave_data_handler_ = nullptr;
/// Slave buffer.
char slave_buf_[CONFIG_UCOO_HAL_I2C_SLAVE_BUFFER_SIZE];
/// Current buffer count (bytes to send), or buffer size (available room).
@@ -75,11 +87,11 @@ class I2cHard : public I2c
/// byte).
int buf_index_;
/// Master access granted.
- bool master_;
+ bool master_ = false;
/// Current master transfer status.
- int master_status_;
+ int master_status_ = STATUS_ERROR;
/// Current master transfer buffer.
- char *master_buf_;
+ char *master_buf_ = nullptr;
/// Current master transfer size, copied to buf_count_ when active.
int master_count_;
/// Current master transfer slave address, LSB is set for receiver mode.
diff --git a/ucoo/hal/i2c/test/Makefile b/ucoo/hal/i2c/test/Makefile
index ca6915e..2a3bb91 100644
--- a/ucoo/hal/i2c/test/Makefile
+++ b/ucoo/hal/i2c/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = host stm32f4
PROGS = test_i2c
test_i2c_SOURCES = test_i2c.cc
-MODULES = ucoo/hal/i2c ucoo/utils ucoo/base/test ucoo/hal/usb
+MODULES = ucoo/hal/i2c ucoo/utils ucoo/base/test ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/i2c/test/test_i2c.cc b/ucoo/hal/i2c/test/test_i2c.cc
index 8b6ef9b..bef74b4 100644
--- a/ucoo/hal/i2c/test/test_i2c.cc
+++ b/ucoo/hal/i2c/test/test_i2c.cc
@@ -27,7 +27,6 @@
#include "ucoo/base/test/test.hh"
#ifdef TARGET_stm32
-# include <libopencm3/stm32/rcc.h>
# include "ucoo/hal/gpio/gpio.hh"
#endif
@@ -198,20 +197,19 @@ main (int argc, const char **argv)
// Connect I2C1 to I2C3 for the test.
// I2C1: B6: SCL, B9: SDA
// I2C3: A8: SCL, C9: SDA
- rcc_periph_clock_enable (RCC_GPIOA);
- rcc_periph_clock_enable (RCC_GPIOB);
- rcc_periph_clock_enable (RCC_GPIOC);
- gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO9);
- gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
- gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
- gpio_set_output_options (GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO6 | GPIO9);
- gpio_set_output_options (GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO8);
- gpio_set_output_options (GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO9);
- gpio_set_af (GPIOB, GPIO_AF4, GPIO6 | GPIO9);
- gpio_set_af (GPIOA, GPIO_AF4, GPIO8);
- gpio_set_af (GPIOC, GPIO_AF4, GPIO9);
- ucoo::I2cHard i2c1 (0);
- ucoo::I2cHard i2c2 (2);
+ ucoo::GPIOA.enable ();
+ ucoo::GPIOB.enable ();
+ ucoo::GPIOC.enable ();
+ ucoo::GPIOB[6].af (4);
+ ucoo::GPIOB[6].type (ucoo::Gpio::Type::OPEN_DRAIN);
+ ucoo::GPIOB[9].af (4);
+ ucoo::GPIOB[9].type (ucoo::Gpio::Type::OPEN_DRAIN);
+ ucoo::GPIOA[8].af (4);
+ ucoo::GPIOA[8].type (ucoo::Gpio::Type::OPEN_DRAIN);
+ ucoo::GPIOC[9].af (4);
+ ucoo::GPIOC[9].type (ucoo::Gpio::Type::OPEN_DRAIN);
+ ucoo::I2cHard i2c1 (ucoo::I2cHard::Instance::I2C1);
+ ucoo::I2cHard i2c2 (ucoo::I2cHard::Instance::I2C2);
i2c1.enable ();
i2c2.enable ();
#endif
diff --git a/ucoo/hal/sdram/sdram.stm32f4.cc b/ucoo/hal/sdram/sdram.stm32f4.cc
index 07baf54..4c224c0 100644
--- a/ucoo/hal/sdram/sdram.stm32f4.cc
+++ b/ucoo/hal/sdram/sdram.stm32f4.cc
@@ -22,12 +22,9 @@
//
// }}}
#include "ucoo/hal/sdram/sdram.hh"
+#include "ucoo/arch/rcc.stm32.hh"
#include "ucoo/utils/delay.hh"
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
-#include <libopencm3/stm32/fsmc.h>
-
namespace ucoo {
Sdram::Sdram (std::initializer_list<Io> ios, const Param &params)
@@ -41,20 +38,25 @@ Sdram::enable ()
// Setup GPIO, turn controller on.
for (auto io : ios_)
{
- gpio_mode_setup (io.gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, io.pins);
- gpio_set_output_options (io.gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
- io.pins);
- gpio_set_af (io.gpio, GPIO_AF12, io.pins);
+ for (int i = 0; i < 16; i++)
+ {
+ if (io.pins & (1 << i))
+ {
+ Gpio gpio (io.port[i]);
+ gpio.af (12);
+ gpio.speed (Gpio::Speed::SPEED_50MHZ);
+ }
+ }
}
- rcc_periph_clock_enable (RCC_FSMC);
+ rcc_peripheral_clock_enable (Rcc::FMC);
// Prepare SDRAM clock, can only be HCLK/2 or HCLK/3. Can go slower than
// requested, but not faster.
- int clock_div = (rcc_ahb_frequency + params_.clock_hz - 1)
+ int clock_div = (rcc_ahb_freq_hz + params_.clock_hz - 1)
/ params_.clock_hz;
if (clock_div < 2)
clock_div = 2;
assert (clock_div <= 3);
- int clock_hz = rcc_ahb_frequency / clock_div;
+ int clock_hz = rcc_ahb_freq_hz / clock_div;
int clock_ns = 1000000000 / clock_hz;
// Prepare and set parameters.
assert (params_.bank == 1 || params_.bank == 2);
@@ -64,50 +66,50 @@ Sdram::enable ()
assert (params_.row_bits >= 11 && params_.row_bits <= 13);
assert (params_.col_bits >= 8 && params_.col_bits <= 11);
uint32_t sdcr =
- FMC_SDCR_RPIPE_NONE
+ FMC_SDCR_RPIPE_None
| FMC_SDCR_RBURST
- | (clock_div == 2 ? FMC_SDCR_SDCLK_2HCLK : FMC_SDCR_SDCLK_3HCLK)
- | (params_.cas << FMC_SDCR_CAS_SHIFT)
- | (params_.banks == 2 ? FMC_SDCR_NB2 : FMC_SDCR_NB4)
- | (params_.bits == 8 ? FMC_SDCR_MWID_8b
- : (params_.bits == 16 ? FMC_SDCR_MWID_16b : FMC_SDCR_MWID_32b))
- | ((params_.row_bits - 11) << FMC_SDCR_NR_SHIFT)
- | ((params_.col_bits - 8) << FMC_SDCR_NC_SHIFT);
+ | (clock_div == 2 ? FMC_SDCR_SDCLK_2Hclk : FMC_SDCR_SDCLK_3Hclk)
+ | (params_.cas << FMC_SDCR_CAS_Pos)
+ | (params_.banks == 2 ? 0 : FMC_SDCR_NB)
+ | (params_.bits == 8 ? FMC_SDCR_MWID_8B
+ : (params_.bits == 16 ? FMC_SDCR_MWID_16B : FMC_SDCR_MWID_32B))
+ | ((params_.row_bits - 11) << FMC_SDCR_NR_Pos)
+ | ((params_.col_bits - 8) << FMC_SDCR_NC_Pos);
uint32_t sdtr =
- ((params_.trcd - 1) << FMC_SDTR_TRCD_SHIFT)
- | ((params_.trp - 1) << FMC_SDTR_TRP_SHIFT)
- | ((params_.twr - 1) << FMC_SDTR_TWR_SHIFT)
- | ((params_.trc - 1) << FMC_SDTR_TRC_SHIFT)
- | ((params_.tras - 1) << FMC_SDTR_TRAS_SHIFT)
- | ((params_.txsr - 1) << FMC_SDTR_TXSR_SHIFT)
- | ((params_.tmrd - 1) << FMC_SDTR_TMRD_SHIFT);
+ ((params_.trcd - 1) << FMC_SDTR_TRCD_Pos)
+ | ((params_.trp - 1) << FMC_SDTR_TRP_Pos)
+ | ((params_.twr - 1) << FMC_SDTR_TWR_Pos)
+ | ((params_.trc - 1) << FMC_SDTR_TRC_Pos)
+ | ((params_.tras - 1) << FMC_SDTR_TRAS_Pos)
+ | ((params_.txsr - 1) << FMC_SDTR_TXSR_Pos)
+ | ((params_.tmrd - 1) << FMC_SDTR_TMRD_Pos);
if (params_.bank == 1)
{
- FMC_SDCR1 = sdcr;
- FMC_SDTR1 = sdtr;
+ reg::FMC_Bank5_6->SDCR[0] = sdcr;
+ reg::FMC_Bank5_6->SDTR[0] = sdtr;
}
else
{
- FMC_SDCR1 = sdcr & FMC_SDCR_DNC_MASK;
- FMC_SDCR2 = sdcr;
- FMC_SDTR1 = sdtr & FMC_SDTR_DNC_MASK;
- FMC_SDTR2 = sdtr;
+ reg::FMC_Bank5_6->SDCR[0] = sdcr & FMC_SDCR_DNC_Mask;
+ reg::FMC_Bank5_6->SDCR[1] = sdcr;
+ reg::FMC_Bank5_6->SDTR[0] = sdtr & FMC_SDTR_DNC_Mask;
+ reg::FMC_Bank5_6->SDTR[1] = sdtr;
}
// Initialise SDRAM.
uint32_t bank = params_.bank == 1 ? FMC_SDCMR_CTB1 : FMC_SDCMR_CTB2;
- while (FMC_SDSR & FMC_SDSR_BUSY)
+ while (reg::FMC_Bank5_6->SDSR & FMC_SDSR_BUSY)
;
- FMC_SDCMR = bank | FMC_SDCMR_MODE_CLOCK_CONFIG_ENA;
+ reg::FMC_Bank5_6->SDCMR = bank | FMC_SDCMR_MODE_ClockConfigEna;
delay_us (params_.init_clock_delay_us);
- while (FMC_SDSR & FMC_SDSR_BUSY)
+ while (reg::FMC_Bank5_6->SDSR & FMC_SDSR_BUSY)
;
- FMC_SDCMR = bank | FMC_SDCMR_MODE_PALL;
- while (FMC_SDSR & FMC_SDSR_BUSY)
+ reg::FMC_Bank5_6->SDCMR = bank | FMC_SDCMR_MODE_Pall;
+ while (reg::FMC_Bank5_6->SDSR & FMC_SDSR_BUSY)
;
- FMC_SDCMR = bank | ((params_.init_auto_refresh - 1)
- << FMC_SDCMR_NRFS_SHIFT)
- | FMC_SDCMR_MODE_AUTO_REFRESH;
- while (FMC_SDSR & FMC_SDSR_BUSY)
+ reg::FMC_Bank5_6->SDCMR = bank
+ | ((params_.init_auto_refresh - 1) << FMC_SDCMR_NRFS_Pos)
+ | FMC_SDCMR_MODE_AutoRefresh;
+ while (reg::FMC_Bank5_6->SDSR & FMC_SDSR_BUSY)
;
uint32_t sdram_mode =
SDRAM_MODE_BURST_LENGTH_1
@@ -116,19 +118,19 @@ Sdram::enable ()
: SDRAM_MODE_CAS_LATENCY_3)
| SDRAM_MODE_OPERATING_MODE_STANDARD
| SDRAM_MODE_WRITEBURST_MODE_SINGLE;
- FMC_SDCMR = bank | (sdram_mode << FMC_SDCMR_MRD_SHIFT)
- | FMC_SDCMR_MODE_LOAD_MODE_REGISTER;
+ reg::FMC_Bank5_6->SDCMR = bank | (sdram_mode << FMC_SDCMR_MRD_Pos)
+ | FMC_SDCMR_MODE_LoadModeRegister;
// Set refresh rate.
int refresh_interval_ns = params_.tref_ms * 1000000
/ (1 << params_.row_bits);
- FMC_SDRTR = refresh_interval_ns / clock_ns - 20;
+ reg::FMC_Bank5_6->SDRTR = refresh_interval_ns / clock_ns - 20;
}
void *
Sdram::addr () const
{
- return params_.bank == 1 ? reinterpret_cast<void *> (FMC_BANK7_BASE)
- : reinterpret_cast<void *> (FMC_BANK8_BASE);
+ return params_.bank == 1 ? reinterpret_cast<void *> (FMC_BANK5_BASE)
+ : reinterpret_cast<void *> (FMC_BANK6_BASE);
}
int
diff --git a/ucoo/hal/sdram/sdram.stm32f4.hh b/ucoo/hal/sdram/sdram.stm32f4.hh
index fbeefe0..aac82e0 100644
--- a/ucoo/hal/sdram/sdram.stm32f4.hh
+++ b/ucoo/hal/sdram/sdram.stm32f4.hh
@@ -23,6 +23,7 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
+#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/common.hh"
#include <initializer_list>
@@ -34,7 +35,7 @@ class Sdram
{
public:
struct Io {
- uint32_t gpio;
+ GpioPort &port;
uint16_t pins;
};
struct Param {
diff --git a/ucoo/hal/sdram/test/test_sdram.stm32f4.cc b/ucoo/hal/sdram/test/test_sdram.stm32f4.cc
index 841d486..17ed1b4 100644
--- a/ucoo/hal/sdram/test/test_sdram.stm32f4.cc
+++ b/ucoo/hal/sdram/test/test_sdram.stm32f4.cc
@@ -25,9 +25,7 @@
#include "ucoo/arch/arch.hh"
#include "ucoo/base/test/test.hh"
-
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
+#include "ucoo/utils/bits.hh"
#include <cstdio>
#include <cinttypes>
@@ -65,24 +63,25 @@ main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
ucoo::test_stream_setup ();
- rcc_periph_clock_enable (RCC_GPIOD);
- rcc_periph_clock_enable (RCC_GPIOE);
- rcc_periph_clock_enable (RCC_GPIOF);
- rcc_periph_clock_enable (RCC_GPIOG);
- rcc_periph_clock_enable (RCC_GPIOH);
- rcc_periph_clock_enable (RCC_GPIOI);
+ ucoo::GPIOD.enable ();
+ ucoo::GPIOE.enable ();
+ ucoo::GPIOF.enable ();
+ ucoo::GPIOG.enable ();
+ ucoo::GPIOH.enable ();
+ ucoo::GPIOI.enable ();
std::initializer_list<ucoo::Sdram::Io> sdram_ios {
- { GPIOD, GPIO0 | GPIO1 | GPIO8 | GPIO9 | GPIO10 | GPIO14 | GPIO15 },
- { GPIOE, GPIO0 | GPIO1 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11
- | GPIO12 | GPIO13 | GPIO14 | GPIO15 },
- { GPIOF, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO11
- | GPIO12 | GPIO13 | GPIO14 | GPIO15 },
- { GPIOG, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO8
- | GPIO15 },
- { GPIOH, GPIO2 | GPIO3 | GPIO5 | GPIO8 | GPIO9 | GPIO10 | GPIO11
- | GPIO12 | GPIO13 | GPIO14 | GPIO15 },
- { GPIOI, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO6 | GPIO7
- | GPIO9 | GPIO10 },
+ { ucoo::GPIOD, ucoo::bits<uint16_t> (
+ 0, 1, 8, 9, 10, 14, 15) },
+ { ucoo::GPIOE, ucoo::bits<uint16_t> (
+ 0, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15) },
+ { ucoo::GPIOF, ucoo::bits<uint16_t> (
+ 0, 1, 2, 3, 4, 5, 11, 12, 13, 14, 15) },
+ { ucoo::GPIOG, ucoo::bits<uint16_t> (
+ 0, 1, 2, 3, 4, 5, 8, 15) },
+ { ucoo::GPIOH, ucoo::bits<uint16_t> (
+ 2, 3, 5, 8, 9, 10, 11, 12, 13, 14, 15) },
+ { ucoo::GPIOI, ucoo::bits<uint16_t> (
+ 0, 1, 2, 3, 4, 5, 6, 7, 9, 10) },
};
ucoo::Sdram::Param sdram_param {
.bank = 1,
diff --git a/ucoo/hal/self_programming/self_programming.stm32f1.cc b/ucoo/hal/self_programming/self_programming.stm32f1.cc
index 8cbbb24..8cebd6b 100644
--- a/ucoo/hal/self_programming/self_programming.stm32f1.cc
+++ b/ucoo/hal/self_programming/self_programming.stm32f1.cc
@@ -22,17 +22,14 @@
//
// }}}
#include "ucoo/hal/self_programming/self_programming.hh"
-
-#include <libopencm3/stm32/flash.h>
-#include <libopencm3/stm32/desig.h>
-#include <libopencm3/stm32/dbgmcu.h>
+#include "ucoo/arch/reg.hh"
namespace ucoo {
int
self_programming_flash_size ()
{
- return DESIG_FLASH_SIZE * 1024;
+ return reg::DESIG->FLASH_SIZE * 1024;
}
int
@@ -40,7 +37,7 @@ self_programming_erase_size (uint32_t addr)
{
assert (static_cast<int> (addr - FLASH_BASE)
<= self_programming_flash_size ());
- uint32_t idcode = DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK;
+ uint32_t idcode = reg::DBGMCU->IDCODE & DBGMCU_IDCODE_DEV_ID_Msk;
int page_size = idcode >= 0x414 ? 2048 : 1024;
assert ((addr & (page_size - 1)) == 0);
return page_size;
@@ -53,14 +50,23 @@ self_programming_erase (uint32_t addr, int count)
<= self_programming_flash_size ());
int page_size = self_programming_erase_size (addr);
assert ((count & (page_size - 1)) == 0);
+ reg::FLASH->CR = FLASH_CR_LOCK;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY1;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY2;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
while (count)
{
- flash_unlock ();
- flash_erase_page (addr);
- flash_lock ();
+ reg::FLASH->CR = FLASH_CR_PER;
+ reg::FLASH->AR = addr;
+ reg::FLASH->CR |= FLASH_CR_STRT;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
+ reg::FLASH->CR = 0;
addr += page_size;
count -= page_size;
}
+ reg::FLASH->CR = FLASH_CR_LOCK;
assert (count == 0);
}
@@ -72,11 +78,21 @@ self_programming_write (uint32_t addr, const char *buf, int count)
assert (count % 2 == 0);
assert (static_cast<int> (addr - FLASH_BASE + count)
<= self_programming_flash_size ());
- flash_unlock ();
+ reg::FLASH->CR = FLASH_CR_LOCK;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY1;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY2;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
for (int i = 0; i < count; i += 2)
- flash_program_half_word (
- addr + i, *reinterpret_cast<const uint16_t *> (buf + i));
- flash_lock ();
+ {
+ reg::FLASH->CR = FLASH_CR_PG;
+ *reinterpret_cast<uint16_t *> (addr + i)
+ = *reinterpret_cast<const uint16_t *> (buf + i);
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
+ reg::FLASH->CR = 0;
+ }
+ reg::FLASH->CR = FLASH_CR_LOCK;
}
} // namespace ucoo
diff --git a/ucoo/hal/self_programming/self_programming.stm32f4.cc b/ucoo/hal/self_programming/self_programming.stm32f4.cc
index 3956b1e..4d8418f 100644
--- a/ucoo/hal/self_programming/self_programming.stm32f4.cc
+++ b/ucoo/hal/self_programming/self_programming.stm32f4.cc
@@ -22,9 +22,7 @@
//
// }}}
#include "ucoo/hal/self_programming/self_programming.hh"
-
-#include <libopencm3/stm32/flash.h>
-#include <libopencm3/stm32/desig.h>
+#include "ucoo/arch/reg.hh"
namespace ucoo {
@@ -49,7 +47,7 @@ static const uint32_t sector_addr[] = {
int
self_programming_flash_size ()
{
- return DESIG_FLASH_SIZE * 1024;
+ return reg::DESIG->FLASH_SIZE * 1024;
}
int
@@ -69,19 +67,28 @@ self_programming_erase (uint32_t addr, int count)
assert (static_cast<int> (addr - sector_addr[0] + count)
<= self_programming_flash_size ());
int sector;
+ reg::FLASH->CR = FLASH_CR_LOCK;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY1;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY2;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
+ reg::FLASH->CR = FLASH_CR_PSIZE_x32;
for (sector = 0; count && sector < lengthof (sector_addr); sector++)
{
if (addr == sector_addr[sector])
{
int snb = sector >= 12 ? sector + 16 - 12 : sector;
- flash_unlock ();
- flash_erase_sector (snb, FLASH_CR_PROGRAM_X32);
- flash_lock ();
+ reg::FLASH->CR = FLASH_CR_PSIZE_x32 | (snb * FLASH_CR_SNB_0)
+ | FLASH_CR_SER;
+ reg::FLASH->CR |= FLASH_CR_STRT;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
int sector_size = sector_addr[sector + 1] - addr;
addr += sector_size;
count -= sector_size;
}
}
+ reg::FLASH->CR = FLASH_CR_LOCK;
assert (count == 0);
}
@@ -93,11 +100,20 @@ self_programming_write (uint32_t addr, const char *buf, int count)
assert (count % 4 == 0);
assert (static_cast<int> (addr - sector_addr[0] + count)
<= self_programming_flash_size ());
- flash_unlock ();
+ reg::FLASH->CR = FLASH_CR_LOCK;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY1;
+ reg::FLASH->KEYR = FLASH_KEYR_KEY2;
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
+ reg::FLASH->CR = FLASH_CR_PSIZE_x32 | FLASH_CR_PG;
for (int i = 0; i < count; i += 4)
- flash_program_word (addr + i,
- *reinterpret_cast<const uint32_t *> (buf + i));
- flash_lock ();
+ {
+ *reinterpret_cast<volatile uint32_t *> (addr + i) =
+ *reinterpret_cast<const uint32_t *> (buf + i);
+ while (reg::FLASH->SR & FLASH_SR_BSY)
+ ;
+ }
+ reg::FLASH->CR = FLASH_CR_LOCK;
}
} // namespace ucoo
diff --git a/ucoo/hal/spi/spi_hard.stm32.cc b/ucoo/hal/spi/spi_hard.stm32.cc
index 264647d..898a565 100644
--- a/ucoo/hal/spi/spi_hard.stm32.cc
+++ b/ucoo/hal/spi/spi_hard.stm32.cc
@@ -22,10 +22,7 @@
//
// }}}
#include "ucoo/hal/spi/spi_hard.stm32.hh"
-
-#include <libopencm3/stm32/spi.h>
-#include <libopencm3/stm32/rcc.h>
-
+#include "ucoo/arch/rcc.stm32.hh"
#include "ucoo/common.hh"
namespace ucoo {
@@ -34,34 +31,33 @@ namespace ucoo {
struct spi_hardware_t
{
/// SPI base address.
- uint32_t base;
- /// APB number.
- int apb;
- /// Clock enable identifier.
- enum rcc_periph_clken clken;
+ SPI_TypeDef *base;
+ /// APB bus.
+ Bus bus;
+ /// RCC identifier.
+ Rcc rcc;
};
/// Information on SPI hardware array, this is zero indexed.
static const spi_hardware_t spi_hardware[] =
{
- { SPI1, 2, RCC_SPI1 },
- { SPI2, 1, RCC_SPI2 },
- { SPI3, 1, RCC_SPI3 },
+ { reg::SPI1, Bus::APB2, Rcc::SPI1 },
+ { reg::SPI2, Bus::APB1, Rcc::SPI2 },
+ { reg::SPI3, Bus::APB1, Rcc::SPI3 },
#ifdef SPI4_BASE
- { SPI4, 2, RCC_SPI4 },
+ { reg::SPI4, Bus::APB2, Rcc::SPI4 },
#endif
#ifdef SPI5_BASE
- { SPI5, 2, RCC_SPI5 },
+ { reg::SPI5, Bus::APB2, Rcc::SPI5 },
#endif
#ifdef SPI6_BASE
- { SPI6, 2, RCC_SPI6 },
+ { reg::SPI6, Bus::APB2, Rcc::SPI6 },
#endif
};
-SpiHardMaster::SpiHardMaster (int n)
- : n_ (n), enabled_ (false)
+SpiHardMaster::SpiHardMaster (SpiHardMaster::Instance inst)
+ : n_ (static_cast<int> (inst)), enabled_ (false)
{
- assert (n < lengthof (spi_hardware));
}
SpiHardMaster::~SpiHardMaster ()
@@ -73,24 +69,24 @@ void
SpiHardMaster::enable (int speed_hz, SpiMode mode)
{
enabled_ = true;
- uint32_t base = spi_hardware[n_].base;
+ auto base = spi_hardware[n_].base;
// Turn on.
- rcc_periph_clock_enable (spi_hardware[n_].clken);
+ rcc_peripheral_clock_enable (spi_hardware[n_].rcc);
// Compute speed, rounded down.
- int apb_freq = spi_hardware[n_].apb == 1 ? rcc_apb1_frequency
- : rcc_apb2_frequency;
- int freq = apb_freq / 2;
+ int apb_freq_hz = spi_hardware[n_].bus == Bus::APB1 ? rcc_apb1_freq_hz
+ : rcc_apb2_freq_hz;
+ int freq_hz = apb_freq_hz / 2;
int br = 0;
- while (freq > speed_hz)
+ while (freq_hz > speed_hz)
{
- freq = freq / 2;
+ freq_hz = freq_hz / 2;
br++;
- assert (br <= SPI_CR1_BR_FPCLK_DIV_256);
+ assert (br <= 7);
}
// Set parameters and enable.
- SPI_CR2 (base) = 0;
- SPI_CR1 (base) = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | (br << 3)
- | SPI_CR1_MSTR | mode;
+ base->CR2 = 0;
+ base->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE
+ | (br << SPI_CR1_BR_Pos) | SPI_CR1_MSTR | mode;
}
void
@@ -99,11 +95,11 @@ SpiHardMaster::disable ()
if (enabled_)
{
enabled_ = false;
- uint32_t base = spi_hardware[n_].base;
+ auto base = spi_hardware[n_].base;
// Stop SPI.
- SPI_CR1 (base) = 0;
+ base->CR1 = 0;
// Turn off.
- rcc_periph_clock_disable (spi_hardware[n_].clken);
+ rcc_peripheral_clock_disable (spi_hardware[n_].rcc);
}
}
@@ -111,13 +107,13 @@ void
SpiHardMaster::send_and_recv (const char *tx_buf, char *rx_buf, int count)
{
assert (enabled_);
- uint32_t base = spi_hardware[n_].base;
+ auto base = spi_hardware[n_].base;
while (count--)
{
- SPI_DR (base) = *tx_buf++;
- while (!(SPI_SR (base) & SPI_SR_RXNE))
+ base->DR = *tx_buf++;
+ while (!(base->SR & SPI_SR_RXNE))
;
- *rx_buf++ = SPI_DR (base);
+ *rx_buf++ = base->DR;
}
}
@@ -125,31 +121,31 @@ void
SpiHardMaster::send (const char *tx_buf, int count)
{
assert (enabled_);
- uint32_t base = spi_hardware[n_].base;
+ auto base = spi_hardware[n_].base;
while (count--)
{
- SPI_DR (base) = *tx_buf++;
- while (!(SPI_SR (base) & SPI_SR_TXE))
+ base->DR = *tx_buf++;
+ while (!(base->SR & SPI_SR_TXE))
;
}
// Wait for end of transfer.
- while (SPI_SR (base) & SPI_SR_BSY)
+ while (base->SR & SPI_SR_BSY)
;
// Clear RXNE.
- (void) SPI_DR (base);
+ (void) base->DR;
}
void
SpiHardMaster::recv (char *rx_buf, int count)
{
assert (enabled_);
- uint32_t base = spi_hardware[n_].base;
+ auto base = spi_hardware[n_].base;
while (count--)
{
- SPI_DR (base) = 0;
- while (!(SPI_SR (base) & SPI_SR_RXNE))
+ base->DR = 0;
+ while (!(base->SR & SPI_SR_RXNE))
;
- *rx_buf++ = SPI_DR (base);
+ *rx_buf++ = base->DR;
}
}
diff --git a/ucoo/hal/spi/spi_hard.stm32.hh b/ucoo/hal/spi/spi_hard.stm32.hh
index 7576be5..13d24d3 100644
--- a/ucoo/hal/spi/spi_hard.stm32.hh
+++ b/ucoo/hal/spi/spi_hard.stm32.hh
@@ -24,6 +24,7 @@
//
// }}}
#include "ucoo/intf/spi_master.hh"
+#include "ucoo/arch/reg.hh"
namespace ucoo {
@@ -31,8 +32,24 @@ namespace ucoo {
class SpiHardMaster : public SpiMaster
{
public:
- /// Constructor for the Nth SPI.
- SpiHardMaster (int n);
+ enum class Instance
+ {
+ SPI1,
+ SPI2,
+ SPI3,
+#ifdef SPI4_BASE
+ SPI4,
+#endif
+#ifdef SPI5_BASE
+ SPI5,
+#endif
+#ifdef SPI6_BASE
+ SPI6,
+#endif
+ };
+ public:
+ /// Constructor for an SPI instance.
+ SpiHardMaster (Instance inst);
/// Destructor, disable.
~SpiHardMaster ();
/// See SpiMaster::enable.
diff --git a/ucoo/hal/spi/test/test_spi.cc b/ucoo/hal/spi/test/test_spi.cc
index de155b7..73225ce 100644
--- a/ucoo/hal/spi/test/test_spi.cc
+++ b/ucoo/hal/spi/test/test_spi.cc
@@ -29,8 +29,6 @@
#include "ucoo/arch/arch.hh"
#include "ucoo/base/test/test.hh"
-#include <libopencm3/stm32/rcc.h>
-
#include <algorithm>
#include <cstdio>
@@ -41,15 +39,16 @@ main (int argc, const char **argv)
ucoo::Stream &ts = ucoo::test_stream ();
// Use connection to LIS302DL device on discovery board revision MB997B.
// Revision MB997C uses a different device.
- rcc_periph_clock_enable (RCC_GPIOA);
- rcc_periph_clock_enable (RCC_GPIOE);
- ucoo::Gpio ss (GPIOE, 3);
+ ucoo::GPIOA.enable ();
+ ucoo::GPIOE.enable ();
+ ucoo::Gpio ss = ucoo::GPIOE[3];
ss.set ();
ss.output ();
- ucoo::Gpio sck (GPIOA, 5), mosi (GPIOA, 7), miso (GPIOA, 6);
+ ucoo::Gpio sck = ucoo::GPIOA[5], mosi = ucoo::GPIOA[7],
+ miso = ucoo::GPIOA[6];
ucoo::SpiSoftMaster spis (sck, mosi, miso);
spis.enable (1000000, ucoo::SPI_MODE_3);
- ucoo::SpiHardMaster spih (0);
+ ucoo::SpiHardMaster spih (ucoo::SpiHardMaster::Instance::SPI1);
ucoo::SpiMaster *spi = &spis;
// Loop with simple IU.
char buf[64];
@@ -115,9 +114,9 @@ main (int argc, const char **argv)
case 'h':
spi->disable ();
spi = &spih;
- gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO5 | GPIO6 | GPIO7);
- gpio_set_af (GPIOA, GPIO_AF5, GPIO5 | GPIO6 | GPIO7);
+ miso.af (5);
+ mosi.af (5);
+ sck.af (5);
spi->enable (1000000, ucoo::SPI_MODE_3);
break;
case 's':
diff --git a/ucoo/hal/timer/test/Makefile b/ucoo/hal/timer/test/Makefile
index 284ad18..c0d1b49 100644
--- a/ucoo/hal/timer/test/Makefile
+++ b/ucoo/hal/timer/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = stm32f4
PROGS = test_timer
test_timer_SOURCES = test_timer.cc
-MODULES = ucoo/base/test ucoo/hal/timer ucoo/hal/usb ucoo/utils
+MODULES = ucoo/base/test ucoo/hal/timer ucoo/hal/usb ucoo/hal/gpio ucoo/utils
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/timer/test/test_timer.cc b/ucoo/hal/timer/test/test_timer.cc
index e02e92f..f3b47e8 100644
--- a/ucoo/hal/timer/test/test_timer.cc
+++ b/ucoo/hal/timer/test/test_timer.cc
@@ -24,9 +24,7 @@
#include "ucoo/base/test/test.hh"
#include "ucoo/arch/arch.hh"
#include "ucoo/hal/timer/timer.hh"
-
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
+#include "ucoo/hal/gpio/gpio.hh"
#include <cstdio>
@@ -39,17 +37,19 @@ main (int argc, const char **argv)
// PD15 (T4_CH4).
ucoo::arch_init (argc, argv);
ucoo::test_stream_setup ();
- using Timer = ucoo::TimerHard<TIM4>;
- using TimerRef = ucoo::TimerHard<TIM2>;
+ using Timer = ucoo::TimerHard<ucoo::TimerInstance::TIM4>;
+ using TimerRef = ucoo::TimerHard<ucoo::TimerInstance::TIM2>;
Timer timer;
TimerRef timerref;
// AF setup.
- rcc_periph_clock_enable (RCC_GPIOA);
- rcc_periph_clock_enable (RCC_GPIOD);
- gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLDOWN, GPIO1);
- gpio_set_af (GPIOA, GPIO_AF1, GPIO1);
- gpio_mode_setup (GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLDOWN, GPIO13 | GPIO15);
- gpio_set_af (GPIOD, GPIO_AF2, GPIO13 | GPIO15);
+ ucoo::GPIOA.enable ();
+ ucoo::GPIOD.enable ();
+ ucoo::GPIOA[1].af (1);
+ ucoo::GPIOA[1].pull (ucoo::Gpio::Pull::DOWN);
+ ucoo::GPIOD[13].af (2);
+ ucoo::GPIOD[13].pull (ucoo::Gpio::Pull::DOWN);
+ ucoo::GPIOD[15].af (2);
+ ucoo::GPIOD[15].pull (ucoo::Gpio::Pull::DOWN);
// Timers setup.
timerref.enable<TimerRef::OptionReloadValue<5000>,
TimerRef::OptionOutputCompare<2> > (2000);
diff --git a/ucoo/hal/timer/timer.stm32.hh b/ucoo/hal/timer/timer.stm32.hh
index 85941e4..6b2f2dd 100644
--- a/ucoo/hal/timer/timer.stm32.hh
+++ b/ucoo/hal/timer/timer.stm32.hh
@@ -27,8 +27,23 @@
namespace ucoo {
+/// Available instances.
+enum class TimerInstance
+{
+ TIM1,
+ TIM2,
+ TIM3,
+ TIM4,
+ TIM5,
+ TIM10,
+ TIM11,
+};
+
+template<TimerInstance inst>
+struct TimerHardware { };
+
/// STM32 timer very basic support.
-template<uint32_t Base>
+template<TimerInstance inst>
class TimerHard
{
public:
@@ -39,7 +54,7 @@ class TimerHard
~TimerHard ();
/// Enable timer.
template <typename... Options>
- void enable (int freq, bool start = true);
+ void enable (int freq_hz, bool start = true);
/// Disable timer.
void disable ();
/// Manually start timer.
@@ -57,7 +72,7 @@ class TimerHard
/// Wait until a new input capture value is available.
void wait_input_capture (int ch) const;
/// Get timer frequency.
- int get_freq () const { return freq_; }
+ int get_freq_hz () const { return freq_hz_; }
/// Enable interrupts on update event.
void enable_interrupt ();
/// Disable interrupts on update event.
@@ -95,11 +110,11 @@ class TimerHard
{
public:
/// Disable updates.
- UpdateDisabled (TimerHard<Base> &timer);
+ UpdateDisabled (TimerHard<inst> &timer);
/// Enable updates.
~UpdateDisabled ();
private:
- TimerHard<Base> &timer_;
+ TimerHard<inst> &timer_;
};
friend class UpdateDisabled;
/// Base class for options.
@@ -129,7 +144,9 @@ class TimerHard
struct CombinedOptions;
private:
/// When enabled, programmed frequency.
- int freq_ = 0;
+ int freq_hz_ = 0;
+ /// Hardware characteristics.
+ using Hard = TimerHardware<inst>;
};
} // namespace ucoo
diff --git a/ucoo/hal/timer/timer.stm32.tcc b/ucoo/hal/timer/timer.stm32.tcc
index 9adc8d2..3a0b4ef 100644
--- a/ucoo/hal/timer/timer.stm32.tcc
+++ b/ucoo/hal/timer/timer.stm32.tcc
@@ -23,22 +23,19 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include <libopencm3/stm32/timer.h>
-#include <libopencm3/stm32/rcc.h>
+#include "ucoo/arch/rcc.stm32.hh"
+#include "ucoo/arch/reg.hh"
namespace ucoo {
-template<uint32_t Base>
-struct TimerHardware { };
-
// TODO add more timers.
-// TODO timer uses a double frequency only if APB prescaler is not 1.
template<>
-struct TimerHardware<TIM1>
+struct TimerHardware<TimerInstance::TIM1>
{
- static const enum rcc_periph_clken clken = RCC_TIM1;
- static int freq () { return 2 * rcc_apb2_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM1;
+ static const Rcc rcc = Rcc::TIM1;
+ static int freq_hz () { return rcc_apb2_timer_freq_hz; }
static const unsigned int max = 0xffff;
static const bool advanced = true;
static const bool slave = true;
@@ -47,10 +44,11 @@ struct TimerHardware<TIM1>
};
template<>
-struct TimerHardware<TIM2>
+struct TimerHardware<TimerInstance::TIM2>
{
- static const enum rcc_periph_clken clken = RCC_TIM2;
- static int freq () { return 2 * rcc_apb1_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM2;
+ static const Rcc rcc = Rcc::TIM2;
+ static int freq_hz () { return rcc_apb1_timer_freq_hz; }
#if defined TARGET_stm32f4
static const unsigned int max = 0xffffffff;
#else
@@ -63,10 +61,11 @@ struct TimerHardware<TIM2>
};
template<>
-struct TimerHardware<TIM3>
+struct TimerHardware<TimerInstance::TIM3>
{
- static const enum rcc_periph_clken clken = RCC_TIM3;
- static int freq () { return 2 * rcc_apb1_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM3;
+ static const Rcc rcc = Rcc::TIM3;
+ static int freq_hz () { return rcc_apb1_timer_freq_hz; }
static const unsigned int max = 0xffff;
static const bool advanced = false;
static const bool slave = true;
@@ -75,10 +74,11 @@ struct TimerHardware<TIM3>
};
template<>
-struct TimerHardware<TIM4>
+struct TimerHardware<TimerInstance::TIM4>
{
- static const enum rcc_periph_clken clken = RCC_TIM4;
- static int freq () { return 2 * rcc_apb1_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM4;
+ static const Rcc rcc = Rcc::TIM4;
+ static int freq_hz () { return rcc_apb1_timer_freq_hz; }
static const unsigned int max = 0xffff;
static const bool advanced = false;
static const bool slave = true;
@@ -87,10 +87,11 @@ struct TimerHardware<TIM4>
};
template<>
-struct TimerHardware<TIM5>
+struct TimerHardware<TimerInstance::TIM5>
{
- static const enum rcc_periph_clken clken = RCC_TIM5;
- static int freq () { return 2 * rcc_apb1_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM5;
+ static const Rcc rcc = Rcc::TIM5;
+ static int freq_hz () { return rcc_apb1_timer_freq_hz; }
#if defined TARGET_stm32f4
static const unsigned int max = 0xffffffff;
#else
@@ -103,10 +104,11 @@ struct TimerHardware<TIM5>
};
template<>
-struct TimerHardware<TIM10>
+struct TimerHardware<TimerInstance::TIM10>
{
- static const enum rcc_periph_clken clken = RCC_TIM10;
- static int freq () { return 2 * rcc_apb2_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM10;
+ static const Rcc rcc = Rcc::TIM10;
+ static int freq_hz () { return rcc_apb2_timer_freq_hz; }
static const unsigned int max = 0xffff;
static const bool advanced = false;
static const bool slave = false;
@@ -115,10 +117,11 @@ struct TimerHardware<TIM10>
};
template<>
-struct TimerHardware<TIM11>
+struct TimerHardware<TimerInstance::TIM11>
{
- static const enum rcc_periph_clken clken = RCC_TIM10;
- static int freq () { return 2 * rcc_apb2_frequency; }
+ static constexpr TIM_TypeDef *base = reg::TIM11;
+ static const Rcc rcc = Rcc::TIM10;
+ static int freq_hz () { return rcc_apb2_timer_freq_hz; }
static const unsigned int max = 0xffff;
static const bool advanced = false;
static const bool slave = false;
@@ -126,175 +129,174 @@ struct TimerHardware<TIM11>
static const int channels = 1;
};
-template<uint32_t Base>
-const unsigned int TimerHard<Base>::max = TimerHardware<Base>::max;
+template<TimerInstance inst>
+const unsigned int TimerHard<inst>::max = TimerHardware<inst>::max;
-template<uint32_t Base>
-TimerHard<Base>::~TimerHard ()
+template<TimerInstance inst>
+TimerHard<inst>::~TimerHard ()
{
disable ();
}
-template<uint32_t Base>
+template<TimerInstance inst>
template<typename... Options>
void
-TimerHard<Base>::enable (int freq, bool start)
-{
- using Hard = TimerHardware<Base>;
- rcc_periph_clock_enable (Hard::clken);
- int in_freq = Hard::freq ();
- int div = in_freq / freq;
- assert (div <= 0x10000 && in_freq / div == freq);
- freq_ = freq;
+TimerHard<inst>::enable (int freq_hz, bool start)
+{
+ rcc_peripheral_clock_enable (Hard::rcc);
+ int in_freq_hz = Hard::freq_hz ();
+ int div = in_freq_hz / freq_hz;
+ assert (div <= 0x10000 && in_freq_hz / div == freq_hz);
+ freq_hz_ = freq_hz;
using OptionsCombined = CombinedOptions<Options...>;
- TIM_CR1 (Base) = TIM_CR1_ARPE | OptionsCombined::cr1;
- TIM_CR2 (Base) = 0;
+ Hard::base->CR1 = TIM_CR1_ARPE | OptionsCombined::cr1;
+ Hard::base->CR2 = 0;
if (Hard::slave)
- TIM_SMCR (Base) = OptionsCombined::smcr;
+ Hard::base->SMCR = OptionsCombined::smcr;
if (Hard::channels > 0)
{
- TIM_CCER (Base) = 0;
- TIM_CCMR1 (Base) = OptionsCombined::ccmr1;
+ Hard::base->CCER = 0;
+ Hard::base->CCMR1 = OptionsCombined::ccmr1;
if (Hard::channels > 2)
- TIM_CCMR2 (Base) = OptionsCombined::ccmr2;
- TIM_CCER (Base) = OptionsCombined::ccer;
- TIM_CCR1 (Base) = OptionsCombined::ccr1;
+ Hard::base->CCMR2 = OptionsCombined::ccmr2;
+ Hard::base->CCER = OptionsCombined::ccer;
+ Hard::base->CCR1 = OptionsCombined::ccr1;
if (Hard::channels >= 2)
- TIM_CCR2 (Base) = OptionsCombined::ccr2;
+ Hard::base->CCR2 = OptionsCombined::ccr2;
if (Hard::channels >= 3)
- TIM_CCR3 (Base) = OptionsCombined::ccr3;
+ Hard::base->CCR3 = OptionsCombined::ccr3;
if (Hard::channels >= 4)
- TIM_CCR4 (Base) = OptionsCombined::ccr4;
+ Hard::base->CCR4 = OptionsCombined::ccr4;
}
- TIM_PSC (Base) = div - 1;
- TIM_ARR (Base) = OptionsCombined::arr ? OptionsCombined::arr : Hard::max;
+ Hard::base->PSC = div - 1;
+ Hard::base->ARR = OptionsCombined::arr ? OptionsCombined::arr : Hard::max;
if (Hard::advanced)
- TIM_BDTR (Base) = TIM_BDTR_MOE;
- TIM_EGR (Base) = TIM_EGR_UG;
+ Hard::base->BDTR = TIM_BDTR_MOE;
+ Hard::base->EGR = TIM_EGR_UG;
if (start)
- TIM_CR1 (Base) = TIM_CR1_ARPE | OptionsCombined::cr1 | TIM_CR1_CEN;
+ Hard::base->CR1 = TIM_CR1_ARPE | OptionsCombined::cr1 | TIM_CR1_CEN;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::disable ()
+TimerHard<inst>::disable ()
{
- TIM_CR1 (Base) = 0;
- rcc_periph_clock_disable (TimerHardware<Base>::clken);
- freq_ = 0;
+ Hard::base->CR1 = 0;
+ rcc_peripheral_clock_disable (TimerHardware<inst>::rcc);
+ freq_hz_ = 0;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::start ()
+TimerHard<inst>::start ()
{
- TIM_CR1 (Base) |= TIM_CR1_CEN;
+ Hard::base->CR1 |= TIM_CR1_CEN;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::set_reload (unsigned int value)
+TimerHard<inst>::set_reload (unsigned int value)
{
- assert (value <= TimerHardware<Base>::max);
- TIM_ARR (Base) = value;
+ assert (value <= Hard::max);
+ Hard::base->ARR = value;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::set_output_compare (int ch, unsigned int value)
+TimerHard<inst>::set_output_compare (int ch, unsigned int value)
{
- assert (ch > 0 && ch <= TimerHardware<Base>::channels);
- assert (value <= TimerHardware<Base>::max);
- *(&TIM_CCR1 (Base) + ch - 1) = value;
+ assert (ch > 0 && ch <= Hard::channels);
+ assert (value <= Hard::max);
+ *(&Hard::base->CCR1 + ch - 1) = value;
}
-template<uint32_t Base>
+template<TimerInstance inst>
unsigned int
-TimerHard<Base>::get_value ()
+TimerHard<inst>::get_value ()
{
- return TIM_CNT (Base);
+ return Hard::base->CNT;
}
-template<uint32_t Base>
+template<TimerInstance inst>
unsigned int
-TimerHard<Base>::get_input_capture (int ch) const
+TimerHard<inst>::get_input_capture (int ch) const
{
- assert (ch > 0 && ch <= TimerHardware<Base>::channels);
- return *(&TIM_CCR1 (Base) + ch - 1);
+ assert (ch > 0 && ch <= Hard::channels);
+ return *(&Hard::base->CCR1 + ch - 1);
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::wait_update () const
+TimerHard<inst>::wait_update () const
{
unsigned int mask = TIM_SR_UIF;
- while (!(TIM_SR (Base) & mask))
+ while (!(Hard::base->SR & mask))
;
- TIM_SR (Base) = ~mask;
+ Hard::base->SR = ~mask;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::wait_input_capture (int ch) const
+TimerHard<inst>::wait_input_capture (int ch) const
{
unsigned int mask = TIM_SR_CC1IF >> 1 << ch;
- while (!(TIM_SR (Base) & mask))
+ while (!(Hard::base->SR & mask))
;
- TIM_SR (Base) = ~mask;
+ Hard::base->SR = ~mask;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::enable_interrupt ()
+TimerHard<inst>::enable_interrupt ()
{
- TIM_DIER (Base) |= TIM_DIER_UIE;
+ Hard::base->DIER |= TIM_DIER_UIE;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::disable_interrupt ()
+TimerHard<inst>::disable_interrupt ()
{
- TIM_DIER (Base) &= ~TIM_DIER_UIE;
+ Hard::base->DIER &= ~TIM_DIER_UIE;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::clear_interrupt ()
+TimerHard<inst>::clear_interrupt ()
{
- TIM_SR (Base) = ~TIM_SR_UIF;
+ Hard::base->SR = ~TIM_SR_UIF;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::enable_updates ()
+TimerHard<inst>::enable_updates ()
{
- TIM_CR1 (Base) &= ~TIM_CR1_UDIS;
+ Hard::base->CR1 &= ~TIM_CR1_UDIS;
}
-template<uint32_t Base>
+template<TimerInstance inst>
void
-TimerHard<Base>::disable_updates ()
+TimerHard<inst>::disable_updates ()
{
- TIM_CR1 (Base) |= TIM_CR1_UDIS;
+ Hard::base->CR1 |= TIM_CR1_UDIS;
}
-template<uint32_t Base>
-TimerHard<Base>::UpdateDisabled::UpdateDisabled (TimerHard<Base> &timer)
+template<TimerInstance inst>
+TimerHard<inst>::UpdateDisabled::UpdateDisabled (TimerHard<inst> &timer)
: timer_ (timer)
{
timer_.disable_updates ();
}
-template<uint32_t Base>
-TimerHard<Base>::UpdateDisabled::~UpdateDisabled ()
+template<TimerInstance inst>
+TimerHard<inst>::UpdateDisabled::~UpdateDisabled ()
{
timer_.enable_updates ();
}
-template<uint32_t Base>
-struct TimerHard<Base>::Option
+template<TimerInstance inst>
+struct TimerHard<inst>::Option
{
- static const uint32_t base = Base;
+ static const TimerInstance opinst = inst;
static const unsigned cr1 = 0;
static const unsigned smcr = 0;
static const unsigned ccmr1 = 0;
@@ -307,214 +309,214 @@ struct TimerHard<Base>::Option
static const unsigned ccr4 = 0;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<unsigned int value>
-struct TimerHard<Base>::OptionReloadValue : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionReloadValue : public TimerHard<inst>::Option
{
- static_assert (value <= TimerHardware<Base>::max, "value too large");
+ static_assert (value <= Hard::max, "value too large");
static const unsigned arr = value;
};
-template<uint32_t Base>
-struct TimerHard<Base>::OptionOnePulse : public TimerHard<Base>::Option
+template<TimerInstance inst>
+struct TimerHard<inst>::OptionOnePulse : public TimerHard<inst>::Option
{
- static_assert (TimerHardware<Base>::one_pulse, "no one pulse mode");
+ static_assert (Hard::one_pulse, "no one pulse mode");
static const unsigned cr1 = TIM_CR1_OPM;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<int timer_input>
-struct TimerHard<Base>::OptionTrigger : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionTrigger : public TimerHard<inst>::Option
{
- static_assert (TimerHardware<Base>::slave, "no external trigger");
+ static_assert (Hard::slave, "no external trigger");
static_assert (timer_input >= 1 && timer_input <= 2, "no such input");
static const unsigned smcr =
- (timer_input == 1 ? TIM_SMCR_TS_IT1FP1 : TIM_SMCR_TS_IT1FP2)
+ (timer_input == 1 ? TIM_SMCR_TS_TI1FP1 : TIM_SMCR_TS_TI1FP2)
| TIM_SMCR_SMS_TM;
};
-template<uint32_t Base>
-template<int channel, typename TimerHard<Base>::Filter filter,
- typename TimerHard<Base>::Map map,
- typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionInputCapture
+template<TimerInstance inst>
+template<int channel, typename TimerHard<inst>::Filter filter,
+ typename TimerHard<inst>::Map map,
+ typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionInputCapture
{
static_assert (channel == 1, "no such channel");
// Always activate input capture (through Polarity values), even when only
// used as a trigger, no harm is done.
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Filter filter,
- typename TimerHard<Base>::Map map,
- typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionInputCapture<1, filter, map, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Filter filter,
+ typename TimerHard<inst>::Map map,
+ typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionInputCapture<1, filter, map, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (1 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (1 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr1 =
(static_cast<int> (filter)
- * (TIM_CCMR1_IC1F_MASK & ~(TIM_CCMR1_IC1F_MASK - 1)))
+ * (TIM_CCMR1_IC1F & ~(TIM_CCMR1_IC1F - 1)))
| (static_cast<int> (map)
- * (TIM_CCMR1_CC1S_MASK & ~(TIM_CCMR1_CC1S_MASK - 1)));
+ * (TIM_CCMR1_CC1S & ~(TIM_CCMR1_CC1S - 1)));
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC1E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Filter filter,
- typename TimerHard<Base>::Map map,
- typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionInputCapture<2, filter, map, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Filter filter,
+ typename TimerHard<inst>::Map map,
+ typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionInputCapture<2, filter, map, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (2 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (2 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr1 =
(static_cast<int> (filter)
- * (TIM_CCMR1_IC2F_MASK & ~(TIM_CCMR1_IC2F_MASK - 1)))
+ * (TIM_CCMR1_IC2F & ~(TIM_CCMR1_IC2F - 1)))
| (static_cast<int> (map)
- * (TIM_CCMR1_CC2S_MASK & ~(TIM_CCMR1_CC2S_MASK - 1)));
+ * (TIM_CCMR1_CC2S & ~(TIM_CCMR1_CC2S - 1)));
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC2E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Filter filter,
- typename TimerHard<Base>::Map map,
- typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionInputCapture<3, filter, map, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Filter filter,
+ typename TimerHard<inst>::Map map,
+ typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionInputCapture<3, filter, map, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (3 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (3 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr2 =
(static_cast<int> (filter)
- * (TIM_CCMR2_IC3F_MASK & ~(TIM_CCMR2_IC3F_MASK - 1)))
+ * (TIM_CCMR2_IC3F & ~(TIM_CCMR2_IC3F - 1)))
| (static_cast<int> (map)
- * (TIM_CCMR2_CC3S_MASK & ~(TIM_CCMR2_CC3S_MASK - 1)));
+ * (TIM_CCMR2_CC3S & ~(TIM_CCMR2_CC3S - 1)));
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC3E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Filter filter,
- typename TimerHard<Base>::Map map,
- typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionInputCapture<4, filter, map, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Filter filter,
+ typename TimerHard<inst>::Map map,
+ typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionInputCapture<4, filter, map, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (4 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (4 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr2 =
(static_cast<int> (filter)
- * (TIM_CCMR2_IC4F_MASK & ~(TIM_CCMR2_IC4F_MASK - 1)))
+ * (TIM_CCMR2_IC4F & ~(TIM_CCMR2_IC4F - 1)))
| (static_cast<int> (map)
- * (TIM_CCMR2_CC4S_MASK & ~(TIM_CCMR2_CC4S_MASK - 1)));
+ * (TIM_CCMR2_CC4S & ~(TIM_CCMR2_CC4S - 1)));
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC4E;
};
-template<uint32_t Base>
-template<int channel, typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionOutputCompare
+template<TimerInstance inst>
+template<int channel, typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionOutputCompare
{
static_assert (channel == 1, "no such channel");
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionOutputCompare<1, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionOutputCompare<1, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (1 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (1 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr1 = TIM_CCMR1_OC1M_PWM1 | TIM_CCMR1_OC1PE;
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC1E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionOutputCompare<2, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionOutputCompare<2, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (2 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (2 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr1 = TIM_CCMR1_OC2M_PWM1 | TIM_CCMR1_OC2PE;
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC2E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionOutputCompare<3, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionOutputCompare<3, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (3 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (3 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr2 = TIM_CCMR2_OC3M_PWM1 | TIM_CCMR2_OC3PE;
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC3E;
};
-template<uint32_t Base>
-template<typename TimerHard<Base>::Polarity polarity>
-struct TimerHard<Base>::OptionOutputCompare<4, polarity>
- : public TimerHard<Base>::Option
+template<TimerInstance inst>
+template<typename TimerHard<inst>::Polarity polarity>
+struct TimerHard<inst>::OptionOutputCompare<4, polarity>
+ : public TimerHard<inst>::Option
{
- static_assert (4 <= TimerHardware<Base>::channels, "no such channel");
+ static_assert (4 <= TimerHard<inst>::Hard::channels, "no such channel");
static const unsigned ccmr2 = TIM_CCMR2_OC4M_PWM1 | TIM_CCMR2_OC4PE;
static const unsigned ccer = static_cast<int> (polarity) * TIM_CCER_CC4E;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<int channel, unsigned int value>
-struct TimerHard<Base>::OptionOutputCompareValue
- : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionOutputCompareValue
+ : public TimerHard<inst>::Option
{
static_assert (channel == 1, "no such channel");
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<unsigned int value>
-struct TimerHard<Base>::OptionOutputCompareValue<1, value>
- : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionOutputCompareValue<1, value>
+ : public TimerHard<inst>::Option
{
- static_assert (1 <= TimerHardware<Base>::channels, "no such channel");
- static_assert (value <= TimerHardware<Base>::max, "value too large");
+ static_assert (1 <= TimerHard<inst>::Hard::channels, "no such channel");
+ static_assert (value <= TimerHard<inst>::Hard::max, "value too large");
static const unsigned ccr1 = value;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<unsigned int value>
-struct TimerHard<Base>::OptionOutputCompareValue<2, value>
- : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionOutputCompareValue<2, value>
+ : public TimerHard<inst>::Option
{
- static_assert (2 <= TimerHardware<Base>::channels, "no such channel");
- static_assert (value <= TimerHardware<Base>::max, "value too large");
+ static_assert (2 <= TimerHard<inst>::Hard::channels, "no such channel");
+ static_assert (value <= TimerHard<inst>::Hard::max, "value too large");
static const unsigned ccr2 = value;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<unsigned int value>
-struct TimerHard<Base>::OptionOutputCompareValue<3, value>
- : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionOutputCompareValue<3, value>
+ : public TimerHard<inst>::Option
{
- static_assert (3 <= TimerHardware<Base>::channels, "no such channel");
- static_assert (value <= TimerHardware<Base>::max, "value too large");
+ static_assert (3 <= TimerHard<inst>::Hard::channels, "no such channel");
+ static_assert (value <= TimerHard<inst>::Hard::max, "value too large");
static const unsigned ccr3 = value;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<unsigned int value>
-struct TimerHard<Base>::OptionOutputCompareValue<4, value>
- : public TimerHard<Base>::Option
+struct TimerHard<inst>::OptionOutputCompareValue<4, value>
+ : public TimerHard<inst>::Option
{
- static_assert (4 <= TimerHardware<Base>::channels, "no such channel");
- static_assert (value <= TimerHardware<Base>::max, "value too large");
+ static_assert (4 <= TimerHard<inst>::Hard::channels, "no such channel");
+ static_assert (value <= TimerHard<inst>::Hard::max, "value too large");
static const unsigned ccr4 = value;
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<typename... Options>
-struct TimerHard<Base>::CombinedOptions : public TimerHard<Base>::Option
+struct TimerHard<inst>::CombinedOptions : public TimerHard<inst>::Option
{
};
-template<uint32_t Base>
+template<TimerInstance inst>
template<typename Option, typename... Options>
-struct TimerHard<Base>::CombinedOptions<Option, Options...>
+struct TimerHard<inst>::CombinedOptions<Option, Options...>
{
- static_assert (Base == Option::base, "option for another timer");
- static const uint32_t base = Base;
+ static_assert (inst == Option::opinst, "option for another timer");
+ static const TimerInstance opinst = inst;
static const unsigned cr1 = Option::cr1
| CombinedOptions<Options...>::cr1;
static const unsigned smcr = Option::smcr
diff --git a/ucoo/hal/uart/test/Makefile b/ucoo/hal/uart/test/Makefile
index b1e9c71..4e00795 100644
--- a/ucoo/hal/uart/test/Makefile
+++ b/ucoo/hal/uart/test/Makefile
@@ -6,7 +6,7 @@ stm32f4_PROGS = test_uart_disc
test_uart_SOURCES = test_uart.cc
test_uart_disc_SOURCES = test_uart_disc.cc
-MODULES = ucoo/hal/uart
+MODULES = ucoo/hal/uart ucoo/hal/gpio
test_uart_disc_MODULES = $(MODULES) ucoo/base/test ucoo/hal/usb
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/uart/test/test_uart.cc b/ucoo/hal/uart/test/test_uart.cc
index 6236938..b43b797 100644
--- a/ucoo/hal/uart/test/test_uart.cc
+++ b/ucoo/hal/uart/test/test_uart.cc
@@ -26,7 +26,6 @@
#include "ucoo/arch/arch.hh"
#if defined (TARGET_stm32)
-# include <libopencm3/stm32/rcc.h>
# include "ucoo/hal/gpio/gpio.hh"
#endif
@@ -41,14 +40,14 @@ main (int argc, const char **argv)
#elif defined (TARGET_stm32)
// D8, D9: UART3
// C12, D2: UART5
- rcc_periph_clock_enable (RCC_GPIOC);
- rcc_periph_clock_enable (RCC_GPIOD);
- gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12);
- gpio_mode_setup (GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO8 | GPIO9);
- gpio_set_af (GPIOC, GPIO_AF8, GPIO12);
- gpio_set_af (GPIOD, GPIO_AF8, GPIO2);
- gpio_set_af (GPIOD, GPIO_AF7, GPIO8 | GPIO9);
- ucoo::Uart u0 (2), u1 (4);
+ ucoo::GPIOC.enable ();
+ ucoo::GPIOD.enable ();
+ ucoo::GPIOC[12].af (8);
+ ucoo::GPIOD[2].af (8);
+ ucoo::GPIOD[8].af (7);
+ ucoo::GPIOD[9].af (7);
+ ucoo::Uart u0 (ucoo::Uart::Instance::USART3);
+ ucoo::Uart u1 (ucoo::Uart::Instance::UART5);
u0.enable (38400, ucoo::Uart::Parity::EVEN, 1);
u1.enable (38400, ucoo::Uart::Parity::EVEN, 1);
#endif
diff --git a/ucoo/hal/uart/test/test_uart_disc.cc b/ucoo/hal/uart/test/test_uart_disc.cc
index 3893f7e..029b28d 100644
--- a/ucoo/hal/uart/test/test_uart_disc.cc
+++ b/ucoo/hal/uart/test/test_uart_disc.cc
@@ -27,8 +27,6 @@
#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/base/test/test.hh"
-#include <libopencm3/stm32/rcc.h>
-
static void
check_act (ucoo::Stream &ts, ucoo::Stream &u, char n)
{
@@ -53,23 +51,20 @@ main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
ucoo::Stream &ts = ucoo::test_stream ();
- ucoo::Uart u1 (0);
- ucoo::Uart u3 (2);
- ucoo::Uart u4 (3);
+ ucoo::Uart u1 (ucoo::Uart::Instance::USART1);
+ ucoo::Uart u3 (ucoo::Uart::Instance::USART3);
+ ucoo::Uart u4 (ucoo::Uart::Instance::UART4);
u1.enable (38400, ucoo::Uart::Parity::EVEN, 1);
u3.enable (38400, ucoo::Uart::Parity::EVEN, 1);
u4.enable (38400, ucoo::Uart::Parity::EVEN, 1);
// For this test, shorten B6 & B7 to have a loopback on UART1, shorten C10
// & C11 to connect UART3 to UART4.
- rcc_periph_clock_enable (RCC_GPIOB);
- rcc_periph_clock_enable (RCC_GPIOC);
- gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO6 | GPIO7);
- gpio_set_af (GPIOB, GPIO_AF7, GPIO6 | GPIO7);
- gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO10 | GPIO11);
- gpio_set_af (GPIOC, GPIO_AF7, GPIO10);
- gpio_set_af (GPIOC, GPIO_AF8, GPIO11);
+ ucoo::GPIOB.enable ();
+ ucoo::GPIOC.enable ();
+ ucoo::GPIOB[6].af (7);
+ ucoo::GPIOB[7].af (7);
+ ucoo::GPIOC[10].af (7);
+ ucoo::GPIOC[11].af (8);
// Loop to report any activity on ports and provide a simple UI.
char buf[64];
int buf_i = 0;
diff --git a/ucoo/hal/uart/uart.stm32.cc b/ucoo/hal/uart/uart.stm32.cc
index 9fdeee9..b6efbb4 100644
--- a/ucoo/hal/uart/uart.stm32.cc
+++ b/ucoo/hal/uart/uart.stm32.cc
@@ -21,11 +21,9 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
-#include "uart.stm32.hh"
-
-#include <libopencm3/stm32/usart.h>
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/cm3/nvic.h>
+#include "ucoo/hal/uart/uart.stm32.hh"
+#include "ucoo/arch/interrupt.arm.hh"
+#include "ucoo/arch/rcc.stm32.hh"
namespace ucoo {
@@ -33,95 +31,96 @@ namespace ucoo {
struct uart_hardware_t
{
/// UART base address.
- uint32_t base;
+ USART_TypeDef *base;
/// APB number.
- int apb;
- /// Clock enable identifier.
- enum rcc_periph_clken clken;
+ Bus apb;
+ /// RCC identifier, to enable clock.
+ Rcc rcc;
/// Corresponding IRQ.
- int irq;
+ Irq irq;
};
/// Information on UART hardware array, this is zero indexed, USART1 is at
/// index 0.
static const uart_hardware_t uart_hardware[] =
{
- { USART1, 2, RCC_USART1, NVIC_USART1_IRQ },
- { USART2, 1, RCC_USART2, NVIC_USART2_IRQ },
- { USART3, 1, RCC_USART3, NVIC_USART3_IRQ },
- { UART4, 1, RCC_UART4, NVIC_UART4_IRQ },
- { UART5, 1, RCC_UART5, NVIC_UART5_IRQ },
-#ifdef USART6
- { USART6, 2, RCC_USART6, NVIC_USART6_IRQ },
+ { reg::USART1, Bus::APB2, Rcc::USART1, Irq::USART1 },
+ { reg::USART2, Bus::APB1, Rcc::USART2, Irq::USART2 },
+ { reg::USART3, Bus::APB1, Rcc::USART3, Irq::USART3 },
+ { reg::UART4, Bus::APB1, Rcc::UART4, Irq::UART4 },
+ { reg::UART5, Bus::APB1, Rcc::UART5, Irq::UART5 },
+#ifdef USART6_BASE
+ { reg::USART6, Bus::APB2, Rcc::USART6, Irq::USART6 },
#endif
};
static Uart *uart_instances[lengthof (uart_hardware)];
-} // namespace ucoo
-
-extern "C" {
-
-void usart1_isr () { ucoo::Uart::isr (0); }
-
-void usart2_isr () { ucoo::Uart::isr (1); }
+template<>
+void interrupt<Irq::USART1> () { Uart::isr (0); }
-void usart3_isr () { ucoo::Uart::isr (2); }
+template<>
+void interrupt<Irq::USART2> () { Uart::isr (1); }
-void uart4_isr () { ucoo::Uart::isr (3); }
+template<>
+void interrupt<Irq::USART3> () { Uart::isr (2); }
-void uart5_isr () { ucoo::Uart::isr (4); }
+template<>
+void interrupt<Irq::UART4> () { Uart::isr (3); }
-void usart6_isr () { ucoo::Uart::isr (5); }
+template<>
+void interrupt<Irq::UART5> () { Uart::isr (4); }
-}
-
-namespace ucoo {
+#ifdef USART6_BASE
+template<>
+void interrupt<Irq::USART6> () { Uart::isr (5); }
+#endif
-Uart::Uart (int n)
- : n_ (n), error_char_ (default_error_char), enabled_ (false)
+Uart::Uart (Uart::Instance inst)
+ : n_ (static_cast<int> (inst)),
+ error_char_ (default_error_char), enabled_ (false)
{
- assert (n < lengthof (uart_instances));
- assert (!uart_instances[n]);
- uart_instances[n] = this;
+ assert (!uart_instances[n_]);
+ uart_instances[n_] = this;
}
Uart::~Uart ()
{
disable ();
- uart_instances[n_] = 0;
+ uart_instances[n_] = nullptr;
}
void
Uart::enable (int speed, Parity parity, int stop_bits)
{
enabled_ = true;
- uint32_t base = uart_hardware[n_].base;
+ auto base = uart_hardware[n_].base;
// Turn on.
- rcc_periph_clock_enable (uart_hardware[n_].clken);
+ rcc_peripheral_clock_enable (uart_hardware[n_].rcc);
// Set speed, rounded to nearest.
- int apb_freq = uart_hardware[n_].apb == 1 ? rcc_apb1_frequency
- : rcc_apb2_frequency;
- USART_BRR (base) = (2 * apb_freq + speed) / (2 * speed);
+ int apb_freq = uart_hardware[n_].apb == Bus::APB1 ? rcc_apb1_freq_hz
+ : rcc_apb2_freq_hz;
+ base->BRR = (2 * apb_freq + speed) / (2 * speed);
// Set parameters and enable.
if (stop_bits == 1)
- USART_CR2 (base) = USART_CR2_STOPBITS_1;
+ base->CR2 = USART_CR2_STOP_Bits_1;
else if (stop_bits == 2)
- USART_CR2 (base) = USART_CR2_STOPBITS_2;
+ base->CR2 = USART_CR2_STOP_Bits_2;
else
assert_unreachable ();
- USART_CR3 (base) = 0;
- uint32_t cr1 = USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ base->CR3 = 0;
+ uint32_t cr1 = USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE
+ | USART_CR1_RE;
if (parity != Parity::NONE)
cr1 |= USART_CR1_M | USART_CR1_PCE;
if (parity == Parity::ODD)
cr1 |= USART_CR1_PS;
- USART_CR1 (base) = cr1;
+ base->CR1 = cr1;
// Reset status.
- (void) USART_SR (base);
- (void) USART_DR (base);
+ (void) base->SR;
+ (void) base->DR;
// Enable interrupts.
- nvic_enable_irq (uart_hardware[n_].irq);
+ interrupt_enable (uart_hardware[n_].irq);
}
void
@@ -130,12 +129,12 @@ Uart::disable ()
if (enabled_)
{
enabled_ = false;
- uint32_t base = uart_hardware[n_].base;
+ auto base = uart_hardware[n_].base;
// Stop UART.
- nvic_disable_irq (uart_hardware[n_].irq);
- USART_CR1 (base) = 0;
+ interrupt_disable (uart_hardware[n_].irq);
+ base->CR1 = 0;
// Turn off.
- rcc_periph_clock_disable (uart_hardware[n_].clken);
+ rcc_peripheral_clock_disable (uart_hardware[n_].rcc);
}
}
@@ -165,7 +164,7 @@ Uart::write (const char *buf, int count)
int r = tx_fifo_.write (buf, left);
if (r)
{
- USART_CR1 (uart_hardware[n_].base) |= USART_CR1_TXEIE;
+ uart_hardware[n_].base->CR1 |= USART_CR1_TXEIE;
buf += r;
left -= r;
}
@@ -184,12 +183,12 @@ Uart::poll ()
void
Uart::isr (int n)
{
- uint32_t base = uart_hardware[n].base;
- uint32_t sr = USART_SR (base);
- uint32_t dr = USART_DR (base);
+ auto base = uart_hardware[n].base;
+ uint32_t sr = base->SR;
+ uint32_t dr = base->DR;
assert (uart_instances[n]);
Uart &uart = *uart_instances[n];
- if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
+ if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
{
dr = uart.error_char_;
// Datasheet is not really clear about this when error bits are set.
@@ -209,9 +208,9 @@ Uart::isr (int n)
{
bool was_full = uart.tx_fifo_.full ();
if (!uart.tx_fifo_.empty ())
- USART_DR (base) = static_cast<uint8_t> (uart.tx_fifo_.pop ());
+ base->DR = static_cast<uint8_t> (uart.tx_fifo_.pop ());
if (uart.tx_fifo_.empty ())
- USART_CR1 (base) &= ~USART_CR1_TXEIE;
+ base->CR1 &= ~USART_CR1_TXEIE;
if (was_full && uart.handler_)
uart.handler_ (false);
}
diff --git a/ucoo/hal/uart/uart.stm32.hh b/ucoo/hal/uart/uart.stm32.hh
index a38d4d6..bf73302 100644
--- a/ucoo/hal/uart/uart.stm32.hh
+++ b/ucoo/hal/uart/uart.stm32.hh
@@ -29,6 +29,8 @@
#include "config/ucoo/hal/uart.hh"
+#include "ucoo/arch/reg.hh"
+
namespace ucoo {
/// Universal asynchronous receiver transmitter (UART).
@@ -42,9 +44,21 @@ class Uart : public Stream
enum class Parity { ODD, EVEN, NONE };
/// Default error character.
static const char default_error_char = '~';
+ /// Available UARTS.
+ enum class Instance
+ {
+ USART1,
+ USART2,
+ USART3,
+ UART4,
+ UART5,
+#ifdef USART6_BASE
+ USART6,
+#endif
+ };
public:
- /// Constructor for the Nth UART.
- Uart (int n);
+ /// Constructor for an UART instance.
+ Uart (Instance inst);
/// Shutdown UART.
~Uart ();
/// Enable and setup UART.
diff --git a/ucoo/hal/usb/Config b/ucoo/hal/usb/Config
index 249a0ac..e0cd973 100644
--- a/ucoo/hal/usb/Config
+++ b/ucoo/hal/usb/Config
@@ -2,15 +2,12 @@
# Theses are APBTeam IDs, given by Openmoko!
vendor_id = 0x1d50
product_id = 0x6052
-# Declare as a CDC ACM device.
-cdc_acm = true
-# Number of streams, interfaces, or pair of endpoints.
-stream_nb = 1
-# Set to 0 if powered from USB cable, 1 if device has its own power supply.
-self_powered = 0
+# Set to false if powered from USB cable, true if device has its own power
+# supply.
+self_powered = false
# Maximum power consumed from USB cable (mA).
max_power = 100
# End point size, you should use 64.
ep_size = 64
-# Use HS driver instead of FS
-driver_hs = false
+# Enable trace buffer.
+trace = false
diff --git a/ucoo/hal/usb/Module b/ucoo/hal/usb/Module
index e47e0e8..b879961 100644
--- a/ucoo/hal/usb/Module
+++ b/ucoo/hal/usb/Module
@@ -1 +1,5 @@
-ucoo_hal_usb_SOURCES = usb.stm32.cc usb_desc.stm32.c
+ucoo_hal_usb_SOURCES = \
+ usb_driver.cc \
+ usb_application.cc \
+ usb_cdc.cc \
+ usb_dwc_otg.stm32.cc
diff --git a/ucoo/hal/usb/test/Config b/ucoo/hal/usb/test/Config
index a29fd20..908a0df 100644
--- a/ucoo/hal/usb/test/Config
+++ b/ucoo/hal/usb/test/Config
@@ -1,2 +1,2 @@
[ucoo/hal/usb]
-stream_nb = 1
+trace = true
diff --git a/ucoo/hal/usb/test/Makefile b/ucoo/hal/usb/test/Makefile
index 95e4648..d4849df 100644
--- a/ucoo/hal/usb/test/Makefile
+++ b/ucoo/hal/usb/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = stm32f4
PROGS = test_usb
test_usb_SOURCES = test_usb.cc
-MODULES = ucoo/hal/usb
+MODULES = ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/hal/usb/test/test_usb.cc b/ucoo/hal/usb/test/test_usb.cc
index eb2eb12..ff730a4 100644
--- a/ucoo/hal/usb/test/test_usb.cc
+++ b/ucoo/hal/usb/test/test_usb.cc
@@ -22,53 +22,34 @@
//
// }}}
#include "ucoo/hal/usb/usb.hh"
+#include "ucoo/hal/usb/usb_cdc.hh"
+#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/arch/arch.hh"
+static const auto string_descs_pack = ucoo::usb_descs_pack (
+ ucoo::usb_string_desc (ucoo::USB_LANGUAGE_EN_US),
+ ucoo::usb_string_desc (u"APBTeam"),
+ ucoo::usb_string_desc (u"test"));
+
+static const auto string_descs = ucoo::usb_descs (string_descs_pack);
+
int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- ucoo::UsbStreamControl usc ("APBTeam", "USB test");
- usc.enable ();
- ucoo::UsbStream us[] = {
- ucoo::UsbStream (usc, 0),
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
- ucoo::UsbStream (usc, 1),
-#endif
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
- ucoo::UsbStream (usc, 2),
-#endif
- };
- if (CONFIG_UCOO_HAL_USB_STREAM_NB > 1)
- {
- for (int i = 0; i < CONFIG_UCOO_HAL_USB_STREAM_NB; i++)
- us[i].block (false);
- }
- char buf[6];
+ ucoo::UsbDriverDwcOtg driver (ucoo::UsbDriverDwcOtg::Instance::OTG_FS,
+ ucoo::usb_cdc_default_device_desc (),
+ ucoo::usb_cdc_default_configuration_desc (),
+ string_descs);
+ ucoo::UsbApplicationCdcAcm cdc (driver);
+ driver.enable ();
+ cdc.write ("hello", 5);
while (1)
{
- for (int i = 0; i < CONFIG_UCOO_HAL_USB_STREAM_NB; i++)
- {
- int len = us[i].read (buf + 2, sizeof (buf) - 2);
- if (len)
- {
- buf[0] = i + '0';
- buf[1] = '>';
- len += 2;
- if (CONFIG_UCOO_HAL_USB_STREAM_NB == 1)
- us[i].write (buf, len);
- else
- {
- const char *p = buf;
- while (len)
- {
- int r = us[i].write (p, len);
- p += r;
- len -= r;
- }
- }
- }
- }
+ char buf[64];
+ int r = cdc.read (buf, sizeof (buf));
+ if (r)
+ cdc.write (buf, r);
}
}
diff --git a/ucoo/hal/usb/usb.hh b/ucoo/hal/usb/usb.hh
index 5324058..8115bc7 100644
--- a/ucoo/hal/usb/usb.hh
+++ b/ucoo/hal/usb/usb.hh
@@ -24,8 +24,10 @@
//
// }}}
+#include "usb_driver.hh"
+#include "usb_application.hh"
#ifdef TARGET_stm32
-# include "usb.stm32.hh"
+# include "usb_dwc_otg.stm32.hh"
#else
# error "not implemented for this target"
#endif
diff --git a/ucoo/hal/usb/usb.stm32.cc b/ucoo/hal/usb/usb.stm32.cc
deleted file mode 100644
index 5ed6b27..0000000
--- a/ucoo/hal/usb/usb.stm32.cc
+++ /dev/null
@@ -1,311 +0,0 @@
-// ucoolib - Microcontroller object oriented library. {{{
-//
-// Copyright (C) 2012 Nicolas Schodet
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-//
-// }}}
-#include "usb.stm32.hh"
-#include <algorithm>
-
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
-#include <libopencm3/cm3/nvic.h>
-#include <libopencm3/stm32/otg_fs.h>
-#include <libopencm3/stm32/otg_hs.h>
-
-#include "usb_desc.stm32.h"
-
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
-# include <libopencm3/usb/cdc.h>
-#endif
-
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
-# define usb_isr otg_hs_isr
-# define usb_driver otghs_usb_driver
-# else
-# define usb_isr otg_fs_isr
-# define usb_driver otgfs_usb_driver
-# endif
-#elif defined (TARGET_stm32f1)
-# define usb_isr otg_fs_isr
-# define usb_driver otgfs_usb_driver
-#else
-# error "not implemented for this target"
-#endif
-
-static usbd_device *usbdev;
-
-// Buffer for control requests.
-static uint8_t usb_control_buffer[128];
-
-extern "C" {
-
-void
-usb_isr ()
-{
- usbd_poll (usbdev);
-}
-
-}
-
-namespace ucoo {
-
-UsbStreamControl *UsbStreamControl::instance_;
-
-const char *strings[] = {
- NULL,
- NULL
-};
-
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static void
-usb_cdc_acm_send_serial_state (usbd_device *usbdev, bool active)
-{
- struct serial_state_notification
- {
- struct usb_cdc_notification notification;
- uint16_t state;
- } n;
- n.notification.bmRequestType = 0xa1;
- n.notification.bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
- n.notification.wValue = 0;
- n.notification.wIndex = 0;
- n.notification.wLength = 2;
- n.state = active ? 3 : 0;
- usbd_ep_write_packet (usbdev, 0x82, reinterpret_cast<void *> (&n),
- sizeof (n));
-}
-
-static int
-usb_cdc_acm_control_request (
- usbd_device *usbdev,
- struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete) (usbd_device *usbdev, struct usb_setup_data *req))
-{
- switch (req->bRequest)
- {
- case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- usb_cdc_acm_send_serial_state (usbdev, true);
- return USBD_REQ_HANDLED;
- case USB_CDC_REQ_SET_LINE_CODING:
- if (*len < sizeof (struct usb_cdc_line_coding))
- return USBD_REQ_NOTSUPP;
- return USBD_REQ_HANDLED;
- }
- return 0;
-}
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-UsbStreamControl::RxBuffer::RxBuffer (void)
- : size (0), offset (0)
-{
-}
-
-UsbStreamControl::UsbStreamControl (const char *vendor, const char *product)
- : enabled_ (false), configured_ (false)
-{
- assert (!instance_);
- instance_ = this;
- strings[0] = vendor;
- strings[1] = product;
-}
-
-UsbStreamControl::~UsbStreamControl ()
-{
- disable ();
-}
-
-void
-UsbStreamControl::enable ()
-{
- if (!enabled_)
- {
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
- rcc_periph_clock_enable (RCC_OTGHS);
- rcc_periph_clock_enable (RCC_GPIOB);
- gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14 | GPIO15);
- gpio_set_af (GPIOB, GPIO_AF12, GPIO14 | GPIO15);
-# else
- rcc_periph_clock_enable (RCC_OTGFS);
- rcc_periph_clock_enable (RCC_GPIOA);
- gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
- gpio_set_af (GPIOA, GPIO_AF10, GPIO11 | GPIO12);
-# endif
-#elif defined (TARGET_stm32f1)
- rcc_periph_clock_enable (RCC_OTGFS);
- rcc_periph_clock_enable (RCC_GPIOA);
-#endif
- usbdev = usbd_init (&usb_driver, &usb_desc_dev, &usb_desc_config,
- strings, lengthof (strings),
- usb_control_buffer, sizeof (usb_control_buffer));
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- if (OTG_HS_CID == 0x2000)
- {
- // Different registers in F479.
- OTG_HS_GCCFG = (1 << 21) | (1 << 16);
- OTG_HS_DCTL = 0;
- }
-#else
- if (OTG_FS_CID == 0x2000)
- {
- // Different registers in F479.
- OTG_FS_GCCFG = (1 << 21) | (1 << 16);
- OTG_FS_DCTL = 0;
- }
-#endif
- usbd_register_set_config_callback (usbdev, set_config);
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- nvic_enable_irq (NVIC_OTG_HS_IRQ);
-#else
- nvic_enable_irq (NVIC_OTG_FS_IRQ);
-#endif
- enabled_ = true;
- }
-}
-
-void
-UsbStreamControl::disable ()
-{
- if (enabled_)
- {
- enabled_ = false;
- configured_ = false;
-#if CONFIG_UCOO_HAL_USB_DRIVER_HS
- nvic_disable_irq (NVIC_OTG_HS_IRQ);
-#else
- nvic_disable_irq (NVIC_OTG_FS_IRQ);
-#endif
- usbd_disconnect (usbdev, true);
-#if defined (TARGET_stm32f4)
-# if CONFIG_UCOO_HAL_USB_DRIVER_HS
- rcc_periph_clock_disable (RCC_OTGHS);
- gpio_mode_setup (GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO14 | GPIO15);
-# else
- rcc_periph_clock_disable (RCC_OTGFS);
- gpio_mode_setup (GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO11 | GPIO12);
-# endif
-#elif defined (TARGET_stm32f1)
- rcc_periph_clock_disable (RCC_OTGFS);
-#endif
- }
-}
-
-void
-UsbStreamControl::set_config (usbd_device *usbdev, uint16_t configured)
-{
- instance_->configured_ = configured;
- if (configured)
- {
- for (int i = 0; i < stream_nb_; i++)
- {
- usbd_ep_setup (usbdev, 0x01 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
- rx_callback);
- usbd_ep_setup (usbdev, 0x81 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
- NULL);
- }
-#if CONFIG_UCOO_HAL_USB_CDC_ACM
- usbd_ep_setup (usbdev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
- usbd_register_control_callback (
- usbdev,
- USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- usb_cdc_acm_control_request);
- usb_cdc_acm_send_serial_state (usbdev, true);
-#endif
- }
-}
-
-void
-UsbStreamControl::rx_callback (usbd_device *usbdev, uint8_t ep)
-{
- assert (ep > 0 && ep <= stream_nb_);
- int num = ep - 1;
- RxBuffer &rb = instance_->rx_buffer_[num];
- assert (rb.size == 0 && rb.offset == 0);
- usbd_ep_nak_set (usbdev, ep, 1);
- rb.size = usbd_ep_read_packet (usbdev, ep, rb.buf, ep_size_);
-}
-
-UsbStream::UsbStream (UsbStreamControl &control, int num)
- : control_ (control), num_ (num)
-{
- assert (num < UsbStreamControl::stream_nb_);
-}
-
-int
-UsbStream::read (char *buf, int count)
-{
- UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
- /* Wait for reception. */
- if (!rb.size && !block_)
- return 0;
- while (!rb.size)
- barrier ();
- /* Copy to provided buffer. */
- int len = std::min (count, rb.size - rb.offset);
- buf = std::copy (rb.buf + rb.offset, rb.buf + rb.offset + len, buf);
- rb.offset += len;
- /* Reload buffer? */
- if (rb.offset == rb.size)
- {
- rb.offset = rb.size = 0;
- barrier ();
- usbd_ep_nak_set (usbdev, num_ + 1, 0);
- }
- /* Done. */
- return len;
-}
-
-int
-UsbStream::write (const char *buf, int count)
-{
- int left = count;
- while (left)
- {
- if (control_.configured_)
- {
- // Do the FIFO write with IRQ locked, as the USB IP does not
- // tolerate any interruption while the FIFO is being filled.
- int len = std::min (left, UsbStreamControl::ep_size_);
- irq_flags_t f = irq_lock ();
- len = usbd_ep_write_packet (usbdev, num_ + 0x81, buf, len);
- irq_restore (f);
- buf += len;
- left -= len;
- }
- if (!block_)
- break;
- barrier ();
- }
- return count - left;
-}
-
-int
-UsbStream::poll ()
-{
- UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
- return rb.size - rb.offset;
-}
-
-} // namespace ucoo
diff --git a/ucoo/hal/usb/usb.stm32.hh b/ucoo/hal/usb/usb.stm32.hh
deleted file mode 100644
index 5c44e2f..0000000
--- a/ucoo/hal/usb/usb.stm32.hh
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef ucoo_hal_usb_usb_stm32_hh
-#define ucoo_hal_usb_usb_stm32_hh
-// ucoolib - Microcontroller object oriented library. {{{
-//
-// Copyright (C) 2012 Nicolas Schodet
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-//
-// }}}
-#include "ucoo/intf/stream.hh"
-#include "ucoo/common.hh"
-
-#include "config/ucoo/hal/usb.hh"
-
-#include <libopencm3/usb/usbd.h>
-
-namespace ucoo {
-
-class UsbStream;
-
-/// Top control class for an USB device. This is a limited implementation
-/// which fulfill most of our needs: one or more interfaces, each of them is
-/// handled as a character stream. This should be instantiated only once.
-class UsbStreamControl
-{
- public:
- /// Construct a new USB control object, with given VENDOR and PRODUCT
- /// strings.
- UsbStreamControl (const char *vendor, const char *product);
- /// Destruct and disable.
- ~UsbStreamControl ();
- /// Enable device.
- void enable ();
- /// Disable device.
- void disable ();
- /// Return true if the device is configured. This means that the
- /// connection is done with the host and data can be exchanged.
- bool is_configured () const { return configured_; }
- private:
- /// Called by USB stack when device is configured. This is expected to
- /// setup endpoints.
- static void set_config (usbd_device *usbdev, uint16_t wValue);
- /// Called by USB stack when a frame is received on a OUT endpoint.
- static void rx_callback (usbd_device *usbdev, uint8_t ep);
- private:
- /// Size of endpoints.
- static const int ep_size_ = CONFIG_UCOO_HAL_USB_EP_SIZE;
- /// Number of streams (also interfaces or pair of endpoints).
- static const int stream_nb_ = CONFIG_UCOO_HAL_USB_STREAM_NB;
- /// Pointer to the one and only instance.
- static UsbStreamControl *instance_;
- /// Is currently enabled?
- bool enabled_;
- /// Whether device is currently configured.
- bool configured_;
- /// Internal RX buffer type.
- struct RxBuffer
- {
- char buf[ep_size_];
- int size, offset;
- RxBuffer (void);
- };
- /// Internal RX buffer, one per stream.
- RxBuffer rx_buffer_[stream_nb_];
- friend class UsbStream;
-};
-
-/// One USB stream, instantiated for each stream, interface, or pair of
-/// endpoints.
-class UsbStream : public Stream
-{
- public:
- /// Construct from control object and stream index.
- UsbStream (UsbStreamControl &control, int num);
- /// See Stream::read.
- int read (char *buf, int count);
- /// See Stream::write.
- int write (const char *buf, int count);
- /// See Stream::poll.
- int poll ();
- private:
- /// Reference to control object.
- UsbStreamControl &control_;
- /// Stream index.
- int num_;
-};
-
-} // namespace ucoo
-
-#endif // ucoo_hal_usb_usb_stm32_hh
diff --git a/ucoo/hal/usb/usb_application.cc b/ucoo/hal/usb/usb_application.cc
new file mode 100644
index 0000000..3ae6bd5
--- /dev/null
+++ b/ucoo/hal/usb/usb_application.cc
@@ -0,0 +1,222 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+#include "ucoo/hal/usb/usb_driver.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+UsbApplication::UsbApplication (UsbDriver &driver)
+ : driver_ (driver)
+{
+ driver.register_application (*this);
+}
+
+void
+UsbApplicationWithSetup::ep_handle_out (uint8_t ep_address, int bcnt)
+{
+ assert (ep_address == 0);
+ if (setup_stage_ == SetupStage::HostToDeviceOUT)
+ {
+ if (bcnt <= data_size_)
+ {
+ if (bcnt)
+ {
+ driver_.ep_read (0, data_, bcnt);
+ data_ += bcnt;
+ data_size_ -= bcnt;
+ }
+ if (bcnt < USB_CONTROL_END_POINT_SIZE)
+ recv_done ();
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+ }
+ else if (setup_stage_ == SetupStage::DeviceToHostStatusOUT && bcnt == 0)
+ {
+ // Status received, done.
+ setup_stage_ = SetupStage::Idle;
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+}
+
+void
+UsbApplicationWithSetup::ep_handle_in (uint8_t ep_address)
+{
+ assert (ep_address == 0);
+ if (setup_stage_ == SetupStage::DeviceToHostIN)
+ {
+ if (data_)
+ {
+ int r = driver_.ep_write (0, data_, data_size_);
+ if (data_size_ < USB_CONTROL_END_POINT_SIZE)
+ data_ = nullptr;
+ else
+ {
+ data_ += r;
+ data_size_ -= r;
+ }
+ }
+ else
+ {
+ driver_.ep_read_ready (0, USB_CONTROL_END_POINT_SIZE);
+ setup_stage_ = SetupStage::DeviceToHostStatusOUT;
+ }
+ }
+ else if (setup_stage_ == SetupStage::HostToDeviceStatusIN)
+ {
+ // Status sent, done.
+ setup_stage_ = SetupStage::Idle;
+ }
+ else
+ {
+ driver_.ep_stall (0);
+ setup_stage_ = SetupStage::Idle;
+ }
+}
+
+void
+UsbApplicationWithSetup::send_status ()
+{
+ driver_.ep_write (0, nullptr, 0);
+ setup_stage_ = SetupStage::HostToDeviceStatusIN;
+}
+
+void
+UsbApplicationWithSetup::send (const char *data, int data_size)
+{
+ int r = driver_.ep_write (0, data, data_size);
+ if (data_size < USB_CONTROL_END_POINT_SIZE)
+ data_ = nullptr;
+ else
+ {
+ data_ = const_cast<char *> (data) + r;
+ data_size_ = data_size - r;
+ }
+ setup_stage_ = SetupStage::DeviceToHostIN;
+}
+
+void
+UsbApplicationWithSetup::recv (char *data, int data_size)
+{
+ data_ = data;
+ data_size_ = data_size;
+ driver_.ep_read_ready (0, USB_CONTROL_END_POINT_SIZE);
+ setup_stage_ = SetupStage::HostToDeviceOUT;
+}
+
+void
+UsbApplicationWithSetup::recv_done ()
+{
+ // Must be overrided if used.
+ assert_unreachable ();
+}
+
+UsbApplicationBasic::SetupResult
+UsbApplicationBasic::handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length)
+{
+ SetupResult res = SetupResult::NotHandled;
+ switch (request_n_type)
+ {
+ case USB_REQ_SET_ADDRESS:
+ if (index == 0 && length == 0)
+ {
+ usb_trace ("setup set address %d", value);
+ driver_.set_address (value);
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ usb_trace ("setup get descriptor 0x%04x", value);
+ res = send_descriptor (value >> 8, value & 0xff, index, length);
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ if (index == 0 && length == 0)
+ {
+ usb_trace ("setup set configuration %d", value);
+ driver_.set_configuration (value);
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ case USB_REQ_SET_INTERFACE:
+ if (length == 0)
+ {
+ usb_trace ("setup set interface %d", value);
+ // TODO
+ send_status ();
+ res = SetupResult::Handled;
+ }
+ break;
+ }
+ return res;
+}
+
+void
+UsbApplicationBasic::handle_configuration_set (uint8_t configuration)
+{
+}
+
+UsbApplicationBasic::SetupResult
+UsbApplicationBasic::send_descriptor (uint8_t desc_type, uint8_t desc_index,
+ uint16_t language, uint16_t length)
+{
+ const details::UsbDesc *desc = nullptr;
+ switch (desc_type)
+ {
+ case 1: // Device.
+ if (desc_index == 0 || language == 0)
+ desc = &device_desc_;
+ break;
+ case 2: // Configuration.
+ if (desc_index == 0 || language == 0)
+ desc = &configuration_desc_;
+ break;
+ case 3: // String.
+ if ((desc_index == 0 && language == 0)
+ || (desc_index != 0 && desc_index < string_descs_nb_
+ && language == ucoo::USB_LANGUAGE_EN_US))
+ desc = &string_descs_[desc_index];
+ }
+ if (desc)
+ {
+ send (desc->desc,
+ desc->desc_size < length ? desc->desc_size : length);
+ return SetupResult::Handled;
+ }
+ else
+ return SetupResult::NotHandled;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_application.hh b/ucoo/hal/usb/usb_application.hh
new file mode 100644
index 0000000..ac1ea2d
--- /dev/null
+++ b/ucoo/hal/usb/usb_application.hh
@@ -0,0 +1,158 @@
+#ifndef ucoo_hal_usb_usb_application_hh
+#define ucoo_hal_usb_usb_application_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_desc.hh"
+
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+class UsbDriver;
+
+/// Class which handles application specific controls and data exchanges.
+class UsbApplication
+{
+ public:
+ /// Response from a setup handler.
+ enum class SetupResult
+ {
+ /// Setup not handled, should continue with next registered
+ /// application.
+ NotHandled,
+ /// Setup handled, this application is now responsible for any
+ /// following IN or OUT.
+ Handled,
+ /// Setup error, STALL the control end point.
+ Error
+ };
+ public:
+ /// Handle setup message received on control end point. If message is
+ /// handled, this application is automatically made responsible for IN and
+ /// OUT on this end point. It can use ep_write right now (if it does not,
+ /// it will not receive any ep_handle_in event).
+ /// On error the control end point is STALLed.
+ virtual SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) = 0;
+ /// Handle configuration set, should setup any used end points.
+ virtual void handle_configuration_set (uint8_t configuration) = 0;
+ /// Handle data received on an OUT end point. The application must use
+ /// ep_read once to receive data.
+ virtual void ep_handle_out (uint8_t ep_address, int bcnt) = 0;
+ /// Handle data needed to be transmitted on an IN end point. The
+ /// application can use ep_write once to transmit data. Else the end
+ /// point is left in a NAK state.
+ virtual void ep_handle_in (uint8_t ep_address) = 0;
+ protected:
+ /// Register application.
+ UsbApplication (UsbDriver &driver);
+ protected:
+ UsbDriver &driver_;
+};
+
+/// Helper for SETUP handling.
+class UsbApplicationWithSetup : public UsbApplication
+{
+ public:
+ /// SETUP stage, to be used as a SETUP FSM.
+ enum class SetupStage
+ {
+ /// Idle, waiting for a SETUP frame.
+ Idle,
+ /// Host to device, waiting for an OUT frame.
+ HostToDeviceOUT,
+ /// Host to device, status IN frame ready to send.
+ HostToDeviceStatusIN,
+ /// Device to host, IN frame ready to send.
+ DeviceToHostIN,
+ /// Device to host, waiting for status OUT frame.
+ DeviceToHostStatusOUT,
+
+ };
+ public:
+ UsbApplicationWithSetup (UsbDriver &driver)
+ : UsbApplication (driver) { }
+ void ep_handle_out (uint8_t ep_address, int bcnt) override;
+ void ep_handle_in (uint8_t ep_address) override;
+ protected:
+ /// Send status IN.
+ void send_status ();
+ /// Enqueue data to send in response to SETUP.
+ void send (const char *data, int data_size);
+ /// Prepare to receive data after SETUP.
+ void recv (char *data, int data_size);
+ /// Data reception done after SETUP.
+ virtual void recv_done ();
+ private:
+ SetupStage setup_stage_ = SetupStage::Idle;
+ char *data_ = nullptr;
+ int data_size_ = 0;
+};
+
+/// Handle basic USB protocol.
+class UsbApplicationBasic : public UsbApplicationWithSetup
+{
+ public:
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbApplicationBasic (UsbDriver &driver,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) override;
+ void handle_configuration_set (uint8_t configuration) override;
+ private:
+ /// Send a descriptor.
+ SetupResult send_descriptor (uint8_t desc_type, uint8_t desc_index,
+ uint16_t language, uint16_t length);
+ private:
+ const details::UsbDesc device_desc_;
+ const details::UsbDesc configuration_desc_;
+ const details::UsbDesc *string_descs_;
+ const int string_descs_nb_;
+ SetupStage setup_stage_ = SetupStage::Idle;
+ const char *to_send_ = nullptr;
+ int to_send_size_ = 0;
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbApplicationBasic::UsbApplicationBasic (
+ UsbDriver &driver,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : UsbApplicationWithSetup (driver),
+ device_desc_ (device_desc), configuration_desc_ (configuration_desc),
+ string_descs_ (reinterpret_cast<const details::UsbDesc *> (&string_descs)),
+ string_descs_nb_ (sizeof (string_descs) / sizeof (details::UsbDesc))
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_application_hh
diff --git a/ucoo/hal/usb/usb_cdc.cc b/ucoo/hal/usb/usb_cdc.cc
new file mode 100644
index 0000000..36d0889
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc.cc
@@ -0,0 +1,235 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_cdc.hh"
+#include "ucoo/hal/usb/usb_cdc_desc.hh"
+#include "ucoo/hal/usb/usb_driver.hh"
+
+#include "ucoo/utils/irq_locked.hh"
+
+namespace ucoo {
+
+enum
+{
+ END_POINT_RX = 0x01,
+ END_POINT_TX = 0x81,
+ END_POINT_NOTIF = 0x82,
+};
+
+static const auto device_desc = usb_device_desc (
+ 0x0200, USB_CLASS_CDC, 0, 0, USB_CONTROL_END_POINT_SIZE,
+ CONFIG_UCOO_HAL_USB_VENDOR_ID,
+ CONFIG_UCOO_HAL_USB_PRODUCT_ID,
+ 0x0100, 1, 2, 0, 1);
+
+static const auto configuration_desc = usb_configuration_desc (
+ 2, 1, 0,
+ 0x80 | (CONFIG_UCOO_HAL_USB_SELF_POWERED ? 0x40 : 0),
+ CONFIG_UCOO_HAL_USB_MAX_POWER / 2,
+ usb_interface_desc (
+ 0, 0, 1,
+ USB_CLASS_CDC, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTOCOL_AT, 0,
+ usb_endpoint_desc (END_POINT_NOTIF, 0x03, 16, 128),
+ usb_cdc_header_desc (0x0110),
+ usb_cdc_call_management_desc (0, 1),
+ usb_cdc_abstract_control_management_desc (2),
+ usb_cdc_union_desc (0, 1)),
+ usb_interface_desc (
+ 1, 0, 2,
+ USB_CLASS_DATA, 0, 0, 0,
+ usb_endpoint_desc_bulk (END_POINT_RX, CONFIG_UCOO_HAL_USB_EP_SIZE),
+ usb_endpoint_desc_bulk (END_POINT_TX, CONFIG_UCOO_HAL_USB_EP_SIZE)));
+
+details::UsbDesc
+usb_cdc_default_device_desc ()
+{
+ return device_desc;
+}
+
+details::UsbDesc
+usb_cdc_default_configuration_desc ()
+{
+ return configuration_desc;
+}
+
+UsbApplicationCdcAcm::SetupResult
+UsbApplicationCdcAcm::handle_setup (uint16_t request_n_type, uint16_t value,
+ uint16_t index, uint16_t length)
+{
+ SetupResult res = SetupResult::NotHandled;
+ switch (request_n_type)
+ {
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+ usb_trace ("setup set control line state");
+ send_status ();
+ send_serial_state_ = true;
+ driver_.ep_write_ready (END_POINT_NOTIF);
+ res = SetupResult::Handled;
+ break;
+ case USB_CDC_REQ_SET_LINE_CODING:
+ usb_trace ("setup set line coding");
+ recv (reinterpret_cast<char *> (&line_coding_),
+ sizeof (line_coding_));
+ res = SetupResult::Handled;
+ break;
+ }
+ return res;
+}
+
+void
+UsbApplicationCdcAcm::handle_configuration_set (uint8_t configuration)
+{
+ driver_.ep_setup (END_POINT_RX, UsbDriver::EpType::Bulk,
+ CONFIG_UCOO_HAL_USB_EP_SIZE, *this);
+ driver_.ep_setup (END_POINT_TX, UsbDriver::EpType::Bulk,
+ CONFIG_UCOO_HAL_USB_EP_SIZE, *this);
+ driver_.ep_setup (END_POINT_NOTIF, UsbDriver::EpType::Interrupt,
+ 16, *this);
+ if (!rx_buffer_.full ())
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ if (!tx_buffer_.empty ())
+ driver_.ep_write_ready (END_POINT_TX);
+ send_serial_state_ = true;
+ driver_.ep_write_ready (END_POINT_NOTIF);
+ configured_ = true;
+}
+
+void
+UsbApplicationCdcAcm::ep_handle_out (uint8_t ep_address, int bcnt)
+{
+ if (ep_address == 0)
+ UsbApplicationWithSetup::ep_handle_out (0, bcnt);
+ else if (ep_address == END_POINT_RX)
+ {
+ int r = driver_.ep_read (END_POINT_RX, rx_buffer_.write (),
+ rx_buffer_.room ());
+ rx_buffer_.written (r);
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ }
+ else
+ assert_unreachable ();
+}
+
+void
+UsbApplicationCdcAcm::ep_handle_in (uint8_t ep_address)
+{
+ if (ep_address == 0)
+ UsbApplicationWithSetup::ep_handle_in (0);
+ else if (ep_address == END_POINT_TX)
+ {
+ if (!tx_buffer_.empty ())
+ {
+ int r = driver_.ep_write (END_POINT_TX, tx_buffer_.read (),
+ tx_buffer_.size ());
+ tx_buffer_.drop (r);
+ tx_buffer_.rewind ();
+ }
+ }
+ else if (ep_address == END_POINT_NOTIF)
+ {
+ if (send_serial_state_)
+ {
+ struct
+ {
+ UsbCdcNotification notification;
+ uint16_t state;
+ } n;
+ n.notification.bmRequestType = USB_REQ (INTERFACE, CLASS, IN, 0);
+ n.notification.bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE;
+ n.notification.wValue = 0;
+ n.notification.wIndex = 0;
+ n.notification.wLength = 2;
+ n.state = active_ ? 3 : 0;
+ driver_.ep_write (END_POINT_NOTIF,
+ reinterpret_cast<const char *> (&n), sizeof (n));
+ send_serial_state_ = false;
+ }
+ }
+ else
+ assert_unreachable ();
+}
+
+int
+UsbApplicationCdcAcm::read (char *buf, int count)
+{
+ while (1)
+ {
+ {
+ IrqLocked flags;
+ if (!rx_buffer_.empty ())
+ {
+ int r = std::min (rx_buffer_.size (), count);
+ const char *f = rx_buffer_.read ();
+ std::copy (f, f + r, buf);
+ rx_buffer_.drop (r);
+ rx_buffer_.rewind ();
+ if (configured_)
+ driver_.ep_read_ready (END_POINT_RX, rx_buffer_.room ());
+ return r;
+ }
+ else if (!block_)
+ return 0;
+ }
+ yield ();
+ }
+}
+
+int
+UsbApplicationCdcAcm::write (const char *buf, int count)
+{
+ int left = count;
+ while (left)
+ {
+ {
+ IrqLocked flags;
+ if (!tx_buffer_.full ())
+ {
+ int r = std::min (tx_buffer_.room (), left);
+ std::copy (buf, buf + r, tx_buffer_.write (r));
+ if (configured_)
+ driver_.ep_write_ready (END_POINT_TX);
+ buf += r;
+ left -= r;
+ }
+ }
+ if (!block_)
+ break;
+ yield ();
+ }
+ return count - left;
+}
+
+int
+UsbApplicationCdcAcm::poll ()
+{
+ return rx_buffer_.size ();
+}
+
+void
+UsbApplicationCdcAcm::recv_done ()
+{
+ // Do not actually use the line coding information.
+ send_status ();
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_cdc.hh b/ucoo/hal/usb/usb_cdc.hh
new file mode 100644
index 0000000..7dd5aad
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc.hh
@@ -0,0 +1,81 @@
+#ifndef ucoo_hal_usb_usb_cdc_hh
+#define ucoo_hal_usb_usb_cdc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+#include "ucoo/hal/usb/usb_desc.hh"
+#include "ucoo/hal/usb/usb_cdc_def.hh"
+#include "ucoo/intf/stream.hh"
+#include "ucoo/utils/buffer.hh"
+
+#include "config/ucoo/hal/usb.hh"
+
+namespace ucoo {
+
+/// Return a default device descriptor for single CDC ACM device.
+details::UsbDesc
+usb_cdc_default_device_desc ();
+
+/// Return a default configuration descriptor for single CDC ACM device.
+details::UsbDesc
+usb_cdc_default_configuration_desc ();
+
+/// Handle a CDC ACM device, in our case a simple serial port.
+class UsbApplicationCdcAcm : public UsbApplicationWithSetup, public Stream
+{
+ public:
+ UsbApplicationCdcAcm (UsbDriver &driver)
+ : UsbApplicationWithSetup (driver) { }
+ SetupResult handle_setup (uint16_t request_n_type,
+ uint16_t value, uint16_t index,
+ uint16_t length) override;
+ void handle_configuration_set (uint8_t configuration) override;
+ void ep_handle_out (uint8_t ep_address, int bcnt) override;
+ void ep_handle_in (uint8_t ep_address) override;
+ int read (char *buf, int count) override;
+ int write (const char *buf, int count) override;
+ int poll () override;
+ protected:
+ void recv_done () override;
+ private:
+ /// Send serial state over notification end point.
+ void send_serial_state (bool active);
+ private:
+ /// Line coding being received.
+ UsbCdcLineCoding line_coding_;
+ /// Whether serial port is active (always the case now).
+ static const bool active_ = true;
+ /// RX buffer.
+ Buffer<char, CONFIG_UCOO_HAL_USB_EP_SIZE * 2> rx_buffer_;
+ /// TX buffer.
+ Buffer<char, CONFIG_UCOO_HAL_USB_EP_SIZE * 2> tx_buffer_;
+ /// Is ready to exchange data?
+ bool configured_ = false;
+ /// Was serial state requested?
+ bool send_serial_state_ = false;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_cdc_hh
diff --git a/ucoo/hal/usb/usb_cdc_def.hh b/ucoo/hal/usb/usb_cdc_def.hh
new file mode 100644
index 0000000..6ad93fa
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc_def.hh
@@ -0,0 +1,75 @@
+#ifndef ucoo_hal_usb_usb_cdc_def_hh
+#define ucoo_hal_usb_usb_cdc_def_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+enum
+{
+ USB_CDC_NOTIFICATION_SERIAL_STATE = 0x20,
+};
+
+/// Agglomeration of bmRequestType and bRequest.
+enum
+{
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE = USB_REQ (INTERFACE, CLASS, OUT, 0x22),
+ USB_CDC_REQ_SET_LINE_CODING = USB_REQ (INTERFACE, CLASS, OUT, 0x20),
+};
+
+/// Line coding structure.
+struct __attribute__ ((packed, aligned (1))) UsbCdcLineCoding
+{
+ /// Data terminal rate in bits per second.
+ uint32_t dwDTERate;
+ /// Stop bits:
+ /// - 0: 1 stop bit
+ /// - 1: 1.5 stop bits
+ /// - 2: 2 stop bits
+ uint8_t bCharFormat;
+ /// Parity:
+ /// - 0: None
+ /// - 1: Odd
+ /// - 2: Even
+ /// - 3: Mark
+ /// - 4: Space
+ uint8_t bParityType;
+ /// Data bits, 5, 6, 7, 8 or 16.
+ uint8_t bDataBits;
+};
+
+/// Notification structure.
+struct __attribute__ ((packed, aligned (1))) UsbCdcNotification
+{
+ uint8_t bmRequestType;
+ uint8_t bNotification;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_cdc_def_hh
diff --git a/ucoo/hal/usb/usb_cdc_desc.hh b/ucoo/hal/usb/usb_cdc_desc.hh
new file mode 100644
index 0000000..5c1fac2
--- /dev/null
+++ b/ucoo/hal/usb/usb_cdc_desc.hh
@@ -0,0 +1,174 @@
+#ifndef ucoo_hal_usb_usb_desc_cdc_hh
+#define ucoo_hal_usb_usb_desc_cdc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_desc.hh"
+
+namespace ucoo {
+
+enum
+{
+ USB_CLASS_CDC = 0x02,
+ USB_CLASS_DATA = 0x0a,
+ USB_CDC_SUBCLASS_ACM = 0x02,
+ USB_CDC_PROTOCOL_AT = 0x01,
+};
+
+/// CDC header descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcHeaderDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 0).
+ uint8_t bDescriptorSubtype;
+ /// USB CDC release number (0x0110 for USB CDC 1.1).
+ uint16_t bcdCDC;
+};
+
+/// Make a header descriptor.
+constexpr UsbCdcHeaderDesc
+usb_cdc_header_desc (uint16_t bcdCDC)
+{
+ return { sizeof (UsbCdcHeaderDesc), 0x24, 0, bcdCDC };
+}
+
+/// CDC call management descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcCallManagementDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 1).
+ uint8_t bDescriptorSubtype;
+ /// Capabilities:
+ /// - bit 0: device handles call management itself
+ /// - bit 1: device can send/receive call management information over
+ /// data class interface
+ uint8_t bmCapabilities;
+ /// Interface number of data class interface used for call management.
+ uint8_t bDataInterface;
+};
+
+/// Make a call management descriptor.
+constexpr UsbCdcCallManagementDesc
+usb_cdc_call_management_desc (
+ uint8_t bmCapabilities,
+ uint8_t bDataInterface)
+{
+ return { sizeof (UsbCdcCallManagementDesc), 0x24, 1, bmCapabilities,
+ bDataInterface };
+}
+
+/// CDC abstract control management descriptor.
+struct __attribute__ ((packed, aligned (1)))
+ UsbCdcAbstractControlManagementDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 2).
+ uint8_t bDescriptorSubtype;
+ /// Capabilities:
+ /// - bit 0: support Set_Comm_Feature, Clear_Comm_Feature and
+ /// Get_Comm_Feature
+ /// - bit 1: support Set_Line_Coding, Set_Control_Line_State,
+ /// Get_Line_Coding and Serial_State notification
+ /// - bit 2: support Send_Break
+ /// - bit 3: support Network_Connection notification
+ uint8_t bmCapabilities;
+};
+
+/// Make an abstract control management descriptor.
+constexpr UsbCdcAbstractControlManagementDesc
+usb_cdc_abstract_control_management_desc (
+ uint8_t bmCapabilities)
+{
+ return { sizeof (UsbCdcAbstractControlManagementDesc), 0x24, 2,
+ bmCapabilities };
+}
+
+/// CDC union descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbCdcUnionDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Descriptor type (CS_INTERFACE: 0x24).
+ uint8_t bDescriptorType;
+ /// Descriptor sub type (header functional descriptor: 6).
+ uint8_t bDescriptorSubtype;
+ /// Interface number of the communication or data class interface
+ /// designated as the controlling interface for the union.
+ uint8_t bControlInterface;
+ /// Interface number of the first subordinated interface in the union.
+ uint8_t bSubordinateInterface0;
+ /// Other subordinated interface number follows...
+};
+
+namespace details { // {{{
+
+template<typename Desc>
+constexpr Desc
+usb_cdc_union_desc (Desc desc)
+{
+ return desc;
+}
+
+template<typename Desc, typename... Rest>
+constexpr auto
+usb_cdc_union_desc (Desc desc, uint8_t bSubordinateInterfaceN,
+ Rest... rest)
+ -> decltype (usb_cdc_union_desc (
+ Pack<Desc, uint8_t> (desc, 0), rest...))
+{
+ return usb_cdc_union_desc (
+ Pack<Desc, uint8_t> (desc, bSubordinateInterfaceN),
+ rest...);
+}
+
+} // namespace details }}}
+
+/// Make an union descriptor.
+template<typename... SubInterfaces>
+constexpr auto
+usb_cdc_union_desc (
+ uint8_t bControlInterface,
+ uint8_t bSubordinateInterface0,
+ SubInterfaces... sub_interfaces)
+ -> decltype (details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { 0, 0, 0, 0, 0 }, sub_interfaces...))
+{
+ using Ret = decltype (details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { 0, 0, 0, 0, 0 }, sub_interfaces...));
+ return details::usb_cdc_union_desc (
+ (UsbCdcUnionDesc) { sizeof (Ret), 0x24, 6, bControlInterface,
+ bSubordinateInterface0 }, sub_interfaces...);
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_desc_cdc_hh
diff --git a/ucoo/hal/usb/usb_def.hh b/ucoo/hal/usb/usb_def.hh
new file mode 100644
index 0000000..f02ba74
--- /dev/null
+++ b/ucoo/hal/usb/usb_def.hh
@@ -0,0 +1,71 @@
+#ifndef ucoo_hal_usb_usb_def_hh
+#define ucoo_hal_usb_usb_def_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+enum
+{
+ /// Only support one control end point size.
+ USB_CONTROL_END_POINT_SIZE = 64,
+};
+
+/// Agglomeration of bmRequestType and bRequest.
+enum
+{
+ USB_REQ_TYPE_DEVICE = 0x0000,
+ USB_REQ_TYPE_INTERFACE = 0x0001,
+ USB_REQ_TYPE_END_POINT = 0x0002,
+ USB_REQ_TYPE_OTHER = 0x0003,
+ USB_REQ_TYPE_STANDARD = 0x0000,
+ USB_REQ_TYPE_CLASS = 0x0020,
+ USB_REQ_TYPE_VENDOR = 0x0040,
+ USB_REQ_TYPE_OUT = 0x0000,
+ USB_REQ_TYPE_IN = 0x0080,
+#define USB_REQ(rec, type, dir, code) \
+ (USB_REQ_TYPE_ ## rec | USB_REQ_TYPE_ ## type | USB_REQ_TYPE_ ## dir \
+ | ((code) << 8))
+ USB_REQ_CLEAR_FEATURE_DEVICE = USB_REQ (DEVICE, STANDARD, OUT, 0x01),
+ USB_REQ_CLEAR_FEATURE_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x01),
+ USB_REQ_CLEAR_FEATURE_END_POINT = USB_REQ (END_POINT, STANDARD, OUT, 0x01),
+ USB_REQ_GET_CONFIGURATION = USB_REQ (DEVICE, STANDARD, IN, 0x08),
+ USB_REQ_GET_DESCRIPTOR = USB_REQ (DEVICE, STANDARD, IN, 0x06),
+ USB_REQ_GET_INTERFACE = USB_REQ (INTERFACE, STANDARD, IN, 0x0a),
+ USB_REQ_GET_STATUS_DEVICE = USB_REQ (DEVICE, STANDARD, IN, 0x00),
+ USB_REQ_GET_STATUS_INTERFACE = USB_REQ (INTERFACE, STANDARD, IN, 0x00),
+ USB_REQ_GET_STATUS_END_POINT = USB_REQ (END_POINT, STANDARD, IN, 0x00),
+ USB_REQ_SET_ADDRESS = USB_REQ (DEVICE, STANDARD, OUT, 0x05),
+ USB_REQ_SET_CONFIGURATION = USB_REQ (DEVICE, STANDARD, OUT, 0x09),
+ USB_REQ_SET_DESCRIPTOR = USB_REQ (DEVICE, STANDARD, OUT, 0x07),
+ USB_REQ_SET_FEATURE_DEVICE = USB_REQ (DEVICE, STANDARD, OUT, 0x03),
+ USB_REQ_SET_FEATURE_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x03),
+ USB_REQ_SET_FEATURE_END_POINT = USB_REQ (END_POINT, STANDARD, OUT, 0x03),
+ USB_REQ_SET_INTERFACE = USB_REQ (INTERFACE, STANDARD, OUT, 0x0b),
+ USB_REQ_SYNCH_FRAME = USB_REQ (END_POINT, STANDARD, IN, 0x0c),
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_def_hh
diff --git a/ucoo/hal/usb/usb_desc.hh b/ucoo/hal/usb/usb_desc.hh
new file mode 100644
index 0000000..e23af04
--- /dev/null
+++ b/ucoo/hal/usb/usb_desc.hh
@@ -0,0 +1,406 @@
+#ifndef ucoo_hal_usb_usb_desc_hh
+#define ucoo_hal_usb_usb_desc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+namespace details { // {{{
+
+/// Pack several elements in a new types (std::tuple constructor is not
+/// constexpr in C++11).
+template<typename... Elements>
+struct Pack;
+
+template<typename Head, typename... Tail>
+struct __attribute__ ((packed, aligned (1))) Pack<Head, Tail...>
+{
+ Head head;
+ Pack<Tail...> tail;
+ constexpr Pack (Head head_, Tail... tail_)
+ : head (head_), tail (tail_...) { }
+};
+
+template<typename Head>
+struct __attribute__ ((packed, aligned (1))) Pack<Head>
+{
+ Head head;
+ constexpr Pack (Head head_) : head (head_) { }
+};
+
+/// Take a pack, unpack the Nth value.
+template<int N, typename Pack>
+struct Unpack;
+
+template<typename Head, typename... Tail>
+struct Unpack<0, Pack<Head, Tail...>>
+{
+ static constexpr const Head &unpack (const Pack<Head, Tail...> &pack)
+ {
+ return pack.head;
+ }
+};
+
+template<int N, typename Head, typename... Tail>
+struct Unpack<N, Pack<Head, Tail...>>
+{
+ static constexpr auto unpack (const Pack<Head, Tail...> &pack)
+ -> decltype (Unpack<N - 1, Pack<Tail...>>::unpack (pack.tail))
+ {
+ return Unpack<N - 1, Pack<Tail...>>::unpack (pack.tail);
+ }
+};
+
+/// Type whose only purpose is to have a sequence of integer as template
+/// parameter.
+template<int ...>
+struct Range
+{
+};
+
+template<int N, int... Next>
+struct RangeGen
+{
+ using Type = typename RangeGen<N - 1, N - 1, Next...>::Type;
+};
+
+template<int... Next>
+struct RangeGen<0, Next...>
+{
+ using Type = Range<Next...>;
+};
+
+} // namespace details }}}
+
+/// Device descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbDeviceDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Device descriptor type (1).
+ uint8_t bDescriptorType;
+ /// USB spec release number (0x0200 for USB 2.0).
+ uint16_t bcdUSB;
+ /// Class code assigned by USB-IF (0x00: each interface defines its own
+ /// class, 0xff: vendor defined).
+ uint8_t bDeviceClass;
+ /// SubClass code assigned by USB-IF.
+ uint8_t bDeviceSubClass;
+ /// Protocol code assigned by USB-IF.
+ uint8_t bDeviceProtocol;
+ /// Max packet size for endpoint 0 (8, 16, 32 or 64).
+ uint8_t bMaxPacketSize0;
+ /// Vendor ID.
+ uint16_t idVendor;
+ /// Product ID.
+ uint16_t idProduct;
+ /// Device release number.
+ uint16_t bcdDevice;
+ /// Index of string descriptor describing manufacturer (0 if no string).
+ uint8_t iManufacturer;
+ /// Index of string descriptor describing product (0 if no string).
+ uint8_t iProduct;
+ /// Index of string descriptor describing device serial number (0 if no
+ /// string).
+ uint8_t iSerialNumber;
+ /// Number of possible configurations.
+ uint8_t bNumConfigurations;
+};
+
+/// Make a device descriptor.
+constexpr UsbDeviceDesc
+usb_device_desc (
+ uint16_t bcdUSB,
+ uint8_t bDeviceClass,
+ uint8_t bDeviceSubClass,
+ uint8_t bDeviceProtocol,
+ uint8_t bMaxPacketSize0,
+ uint16_t idVendor,
+ uint16_t idProduct,
+ uint16_t bcdDevice,
+ uint8_t iManufacturer,
+ uint8_t iProduct,
+ uint8_t iSerialNumber,
+ uint8_t bNumConfigurations)
+{
+ return { sizeof (UsbDeviceDesc), 1, bcdUSB, bDeviceClass, bDeviceSubClass,
+ bDeviceProtocol, bMaxPacketSize0, idVendor, idProduct, bcdDevice,
+ iManufacturer, iProduct, iSerialNumber, bNumConfigurations };
+}
+
+/// Configuration descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbConfigurationDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Configuration descriptor type (2).
+ uint8_t bDescriptorType;
+ /// Total number of bytes in this descriptor and all the following
+ /// descriptors.
+ uint16_t wTotalLength;
+ /// Number of interfaces supported by this configuration.
+ uint8_t bNumInterfaces;
+ /// Value used by Set Configuration to select this configuration.
+ uint8_t bConfigurationValue;
+ /// Index of string descriptor describing configuration (0 if no string).
+ uint8_t iConfiguration;
+ /// Attributes:
+ /// - bit 7: must be set
+ /// - bit 6: self-powered
+ /// - bit 5: remote wakeup
+ /// - others: must be 0
+ uint8_t bmAttributes;
+ /// Maximum current drawn by device in this configuration in units of
+ /// 2 mA.
+ uint8_t bMaxPower;
+};
+
+/// Make a configuration descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbConfigurationDesc, SubDesc...>
+usb_configuration_desc (
+ uint8_t bNumInterfaces,
+ uint8_t bConfigurationValue,
+ uint8_t iConfiguration,
+ uint8_t bmAttributes,
+ uint8_t bMaxPower,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbConfigurationDesc, SubDesc...> (
+ { sizeof (UsbConfigurationDesc), 2,
+ sizeof (details::Pack<UsbConfigurationDesc, SubDesc...>),
+ bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes,
+ bMaxPower }, sub_descs...);
+}
+
+/// Interface descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbInterfaceDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Interface descriptor type (4).
+ uint8_t bDescriptorType;
+ /// Number identifying this interface (start at 0).
+ uint8_t bInterfaceNumber;
+ /// Value used to select this alternate setting for this interface (0 for
+ /// first and default setting).
+ uint8_t bAlternateSetting;
+ /// Number of endpoints used by this interface.
+ uint8_t bNumEndpoints;
+ /// Class code assigned by USB-IF.
+ uint8_t bInterfaceClass;
+ /// SubClass Code assigned by USB-IF.
+ uint8_t bInterfaceSubClass;
+ /// Protocol Code assigned by USB-IF.
+ uint8_t bInterfaceProtocol;
+ /// Index of string descriptor describing interface (0 if no string).
+ uint8_t iInterface;
+};
+
+/// Make an interface descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbInterfaceDesc, SubDesc...>
+usb_interface_desc (
+ uint8_t bInterfaceNumber,
+ uint8_t bAlternateSetting,
+ uint8_t bNumEndpoints,
+ uint8_t bInterfaceClass,
+ uint8_t bInterfaceSubClass,
+ uint8_t bInterfaceProtocol,
+ uint8_t iInterface,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbInterfaceDesc, SubDesc...> (
+ { sizeof (UsbInterfaceDesc), 4, bInterfaceNumber, bAlternateSetting,
+ bNumEndpoints, bInterfaceClass, bInterfaceSubClass,
+ bInterfaceProtocol, iInterface }, sub_descs...);
+}
+
+/// Endpoint descriptor.
+struct __attribute__ ((packed, aligned (1))) UsbEndpointDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// Endpoint descriptor type (5).
+ uint8_t bDescriptorType;
+ /// The address of this endpoint within the device.
+ /// - bit 7: direction: 0: OUT, 1: IN
+ /// - bit 3-0: endpoint number
+ uint8_t bEndpointAddress;
+ /// Attributes:
+ /// - bit 7-6: must be 0
+ /// - bit 5-4: usage type:
+ /// - 00: data endpoint
+ /// - 01: feedback endpoint
+ /// - 10: implicit feedback data endpoint
+ /// - bit 3-2: synchronisation type
+ /// - 00: none
+ /// - 01: asynchronous
+ /// - 10: adaptive
+ /// - 11: synchronous
+ /// - bit 1-0: transfer type
+ /// - 00: control
+ /// - 01: isochronous
+ /// - 10: bulk
+ /// - 11: interrupt
+ uint8_t bmAttributes;
+ /// Maximum packet size this endpoint can send or receive when this
+ /// configuration is selected.
+ uint16_t wMaxPacketSize;
+ /// Interval for polling endpoint for data transfers. Expressed in frames
+ /// (ms) for low/full speed.
+ uint8_t bInterval;
+};
+
+/// Make an endpoint descriptor.
+template<typename... SubDesc>
+constexpr details::Pack<UsbEndpointDesc, SubDesc...>
+usb_endpoint_desc (
+ uint8_t bEndpointAddress,
+ uint8_t bmAttributes,
+ uint16_t wMaxPacketSize,
+ uint8_t bInterval,
+ SubDesc... sub_descs)
+{
+ return details::Pack<UsbEndpointDesc, SubDesc...> (
+ { sizeof (UsbEndpointDesc), 5, bEndpointAddress, bmAttributes,
+ wMaxPacketSize, bInterval }, sub_descs...);
+}
+
+/// Make a bulk endpoint descriptor, shortcut.
+template<typename... SubDesc>
+constexpr details::Pack<UsbEndpointDesc, SubDesc...>
+usb_endpoint_desc_bulk (
+ uint8_t bEndpointAddress,
+ uint16_t wMaxPacketSize,
+ SubDesc... sub_descs)
+{
+ return usb_endpoint_desc (bEndpointAddress, 0x02, wMaxPacketSize, 0,
+ sub_descs...);
+}
+
+enum
+{
+ USB_LANGUAGE_EN_US = 0x0409,
+};
+
+/// String descriptor.
+template<int Length>
+struct __attribute__ ((packed, aligned (1))) UsbStringDesc
+{
+ /// Size of this descriptor in bytes.
+ uint8_t bLength;
+ /// String descriptor type (3).
+ uint8_t bDescriptorType;
+ /// Unicode encoded string.
+ char16_t bString[Length];
+};
+
+namespace details { // {{{
+
+template<int LengthWithNull, int... Rng>
+constexpr UsbStringDesc<LengthWithNull - 1>
+usb_string_desc (const char16_t (&string)[LengthWithNull],
+ const Range<Rng...> &)
+{
+ return { sizeof (UsbStringDesc<LengthWithNull - 1>), 3,
+ { string[Rng]... } };
+}
+
+} // namespace details }}}
+
+/// Make a string descriptor.
+template<int LengthWithNull>
+constexpr UsbStringDesc<LengthWithNull - 1>
+usb_string_desc (const char16_t (&string)[LengthWithNull])
+{
+ return details::usb_string_desc (
+ string, typename details::RangeGen<LengthWithNull - 1>::Type ());
+}
+
+/// Make the first string descriptor (language descriptor).
+template<typename... Languages>
+constexpr UsbStringDesc<sizeof... (Languages)>
+usb_string_desc (Languages... languages)
+{
+ return { sizeof (UsbStringDesc<sizeof... (Languages)>), 3,
+ { static_cast<char16_t> (languages)... } };
+}
+
+/// Make a descriptors pack.
+template<typename... Descs>
+constexpr details::Pack<Descs...>
+usb_descs_pack (Descs... descs)
+{
+ return details::Pack<Descs...> (descs...);
+}
+
+namespace details {
+
+/// Descriptor with its size.
+struct UsbDesc
+{
+ const char *desc;
+ int desc_size;
+ template<typename Desc>
+ constexpr UsbDesc (const Desc &desc_)
+ : desc (reinterpret_cast<const char *> (&desc_)),
+ desc_size (sizeof (desc_)) { }
+};
+
+/// Descriptors with their size.
+template<typename... Elements>
+struct UsbDescs;
+
+template<typename Head>
+struct UsbDescs<Head>
+{
+ UsbDesc head;
+ constexpr UsbDescs (const Pack<Head> &pack)
+ : head (pack.head) { }
+};
+
+template<typename Head, typename... Tail>
+struct UsbDescs<Head, Tail...>
+{
+ UsbDesc head;
+ UsbDescs<Tail...> tail;
+ constexpr UsbDescs (const Pack<Head, Tail...> &pack)
+ : head (pack.head), tail (pack.tail) { }
+};
+
+} // namespace details }}}
+
+/// Make an object with descriptors and their sizes.
+template<typename... Descs>
+constexpr details::UsbDescs<Descs...>
+usb_descs (const details::Pack<Descs...> &descs_pack)
+{
+ return descs_pack;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_desc_hh
diff --git a/ucoo/hal/usb/usb_desc.stm32.c b/ucoo/hal/usb/usb_desc.stm32.c
deleted file mode 100644
index aecc4da..0000000
--- a/ucoo/hal/usb/usb_desc.stm32.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* ucoolib - Microcontroller object oriented library. {{{
- *
- * Copyright (C) 2012 Nicolas Schodet
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * }}} */
-#include "usb_desc.stm32.h"
-#include <libopencm3/usb/usbstd.h>
-#include <libopencm3/usb/cdc.h>
-
-#include "config/ucoo/hal/usb.hh"
-
-const struct usb_device_descriptor usb_desc_dev = {
- .bLength = USB_DT_DEVICE_SIZE,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = 0x0200,
- .bDeviceClass = CONFIG_UCOO_HAL_USB_CDC_ACM ? USB_CLASS_CDC : 0xff,
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
- .bMaxPacketSize0 = 64,
- .idVendor = CONFIG_UCOO_HAL_USB_VENDOR_ID,
- .idProduct = CONFIG_UCOO_HAL_USB_PRODUCT_ID,
- .bcdDevice = 0x0000,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 0,
- .bNumConfigurations = 1,
-};
-
-static const struct usb_endpoint_descriptor usb_desc_endp_1[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x01,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x81,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-#if !CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static const struct usb_interface_descriptor usb_desc_iface_1[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1,
- },
-};
-
-#else /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-static const struct usb_interface_descriptor usb_desc_iface_1[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1,
- },
-};
-
-static const struct {
- struct usb_cdc_header_descriptor header;
- struct usb_cdc_call_management_descriptor call_mgmt;
- struct usb_cdc_acm_descriptor acm;
- struct usb_cdc_union_descriptor cdc_union;
-} __attribute__ ((packed)) usb_desc_func_desc_1 = {
- .header = {
- .bFunctionLength = sizeof (struct usb_cdc_header_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
- .bcdCDC = 0x0110,
- },
- .call_mgmt = {
- .bFunctionLength = sizeof (struct usb_cdc_call_management_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
- .bmCapabilities = 0,
- .bDataInterface = 1,
- },
- .acm = {
- .bFunctionLength = sizeof (struct usb_cdc_acm_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_ACM,
- .bmCapabilities = 2, /* SET_LINE_CODING, SET_CONTROL_LINE_STATE,
- GET_LINE_CODING, and SERIAL_STATE
- notification. */
- },
- .cdc_union = {
- .bFunctionLength = sizeof (struct usb_cdc_union_descriptor),
- .bDescriptorType = CS_INTERFACE,
- .bDescriptorSubtype = USB_CDC_TYPE_UNION,
- .bControlInterface = 0,
- .bSubordinateInterface0 = 1,
- },
-};
-
-static const struct usb_endpoint_descriptor usb_desc_endp_1_notif[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
- .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
- .wMaxPacketSize = 16,
- .bInterval = 128,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_1_notif[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_CDC,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_1_notif,
-
- .extra = &usb_desc_func_desc_1,
- .extralen = sizeof (usb_desc_func_desc_1),
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
-# if CONFIG_UCOO_HAL_USB_CDC_ACM
-# error "no enough endpoints to implement CDC ACM"
-# endif
-
-static const struct usb_endpoint_descriptor usb_desc_endp_2[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x02,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_2[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_2,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_STREAM_NB >= 2 */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
-
-static const struct usb_endpoint_descriptor usb_desc_endp_3[] = {
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x03,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
- {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x83,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CONFIG_UCOO_HAL_USB_EP_SIZE,
- .bInterval = 0,
- },
-};
-
-static const struct usb_interface_descriptor usb_desc_iface_3[] = {
- {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 2,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = 0,
-
- .endpoint = usb_desc_endp_3,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_STREAM_NB >= 3 */
-
-#if CONFIG_UCOO_HAL_USB_STREAM_NB > 3
-# error "too many streams requested"
-#endif
-
-#if !CONFIG_UCOO_HAL_USB_CDC_ACM
-
-static const struct usb_interface usb_desc_ifaces[] = {
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1,
- },
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 2
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_2,
- },
-#endif
-#if CONFIG_UCOO_HAL_USB_STREAM_NB >= 3
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_3,
- },
-#endif
-};
-
-#else /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-static const struct usb_interface usb_desc_ifaces[] = {
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1_notif,
- },
- {
- .num_altsetting = 1,
- .altsetting = usb_desc_iface_1,
- },
-};
-
-#endif /* CONFIG_UCOO_HAL_USB_CDC_ACM */
-
-const struct usb_config_descriptor usb_desc_config = {
- .bLength = USB_DT_CONFIGURATION_SIZE,
- .bDescriptorType = USB_DT_CONFIGURATION,
- .wTotalLength = 0,
- .bNumInterfaces = CONFIG_UCOO_HAL_USB_CDC_ACM ? 2 : CONFIG_UCOO_HAL_USB_STREAM_NB,
- .bConfigurationValue = 1,
- .iConfiguration = 0,
- .bmAttributes = 0x80 | (CONFIG_UCOO_HAL_USB_SELF_POWERED ? 0x40 : 0),
- .bMaxPower = CONFIG_UCOO_HAL_USB_MAX_POWER / 2,
-
- .interface = usb_desc_ifaces,
-};
-
diff --git a/ucoo/hal/usb/usb_desc.stm32.h b/ucoo/hal/usb/usb_desc.stm32.h
deleted file mode 100644
index dca84b7..0000000
--- a/ucoo/hal/usb/usb_desc.stm32.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ucoo_hal_usb_usb_desc_stm32_h
-#define ucoo_hal_usb_usb_desc_stm32_h
-/* ucoolib - Microcontroller object oriented library. {{{
- *
- * Copyright (C) 2012 Nicolas Schodet
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * }}} */
-#include <libopencm3/usb/usbstd.h>
-
-/** USB device descriptor. */
-extern const struct usb_device_descriptor usb_desc_dev;
-/** USB configuration descriptor. */
-extern const struct usb_config_descriptor usb_desc_config;
-
-#endif /* ucoo_hal_usb_usb_desc_stm32_h */
diff --git a/ucoo/hal/usb/usb_driver.cc b/ucoo/hal/usb/usb_driver.cc
new file mode 100644
index 0000000..efd8e6c
--- /dev/null
+++ b/ucoo/hal/usb/usb_driver.cc
@@ -0,0 +1,130 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_driver.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+namespace ucoo {
+
+Trace<CONFIG_UCOO_HAL_USB_TRACE> usb_trace;
+
+void
+UsbDriver::register_application (UsbApplication &app)
+{
+ for (auto &ap : applications_)
+ {
+ if (!ap)
+ {
+ ap = &app;
+ return;
+ }
+ }
+ assert_unreachable ();
+}
+
+void
+UsbDriver::set_configuration (int configuration)
+{
+ if (configuration == current_configuration_)
+ return;
+ assert (current_configuration_ == -1); // TODO: handle change.
+ for (auto app : applications_)
+ {
+ if (!app)
+ break;
+ app->handle_configuration_set (configuration);
+ }
+ current_configuration_ = configuration;
+}
+
+void
+UsbDriver::ep_setup (uint8_t address, EpType type, int size,
+ UsbApplication &app)
+{
+ bool in = address & 0x80;
+ int ep = address & 0x7f;
+ assert (ep < END_POINT_MAX);
+ if (in)
+ in_handlers_[ep] = &app;
+ else
+ out_handlers_[ep] = &app;
+ ep_setup (address, type, size);
+}
+
+void
+UsbDriver::handle_reset ()
+{
+ ep_setup (0, EpType::Control, USB_CONTROL_END_POINT_SIZE);
+}
+
+void
+UsbDriver::handle_setup (uint32_t *msg)
+{
+ uint16_t bmRequestType_n_bRequest = (msg[0] >> 0) & 0xffff;
+ uint16_t wValue = (msg[0] >> 16) & 0xffff;
+ uint16_t wIndex = (msg[1] >> 0) & 0xffff;
+ uint16_t wLength = (msg[1] >> 16) & 0xffff;
+ bool ok = false;
+ out_handlers_[0] = nullptr;
+ in_handlers_[0] = nullptr;
+ for (auto app : applications_)
+ {
+ if (!app)
+ break;
+ UsbApplication::SetupResult r = app->handle_setup (
+ bmRequestType_n_bRequest, wValue, wIndex, wLength);
+ if (r == UsbApplication::SetupResult::Handled)
+ {
+ out_handlers_[0] = app;
+ in_handlers_[0] = app;
+ ok = true;
+ break;
+ }
+ else if (r == UsbApplication::SetupResult::Error)
+ break;
+ }
+ if (!ok)
+ ep_stall (0);
+}
+
+void
+UsbDriver::ep_handle_out (uint8_t address, int bcnt)
+{
+ int ep_num = address;
+ if (out_handlers_[ep_num])
+ out_handlers_[ep_num]->ep_handle_out (address, bcnt);
+ else
+ ep_stall (address);
+}
+
+void
+UsbDriver::ep_handle_in (uint8_t address)
+{
+ int ep_num = address & 0x7f;
+ if (in_handlers_[ep_num])
+ in_handlers_[ep_num]->ep_handle_in (address);
+ else
+ ep_stall (address);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_driver.hh b/ucoo/hal/usb/usb_driver.hh
new file mode 100644
index 0000000..3f36b1d
--- /dev/null
+++ b/ucoo/hal/usb/usb_driver.hh
@@ -0,0 +1,120 @@
+#ifndef ucoo_hal_usb_usb_driver_hh
+#define ucoo_hal_usb_usb_driver_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_application.hh"
+
+#include "ucoo/utils/trace.hh"
+#include "config/ucoo/hal/usb.hh"
+
+namespace ucoo {
+
+extern Trace<CONFIG_UCOO_HAL_USB_TRACE> usb_trace;
+
+/// Low level USB driver.
+class UsbDriver
+{
+ public:
+ enum class EpType
+ {
+ Control,
+ Isochronous,
+ Bulk,
+ Interrupt,
+ };
+ public:
+ /// Constructor.
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbDriver (const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ /// No copy constructor.
+ UsbDriver (const UsbDriver &) = delete;
+ /// Register an application, typically done in application constructor.
+ void register_application (UsbApplication &app);
+ /// Enable hardware.
+ virtual void enable () = 0;
+ /// Disable hardware.
+ virtual void disable () = 0;
+ /// Write data to an end point. Return the number of written bytes,
+ /// following bytes will have to be written once there is room in TX FIFO.
+ virtual int ep_write (uint8_t address, const char *data, int size) = 0;
+ /// Signal application have some data to send.
+ virtual void ep_write_ready (uint8_t address) = 0;
+ /// Read data from an end point. Should only be done when data is
+ /// signaled to be available. Return the number of read bytes.
+ virtual int ep_read (uint8_t address, char *data, int size) = 0;
+ /// Signal application can read data (with maximum buffer size).
+ virtual void ep_read_ready (uint8_t address, int size) = 0;
+ /// Stall an end point.
+ virtual void ep_stall (uint8_t address, bool stall = true) = 0;
+ /// Set device address.
+ virtual void set_address (uint8_t address) = 0;
+ /// Set configuration.
+ void set_configuration (int configuration);
+ /// Setup an end point, make an application responsible for it.
+ void ep_setup (uint8_t address, EpType type, int size, UsbApplication &app);
+ protected:
+ /// Setup an end point.
+ virtual void ep_setup (uint8_t address, EpType type, int size) = 0;
+ /// Handle reset, called by driver.
+ void handle_reset ();
+ /// Handle SETUP, called by driver when received.
+ void handle_setup (uint32_t *msg);
+ /// Handle OUT, called by driver when received.
+ void ep_handle_out (uint8_t address, int bcnt);
+ /// Handle IN, called by driver when transmission can be done.
+ void ep_handle_in (uint8_t address);
+ private:
+ enum {
+ APPLICATION_MAX = 3,
+ END_POINT_MAX = 4,
+ };
+ /// Registered applications.
+ UsbApplication *applications_[APPLICATION_MAX];
+ /// Handlers of OUT events.
+ UsbApplication *out_handlers_[END_POINT_MAX];
+ /// Handlers of IN events.
+ UsbApplication *in_handlers_[END_POINT_MAX];
+ /// Basic USB protocol application.
+ UsbApplicationBasic app_basic_;
+ /// Current configuration or -1 if not configured.
+ int current_configuration_ = -1;
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbDriver::UsbDriver (const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : applications_ { nullptr }, out_handlers_ { nullptr },
+ in_handlers_ { nullptr },
+ app_basic_ (*this, device_desc, configuration_desc, string_descs)
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_driver_hh
diff --git a/ucoo/hal/usb/usb_dwc_otg.stm32.cc b/ucoo/hal/usb/usb_dwc_otg.stm32.cc
new file mode 100644
index 0000000..a19fca7
--- /dev/null
+++ b/ucoo/hal/usb/usb_dwc_otg.stm32.cc
@@ -0,0 +1,412 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_dwc_otg.stm32.hh"
+#include "ucoo/hal/usb/usb_def.hh"
+
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/interrupt.arm.hh"
+#include "ucoo/arch/rcc.stm32.hh"
+
+namespace ucoo {
+
+/// Information on USB hardware.
+struct UsbHardware
+{
+ /// Base address.
+ USB_OTG_TypeDef *base;
+ /// RCC identifier.
+ Rcc rcc;
+ /// Corresponding IRQ.
+ Irq irq;
+ /// Used GPIO port
+ GpioPort &gpio_port;
+#ifdef TARGET_stm32f4
+ /// D+ and D- pins.
+ int gpio_dp, gpio_dm;
+ /// GPIO alternate function.
+ int gpio_af;
+#endif
+};
+
+static const UsbHardware usb_hardware[] =
+{
+ { reg::USB_OTG_FS, Rcc::OTGFS, Irq::OTG_FS, GPIOA,
+#ifdef TARGET_stm32f4
+ 12, 11, 10
+#endif
+ },
+#ifdef USB_OTG_HS_BASE
+ { reg::USB_OTG_HS, Rcc::OTGHS, Irq::OTG_HS, GPIOB, 15, 14, 12 },
+#endif
+};
+
+static UsbDriverDwcOtg *usb_instance;
+
+template<>
+void interrupt<Irq::OTG_FS> ()
+{
+ ucoo::assert (usb_instance);
+ usb_instance->isr ();
+}
+
+#ifdef USB_OTG_HS_BASE
+template<>
+void interrupt<Irq::OTG_HS> ()
+{
+ ucoo::assert (usb_instance);
+ usb_instance->isr ();
+}
+#endif
+
+void
+UsbDriverDwcOtg::enable ()
+{
+ assert (!usb_instance);
+ usb_trace ("enable");
+ enabled_ = true;
+ usb_instance = this;
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ /// Setup GPIO (this is an exception of the global scheme where the user
+ /// do this).
+ hard.gpio_port.enable ();
+#ifdef TARGET_stm32f4
+ hard.gpio_port[hard.gpio_dp].af (hard.gpio_af);
+ hard.gpio_port[hard.gpio_dm].af (hard.gpio_af);
+#endif
+ /// Enable clock.
+ rcc_peripheral_clock_enable (hard.rcc);
+ asm volatile ("nop"); // TODO: Do not know why this is needed.
+ asm volatile ("nop");
+ asm volatile ("nop");
+ // Reset.
+ while (!(hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_AHBIDL))
+ ;
+ hard.base->global.GRSTCTL = USB_OTG_GRSTCTL_CSRST;
+ while (hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_CSRST)
+ ;
+ while (!(hard.base->global.GRSTCTL & USB_OTG_GRSTCTL_AHBIDL))
+ ;
+ // Setup USB core.
+ assert (rcc_ahb_freq_hz > 32000000); // Or else, should change TRDT.
+ hard.base->global.GUSBCFG = USB_OTG_GUSBCFG_FDMOD
+ | (6 * USB_OTG_GUSBCFG_TRDT_0) | USB_OTG_GUSBCFG_PHYSEL;
+ hard.base->global.GAHBCFG |= USB_OTG_GAHBCFG_GINT;
+ hard.base->global.GINTMSK |= USB_OTG_GINTMSK_RXFLVLM
+ | USB_OTG_GINTMSK_USBSUSPM | USB_OTG_GINTMSK_USBRST
+ | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_IEPINT
+ | USB_OTG_GINTMSK_SRQIM /* ? */
+ | USB_OTG_GINTMSK_WUIM;
+ // TODO: USB_OTG_GCCFG_VBDEN for F479.
+ hard.base->global.GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
+ hard.base->device.DCFG |= USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD;
+ hard.base->device.DCTL = 0;
+ hard.base->device.DIEPMSK = USB_OTG_DIEPMSK_XFRCM;
+ hard.base->device.DAINTMSK = USB_OTG_DAINTMSK_IEPM;
+ // Enable interrupts.
+ interrupt_enable (hard.irq);
+}
+
+void
+UsbDriverDwcOtg::disable ()
+{
+ if (enabled_)
+ {
+ usb_trace ("disable");
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->device.DCTL = USB_OTG_DCTL_SDIS;
+ interrupt_disable (hard.irq);
+ rcc_peripheral_clock_disable (hard.rcc);
+#ifdef TARGET_stm32f4
+ hard.gpio_port[hard.gpio_dp].input ();
+ hard.gpio_port[hard.gpio_dm].input ();
+#endif
+ usb_instance = nullptr;
+ }
+}
+
+int
+UsbDriverDwcOtg::ep_write (uint8_t address, const char *data, int size)
+{
+ int ep = address & 0x7f;
+ if (size > ep_in_size_[ep])
+ size = ep_in_size_[ep];
+ usb_trace ("write %d %d", ep, size);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ assert (!(hard.base->ep_in[ep].DIEPCTL & USB_OTG_DIEPCTL_EPENA));
+ hard.base->ep_in[ep].DIEPTSIZ = (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | size;
+ hard.base->ep_in[ep].DIEPCTL |=
+ USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
+ const uint32_t *data32 = reinterpret_cast<const uint32_t *> (data);
+ for (int i = 0; i < size; i += 4)
+ hard.base->fifo[ep].FIFO = *data32++;
+ return size;
+}
+
+void
+UsbDriverDwcOtg::ep_write_ready (uint8_t address)
+{
+ int ep = address & 0x7f;
+ usb_trace ("write ready %d", ep);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ irq_flags_t flags = irq_lock ();
+ // Before the interrupt is locked, an interrupt could have been triggered.
+ // This code might call ep_handle_in in this case, but only if no data was
+ // written by the application.
+ if (hard.base->ep_in[ep].DIEPCTL & USB_OTG_DIEPCTL_EPENA)
+ // End point is enabled, will trigger an interrupt when done.
+ ;
+ else if (hard.base->ep_in[ep].DIEPINT & USB_OTG_DIEPINT_XFRC)
+ // Interrupt triggered, waiting to deliver the interrupt.
+ ;
+ else
+ // Restart data flow.
+ ep_handle_in (address);
+ irq_restore (flags);
+}
+
+int
+UsbDriverDwcOtg::ep_read (uint8_t address, char *data, int size)
+{
+ int ep = address;
+ assert (ep == rx_ep_);
+ if (size > rx_length_)
+ size = rx_length_;
+ usb_trace ("read %d %d", ep, size);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t *data32 = reinterpret_cast<uint32_t *> (data);
+ for (int i = 0; i < size / 4; i++)
+ *data32++ = hard.base->fifo[0].FIFO;
+ if (size % 4)
+ {
+ uint32_t w = hard.base->fifo[0].FIFO;
+ uint8_t *data8 = reinterpret_cast<uint8_t *> (data32);
+ for (int i = 0; i < size % 4; i++)
+ {
+ *data8++ = w & 0xff;
+ w >>= 8;
+ }
+ }
+ rx_length_ -= size;
+ if (rx_length_ == 0)
+ rx_ep_ = -1;
+ return size;
+}
+
+void
+UsbDriverDwcOtg::ep_read_ready (uint8_t address, int size)
+{
+ int ep = address;
+ usb_trace ("read ready %d %d", ep, size);
+ if (size >= ep_out_size_[ep])
+ {
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ irq_flags_t flags = irq_lock ();
+ if (!(hard.base->ep_out[ep].DOEPCTL & USB_OTG_DOEPCTL_EPENA))
+ {
+ hard.base->ep_out[ep].DOEPTSIZ = ep_out_doeptsiz_[ep];
+ hard.base->ep_out[ep].DOEPCTL |= USB_OTG_DOEPCTL_EPENA
+ | USB_OTG_DOEPCTL_CNAK;
+ usb_trace ("read ready done");
+ }
+ irq_restore (flags);
+ }
+}
+
+void
+UsbDriverDwcOtg::ep_stall (uint8_t address, bool stall)
+{
+ assert (address == 0 && stall == true);
+ usb_trace ("ep stall %d %d", address, stall);
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->ep_in[0].DIEPCTL |= USB_OTG_DIEPCTL_STALL;
+}
+
+void
+UsbDriverDwcOtg::set_address (uint8_t address)
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ hard.base->device.DCFG |= USB_OTG_DCFG_DAD_0 * address;
+}
+
+void
+UsbDriverDwcOtg::ep_setup (uint8_t address, EpType type, int size)
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ if (address == 0)
+ {
+ usb_trace ("ep setup 0");
+ assert (type == EpType::Control
+ && size == USB_CONTROL_END_POINT_SIZE);
+ hard.base->global.GRXFSIZ = rx_fifo_size_ / 4;
+ fifo_used_ = rx_fifo_size_;
+ hard.base->global.DIEPTXF0_HNPTXFSIZ =
+ (USB_CONTROL_END_POINT_SIZE / 4) << 16 | fifo_used_ / 4;
+ fifo_used_ += USB_CONTROL_END_POINT_SIZE;
+ ep_in_size_[0] = USB_CONTROL_END_POINT_SIZE;
+ ep_out_size_[0] = USB_CONTROL_END_POINT_SIZE;
+ ep_out_doeptsiz_[0] = USB_OTG_DOEPTSIZ_STUPCNT
+ | (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | USB_CONTROL_END_POINT_SIZE;
+ hard.base->ep_out[0].DOEPTSIZ = ep_out_doeptsiz_[0];
+ hard.base->ep_out[0].DOEPCTL = USB_OTG_DOEPCTL_SNAK
+ | USB_OTG_DOEPCTL_USBAEP;
+ hard.base->ep_in[0].DIEPCTL = USB_OTG_DIEPCTL_SNAK
+ | USB_OTG_DIEPCTL_USBAEP;
+ }
+ else
+ {
+ int ep = address & 0x7f;
+ uint32_t epctl =
+ USB_OTG_DOEPCTL_SD0PID_SEVNFRM
+ | USB_OTG_DOEPCTL_SNAK
+ | (type == EpType::Control ? 0 :
+ type == EpType::Isochronous ? USB_OTG_DOEPCTL_EPTYP_0 :
+ type == EpType::Bulk ? USB_OTG_DOEPCTL_EPTYP_1 :
+ USB_OTG_DOEPCTL_EPTYP_1 | USB_OTG_DOEPCTL_EPTYP_0)
+ | USB_OTG_DOEPCTL_USBAEP
+ | size;
+ if (address & 0x80)
+ {
+ usb_trace ("ep setup in %d %d %d", ep, static_cast<int> (type),
+ size);
+ hard.base->global.DIEPTXF[ep - 1] = (size / 4) << 16
+ | fifo_used_ / 4;
+ fifo_used_ += size;
+ ep_in_size_[ep] = size;
+ hard.base->ep_in[ep].DIEPCTL = epctl
+ | (ep * USB_OTG_DIEPCTL_TXFNUM_0);
+ }
+ else
+ {
+ usb_trace ("ep setup out %d %d %d", ep, static_cast<int> (type),
+ size);
+ ep_out_size_[ep] = size;
+ ep_out_doeptsiz_[ep] = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | size;
+ hard.base->ep_out[ep].DOEPCTL = epctl;
+ }
+ }
+}
+
+void
+UsbDriverDwcOtg::isr ()
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t gintsts = hard.base->global.GINTSTS;
+ if (gintsts & USB_OTG_GINTSTS_USBRST)
+ {
+ /* Reset. */
+ usb_trace ("isr reset");
+ hard.base->device.DCFG &= ~USB_OTG_DCFG_DAD;
+ for (int i = 0; i < END_POINT_NB; i++)
+ hard.base->ep_out[i].DOEPCTL = USB_OTG_DOEPCTL_SNAK;
+ handle_reset ();
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_USBRST;
+ }
+ if (gintsts & USB_OTG_GINTSTS_ENUMDNE)
+ {
+ /* Enumeration done. */
+ usb_trace ("isr enumeration done");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
+ }
+ if (gintsts & USB_OTG_GINTSTS_RXFLVL)
+ {
+ /* RX FIFO not empty. */
+ isr_rx_fifo ();
+ }
+ if (gintsts & USB_OTG_GINTSTS_USBSUSP)
+ {
+ /* USB suspend. */
+ usb_trace ("isr suspend");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_USBSUSP;
+ }
+ if (gintsts & USB_OTG_GINTSTS_IEPINT)
+ {
+ /* IN end point interrupt. */
+ uint32_t daint = hard.base->device.DAINT;
+ for (int i = 0; i < END_POINT_NB; i++)
+ {
+ if (daint & (1 << i))
+ {
+ usb_trace ("isr in xfrc %d", i);
+ ep_handle_in (i ? 0x80 | i : 0);
+ hard.base->ep_in[i].DIEPINT = USB_OTG_DIEPINT_XFRC;
+ }
+ }
+ }
+ if (gintsts & USB_OTG_GINTSTS_DISCINT)
+ {
+ /* Disconnect. */
+ usb_trace ("isr disconnect");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_DISCINT;
+ }
+ if (gintsts & USB_OTG_GINTSTS_SRQINT)
+ {
+ /* New session. */
+ usb_trace ("isr new session");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_SRQINT;
+ }
+ if (gintsts & USB_OTG_GINTSTS_WKUINT)
+ {
+ /* Wake up. */
+ usb_trace ("isr wake up");
+ hard.base->global.GINTSTS = USB_OTG_GINTSTS_WKUINT;
+ }
+}
+
+void
+UsbDriverDwcOtg::isr_rx_fifo ()
+{
+ const auto &hard = usb_hardware[static_cast<int> (inst_)];
+ uint32_t rx = hard.base->global.GRXSTSP;
+ uint32_t pkt_status = rx & USB_OTG_GRXSTSP_PKTSTS;
+ int ep = rx & USB_OTG_GRXSTSP_EPNUM;
+ int bcnt = (rx & USB_OTG_GRXSTSP_BCNT) >> USB_OTG_GRXSTSP_BCNT_Pos;
+ if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_Setup)
+ {
+ usb_trace ("isr rx setup");
+ assert (ep == 0 && bcnt == 8);
+ setup_buf_[0] = hard.base->fifo[0].FIFO;
+ setup_buf_[1] = hard.base->fifo[0].FIFO;
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_SetupCompleted)
+ {
+ usb_trace ("isr rx setup completed");
+ handle_setup (&setup_buf_[0]);
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_Out)
+ {
+ usb_trace ("isr rx out %d %d", ep, bcnt);
+ rx_ep_ = ep;
+ rx_length_ = bcnt;
+ ep_handle_out (ep, bcnt);
+ assert (rx_length_ == 0);
+ }
+ else if (pkt_status == USB_OTG_GRXSTSP_PKTSTS_OutCompleted)
+ usb_trace ("isr rx out completed");
+ else
+ usb_trace ("isr rx other %d",
+ pkt_status >> USB_OTG_GRXSTSP_PKTSTS_Pos);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb_dwc_otg.stm32.hh b/ucoo/hal/usb/usb_dwc_otg.stm32.hh
new file mode 100644
index 0000000..dec71ec
--- /dev/null
+++ b/ucoo/hal/usb/usb_dwc_otg.stm32.hh
@@ -0,0 +1,94 @@
+#ifndef ucoo_hal_usb_usb_dwc_otg_stm32_hh
+#define ucoo_hal_usb_usb_dwc_otg_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb_driver.hh"
+
+namespace ucoo {
+
+/// Low level USB driver.
+class UsbDriverDwcOtg : public UsbDriver
+{
+ public:
+ enum
+ {
+ END_POINT_NB = 4,
+ };
+ enum class Instance
+ {
+ OTG_FS,
+ OTG_HS,
+ };
+ public:
+ /// Constructor for a USB OTG instance.
+ template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+ UsbDriverDwcOtg (Instance inst,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs);
+ /// Destructor, disable.
+ ~UsbDriverDwcOtg () { disable (); }
+ void enable () override;
+ void disable () override;
+ int ep_write (uint8_t address, const char *data, int size) override;
+ void ep_write_ready (uint8_t address) override;
+ int ep_read (uint8_t address, char *data, int size) override;
+ void ep_read_ready (uint8_t address, int size) override;
+ void ep_stall (uint8_t address, bool stall = true) override;
+ void set_address (uint8_t address) override;
+ protected:
+ void ep_setup (uint8_t address, EpType type, int size) override;
+ public:
+ void isr ();
+ private:
+ void isr_rx_fifo ();
+ private:
+ Instance inst_;
+ bool enabled_ = false;
+ const int rx_fifo_size_ = 512;
+ int rx_ep_ = -1;
+ int rx_length_ = -1;
+ int ep_out_size_[END_POINT_NB];
+ int ep_in_size_[END_POINT_NB];
+ uint32_t ep_out_doeptsiz_[END_POINT_NB];
+ int fifo_used_ = 0;
+ uint32_t setup_buf_[2];
+};
+
+template<typename DeviceDesc, typename ConfigurationDesc,
+ typename... StringDescs>
+UsbDriverDwcOtg::UsbDriverDwcOtg (
+ Instance inst,
+ const DeviceDesc &device_desc,
+ const ConfigurationDesc &configuration_desc,
+ const details::UsbDescs<StringDescs...> &string_descs)
+ : UsbDriver (device_desc, configuration_desc, string_descs),
+ inst_ (inst)
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_dwc_otg_stm32_hh
diff --git a/ucoo/math/test/Makefile b/ucoo/math/test/Makefile
index 353bc10..c0a17ee 100644
--- a/ucoo/math/test/Makefile
+++ b/ucoo/math/test/Makefile
@@ -4,6 +4,6 @@ TARGETS = host stm32f4
PROGS = test_math
test_math_SOURCES = test_math.cc
-MODULES = ucoo/math ucoo/utils ucoo/base/test ucoo/hal/usb
+MODULES = ucoo/math ucoo/utils ucoo/base/test ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/utils/bits.hh b/ucoo/utils/bits.hh
new file mode 100644
index 0000000..3c1916b
--- /dev/null
+++ b/ucoo/utils/bits.hh
@@ -0,0 +1,45 @@
+#ifndef ucoo_utils_bits_hh
+#define ucoo_utils_bits_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+template<typename T>
+T
+bits (int index)
+{
+ return 1 << index;
+}
+
+template<typename T, typename... Indices>
+T
+bits (int index, Indices... indices)
+{
+ return bits<T> (index) | bits<T> (indices...);
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_bits_hh
diff --git a/ucoo/utils/buffer.hh b/ucoo/utils/buffer.hh
new file mode 100644
index 0000000..b665d25
--- /dev/null
+++ b/ucoo/utils/buffer.hh
@@ -0,0 +1,74 @@
+#ifndef ucoo_utils_buffer_hh
+#define ucoo_utils_buffer_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Buffer with linear reads and writes. Looks like a fifo but without thread
+/// safety and with poorer performance, but access is linear.
+///
+/// Warning: no safety net, make sure not to read non present elements or to
+/// write more elements than available space.
+template<typename T, int max_size>
+class Buffer
+{
+ public:
+ /// Constructor, empty buffer.
+ Buffer ();
+ /// Test whether the buffer is empty.
+ bool empty () const;
+ /// Test whether the buffer is full (no element can be written, but see
+ /// rewind()).
+ bool full () const;
+ /// Return the number of available elements.
+ int size () const;
+ /// Return the available space for elements.
+ int room () const;
+ /// Return pointer to readable elements.
+ const T *read () const;
+ /// Drop a number of elements after they have been read (or not).
+ void drop (int n);
+ /// Return pointer to readable elements and drop them (remember: not
+ /// thread safe).
+ const T *read (int n);
+ /// Return pointer to writable space.
+ T *write ();
+ /// Increase the number of available elements (just written).
+ void written (int n);
+ /// Return pointer to writable space and increase the number of available
+ /// elements (remember: not thread safe).
+ T *write (int n);
+ /// Move data to begin of buffer to make room after it.
+ void rewind ();
+ private:
+ T data_[max_size];
+ T *begin_, *end_;
+};
+
+} // namespace ucoo
+
+#include "buffer.tcc"
+
+#endif // ucoo_utils_buffer_hh
diff --git a/ucoo/utils/buffer.tcc b/ucoo/utils/buffer.tcc
new file mode 100644
index 0000000..bc25bb7
--- /dev/null
+++ b/ucoo/utils/buffer.tcc
@@ -0,0 +1,125 @@
+#ifndef ucoo_utils_buffer_tcc
+#define ucoo_utils_buffer_tcc
+// buffer.tcc
+// {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Contact :
+// Web: http://ni.fr.eu.org/
+// Email: <nico at ni.fr.eu.org>
+// }}}
+#include <algorithm>
+
+namespace ucoo {
+
+template<typename T, int max_size>
+Buffer<T, max_size>::Buffer ()
+ : begin_ (data_), end_ (data_)
+{
+}
+
+template<typename T, int max_size>
+bool
+Buffer<T, max_size>::empty () const
+{
+ return begin_ == end_;
+}
+
+template<typename T, int max_size>
+bool
+Buffer<T, max_size>::full () const
+{
+ return end_ == &data_[max_size];
+}
+
+template<typename T, int max_size>
+int
+Buffer<T, max_size>::size () const
+{
+ return end_ - begin_;
+}
+
+template<typename T, int max_size>
+int
+Buffer<T, max_size>::room () const
+{
+ return &data_[max_size] - end_;
+}
+
+template<typename T, int max_size>
+const T *
+Buffer<T, max_size>::read () const
+{
+ return begin_;
+}
+
+template<typename T, int max_size>
+void
+Buffer<T, max_size>::drop (int n)
+{
+ begin_ += n;
+ if (empty ())
+ begin_ = end_ = &data_[0];
+}
+
+template<typename T, int max_size>
+const T *
+Buffer<T, max_size>::read (int n)
+{
+ drop (n);
+ return read ();
+}
+
+template<typename T, int max_size>
+T *
+Buffer<T, max_size>::write ()
+{
+ return end_;
+}
+
+template<typename T, int max_size>
+void
+Buffer<T, max_size>::written (int n)
+{
+ end_ += n;
+}
+
+template<typename T, int max_size>
+T *
+Buffer<T, max_size>::write (int n)
+{
+ T *r = write ();
+ written (n);
+ return r;
+}
+
+template<typename T, int max_size>
+void
+Buffer<T, max_size>::rewind ()
+{
+ if (begin_ != &data_[0])
+ {
+ std::copy (begin_, end_, &data_[0]);
+ end_ -= begin_ - &data_[0];
+ begin_ = &data_[0];
+ }
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_buffer_tcc
diff --git a/ucoo/utils/delay.arm.cc b/ucoo/utils/delay.arm.cc
index 244d521..086ca4c 100644
--- a/ucoo/utils/delay.arm.cc
+++ b/ucoo/utils/delay.arm.cc
@@ -22,12 +22,11 @@
//
// }}}
#include "delay.arm.hh"
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
#include <algorithm>
-#include <libopencm3/cm3/systick.h>
-#include <libopencm3/stm32/rcc.h>
-
namespace ucoo {
void
@@ -35,21 +34,21 @@ delay_us (int us)
{
// Suppose that frequency is a multiple of 8 MHz (to avoid 64 bit
// division).
- int systick_mhz = rcc_ahb_frequency / (8 * 1000000);
+ int systick_mhz = rcc_ahb_freq_hz / (8 * 1000000);
int cycles = systick_mhz * us;
- STK_CSR = 0;
+ reg::SysTick->CTRL = 0;
// Loop several times if cycles is too big for the systick timer. Some
// nanoseconds are lost every second, I can live with that, it simplifies
// code.
while (cycles)
{
int loop_cycles = std::min (1 << 24, cycles);
- STK_RVR = loop_cycles - 1;
- STK_CVR = 0;
- STK_CSR = STK_CSR_ENABLE;
- while (!(STK_CSR & STK_CSR_COUNTFLAG))
+ reg::SysTick->LOAD = loop_cycles - 1;
+ reg::SysTick->VAL = 0;
+ reg::SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
+ while (!(reg::SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
;
- STK_CSR = 0;
+ reg::SysTick->CTRL = 0;
cycles -= loop_cycles;
}
}
@@ -59,16 +58,16 @@ delay_ns (int ns)
{
// Suppose that frequency is a multiple of 1 MHz (to avoid 64 bit
// division).
- int hclock_mhz = rcc_ahb_frequency / 1000000;
+ int hclock_mhz = rcc_ahb_freq_hz / 1000000;
int cycles = (hclock_mhz * ns + 999) / 1000;
- STK_CSR = 0;
+ reg::SysTick->CTRL = 0;
// Loop once, ns is supposed to be small.
- STK_RVR = cycles - 1;
- STK_CVR = 0;
- STK_CSR = STK_CSR_CLKSOURCE_AHB | STK_CSR_ENABLE;
- while (!(STK_CSR & STK_CSR_COUNTFLAG))
+ reg::SysTick->LOAD = cycles - 1;
+ reg::SysTick->VAL = 0;
+ reg::SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
+ while (!(reg::SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
;
- STK_CSR = 0;
+ reg::SysTick->CTRL = 0;
}
} // namespace ucoo
diff --git a/ucoo/utils/irq_locked.hh b/ucoo/utils/irq_locked.hh
new file mode 100644
index 0000000..5f4a1a0
--- /dev/null
+++ b/ucoo/utils/irq_locked.hh
@@ -0,0 +1,45 @@
+#ifndef ucoo_utils_irq_locked_hh
+#define ucoo_utils_irq_locked_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// Make sure interrupts are unlocked when scope is exited.
+class IrqLocked
+{
+ irq_flags_t flags_;
+ public:
+ /// Constructor, lock interrupts.
+ IrqLocked () { flags_ = irq_lock (); }
+ /// Destructor, unlock.
+ ~IrqLocked () { irq_restore (flags_); }
+ /// No copy constructor.
+ IrqLocked (const IrqLocked &) = delete;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_utils_irq_locked_hh
diff --git a/ucoo/utils/rate_limit.tcc b/ucoo/utils/rate_limit.tcc
index 0d034e3..938c20f 100644
--- a/ucoo/utils/rate_limit.tcc
+++ b/ucoo/utils/rate_limit.tcc
@@ -46,7 +46,7 @@ template<typename Timer>
void
RateLimit<Timer>::set_limit (int rate_num, int rate_denum)
{
- int freq = timer_.get_freq ();
+ int freq = timer_.get_freq_hz ();
interval_ = freq * rate_denum / rate_num;
ucoo::assert (interval_ <= Timer::max / 2 + 1);
next_ = timer_.get_value ();
diff --git a/ucoo/utils/table_lookup.hh b/ucoo/utils/table_lookup.hh
new file mode 100644
index 0000000..ffd8e3d
--- /dev/null
+++ b/ucoo/utils/table_lookup.hh
@@ -0,0 +1,51 @@
+#ifndef ucoo_utils_table_lookup_hh
+#define ucoo_utils_table_lookup_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+template<typename K, typename V>
+struct LookupTable
+{
+ K key;
+ V val;
+};
+
+template<typename K, typename V, int N>
+V
+simple_table_lookup (const LookupTable<K, V> (&t)[N], K key)
+{
+ for (int i = 0; i < N; i++)
+ {
+ if (t[i].key == key)
+ return t[i].val;
+ }
+ assert_unreachable ();
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_table_lookup_hh
diff --git a/ucoo/utils/test/Makefile b/ucoo/utils/test/Makefile
index 6f2094e..1255cae 100644
--- a/ucoo/utils/test/Makefile
+++ b/ucoo/utils/test/Makefile
@@ -9,6 +9,6 @@ test_crc_SOURCES = test_crc.cc
test_function_SOURCES = test_function.cc
test_pool_SOURCES = test_pool.cc
-MODULES = ucoo/utils ucoo/base/test ucoo/hal/usb
+MODULES = ucoo/utils ucoo/base/test ucoo/hal/usb ucoo/hal/gpio
include $(BASE)/build/top.mk
diff --git a/ucoo/utils/test/test_delay.cc b/ucoo/utils/test/test_delay.cc
index b56c7c1..87945d3 100644
--- a/ucoo/utils/test/test_delay.cc
+++ b/ucoo/utils/test/test_delay.cc
@@ -23,39 +23,47 @@
// }}}
#include "ucoo/utils/delay.hh"
#include "ucoo/arch/arch.hh"
-
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/common.hh"
int
main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
- rcc_periph_clock_enable (RCC_GPIOD);
- gpio_mode_setup (GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
- GPIO12 | GPIO13 | GPIO14 | GPIO15);
- gpio_clear (GPIOD, GPIO12 | GPIO13 | GPIO14 | GPIO15);
+ ucoo::GPIOD.enable ();
+ ucoo::Gpio leds[] =
+ {
+ ucoo::GPIOD[12],
+ ucoo::GPIOD[13],
+ ucoo::GPIOD[14],
+ ucoo::GPIOD[15],
+ };
+ for (int i = 0; i < ucoo::lengthof (leds); i++)
+ {
+ leds[i].output ();
+ leds[i].reset ();
+ }
int i, j;
while (1)
{
for (i = 0; i < 4; i++)
{
- gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ leds[i % 4].toggle ();
ucoo::delay (1);
}
for (i = 0; i < 16; i++)
{
- gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ leds[i % 4].toggle ();
ucoo::delay_ms (250);
}
for (i = 0; i < 16000; i++)
{
- gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ leds[i % 4].toggle ();
ucoo::delay_us (250);
}
for (i = 0; i < 16; i++)
{
- gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ leds[i % 4].toggle ();
for (j = 0; j < 1000; j++)
ucoo::delay_us (250);
}
diff --git a/ucoo/utils/trace.hh b/ucoo/utils/trace.hh
index dbbf442..7cae33d 100644
--- a/ucoo/utils/trace.hh
+++ b/ucoo/utils/trace.hh
@@ -42,7 +42,7 @@ class TraceBuffer
/// Maximum number of arguments.
static const int args_nb = 4;
/// Maximum number of trace entries.
- static const int entries_nb = 32;
+ static const int entries_nb = 512;
public:
/// Constructor.
TraceBuffer (const Timestamp &timestamp = Timestamp ());
diff --git a/ucoo/utils/trace.tcc b/ucoo/utils/trace.tcc
index e48c5d8..8d1fc29 100644
--- a/ucoo/utils/trace.tcc
+++ b/ucoo/utils/trace.tcc
@@ -68,7 +68,9 @@ TraceBuffer<Timestamp>::operator() (const char *str, int a0, int a1, int a2)
{
timestamp_ (entries[index]);
entries[index].str = str;
- entries[index].args = { a0, a1, a2 };
+ entries[index].args[0] = a0;
+ entries[index].args[1] = a1;
+ entries[index].args[2] = a2;
index = (index + 1) % entries_nb;
}