diff --git a/.gitignore b/.gitignore
index f9ecd85b..88c8143e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,11 @@
*.list
*.map
*.stylecheck
-nbproject
+generated.*.ld
.gdb_history
.DS_Store
+
+# Project files from idea/netbeans/eclipse
+nbproject/
+.idea/
+.project
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..fe81f68b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: c
+script:
+ - make
+
+addons:
+ apt:
+ sources:
+ - sourceline: 'ppa:team-gcc-arm-embedded/ppa'
+ packages:
+ - gcc-arm-embedded
+
+notifications:
+ irc:
+ channels:
+ - "chat.freenode.net#libopencm3"
+ use_notice: true
diff --git a/Makefile b/Makefile
index 7204b1d7..1e986542 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,7 @@ TARGETS += lpc/lpc13xx lpc/lpc17xx #lpc/lpc43xx
TARGETS += tiva/lm3s tiva/lm4f
TARGETS += efm32/efm32tg efm32/efm32g efm32/efm32lg efm32/efm32gg
TARGETS += vf6xx
+TARGETS += sam/d
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
@@ -73,7 +74,9 @@ $(EXAMPLE_DIRS): lib
examples: $(EXAMPLE_DIRS)
$(Q)true
-clean: $(EXAMPLE_DIRS:=.clean) styleclean
+examplesclean: $(EXAMPLE_DIRS:=.clean)
+
+clean: examplesclean styleclean
$(Q)$(MAKE) -C libopencm3 clean
stylecheck: $(EXAMPLE_DIRS:=.stylecheck)
diff --git a/README.md b/README.md
index 41c1d9ec..a79bc9e4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# README
+[![Build Status](https://travis-ci.org/libopencm3/libopencm3-examples.svg?branch=master)](https://travis-ci.org/libopencm3/libopencm3-examples)
[![Gitter channel](https://badges.gitter.im/libopencm3/discuss.svg)](https://gitter.im/libopencm3/discuss)
@@ -10,7 +11,9 @@ various ARM Cortex-M microcontrollers.
For more information visit http://libopencm3.org
The examples are meant as starting points for different subsystems on multitude
-of platforms.
+of platforms. If you're just looking to test your build environment and hardware,
+the [libopencm3-miniblink](https://github.com/libopencm3/libopencm3-miniblink)
+may be more useful, as it covers _many_ more boards, but it is much more limited.
Feel free to add new examples and send them to us either via the mailinglist or
preferably via a github pull request.
@@ -29,34 +32,30 @@ The makefiles are generally useable for your own projects with
only minimal changes for the libopencm3 install path (See Reuse)
## Make Flash Target
+
+Please note, the "make flash" target is complicated and not always self-consistent. Please see: https://github.com/libopencm3/libopencm3-examples/issues/34
+
For flashing the 'miniblink' example (after you built libopencm3 and the
examples by typing 'make' at the top-level directory) onto the Olimex
STM32-H103 eval board (ST STM32F1 series microcontroller), you can execute:
cd examples/stm32/f1/stm32-h103/miniblink
- make flash
+ make flash V=1
The Makefiles of the examples are configured to use a certain OpenOCD
flash programmer, you might need to change some of the variables in the
Makefile if you use a different one.
-The make flash target also supports a few other programmers. If you provide the
-Black Magic Probe serial port the target will automatically choose to program
-via Black Magic Probe. For example on linux you would do the following:
+To program via a Black Magic Probe, simply provide the serial port, eg:
cd examples/stm32/f1/stm32-h103/miniblink
make flash BMP_PORT=/dev/ttyACM0
-This will also work with discovery boards that got the st-link firmware
-replaced with the Black Magic Probe firmware.
-
-In case you did not replace the firmware you can program using the st-flash
-program by invoking the stlink-flash target:
+To program via texane/stlink (st-flash utility), use the special target:
cd examples/stm32/f1/stm32vl-discovery/miniblink
make miniblink.stlink-flash
-
If you rather use GDB to connect to the st-util you can provide the STLINK\_PORT
to the flash target.
@@ -114,69 +113,14 @@ This example uses the st-util by texane that you can find on [GitHub](https://gi
cd examples/stm32/f1/stm32vl-discovery/miniblink
arm-none-eabi-gdb miniblink.elf
- tar extended-remote :4242
+ target extended-remote :4242
load
run
## Reuse
-If you want to use libopencm3 in your own project, this examples repository
-shows the general way. (If there's interest, we can make a stub template
-repository)
-
-1. Create an empty repository
-
- mkdir mycoolrobot && cd mycoolrobot && git init .
-
-2. Add libopencm3 as a submodule
-
- git submodule add https://github.com/libopencm3/libopencm3
-
-
-3. Grab a copy of the basic rules
-These urls grab the latest from the libopencm3-examples repository
-
- wget \
- https://raw.githubusercontent.com/libopencm3/libopencm3-examples/master/examples/Makefile.rules \
- -O libopencm3.rules.mk
-
-4. Grab a copy of your target Makefile in this case, for STM32L1
-
- wget \
- https://raw.githubusercontent.com/libopencm3/libopencm3-examples/master/examples/stm32/l1/Makefile.include \
- -O libopencm3.target.mk
-
-5. Edit paths in `libopencm3.target.mk`
-Edit the _last_ line of `libopencm3.target.mk` and change the include to read
-include `../libopencm3.rules.mk` (the amount of .. depends on where you put your
-project in the next step..
-
-6. beg/borrow/steal an example project
-For sanity's sake, use the same target as the makefile you grabbed up above)
-
- cp -a \
- somewhere/libopencm3-examples/examples/stm32/l1/stm32ldiscovery/miniblink \
- myproject
-
-Add the path to OPENCM3\_DIR, and modify the path to makefile include
-
+If you want to use libopencm3 in your own project, the _easiest_ way is
+to use the template repository we created for this purpose.
- diff -u
- ---
- 2014-01-24 21:10:52.687477831 +0000
- +++ Makefile 2014-03-23 12:27:57.696088076 +0000
- @@ -19,7 +19,8 @@
-
- BINARY = miniblink
-
- +OPENCM3_DIR=../libopencm3
- LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/l1/stm32l15xxb.ld
-
- -include ../../Makefile.include
- +include ../libopencm3.target.mk
-
-You're done :)
+See https://github.com/libopencm3/libopencm3-template
-You need to run "make" inside the libopencm3 directory once to build the
-library, then you can just run make/make clean in your project directory as
-often as you like.
diff --git a/examples/lpc/lpc13xx/Makefile.include b/examples/lpc/lpc13xx/Makefile.include
index 6371a217..f0efdf57 100644
--- a/examples/lpc/lpc13xx/Makefile.include
+++ b/examples/lpc/lpc13xx/Makefile.include
@@ -29,7 +29,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_TARGET ?= lpc13xx
################################################################################
# Black Magic Probe specific variables
@@ -41,4 +41,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/lpc/lpc13xx/lpc-p1343/lpc-p1343.ld b/examples/lpc/lpc13xx/lpc-p1343/lpc-p1343.ld
index bea49c8b..6e66ccfb 100644
--- a/examples/lpc/lpc13xx/lpc-p1343/lpc-p1343.ld
+++ b/examples/lpc/lpc13xx/lpc-p1343/lpc-p1343.ld
@@ -27,4 +27,4 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_lpc13xx.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/lpc/lpc17xx/Makefile.include b/examples/lpc/lpc17xx/Makefile.include
index d0c102a2..d66e08af 100644
--- a/examples/lpc/lpc17xx/Makefile.include
+++ b/examples/lpc/lpc17xx/Makefile.include
@@ -30,7 +30,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_TARGET ?= lpc17xx
################################################################################
# Black Magic Probe specific variables
@@ -42,4 +42,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/lpc/lpc17xx/blueboard-lpc1768-h/blueboard-lpc1768-h.ld b/examples/lpc/lpc17xx/blueboard-lpc1768-h/blueboard-lpc1768-h.ld
index e2e480ff..4d750318 100644
--- a/examples/lpc/lpc17xx/blueboard-lpc1768-h/blueboard-lpc1768-h.ld
+++ b/examples/lpc/lpc17xx/blueboard-lpc1768-h/blueboard-lpc1768-h.ld
@@ -29,4 +29,4 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_lpc17xx.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/lpc/lpc43xx/Makefile.include b/examples/lpc/lpc43xx/Makefile.include
index fd9218da..2f626716 100644
--- a/examples/lpc/lpc43xx/Makefile.include
+++ b/examples/lpc/lpc43xx/Makefile.include
@@ -32,7 +32,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_TARGET ?= lpc4357
################################################################################
# Black Magic Probe specific variables
@@ -44,4 +44,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/Makefile.rules b/examples/rules.mk
similarity index 59%
rename from examples/Makefile.rules
rename to examples/rules.mk
index 8fc56ffb..c1a5dade 100644
--- a/examples/Makefile.rules
+++ b/examples/rules.mk
@@ -42,13 +42,14 @@ STFLASH = $(shell which st-flash)
STYLECHECK := /checkpatch.pl
STYLECHECKFLAGS := --no-tree -f --terse --mailback
STYLECHECKFILES := $(shell find . -name '*.[ch]')
+OPT := -Os
+DEBUG := -ggdb3
+CSTD ?= -std=c99
###############################################################################
# Source files
-LDSCRIPT ?= $(BINARY).ld
-
OBJS += $(BINARY).o
@@ -71,48 +72,69 @@ ifeq ($(V),1)
$(info Using $(OPENCM3_DIR) path to library)
endif
-INCLUDE_DIR = $(OPENCM3_DIR)/include
-LIB_DIR = $(OPENCM3_DIR)/lib
-SCRIPT_DIR = $(OPENCM3_DIR)/scripts
+define ERR_DEVICE_LDSCRIPT_CONFLICT
+You can either specify DEVICE=blah, and have the LDSCRIPT generated,
+or you can provide LDSCRIPT, and ensure CPPFLAGS, LDFLAGS and LDLIBS
+all contain the correct values for the target you wish to use.
+You cannot provide both!
+endef
+
+ifeq ($(strip $(DEVICE)),)
+# Old style, assume LDSCRIPT exists
+DEFS += -I$(OPENCM3_DIR)/include
+LDFLAGS += -L$(OPENCM3_DIR)/lib
+LDLIBS += -l$(LIBNAME)
+LDSCRIPT ?= $(BINARY).ld
+else
+# New style, assume device is provided, and we're generating the rest.
+ifneq ($(strip $(LDSCRIPT)),)
+$(error $(ERR_DEVICE_LDSCRIPT_CONFLICT))
+endif
+include $(OPENCM3_DIR)/mk/genlink-config.mk
+endif
+
+OPENCM3_SCRIPT_DIR = $(OPENCM3_DIR)/scripts
+EXAMPLES_SCRIPT_DIR = $(OPENCM3_DIR)/../scripts
###############################################################################
# C flags
-CFLAGS += -Os -g
-CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration
-CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
-CFLAGS += -fno-common -ffunction-sections -fdata-sections
+TGT_CFLAGS += $(OPT) $(CSTD) $(DEBUG)
+TGT_CFLAGS += $(ARCH_FLAGS)
+TGT_CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration
+TGT_CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
+TGT_CFLAGS += -fno-common -ffunction-sections -fdata-sections
###############################################################################
# C++ flags
-CXXFLAGS += -Os -g
-CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++
-CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
+TGT_CXXFLAGS += $(OPT) $(CXXSTD) $(DEBUG)
+TGT_CXXFLAGS += $(ARCH_FLAGS)
+TGT_CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++
+TGT_CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
###############################################################################
# C & C++ preprocessor common flags
-CPPFLAGS += -MD
-CPPFLAGS += -Wall -Wundef
-CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS)
+TGT_CPPFLAGS += -MD
+TGT_CPPFLAGS += -Wall -Wundef
+TGT_CPPFLAGS += $(DEFS)
###############################################################################
# Linker flags
-LDFLAGS += --static -nostartfiles
-LDFLAGS += -L$(LIB_DIR)
-LDFLAGS += -T$(LDSCRIPT)
-LDFLAGS += -Wl,-Map=$(*).map
-LDFLAGS += -Wl,--gc-sections
+TGT_LDFLAGS += --static -nostartfiles
+TGT_LDFLAGS += -T$(LDSCRIPT)
+TGT_LDFLAGS += $(ARCH_FLAGS) $(DEBUG)
+TGT_LDFLAGS += -Wl,-Map=$(*).map -Wl,--cref
+TGT_LDFLAGS += -Wl,--gc-sections
ifeq ($(V),99)
-LDFLAGS += -Wl,--print-gc-sections
+TGT_LDFLAGS += -Wl,--print-gc-sections
endif
###############################################################################
# Used libraries
-LDLIBS += -l$(LIBNAME)
LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
###############################################################################
@@ -130,14 +152,33 @@ bin: $(BINARY).bin
hex: $(BINARY).hex
srec: $(BINARY).srec
list: $(BINARY).list
+GENERATED_BINARIES=$(BINARY).elf $(BINARY).bin $(BINARY).hex $(BINARY).srec $(BINARY).list $(BINARY).map
images: $(BINARY).images
flash: $(BINARY).flash
+# Either verify the user provided LDSCRIPT exists, or generate it.
+ifeq ($(strip $(DEVICE)),)
$(LDSCRIPT):
ifeq (,$(wildcard $(LDSCRIPT)))
$(error Unable to find specified linker script: $(LDSCRIPT))
endif
+else
+include $(OPENCM3_DIR)/mk/genlink-rules.mk
+endif
+
+$(OPENCM3_DIR)/lib/lib$(LIBNAME).a:
+ifeq (,$(wildcard $@))
+ $(warning $(LIBNAME).a not found, attempting to rebuild in $(OPENCM3_DIR))
+ $(MAKE) -C $(OPENCM3_DIR)
+endif
+
+# Define a helper macro for debugging make errors online
+# you can type "make print-OPENCM3_DIR" and it will show you
+# how that ended up being resolved by all of the included
+# makefiles.
+print-%:
+ @echo $*=$($*)
%.images: %.bin %.hex %.srec %.list %.map
@#printf "*** $* images generated ***\n"
@@ -158,32 +199,32 @@ $(LDSCRIPT):
@#printf " OBJDUMP $(*).list\n"
$(Q)$(OBJDUMP) -S $(*).elf > $(*).list
-%.elf %.map: $(OBJS) $(LDSCRIPT)
+%.elf %.map: $(OBJS) $(LDSCRIPT) $(OPENCM3_DIR)/lib/lib$(LIBNAME).a
@#printf " LD $(*).elf\n"
- $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf
+ $(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(*).elf
%.o: %.c
@#printf " CC $(*).c\n"
- $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).c
+ $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c
%.o: %.cxx
@#printf " CXX $(*).cxx\n"
- $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cxx
+ $(Q)$(CXX) $(TGT_CXXFLAGS) $(CXXFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).cxx
%.o: %.cpp
@#printf " CXX $(*).cpp\n"
- $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cpp
+ $(Q)$(CXX) $(TGT_CXXFLAGS) $(CXXFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).cpp
clean:
@#printf " CLEAN\n"
- $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map
+ $(Q)$(RM) $(GENERATED_BINARIES) generated.* $(OBJS) $(OBJS:%.o=%.d)
stylecheck: $(STYLECHECKFILES:=.stylecheck)
styleclean: $(STYLECHECKFILES:=.styleclean)
# the cat is due to multithreaded nature - we like to have consistent chunks of text on the output
%.stylecheck: %
- $(Q)$(SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \
+ $(Q)$(OPENCM3_SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \
if [ -s $*.stylecheck ]; then \
cat $*.stylecheck; \
else \
@@ -196,46 +237,31 @@ styleclean: $(STYLECHECKFILES:=.styleclean)
%.stlink-flash: %.bin
@printf " FLASH $<\n"
- $(Q)$(STFLASH) write $(*).bin 0x8000000
+ $(STFLASH) write $(*).bin 0x8000000
-ifeq ($(STLINK_PORT),)
ifeq ($(BMP_PORT),)
-ifeq ($(OOCD_SERIAL),)
-%.flash: %.hex
+ifeq ($(OOCD_FILE),)
+%.flash: %.elf
@printf " FLASH $<\n"
- @# IMPORTANT: Don't use "resume", only "reset" will work correctly!
- $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
- -f board/$(OOCD_BOARD).cfg \
- -c "init" -c "reset init" \
- -c "flash write_image erase $(*).hex" \
- -c "reset" \
- -c "shutdown" $(NULL)
+ (echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \
+ $(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
+ -f target/$(OOCD_TARGET).cfg \
+ -c "program $(*).elf verify reset exit" \
+ $(NULL)
else
-%.flash: %.hex
+%.flash: %.elf
@printf " FLASH $<\n"
- @# IMPORTANT: Don't use "resume", only "reset" will work correctly!
- $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
- -f board/$(OOCD_BOARD).cfg \
- -c "ft2232_serial $(OOCD_SERIAL)" \
- -c "init" -c "reset init" \
- -c "flash write_image erase $(*).hex" \
- -c "reset" \
- -c "shutdown" $(NULL)
+ (echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \
+ $(OOCD) -f $(OOCD_FILE) \
+ -c "program $(*).elf verify reset exit" \
+ $(NULL)
endif
else
%.flash: %.elf
@printf " GDB $(*).elf (flash)\n"
- $(Q)$(GDB) --batch \
+ $(GDB) --batch \
-ex 'target extended-remote $(BMP_PORT)' \
- -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \
- $(*).elf
-endif
-else
-%.flash: %.elf
- @printf " GDB $(*).elf (flash)\n"
- $(Q)$(GDB) --batch \
- -ex 'target extended-remote $(STLINK_PORT)' \
- -x $(SCRIPT_DIR)/stlink_flash.scr \
+ -x $(EXAMPLES_SCRIPT_DIR)/black_magic_probe_flash.scr \
$(*).elf
endif
diff --git a/examples/sam/d/Makefile.include b/examples/sam/d/Makefile.include
new file mode 100644
index 00000000..f9b6759b
--- /dev/null
+++ b/examples/sam/d/Makefile.include
@@ -0,0 +1,33 @@
+##
+## This file is part of the libopencm3 project.
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see .
+##
+
+# You should use linker script generation! Specify device!
+ifeq ($(DEVICE),)
+LIBNAME = opencm3_samd
+DEFS += -DSAMD
+FP_FLAGS ?= -msoft-float
+ARCH_FLAGS = -mthumb -mcpu=cortex-m0plus $(FP_FLAGS)
+endif
+
+################################################################################
+# OpenOCD specific variables
+
+OOCD ?= openocd
+OOCD_INTERFACE ?= cmsis-dap
+OOCD_TARGET ?= at91samdXX
+
+include ../../../../rules.mk
diff --git a/examples/stm32/f1/stm32-h103/usb_hid/Makefile b/examples/sam/d/d10-xplained-mini/miniblink/Makefile
similarity index 88%
rename from examples/stm32/f1/stm32-h103/usb_hid/Makefile
rename to examples/sam/d/d10-xplained-mini/miniblink/Makefile
index fe73c62e..9ecc3826 100644
--- a/examples/stm32/f1/stm32-h103/usb_hid/Makefile
+++ b/examples/sam/d/d10-xplained-mini/miniblink/Makefile
@@ -1,8 +1,6 @@
##
## This file is part of the libopencm3 project.
##
-## Copyright (C) 2009 Uwe Hermann
-##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
@@ -17,9 +15,8 @@
## along with this library. If not, see .
##
-BINARY = usbhid
-
-LDSCRIPT = ../stm32-h103.ld
+BINARY = miniblink
+DEVICE = samd10d14
include ../../Makefile.include
diff --git a/examples/sam/d/d10-xplained-mini/miniblink/miniblink.c b/examples/sam/d/d10-xplained-mini/miniblink/miniblink.c
new file mode 100644
index 00000000..f1445b43
--- /dev/null
+++ b/examples/sam/d/d10-xplained-mini/miniblink/miniblink.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Karl Palsson
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include
+#include
+
+// led is on PA09
+
+static void gpio_setup(void)
+{
+ PORT_DIR(PORTA) = (1<<9);
+ PORT_PINCFG(PORTA, 9) = 0;
+}
+
+int main(void)
+{
+ int i, j;
+
+ gpio_setup();
+
+ while (1) {
+ for (j = 0; j < 10; j++) {
+ PORT_OUTTGL(PORTA) = 1<<9;
+ for (i = 0; i < (5000 + (j) * 10000); i++) { /* Wait a bit. */
+ __asm__("nop");
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/stm32/f0/Makefile.include b/examples/stm32/f0/Makefile.include
index cceb380c..0e04a9f6 100644
--- a/examples/stm32/f0/Makefile.include
+++ b/examples/stm32/f0/Makefile.include
@@ -28,8 +28,8 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m0 $(FP_FLAGS)
# OpenOCD specific variables
OOCD ?= openocd
-OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_INTERFACE ?= stlink-v2-1
+OOCD_TARGET ?= stm32f0x
################################################################################
# Black Magic Probe specific variables
@@ -41,4 +41,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/stm32/f0/stm32f0-discovery/adc/adc.c b/examples/stm32/f0/stm32f0-discovery/adc/adc.c
index cb9ea39e..7a1d1aa5 100644
--- a/examples/stm32/f0/stm32f0-discovery/adc/adc.c
+++ b/examples/stm32/f0/stm32f0-discovery/adc/adc.c
@@ -38,8 +38,7 @@ static void adc_setup(void)
adc_power_off(ADC1);
adc_set_clk_source(ADC1, ADC_CLKSOURCE_ADC);
- adc_calibrate_start(ADC1);
- adc_calibrate_wait_finish(ADC1);
+ adc_calibrate(ADC1);
adc_set_operation_mode(ADC1, ADC_MODE_SCAN);
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
@@ -71,7 +70,7 @@ static void usart_setup(void)
/* Setup UART parameters. */
usart_set_baudrate(USART1, 38400);
usart_set_databits(USART1, 8);
- usart_set_stopbits(USART1, USART_CR2_STOP_1_0BIT);
+ usart_set_stopbits(USART1, USART_CR2_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
diff --git a/examples/stm32/f0/stm32f0-discovery/miniblink/miniblink.c b/examples/stm32/f0/stm32f0-discovery/miniblink/miniblink.c
index d95da3a6..217827f7 100644
--- a/examples/stm32/f0/stm32f0-discovery/miniblink/miniblink.c
+++ b/examples/stm32/f0/stm32f0-discovery/miniblink/miniblink.c
@@ -27,14 +27,14 @@
static void gpio_setup(void)
{
- /* Enable GPIOB clock. */
+ /* Enable GPIOC clock. */
/* Manually: */
//RCC_AHBENR |= RCC_AHBENR_GPIOCEN;
/* Using API functions: */
rcc_periph_clock_enable(RCC_GPIOC);
- /* Set GPIO6 (in GPIO port B) to 'output push-pull'. */
+ /* Set GPIO8 (in GPIO port C) to 'output push-pull'. */
/* Using API functions: */
gpio_mode_setup(PORT_LED, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, PIN_LED);
}
@@ -51,12 +51,12 @@ int main(void)
// GPIOC_BSRR = PIN_LED; /* LED off */
// for (i = 0; i < 1000000; i++) /* Wait a bit. */
// __asm__("nop");
- // GPIOC_BRR = PIN_LED; /* LED on */
+ // GPIOC_BRR = PIN_LED; /* LED on */
// for (i = 0; i < 1000000; i++) /* Wait a bit. */
// __asm__("nop");
/* Using API functions gpio_set()/gpio_clear(): */
- // gpio_set(PORT_LED, PIN_LED); /* LED off */
+ // gpio_set(PORT_LED, PIN_LED); /* LED off */
// for (i = 0; i < 1000000; i++) /* Wait a bit. */
// __asm__("nop");
// gpio_clear(PORT_LED, PIN_LED); /* LED on */
diff --git a/examples/stm32/f0/stm32f0-discovery/stm32f0-discovery.ld b/examples/stm32/f0/stm32f0-discovery/stm32f0-discovery.ld
index 7e54e844..26ce5818 100644
--- a/examples/stm32/f0/stm32f0-discovery/stm32f0-discovery.ld
+++ b/examples/stm32/f0/stm32f0-discovery/stm32f0-discovery.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f0.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f0/stm32f0-discovery/usart/usart.c b/examples/stm32/f0/stm32f0-discovery/usart/usart.c
index e6b76d45..135ea246 100644
--- a/examples/stm32/f0/stm32f0-discovery/usart/usart.c
+++ b/examples/stm32/f0/stm32f0-discovery/usart/usart.c
@@ -38,7 +38,7 @@ static void usart_setup(void)
usart_set_baudrate(USART1, 38400);
usart_set_databits(USART1, 8);
usart_set_parity(USART1, USART_PARITY_NONE);
- usart_set_stopbits(USART1, USART_CR2_STOP_1_0BIT);
+ usart_set_stopbits(USART1, USART_CR2_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
diff --git a/examples/stm32/f0/stm32f0-discovery/usart_stdio/Makefile b/examples/stm32/f0/stm32f0-discovery/usart_stdio/Makefile
index 4c9a0fb8..f2648ad6 100644
--- a/examples/stm32/f0/stm32f0-discovery/usart_stdio/Makefile
+++ b/examples/stm32/f0/stm32f0-discovery/usart_stdio/Makefile
@@ -18,6 +18,7 @@
##
BINARY = usart_stdio
+CSTD = -std=gnu99
LDSCRIPT = ../stm32f0-discovery.ld
diff --git a/examples/stm32/f0/stm32f0-discovery/usart_stdio/usart_stdio.c b/examples/stm32/f0/stm32f0-discovery/usart_stdio/usart_stdio.c
index 012786d4..bfd120d2 100644
--- a/examples/stm32/f0/stm32f0-discovery/usart_stdio/usart_stdio.c
+++ b/examples/stm32/f0/stm32f0-discovery/usart_stdio/usart_stdio.c
@@ -58,7 +58,7 @@ static FILE *usart_setup(uint32_t dev)
usart_set_baudrate(dev, 38400);
usart_set_databits(dev, 8);
usart_set_parity(dev, USART_PARITY_NONE);
- usart_set_stopbits(dev, USART_CR2_STOP_1_0BIT);
+ usart_set_stopbits(dev, USART_CR2_STOPBITS_1);
usart_set_mode(dev, USART_MODE_TX_RX);
usart_set_flow_control(dev, USART_FLOWCONTROL_NONE);
diff --git a/examples/stm32/f1/Makefile.include b/examples/stm32/f1/Makefile.include
index cd5118c3..503e1544 100644
--- a/examples/stm32/f1/Makefile.include
+++ b/examples/stm32/f1/Makefile.include
@@ -29,7 +29,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_TARGET ?= stm32f1x
################################################################################
# Black Magic Probe specific variables
@@ -41,4 +41,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/stm32/f1/lisa-m-1/can/can.c b/examples/stm32/f1/lisa-m-1/can/can.c
index 36739962..96643a41 100644
--- a/examples/stm32/f1/lisa-m-1/can/can.c
+++ b/examples/stm32/f1/lisa-m-1/can/can.c
@@ -18,12 +18,13 @@
* along with this library. If not, see .
*/
-#include
-#include
-#include
+#include
#include
#include
#include
+#include
+#include
+#include
struct can_tx_msg {
uint32_t std_id;
@@ -152,7 +153,7 @@ static void can_setup(void)
}
/* CAN filter 0 init. */
- can_filter_id_mask_32bit_init(CAN1,
+ can_filter_id_mask_32bit_init(
0, /* Filter ID */
0, /* CAN ID */
0, /* CAN ID mask */
@@ -195,11 +196,11 @@ void sys_tick_handler(void)
void usb_lp_can_rx0_isr(void)
{
- uint32_t id, fmi;
+ uint32_t id;
bool ext, rtr;
- uint8_t length, data[8];
+ uint8_t fmi, length, data[8];
- can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data);
+ can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data, NULL);
if (data[0] & 1)
gpio_clear(GPIOA, GPIO8);
diff --git a/examples/stm32/f1/lisa-m-1/lisa-m.ld b/examples/stm32/f1/lisa-m-1/lisa-m.ld
index e03eb800..f6ab79f9 100644
--- a/examples/stm32/f1/lisa-m-1/lisa-m.ld
+++ b/examples/stm32/f1/lisa-m-1/lisa-m.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c
index e9bf0a1c..9f6a133f 100644
--- a/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c
@@ -166,7 +166,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)complete;
@@ -192,15 +192,15 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if (*len < sizeof(struct usb_cdc_line_coding))
- return 0;
+ return USBD_REQ_NOTSUPP;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
diff --git a/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile b/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile
index eab15672..c09ad9e6 100644
--- a/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile
+++ b/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile
@@ -18,6 +18,7 @@
##
BINARY = usbdfu
+CSTD = -std=gnu99
LDSCRIPT = ../lisa-m.ld
diff --git a/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c b/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c
index 91503ac9..1b089c12 100644
--- a/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c
+++ b/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c
@@ -174,39 +174,38 @@ static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_da
}
}
-static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)usbd_dev;
if ((req->bmRequestType & 0x7F) != 0x21)
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
- return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
- return 1;
}
+ return USBD_REQ_HANDLED;
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_UPLOAD:
/* Upload not supported for now. */
- return 0;
+ return USBD_REQ_NOTSUPP;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
@@ -217,16 +216,16 @@ static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
diff --git a/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c b/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c
index dd84f80a..df34be05 100644
--- a/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c
+++ b/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c
@@ -24,7 +24,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include "adxl345.h"
@@ -205,7 +205,7 @@ static const char *usb_strings[] = {
/* Buffer used for control requests. */
uint8_t usbd_control_buffer[128];
-static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+static enum usbd_request_return_codes hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)complete;
@@ -214,13 +214,13 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin
if((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
(req->wValue != 0x2200))
- return 0;
+ return USBD_REQ_NOTSUPP;
/* Handle the HID report descriptor. */
*buf = (uint8_t *)hid_report_descriptor;
*len = sizeof(hid_report_descriptor);
- return 1;
+ return USBD_REQ_HANDLED;
}
#ifdef INCLUDE_DFU_INTERFACE
@@ -236,7 +236,7 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
scb_reset_core();
}
-static int dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+static enum usbd_request_return_codes dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)buf;
@@ -244,11 +244,11 @@ static int dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uin
(void)dev;
if ((req->bmRequestType != 0x21) || (req->bRequest != DFU_DETACH))
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
*complete = dfu_detach_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
#endif
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec/Makefile b/examples/stm32/f1/lisa-m-2/adc_injec/Makefile
index 666c393b..ad3f5970 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec/Makefile
+++ b/examples/stm32/f1/lisa-m-2/adc_injec/Makefile
@@ -21,7 +21,6 @@ BINARY = adc_injec
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec/adc_injec.c b/examples/stm32/f1/lisa-m-2/adc_injec/adc_injec.c
index f8a3114e..7b550bde 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec/adc_injec.c
+++ b/examples/stm32/f1/lisa-m-2/adc_injec/adc_injec.c
@@ -79,7 +79,7 @@ static void adc_setup(void)
adc_enable_external_trigger_injected(ADC1,ADC_CR2_JEXTSEL_JSWSTART);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@@ -89,9 +89,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_RSTCAL) != 0); //added this check
- adc_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_CAL) != 0); //added this check
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/Makefile b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/Makefile
index 72eab49e..5aa32c3d 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/Makefile
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/Makefile
@@ -21,7 +21,6 @@ BINARY = adc_injec_timtrig
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/adc_injec_timtrig.c b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/adc_injec_timtrig.c
index 2176d8ec..bbeed14c 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/adc_injec_timtrig.c
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig/adc_injec_timtrig.c
@@ -70,7 +70,7 @@ static void timer_setup(void)
rcc_periph_clock_enable(RCC_TIM2);
/* Time Base configuration */
- timer_reset(timer);
+ rcc_periph_reset_pulse(RST_TIM2);
timer_set_mode(timer, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
timer_set_period(timer, 0xFF);
@@ -99,7 +99,7 @@ static void adc_setup(void)
adc_enable_external_trigger_injected(ADC1,ADC_CR2_JEXTSEL_TIM2_TRGO);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@@ -109,9 +109,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_RSTCAL) != 0);
- adc_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_CAL) != 0);
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/Makefile b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/Makefile
index 8ad47e2d..fd7077c2 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/Makefile
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/Makefile
@@ -21,7 +21,6 @@ BINARY = adc_injec_timtrig_irq
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/adc_injec_timtrig_irq.c b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/adc_injec_timtrig_irq.c
index c7386405..dae4f812 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/adc_injec_timtrig_irq.c
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq/adc_injec_timtrig_irq.c
@@ -73,7 +73,7 @@ static void timer_setup(void)
rcc_periph_clock_enable(RCC_TIM2);
/* Time Base configuration */
- timer_reset(timer);
+ rcc_periph_reset_pulse(RST_TIM2);
timer_set_mode(timer, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
timer_set_period(timer, 0xFF);
@@ -112,7 +112,7 @@ static void adc_setup(void)
adc_enable_eoc_interrupt_injected(ADC1);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@@ -122,9 +122,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_RSTCAL) != 0);
- adc_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_CAL) != 0);
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/Makefile b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/Makefile
index a3cccece..712fdb6d 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/Makefile
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/Makefile
@@ -21,7 +21,6 @@ BINARY = adc_injec_timtrig_irq_4ch
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/adc_injec_timtrig_irq_4ch.c b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/adc_injec_timtrig_irq_4ch.c
index c74ac22b..7e8fdc5d 100644
--- a/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/adc_injec_timtrig_irq_4ch.c
+++ b/examples/stm32/f1/lisa-m-2/adc_injec_timtrig_irq_4ch/adc_injec_timtrig_irq_4ch.c
@@ -81,7 +81,7 @@ static void timer_setup(void)
rcc_periph_clock_enable(RCC_TIM2);
/* Time Base configuration */
- timer_reset(timer);
+ rcc_periph_reset_pulse(RST_TIM2);
timer_set_mode(timer, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
timer_set_period(timer, 0xFF);
@@ -120,7 +120,7 @@ static void adc_setup(void)
adc_enable_eoc_interrupt_injected(ADC1);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
/* Select the channels we want to convert.
@@ -139,9 +139,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_RSTCAL) != 0); //added this check
- adc_calibration(ADC1);
- while ((ADC_CR2(ADC1) & ADC_CR2_CAL) != 0); //added this check
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/lisa-m-2/adc_regular/Makefile b/examples/stm32/f1/lisa-m-2/adc_regular/Makefile
index b61587f5..ef98ed0b 100644
--- a/examples/stm32/f1/lisa-m-2/adc_regular/Makefile
+++ b/examples/stm32/f1/lisa-m-2/adc_regular/Makefile
@@ -21,7 +21,6 @@ BINARY = adc
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/adc_regular/adc.c b/examples/stm32/f1/lisa-m-2/adc_regular/adc.c
index f6c80aef..309cebb2 100644
--- a/examples/stm32/f1/lisa-m-2/adc_regular/adc.c
+++ b/examples/stm32/f1/lisa-m-2/adc_regular/adc.c
@@ -75,7 +75,7 @@ static void adc_setup(void)
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@@ -85,7 +85,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- adc_calibration(ADC1);
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/lisa-m-2/can/Makefile b/examples/stm32/f1/lisa-m-2/can/Makefile
index 71a787ab..63133016 100644
--- a/examples/stm32/f1/lisa-m-2/can/Makefile
+++ b/examples/stm32/f1/lisa-m-2/can/Makefile
@@ -21,7 +21,6 @@ BINARY = can
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/can/can.c b/examples/stm32/f1/lisa-m-2/can/can.c
index 5703a4f5..2614ecbc 100644
--- a/examples/stm32/f1/lisa-m-2/can/can.c
+++ b/examples/stm32/f1/lisa-m-2/can/can.c
@@ -18,12 +18,13 @@
* along with this library. If not, see .
*/
-#include
-#include
-#include
+#include
#include
#include
#include
+#include
+#include
+#include
struct can_tx_msg {
uint32_t std_id;
@@ -152,7 +153,7 @@ static void can_setup(void)
}
/* CAN filter 0 init. */
- can_filter_id_mask_32bit_init(CAN1,
+ can_filter_id_mask_32bit_init(
0, /* Filter ID */
0, /* CAN ID */
0, /* CAN ID mask */
@@ -195,11 +196,11 @@ void sys_tick_handler(void)
void usb_lp_can_rx0_isr(void)
{
- uint32_t id, fmi;
+ uint32_t id;
bool ext, rtr;
- uint8_t length, data[8];
+ uint8_t fmi, length, data[8];
- can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data);
+ can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data, NULL);
if (data[0] & 1)
gpio_clear(GPIOA, GPIO8);
diff --git a/examples/stm32/f1/lisa-m-2/fancyblink/Makefile b/examples/stm32/f1/lisa-m-2/fancyblink/Makefile
index 90ce834e..1a07a940 100644
--- a/examples/stm32/f1/lisa-m-2/fancyblink/Makefile
+++ b/examples/stm32/f1/lisa-m-2/fancyblink/Makefile
@@ -21,7 +21,6 @@ BINARY = fancyblink
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/lisa-m.ld b/examples/stm32/f1/lisa-m-2/lisa-m.ld
index 55711e78..a638592d 100644
--- a/examples/stm32/f1/lisa-m-2/lisa-m.ld
+++ b/examples/stm32/f1/lisa-m-2/lisa-m.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/lisa-m-2/spi/Makefile b/examples/stm32/f1/lisa-m-2/spi/Makefile
index 9d90a1c7..2ac06206 100644
--- a/examples/stm32/f1/lisa-m-2/spi/Makefile
+++ b/examples/stm32/f1/lisa-m-2/spi/Makefile
@@ -21,7 +21,6 @@ BINARY = spi
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/spi_dma/Makefile b/examples/stm32/f1/lisa-m-2/spi_dma/Makefile
index 9aff3f1a..05eb3718 100644
--- a/examples/stm32/f1/lisa-m-2/spi_dma/Makefile
+++ b/examples/stm32/f1/lisa-m-2/spi_dma/Makefile
@@ -21,7 +21,6 @@ BINARY = spi_dma
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/spi_dma_adv/Makefile b/examples/stm32/f1/lisa-m-2/spi_dma_adv/Makefile
index 4e524ad9..8fe020d0 100644
--- a/examples/stm32/f1/lisa-m-2/spi_dma_adv/Makefile
+++ b/examples/stm32/f1/lisa-m-2/spi_dma_adv/Makefile
@@ -21,7 +21,6 @@ BINARY = spi_dma_adv
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/usart/Makefile b/examples/stm32/f1/lisa-m-2/usart/Makefile
index 498cd83f..6ab92e32 100644
--- a/examples/stm32/f1/lisa-m-2/usart/Makefile
+++ b/examples/stm32/f1/lisa-m-2/usart/Makefile
@@ -21,7 +21,6 @@ BINARY = usart
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/usart_dma/Makefile b/examples/stm32/f1/lisa-m-2/usart_dma/Makefile
index 5fa5c519..a55f1940 100644
--- a/examples/stm32/f1/lisa-m-2/usart_dma/Makefile
+++ b/examples/stm32/f1/lisa-m-2/usart_dma/Makefile
@@ -21,7 +21,6 @@ BINARY = usart_dma
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/usart_irq/Makefile b/examples/stm32/f1/lisa-m-2/usart_irq/Makefile
index dbab248d..9b36d42d 100644
--- a/examples/stm32/f1/lisa-m-2/usart_irq/Makefile
+++ b/examples/stm32/f1/lisa-m-2/usart_irq/Makefile
@@ -21,7 +21,6 @@ BINARY = usart_irq
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/usart_irq_printf/Makefile b/examples/stm32/f1/lisa-m-2/usart_irq_printf/Makefile
index 1cc2ed1b..843b1850 100644
--- a/examples/stm32/f1/lisa-m-2/usart_irq_printf/Makefile
+++ b/examples/stm32/f1/lisa-m-2/usart_irq_printf/Makefile
@@ -21,7 +21,6 @@ BINARY = usart_irq_printf
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/lisa-m-2/usart_printf/Makefile b/examples/stm32/f1/lisa-m-2/usart_printf/Makefile
index 6eaf0051..6eeac175 100644
--- a/examples/stm32/f1/lisa-m-2/usart_printf/Makefile
+++ b/examples/stm32/f1/lisa-m-2/usart_printf/Makefile
@@ -21,7 +21,6 @@ BINARY = usart_printf
# Comment the following line if you _don't_ have luftboot flashed!
LDFLAGS += -Wl,-Ttext=0x8002000
-CFLAGS += -std=c99
LDSCRIPT = ../lisa-m.ld
include ../../Makefile.include
diff --git a/examples/stm32/f1/mb525/mb525.ld b/examples/stm32/f1/mb525/mb525.ld
index c678ffbb..724f1c11 100644
--- a/examples/stm32/f1/mb525/mb525.ld
+++ b/examples/stm32/f1/mb525/mb525.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/obldc-strip/can/can.c b/examples/stm32/f1/obldc-strip/can/can.c
index fc218090..19e3e4c7 100644
--- a/examples/stm32/f1/obldc-strip/can/can.c
+++ b/examples/stm32/f1/obldc-strip/can/can.c
@@ -17,6 +17,7 @@
* along with this library. If not, see .
*/
+#include
#include
#include
#include
@@ -138,7 +139,7 @@ static void can_setup(void)
}
/* CAN filter 0 init. */
- can_filter_id_mask_32bit_init(CAN1,
+ can_filter_id_mask_32bit_init(
0, /* Filter ID */
0, /* CAN ID */
0, /* CAN ID mask */
@@ -173,11 +174,11 @@ void sys_tick_handler(void)
void usb_lp_can_rx0_isr(void)
{
- uint32_t id, fmi;
+ uint32_t id;
bool ext, rtr;
- uint8_t length, data[8];
+ uint8_t fmi, length, data[8];
- can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data);
+ can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data, NULL);
if (data[0] & 0x40)
gpio_clear(GPIOB, GPIO4);
diff --git a/examples/stm32/f1/obldc-strip/obldc-strip.ld b/examples/stm32/f1/obldc-strip/obldc-strip.ld
index 9778070f..09f387c3 100644
--- a/examples/stm32/f1/obldc-strip/obldc-strip.ld
+++ b/examples/stm32/f1/obldc-strip/obldc-strip.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/obldc/can/can.c b/examples/stm32/f1/obldc/can/can.c
index 5b6d4f71..83c573e3 100644
--- a/examples/stm32/f1/obldc/can/can.c
+++ b/examples/stm32/f1/obldc/can/can.c
@@ -18,12 +18,13 @@
* along with this library. If not, see .
*/
-#include
-#include
-#include
+#include
#include
#include
#include
+#include
+#include
+#include
struct can_tx_msg {
uint32_t std_id;
@@ -137,7 +138,7 @@ static void can_setup(void)
}
/* CAN filter 0 init. */
- can_filter_id_mask_32bit_init(CAN1,
+ can_filter_id_mask_32bit_init(
0, /* Filter ID */
0, /* CAN ID */
0, /* CAN ID mask */
@@ -177,11 +178,11 @@ void sys_tick_handler(void)
void usb_lp_can_rx0_isr(void)
{
- uint32_t id, fmi;
+ uint32_t id;
bool ext, rtr;
- uint8_t length, data[8];
+ uint8_t fmi, length, data[8];
- can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data);
+ can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data, NULL);
if (data[0] & 1)
gpio_clear(GPIOA, GPIO6);
diff --git a/examples/stm32/f1/obldc/obldc.ld b/examples/stm32/f1/obldc/obldc.ld
index 9778070f..09f387c3 100644
--- a/examples/stm32/f1/obldc/obldc.ld
+++ b/examples/stm32/f1/obldc/obldc.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/obldc/usart_irq/Makefile b/examples/stm32/f1/obldc/usart_irq/Makefile
index af12f399..411b7a41 100644
--- a/examples/stm32/f1/obldc/usart_irq/Makefile
+++ b/examples/stm32/f1/obldc/usart_irq/Makefile
@@ -19,7 +19,7 @@
BINARY = usart_irq
-OOCD_BOARD = open-bldc
+OOCD_FILE = board/open-bldc.cfg
LDSCRIPT = ../obldc.ld
diff --git a/examples/stm32/f1/other/adc_temperature_sensor/adc.c b/examples/stm32/f1/other/adc_temperature_sensor/adc.c
index 0f2a6b63..31552b84 100644
--- a/examples/stm32/f1/other/adc_temperature_sensor/adc.c
+++ b/examples/stm32/f1/other/adc_temperature_sensor/adc.c
@@ -72,7 +72,7 @@ static void adc_setup(void)
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
/* We want to read the temperature sensor, so we have to enable it. */
- adc_enable_temperature_sensor(ADC1);
+ adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@@ -82,7 +82,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- adc_calibration(ADC1);
+ adc_calibrate(ADC1);
}
static void my_usart_print_int(uint32_t usart, int value)
diff --git a/examples/stm32/f1/other/adc_temperature_sensor/adc.ld b/examples/stm32/f1/other/adc_temperature_sensor/adc.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/adc_temperature_sensor/adc.ld
+++ b/examples/stm32/f1/other/adc_temperature_sensor/adc.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/dma_mem2mem/dma.ld b/examples/stm32/f1/other/dma_mem2mem/dma.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/dma_mem2mem/dma.ld
+++ b/examples/stm32/f1/other/dma_mem2mem/dma.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/dogm128/main.ld b/examples/stm32/f1/other/dogm128/main.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/dogm128/main.ld
+++ b/examples/stm32/f1/other/dogm128/main.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/i2c_stts75_sensor/i2c_stts75_sensor.ld b/examples/stm32/f1/other/i2c_stts75_sensor/i2c_stts75_sensor.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/i2c_stts75_sensor/i2c_stts75_sensor.ld
+++ b/examples/stm32/f1/other/i2c_stts75_sensor/i2c_stts75_sensor.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/systick/systick.ld b/examples/stm32/f1/other/systick/systick.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/systick/systick.ld
+++ b/examples/stm32/f1/other/systick/systick.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/timer_interrupt/timer.ld b/examples/stm32/f1/other/timer_interrupt/timer.ld
index 9c6c11a2..54fcdd79 100644
--- a/examples/stm32/f1/other/timer_interrupt/timer.ld
+++ b/examples/stm32/f1/other/timer_interrupt/timer.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/usb_cdcacm/cdcacm.c b/examples/stm32/f1/other/usb_cdcacm/cdcacm.c
index ae54b278..d63be7e8 100644
--- a/examples/stm32/f1/other/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f1/other/usb_cdcacm/cdcacm.c
@@ -166,7 +166,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)complete;
@@ -192,15 +192,15 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if(*len < sizeof(struct usb_cdc_line_coding))
- return 0;
+ return USBD_REQ_NOTSUPP;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
diff --git a/examples/stm32/f1/other/usb_cdcacm/cdcacm.ld b/examples/stm32/f1/other/usb_cdcacm/cdcacm.ld
index a8223565..aa4054f0 100644
--- a/examples/stm32/f1/other/usb_cdcacm/cdcacm.ld
+++ b/examples/stm32/f1/other/usb_cdcacm/cdcacm.ld
@@ -25,5 +25,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/usb_dfu/Makefile b/examples/stm32/f1/other/usb_dfu/Makefile
index c1e30dc4..cbbcffa6 100644
--- a/examples/stm32/f1/other/usb_dfu/Makefile
+++ b/examples/stm32/f1/other/usb_dfu/Makefile
@@ -18,6 +18,7 @@
##
BINARY = usbdfu
+CSTD = -std=gnu99
include ../../Makefile.include
diff --git a/examples/stm32/f1/other/usb_dfu/usbdfu.c b/examples/stm32/f1/other/usb_dfu/usbdfu.c
index d634513d..3a310040 100644
--- a/examples/stm32/f1/other/usb_dfu/usbdfu.c
+++ b/examples/stm32/f1/other/usb_dfu/usbdfu.c
@@ -174,39 +174,38 @@ static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_da
}
}
-static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)usbd_dev;
if ((req->bmRequestType & 0x7F) != 0x21)
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
- return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
- return 1;
}
+ return USBD_REQ_HANDLED;
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_UPLOAD:
/* Upload not supported for now. */
- return 0;
+ return USBD_REQ_NOTSUPP;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
@@ -217,16 +216,16 @@ static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
diff --git a/examples/stm32/f1/other/usb_dfu/usbdfu.ld b/examples/stm32/f1/other/usb_dfu/usbdfu.ld
index 41b0f8df..6ac3ebc3 100644
--- a/examples/stm32/f1/other/usb_dfu/usbdfu.ld
+++ b/examples/stm32/f1/other/usb_dfu/usbdfu.ld
@@ -25,5 +25,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/other/usb_hid/usbhid.c b/examples/stm32/f1/other/usb_hid/usbhid.c
index 935b15d7..14694c53 100644
--- a/examples/stm32/f1/other/usb_hid/usbhid.c
+++ b/examples/stm32/f1/other/usb_hid/usbhid.c
@@ -201,7 +201,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+static enum usbd_request_return_codes hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *, struct usb_setup_data *))
{
(void)complete;
@@ -210,13 +210,13 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin
if((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
(req->wValue != 0x2200))
- return 0;
+ return USBD_REQ_NOTSUPP;
/* Handle the HID report descriptor. */
*buf = (uint8_t *)hid_report_descriptor;
*len = sizeof(hid_report_descriptor);
- return 1;
+ return USBD_REQ_HANDLED;
}
#ifdef INCLUDE_DFU_INTERFACE
@@ -225,14 +225,13 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
(void)req;
(void)dev;
- gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO10);
gpio_set(GPIOA, GPIO10);
scb_reset_core();
}
-static int dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+static enum usbd_request_return_codes dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *, struct usb_setup_data *))
{
(void)buf;
@@ -240,11 +239,11 @@ static int dfu_control_request(usbd_device *dev, struct usb_setup_data *req, uin
(void)dev;
if ((req->bmRequestType != 0x21) || (req->bRequest != DFU_DETACH))
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
*complete = dfu_detach_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
#endif
@@ -280,18 +279,25 @@ int main(void)
rcc_clock_setup_in_hsi_out_48mhz();
rcc_periph_clock_enable(RCC_GPIOA);
- rcc_periph_clock_enable(RCC_AFIO);
-
- AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON;
- gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15);
+ /*
+ * This is a somewhat common cheap hack to trigger device re-enumeration
+ * on startup. Assuming a fixed external pullup on D+, (For USB-FS)
+ * setting the pin to output, and driving it explicitly low effectively
+ * "removes" the pullup. The subsequent USB init will "take over" the
+ * pin, and it will appear as a proper pullup to the host.
+ * The magic delay is somewhat arbitrary, no guarantees on USBIF
+ * compliance here, but "it works" in most places.
+ */
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
+ gpio_clear(GPIOA, GPIO12);
+ for (unsigned i = 0; i < 800000; i++) {
+ __asm__("nop");
+ }
usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, hid_set_config);
- gpio_set(GPIOA, GPIO15);
- gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
- GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
-
while (1)
usbd_poll(usbd_dev);
}
diff --git a/examples/stm32/f1/other/usb_hid/usbhid.ld b/examples/stm32/f1/other/usb_hid/usbhid.ld
index a8223565..aa4054f0 100644
--- a/examples/stm32/f1/other/usb_hid/usbhid.ld
+++ b/examples/stm32/f1/other/usb_hid/usbhid.ld
@@ -25,5 +25,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/stm32-h103/button/button.c b/examples/stm32/f1/stm32-h103/button/button.c
index 84bc1802..afbd2ee2 100644
--- a/examples/stm32/f1/stm32-h103/button/button.c
+++ b/examples/stm32/f1/stm32-h103/button/button.c
@@ -23,8 +23,6 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 72 MHz. */
static void clock_setup(void)
{
@@ -62,8 +60,7 @@ int main(void)
while (1) {
gpio_toggle(GPIOC, GPIO12);
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 0)) != 0) {
+ if (gpio_get(GPIOA, GPIO0)) {
for (i = 0; i < 800000; i++) /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f1/stm32-h103/pwm_6step/pwm_6step.c b/examples/stm32/f1/stm32-h103/pwm_6step/pwm_6step.c
index ce82a8c0..b09112fc 100644
--- a/examples/stm32/f1/stm32-h103/pwm_6step/pwm_6step.c
+++ b/examples/stm32/f1/stm32-h103/pwm_6step/pwm_6step.c
@@ -110,7 +110,7 @@ static void tim_setup(void)
nvic_enable_irq(NVIC_TIM1_TRG_COM_IRQ);
/* Reset TIM1 peripheral. */
- timer_reset(TIM1);
+ rcc_periph_reset_pulse(RST_TIM1);
/* Timer global mode:
* - No divider
diff --git a/examples/stm32/f1/stm32-h103/stm32-h103.ld b/examples/stm32/f1/stm32-h103/stm32-h103.ld
index e15beca5..b2e5eb4b 100644
--- a/examples/stm32/f1/stm32-h103/stm32-h103.ld
+++ b/examples/stm32/f1/stm32-h103/stm32-h103.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/stm32-h103/timer/README.md b/examples/stm32/f1/stm32-h103/timer/README.md
new file mode 100644
index 00000000..e862d554
--- /dev/null
+++ b/examples/stm32/f1/stm32-h103/timer/README.md
@@ -0,0 +1,15 @@
+# README
+
+This example demonstrates the use of timers to trigger an interrupt. This
+example will toggle a LED spelling out the following morse code:
+
+SOS -> ...---...
+
+using international morse timing, with a dot element of 100ms
+
+It's intended for the olimex stm32-h103 eval board. It should blink
+a LED on the board.
+
+## Board connections
+
+*none required*
diff --git a/examples/stm32/f1/stm32-h103/timer/timer.c b/examples/stm32/f1/stm32-h103/timer/timer.c
index 03189ac5..843883c0 100644
--- a/examples/stm32/f1/stm32-h103/timer/timer.c
+++ b/examples/stm32/f1/stm32-h103/timer/timer.c
@@ -17,40 +17,49 @@
* along with this library. If not, see .
*/
+#include
#include
#include
#include
-#include
-#include
-
-uint16_t frequency_sequence[18] = {
- 1000,
- 500,
- 1000,
- 500,
- 1000,
- 500,
- 2000,
- 500,
- 2000,
- 500,
- 2000,
- 500,
- 1000,
- 500,
- 1000,
- 500,
- 1000,
- 5000,
+
+#ifndef ARRAY_LEN
+#define ARRAY_LEN(array) (sizeof((array))/sizeof((array)[0]))
+#endif
+
+#define LED1_PORT GPIOC
+#define LED1_PIN GPIO12
+
+/* Morse standard timings */
+#define ELEMENT_TIME 500
+#define DIT (1*ELEMENT_TIME)
+#define DAH (3*ELEMENT_TIME)
+#define INTRA (1*ELEMENT_TIME)
+#define INTER (3*ELEMENT_TIME)
+#define WORD (7*ELEMENT_TIME)
+
+uint16_t frequency_sequence[] = {
+ DIT,
+ INTRA,
+ DIT,
+ INTRA,
+ DIT,
+ INTER,
+ DAH,
+ INTRA,
+ DAH,
+ INTRA,
+ DAH,
+ INTER,
+ DIT,
+ INTRA,
+ DIT,
+ INTRA,
+ DIT,
+ WORD,
};
int frequency_sel = 0;
-uint16_t compare_time;
-uint16_t new_time;
-uint16_t frequency;
-int debug = 0;
-
static void clock_setup(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
@@ -58,14 +67,13 @@ static void clock_setup(void)
static void gpio_setup(void)
{
- /* Enable GPIOC clock. */
+ /* Enable GPIO clock for leds. */
rcc_periph_clock_enable(RCC_GPIOC);
- /* Set GPIO12 (in GPIO port C) to 'output push-pull'. */
- gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
- GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
-
- gpio_set(GPIOC, GPIO12);
+ /* Enable led as output */
+ gpio_set_mode(LED1_PORT, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, LED1_PIN);
+ gpio_set(LED1_PORT, LED1_PIN);
}
static void tim_setup(void)
@@ -76,55 +84,42 @@ static void tim_setup(void)
/* Enable TIM2 interrupt. */
nvic_enable_irq(NVIC_TIM2_IRQ);
- /* Reset TIM2 peripheral. */
- timer_reset(TIM2);
+ /* Reset TIM2 peripheral to defaults. */
+ rcc_periph_reset_pulse(RST_TIM2);
/* Timer global mode:
* - No divider
* - Alignment edge
* - Direction up
+ * (These are actually default values after reset above, so this call
+ * is strictly unnecessary, but demos the api for alternative settings)
*/
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
- TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
-
- /* Reset prescaler value. */
- timer_set_prescaler(TIM2, 36000);
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+
+ /*
+ * Please take note that the clock source for STM32 timers
+ * might not be the raw APB1/APB2 clocks. In various conditions they
+ * are doubled. See the Reference Manual for full details!
+ * In our case, TIM2 on APB1 is running at double frequency, so this
+ * sets the prescaler to have the timer run at 5kHz
+ */
+ timer_set_prescaler(TIM2, ((rcc_apb1_frequency * 2) / 5000));
- /* Enable preload. */
+ /* Disable preload. */
timer_disable_preload(TIM2);
-
- /* Continous mode. */
timer_continuous_mode(TIM2);
- /* Period (36kHz). */
+ /* count full range, as we'll update compare value continuously */
timer_set_period(TIM2, 65535);
- /* Disable outputs. */
- timer_disable_oc_output(TIM2, TIM_OC1);
- timer_disable_oc_output(TIM2, TIM_OC2);
- timer_disable_oc_output(TIM2, TIM_OC3);
- timer_disable_oc_output(TIM2, TIM_OC4);
-
- /* -- OC1 configuration -- */
-
- /* Configure global mode of line 1. */
- timer_disable_oc_clear(TIM2, TIM_OC1);
- timer_disable_oc_preload(TIM2, TIM_OC1);
- timer_set_oc_slow_mode(TIM2, TIM_OC1);
- timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_FROZEN);
-
- /* Set the capture compare value for OC1. */
- timer_set_oc_value(TIM2, TIM_OC1, 1000);
-
- /* ---- */
-
- /* ARR reload enable. */
- timer_disable_preload(TIM2);
+ /* Set the initual output compare value for OC1. */
+ timer_set_oc_value(TIM2, TIM_OC1, frequency_sequence[frequency_sel++]);
/* Counter enable. */
timer_enable_counter(TIM2);
- /* Enable commutation interrupt. */
+ /* Enable Channel 1 compare interrupt to recalculate compare values */
timer_enable_irq(TIM2, TIM_DIER_CC1IE);
}
@@ -139,18 +134,19 @@ void tim2_isr(void)
* Get current timer value to calculate next
* compare register value.
*/
- compare_time = timer_get_counter(TIM2);
+ uint16_t compare_time = timer_get_counter(TIM2);
/* Calculate and set the next compare value. */
- frequency = frequency_sequence[frequency_sel++];
- new_time = compare_time + frequency;
+ uint16_t frequency = frequency_sequence[frequency_sel++];
+ uint16_t new_time = compare_time + frequency;
timer_set_oc_value(TIM2, TIM_OC1, new_time);
- if (frequency_sel == 18)
+ if (frequency_sel == ARRAY_LEN(frequency_sequence)) {
frequency_sel = 0;
+ }
/* Toggle LED to indicate compare event. */
- gpio_toggle(GPIOC, GPIO12);
+ gpio_toggle(LED1_PORT, LED1_PIN);
}
}
@@ -160,8 +156,9 @@ int main(void)
gpio_setup();
tim_setup();
- while (1)
- __asm("nop");
+ while (1) {
+ ;
+ }
return 0;
}
diff --git a/examples/stm32/f1/stm32-h103/usb_cdcacm/cdcacm.c b/examples/stm32/f1/stm32-h103/usb_cdcacm/cdcacm.c
index d72b65f1..faec759c 100644
--- a/examples/stm32/f1/stm32-h103/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f1/stm32-h103/usb_cdcacm/cdcacm.c
@@ -166,7 +166,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)complete;
@@ -192,14 +192,14 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if (*len < sizeof(struct usb_cdc_line_coding))
- return 0;
- return 1;
+ return USBD_REQ_NOTSUPP;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
diff --git a/examples/stm32/f1/stm32-h103/usb_dfu/Makefile b/examples/stm32/f1/stm32-h103/usb_dfu/Makefile
index cc690fed..6ff7ce1c 100644
--- a/examples/stm32/f1/stm32-h103/usb_dfu/Makefile
+++ b/examples/stm32/f1/stm32-h103/usb_dfu/Makefile
@@ -18,6 +18,7 @@
##
BINARY = usbdfu
+CSTD = -std=gnu99
LDSCRIPT = ../stm32-h103.ld
diff --git a/examples/stm32/f1/stm32-h103/usb_dfu/usbdfu.c b/examples/stm32/f1/stm32-h103/usb_dfu/usbdfu.c
index 60aeba22..e61c98c4 100644
--- a/examples/stm32/f1/stm32-h103/usb_dfu/usbdfu.c
+++ b/examples/stm32/f1/stm32-h103/usb_dfu/usbdfu.c
@@ -176,37 +176,36 @@ static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_da
}
}
-static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
if ((req->bmRequestType & 0x7F) != 0x21)
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
- return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
- return 1;
}
+ return USBD_REQ_HANDLED;
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_UPLOAD:
/* Upload not supported for now. */
- return 0;
+ return USBD_REQ_NOTSUPP;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(usbd_dev, &bwPollTimeout);
@@ -217,16 +216,16 @@ static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
diff --git a/examples/stm32/f1/stm32-h103/usb_hid/README.md b/examples/stm32/f1/stm32-h103/usb_hid/README.md
deleted file mode 100644
index 98d3caaf..00000000
--- a/examples/stm32/f1/stm32-h103/usb_hid/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# README
-
-This example implements a USB Human Interface Device (HID)
-to demonstrate the use of the USB device stack.
-
diff --git a/examples/stm32/f1/stm32-h103/usb_hid/usbhid.c b/examples/stm32/f1/stm32-h103/usb_hid/usbhid.c
deleted file mode 100644
index b42afa29..00000000
--- a/examples/stm32/f1/stm32-h103/usb_hid/usbhid.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * This file is part of the libopencm3 project.
- *
- * Copyright (C) 2010 Gareth McMullin
- *
- * This library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library. If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* Define this to include the DFU APP interface. */
-#define INCLUDE_DFU_INTERFACE
-
-#ifdef INCLUDE_DFU_INTERFACE
-#include
-#include
-#endif
-
-const struct usb_device_descriptor dev = {
- .bLength = USB_DT_DEVICE_SIZE,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = 0x0200,
- .bDeviceClass = 0,
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
- .bMaxPacketSize0 = 64,
- .idVendor = 0x0483,
- .idProduct = 0x5710,
- .bcdDevice = 0x0200,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 3,
- .bNumConfigurations = 1,
-};
-
-static const uint8_t hid_report_descriptor[] = {
- 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
- 0x09, 0x02, /* USAGE (Mouse) */
- 0xa1, 0x01, /* COLLECTION (Application) */
- 0x09, 0x01, /* USAGE (Pointer) */
- 0xa1, 0x00, /* COLLECTION (Physical) */
- 0x05, 0x09, /* USAGE_PAGE (Button) */
- 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
- 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
- 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
- 0x95, 0x03, /* REPORT_COUNT (3) */
- 0x75, 0x01, /* REPORT_SIZE (1) */
- 0x81, 0x02, /* INPUT (Data,Var,Abs) */
- 0x95, 0x01, /* REPORT_COUNT (1) */
- 0x75, 0x05, /* REPORT_SIZE (5) */
- 0x81, 0x01, /* INPUT (Cnst,Ary,Abs) */
- 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
- 0x09, 0x30, /* USAGE (X) */
- 0x09, 0x31, /* USAGE (Y) */
- 0x09, 0x38, /* USAGE (Wheel) */
- 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
- 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
- 0x75, 0x08, /* REPORT_SIZE (8) */
- 0x95, 0x03, /* REPORT_COUNT (3) */
- 0x81, 0x06, /* INPUT (Data,Var,Rel) */
- 0xc0, /* END_COLLECTION */
- 0x09, 0x3c, /* USAGE (Motion Wakeup) */
- 0x05, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
- 0x09, 0x01, /* USAGE (Vendor Usage 1) */
- 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
- 0x75, 0x01, /* REPORT_SIZE (1) */
- 0x95, 0x02, /* REPORT_COUNT (2) */
- 0xb1, 0x22, /* FEATURE (Data,Var,Abs,NPrf) */
- 0x75, 0x06, /* REPORT_SIZE (6) */
- 0x95, 0x01, /* REPORT_COUNT (1) */
- 0xb1, 0x01, /* FEATURE (Cnst,Ary,Abs) */
- 0xc0 /* END_COLLECTION */
-};
-
-static const struct {
- struct usb_hid_descriptor hid_descriptor;
- struct {
- uint8_t bReportDescriptorType;
- uint16_t wDescriptorLength;
- } __attribute__((packed)) hid_report;
-} __attribute__((packed)) hid_function = {
- .hid_descriptor = {
- .bLength = sizeof(hid_function),
- .bDescriptorType = USB_DT_HID,
- .bcdHID = 0x0100,
- .bCountryCode = 0,
- .bNumDescriptors = 1,
- },
- .hid_report = {
- .bReportDescriptorType = USB_DT_REPORT,
- .wDescriptorLength = sizeof(hid_report_descriptor),
- },
-};
-
-const struct usb_endpoint_descriptor hid_endpoint = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x81,
- .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
- .wMaxPacketSize = 4,
- .bInterval = 0x20,
-};
-
-const struct usb_interface_descriptor hid_iface = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bAlternateSetting = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 1, /* boot */
- .bInterfaceProtocol = 2, /* mouse */
- .iInterface = 0,
-
- .endpoint = &hid_endpoint,
-
- .extra = &hid_function,
- .extralen = sizeof(hid_function),
-};
-
-#ifdef INCLUDE_DFU_INTERFACE
-const struct usb_dfu_descriptor dfu_function = {
- .bLength = sizeof(struct usb_dfu_descriptor),
- .bDescriptorType = DFU_FUNCTIONAL,
- .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
- .wDetachTimeout = 255,
- .wTransferSize = 1024,
- .bcdDFUVersion = 0x011A,
-};
-
-const struct usb_interface_descriptor dfu_iface = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = 0xFE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
- .iInterface = 0,
-
- .extra = &dfu_function,
- .extralen = sizeof(dfu_function),
-};
-#endif
-
-const struct usb_interface ifaces[] = {{
- .num_altsetting = 1,
- .altsetting = &hid_iface,
-#ifdef INCLUDE_DFU_INTERFACE
-}, {
- .num_altsetting = 1,
- .altsetting = &dfu_iface,
-#endif
-}};
-
-const struct usb_config_descriptor config = {
- .bLength = USB_DT_CONFIGURATION_SIZE,
- .bDescriptorType = USB_DT_CONFIGURATION,
- .wTotalLength = 0,
-#ifdef INCLUDE_DFU_INTERFACE
- .bNumInterfaces = 2,
-#else
- .bNumInterfaces = 1,
-#endif
- .bConfigurationValue = 1,
- .iConfiguration = 0,
- .bmAttributes = 0xC0,
- .bMaxPower = 0x32,
-
- .interface = ifaces,
-};
-
-static const char *usb_strings[] = {
- "Black Sphere Technologies",
- "HID Demo",
- "DEMO",
-};
-
-/* Buffer to be used for control requests. */
-uint8_t usbd_control_buffer[128];
-
-static int hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
-{
- (void)complete;
- (void)usbd_dev;
-
- if ((req->bmRequestType != 0x81) ||
- (req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
- (req->wValue != 0x2200))
- return 0;
-
- /* Handle the HID report descriptor. */
- *buf = (uint8_t *)hid_report_descriptor;
- *len = sizeof(hid_report_descriptor);
-
- return 1;
-}
-
-#ifdef INCLUDE_DFU_INTERFACE
-static void dfu_detach_complete(usbd_device *usbd_dev, struct usb_setup_data *req)
-{
- (void)req;
- (void)usbd_dev;
-
- gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15);
- gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
- GPIO_CNF_OUTPUT_PUSHPULL, GPIO10);
- gpio_set(GPIOA, GPIO10);
- scb_reset_core();
-}
-
-static int dfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
-{
- (void)buf;
- (void)len;
- (void)usbd_dev;
-
- if ((req->bmRequestType != 0x21) || (req->bRequest != DFU_DETACH))
- return 0; /* Only accept class request. */
-
- *complete = dfu_detach_complete;
-
- return 1;
-}
-#endif
-
-static void hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
-{
- (void)wValue;
- (void)usbd_dev;
-
- usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 4, NULL);
-
- usbd_register_control_callback(
- usbd_dev,
- USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- hid_control_request);
-#ifdef INCLUDE_DFU_INTERFACE
- usbd_register_control_callback(
- usbd_dev,
- USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- dfu_control_request);
-#endif
-
- systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
- /* SysTick interrupt every N clock pulses: set reload to N-1 */
- systick_set_reload(99999);
- systick_interrupt_enable();
- systick_counter_enable();
-}
-
-int main(void)
-{
- int i;
-
- usbd_device *usbd_dev;
-
- rcc_clock_setup_in_hsi_out_48mhz();
-
- rcc_periph_clock_enable(RCC_GPIOC);
-
- gpio_set(GPIOC, GPIO11);
- gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
- GPIO_CNF_OUTPUT_PUSHPULL, GPIO11);
-
- usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
- usbd_register_set_config_callback(usbd_dev, hid_set_config);
-
- for (i = 0; i < 0x80000; i++)
- __asm__("nop");
-
- gpio_clear(GPIOC, GPIO11);
-
- while (1)
- usbd_poll(usbd_dev);
-}
-
-#if 0 /* is this used? */
-void sys_tick_handler(void)
-{
- static int x = 0;
- static int dir = 1;
- uint8_t buf[4] = {0, 0, 0, 0};
-
- buf[1] = dir;
- x += dir;
- if (x > 30)
- dir = -dir;
- if (x < -30)
- dir = -dir;
-
- usbd_ep_write_packet(usbd_dev, 0x81, buf, 4);
-}
-#endif
diff --git a/examples/stm32/f1/stm32-h103/usb_iap/Makefile b/examples/stm32/f1/stm32-h103/usb_iap/Makefile
index eacc672c..f81a18b2 100644
--- a/examples/stm32/f1/stm32-h103/usb_iap/Makefile
+++ b/examples/stm32/f1/stm32-h103/usb_iap/Makefile
@@ -18,6 +18,7 @@
##
BINARY = usbiap
+CSTD = -std=gnu99
LDSCRIPT = ../stm32-h103.ld
diff --git a/examples/stm32/f1/stm32-h103/usb_iap/usbiap.c b/examples/stm32/f1/stm32-h103/usb_iap/usbiap.c
index b4089505..087098b1 100644
--- a/examples/stm32/f1/stm32-h103/usb_iap/usbiap.c
+++ b/examples/stm32/f1/stm32-h103/usb_iap/usbiap.c
@@ -176,37 +176,36 @@ static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_da
}
}
-static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
if ((req->bmRequestType & 0x7F) != 0x21)
- return 0; /* Only accept class request. */
+ return USBD_REQ_NOTSUPP; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
- return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
- return 1;
}
+ return USBD_REQ_HANDLED;
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
- return 1;
+ return USBD_REQ_HANDLED;
case DFU_UPLOAD:
/* Upload not supported for now. */
- return 0;
+ return USBD_REQ_NOTSUPP;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(usbd_dev, &bwPollTimeout);
@@ -217,16 +216,16 @@ static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
- return 1;
+ return USBD_REQ_HANDLED;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
diff --git a/examples/stm32/f1/stm32-h107/stm32-h107.ld b/examples/stm32/f1/stm32-h107/stm32-h107.ld
index ee8319ed..cc113d69 100644
--- a/examples/stm32/f1/stm32-h107/stm32-h107.ld
+++ b/examples/stm32/f1/stm32-h107/stm32-h107.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/stm32-h107/usb_simple/usb_simple.c b/examples/stm32/f1/stm32-h107/usb_simple/usb_simple.c
index 97d44cd0..ca715819 100644
--- a/examples/stm32/f1/stm32-h107/usb_simple/usb_simple.c
+++ b/examples/stm32/f1/stm32-h107/usb_simple/usb_simple.c
@@ -77,7 +77,7 @@ const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int simple_control_callback(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes simple_control_callback(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)buf;
@@ -86,14 +86,14 @@ static int simple_control_callback(usbd_device *usbd_dev, struct usb_setup_data
(void)usbd_dev;
if (req->bmRequestType != 0x40)
- return 0; /* Only accept vendor request. */
+ return USBD_REQ_NOTSUPP; /* Only accept vendor request. */
if (req->wValue & 1)
gpio_set(GPIOC, GPIO6);
else
gpio_clear(GPIOC, GPIO6);
- return 1;
+ return USBD_REQ_HANDLED;
}
static void usb_set_config_cb(usbd_device *usbd_dev, uint16_t wValue)
diff --git a/examples/stm32/f1/stm32-maple/stm32-maple.ld b/examples/stm32/f1/stm32-maple/stm32-maple.ld
index 65860a48..f8260a5a 100644
--- a/examples/stm32/f1/stm32-maple/stm32-maple.ld
+++ b/examples/stm32/f1/stm32-maple/stm32-maple.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/stm32-maple/usb_cdcacm/cdcacm.c b/examples/stm32/f1/stm32-maple/usb_cdcacm/cdcacm.c
index 82cf84a6..1dbf06ae 100644
--- a/examples/stm32/f1/stm32-maple/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f1/stm32-maple/usb_cdcacm/cdcacm.c
@@ -167,7 +167,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)complete;
@@ -193,14 +193,14 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if (*len < sizeof(struct usb_cdc_line_coding))
- return 0;
- return 1;
+ return USBD_REQ_NOTSUPP;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
diff --git a/examples/stm32/f1/stm32vl-discovery/adc-dac-printf/adc-dac-printf.c b/examples/stm32/f1/stm32vl-discovery/adc-dac-printf/adc-dac-printf.c
index 8d0c12c8..c6f0e8e3 100644
--- a/examples/stm32/f1/stm32vl-discovery/adc-dac-printf/adc-dac-printf.c
+++ b/examples/stm32/f1/stm32vl-discovery/adc-dac-printf/adc-dac-printf.c
@@ -112,7 +112,7 @@ static void adc_setup(void)
__asm__("nop");
adc_reset_calibration(ADC1);
- adc_calibration(ADC1);
+ adc_calibrate(ADC1);
}
static void dac_setup(void)
diff --git a/examples/stm32/f1/stm32vl-discovery/button/button.c b/examples/stm32/f1/stm32vl-discovery/button/button.c
index 41bdda0a..46db5b2b 100644
--- a/examples/stm32/f1/stm32vl-discovery/button/button.c
+++ b/examples/stm32/f1/stm32vl-discovery/button/button.c
@@ -21,8 +21,6 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 24 MHz. */
static void clock_setup(void)
{
@@ -61,8 +59,7 @@ int main(void)
gpio_toggle(GPIOC, GPIO9);
/* Upon button press, blink more slowly. */
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 0)) != 0) {
+ if (gpio_get(GPIOA, GPIO0)) {
for (i = 0; i < 800000; i++) /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f1/stm32vl-discovery/stm32vl-discovery.ld b/examples/stm32/f1/stm32vl-discovery/stm32vl-discovery.ld
index 40de3d3a..572e285e 100644
--- a/examples/stm32/f1/stm32vl-discovery/stm32vl-discovery.ld
+++ b/examples/stm32/f1/stm32vl-discovery/stm32vl-discovery.ld
@@ -27,5 +27,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f1/waveshare-open103r/button/button.c b/examples/stm32/f1/waveshare-open103r/button/button.c
index 036ea462..18d246f2 100644
--- a/examples/stm32/f1/waveshare-open103r/button/button.c
+++ b/examples/stm32/f1/waveshare-open103r/button/button.c
@@ -22,8 +22,6 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 24 MHz. */
static void clock_setup(void)
{
@@ -64,8 +62,7 @@ int main(void)
gpio_toggle(GPIOC, GPIO9);
/* Upon button press, blink more slowly. */
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 9)) == 0) {
+ if (gpio_get(GPIOA, GPIO9)) {
for (i = 0; i < 800000; i++) /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f1/waveshare-open103r/usbserial/usbserial.c b/examples/stm32/f1/waveshare-open103r/usbserial/usbserial.c
index 1a5dc56f..461752d2 100644
--- a/examples/stm32/f1/waveshare-open103r/usbserial/usbserial.c
+++ b/examples/stm32/f1/waveshare-open103r/usbserial/usbserial.c
@@ -175,7 +175,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev,
struct usb_setup_data *req,
uint8_t **buf,
uint16_t *len,
@@ -205,13 +205,13 @@ static int cdcacm_control_request(usbd_device *usbd_dev,
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if(*len < sizeof(struct usb_cdc_line_coding)) {
- return 0;
+ return USBD_REQ_NOTSUPP;
}
- return 1;
+ return USBD_REQ_HANDLED;
}
return 0;
}
diff --git a/examples/stm32/f1/waveshare-open103r/waveshare-open103r.ld b/examples/stm32/f1/waveshare-open103r/waveshare-open103r.ld
index 9c9011e7..915a3ea0 100644
--- a/examples/stm32/f1/waveshare-open103r/waveshare-open103r.ld
+++ b/examples/stm32/f1/waveshare-open103r/waveshare-open103r.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f1.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f2/Makefile.include b/examples/stm32/f2/Makefile.include
index cc7e4b7e..34b43bd2 100644
--- a/examples/stm32/f2/Makefile.include
+++ b/examples/stm32/f2/Makefile.include
@@ -31,7 +31,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= flossjtag
-OOCD_BOARD ?= olimex_stm32_h103
+OOCD_TARGET ?= stm32f2x
################################################################################
# Black Magic Probe specific variables
@@ -43,4 +43,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/stm32/f2/jobygps/jobygps.ld b/examples/stm32/f2/jobygps/jobygps.ld
index 73caf0ea..f9ef55b0 100644
--- a/examples/stm32/f2/jobygps/jobygps.ld
+++ b/examples/stm32/f2/jobygps/jobygps.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f2.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f3/Makefile.include b/examples/stm32/f3/Makefile.include
index d0119659..1f4a6d64 100644
--- a/examples/stm32/f3/Makefile.include
+++ b/examples/stm32/f3/Makefile.include
@@ -30,7 +30,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2
-OOCD_BOARD ?= stm32f3discovery
+OOCD_TARGET ?= stm32f3x
################################################################################
# Black Magic Probe specific variables
@@ -42,4 +42,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
+include ../../../../rules.mk
diff --git a/examples/stm32/f3/stm32f3-discovery/adc/adc.c b/examples/stm32/f3/stm32f3-discovery/adc/adc.c
index f66d8114..a717a92d 100644
--- a/examples/stm32/f3/stm32f3-discovery/adc/adc.c
+++ b/examples/stm32/f3/stm32f3-discovery/adc/adc.c
@@ -60,9 +60,7 @@ static void adc_setup(void)
/* We want to read the temperature sensor, so we have to enable it. */
adc_enable_temperature_sensor();
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_61DOT5CYC);
- uint8_t channel_array[16];
- channel_array[0]=16; // Vts (Internal temperature sensor
- channel_array[0]=1; //ADC1_IN1 (PA0)
+ uint8_t channel_array[] = { 1 }; /* ADC1_IN1 (PA0) */
adc_set_regular_sequence(ADC1, 1, channel_array);
adc_set_resolution(ADC1, ADC_CFGR1_RES_12_BIT);
adc_power_on(ADC1);
@@ -134,7 +132,7 @@ static void my_usart_print_int(uint32_t usart, int16_t value)
static void clock_setup(void)
{
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_64MHZ]);
+ rcc_clock_setup_hsi(&rcc_hsi_configs[RCC_CLOCK_HSI_64MHZ]);
}
diff --git a/examples/stm32/f3/stm32f3-discovery/button/button.c b/examples/stm32/f3/stm32f3-discovery/button/button.c
index 653eea74..7239aff9 100644
--- a/examples/stm32/f3/stm32f3-discovery/button/button.c
+++ b/examples/stm32/f3/stm32f3-discovery/button/button.c
@@ -24,12 +24,10 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 64 MHz. */
static void clock_setup(void)
{
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_64MHZ]);
+ rcc_clock_setup_hsi(&rcc_hsi_configs[RCC_CLOCK_HSI_64MHZ]);
}
static void gpio_setup(void)
@@ -64,8 +62,7 @@ int main(void)
gpio_toggle(GPIOE, GPIO11);
/* Upon button press, blink more slowly. */
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 0)) != 0) {
+ if (gpio_get(GPIOA, GPIO0)) {
for (i = 0; i < 3000000; i++) /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f3/stm32f3-discovery/fancyblink/fancyblink.c b/examples/stm32/f3/stm32f3-discovery/fancyblink/fancyblink.c
index 7b407f19..9ffff8a8 100644
--- a/examples/stm32/f3/stm32f3-discovery/fancyblink/fancyblink.c
+++ b/examples/stm32/f3/stm32f3-discovery/fancyblink/fancyblink.c
@@ -25,7 +25,7 @@
/* Set STM32 to 64 MHz. */
static void clock_setup(void)
{
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_64MHZ]);
+ rcc_clock_setup_hsi(&rcc_hsi_configs[RCC_CLOCK_HSI_64MHZ]);
/* Enable GPIOE clock. */
rcc_periph_clock_enable(RCC_GPIOE);
diff --git a/examples/stm32/f3/stm32f3-discovery/i2c/README.md b/examples/stm32/f3/stm32f3-discovery/i2c/README.md
index 58f234f6..3a992128 100644
--- a/examples/stm32/f3/stm32f3-discovery/i2c/README.md
+++ b/examples/stm32/f3/stm32f3-discovery/i2c/README.md
@@ -1,5 +1,8 @@
# README
-I2C example reading from the stm32f3discovery accelerometer.
-
+UART TX on PA2 @ 115200/8n1
+This example reads the onboard accelerometer and dumps the raw value
+of the ACC_OUT_X_L_A/ACC_OUT_X_H_A registers. (you should see ~0 for flat,
+and positive/negative values for tipping the board along it's long axis,
+ranging up to plus/minus 16k or so for vertical.
diff --git a/examples/stm32/f3/stm32f3-discovery/i2c/i2c.c b/examples/stm32/f3/stm32f3-discovery/i2c/i2c.c
index 29ef6613..d497e86c 100644
--- a/examples/stm32/f3/stm32f3-discovery/i2c/i2c.c
+++ b/examples/stm32/f3/stm32f3-discovery/i2c/i2c.c
@@ -20,6 +20,8 @@
* along with this library. If not, see .
*/
+#include
+#include
#include
#include
#include
@@ -43,6 +45,8 @@
#define LD8 GPIOE, GPIO14
#define LD6 GPIOE, GPIO15
+int _write(int file, char *ptr, int len);
+
static void i2c_setup(void)
{
rcc_periph_clock_enable(RCC_I2C1);
@@ -52,14 +56,13 @@ static void i2c_setup(void)
i2c_reset(I2C1);
/* Setup GPIO pin GPIO_USART2_TX/GPIO9 on GPIO port A for transmit. */
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7);
- gpio_set_af(GPIOB, GPIO_AF4, GPIO6| GPIO7);
+ gpio_set_af(GPIOB, GPIO_AF4, GPIO6 | GPIO7);
i2c_peripheral_disable(I2C1);
//configure ANFOFF DNF[3:0] in CR1
i2c_enable_analog_filter(I2C1);
- i2c_set_digital_filter(I2C1, I2C_CR1_DNF_DISABLED);
- //Configure PRESC[3:0] SDADEL[3:0] SCLDEL[3:0] SCLH[7:0] SCLL[7:0]
- // in TIMINGR
- i2c_100khz_i2cclk8mhz(I2C1);
+ i2c_set_digital_filter(I2C1, 0);
+ /* HSI is at 8Mhz */
+ i2c_set_speed(I2C1, i2c_speed_sm_100k, 8);
//configure No-Stretch CR1 (only relevant in slave mode)
i2c_enable_stretching(I2C1);
//addressing mode
@@ -97,37 +100,27 @@ static void gpio_setup(void)
GPIO14 | GPIO15);
}
-static void my_usart_print_int(uint32_t usart, int32_t value)
+int _write(int file, char *ptr, int len)
{
- int8_t i;
- int8_t nr_digits = 0;
- char buffer[25];
-
- if (value < 0) {
- usart_send_blocking(usart, '-');
- value = value * -1;
- }
-
- if (value == 0) {
- usart_send_blocking(usart, '0');
- }
-
- while (value > 0) {
- buffer[nr_digits++] = "0123456789"[value % 10];
- value /= 10;
- }
-
- for (i = nr_digits-1; i >= 0; i--) {
- usart_send_blocking(usart, buffer[i]);
- }
-
- usart_send_blocking(usart, '\r');
- usart_send_blocking(usart, '\n');
+ int i;
+
+ if (file == 1) {
+ for (i = 0; i < len; i++) {
+ if (ptr[i] == '\n') {
+ usart_send_blocking(USART2, '\r');
+ }
+ usart_send_blocking(USART2, ptr[i]);
+ }
+ return i;
+ }
+ errno = EIO;
+ return -1;
}
+
static void clock_setup(void)
{
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_64MHZ]);
+ rcc_clock_setup_hsi(&rcc_hsi_configs[RCC_CLOCK_HSI_64MHZ]);
}
#define I2C_ACC_ADDR 0x19
@@ -142,34 +135,31 @@ static void clock_setup(void)
#define ACC_OUT_X_L_A 0x28
#define ACC_OUT_X_H_A 0x29
-// gpio_port_write(GPIOE, (I2C_ISR(i2c) & 0xFF) << 8);
-// my_usart_print_int(USART2, (I2C_ISR(i2c) & 0xFF));
-
int main(void)
{
clock_setup();
gpio_setup();
usart_setup();
+ printf("Hello, we're running\n");
i2c_setup();
- /*uint8_t data[1]={(0x4 << ACC_CTRL_REG1_A_ODR_SHIFT) | ACC_CTRL_REG1_A_XEN};*/
- uint8_t data[1]={0x97};
- write_i2c(I2C1, I2C_ACC_ADDR, ACC_CTRL_REG1_A, 1, data);
- data[0]=0x08;
- write_i2c(I2C1, I2C_ACC_ADDR, ACC_CTRL_REG4_A, 1, data);
- uint16_t acc_x;
+ uint8_t cmd = ACC_CTRL_REG1_A;
+ uint8_t data;
+ i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
+ cmd = ACC_CTRL_REG4_A;
+ i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
+ int16_t acc_x;
while (1) {
- read_i2c(I2C1, I2C_ACC_ADDR, ACC_STATUS, 1, data);
- /*my_usart_print_int(USART2, data[0]);*/
- read_i2c(I2C1, I2C_ACC_ADDR, ACC_OUT_X_L_A, 1, data);
- acc_x=data[0];
- read_i2c(I2C1, I2C_ACC_ADDR, ACC_OUT_X_H_A, 1, data);
- acc_x|=(data[0] << 8);
- my_usart_print_int(USART2, (int16_t) acc_x);
- //int i;
- //for (i = 0; i < 800000; i++) /* Wait a bit. */
- // __asm__("nop");
+ cmd = ACC_STATUS;
+ i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
+ cmd = ACC_OUT_X_L_A;
+ i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
+ acc_x = data;
+ cmd = ACC_OUT_X_H_A;
+ i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
+ acc_x |= ((uint16_t)data << 8);
+ printf("data was %d\n", acc_x);
}
return 0;
diff --git a/examples/stm32/f3/stm32f3-discovery/spi/spi.c b/examples/stm32/f3/stm32f3-discovery/spi/spi.c
index ee3ae710..1d7faad7 100644
--- a/examples/stm32/f3/stm32f3-discovery/spi/spi.c
+++ b/examples/stm32/f3/stm32f3-discovery/spi/spi.c
@@ -138,7 +138,7 @@ static void my_usart_print_int(uint32_t usart, int32_t value)
static void clock_setup(void)
{
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_64MHZ]);
+ rcc_clock_setup_hsi(&rcc_hsi_configs[RCC_CLOCK_HSI_64MHZ]);
}
#define GYR_RNW (1 << 7) /* Write when zero */
diff --git a/examples/stm32/f3/stm32f3-discovery/stm32f3-discovery.ld b/examples/stm32/f3/stm32f3-discovery/stm32f3-discovery.ld
index 5e83aaac..c380f240 100644
--- a/examples/stm32/f3/stm32f3-discovery/stm32f3-discovery.ld
+++ b/examples/stm32/f3/stm32f3-discovery/stm32f3-discovery.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f3.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f3/stm32f3-discovery/usb_cdcacm/cdcacm.c b/examples/stm32/f3/stm32f3-discovery/usb_cdcacm/cdcacm.c
index c6419b73..a94996bd 100644
--- a/examples/stm32/f3/stm32f3-discovery/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f3/stm32f3-discovery/usb_cdcacm/cdcacm.c
@@ -166,7 +166,7 @@ static const char *usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
(void)complete;
@@ -192,14 +192,14 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
local_buf[8] = req->wValue & 3;
local_buf[9] = 0;
// usbd_ep_write_packet(0x83, buf, 10);
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if (*len < sizeof(struct usb_cdc_line_coding))
- return 0;
- return 1;
+ return USBD_REQ_NOTSUPP;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
@@ -235,32 +235,27 @@ static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
static void usb_setup(void)
{
- /* Enable clocks for GPIO port A (for GPIO_USART2_TX) and USART2. */
- rcc_usb_prescale_1();
+ /* Enable clocks for GPIO port A and USB peripheral. */
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
- /* Setup GPIO pin GPIO_USART2_TX/GPIO9 on GPIO port A for transmit. */
+ /* Setup GPIO pins for USB D+/D-. */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF14, GPIO11| GPIO12);
}
int main(void)
{
- int i;
-
usbd_device *usbd_dev;
- rcc_clock_setup_hsi(&rcc_hsi_8mhz[RCC_CLOCK_48MHZ]);
+ rcc_clock_setup_pll(&rcc_hse8mhz_configs[RCC_CLOCK_HSE8_72MHZ]);
usb_setup();
usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings,
3, usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
- for (i = 0; i < 0x800000; i++)
- __asm__("nop");
-
- while (1)
+ while (1) {
usbd_poll(usbd_dev);
+ }
}
diff --git a/examples/stm32/f4/Makefile.include b/examples/stm32/f4/Makefile.include
index 6ea1368c..c5b125b4 100644
--- a/examples/stm32/f4/Makefile.include
+++ b/examples/stm32/f4/Makefile.include
@@ -19,18 +19,21 @@
## along with this library. If not, see .
##
+# You should use linker script generation! Specify device!
+ifeq ($(DEVICE),)
LIBNAME = opencm3_stm32f4
DEFS += -DSTM32F4
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
+endif
################################################################################
# OpenOCD specific variables
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2
-OOCD_BOARD ?= stm32f4discovery
+OOCD_TARGET ?= stm32f4x
################################################################################
# Black Magic Probe specific variables
@@ -42,7 +45,4 @@ BMP_PORT ?=
#STLINK_PORT ?= :4242
-include ../../../../Makefile.rules
-
-
-
+include ../../../../rules.mk
diff --git a/examples/stm32/f4/nucleo-f411re/nucleo-f411re.ld b/examples/stm32/f4/nucleo-f411re/nucleo-f411re.ld
index fa246193..9762ee24 100644
--- a/examples/stm32/f4/nucleo-f411re/nucleo-f411re.ld
+++ b/examples/stm32/f4/nucleo-f411re/nucleo-f411re.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f4.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f4/other/stm32f4-discovery.ld b/examples/stm32/f4/other/stm32f4-discovery.ld
index 927c786b..c72a9bf8 100644
--- a/examples/stm32/f4/other/stm32f4-discovery.ld
+++ b/examples/stm32/f4/other/stm32f4-discovery.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f4.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f4/stm32f4-discovery/README.md b/examples/stm32/f4/stm32f4-discovery/README.md
index f91a1846..c0286dcc 100644
--- a/examples/stm32/f4/stm32f4-discovery/README.md
+++ b/examples/stm32/f4/stm32f4-discovery/README.md
@@ -1,7 +1,7 @@
# README
This directory contains examples for the _original_ stm32f4 discovery.
-The PCB should be labelled either MB997A or MB997B, and contains a user USB
+The PCB should be labelled as MB997{A,B,C}, and contains a user USB
port, and an audio dac on board, along with a MEMs microphone and an
accelerometer.
diff --git a/examples/stm32/f4/stm32f4-discovery/adc-dac-printf/Makefile b/examples/stm32/f4/stm32f4-discovery/adc-dac-printf/Makefile
index 35d1111c..4f4af416 100644
--- a/examples/stm32/f4/stm32f4-discovery/adc-dac-printf/Makefile
+++ b/examples/stm32/f4/stm32f4-discovery/adc-dac-printf/Makefile
@@ -18,7 +18,7 @@
##
BINARY = adc-dac-printf
-LDSCRIPT = ../stm32f4-discovery.ld
+DEVICE=STM32F407VG
include ../../Makefile.include
diff --git a/examples/stm32/f4/stm32f4-discovery/button/button.c b/examples/stm32/f4/stm32f4-discovery/button/button.c
index a0cb1905..c5fd3cab 100644
--- a/examples/stm32/f4/stm32f4-discovery/button/button.c
+++ b/examples/stm32/f4/stm32f4-discovery/button/button.c
@@ -22,8 +22,6 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 168 MHz. */
static void clock_setup(void)
{
@@ -45,7 +43,7 @@ static void button_setup(void)
/* Enable GPIOA clock. */
rcc_periph_clock_enable(RCC_GPIOA);
- /* Set GPIO0 (in GPIO port A) to 'input open-drain'. */
+ /* Set GPIOA0 to 'input floating'. */
gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO0);
}
@@ -62,8 +60,7 @@ int main(void)
gpio_toggle(GPIOD, GPIO12);
/* Upon button press, blink more slowly. */
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 0)) != 0) {
+ if (gpio_get(GPIOA, GPIO0)) {
for (i = 0; i < 3000000; i++) { /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f4/stm32f4-discovery/dac-dma/dac-dma.c b/examples/stm32/f4/stm32f4-discovery/dac-dma/dac-dma.c
index 8359c1a8..d8772fbe 100644
--- a/examples/stm32/f4/stm32f4-discovery/dac-dma/dac-dma.c
+++ b/examples/stm32/f4/stm32f4-discovery/dac-dma/dac-dma.c
@@ -54,7 +54,7 @@ static void timer_setup(void)
{
/* Enable TIM2 clock. */
rcc_periph_clock_enable(RCC_TIM2);
- timer_reset(TIM2);
+ rcc_periph_reset_pulse(RST_TIM2);
/* Timer global mode: - No divider, Alignment edge, Direction up */
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
diff --git a/examples/stm32/f4/stm32f4-discovery/miniblink/Makefile b/examples/stm32/f4/stm32f4-discovery/miniblink/Makefile
index 6f179864..022c78b7 100644
--- a/examples/stm32/f4/stm32f4-discovery/miniblink/Makefile
+++ b/examples/stm32/f4/stm32f4-discovery/miniblink/Makefile
@@ -19,7 +19,7 @@
BINARY = miniblink
-LDSCRIPT = ../stm32f4-discovery.ld
+DEVICE=STM32F407VG
include ../../Makefile.include
diff --git a/examples/stm32/f4/stm32f4-discovery/stm32f4-discovery.ld b/examples/stm32/f4/stm32f4-discovery/stm32f4-discovery.ld
index 927c786b..c72a9bf8 100644
--- a/examples/stm32/f4/stm32f4-discovery/stm32f4-discovery.ld
+++ b/examples/stm32/f4/stm32f4-discovery/stm32f4-discovery.ld
@@ -28,5 +28,5 @@ MEMORY
}
/* Include the common ld script. */
-INCLUDE libopencm3_stm32f4.ld
+INCLUDE cortex-m-generic.ld
diff --git a/examples/stm32/f4/stm32f4-discovery/timer/README.md b/examples/stm32/f4/stm32f4-discovery/timer/README.md
index 55e10060..5ab17cbf 100644
--- a/examples/stm32/f4/stm32f4-discovery/timer/README.md
+++ b/examples/stm32/f4/stm32f4-discovery/timer/README.md
@@ -1,14 +1,14 @@
# README
This example demonstrates the use of timers to trigger an interrupt. This
-example will toggle two LEDs spelling out the following morse code:
+example will toggle a LED spelling out the following morse code:
SOS -> ...---...
-Where dots are .1s, dashes .2s, gaps .05s and the word pause .5s.
+using international morse timing, with a dot element of 100ms
It's intended for the ST STM32F4DISCOVERY eval board. It should blink
-the LEDs on the board.
+a LED on the board.
## Board connections
diff --git a/examples/stm32/f4/stm32f4-discovery/timer/timer.c b/examples/stm32/f4/stm32f4-discovery/timer/timer.c
index 2f1dc2fa..2e22e80b 100644
--- a/examples/stm32/f4/stm32f4-discovery/timer/timer.c
+++ b/examples/stm32/f4/stm32f4-discovery/timer/timer.c
@@ -18,41 +18,48 @@
* along with this library. If not, see .
*/
+#include
#include
#include
#include
-#include
-#include
-
-#include
-
-uint16_t frequency_sequence[18] = {
- 1000,
- 500,
- 1000,
- 500,
- 1000,
- 500,
- 2000,
- 500,
- 2000,
- 500,
- 2000,
- 500,
- 1000,
- 500,
- 1000,
- 500,
- 1000,
- 5000,
-};
-uint16_t frequency_sel = 0;
+#ifndef ARRAY_LEN
+#define ARRAY_LEN(array) (sizeof((array))/sizeof((array)[0]))
+#endif
+
+#define LED1_PORT GPIOD
+#define LED1_PIN GPIO12
+
+/* Morse standard timings */
+#define ELEMENT_TIME 500
+#define DIT (1*ELEMENT_TIME)
+#define DAH (3*ELEMENT_TIME)
+#define INTRA (1*ELEMENT_TIME)
+#define INTER (3*ELEMENT_TIME)
+#define WORD (7*ELEMENT_TIME)
+
+uint16_t frequency_sequence[] = {
+ DIT,
+ INTRA,
+ DIT,
+ INTRA,
+ DIT,
+ INTER,
+ DAH,
+ INTRA,
+ DAH,
+ INTRA,
+ DAH,
+ INTER,
+ DIT,
+ INTRA,
+ DIT,
+ INTRA,
+ DIT,
+ WORD,
+};
-uint16_t compare_time;
-uint16_t new_time;
-uint16_t frequency;
-int debug = 0;
+int frequency_sel = 0;
static void clock_setup(void)
{
@@ -64,12 +71,9 @@ static void gpio_setup(void)
/* Enable GPIO clock for leds. */
rcc_periph_clock_enable(RCC_GPIOD);
- /* Set GPIO12 (in GPIO port D) to 'output push-pull'. */
- gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT,
- GPIO_PUPD_NONE, GPIO12 | GPIO13);
-
- gpio_set(GPIOD, GPIO12);
- gpio_clear(GPIOD, GPIO13);
+ /* Enable led as output */
+ gpio_mode_setup(LED1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED1_PIN);
+ gpio_set(LED1_PORT, LED1_PIN);
}
static void tim_setup(void)
@@ -80,75 +84,42 @@ static void tim_setup(void)
/* Enable TIM2 interrupt. */
nvic_enable_irq(NVIC_TIM2_IRQ);
- /* Reset TIM2 peripheral. */
- timer_reset(TIM2);
+ /* Reset TIM2 peripheral to defaults. */
+ rcc_periph_reset_pulse(RST_TIM2);
/* Timer global mode:
* - No divider
* - Alignment edge
* - Direction up
+ * (These are actually default values after reset above, so this call
+ * is strictly unnecessary, but demos the api for alternative settings)
*/
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
- TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
- /* Reset prescaler value.
- * Running the clock at 5kHz.
- */
/*
- * On STM32F4 the timers are not running directly from pure APB1 or
- * APB2 clock busses. The APB1 and APB2 clocks used for timers might
- * be the double of the APB1 and APB2 clocks. This depends on the
- * setting in DCKCFGR register. By default the behaviour is the
- * following: If the Prescaler APBx is greater than 1 the derived timer
- * APBx clocks will be double of the original APBx frequencies. Only if
- * the APBx prescaler is set to 1 the derived timer APBx will equal the
- * original APBx frequencies.
- *
- * In our case here the APB1 is devided by 4 system frequency and APB2
- * divided by 2. This means APB1 timer will be 2 x APB1 and APB2 will
- * be 2 x APB2. So when we try to calculate the prescaler value we have
- * to use rcc_apb1_freqency * 2!!!
- *
- * For additional information see reference manual for the stm32f4
- * familiy of chips. Page 204 and 213
+ * Please take note that the clock source for STM32 timers
+ * might not be the raw APB1/APB2 clocks. In various conditions they
+ * are doubled. See the Reference Manual for full details!
+ * In our case, TIM2 on APB1 is running at double frequency, so this
+ * sets the prescaler to have the timer run at 5kHz
*/
- timer_set_prescaler(TIM2, ((rcc_apb1_frequency * 2) / 10000));
+ timer_set_prescaler(TIM2, ((rcc_apb1_frequency * 2) / 5000));
- /* Enable preload. */
+ /* Disable preload. */
timer_disable_preload(TIM2);
-
- /* Continous mode. */
timer_continuous_mode(TIM2);
- /* Period (36kHz). */
+ /* count full range, as we'll update compare value continuously */
timer_set_period(TIM2, 65535);
- /* Disable outputs. */
- timer_disable_oc_output(TIM2, TIM_OC1);
- timer_disable_oc_output(TIM2, TIM_OC2);
- timer_disable_oc_output(TIM2, TIM_OC3);
- timer_disable_oc_output(TIM2, TIM_OC4);
-
- /* -- OC1 configuration -- */
-
- /* Configure global mode of line 1. */
- timer_disable_oc_clear(TIM2, TIM_OC1);
- timer_disable_oc_preload(TIM2, TIM_OC1);
- timer_set_oc_slow_mode(TIM2, TIM_OC1);
- timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_FROZEN);
-
- /* Set the capture compare value for OC1. */
- timer_set_oc_value(TIM2, TIM_OC1, 1000);
-
- /* ---- */
-
- /* ARR reload enable. */
- timer_disable_preload(TIM2);
+ /* Set the initual output compare value for OC1. */
+ timer_set_oc_value(TIM2, TIM_OC1, frequency_sequence[frequency_sel++]);
/* Counter enable. */
timer_enable_counter(TIM2);
- /* Enable commutation interrupt. */
+ /* Enable Channel 1 compare interrupt to recalculate compare values */
timer_enable_irq(TIM2, TIM_DIER_CC1IE);
}
@@ -163,19 +134,19 @@ void tim2_isr(void)
* Get current timer value to calculate next
* compare register value.
*/
- compare_time = timer_get_counter(TIM2);
+ uint16_t compare_time = timer_get_counter(TIM2);
/* Calculate and set the next compare value. */
- frequency = frequency_sequence[frequency_sel++];
- new_time = compare_time + frequency;
+ uint16_t frequency = frequency_sequence[frequency_sel++];
+ uint16_t new_time = compare_time + frequency;
timer_set_oc_value(TIM2, TIM_OC1, new_time);
- if (frequency_sel == 18)
+ if (frequency_sel == ARRAY_LEN(frequency_sequence)) {
frequency_sel = 0;
+ }
/* Toggle LED to indicate compare event. */
- gpio_toggle(GPIOD, GPIO12);
- gpio_toggle(GPIOD, GPIO13);
+ gpio_toggle(LED1_PORT, LED1_PIN);
}
}
@@ -185,16 +156,9 @@ int main(void)
gpio_setup();
tim_setup();
- /* Loop calling Wait For Interrupt. In older pre cortex ARM this is
- * just equivalent to nop. On cortex it puts the cpu to sleep until
- * one of the three occurs:
- *
- * a non-masked interrupt occurs and is taken
- * an interrupt masked by PRIMASK becomes pending
- * a Debug Entry request
- */
- while (1)
- __WFI(); /* Wait For Interrupt. */
+ while (1) {
+ ;
+ }
return 0;
}
diff --git a/examples/stm32/f4/stm32f4-discovery/usb_cdcacm/cdcacm.c b/examples/stm32/f4/stm32f4-discovery/usb_cdcacm/cdcacm.c
index 9d2ea4c4..69d390dc 100644
--- a/examples/stm32/f4/stm32f4-discovery/usb_cdcacm/cdcacm.c
+++ b/examples/stm32/f4/stm32f4-discovery/usb_cdcacm/cdcacm.c
@@ -167,7 +167,7 @@ static const char * usb_strings[] = {
/* Buffer to be used for control requests. */
uint8_t usbd_control_buffer[128];
-static int cdcacm_control_request(usbd_device *usbd_dev,
+static enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{
@@ -182,16 +182,16 @@ static int cdcacm_control_request(usbd_device *usbd_dev,
* even though it's optional in the CDC spec, and we don't
* advertise it in the ACM functional descriptor.
*/
- return 1;
+ return USBD_REQ_HANDLED;
}
case USB_CDC_REQ_SET_LINE_CODING:
if (*len < sizeof(struct usb_cdc_line_coding)) {
- return 0;
+ return USBD_REQ_NOTSUPP;
}
- return 1;
+ return USBD_REQ_HANDLED;
}
- return 0;
+ return USBD_REQ_NOTSUPP;
}
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
@@ -231,9 +231,8 @@ int main(void)
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_OTGFS);
- gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO9 | GPIO11 | GPIO12);
- gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
+ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
+ gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
usbd_dev = usbd_init(&otgfs_usb_driver, &dev, &config,
usb_strings, 3,
diff --git a/examples/stm32/f4/stm32f4-discovery/usb_midi/usbmidi.c b/examples/stm32/f4/stm32f4-discovery/usb_midi/usbmidi.c
index b57f9997..2f428374 100644
--- a/examples/stm32/f4/stm32f4-discovery/usb_midi/usbmidi.c
+++ b/examples/stm32/f4/stm32f4-discovery/usb_midi/usbmidi.c
@@ -371,9 +371,8 @@ int main(void)
rcc_periph_clock_enable(RCC_OTGFS);
/* USB pins */
- gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO9 | GPIO11 | GPIO12);
- gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
+ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
+ gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
desig_get_unique_id_as_string(usb_serial_number, sizeof(usb_serial_number));
diff --git a/examples/stm32/f4/stm32f4-discovery/usb_msc/msc.c b/examples/stm32/f4/stm32f4-discovery/usb_msc/msc.c
index a7863399..0a27ea1d 100644
--- a/examples/stm32/f4/stm32f4-discovery/usb_msc/msc.c
+++ b/examples/stm32/f4/stm32f4-discovery/usb_msc/msc.c
@@ -109,9 +109,8 @@ int main(void)
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_OTGFS);
- gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
- GPIO9 | GPIO11 | GPIO12);
- gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
+ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
+ gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
msc_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config_descr,
usb_strings, 3,
diff --git a/examples/stm32/f4/stm32f429i-discovery/button/button.c b/examples/stm32/f4/stm32f429i-discovery/button/button.c
index 1f06f14b..5eb54542 100644
--- a/examples/stm32/f4/stm32f429i-discovery/button/button.c
+++ b/examples/stm32/f4/stm32f429i-discovery/button/button.c
@@ -22,8 +22,6 @@
#include
#include
-uint16_t exti_line_state;
-
/* Set STM32 to 168 MHz. */
static void clock_setup(void)
{
@@ -62,8 +60,7 @@ int main(void)
gpio_toggle(GPIOG, GPIO13);
/* Upon button press, blink more slowly. */
- exti_line_state = GPIOA_IDR;
- if ((exti_line_state & (1 << 0)) != 0) {
+ if (gpio_get(GPIOA, GPIO0)) {
for (i = 0; i < 3000000; i++) { /* Wait a bit. */
__asm__("nop");
}
diff --git a/examples/stm32/f4/stm32f429i-discovery/dac-dma/dac-dma.c b/examples/stm32/f4/stm32f429i-discovery/dac-dma/dac-dma.c
index 268dad78..963a3bf1 100644
--- a/examples/stm32/f4/stm32f429i-discovery/dac-dma/dac-dma.c
+++ b/examples/stm32/f4/stm32f429i-discovery/dac-dma/dac-dma.c
@@ -55,7 +55,7 @@ static void timer_setup(void)
{
/* Enable TIM2 clock. */
rcc_periph_clock_enable(RCC_TIM2);
- timer_reset(TIM2);
+ rcc_periph_reset_pulse(RST_TIM2);
/* Timer global mode: - No divider, Alignment edge, Direction up */
timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,
TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile b/examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile
index 4f84e13d..a782d791 100644
--- a/examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-dma/Makefile
@@ -1,6 +1,7 @@
OBJS = sdram.o clock.o console.o lcd-spi.o
BINARY = lcd-dma
+CSTD = -std=gnu99
# we use sin/cos from the library
LDLIBS += -lm
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.cproject b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.cproject
new file mode 100644
index 00000000..236d2e88
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.cproject
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ make
+
+ clean all flash OOCD_INTERFACE=stlink-v2-1 OOCD_BOARD=stm32f429disc1 V=1
+ true
+ true
+ true
+
+
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.project b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.project
new file mode 100644
index 00000000..bbed6ae6
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.project
@@ -0,0 +1,27 @@
+
+
+ lcd-ltdc-touch-game
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.settings/language.settings.xml b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.settings/language.settings.xml
new file mode 100644
index 00000000..27b4f5c4
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/.settings/language.settings.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/Makefile b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/Makefile
new file mode 100644
index 00000000..9c16c1a2
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/Makefile
@@ -0,0 +1,16 @@
+OBJS = clock.o gfx_locm3.o lcd_ili9341.o sdram.o
+OBJS += fonts/Tamsyn5x9b_9.o fonts/Tamsyn5x9r_9.o
+OBJS += vector_gfx/bezier.o vector_gfx/drawing.o
+OBJS += i2c.o touchscreen_controller_stmpe811.o
+
+BINARY = application
+
+#CFLAGS = -O0 -ggdb3
+CFLAGS = -O3 -ggdb3
+
+# we use sin/cos from the library
+LDLIBS = -lm
+
+LDSCRIPT = ../stm32f429i-discovery.ld
+
+include ../../Makefile.include
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/README.md b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/README.md
new file mode 100644
index 00000000..a881fd90
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/README.md
@@ -0,0 +1,7 @@
+# README
+
+Small test with minimal graphics lib for ltdc graphics controller.
+
+Two additional python scripts are provided to create your own font and bitmap header files.
+
+06/01/16 H2OBrain
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/application.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/application.c
new file mode 100644
index 00000000..fa42a09b
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/application.c
@@ -0,0 +1,730 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include "clock.h"
+#include "sdram.h"
+#include "lcd_ili9341.h"
+
+#include "touchscreen_controller_stmpe811.h"
+#include "fonts/Tamsyn5x9r_9.h"
+#include "fonts/Tamsyn5x9b_9.h"
+#include "vector_gfx/vector_gfx.h"
+
+
+/* snake definitions */
+typedef enum {
+ RIGHT,UP,LEFT,DOWN
+} direction_t;
+typedef enum {
+ LOST,
+ STARTED
+} state_t;
+typedef struct {
+ bool placed;
+ point2d_t pos;
+} snake_food_t;
+typedef struct {
+ /* play-field */
+ int16_t off_x,off_y,fw,fh;
+ /* snake */
+ uint64_t last_time;
+ float size, length, max_length, speed;
+ point2d_t *history, *hcurr, *hfirst, *hend;
+ direction_t dir;
+ state_t state;
+ snake_food_t food;
+} snake_state_t;
+
+snake_state_t snake;
+
+static inline void snake_history_reset(void);
+static void snake_turn(direction_t dir);
+
+
+// simple static extension functions
+static inline void enable_interrupts(void) {
+ __enable_irq();
+}
+static inline void disable_interrupts(void) {
+ __disable_irq();
+}
+
+static inline bool is_interrupt(void) {
+ return (SCB->ICSR & SCB_ICSR_VECTACTIVE) != 0 ;
+}
+
+/**
+ * Interrupts
+ */
+
+/* Display SPI interrupt */
+void spi5_isr()
+{
+ if (ILI9341_SPI_IS_SELECTED()) {
+ ili9341_spi5_isr();
+ } else {
+ spi_disable_tx_buffer_empty_interrupt(SPI5);
+ (void)SPI_DR(SPI5);
+ }
+}
+
+/* Touchscreen interrupt */
+void
+exti15_10_isr() {
+ exti_reset_request(EXTI15);
+ stmpe811_handle_interrupt();
+}
+
+/* Blue button interrupt */
+bool rotate_screen = false;
+void
+exti0_isr()
+{
+ exti_reset_request(EXTI0);
+ rotate_screen = true;
+}
+
+
+/**
+ * Update touchscreen input
+ */
+typedef enum {
+ TS_TOUCHED,
+ TS_DRAGGING,
+ TS_DRAGGED,
+ TS_NONE,
+} touchscreen_action_t;
+static
+point2d_t
+touch_data_to_coordinate(stmpe811_touch_t touch_data)
+{
+ point2d_t p = (point2d_t){
+ .x = (vector_flt_t)(touch_data.x-STMPE811_X_MIN)/(STMPE811_X_MAX-STMPE811_X_MIN),
+ .y = (vector_flt_t)(touch_data.y-STMPE811_Y_MIN)/(STMPE811_Y_MAX-STMPE811_Y_MIN)
+ };
+ switch (gfx_get_rotation()) {
+ case GFX_ROTATION_0_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*(1.0f-p.x), .y = gfx_height()* p.y };
+ break;
+ case GFX_ROTATION_180_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.x , .y = gfx_height()*(1.0f-p.y) };
+ break;
+ case GFX_ROTATION_90_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*(1.0f-p.y), .y = gfx_height()*(1.0f-p.x) };
+ break;
+ case GFX_ROTATION_270_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.y , .y = gfx_height()* p.x };
+ break;
+ }
+ return p;
+}
+static
+point2d_t
+drag_data_to_coordinate(stmpe811_drag_data_t drag_data)
+{
+ point2d_t p = (point2d_t){
+ .x = (vector_flt_t)drag_data.dx/(STMPE811_X_MAX-STMPE811_X_MIN),
+ .y = (vector_flt_t)drag_data.dy/(STMPE811_Y_MAX-STMPE811_Y_MIN)
+ };
+ switch (gfx_get_rotation()) {
+ case GFX_ROTATION_0_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*( -p.x), .y = gfx_height()*( p.y) };
+ break;
+ case GFX_ROTATION_180_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.x , .y = gfx_height()* -p.y };
+ break;
+ case GFX_ROTATION_90_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*( -p.y), .y = gfx_height()* -p.x };
+ break;
+ case GFX_ROTATION_270_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.y , .y = gfx_height()*( p.x) };
+ break;
+ }
+ return p;
+}
+static
+touchscreen_action_t
+update_touchscreen_data(point2d_t *touch_point, point2d_t *drag_distance)
+{
+ stmpe811_touch_t touch_data = stmpe811_get_touch_data();
+ if (touch_data.touched == 1) {
+ *touch_point = touch_data_to_coordinate(touch_data);
+ return TS_TOUCHED;
+ } else {
+ stmpe811_drag_data_t drag_data = stmpe811_get_drag_data();
+ if (drag_data.data_is_valid) {
+ *drag_distance = drag_data_to_coordinate(drag_data);
+ return TS_DRAGGING;
+ } else {
+ /* stop drag*/
+ return TS_DRAGGED;
+ }
+ }
+ return TS_NONE;
+}
+
+
+static
+void
+print_touchscreen_data(
+ int16_t x, int16_t y, uint16_t color,
+ touchscreen_action_t ts_action,
+ point2d_t touch_point, point2d_t drag_distance
+) {
+ char conv_buf[1024];
+
+ //const char *state;
+ //switch (stmpe811.current_touch_state) {
+ //case STMPE811_TOUCH_STATE__UNTOUCHED:
+ //state = "untouched";
+ //break;
+ //case STMPE811_TOUCH_STATE__TOUCHED:
+ //state = "touched";
+ //break;
+ //case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ //state = "touched waiting";
+ //break;
+ //default:
+ //state = "invalid";
+ //break;
+ //}
+
+ static char *action = "none";
+ switch (ts_action) {
+ case TS_TOUCHED:
+ action = "touched";
+ break;
+ case TS_DRAGGING:
+ action = "dragging";
+ break;
+ case TS_DRAGGED:
+ action = "dragged";
+ break;
+ case TS_NONE:
+ break;
+ }
+
+ sprintf(conv_buf,
+ "action : %s\n"
+ "touch : %5.1f % 5.1f\n"
+ "drag : %+5.1f %+5.1f\n"
+ "ints : %lu\n"
+ "count : %lu",
+ action,
+ (double)touch_point.x, (double)touch_point.y,
+ (double)drag_distance.x, (double)drag_distance.y,
+ stmpe811.touch_interrupts,
+ stmpe811.last_values_count
+ );
+
+ gfx_puts2(x, y, conv_buf, &font_Tamsyn5x9r_9, color);
+}
+
+
+/**
+ * Re-/draw background
+ */
+static void draw_background(void)
+{
+ ili9341_set_layer1();
+
+ gfx_fill_screen(GFX_COLOR_BLACK);
+
+ gfx_draw_rect(0, 0, gfx_width() , 40 , GFX_COLOR_DARKGREY);
+ gfx_fill_rect(1, 1, gfx_width()-2, 40-2, GFX_COLOR_BLUE);
+
+// draw_antialised_line((segment2d_t){20,20,200,200},GFX_COLOR_GREEN2);
+ gfx_set_font_scale(3);
+ gfx_puts2(10, 8, "Snake", &font_Tamsyn5x9b_9 , GFX_COLOR_WHITE);
+
+ /* flip background buffer */
+ ili9341_flip_layer1_buffer();
+}
+
+/* Snake */
+static inline
+point2d_t *dec(point2d_t *p) {
+ if (p==snake.history) p = snake.hend-1;
+ else p--;
+ return p;
+}
+static inline
+point2d_t *inc(point2d_t *p) {
+ if (p==snake.hend-1) p = snake.history;
+ else p++;
+ return p;
+}
+static inline
+bool dec_and_test(point2d_t **p, point2d_t *test_p) {
+ return test_p == (*p=dec(*p));
+}
+static inline
+bool inc_and_test(point2d_t **p, point2d_t *test_p) {
+ return test_p == (*p=inc(*p));
+}
+#define SNAKE_HISTORY_LENGTH 1000
+static void init_snake(void) {
+ point2d_t *history = malloc(sizeof(point2d_t)*SNAKE_HISTORY_LENGTH);
+ snake = (snake_state_t) {
+ .off_x=5,.off_y=45, .fw=gfx_width()-10, .fh=gfx_height()-50,
+ .last_time=mtime(),
+ .size=10,.length=0,.max_length=50,.speed=30,
+ .history=history,.hcurr=history,.hfirst=history,.hend=history+SNAKE_HISTORY_LENGTH,
+ .dir=RIGHT,
+ .state=LOST,
+ .food={0}
+ };
+ snake_history_reset();
+ srand(666);
+}
+static inline void snake_history_reset(void) {
+ snake.length = 0; snake.max_length = 50;
+ snake.speed = 30;
+ snake.dir = RIGHT;
+ snake.hfirst = snake.hcurr;
+ point2d_t reset_point = (point2d_t){snake.off_x+snake.fw/2,snake.off_y+snake.fh/2};
+ *snake.hcurr = reset_point;
+ snake.hcurr = inc(snake.hcurr);
+ *snake.hcurr = reset_point;
+}
+static vector_flt_t var_thickness(vector_flt_t *arg, int16_t p, int16_t length) {
+ (void)p;(void)length;
+ return snake.size/4-1+snake.size/4*(((1+vector_flt_cos((*arg+p)/5))/2));
+}
+static void do_snake(void) {
+ disable_interrupts();
+
+ uint64_t t = mtime();
+ float tdiff = (float)(t-snake.last_time) / 1000;
+
+ point2d_t *p = snake.hcurr;
+ bool lost = false;
+ switch (snake.state) {
+ case STARTED :
+ {
+ float dist = snake.speed * tdiff;
+ switch (snake.dir) {
+ case RIGHT :
+ p->x += dist;
+ break;
+ case UP :
+ p->y -= dist;
+ break;
+ case LEFT :
+ p->x -= dist;
+ break;
+ case DOWN :
+ p->y += dist;
+ break;
+ }
+
+ snake.length += dist;
+ if (snake.length > snake.max_length) snake.length = snake.max_length;
+
+ lost = p->x < snake.off_x
+ || p->x > snake.off_x+snake.fw
+ || p->y < snake.off_y
+ || p->y > snake.off_y+snake.fh;
+
+ if (!snake.food.placed) {
+ snake.food.placed = true;
+ snake.food.pos = (point2d_t){
+ (vector_flt_t)rand()/RAND_MAX*snake.fw+snake.off_x,
+ (vector_flt_t)rand()/RAND_MAX*snake.fh+snake.off_y
+ };
+ }
+ } break;
+ case LOST :
+// default :
+ lost = true;
+ break;
+ }
+ snake.last_time = t;
+
+ /* drawing snake from front to back, while keeping track of the total length */
+ bool done = false;
+ float l = snake.length;
+ float dl = 0;
+ point2d_t *lp = p;
+ while (true) {
+ done = dec_and_test(&p, snake.hfirst);
+ vector_flt_t dist = point2d_dist(*lp,*p);
+ l -= dist;
+ if (l<=0.0001f) { // <=0
+ if (l<0) {
+ point2d_t dir = point2d_normalize(point2d_sub_ts(*lp,*p));
+ *p = point2d_add_ts(*p, point2d_mul_t(dir,-l));
+ }
+ done = true;
+ }
+
+ draw_thick_line(
+ lp->x,lp->y,p->x,p->y,
+ snake.size,
+ GFX_COLOR_GREEN2
+ );
+ draw_varthick_line(
+ lp->x,lp->y,p->x,p->y,
+ (drawing_varthick_fct_t)var_thickness, &dl,
+ (drawing_varthick_fct_t)var_thickness, &dl,
+ GFX_COLOR_RED
+ );
+// draw_antialised_line((segment2d_t){*lp,*p},GFX_COLOR_WHITE);
+
+ if (done) break;
+ lp = p;
+ dl += dist;
+ }
+ gfx_fill_circle(
+ (int16_t)snake.hcurr->x,(int16_t)snake.hcurr->y,
+ (int16_t)vector_flt_round(snake.size/2),
+ GFX_COLOR_GREEN2
+ );
+
+ snake.hfirst = p;
+ if (!lost) {
+ /* test for intersections in the current direction */
+ /* TODO this is very inefficient.. */
+ segment2d_t s1;
+ p = snake.hcurr;
+ s1.p1 = *p;
+ if (snake.food.placed
+ && (point2d_dist(snake.food.pos,s1.p1) < snake.size)
+ ) {
+ snake.food.placed = false;
+ snake.max_length += 50;
+ snake.speed += 5;
+ }
+
+ done = dec_and_test(&p, snake.hfirst);
+ s1.p2 = *p;
+ if (snake.food.placed
+ && (dist_point_to_segment(snake.food.pos,s1) < snake.size)
+ ) {
+ snake.food.placed = false;
+ }
+ if (!done) {
+ while (p != snake.hcurr) {
+ /* TODO optimize.. */
+ if (dec_and_test(&p, snake.hfirst)) break;
+ segment2d_t s2;
+ s2.p1 = *p;
+ while (true) {
+ bool last_p;
+ last_p = dec_and_test(&p, snake.hfirst);
+ s2.p2 = *p;
+ if (dist_segment_to_segment(s1,s2).distance < snake.size) {
+ lost = true;
+ break;
+ }
+ if (snake.food.placed
+ && (dist_point_to_segment(snake.food.pos,s2) < snake.size)
+ ) {
+ snake.food.placed = false;
+ }
+ if (last_p) break;
+ s2.p1 = s2.p2;
+ }
+ break;
+ }
+ }
+ }
+
+ /* draw food */
+ if (snake.food.placed) {
+ gfx_fill_circle(
+ (int16_t)snake.food.pos.x,(int16_t)snake.food.pos.y,
+ (int16_t)vector_flt_round(snake.size/2),
+ GFX_COLOR_RED
+ );
+ }
+
+ /* check if lost */
+ if (lost) { snake.state = LOST; }
+
+ enable_interrupts();
+}
+static void snake_turn(direction_t dir) {
+ /* snake */
+ switch (snake.state) {
+ case LOST :
+ snake_history_reset();
+ snake.state = STARTED;
+ break;
+ case STARTED :
+ {
+ point2d_t *third_last = snake.hcurr;
+ if (!dec_and_test(&third_last, snake.hfirst)) {
+ dec(third_last);
+ switch (snake.dir) {
+ case RIGHT :
+ case LEFT :
+ if (fabsf(third_last->x-snake.hcurr->x) < snake.size) return;
+ break;
+ case UP :
+ case DOWN :
+ if (fabsf(third_last->y-snake.hcurr->y) < snake.size) return;
+ break;
+ }
+ }
+ switch (dir) {
+ case UP :
+ case DOWN :
+ assert(0);
+ break;
+ case LEFT :
+ if (snake.dir==DOWN) snake.dir = RIGHT;
+ else snake.dir++;
+ break;
+ case RIGHT :
+ if (snake.dir==RIGHT) snake.dir = DOWN;
+ else snake.dir--;
+ break;
+ }
+ point2d_t p = *snake.hcurr;
+ snake.hcurr++;
+ if (snake.hcurr==snake.hend) {
+ snake.hcurr = snake.history;
+ }
+ *snake.hcurr = p;
+ } break;
+ }
+}
+
+
+/**
+ * Main loop
+ */
+
+#define DISPLAY_TIMEOUT 33 /* ~30fps */
+int main(void)
+{
+ /* init timers. */
+ clock_setup();
+
+ /* setup blue button */
+ rcc_periph_clock_enable(RCC_GPIOA);
+ gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO0);
+ exti_select_source(EXTI0, GPIOA);
+ exti_set_trigger(EXTI0, EXTI_TRIGGER_RISING);
+ exti_enable_request(EXTI0);
+ nvic_enable_irq(NVIC_EXTI0_IRQ);
+
+ /* set up SDRAM. */
+ sdram_init();
+
+ /* init LTDC (gfx
+ * cm3 and spi are also initialized by this function call) */
+ ili9341_init(
+ (uint16_t *[]){
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 0*ILI9341_SURFACE_SIZE
+ ),
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 1*ILI9341_SURFACE_SIZE
+ )
+ },
+ (uint16_t *[]){
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 2*ILI9341_SURFACE_SIZE
+ ),
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 3*ILI9341_SURFACE_SIZE
+ )
+ }
+
+ );
+
+
+ /**
+ * setup stmpe811 touchscreen controller (via i2c)
+ */
+ stmpe811_setup_hardware();
+ stmpe811_setup();
+ /* Temperature readings make no sense!
+ stmpe811_start_temp_measurements();
+ msleep(100);
+ for (i=0; i<100000; i++) {
+ uint16_t temp;
+ msleep(11);
+ temp = stmpe811_read_temp_sample();
+ // do something with temp
+ }
+ stmpe811_stop_temp_measuements();
+ */
+ stmpe811_start_tsc();
+ stmpe811_enable_interrupts();
+
+
+ /*
+ * Application start..
+ */
+
+ /* rotate LCD */
+ gfx_set_rotation(GFX_ROTATION_180_DEGREES);
+
+ /* set background color */
+ ltdc_set_background_color(0, 0, 0);
+
+ /* clear unused layers */
+ ili9341_set_layer1();
+ gfx_fill_screen(GFX_COLOR_BLACK);
+ ili9341_flip_layer1_buffer();
+
+ ili9341_set_layer2();
+
+ /* color key sets alpha to 0 (aka clear screen) */
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+ ili9341_flip_layer2_buffer();
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+ ili9341_flip_layer2_buffer();
+
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ while (LTDC_SRCR_IS_RELOADING());
+
+ /* draw background */
+ draw_background();
+
+ /* init snake */
+ init_snake();
+
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+
+ point2d_t touch_point = {0};
+ point2d_t drag_distance = {0};
+ while (1) {
+ uint64_t ctime = mtime();
+ static uint64_t draw_timeout = 1;
+ static char fps_s[32] = " fps";
+
+ if (!LTDC_SRCR_IS_RELOADING() && (draw_timeout <= ctime)) {
+ if (rotate_screen) {
+ rotate_screen = false;
+ gfx_set_rotation((gfx_get_rotation()+1)%(GFX_ROTATION_270_DEGREES+1));
+ draw_background();
+ }
+
+ /* calculate fps */
+ uint32_t fps;
+ fps = 1000 / (ctime-draw_timeout+DISPLAY_TIMEOUT);
+ /* set next timeout */
+ draw_timeout = ctime+DISPLAY_TIMEOUT;
+
+ /* select layer to draw on */
+ ili9341_set_layer2();
+ /* clear the whole screen */
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+
+ /**
+ * Get touch infos
+ */
+ touchscreen_action_t ts_action;
+ ts_action = update_touchscreen_data(&touch_point,&drag_distance);
+ switch (ts_action) {
+ case TS_TOUCHED:
+ if (touch_point.y > gfx_height()/2) {
+ if (touch_point.x < gfx_width()/2) {
+ disable_interrupts();
+ snake_turn(LEFT);
+ enable_interrupts();
+ } else
+ if (touch_point.x > gfx_width()/2) {
+ disable_interrupts();
+ snake_turn(RIGHT);
+ enable_interrupts();
+ }
+ }
+ break;
+ case TS_DRAGGING:
+ break;
+ case TS_DRAGGED:
+ break;
+ case TS_NONE:
+ break;
+ }
+
+ /**
+ * Display touch infos
+ */
+ print_touchscreen_data(2,42,GFX_COLOR_DARKGREY, ts_action,touch_point,drag_distance);
+ //gfx_fill_circle((int16_t)touch_point.x,(int16_t)touch_point.y,10,GFX_COLOR_WHITE);
+
+
+ /* draw fps */
+ gfx_set_font_scale(1);
+ gfx_set_font(&font_Tamsyn5x9r_9);
+ gfx_set_text_color(GFX_COLOR_DARKGREY);
+ sprintf(fps_s, "%lu fps", fps);
+ gfx_puts3(gfx_width()-2,gfx_height()-11,fps_s, GFX_ALIGNMENT_RIGHT);
+
+ /**
+ * Snake
+ */
+ do_snake();
+ char snake_length_s[64];
+ gfx_set_font_scale(1);
+ gfx_set_font(&font_Tamsyn5x9r_9);
+ gfx_set_text_color(GFX_COLOR_WHITE);
+ sprintf(snake_length_s, "snake length:% 6.1f", (double)snake.length);
+ switch (snake.state) {
+ case STARTED:
+ gfx_puts3(gfx_width()-2,17,snake_length_s, GFX_ALIGNMENT_RIGHT);
+ break;
+ case LOST:
+ gfx_draw_rect(20,60,gfx_width()-40,96, GFX_COLOR_DARKGREY);
+ gfx_fill_rect(21,61,gfx_width()-42,94, GFX_COLOR_WHITE);
+
+ gfx_set_font(&font_Tamsyn5x9r_9);
+ gfx_set_text_color(GFX_COLOR_BLACK);
+ gfx_set_font_scale(3);
+ gfx_puts3(gfx_width()/2,65,"Game over!", GFX_ALIGNMENT_CENTER);
+ gfx_set_cursor(25, 100);
+ gfx_set_font_scale(2);
+ gfx_puts(snake_length_s);
+ gfx_set_font_scale(1);
+ gfx_puts("\n"
+ "\n"
+ "\n"
+ "Help:\n"
+ " Blue button rotates the screen\n"
+ " Touch screen controls the snake");
+ break;
+ }
+
+ /* swap the double buffer */
+ ili9341_flip_layer2_buffer();
+
+ /* update dislay */
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ }
+ }
+}
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.c
new file mode 100644
index 00000000..f14a2c9f
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+/*
+ * Now this is just the clock setup code from systick-blink as it is the
+ * transferrable part.
+ */
+
+#include
+#include
+
+/* Common function descriptions */
+#include "clock.h"
+
+/* milliseconds since boot */
+static volatile uint64_t system_millis;
+
+/* Called when systick fires */
+void sys_tick_handler(void)
+{
+ system_millis++;
+}
+
+/* simple sleep for delay milliseconds */
+void milli_sleep(uint32_t delay)
+{
+ uint64_t wake = system_millis + delay;
+ while (wake > system_millis) {
+ continue;
+ }
+}
+
+/* Getter function for the current time */
+uint64_t mtime(void)
+{
+ return system_millis;
+}
+
+/*
+ * clock_setup(void)
+ *
+ * This function sets up both the base board clock rate
+ * and a 1khz "system tick" count. The SYSTICK counter is
+ * a standard feature of the Cortex-M series.
+ */
+void clock_setup(void)
+{
+ /* Base board frequency, set to 168Mhz */
+ rcc_clock_setup_hse_3v3(&CLOCK_SETUP);
+
+ /* clock rate / 168000 to get 1mS interrupt rate */
+ systick_set_reload(168000);
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
+ systick_counter_enable();
+
+ /* this done last */
+ systick_interrupt_enable();
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.h
new file mode 100644
index 00000000..45cb11e6
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/clock.h
@@ -0,0 +1,38 @@
+/*
+ * This include file describes the functions exported by clock.c
+ */
+#ifndef __CLOCK_H
+#define __CLOCK_H
+
+#include
+
+#include
+
+#define CLOCK_SETUP rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]
+
+/*
+ * Definitions for functions being abstracted out
+ */
+void milli_sleep(uint32_t);
+uint64_t mtime(void);
+void clock_setup(void);
+
+/*
+ * Delay functions which are not using clock :)
+ */
+#define CYCLES_PER_LOOP 3
+static inline void wait_cycles(uint32_t n)
+{
+ uint32_t l = n/CYCLES_PER_LOOP;
+ //asm volatile("0:" "SUBS %[count], 1;" "BNE 0b;":[count]"+r"(l));
+ __asm__ __volatile__("0:" "SUBS %[count], 1;" "BNE 0b;":[count]"+r"(l));
+}
+
+static inline void msleep_loop(uint32_t ms)
+{
+ wait_cycles(168000000 / 1000 * ms);
+}
+
+
+#endif /* generic header protector */
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.c
new file mode 100644
index 00000000..efd40f67
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.c
@@ -0,0 +1,864 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#include "Tamsyn5x9b_9.h"
+
+static const uint32_t chars_data_Tamsyn5x9b_9[] = {
+ /* ' ' */
+
+ /* '!' */
+ 0x00000cff,
+ /* '"' */
+ 0x000005ff,
+ /* '#' */
+ 0x00affafa,
+ /* '$' */
+ 0x22fc6e44,
+ /* '%' */
+ 0x08936c91,
+ /* '&' */
+ 0x2ebd9966,
+ /* ''' */
+ 0x0000003f,
+ /* '(' */
+ 0x0c63336c,
+ /* ')' */
+ 0x036ccc63,
+ /* '*' */
+ 0x000576f4,
+ /* '+' */
+ 0x00637cc6,
+ /* ',' */
+ 0x000000f6,
+ /* '-' */
+ 0x0000000f,
+ /* '.' */
+ 0x0000000f,
+ /* '/' */
+ 0x003366cc,
+ /* '0' */
+ 0x0006bbb6,
+ /* '1' */
+ 0x000f6676,
+ /* '2' */
+ 0x000f36c7,
+ /* '3' */
+ 0x0007c6c7,
+ /* '4' */
+ 0x000cfdec,
+ /* '5' */
+ 0x0007c73f,
+ /* '6' */
+ 0x0006b736,
+ /* '7' */
+ 0x000336cf,
+ /* '8' */
+ 0x0006b6b6,
+ /* '9' */
+ 0x0006ceb6,
+ /* ':' */
+ 0x000003cf,
+ /* ';' */
+ 0x0001ec36,
+ /* '<' */
+ 0x000c636c,
+ /* '=' */
+ 0x00000f0f,
+ /* '>' */
+ 0x00036c63,
+ /* '?' */
+ 0x00606cd6,
+ /* '@' */
+ 0x0e33bbb6,
+ /* 'A' */
+ 0x000dfde4,
+ /* 'B' */
+ 0x0007b7b7,
+ /* 'C' */
+ 0x000e333e,
+ /* 'D' */
+ 0x0007bbb7,
+ /* 'E' */
+ 0x000f373f,
+ /* 'F' */
+ 0x0003373f,
+ /* 'G' */
+ 0x000ebb3e,
+ /* 'H' */
+ 0x000bbfbb,
+ /* 'I' */
+ 0x000f666f,
+ /* 'J' */
+ 0x0006dccc,
+ /* 'K' */
+ 0x000bb7bb,
+ /* 'L' */
+ 0x000f3333,
+ /* 'M' */
+ 0x00099ff9,
+ /* 'N' */
+ 0x000ddfbb,
+ /* 'O' */
+ 0x0006bbb6,
+ /* 'P' */
+ 0x000337b7,
+ /* 'Q' */
+ 0x00c6bbb6,
+ /* 'R' */
+ 0x000b77b7,
+ /* 'S' */
+ 0x0007c63e,
+ /* 'T' */
+ 0x0006666f,
+ /* 'U' */
+ 0x0006bbbb,
+ /* 'V' */
+ 0x00027bbb,
+ /* 'W' */
+ 0x0009ff99,
+ /* 'X' */
+ 0x000b666b,
+ /* 'Y' */
+ 0x000666bb,
+ /* 'Z' */
+ 0x000f36cf,
+ /* '[' */
+ 0x001db6df,
+ /* '\' */
+ 0x00cc6633,
+ /* ']' */
+ 0x001f6db7,
+ /* '^' */
+ 0x0000017a,
+ /* '_' */
+ 0x0000001f,
+ /* '`' */
+ 0x00000999,
+ /* 'a' */
+ 0x0000edde,
+ /* 'b' */
+ 0x007bb733,
+ /* 'c' */
+ 0x0000e33e,
+ /* 'd' */
+ 0x00eddecc,
+ /* 'e' */
+ 0x0000e7de,
+ /* 'f' */
+ 0x00666f6c,
+ /* 'g' */
+ 0x006cebbe,
+ /* 'h' */
+ 0x00bbb733,
+ /* 'i' */
+ 0x00f66706,
+ /* 'j' */
+ 0x7cccce0c,
+ /* 'k' */
+ 0x00bb7b33,
+ /* 'l' */
+ 0x00f66667,
+ /* 'm' */
+ 0x0000bbfb,
+ /* 'n' */
+ 0x0000bbb7,
+ /* 'o' */
+ 0x00006bb6,
+ /* 'p' */
+ 0x00337bb7,
+ /* 'q' */
+ 0x00ccedde,
+ /* 'r' */
+ 0x0000333f,
+ /* 's' */
+ 0x0000fc6e,
+ /* 't' */
+ 0x000e66f6,
+ /* 'u' */
+ 0x00006bbb,
+ /* 'v' */
+ 0x000027bb,
+ /* 'w' */
+ 0x0000bfbb,
+ /* 'x' */
+ 0x0000b66b,
+ /* 'y' */
+ 0x006cebbb,
+ /* 'z' */
+ 0x0000f36f,
+ /* '{' */
+ 0x18c7b19c, 0x00000007,
+ /* '|' */
+ 0x00003fff,
+ /* '}' */
+ 0xcc6f18c7, 0x00000001,
+ /* '~' */
+ 0x000005fa,
+ /* '¡' */
+ 0x00000ff3,
+ /* '£' */
+ 0x00f66f6c,
+ /* '«' */
+ 0x00004b72,
+ /* '°' */
+ 0x000006b6,
+ /* '»' */
+ 0x00002769,
+ /* '¿' */
+ 0x006b3606,
+ /* 'Ä' */
+ 0x0dfde409,
+ /* 'Å' */
+ 0x00dfd6d6,
+ /* 'Æ' */
+ 0x000d5f5e,
+ /* 'Ç' */
+ 0x064e333e,
+ /* 'É' */
+ 0x0f373f48,
+ /* 'Ñ' */
+ 0x0ddfb0db,
+ /* 'Ö' */
+ 0x06bbb605,
+ /* '¥' */
+ 0x00066f6b,
+ /* 'Ü' */
+ 0x06bbbb05,
+ /* 'ß' */
+ 0x0007b7be,
+ /* 'à' */
+ 0x00edde21,
+ /* 'á' */
+ 0x00edde48,
+ /* 'â' */
+ 0x0edde052,
+ /* 'ä' */
+ 0x00edde05,
+ /* 'å' */
+ 0x00edd6d6,
+ /* 'æ' */
+ 0x0000f5ef,
+ /* 'ç' */
+ 0x0064e33e,
+ /* 'è' */
+ 0x00e7de21,
+ /* 'é' */
+ 0x00e7de48,
+ /* 'ê' */
+ 0x0e7de052,
+ /* 'ë' */
+ 0x00e7de05,
+ /* 'ì' */
+ 0x00f66721,
+ /* 'í' */
+ 0x00f66748,
+ /* 'î' */
+ 0x0f667052,
+ /* 'ï' */
+ 0x00f66705,
+ /* 'ñ' */
+ 0x0bbb70db,
+ /* 'ò' */
+ 0x006bb621,
+ /* 'ó' */
+ 0x006bb648,
+ /* 'ô' */
+ 0x06bb6052,
+ /* 'ö' */
+ 0x006bb605,
+ /* '÷' */
+ 0x00060f06,
+ /* '¢' */
+ 0x004e33e4,
+ /* 'ù' */
+ 0x006bbb21,
+ /* 'ú' */
+ 0x006bbb24,
+ /* 'û' */
+ 0x06bbb052,
+ /* 'ü' */
+ 0x006bbb05,
+ /* 'ÿ' */
+ 0x6cebbb05
+};
+
+static const char_t chars_Tamsyn5x9b_9[] = {
+ {
+ .utf8_value = 32,
+ .bbox = { 0, 0, 0, 0 },
+ .data = &chars_data_Tamsyn5x9b_9[0]
+ }, {
+ .utf8_value = 33,
+ .bbox = { 1, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[0]
+ }, {
+ .utf8_value = 34,
+ .bbox = { 0, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[1]
+ }, {
+ .utf8_value = 35,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[2]
+ }, {
+ .utf8_value = 36,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[3]
+ }, {
+ .utf8_value = 37,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[4]
+ }, {
+ .utf8_value = 38,
+ .bbox = { 0, 1, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[5]
+ }, {
+ .utf8_value = 39,
+ .bbox = { 1, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[6]
+ }, {
+ .utf8_value = 40,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[7]
+ }, {
+ .utf8_value = 41,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[8]
+ }, {
+ .utf8_value = 42,
+ .bbox = { 0, 1, 4, 6 },
+ .data = &chars_data_Tamsyn5x9b_9[9]
+ }, {
+ .utf8_value = 43,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[10]
+ }, {
+ .utf8_value = 44,
+ .bbox = { 1, 5, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[11]
+ }, {
+ .utf8_value = 45,
+ .bbox = { 0, 4, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[12]
+ }, {
+ .utf8_value = 46,
+ .bbox = { 1, 5, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[13]
+ }, {
+ .utf8_value = 47,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[14]
+ }, {
+ .utf8_value = 48,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[15]
+ }, {
+ .utf8_value = 49,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[16]
+ }, {
+ .utf8_value = 50,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[17]
+ }, {
+ .utf8_value = 51,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[18]
+ }, {
+ .utf8_value = 52,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[19]
+ }, {
+ .utf8_value = 53,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[20]
+ }, {
+ .utf8_value = 54,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[21]
+ }, {
+ .utf8_value = 55,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[22]
+ }, {
+ .utf8_value = 56,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[23]
+ }, {
+ .utf8_value = 57,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[24]
+ }, {
+ .utf8_value = 58,
+ .bbox = { 1, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[25]
+ }, {
+ .utf8_value = 59,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[26]
+ }, {
+ .utf8_value = 60,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[27]
+ }, {
+ .utf8_value = 61,
+ .bbox = { 0, 3, 4, 6 },
+ .data = &chars_data_Tamsyn5x9b_9[28]
+ }, {
+ .utf8_value = 62,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[29]
+ }, {
+ .utf8_value = 63,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[30]
+ }, {
+ .utf8_value = 64,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[31]
+ }, {
+ .utf8_value = 65,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[32]
+ }, {
+ .utf8_value = 66,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[33]
+ }, {
+ .utf8_value = 67,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[34]
+ }, {
+ .utf8_value = 68,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[35]
+ }, {
+ .utf8_value = 69,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[36]
+ }, {
+ .utf8_value = 70,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[37]
+ }, {
+ .utf8_value = 71,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[38]
+ }, {
+ .utf8_value = 72,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[39]
+ }, {
+ .utf8_value = 73,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[40]
+ }, {
+ .utf8_value = 74,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[41]
+ }, {
+ .utf8_value = 75,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[42]
+ }, {
+ .utf8_value = 76,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[43]
+ }, {
+ .utf8_value = 77,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[44]
+ }, {
+ .utf8_value = 78,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[45]
+ }, {
+ .utf8_value = 79,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[46]
+ }, {
+ .utf8_value = 80,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[47]
+ }, {
+ .utf8_value = 81,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[48]
+ }, {
+ .utf8_value = 82,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[49]
+ }, {
+ .utf8_value = 83,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[50]
+ }, {
+ .utf8_value = 84,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[51]
+ }, {
+ .utf8_value = 85,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[52]
+ }, {
+ .utf8_value = 86,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[53]
+ }, {
+ .utf8_value = 87,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[54]
+ }, {
+ .utf8_value = 88,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[55]
+ }, {
+ .utf8_value = 89,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[56]
+ }, {
+ .utf8_value = 90,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[57]
+ }, {
+ .utf8_value = 91,
+ .bbox = { 0, 1, 3, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[58]
+ }, {
+ .utf8_value = 92,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[59]
+ }, {
+ .utf8_value = 93,
+ .bbox = { 1, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[60]
+ }, {
+ .utf8_value = 94,
+ .bbox = { 1, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[61]
+ }, {
+ .utf8_value = 95,
+ .bbox = { 0, 7, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[62]
+ }, {
+ .utf8_value = 96,
+ .bbox = { 1, 1, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[63]
+ }, {
+ .utf8_value = 97,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[64]
+ }, {
+ .utf8_value = 98,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[65]
+ }, {
+ .utf8_value = 99,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[66]
+ }, {
+ .utf8_value = 100,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[67]
+ }, {
+ .utf8_value = 101,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[68]
+ }, {
+ .utf8_value = 102,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[69]
+ }, {
+ .utf8_value = 103,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[70]
+ }, {
+ .utf8_value = 104,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[71]
+ }, {
+ .utf8_value = 105,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[72]
+ }, {
+ .utf8_value = 106,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[73]
+ }, {
+ .utf8_value = 107,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[74]
+ }, {
+ .utf8_value = 108,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[75]
+ }, {
+ .utf8_value = 109,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[76]
+ }, {
+ .utf8_value = 110,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[77]
+ }, {
+ .utf8_value = 111,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[78]
+ }, {
+ .utf8_value = 112,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[79]
+ }, {
+ .utf8_value = 113,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[80]
+ }, {
+ .utf8_value = 114,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[81]
+ }, {
+ .utf8_value = 115,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[82]
+ }, {
+ .utf8_value = 116,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[83]
+ }, {
+ .utf8_value = 117,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[84]
+ }, {
+ .utf8_value = 118,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[85]
+ }, {
+ .utf8_value = 119,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[86]
+ }, {
+ .utf8_value = 120,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[87]
+ }, {
+ .utf8_value = 121,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[88]
+ }, {
+ .utf8_value = 122,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[89]
+ }, {
+ .utf8_value = 123,
+ .bbox = { 0, 1, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[90]
+ }, {
+ .utf8_value = 124,
+ .bbox = { 1, 1, 3, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[92]
+ }, {
+ .utf8_value = 125,
+ .bbox = { 0, 1, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[93]
+ }, {
+ .utf8_value = 126,
+ .bbox = { 0, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[95]
+ }, {
+ .utf8_value = 161,
+ .bbox = { 1, 3, 3, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[96]
+ }, {
+ .utf8_value = 163,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[97]
+ }, {
+ .utf8_value = 171,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[98]
+ }, {
+ .utf8_value = 176,
+ .bbox = { 0, 2, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[99]
+ }, {
+ .utf8_value = 187,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[100]
+ }, {
+ .utf8_value = 191,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[101]
+ }, {
+ .utf8_value = 196,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[102]
+ }, {
+ .utf8_value = 197,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[103]
+ }, {
+ .utf8_value = 198,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[104]
+ }, {
+ .utf8_value = 199,
+ .bbox = { 0, 2, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[105]
+ }, {
+ .utf8_value = 201,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[106]
+ }, {
+ .utf8_value = 209,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[107]
+ }, {
+ .utf8_value = 214,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[108]
+ }, {
+ .utf8_value = 165,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[109]
+ }, {
+ .utf8_value = 220,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[110]
+ }, {
+ .utf8_value = 223,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[111]
+ }, {
+ .utf8_value = 224,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[112]
+ }, {
+ .utf8_value = 225,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[113]
+ }, {
+ .utf8_value = 226,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[114]
+ }, {
+ .utf8_value = 228,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[115]
+ }, {
+ .utf8_value = 229,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[116]
+ }, {
+ .utf8_value = 230,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[117]
+ }, {
+ .utf8_value = 231,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[118]
+ }, {
+ .utf8_value = 232,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[119]
+ }, {
+ .utf8_value = 233,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[120]
+ }, {
+ .utf8_value = 234,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[121]
+ }, {
+ .utf8_value = 235,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[122]
+ }, {
+ .utf8_value = 236,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[123]
+ }, {
+ .utf8_value = 237,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[124]
+ }, {
+ .utf8_value = 238,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[125]
+ }, {
+ .utf8_value = 239,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[126]
+ }, {
+ .utf8_value = 241,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[127]
+ }, {
+ .utf8_value = 242,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[128]
+ }, {
+ .utf8_value = 243,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[129]
+ }, {
+ .utf8_value = 244,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[130]
+ }, {
+ .utf8_value = 246,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[131]
+ }, {
+ .utf8_value = 247,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[132]
+ }, {
+ .utf8_value = 162,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[133]
+ }, {
+ .utf8_value = 249,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[134]
+ }, {
+ .utf8_value = 250,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[135]
+ }, {
+ .utf8_value = 251,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[136]
+ }, {
+ .utf8_value = 252,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[137]
+ }, {
+ .utf8_value = 255,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[138]
+ }
+};
+
+const font_t font_Tamsyn5x9b_9 = {
+ .fontsize = 9,
+ .lineheight = 9,
+ .ascent = 7,
+ .descent = 2,
+ .charwidth = 5,
+ .char_count = 138,
+ .chars = chars_Tamsyn5x9b_9,
+ .chars_data = chars_data_Tamsyn5x9b_9,
+};
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.h
new file mode 100644
index 00000000..eb91f6ac
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9b_9.h
@@ -0,0 +1,25 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#ifndef _TAMSYN5X9B_9_
+#define _TAMSYN5X9B_9_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_Tamsyn5x9b_9;
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.c
new file mode 100644
index 00000000..b82e9bb1
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.c
@@ -0,0 +1,864 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#include "Tamsyn5x9r_9.h"
+
+static const uint32_t chars_data_Tamsyn5x9r_9[] = {
+ /* ' ' */
+
+ /* '!' */
+ 0x0000002f,
+ /* '"' */
+ 0x0000016d,
+ /* '#' */
+ 0x005f5afa,
+ /* '$' */
+ 0x027861e4,
+ /* '%' */
+ 0x00cd24b3,
+ /* '&' */
+ 0x00b5d256,
+ /* ''' */
+ 0x00000007,
+ /* '(' */
+ 0x00889254,
+ /* ')' */
+ 0x002a4911,
+ /* '*' */
+ 0x000096f4,
+ /* '+' */
+ 0x00427c84,
+ /* ',' */
+ 0x0000001b,
+ /* '-' */
+ 0x0000000f,
+ /* '.' */
+ 0x00000003,
+ /* '/' */
+ 0x000094a4,
+ /* '0' */
+ 0x00069996,
+ /* '1' */
+ 0x0000749a,
+ /* '2' */
+ 0x000f2487,
+ /* '3' */
+ 0x0007864f,
+ /* '4' */
+ 0x0004f564,
+ /* '5' */
+ 0x0007871f,
+ /* '6' */
+ 0x00069716,
+ /* '7' */
+ 0x0002244f,
+ /* '8' */
+ 0x00069696,
+ /* '9' */
+ 0x00068e96,
+ /* ':' */
+ 0x000000c3,
+ /* ';' */
+ 0x000006c3,
+ /* '<' */
+ 0x00004454,
+ /* '=' */
+ 0x00000f0f,
+ /* '>' */
+ 0x00001511,
+ /* '?' */
+ 0x00202487,
+ /* '@' */
+ 0x0e11dd96,
+ /* 'A' */
+ 0x00099f96,
+ /* 'B' */
+ 0x00079797,
+ /* 'C' */
+ 0x000e111e,
+ /* 'D' */
+ 0x00079997,
+ /* 'E' */
+ 0x000f171f,
+ /* 'F' */
+ 0x0001171f,
+ /* 'G' */
+ 0x000e9d1e,
+ /* 'H' */
+ 0x00099f99,
+ /* 'I' */
+ 0x00007497,
+ /* 'J' */
+ 0x00069888,
+ /* 'K' */
+ 0x00095359,
+ /* 'L' */
+ 0x000f1111,
+ /* 'M' */
+ 0x000999f9,
+ /* 'N' */
+ 0x00099db9,
+ /* 'O' */
+ 0x00069996,
+ /* 'P' */
+ 0x00011797,
+ /* 'Q' */
+ 0x00c69996,
+ /* 'R' */
+ 0x00095797,
+ /* 'S' */
+ 0x0007861e,
+ /* 'T' */
+ 0x0042109f,
+ /* 'U' */
+ 0x000e9999,
+ /* 'V' */
+ 0x00066999,
+ /* 'W' */
+ 0x0009f999,
+ /* 'X' */
+ 0x00099699,
+ /* 'Y' */
+ 0x00421151,
+ /* 'Z' */
+ 0x000f124f,
+ /* '[' */
+ 0x00e4924f,
+ /* '\' */
+ 0x00024489,
+ /* ']' */
+ 0x00f24927,
+ /* '^' */
+ 0x0000002a,
+ /* '_' */
+ 0x0000001f,
+ /* '`' */
+ 0x00000111,
+ /* 'a' */
+ 0x0000e99e,
+ /* 'b' */
+ 0x00799711,
+ /* 'c' */
+ 0x00000c4e,
+ /* 'd' */
+ 0x00e99e88,
+ /* 'e' */
+ 0x0000e35e,
+ /* 'f' */
+ 0x00222f2c,
+ /* 'g' */
+ 0x0068e99e,
+ /* 'h' */
+ 0x00999711,
+ /* 'i' */
+ 0x0003a4c2,
+ /* 'j' */
+ 0x00724984,
+ /* 'k' */
+ 0x00953511,
+ /* 'l' */
+ 0x0003a493,
+ /* 'm' */
+ 0x000099fd,
+ /* 'n' */
+ 0x00009997,
+ /* 'o' */
+ 0x00006996,
+ /* 'p' */
+ 0x00117997,
+ /* 'q' */
+ 0x0088e99e,
+ /* 'r' */
+ 0x0000113d,
+ /* 's' */
+ 0x0000f42e,
+ /* 't' */
+ 0x000c22f2,
+ /* 'u' */
+ 0x0000e999,
+ /* 'v' */
+ 0x00006699,
+ /* 'w' */
+ 0x0000ff99,
+ /* 'x' */
+ 0x00009669,
+ /* 'y' */
+ 0x0068e999,
+ /* 'z' */
+ 0x0000f24f,
+ /* '{' */
+ 0x0c44744c,
+ /* '|' */
+ 0x0000007f,
+ /* '}' */
+ 0x0322e223,
+ /* '~' */
+ 0x000000db,
+ /* '¡' */
+ 0x0000003d,
+ /* '£' */
+ 0x00f2272c,
+ /* '«' */
+ 0x00004932,
+ /* '°' */
+ 0x00000696,
+ /* '»' */
+ 0x00002649,
+ /* '¿' */
+ 0x00e12404,
+ /* 'Ä' */
+ 0x009fac0a,
+ /* 'Å' */
+ 0x009fa4ac,
+ /* 'Æ' */
+ 0x000d5f5e,
+ /* 'Ç' */
+ 0x064e111e,
+ /* 'É' */
+ 0x0f171f48,
+ /* 'Ñ' */
+ 0x09db90db,
+ /* 'Ö' */
+ 0x06999609,
+ /* '¥' */
+ 0x084f9151,
+ /* 'Ü' */
+ 0x06999905,
+ /* 'ß' */
+ 0x0005959e,
+ /* 'à' */
+ 0x00e99e21,
+ /* 'á' */
+ 0x00e99e48,
+ /* 'â' */
+ 0x0e99e0a4,
+ /* 'ä' */
+ 0x00e99e0a,
+ /* 'å' */
+ 0x0e99e4ac,
+ /* 'æ' */
+ 0x0000f5ef,
+ /* 'ç' */
+ 0x0001ac4e,
+ /* 'è' */
+ 0x00e35e21,
+ /* 'é' */
+ 0x00e35e48,
+ /* 'ê' */
+ 0x0e35e0a4,
+ /* 'ë' */
+ 0x00e35e0a,
+ /* 'ì' */
+ 0x0003a4d1,
+ /* 'í' */
+ 0x0003a4d4,
+ /* 'î' */
+ 0x001d262a,
+ /* 'ï' */
+ 0x0003a4c5,
+ /* 'ñ' */
+ 0x099970db,
+ /* 'ò' */
+ 0x00699621,
+ /* 'ó' */
+ 0x00699648,
+ /* 'ô' */
+ 0x06996052,
+ /* 'ö' */
+ 0x00699609,
+ /* '÷' */
+ 0x000021c2,
+ /* '¢' */
+ 0x004e55e4,
+ /* 'ù' */
+ 0x00699921,
+ /* 'ú' */
+ 0x00699948,
+ /* 'û' */
+ 0x06999052,
+ /* 'ü' */
+ 0x00699905,
+ /* 'ÿ' */
+ 0x68e99905
+};
+
+static const char_t chars_Tamsyn5x9r_9[] = {
+ {
+ .utf8_value = 32,
+ .bbox = { 0, 0, 0, 0 },
+ .data = &chars_data_Tamsyn5x9r_9[0]
+ }, {
+ .utf8_value = 33,
+ .bbox = { 1, 1, 2, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[0]
+ }, {
+ .utf8_value = 34,
+ .bbox = { 0, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[1]
+ }, {
+ .utf8_value = 35,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[2]
+ }, {
+ .utf8_value = 36,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[3]
+ }, {
+ .utf8_value = 37,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[4]
+ }, {
+ .utf8_value = 38,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[5]
+ }, {
+ .utf8_value = 39,
+ .bbox = { 1, 1, 2, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[6]
+ }, {
+ .utf8_value = 40,
+ .bbox = { 0, 1, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[7]
+ }, {
+ .utf8_value = 41,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[8]
+ }, {
+ .utf8_value = 42,
+ .bbox = { 0, 2, 4, 6 },
+ .data = &chars_data_Tamsyn5x9r_9[9]
+ }, {
+ .utf8_value = 43,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[10]
+ }, {
+ .utf8_value = 44,
+ .bbox = { 1, 6, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[11]
+ }, {
+ .utf8_value = 45,
+ .bbox = { 0, 4, 4, 5 },
+ .data = &chars_data_Tamsyn5x9r_9[12]
+ }, {
+ .utf8_value = 46,
+ .bbox = { 1, 6, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[13]
+ }, {
+ .utf8_value = 47,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[14]
+ }, {
+ .utf8_value = 48,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[15]
+ }, {
+ .utf8_value = 49,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[16]
+ }, {
+ .utf8_value = 50,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[17]
+ }, {
+ .utf8_value = 51,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[18]
+ }, {
+ .utf8_value = 52,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[19]
+ }, {
+ .utf8_value = 53,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[20]
+ }, {
+ .utf8_value = 54,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[21]
+ }, {
+ .utf8_value = 55,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[22]
+ }, {
+ .utf8_value = 56,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[23]
+ }, {
+ .utf8_value = 57,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[24]
+ }, {
+ .utf8_value = 58,
+ .bbox = { 1, 3, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[25]
+ }, {
+ .utf8_value = 59,
+ .bbox = { 1, 3, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[26]
+ }, {
+ .utf8_value = 60,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[27]
+ }, {
+ .utf8_value = 61,
+ .bbox = { 0, 3, 4, 6 },
+ .data = &chars_data_Tamsyn5x9r_9[28]
+ }, {
+ .utf8_value = 62,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[29]
+ }, {
+ .utf8_value = 63,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[30]
+ }, {
+ .utf8_value = 64,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[31]
+ }, {
+ .utf8_value = 65,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[32]
+ }, {
+ .utf8_value = 66,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[33]
+ }, {
+ .utf8_value = 67,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[34]
+ }, {
+ .utf8_value = 68,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[35]
+ }, {
+ .utf8_value = 69,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[36]
+ }, {
+ .utf8_value = 70,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[37]
+ }, {
+ .utf8_value = 71,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[38]
+ }, {
+ .utf8_value = 72,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[39]
+ }, {
+ .utf8_value = 73,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[40]
+ }, {
+ .utf8_value = 74,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[41]
+ }, {
+ .utf8_value = 75,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[42]
+ }, {
+ .utf8_value = 76,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[43]
+ }, {
+ .utf8_value = 77,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[44]
+ }, {
+ .utf8_value = 78,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[45]
+ }, {
+ .utf8_value = 79,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[46]
+ }, {
+ .utf8_value = 80,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[47]
+ }, {
+ .utf8_value = 81,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[48]
+ }, {
+ .utf8_value = 82,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[49]
+ }, {
+ .utf8_value = 83,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[50]
+ }, {
+ .utf8_value = 84,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[51]
+ }, {
+ .utf8_value = 85,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[52]
+ }, {
+ .utf8_value = 86,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[53]
+ }, {
+ .utf8_value = 87,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[54]
+ }, {
+ .utf8_value = 88,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[55]
+ }, {
+ .utf8_value = 89,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[56]
+ }, {
+ .utf8_value = 90,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[57]
+ }, {
+ .utf8_value = 91,
+ .bbox = { 0, 1, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[58]
+ }, {
+ .utf8_value = 92,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[59]
+ }, {
+ .utf8_value = 93,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[60]
+ }, {
+ .utf8_value = 94,
+ .bbox = { 0, 2, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[61]
+ }, {
+ .utf8_value = 95,
+ .bbox = { 0, 7, 5, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[62]
+ }, {
+ .utf8_value = 96,
+ .bbox = { 0, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[63]
+ }, {
+ .utf8_value = 97,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[64]
+ }, {
+ .utf8_value = 98,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[65]
+ }, {
+ .utf8_value = 99,
+ .bbox = { 1, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[66]
+ }, {
+ .utf8_value = 100,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[67]
+ }, {
+ .utf8_value = 101,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[68]
+ }, {
+ .utf8_value = 102,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[69]
+ }, {
+ .utf8_value = 103,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[70]
+ }, {
+ .utf8_value = 104,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[71]
+ }, {
+ .utf8_value = 105,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[72]
+ }, {
+ .utf8_value = 106,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[73]
+ }, {
+ .utf8_value = 107,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[74]
+ }, {
+ .utf8_value = 108,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[75]
+ }, {
+ .utf8_value = 109,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[76]
+ }, {
+ .utf8_value = 110,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[77]
+ }, {
+ .utf8_value = 111,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[78]
+ }, {
+ .utf8_value = 112,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[79]
+ }, {
+ .utf8_value = 113,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[80]
+ }, {
+ .utf8_value = 114,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[81]
+ }, {
+ .utf8_value = 115,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[82]
+ }, {
+ .utf8_value = 116,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[83]
+ }, {
+ .utf8_value = 117,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[84]
+ }, {
+ .utf8_value = 118,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[85]
+ }, {
+ .utf8_value = 119,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[86]
+ }, {
+ .utf8_value = 120,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[87]
+ }, {
+ .utf8_value = 121,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[88]
+ }, {
+ .utf8_value = 122,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[89]
+ }, {
+ .utf8_value = 123,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[90]
+ }, {
+ .utf8_value = 124,
+ .bbox = { 1, 1, 2, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[91]
+ }, {
+ .utf8_value = 125,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[92]
+ }, {
+ .utf8_value = 126,
+ .bbox = { 0, 2, 4, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[93]
+ }, {
+ .utf8_value = 161,
+ .bbox = { 1, 3, 2, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[94]
+ }, {
+ .utf8_value = 163,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[95]
+ }, {
+ .utf8_value = 171,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[96]
+ }, {
+ .utf8_value = 176,
+ .bbox = { 0, 2, 4, 5 },
+ .data = &chars_data_Tamsyn5x9r_9[97]
+ }, {
+ .utf8_value = 187,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[98]
+ }, {
+ .utf8_value = 191,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[99]
+ }, {
+ .utf8_value = 196,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[100]
+ }, {
+ .utf8_value = 197,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[101]
+ }, {
+ .utf8_value = 198,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[102]
+ }, {
+ .utf8_value = 199,
+ .bbox = { 0, 2, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[103]
+ }, {
+ .utf8_value = 201,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[104]
+ }, {
+ .utf8_value = 209,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[105]
+ }, {
+ .utf8_value = 214,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[106]
+ }, {
+ .utf8_value = 165,
+ .bbox = { 0, 1, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[107]
+ }, {
+ .utf8_value = 220,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[108]
+ }, {
+ .utf8_value = 223,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[109]
+ }, {
+ .utf8_value = 224,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[110]
+ }, {
+ .utf8_value = 225,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[111]
+ }, {
+ .utf8_value = 226,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[112]
+ }, {
+ .utf8_value = 228,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[113]
+ }, {
+ .utf8_value = 229,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[114]
+ }, {
+ .utf8_value = 230,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[115]
+ }, {
+ .utf8_value = 231,
+ .bbox = { 1, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[116]
+ }, {
+ .utf8_value = 232,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[117]
+ }, {
+ .utf8_value = 233,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[118]
+ }, {
+ .utf8_value = 234,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[119]
+ }, {
+ .utf8_value = 235,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[120]
+ }, {
+ .utf8_value = 236,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[121]
+ }, {
+ .utf8_value = 237,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[122]
+ }, {
+ .utf8_value = 238,
+ .bbox = { 0, 0, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[123]
+ }, {
+ .utf8_value = 239,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[124]
+ }, {
+ .utf8_value = 241,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[125]
+ }, {
+ .utf8_value = 242,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[126]
+ }, {
+ .utf8_value = 243,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[127]
+ }, {
+ .utf8_value = 244,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[128]
+ }, {
+ .utf8_value = 246,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[129]
+ }, {
+ .utf8_value = 247,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[130]
+ }, {
+ .utf8_value = 162,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[131]
+ }, {
+ .utf8_value = 249,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[132]
+ }, {
+ .utf8_value = 250,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[133]
+ }, {
+ .utf8_value = 251,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[134]
+ }, {
+ .utf8_value = 252,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[135]
+ }, {
+ .utf8_value = 255,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[136]
+ }
+};
+
+const font_t font_Tamsyn5x9r_9 = {
+ .fontsize = 9,
+ .lineheight = 9,
+ .ascent = 7,
+ .descent = 2,
+ .charwidth = 5,
+ .char_count = 138,
+ .chars = chars_Tamsyn5x9r_9,
+ .chars_data = chars_data_Tamsyn5x9r_9,
+};
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.h
new file mode 100644
index 00000000..edb7c8b2
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/Tamsyn5x9r_9.h
@@ -0,0 +1,25 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#ifndef _TAMSYN5X9R_9_
+#define _TAMSYN5X9R_9_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_Tamsyn5x9r_9;
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/fonts.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/fonts.h
new file mode 100644
index 00000000..9e0c157e
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/fonts.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+/**
+ * Fonts library
+ */
+#ifndef FONTS_H
+#define FONTS_H
+
+#include
+#include
+
+/*
+ * the holds the offsets for the data relative to the default char size
+ * and the data width/height
+ * eg. :
+ * m,o = font.getmask2(c, mode="1")
+ * bbox = m.getbbox()
+ * x1 = (charwidth - bbox[2])/2
+ * y1 = (o[1]-offset[1] + bbox[1])
+ * x2 = x1 + bbox[2]-bbox[0]
+ * y2 = y1 + bbox[3]-bbox[1]
+ */
+typedef struct {
+ uint32_t x1, y1, x2, y2;
+} char_data_bbox_t;
+
+typedef struct {
+ uint32_t utf8_value;
+ char_data_bbox_t bbox;
+ const uint32_t *data; /* pointer to char_data_offset */
+} char_t;
+
+typedef struct {
+ uint8_t fontsize;
+ uint8_t lineheight;
+ uint8_t ascent;
+ uint8_t descent;
+ uint8_t charwidth;
+ uint16_t char_count;
+ /* pointer to chars array (sorted by utf8_value) */
+ const char_t *chars;
+ /* pointer to chars_data array */
+ const uint32_t *chars_data;
+} font_t;
+
+/* binary search for char */
+static inline
+const char_t*
+font_get_char_index(uint32_t utf8_value, const font_t *font) {
+ uint32_t s, e, i, j, cc;
+ s = j = 0;
+ e = font->char_count-1;
+ while (1) {
+ i = (s+e)>>1;
+ cc = font->chars[i].utf8_value;
+ if (utf8_value < cc) {
+ e = i;
+ } else
+ if (utf8_value > cc) {
+ s = i;
+ } else {
+ return &font->chars[i];
+ }
+ if (i == j) {
+ return NULL;
+ }
+ j = i;
+ }
+}
+
+#endif
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/create_font.py b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/create_font.py
new file mode 100755
index 00000000..7e6cd7f2
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/create_font.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+# This file is part of the libopencm3 project.
+#
+# Copyright (C) 2016 Oliver Meier
+#
+# This library is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see .
+#
+
+
+from sys import argv,stdout
+from os.path import isfile, dirname, basename, splitext, join
+from PIL import Image, ImageFont, ImageDraw
+import codecs
+
+print len(argv),argv
+
+if len(argv)<3 or len(argv)>4 or (len(argv)==4 and not isfile(argv[3])) :
+ print "usage: ./Create_Font.py ./font.ttf fontsize [charsetfile-utf8.txt]"
+ print " - ./font.ttf can also be ./font.pcf or something like Arial or so
+ exit(0)
+
+fontfile = argv[1]
+fontsize = None
+try :
+ fontsize = int(argv[2])
+except :
+ print "Fontsize is not a number!"
+ exit(0)
+
+if len(argv)==4 :
+ charsetfile = argv[3]
+else :
+ charsetfile = join(dirname(argv[0]),"default_charset.txt")
+
+
+#fontfile = "Tamsyn5x9r.pcf"
+#fontfile = "Tamsyn5x9b.pcf"
+#fontfile = "/usr/share/fonts/liberation/LiberationMono-Regular.ttf"
+#fontfile = "/usr/share/fonts/liberation/LiberationMono-Bold.ttf"
+#fontfile = "/usr/share/fonts/dejavu/DejaVuSansMono.ttf"
+#fontfile = "/usr/share/fonts/dejavu/DejaVuSansMono-Bold.ttf"
+#fontfile = "/usr/share/fonts/gnu-free/FreeMono.ttf"
+#fontfile = "Arial"
+#fontsize = 9
+datasize = 32
+
+charset = codecs.open(charsetfile,'r','utf-8').read().replace('\n','').replace('\r','')
+# sort charset and remove duplicates
+charset = ''.join(sorted(set(charset), key=charset.index))
+font = ImageFont.truetype(fontfile,size=fontsize)
+
+filtered_charset = u""
+for c in charset :
+ if c<>u' ' :
+ m,o = font.getmask2(c, mode="1")
+ if m.getbbox()==None :
+ print "Dropping:",c.encode('utf-8')
+ continue
+ filtered_charset+=c
+charset = filtered_charset
+
+
+
+#render all the text (needed to determine img size)
+dummy_img,offset = font.getmask2(charset, mode="1")
+
+ascent,descent = font.getmetrics()
+lineheight = dummy_img.size[1]+offset[1]
+charwidth = font.getsize("MMM")[0]-font.getsize("MM")[0]
+totalwidth = charwidth*len(charset)
+charset_imgsize = (totalwidth,lineheight)
+
+
+
+charset_image = Image.new(mode="1", size=charset_imgsize)
+d=ImageDraw.Draw(charset_image)
+d.rectangle(((0,0),charset_imgsize), fill=0, outline=None)
+offx=0
+
+
+fontname = splitext(basename(fontfile))[0]+"_"+str(fontsize)
+fontname = fontname.replace("-","_")
+
+print "Creating font", fontname
+
+
+chars_table_name = "chars_"+fontname
+data_table_name = "chars_data_"+fontname
+chars_table = "static const char_t "+chars_table_name+"[] = {\n\t"
+data_table = "static const uint"+str(datasize)+"_t "+data_table_name+"[] = {"
+data_table_offset = 0; v=0; i=0; fmt = "0x%%0%dx,"%(datasize/8*2)
+for c in charset :
+ x1 = y1 = x2 = y2 = 0
+ bbox = (0,0,0,0)
+ if c<>u' ' :
+ m,o = font.getmask2(c, mode="1")
+ bbox = m.getbbox()
+ x1 = (charwidth - bbox[2])/2
+ y1 = (o[1]-offset[1] + bbox[1])
+ x2 = x1 + bbox[2]-bbox[0]
+ y2 = y1 + bbox[3]-bbox[1]
+
+
+ stdout.write((u"%s"%c).encode('utf-8'))
+ #print "",x1,x2,y1,y2
+
+ # dummy image
+ if c<>u' ' :
+ d.draw.draw_bitmap((offx+x1,y1),m.crop(bbox),255)
+ offx += charwidth
+
+ # fill data in chars table
+ chars_table+= """{
+ .utf8_value = %d,
+ .bbox = { % 2d,% 2d,% 2d,% 2d },
+ .data = &%s[%d]
+ }, """ %(
+ ord(c),
+ x1,y1,x2,y2,
+ data_table_name,data_table_offset
+ )
+
+ # fill data in chars data table
+ data_table+= "\n\t/* '%s' */\n\t" %c
+
+ i=0; v=0; lc = 0
+ for y in range(bbox[1],bbox[3]) :
+ for x in range(bbox[0],bbox[2]) :
+ v |= (m.getpixel((x,y))==255) << i
+ i+=1
+ if i==datasize :
+ if lc > 0 : data_table += " "
+ data_table += fmt %v
+ i=0; v=0
+ data_table_offset += 1
+ lc+=1
+ if lc==4 :
+ data_table += "\n\t"
+ lc=0
+
+ # finish last data_table entry
+ if v<>0 :
+ if lc > 0 : data_table += " "
+ data_table += fmt %v
+ data_table_offset += 1
+ elif lc==0 :
+ data_table = data_table[:-1]
+
+data_table = data_table[:-1] + "\n};"
+
+chars_table = chars_table[:-2] + "\n};"
+
+
+charset_image.save(fontname+".pbm")
+
+
+fnu = fontname.upper()
+
+fontsize_definition = "%s %d"%(fnu,fontsize)
+
+header_filename = "%s.h"%fontname
+header_file = """
+#ifndef _%s_
+#define _%s_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_%s;
+
+#endif
+""" %(
+ fnu,fnu,
+ fontname
+)
+
+c_filename = "%s.c"%fontname
+c_file = """
+#include "%s"
+
+%s
+
+%s
+
+const font_t font_%s = {
+ .fontsize = %d,
+ .lineheight = %d,
+ .ascent = %d,
+ .descent = %d,
+ .charwidth = %d,
+ .char_count = %d,
+ .chars = %s,
+ .chars_data = %s,
+};
+
+""" %(
+ header_filename,
+ data_table,
+ chars_table,
+ fontname, fontsize, lineheight, ascent, descent, charwidth,
+ len(charset),chars_table_name, data_table_name,
+)
+
+
+open(header_filename,'w').write(header_file.encode('utf-8'))
+open(c_filename,'w').write(c_file.encode('utf-8'))
+
+print "\ndone."
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/default_charset.txt b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/default_charset.txt
new file mode 100644
index 00000000..9a2864c7
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/default_charset.txt
@@ -0,0 +1 @@
+ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡╜£╧╛▌⌡∙╕ª«¬≡⌐ε°±²ⁿ∩µ⌠·≈√º»¼½≤¿╖╡╢╟ÄÅÆÇ╘É╥╙▐╓╫╪╤ÑπαΓσÖ₧¥δΘΩÜφΦßàáâ╞äåæçèéêëìíîï╨ñòóôΣö÷¢ùúûü∞τÿΩ
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/image_to_rgb565-array.py b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/image_to_rgb565-array.py
new file mode 100755
index 00000000..b55f4f5a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/tools/image_to_rgb565-array.py
@@ -0,0 +1,80 @@
+# This file is part of the libopencm3 project.
+#
+# Copyright (C) 2016 Oliver Meier
+#
+# This library is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see .
+#
+
+from PIL import Image
+from sys import argv
+from os.path import isfile, splitext
+from math import floor
+
+if (not(len(argv)==2 or len(argv)==3)) or not isfile(argv[1]) :
+ print "usage Image...py filename.png width_in_px"
+ exit(0)
+
+infile = argv[1]
+
+basename = splitext(infile)[0]
+outfile = basename+"_RGB565.h"
+if isfile(outfile) :
+ print outfile , "already exists"
+ exit(0)
+
+
+# die here if not an image
+try :
+ img = Image.open(infile)
+except IOError, ex :
+ print "Opening image failed"
+ print "\tPIL(IOError) :",ex.message
+ exit(0)
+
+if len(argv)==3 :
+ try :
+ width = int(argv[2])
+ if img.size[0]<>width :
+ new_size = (width,int(img.size[1]*width/img.size[0]))
+ print "resizing image from",img.size,"to",new_size
+ img = img.resize(new_size,Image.ANTIALIAS)
+ img.show(title="Resized image")
+ except :
+ print "Invalid width"
+ print "usage Image...py filename.png width_in_px"
+ exit(0)
+
+print "image size is",img.size
+width = img.size[0]
+data = img.tobytes(encoder_name='raw')
+
+pixels_per_line = 16
+of = open(outfile,'w')
+of.write("#include \n")
+of.write("#define %s_WIDTH %d\n" %(basename.upper(), width))
+of.write("#define %s_HEIGHT %d\n" %(basename.upper(), len(data)/4/width))
+of.write("const uint16_t %s[] = {" %(basename))
+i = 0
+while i>3); i+=1
+ g = int(ord(data[i])>>2); i+=1
+ b = int(ord(data[i])>>3); i+=1
+ i+=1 # skip alpha
+ i16 = (r<<11) | (g<<5) | b
+ of.write("0x%04x" %(i16))
+of.write("\n};")
+of.close()
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/utf8.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/utf8.h
new file mode 100644
index 00000000..24cf2142
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/fonts/utf8.h
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef UTF8_H_
+#define UTF8_H_
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include
+
+/**
+ *
+ * @param text utf8 string
+ * @param value pointer which holds the utf value after the function returns
+ * @return pointer to the next value in string (-1 for invalid value)
+ */
+static inline
+const char *
+utf8_read_value(const char *text, int32_t *value)
+{
+ char tmp; uint8_t cnt, i;
+
+ tmp = *text++;
+
+ if (!(tmp & 0b10000000)) {
+ *value = tmp;
+ return text;
+ } else
+ if ((tmp & 0b11100000) == 0b11000000) {
+ *value = tmp & ~0b11100000;
+ cnt = 1;
+ } else
+ if ((tmp & 0b11110000) == 0b11100000) {
+ *value = tmp & ~0b11110000;
+ cnt = 2;
+ } else
+ if ((tmp & 0b11111000) == 0b11110000) {
+ *value = tmp & ~0b11111000;
+ cnt = 3;
+ } else {
+ *value = -1;
+ return text;
+ }
+
+ for (i = cnt; i; i--) {
+ tmp = *text++;
+ if ((tmp & 0b11000000) != 0b10000000) {
+ *value = -1;
+ return text;
+ }
+
+ *value = (*value<<6) | (tmp & ~0b11000000);
+ }
+
+ return text;
+}
+
+
+/* utf-8 ... */
+static inline
+const char *
+utf8_find_character_index(
+ int index,
+ const char *text_start, const char *text_end,
+ int *index_rest
+) {
+ const char *result;
+ if (index < 0) {
+ result = text_end;
+ while (index && result != text_start) {
+ index++;
+ result--;
+ /* skip next utf8-character (secondary bytes) */
+ while (((*result)&192) == 128 && result != text_start) {
+ result--;
+ }
+ }
+ } else {
+ result = text_start;
+ while (index && result != text_end) {
+ index--;
+ result++;
+ /* skip last utf8-character (secondary bytes) */
+ while (((*result)&192) == 128 && result != text_end) {
+ result++;
+ }
+ }
+ }
+
+ if (index_rest != NULL) {
+ *index_rest = index;
+ }
+
+ return result;
+}
+
+
+/* untestet! */
+static inline
+const char *utf8_find_character_in_string(
+ const char chr,
+ const char *text_start, const char *text_end
+ /*, int *index_rest */
+) {
+ const char *result = text_start;
+ while (result != text_end) {
+ if (*result == chr) {
+ break;
+ }
+ result = utf8_find_character_index(1, result, text_end, NULL);
+ }
+ return result;
+}
+static inline
+int utf8_find_pointer_diff(const char *text_start, const char *text_end)
+{
+ int diff = 0;
+ while (text_start < text_end) {
+ if (!*text_start) {
+ return -1;
+ }
+
+ text_start++;
+ diff++;
+ /* skip last utf8-character (secondary bytes) */
+ while (((*text_start)&192) == 128 && text_start < text_end) {
+ text_start++;
+ }
+ }
+ return diff;
+}
+
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.c
new file mode 100644
index 00000000..1d1f649a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.c
@@ -0,0 +1,1311 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ *
+ *
+ * This code is based on a fork off a graphics example for libopencm3 made
+ * by Charles McManis in 2014.
+ * The basic drawing functions (circle, line, round-rectangle) are based on
+ * the simple graphics library written by the folks at AdaFruit.
+ * [Adafruit_GFX.cpp](/adafruit/Adafruit-GFX-Library/blob/master/Adafruit_GFX.cpp)
+ *
+ * Graphics lib, possible history
+ * --Probably Knuth, Ada and/or Plato
+ * --WIKIPEDIA
+ * --ADAFRUIT (?, 2013)
+ * --Chuck McManis (2013, 2014)
+ * --Tilen Majerle (2014)
+ * --Oliver Meier (2014+)
+ */
+
+
+#include "gfx_locm3.h"
+
+gfx_state_t __gfx_state = {0};
+
+/*
+ * Make sure the surface is aligned for 32bit!
+ */
+void
+gfx_init(uint16_t *surface, int32_t width, int32_t height)
+{
+ __gfx_state.is_offscreen_rendering = 0;
+
+ *(uint16_t *)&__gfx_state.width_orig = width;
+ *(uint16_t *)&__gfx_state.height_orig = height;
+ *(uint32_t *)&__gfx_state.pixel_count = (uint32_t)width*(uint32_t)height;
+ __gfx_state.width = width;
+ __gfx_state.height = height;
+ __gfx_state.visible_area = (visible_area_t){0, 0, width, height};
+ __gfx_state.rotation = 0;
+ __gfx_state.cursor_y = __gfx_state.cursor_x = __gfx_state.cursor_x_orig
+ = 0;
+ __gfx_state.fontscale = 1;
+ __gfx_state.textcolor = 0;
+ __gfx_state.wrap = true;
+ __gfx_state.surface = surface;
+ __gfx_state.font = NULL;
+}
+
+static gfx_state_t __gfx_state_bkp = {0};
+
+void gfx_set_surface(uint16_t *surface)
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ __gfx_state_bkp.surface = surface;
+ } else {
+ __gfx_state.surface = surface;
+ }
+}
+uint16_t *
+gfx_get_surface()
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ return __gfx_state_bkp.surface;
+ } else {
+ return __gfx_state.surface;
+ }
+}
+
+void gfx_offscreen_rendering_begin(
+ uint16_t *surface,
+ int32_t width,
+ int32_t height
+) {
+ if (!__gfx_state.is_offscreen_rendering) {
+ /*gfx_state_bkp = __gfx_state; ???*/
+ memcpy(&__gfx_state_bkp, &__gfx_state, sizeof(gfx_state_t));
+ }
+ gfx_init(surface, width, height);
+ __gfx_state.is_offscreen_rendering = 1;
+}
+void gfx_offscreen_rendering_end()
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ memcpy(&__gfx_state, &__gfx_state_bkp, sizeof(gfx_state_t));
+ }
+}
+
+void
+gfx_set_clipping_area_max()
+{
+ __gfx_state.visible_area =
+ (visible_area_t){
+ 0, 0, __gfx_state.width, __gfx_state.height
+ };
+}
+void
+gfx_set_clipping_area(int16_t x1, int16_t y1, int16_t x2, int16_t y2) {
+ if (x1 < 0) {
+ x1 = 0;
+ }
+ if (y1 < 0) {
+ y1 = 0;
+ }
+ if (x2 < x1) {
+ x2 = x1;
+ }
+ if (y2 < y1) {
+ y2 = y1;
+ }
+ __gfx_state.visible_area = (visible_area_t){x1, y1, x2, y2};
+}
+visible_area_t
+gfx_get_surface_visible_area() {
+ return __gfx_state.visible_area;
+}
+
+
+/*
+ * just write a RGB565 color to each pixel in the current buffer/surface
+ * this function assumes 32bit aligned buffer!
+ */
+void gfx_fill_screen(uint16_t color)
+{
+ uint32_t color2 = (color<<16)|color;
+
+ uint32_t i; uint32_t *pixel_addr;
+ pixel_addr = (uint32_t *)__gfx_state.surface;
+ for (i = 0; i < __gfx_state.pixel_count/2; i++) {
+ *pixel_addr++ = color2;
+ }
+ if (__gfx_state.pixel_count & 1) {
+ *(__gfx_state.surface+(__gfx_state.pixel_count-1)) = color;
+ }
+
+ /*
+ uint32_t i; uint16_t *pixel_addr;
+ pixel_addr = __gfx_state.surface;
+ for (i = 0; i < __gfx_state.pixel_count&1; i++) {
+ *pixel_addr++ = color;
+ }
+ */
+}
+
+
+
+/* change the rotation and flip width and height accordingly */
+void gfx_set_rotation(gfx_rotation_t rotation)
+{
+ if ((rotation == GFX_ROTATION_0_DEGREES)
+ || (rotation == GFX_ROTATION_180_DEGREES)
+ ) {
+ __gfx_state.width = __gfx_state.width_orig;
+ __gfx_state.height = __gfx_state.height_orig;
+ } else {
+ __gfx_state.width = __gfx_state.height_orig;
+ __gfx_state.height = __gfx_state.width_orig;
+ }
+ __gfx_state.rotation = rotation;
+ gfx_set_clipping_area_max();
+}
+gfx_rotation_t gfx_get_rotation(void)
+{
+ return __gfx_state.rotation;
+}
+/* Return the size of the display (per current rotation) */
+uint16_t gfx_width(void)
+{
+ return __gfx_state.width;
+}
+
+uint16_t gfx_height(void)
+{
+ return __gfx_state.height;
+}
+
+
+/* GFX_GLOBAL_DISPLAY_SCALE can be used as a zoom function
+ * while debugging code..
+ *
+ * NOTE: This breaks offscreen rendering!!
+ */
+#define GFX_GLOBAL_DISPLAY_SCALE 1
+
+static inline uint16_t *gfx_get_pixel_address(int16_t x, int16_t y)
+{
+ uint16_t *pixel_addr;
+ pixel_addr = __gfx_state.surface;
+ switch (__gfx_state.rotation) {
+ case GFX_ROTATION_0_DEGREES:
+ pixel_addr += (x + y*__gfx_state.width_orig);
+ break;
+ case GFX_ROTATION_270_DEGREES:
+ pixel_addr += (x*__gfx_state.width_orig + __gfx_state.width_orig - y) - GFX_GLOBAL_DISPLAY_SCALE;
+ break;
+ case GFX_ROTATION_180_DEGREES:
+ pixel_addr += __gfx_state.pixel_count - (x + (y + (GFX_GLOBAL_DISPLAY_SCALE-1)) * __gfx_state.width_orig) - GFX_GLOBAL_DISPLAY_SCALE;
+ break;
+ case GFX_ROTATION_90_DEGREES:
+ pixel_addr += __gfx_state.pixel_count - ((x + (GFX_GLOBAL_DISPLAY_SCALE-1)) * __gfx_state.width_orig + __gfx_state.width_orig-y);
+ break;
+ }
+ return pixel_addr;
+}
+
+
+#if GFX_GLOBAL_DISPLAY_SCALE > 1
+#define GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X -10
+#define GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y -40
+
+/*
+ * draw a single pixel
+ * changes buffer addressing (surface) according to orientation
+ */
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color)
+{
+ x += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X;
+ y += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y;
+ x *= GFX_GLOBAL_DISPLAY_SCALE;
+ y *= GFX_GLOBAL_DISPLAY_SCALE;
+
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ ) {
+ return;
+ }
+
+ uint16_t *pa = gfx_get_pixel_address(x, y);
+ for (uint32_t sa = 0; sa < GFX_GLOBAL_DISPLAY_SCALE; sa++) {
+ for (uint32_t sb = 0; sb < GFX_GLOBAL_DISPLAY_SCALE; sb++) {
+ *(pa+sb) = color;
+ }
+ pa += __gfx_state.width_orig;
+ }
+
+ return;
+}
+
+/*
+ * get a single pixel
+ */
+int32_t gfx_get_pixel(int16_t x, int16_t y)
+{
+ x += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X;
+ y += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y;
+ x *= GFX_GLOBAL_DISPLAY_SCALE;
+ y *= GFX_GLOBAL_DISPLAY_SCALE;
+
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ ) {
+ return -1;
+ }
+
+ return *gfx_get_pixel_address(x, y);
+}
+
+#else
+
+/*
+ * draw a single pixel
+ * changes buffer addressing (surface) according to orientation
+ */
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color)
+{
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2
+ ) {
+ return;
+ }
+
+ *gfx_get_pixel_address(x, y) = color;
+
+ return;
+}
+
+/*
+ * get a single pixel
+ */
+int32_t gfx_get_pixel(int16_t x, int16_t y)
+{
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2
+ ) {
+ return -1;
+ }
+
+ return *gfx_get_pixel_address(x, y);
+}
+#endif
+
+typedef struct {
+ int16_t ud_dir;
+ int16_t x0, x1;
+ int16_t y; /* actually y-ud_dir.. */
+} fill_segment_t;
+typedef struct {
+ size_t size;
+ fill_segment_t *data;
+ size_t count;
+ fill_segment_queue_statistics_t stats;
+} fill_segment_queue_t;
+
+//#define SHOW_FILLING
+#ifdef SHOW_FILLING
+#include "lcd_ili9341.h"
+#include
+#include "clock.h"
+#endif
+
+
+static inline void gfx_flood_fill4_add_if_found(
+ fill_segment_queue_t *queue,
+ int16_t ud_dir,
+ int16_t xa0, int16_t xa1,
+ int16_t y,
+ uint16_t old_color
+) {
+ y += ud_dir;
+ while ((xa0 <= xa1)) {
+ if (gfx_get_pixel(xa0, y) == old_color) {
+ if (queue->count < queue->size) {
+ queue->data[queue->count++] =
+ (fill_segment_t) {
+ .ud_dir = ud_dir,
+ .x0 = xa0,
+ .x1 = xa1,
+ .y = y-ud_dir
+ };
+ } else {
+ queue->stats.overflows++;
+ }
+ return;
+ }
+ xa0++;
+ }
+}
+
+/* warning! this function might be very slow and fail:) */
+fill_segment_queue_statistics_t
+gfx_flood_fill4(
+ int16_t x, int16_t y,
+ uint16_t old_color, uint16_t new_color,
+ uint8_t fill_segment_buf[], size_t fill_segment_buf_size
+) {
+ if (old_color == new_color) {
+ return (fill_segment_queue_statistics_t){0};
+ }
+
+ if (gfx_get_pixel(x, y) != old_color) {
+ return (fill_segment_queue_statistics_t){0};
+ }
+
+ fill_segment_queue_t queue = {
+ .size = fill_segment_buf_size/sizeof(fill_segment_t),
+ .data = (fill_segment_t *)fill_segment_buf,
+ .count = 0,
+ .stats = (fill_segment_queue_statistics_t) {
+ .count_max = 0,
+ .count_total = 0,
+ .overflows = 0,
+ }
+ };
+
+
+ int16_t sx, sy;
+
+ int16_t ud_dir_init = 1;
+ int16_t ud_dir = 1;
+
+ int16_t x0, x1, x0l, x1l, x0ll, x1ll;
+
+ bool pixel_drawn = false;
+
+ sx = x;
+ sy = y;
+
+ /* process first line */
+ x--; /* x is always increased first! */
+ while (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+ pixel_drawn = true;
+ }
+ x1l = x1ll = x-1;
+ x = sx;
+ while (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+ pixel_drawn = true;
+ }
+ x0l = x0ll = x+1;
+
+#ifdef SHOW_FILLING
+ ltdc_set_fbuffer_address(LTDC_LAYER_2, (uint32_t)__gfx_state.surface);
+#endif
+
+ while (pixel_drawn) {
+ pixel_drawn = false;
+
+#ifdef SHOW_FILLING
+ if (!LTDC_SRCR_IS_RELOADING()) {
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ }
+#endif
+ y += ud_dir;
+
+ /* find x start point (must be between x0 and x1 of the last iteration) */
+ sx = x0l;
+ while ((sx < x1l) && (gfx_get_pixel(sx, y) != old_color)) {
+ sx++;
+ }
+
+ bool sx_was_oc = gfx_get_pixel(sx, y) == old_color;
+
+ /** middle to right */
+ x = sx-1;
+ /* fill additional adjacent old-colored pixels */
+ while (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ pixel_drawn = true;
+ }
+ x1 = x-1;
+ /* check if x1 is bigger compared to the last line */
+ if (x1 > x1l+1) {
+ if (queue.count < queue.size) {
+ queue.data[queue.count++] =
+ (fill_segment_t) {
+ .ud_dir = -ud_dir,
+ .x0 = x1l,
+ .x1 = x1,
+ .y = y
+ };
+ } else {
+ queue.stats.overflows++;
+ }
+ } else {
+ /* fill all lastline-adjacent old-colored pixels */
+ bool adjacent_pixel_drawn = false;
+ int16_t xa0=0, xa1;
+ while ((x < x1l) || adjacent_pixel_drawn) {
+ if (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ if (!adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = true;
+ xa0 = x;
+ }
+ } else
+ if (adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = false;
+ xa1 = x-1;
+
+ gfx_flood_fill4_add_if_found(&queue, ud_dir, xa0, xa1, y, old_color);
+ if (xa1 > x1l+1) {
+ gfx_flood_fill4_add_if_found(&queue, -ud_dir, x1l+1, xa1, y, old_color);
+ }
+ }
+ }
+ }
+ x1l = x1;
+
+
+ /** middle-1 to left */
+ x = sx;
+ if ((sx > x0l) || sx_was_oc) {
+ /* fill additional adjacent old-colored pixels */
+ while (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ pixel_drawn = true;
+ }
+ x0 = x+1;
+ } else {
+ x0 = sx;
+ x--;
+ }
+ /* check if x0 is smaller compared to the last line */
+ if (x0 < x0l-1) {
+ if (queue.count < queue.size) {
+ queue.data[queue.count++] =
+ (fill_segment_t) {
+ .ud_dir = -ud_dir,
+ .x0 = x0,
+ .x1 = x0l,
+ .y = y
+ };
+ } else {
+ queue.stats.overflows++;
+ }
+ } else {
+ /* fill all lastline-adjacent old-colored pixels */
+ bool adjacent_pixel_drawn = false;
+ int16_t xa0, xa1 = 0;
+ while ((x > x0l) || adjacent_pixel_drawn) {
+ if (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ if (!adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = true;
+ xa1 = x;
+ }
+ } else
+ if (adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = false;
+ xa0 = x+1;
+
+ gfx_flood_fill4_add_if_found(&queue, ud_dir, xa0, xa1, y, old_color);
+ if (xa0 < x0l-1) {
+ gfx_flood_fill4_add_if_found(&queue, -ud_dir, xa0, x0l-1, y, old_color);
+ }
+ }
+ }
+ }
+ x0l = x0;
+
+ /** no pixel draw, check if we're already filling upwards */
+ if (!pixel_drawn) {
+ if (ud_dir == ud_dir_init) {
+ pixel_drawn = true;
+ ud_dir = -1;
+ y = sy;
+ x0l = x0ll;
+ x1l = x1ll;
+ } else {
+ ud_dir_init = 2; /* filling saved segments */
+
+ queue.stats.count_total++;
+ if (queue.stats.count_max < queue.count) {
+ queue.stats.count_max = queue.count;
+ }
+
+ if (queue.count) {
+ queue.count--;
+ ud_dir = queue.data[queue.count].ud_dir;
+ x0l = queue.data[queue.count].x0;
+ x1l = queue.data[queue.count].x1;
+ /* sx = (x0l+x1l)/2; */
+ y = queue.data[queue.count].y;
+ pixel_drawn = true;
+
+#ifdef SHOW_FILLING
+ assert(x0l <= x1l);
+#endif
+ }
+ }
+ }
+ }
+
+#ifdef SHOW_FILLING
+ msleep_loop(5000);
+#endif
+
+ return queue.stats;
+}
+
+
+/* Bresenham's algorithm - thx wikpedia */
+void gfx_draw_line(int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ uint16_t fg) {
+ int16_t steep = abs(y1 - y0) > abs(x1 - x0);
+ if (steep) {
+ swap_i16(x0, y0);
+ swap_i16(x1, y1);
+ }
+
+ if (x0 > x1) {
+ swap_i16(x0, x1);
+ swap_i16(y0, y1);
+ }
+
+ int16_t dx, dy;
+ dx = x1 - x0;
+ dy = abs(y1 - y0);
+
+ int16_t err = dx / 2;
+ int16_t ystep;
+
+ if (y0 < y1) {
+ ystep = 1;
+ } else {
+ ystep = -1;
+ }
+
+ for (; x0 <= x1; x0++) {
+ if (steep) {
+ gfx_draw_pixel(y0, x0, fg);
+ } else {
+ gfx_draw_pixel(x0, y0, fg);
+ }
+ err -= dy;
+ if (err < 0) {
+ y0 += ystep;
+ err += dx;
+ }
+ }
+}
+void gfx_draw_hline(int16_t x, int16_t y, int16_t length, uint16_t color)
+{
+ if (length < 0) {
+ length = -length;
+ x -= length;
+ }
+ while (length--) {
+ gfx_draw_pixel(x++, y, color);
+ }
+}
+void gfx_draw_vline(int16_t x, int16_t y, int16_t length, uint16_t color)
+{
+ if (length < 0) {
+ length = -length;
+ y -= length;
+ }
+ while (length--) {
+ gfx_draw_pixel(x, y++, color);
+ }
+}
+
+void gfx_draw_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
+{
+ int16_t x_s, y_e;
+ if (w < 0) {
+ w = -w;
+ x -= w;
+ }
+ if (h < 0) {
+ h = -h;
+ x -= h;
+ }
+ x_s = x;
+ y_e = y+h-1;
+ while (w-- != 0) {
+ gfx_draw_pixel(x, y , color);
+ gfx_draw_pixel(x, y_e, color);
+ x++;
+ }
+ x--;
+ while (h-- != 0) {
+ gfx_draw_pixel(x_s, y, color);
+ gfx_draw_pixel(x , y, color);
+ y++;
+ }
+}
+
+void gfx_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t fg) {
+
+ int16_t i;
+ for (i = x; i < x+w; i++) {
+ gfx_draw_vline(i, y, h, fg);
+ }
+}
+
+
+
+
+/* Draw RGB565 data */
+void gfx_draw_raw_rbg565_buffer(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img
+) {
+ int16_t x_cp, w_cp;
+ while (h--) {
+ x_cp = x;
+ w_cp = w;
+ while (w_cp--) {
+ gfx_draw_pixel(x_cp, y, *img++);
+ x_cp++;
+ }
+ y++;
+ }
+}
+
+/* Draw RGB565 data, do not draw ignored_color */
+void gfx_draw_raw_rbg565_buffer_ignore_color(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img,
+ uint16_t ignored_color
+) {
+ int16_t x_cp, w_cp;
+ while (h--) {
+ x_cp = x;
+ w_cp = w;
+ while (w_cp--) {
+ if (*img != ignored_color) {
+ gfx_draw_pixel(x_cp, y, *img);
+ }
+ img++;
+
+ x_cp++;
+ }
+ y++;
+ }
+}
+
+/* Draw a circle outline */
+void gfx_draw_circle(int16_t x0, int16_t y0, int16_t r, uint16_t fg)
+{
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ gfx_draw_pixel(x0 , y0+r, fg);
+ gfx_draw_pixel(x0 , y0-r, fg);
+ gfx_draw_pixel(x0+r, y0 , fg);
+ gfx_draw_pixel(x0-r, y0 , fg);
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+
+ gfx_draw_pixel(x0 + x, y0 + y, fg);
+ gfx_draw_pixel(x0 - x, y0 + y, fg);
+ gfx_draw_pixel(x0 + x, y0 - y, fg);
+ gfx_draw_pixel(x0 - x, y0 - y, fg);
+ gfx_draw_pixel(x0 + y, y0 + x, fg);
+ gfx_draw_pixel(x0 - y, y0 + x, fg);
+ gfx_draw_pixel(x0 + y, y0 - x, fg);
+ gfx_draw_pixel(x0 - y, y0 - x, fg);
+ }
+}
+
+void gfx_draw_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername,
+ uint16_t fg
+) {
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+ if (cornername & 0x4) {
+ gfx_draw_pixel(x0 + x, y0 + y, fg);
+ gfx_draw_pixel(x0 + y, y0 + x, fg);
+ }
+ if (cornername & 0x2) {
+ gfx_draw_pixel(x0 + x, y0 - y, fg);
+ gfx_draw_pixel(x0 + y, y0 - x, fg);
+ }
+ if (cornername & 0x8) {
+ gfx_draw_pixel(x0 - y, y0 + x, fg);
+ gfx_draw_pixel(x0 - x, y0 + y, fg);
+ }
+ if (cornername & 0x1) {
+ gfx_draw_pixel(x0 - y, y0 - x, fg);
+ gfx_draw_pixel(x0 - x, y0 - y, fg);
+ }
+ }
+}
+
+void gfx_fill_circle(
+ int16_t x0, int16_t y0,
+ int16_t r,
+ uint16_t fg
+) {
+ gfx_draw_vline(x0, y0-r, 2*r+1, fg);
+ gfx_fill_circle_helper(x0, y0, r, 3, 0, fg);
+}
+
+/* Used to do circles and roundrects */
+void gfx_fill_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername, int16_t delta,
+ uint16_t fg
+) {
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+
+ if (cornername & 0x1) {
+ gfx_draw_vline(x0+x, y0-y, 2*y+1+delta, fg);
+ gfx_draw_vline(x0+y, y0-x, 2*x+1+delta, fg);
+ }
+ if (cornername & 0x2) {
+ gfx_draw_vline(x0-x, y0-y, 2*y+1+delta, fg);
+ gfx_draw_vline(x0-y, y0-x, 2*x+1+delta, fg);
+ }
+ }
+}
+
+
+/* Draw a rounded rectangle */
+void gfx_draw_round_rect(
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ int16_t r,
+ uint16_t fg
+) {
+ /* smarter version */
+ gfx_draw_hline(x+r , y , w-2*r, fg); /* Top */
+ gfx_draw_hline(x+r , y+h-1, w-2*r, fg); /* Bottom */
+ gfx_draw_vline(x , y+r , h-2*r, fg); /* Left */
+ gfx_draw_vline(x+w-1, y+r , h-2*r, fg); /* Right */
+ /* draw four corners */
+ gfx_draw_circle_helper(x+r , y+r , r, 1, fg);
+ gfx_draw_circle_helper(x+w-r-1, y+r , r, 2, fg);
+ gfx_draw_circle_helper(x+w-r-1, y+h-r-1, r, 4, fg);
+ gfx_draw_circle_helper(x+r , y+h-r-1, r, 8, fg);
+}
+
+/* Fill a rounded rectangle */
+void gfx_fill_round_rect(
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ int16_t r,
+ uint16_t fg
+) {
+ /* smarter version */
+ gfx_fill_rect(x+r, y, w-2*r, h, fg);
+
+ /* draw four corners */
+ gfx_fill_circle_helper(x+w-r-1, y+r, r, 1, h-2*r-1, fg);
+ gfx_fill_circle_helper(x+r , y+r, r, 2, h-2*r-1, fg);
+}
+
+
+/* Draw a triangle */
+void gfx_draw_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t fg
+) {
+ gfx_draw_line(x0, y0, x1, y1, fg);
+ gfx_draw_line(x1, y1, x2, y2, fg);
+ gfx_draw_line(x2, y2, x0, y0, fg);
+}
+
+/* Fill a triangle */
+void gfx_fill_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t fg
+) {
+ int16_t a, b, y, last;
+
+ /* Sort coordinates by Y order (y2 >= y1 >= y0) */
+ if (y0 > y1) {
+ swap_i16(y0, y1); swap_i16(x0, x1);
+ }
+ if (y1 > y2) {
+ swap_i16(y2, y1); swap_i16(x2, x1);
+ }
+ if (y0 > y1) {
+ swap_i16(y0, y1); swap_i16(x0, x1);
+ }
+
+ /* Handle awkward all-on-same-line case as its own thing */
+ if (y0 == y2) {
+ a = b = x0;
+ if (x1 < a) {
+ a = x1;
+ } else
+ if (x1 > b) {
+ b = x1;
+ }
+ if (x2 < a) {
+ a = x2;
+ } else
+ if (x2 > b) {
+ b = x2;
+ }
+ gfx_draw_hline(a, y0, b-a+1, fg);
+ return;
+ }
+
+ int16_t
+ dx01 = x1 - x0,
+ dy01 = y1 - y0,
+ dx02 = x2 - x0,
+ dy02 = y2 - y0,
+ dx12 = x2 - x1,
+ dy12 = y2 - y1,
+ sa = 0,
+ sb = 0;
+
+ /* For upper part of triangle, find scanline crossings for segments
+ * 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
+ * is included here (and second loop will be skipped, avoiding a /0
+ * error there), otherwise scanline y1 is skipped here and handled
+ * in the second loop...which also avoids a /0 error here if y0=y1
+ * (flat-topped triangle).
+ */
+ if (y1 == y2) {
+ last = y1; /* Include y1 scanline */
+ } else {
+ last = y1-1; /* Skip it */
+ }
+
+ for (y = y0; y <= last; y++) {
+ a = x0 + sa / dy01;
+ b = x0 + sb / dy02;
+ sa += dx01;
+ sb += dx02;
+ /* longhand:
+ a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
+ b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+ */
+ if (a > b) {
+ swap_i16(a, b);
+ }
+ gfx_draw_hline(a, y, b-a+1, fg);
+ }
+
+ /* For lower part of triangle, find scanline crossings for segments
+ * 0-2 and 1-2. This loop is skipped if y1=y2.
+ */
+ sa = dx12 * (y - y1);
+ sb = dx02 * (y - y0);
+ for (; y <= y2; y++) {
+ a = x1 + sa / dy12;
+ b = x0 + sb / dy02;
+ sa += dx12;
+ sb += dx02;
+ /* longhand:
+ a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+ b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+ */
+ if (a > b) {
+ swap_i16(a, b);
+ }
+ gfx_draw_hline(a, y, b-a+1, fg);
+ }
+}
+
+
+
+
+/**
+ * Text functions
+ */
+
+/* Write utf8 text */
+void gfx_write(const uint32_t c)
+{
+ if (!__gfx_state.font) {
+ return;
+ }
+ if (c == '\n') {
+ __gfx_state.cursor_y += gfx_get_line_height();
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ } else if (c == '\r') {
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ } else {
+ if (__gfx_state.wrap
+ && (
+ __gfx_state.cursor_x
+ > (
+ __gfx_state.visible_area.x2
+ - gfx_get_char_width()
+ ))) {
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ __gfx_state.cursor_y += gfx_get_line_height();
+ }
+ gfx_draw_char(
+ __gfx_state.cursor_x, __gfx_state.cursor_y,
+ c,
+ __gfx_state.textcolor, __gfx_state.fontscale
+ );
+ __gfx_state.cursor_x += gfx_get_char_width();
+ }
+}
+
+void gfx_puts(const char *s) {
+ while (*s) {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ }
+}
+void gfx_puts4(const char *s, uint32_t max_len) {
+ while (*s && max_len--) {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ }
+}
+void gfx_puts2(
+ int16_t x, int16_t y,
+ const char *s,
+ const font_t *font,
+ uint16_t col
+) {
+ gfx_set_cursor(x, y);
+ gfx_set_font(font);
+ gfx_set_text_color(col);
+ gfx_puts(s);
+}
+/* this is not utf8 right now.. */
+void gfx_puts3(
+ int16_t x, int16_t y,
+ const char *s,
+ const gfx_alignment_t alignment
+) {
+ const char *s_end;
+ const char *next_nl; //, *last_nl;
+
+ switch (alignment) {
+ case GFX_ALIGNMENT_TOP:
+ case GFX_ALIGNMENT_BOTTOM:
+ case GFX_ALIGNMENT_LEFT:
+ gfx_set_cursor(x, y);
+ gfx_puts(s);
+ return;
+
+ case GFX_ALIGNMENT_RIGHT:
+ s_end = utf8_find_character_in_string(0, s, s+1024);
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ if (next_nl == s_end) {
+ gfx_set_cursor(
+ x
+ - utf8_find_pointer_diff(s, s_end)
+ * gfx_get_char_width(),
+ y
+ );
+ gfx_puts(s);
+ } else {
+ uint32_t line_count = 0;
+ while (s < s_end) {
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ gfx_set_cursor(
+ x
+ - utf8_find_pointer_diff(s, next_nl)
+ * gfx_get_char_width(),
+ y
+ + line_count
+ * gfx_get_line_height()
+ );
+ do {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ } while (s != next_nl);
+ s++; line_count++;
+ }
+ }
+ break;
+
+ case GFX_ALIGNMENT_CENTER:
+ /* TODO correct rounding on /2 */
+ s_end = utf8_find_character_in_string(0, s, s+1024);
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ if (0) { //next_nl == s_end) {
+ gfx_set_cursor(
+ x-(utf8_find_pointer_diff(s, s_end)
+ * gfx_get_char_width())/2,
+ y
+ );
+ gfx_puts(s);
+ } else {
+// /* find longest line */
+// uint32_t line_length, longest_line;
+// longest_line = utf8_find_pointer_diff(s, next_nl);
+// last_nl = next_nl+1;
+// while (last_nl < s_end) {
+// next_nl = utf8_find_character_in_string('\n', last_nl, s_end);
+// line_length = utf8_find_pointer_diff(last_nl, next_nl);
+// if (longest_line < line_length) {
+// longest_line = line_length;
+// }
+// last_nl = next_nl+1;
+// }
+
+ /* print lines */
+ uint32_t line_count = 0;
+ while (s < s_end) {
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ gfx_set_cursor(
+ x
+ -(utf8_find_pointer_diff(s, next_nl)
+ * gfx_get_char_width())/2,
+ //- (longest_line*gfx_get_char_width())
+// - ((longest_line
+// - utf8_find_pointer_diff(s, next_nl)
+// ) * gfx_get_char_width())/2,
+ y
+ + line_count*gfx_get_line_height());
+ do {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ } while (s != next_nl);
+ s++; line_count++;
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * This function gets the index of the char for the font data
+ * converts it's bit array address to a 32bit and mask
+ * and draws a point of size to it's location
+ *
+ * @param x x position
+ * @param y y position
+ * @param c utf8 char id
+ * @param col RGB565 color
+ * @param size Size in multiples of 1
+ */
+void gfx_draw_char(
+ int16_t x, int16_t y,
+ uint32_t c,
+ uint16_t col,
+ uint8_t size
+) {
+ uint32_t i, j, bm;
+ const char_t *cp;
+ const uint32_t *cp_data_p;
+
+ if (!__gfx_state.font) {
+ return;
+ }
+ /* get the data-index for this char code from the lookup table */
+ cp = font_get_char_index(c, __gfx_state.font);
+ if (cp == NULL) {
+ return;
+ }
+
+ cp_data_p = cp->data;
+ bm = 1; /* bit_mask */
+ for (j = cp->bbox.y1; j < cp->bbox.y2; j++) {
+ for (i = cp->bbox.x1; i < cp->bbox.x2; i++) {
+ if (*cp_data_p & bm) {
+ /* default size */
+ if (size == 1) {
+ gfx_draw_pixel(x+i, y+j, col);
+ } else {
+ /* big size */
+ gfx_fill_rect(x+i*size, y+j*size, size, size, col);
+ }
+ }
+ /* overflow */
+ if (bm == 0x80000000) {
+ bm = 1;
+ cp_data_p++;
+ } else {
+ bm <<= 1;
+ }
+ }
+ }
+}
+
+void gfx_set_cursor(int16_t x, int16_t y)
+{
+ __gfx_state.cursor_x_orig = x;
+ __gfx_state.cursor_x = x;
+ __gfx_state.cursor_y = y;
+}
+
+void gfx_set_font_scale(uint8_t s)
+{
+ __gfx_state.fontscale = (s > 0) ? s : 1;
+}
+uint8_t gfx_get_font_scale()
+{
+ return __gfx_state.fontscale;
+}
+
+void gfx_set_text_color(uint16_t col)
+{
+ __gfx_state.textcolor = col;
+}
+void gfx_set_font(const font_t *font)
+{
+ __gfx_state.font = font;
+}
+
+void gfx_set_text_wrap(bool w)
+{
+ __gfx_state.wrap = w;
+}
+
+uint16_t
+gfx_get_char_width()
+{
+ if (!__gfx_state.font) {
+ return 0;
+ } else {
+ return __gfx_state.font->charwidth*__gfx_state.fontscale;
+ }
+}
+uint16_t
+gfx_get_line_height()
+{
+ if (!__gfx_state.font) {
+ return 0;
+ }
+ return __gfx_state.font->lineheight*__gfx_state.fontscale;
+}
+uint16_t
+gfx_get_string_width(const char *s)
+{
+ uint16_t cnt, cnt_max;
+ cnt = cnt_max = 0;
+ while (1) {
+ if ((*s == 0) || (*s == '\n') || (*s == '\r')) {
+ if (cnt_max < cnt) {
+ cnt_max = cnt;
+ }
+
+ if (*s == 0) {
+ break;
+ }
+ cnt = 0;
+ } else {
+ cnt++;
+ }
+ s++;
+ }
+ return cnt_max * gfx_get_char_width();
+}
+uint16_t
+gfx_get_string_height(const char *s)
+{
+ uint16_t cnt;
+ cnt = 1;
+ while (*s) {
+ if (*s == '\n') {
+ cnt++;
+ }
+ s++;
+ }
+ return cnt * gfx_get_line_height();
+}
+uint8_t
+gfx_get_text_size()
+{
+ return __gfx_state.fontscale;
+}
+uint16_t
+gfx_get_text_color()
+{
+ return __gfx_state.textcolor;
+}
+const font_t *
+gfx_get_font()
+{
+ return __gfx_state.font;
+}
+uint8_t
+gfx_get_text_wrap()
+{
+ return __gfx_state.wrap;
+}
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.h
new file mode 100644
index 00000000..6ca4c36b
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/gfx_locm3.h
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef _GFX_LOCM3_H_
+#define _GFX_LOCM3_H_
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include "fonts/utf8.h"
+#include "fonts/fonts.h"
+
+#define swap_i16(a, b) { int16_t t = a; a = b; b = t; }
+
+/*
+ * Python
+ * def get_rgb565(x) :
+ * return ((x&0xf80000)>>8) | ((x&0xfc00)>>5) | ((x&0xf8)>>3)
+ *
+ * print print "0x%X"%get_rgb565(some_rgb_value)
+ */
+#define GFX_COLOR_WHITE 0xFFFF
+#define GFX_COLOR_BLACK 0x0000
+#define GFX_COLOR_DARKGREY 0x4228
+#define GFX_COLOR_GREY 0xF7DE
+#define GFX_COLOR_GREY2 0x7BEF /*1111 0111 1101 1110*/
+#define GFX_COLOR_BLUE 0x001F
+#define GFX_COLOR_BLUE2 0x051F
+#define GFX_COLOR_RED 0xF800
+#define GFX_COLOR_MAGENTA 0xF81F
+#define GFX_COLOR_GREEN 0x07E0
+#define GFX_COLOR_GREEN2 0xB723
+#define GFX_COLOR_CYAN 0x7FFF
+#define GFX_COLOR_YELLOW 0xFFE0
+#define GFX_COLOR_ORANGE 0xFBE4
+#define GFX_COLOR_BROWN 0xBBCA
+
+typedef enum {
+ GFX_ROTATION_0_DEGREES,
+ GFX_ROTATION_90_DEGREES,
+ GFX_ROTATION_180_DEGREES,
+ GFX_ROTATION_270_DEGREES
+} gfx_rotation_t;
+
+typedef enum {
+ GFX_ALIGNMENT_TOP = 1<<0,
+ GFX_ALIGNMENT_BOTTOM = 1<<1,
+ GFX_ALIGNMENT_LEFT = 1<<2,
+ GFX_ALIGNMENT_RIGHT = 1<<3,
+ GFX_ALIGNMENT_CENTER = 1<<4,
+} gfx_alignment_t;
+
+typedef struct {
+ int16_t x1, y1, x2, y2;
+} visible_area_t;
+
+typedef struct {
+ uint32_t is_offscreen_rendering;
+ const int16_t width_orig, height_orig;
+ const uint32_t pixel_count;
+ int16_t width, height;
+ visible_area_t visible_area;
+ int16_t cursor_x, cursor_y, cursor_x_orig;
+ uint16_t textcolor;
+ uint8_t fontscale;
+ gfx_rotation_t rotation;
+ bool wrap;
+ const font_t *font;
+ uint16_t *surface; /* current pixel buffer */
+} gfx_state_t;
+
+extern gfx_state_t __gfx_state;
+
+
+typedef struct {
+ size_t count_max;
+ size_t count_total;
+ size_t overflows;
+} fill_segment_queue_statistics_t;
+
+
+void gfx_init(uint16_t *surface, int32_t w, int32_t h);
+/**
+ * set pixel buffer address to render graphics on..
+ * @param surface pixel buffer address
+ */
+void gfx_set_surface(uint16_t *surface);
+uint16_t *
+gfx_get_surface(void);
+
+void gfx_offscreen_rendering_begin(
+ uint16_t *surface,
+ int32_t width, int32_t height
+ );
+void gfx_offscreen_rendering_end(void);
+
+void
+gfx_set_clipping_area_max(void);
+void
+gfx_set_clipping_area(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
+visible_area_t
+gfx_get_surface_visible_area(void);
+
+
+void gfx_fill_screen(uint16_t color);
+
+void gfx_set_rotation(gfx_rotation_t rotation);
+uint16_t gfx_height(void);
+uint16_t gfx_width(void);
+gfx_rotation_t gfx_get_rotation(void);
+
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color);
+int32_t gfx_get_pixel(int16_t x, int16_t y);
+fill_segment_queue_statistics_t
+gfx_flood_fill4(
+ int16_t x, int16_t y,
+ uint16_t old_color, uint16_t new_color,
+ uint8_t fill_segment_buf[], size_t fill_segment_buf_size
+ );
+
+void gfx_draw_line(
+ int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+ uint16_t color
+ );
+void gfx_draw_hline(int16_t x, int16_t y, int16_t length, uint16_t color);
+void gfx_draw_vline(int16_t x, int16_t y, int16_t length, uint16_t color);
+void gfx_draw_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+void gfx_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+void gfx_draw_raw_rbg565_buffer(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img
+ );
+void gfx_draw_raw_rbg565_buffer_ignore_color(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img,
+ uint16_t ignored_color
+ );
+
+void gfx_draw_circle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
+void gfx_draw_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername,
+ uint16_t color
+ );
+void gfx_fill_circle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
+void gfx_fill_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername, int16_t delta,
+ uint16_t color
+ );
+
+void gfx_draw_round_rect(
+ int16_t x0, int16_t y0, int16_t w, int16_t h,
+ int16_t radius,
+ uint16_t color
+ );
+void gfx_fill_round_rect(
+ int16_t x0, int16_t y0, int16_t w, int16_t h,
+ int16_t radius,
+ uint16_t color
+ );
+
+void gfx_draw_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t color
+ );
+void gfx_fill_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t color
+ );
+
+
+void gfx_draw_char(
+ int16_t x, int16_t y,
+ uint32_t c,
+ uint16_t color,
+ uint8_t size
+ );
+void gfx_set_cursor(int16_t x, int16_t y);
+void gfx_set_text_color(uint16_t col);
+void gfx_set_font_scale(uint8_t s);
+uint8_t gfx_get_font_scale(void);
+void gfx_set_text_wrap(bool w);
+void gfx_set_font(const font_t *font);
+void gfx_puts(const char *);
+void gfx_puts4(const char *s, uint32_t max_len);
+void gfx_puts2(
+ int16_t x, int16_t y,
+ const char *s,
+ const font_t *font,
+ uint16_t col
+ );
+void gfx_puts3(
+ int16_t x, int16_t y,
+ const char *s,
+ const gfx_alignment_t alignment
+ );
+void gfx_write(const uint32_t);
+
+
+uint16_t
+gfx_get_char_width(void);
+uint16_t
+gfx_get_line_height(void);
+uint16_t
+gfx_get_string_width(const char *);
+uint16_t
+gfx_get_string_height(const char *s);
+
+uint8_t
+gfx_get_text_size(void);
+uint16_t
+gfx_get_text_color(void);
+const font_t *
+gfx_get_font(void);
+uint8_t
+gfx_get_text_wrap(void);
+
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.c
new file mode 100644
index 00000000..98236efd
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.c
@@ -0,0 +1,334 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "i2c.h"
+
+static uint32_t dummy __attribute__((unused));
+
+volatile uint32_t stummy;
+
+void i2c_setup_master(uint32_t i2c, uint32_t clock_speed)
+{
+ /* Disable the I2C before changing any configuration. */
+ i2c_reset(i2c); /* rcc_periph_reset_pulse(i2c_RST); */
+ i2c_peripheral_disable(i2c);
+
+ /* analog filter enabled, digital filter 4*Tpclk1 */
+#define DIGITAL_FILTER 2
+ I2C_FILTR(i2c) = DIGITAL_FILTER;
+
+ /* TODO fix timing!!!! */
+ /*i2c_set_clock_frequency(i2c, I2C_CR2_FREQ_42MHZ); // APB @42MHz?*/
+ i2c_set_clock_frequency(i2c, CLOCK_SETUP.apb1_frequency/1000000);
+ if (clock_speed <= 100000) { /* <=100000 according to ref. manual,
+ <88000 according to errata sheet */
+ i2c_set_standard_mode(i2c);
+ i2c_set_ccr(i2c, CLOCK_SETUP.apb1_frequency/(clock_speed*2));
+ stummy = CLOCK_SETUP.apb1_frequency/(clock_speed*2);
+ i2c_set_dutycycle(i2c, I2C_CCR_DUTY_DIV2);
+ i2c_set_trise(i2c, (CLOCK_SETUP.apb1_frequency/1000000) + 1 + DIGITAL_FILTER);
+ } else {
+ i2c_set_fast_mode(i2c);
+ i2c_set_ccr(i2c, CLOCK_SETUP.apb1_frequency/(clock_speed*25));
+ stummy = CLOCK_SETUP.apb1_frequency/(clock_speed*25);
+ i2c_set_dutycycle(i2c, I2C_CCR_DUTY_16_DIV_9);
+ i2c_set_trise(i2c, (((CLOCK_SETUP.apb1_frequency/1000000) * 300) / 1000) + 1 + DIGITAL_FILTER);
+ }
+ /*i2c_set_own_7bit_slave_address(i2c, 0); */
+
+
+ i2c_peripheral_enable(i2c);
+}
+
+
+
+/* Clearing ADDR condition sequence. */
+#define i2c_clear_address(i2c) { dummy = I2C_SR1(i2c); dummy = I2C_SR2(i2c); }
+
+static
+void
+i2c_wait_until_probably_safe(uint32_t i2c);
+static
+void
+i2c_send_start_safe(uint32_t i2c);
+static
+void
+i2c_send_stop_safe(uint32_t i2c);
+static
+void
+i2c_recovery(uint32_t i2c);
+
+
+static
+i2c_flag_wait_error
+i2c_wait_for_sr1_flag_set(uint32_t i2c, uint32_t flag);
+static
+i2c_flag_wait_error
+i2c_wait_while_busy(uint32_t i2c);
+
+
+void
+i2c_wait_until_probably_safe(uint32_t i2c) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (
+ (I2C_CR1(i2c) & (I2C_CR1_STOP | I2C_CR1_START | I2C_CR1_PEC))
+ && timeout
+ ) {
+ timeout--;
+ }
+ if (!timeout) {
+ stummy = I2C_CR1(i2c);
+ i2c_recovery(i2c);
+ }
+}
+void
+i2c_send_start_safe(uint32_t i2c) {
+ i2c_wait_until_probably_safe(i2c);
+ i2c_send_start(i2c);
+}
+void
+i2c_send_stop_safe(uint32_t i2c) {
+ /* sending stop is bad most of the time!! */
+ i2c_wait_until_probably_safe(i2c);
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+}
+void
+i2c_recovery(uint32_t i2c) {
+ uint32_t timeout;
+ /* recover from glitch or so */
+ I2C_CR1(i2c) |= I2C_CR1_SWRST;
+ /* wait a long time.. */
+ timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (timeout) {
+ timeout--;
+ }
+ I2C_CR1(i2c) &= ~I2C_CR1_SWRST;
+}
+
+
+i2c_flag_wait_error
+i2c_wait_for_sr1_flag_set(uint32_t i2c, uint32_t flag) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (!(I2C_SR1(i2c) & (flag | I2C_SR1_AF)) && timeout) {
+ timeout--;
+ }
+ stummy = I2C_SR1(i2c);
+ if ((I2C_SR1(i2c) & I2C_SR1_AF) || !timeout) {
+ stummy = I2C_SR2(i2c);
+
+
+ /* TODO <<< check for AF error */
+ /* TODO make a recovery function.. */
+ /*i2c3_setup();*/
+ /*for (timeout=10; timeout; timeout--) {*/
+ if (I2C_SR1(i2c) & I2C_SR1_AF) {
+ i2c_send_start_safe(i2c);
+ while (!(I2C_SR1(i2c) & I2C_SR1_SB));
+ } else {
+ i2c_recovery(i2c);
+ }
+ /*}*/
+
+ /*sending stop is only allowed after a full byte..*/
+ /*i2c_send_stop_safe(i2c);*/
+
+ /*stummy = I2C_SR1(i2c);*/
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+i2c_flag_wait_error
+i2c_wait_while_busy(uint32_t i2c) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (i2c_is_busy(i2c) && timeout) {
+ timeout--;
+ }
+ if ((I2C_SR1(i2c) & I2C_SR1_AF) || !timeout) {
+ i2c_recovery(i2c);
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+
+volatile uint32_t i2c_failed_horribly;
+
+void
+i2c_trx_retry(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+) {
+ uint32_t retries = I2C_MAX_RETRIES;
+ while (
+ i2c_trx(i2c, address, write_data, write_len, read_data, read_len)
+ && retries) {
+ retries--;
+ }
+ if (!retries) {
+ i2c_failed_horribly = 1;
+ }
+}
+
+i2c_flag_wait_error
+i2c_trx(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+) {
+ /* TODO make it work :) */
+
+ if (i2c_wait_while_busy(i2c)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* enable error IT */
+ /*I2C_CR2(i2c) |= I2C_CR2_ITERREN;*/
+
+ /* Sending the data_p. */
+ if (write_len) {
+ i2c_wait_until_probably_safe(i2c);
+ /* send start */
+ I2C_CR1(i2c) |= I2C_CR1_START; /*i2c_send_start(i2c);*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_SB)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* send address */
+ i2c_send_7bit_address(i2c, address, I2C_WRITE);
+ /* Waiting for address is transferred. */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_ADDR)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* clear ADDR flag by reading SR2 */
+ dummy = I2C_SR2(i2c);
+ /*i2c_clear_address(i2c);*/
+
+ /*i2c_send_data(i2c, *write_data++); write_len--;*/ /*write first byte*/
+ while (write_len) {
+ /*if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) return I2C_FLAG_WAIT_UNKNOWN_ERROR;*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_TxE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ i2c_send_data(i2c, *write_data++); write_len--;
+ if ((I2C_SR1(i2c) & I2C_SR1_BTF) && write_len) {
+ i2c_send_data(i2c, *write_data++); write_len--;
+ }
+ }
+
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_TxE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ }
+ if (!read_len) {
+ i2c_send_stop_safe(i2c);
+ } else {
+ /* Receiving data_p */
+ i2c_wait_until_probably_safe(i2c);
+ /*I2C_CR1(i2c) |= I2C_CR1_ACK;*/ /*enable ack*/
+ i2c_send_start(i2c); /* send repeated start */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_SB)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ i2c_send_7bit_address(i2c, address, I2C_READ);
+ /* Waiting for address is transferred. */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_ADDR)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* Start receiving */
+ switch (read_len) {
+ case 1:
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK; /* disable ack */
+ /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
+ software sequence must complete before the current byte end of transfer */
+ __disable_irq();
+ i2c_clear_address(i2c);
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+ __enable_irq();
+ break;
+ case 2:
+ I2C_CR1(i2c) |= I2C_CR1_POS; /* this may cause trouble? has it to be set before start? */
+ /* EV6_1: The acknowledge disable should be done just after EV6,
+ that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and
+ ACK clearing */
+ __disable_irq();
+ i2c_clear_address(i2c);
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ __enable_irq();
+ /*
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ I2C_CR1(i2c) |= I2C_CR1_POS;
+ i2c_clear_address(i2c);
+ */
+ break;
+ default:
+ I2C_CR1(i2c) |= I2C_CR1_ACK;
+ i2c_clear_address(i2c);
+ break;
+ }
+ while (read_len) {
+ switch (read_len) {
+ case 1:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_RxNE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ *read_data++ = I2C_DR(i2c); read_len--;
+ break;
+ case 2:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ /* TODO i2c_send_stop_safe(i2c); */
+ __disable_irq();
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ __enable_irq();
+ *read_data++ = I2C_DR(i2c); read_len--;
+ break;
+ case 3: /*???!*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ /* goto case 2 to finish.. */
+ break;
+ default:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ *read_data++ = I2C_DR(i2c); read_len--;
+ /*
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_RxNE)) return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ if (I2C_SR1(i2c) & I2C_SR1_BTF) { // read another byte
+ *read_data++ = I2C_DR(i2c); read_len--;
+ }
+ */
+ break;
+ }
+ }
+ i2c_wait_until_probably_safe(i2c);
+ I2C_CR1(i2c) &= ~I2C_CR1_POS;
+ }
+
+ /*return i2c_wait_while_busy(i2c);*/ /* busy checking is done at the beginning of this function.. */
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.h
new file mode 100644
index 00000000..cdeef6f0
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/i2c.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ */
+
+
+#ifndef __I2C_H__
+#define __I2C_H__
+
+#include "clock.h"
+#include
+#include
+
+
+
+/**
+ * I2C extensions
+ */
+
+#define I2C_FILTR(i2c_base) MMIO32(i2c_base + 0x24)
+#define I2C_FILTER_ANOFF_DISABLE_ANALOG_FILTER (0b10000)
+
+
+void i2c_setup_master(uint32_t i2c, uint32_t clock_speed);
+
+#define i2c_is_busy(i2c) ((I2C_SR2(i2c)&I2C_SR2_BUSY) == I2C_SR2_BUSY)
+
+/* TODO FIX I2C CLOCK SETUP!!! */
+#define STMPE811_I2C_CLOCK_SPEED 10000
+#define I2C_FLAG_WAIT_TIMEOUT ((uint32_t)(168000000UL*100/STMPE811_I2C_CLOCK_SPEED))
+#define I2C_MAX_RETRIES 10000
+
+typedef enum {
+ I2C_FLAG_WAIT_NO_ERROR = 0,
+ I2C_FLAG_WAIT_UNKNOWN_ERROR
+} i2c_flag_wait_error;
+
+void
+i2c_trx_retry(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+);
+
+i2c_flag_wait_error
+i2c_trx(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+);
+
+
+#endif /*__I2C_H__ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.c
new file mode 100644
index 00000000..17bc5557
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.c
@@ -0,0 +1,753 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "lcd_ili9341.h"
+#include
+
+volatile int rx_pend;
+volatile uint16_t spi_rx_buf;
+
+void ili9341_spi5_isr()
+{
+ spi_rx_buf = SPI_DR(SPI5);
+ --rx_pend;
+}
+
+/* send spi data */
+static inline void ili9341_send_data(uint8_t data);
+
+/* send spi command */
+static inline void ili9341_send_command(uint8_t data);
+
+/* interrupt driven send command via ssp */
+void
+ili9341_send_command(uint8_t data)
+{
+ ILI9341_WRX_RESET();
+ ILI9341_SPI_SELECT();
+
+ rx_pend++;
+ spi_send(ILI9341_SPI, data);
+ while (rx_pend);
+
+ ILI9341_SPI_DESELECT();
+}
+
+/* interrupt driven send data via ssp */
+void
+ili9341_send_data(uint8_t data)
+{
+ ILI9341_WRX_SET();
+ ILI9341_SPI_SELECT();
+
+ rx_pend++;
+ spi_send(ILI9341_SPI, data);
+ while (rx_pend);
+
+ ILI9341_SPI_DESELECT();
+}
+
+
+
+ili9341_options_t ili9341_opts;
+
+/**
+ * Setup LCD screen to be driven by ltdc
+ *
+ * surface buffers have ILI9341_BUFFERS_PER_LAYER elements
+ * which point to memory areas where each have a size of
+ * ILI9341_SURFACE_SIZE
+ *
+ * @param layer1_surface_buffers
+ * @param layer2_surface_buffers
+ */
+void ili9341_init(
+ uint16_t *layer1_surface_buffers[],
+ uint16_t *layer2_surface_buffers[]
+) {
+ int i;
+
+ /* Initialize pins used */
+ ili9341_init_pins();
+ /* SPI chip select high */
+ ILI9341_SPI_DESELECT();
+ /* Initialize LCD for LTDC */
+ ili9341_init_lcd();
+ /* Initialize LTDC */
+ ili9341_init_ltdc();
+ /* Initialize LTDC layers */
+ ili9341_init_layers();
+
+ ili9341_opts.width = ILI9341_WIDTH;
+ ili9341_opts.height = ILI9341_HEIGHT;
+ ili9341_opts.current_layer = 0;
+ ili9341_opts.layer1_opacity = 255;
+ ili9341_opts.layer2_opacity = 0;
+ ili9341_opts.current_layer1_surface_idx = 0;
+ ili9341_opts.current_layer2_surface_idx = 0;
+ for (i = 0; i < ILI9341_BUFFERS_PER_LAYER; i++) {
+ ili9341_opts.layer1_surface_buffers[i] =
+ layer1_surface_buffers[i];
+ ili9341_opts.layer2_surface_buffers[i] =
+ layer2_surface_buffers[i];
+ }
+
+ gfx_init(layer1_surface_buffers[0], ILI9341_WIDTH, ILI9341_HEIGHT);
+
+ /* initially fill the screen white again to confuse people */
+ /*
+ for (i=0; i> 16)&0xff,
+ (rgb888_color_key >> 8)&0xff,
+ (rgb888_color_key >> 0)&0xff
+ );
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_COLKEY_ENABLE);
+
+ /* the length of one line of pixels in bytes + 3 then :
+ Line Lenth = Active high width x number of bytes per pixel + 3
+ Active high width = LCD_PIXEL_WIDTH
+ number of bytes per pixel = 2 (pixel_format : RGB565)
+ */
+ /* the pitch is the increment from the start of one line of pixels
+ * to the start of the next line in bytes, then :
+ * Pitch = Active high width x number of bytes per pixel
+ */
+ /* I was too lazy to add makros for this */
+ ltdc_set_fb_line_length(LTDC_LAYER_1, (240*2+3), (240*2));
+ ltdc_set_fb_line_length(LTDC_LAYER_2, (240*2+3), (240*2));
+
+
+ /* Configure the number of lines */
+ ltdc_set_fb_line_count(LTDC_LAYER_1, 320);
+ ltdc_set_fb_line_count(LTDC_LAYER_2, 320);
+
+ /* Start Address configuration :
+ * the LCD Frame buffer is defined on SDRAM
+ */
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_1,
+ (uint32_t)ili9341_opts.layer1_surface_buffers[0]
+ );
+
+ /* Start Address configuration :
+ * the LCD Frame buffer is defined on SDRAM w/ Offset
+ */
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_2,
+ (uint32_t)ili9341_opts.layer2_surface_buffers[0]
+ );
+
+
+ /* All the layer configs are shadow registers which can be reloaded
+ * either immediately with LTDC_SRCR_RELOAD_IMR or in the vsync phase
+ * (i guess) with LTDC_SRCR_RELOAD_VBR
+ * if you want to do double buffering just set the new buffer address
+ * and say ltdc_reload(LTDC_SRCR_RELOAD_VBR)
+ */
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /* Enable foreground & background Layers */
+ ltdc_layer_ctrl_enable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /* enable dithering to add artsy graphical artifacts */
+ ltdc_ctrl_enable(LTDC_GCR_DITHER_ENABLE);
+
+ /* turn ltdc on, uh yeah! */
+ ltdc_ctrl_enable(LTDC_GCR_LTDC_ENABLE);
+
+ /* finally make both layers visible
+ */
+ ltdc_set_constant_alpha(LTDC_LAYER_1, 255);
+ ltdc_set_constant_alpha(LTDC_LAYER_2, 255);
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /*
+ * alpha is set by either color_keying, constant_alpha or
+ * layer blending (which probably also includes color_keying)
+ * according to the blending options selected above
+ * color keying is enabled only for layer 2 with the key
+ * ILI9341_LAYER2_COLOR_KEY
+ */
+}
+
+
+
+
+
+
+/*
+ * Interface stuff
+ */
+
+ili9341_driver_t ili9341_get_driver()
+{
+ return ILI9341_DRIVER_LTDC;
+}
+
+
+bool
+ili9341_is_reloading()
+{
+ return LTDC_SRCR_IS_RELOADING();
+}
+
+void
+ili9341_reload(uint32_t mode)
+{
+ ltdc_reload(mode);
+}
+
+
+void
+ili9341_vsync()
+{
+ while (!ltdc_get_display_status(LTDC_CDSR_VSYNCS));
+}
+
+
+/* double buffering feature (2 buffers for each layer makes 2*2) */
+void
+ili9341_flip_layer1_buffer()
+{
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_1,
+ (uint32_t)ili9341_opts.layer1_surface_buffers[ili9341_opts.current_layer1_surface_idx]
+ );
+
+ ili9341_opts.current_layer1_surface_idx = (ili9341_opts.current_layer1_surface_idx + 1) % ILI9341_BUFFERS_PER_LAYER;
+ /*ltdc_set_fbuffer_address(LTDC_LAYER_1, (uint32_t)ili9341_get_current_layer_buffer_address());*/
+ /*ili9341_opts.current_local_layer1_buffer = (ili9341_opts.current_local_layer1_buffer+1)%ILI9341_BUFFERS_PER_LAYER;*/
+
+ /* vsync or so by the controller shadow register update command */
+ /*ltdc_reload(LTDC_SRCR_RELOAD_VBR);*/
+}
+void
+ili9341_flip_layer2_buffer()
+{
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_2,
+ (uint32_t)ili9341_opts.layer2_surface_buffers[ili9341_opts.current_layer2_surface_idx]
+ );
+
+ ili9341_opts.current_layer2_surface_idx = (ili9341_opts.current_layer2_surface_idx + 1) % ILI9341_BUFFERS_PER_LAYER;
+
+ /* vsync or so by the controller shadow register update command */
+ /*ltdc_reload(LTDC_SRCR_RELOAD_VBR);*/
+}
+
+
+/* draw_pixel and fill draw on layer1 after this is called */
+void
+ili9341_set_layer1(void)
+{
+ /*ili9341_change_current_layer_offset(ILI9341_FRAME_OFFSET*(ili9341_opts.current_local_layer1_buffer));*/
+ __gfx_state.surface = ili9341_opts.layer1_surface_buffers[ili9341_opts.current_layer1_surface_idx];
+ ili9341_opts.current_layer = 0;
+}
+
+/* draw_pixel and fill draw on layer2 after this is called */
+void
+ili9341_set_layer2(void)
+{
+ /*ili9341_change_current_layer_offset(ILI9341_FRAME_OFFSET*(ili9341_opts.current_local_layer2_buffer+ILI9341_BUFFERS_PER_LAYER));*/
+ __gfx_state.surface = ili9341_opts.layer2_surface_buffers[ili9341_opts.current_layer2_surface_idx];
+ ili9341_opts.current_layer = 1;
+}
+
+/* set layer 1 alpha (to hide and stuff) */
+void
+ili9341_set_layer1_opacity(uint8_t opacity)
+{
+ ili9341_opts.layer1_opacity = opacity;
+ ili9341_update_layer_opacity();
+}
+
+/* set layer 2 alpha (to hide and stuff) */
+void
+ili9341_set_layer2_opacity(uint8_t opacity)
+{
+ ili9341_opts.layer2_opacity = opacity;
+ ili9341_update_layer_opacity();
+}
+
+
+/*
+ * set alpha and reload the shadow register after opacity update
+ * disables layer rendering if opacity is 0 (not really worth anything)
+ */
+void
+ili9341_update_layer_opacity(void)
+{
+ if (ili9341_opts.layer1_opacity) {
+ ltdc_layer_ctrl_enable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ } else {
+ ltdc_layer_ctrl_disable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ }
+
+ if (ili9341_opts.layer2_opacity) {
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ } else {
+ ltdc_layer_ctrl_disable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ }
+
+ ltdc_set_constant_alpha(LTDC_LAYER_1, ili9341_opts.layer1_opacity);
+ ltdc_set_constant_alpha(LTDC_LAYER_2, ili9341_opts.layer2_opacity);
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+}
+
+
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.h
new file mode 100644
index 00000000..ca3b312a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lcd_ili9341.h
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef LTDC_ILI9341_H
+#define LTDC_ILI9341_H
+
+/**
+ * Includes
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "clock.h"
+#include "sdram.h"
+#include "gfx_locm3.h"
+
+#ifndef ILI9341_LAYER2_COLOR_KEY
+#define ILI9341_LAYER2_COLOR_KEY 0x01ad
+/*#define ILI9341_LAYER2_COLOR_KEY 0x000C*/
+#endif
+
+
+
+/**/
+#ifndef ILI9341_SPI
+#define ILI9341_SPI SPI5
+#endif
+
+#ifndef ILI9341_CS_PIN
+/* This pin is used on STM32F429 discovery board */
+#define ILI9341_CS_CLK RCC_GPIOC
+#define ILI9341_CS_PORT GPIOC
+#define ILI9341_CS_PIN GPIO2
+#endif
+
+#ifndef ILI9341_WRX_PIN
+/* This pin is used on STM32F429 discovery board */
+#define ILI9341_WRX_CLK RCC_GPIOD
+#define ILI9341_WRX_PORT GPIOD
+#define ILI9341_WRX_PIN GPIO13
+#endif
+
+/* Reset pin */
+#ifndef ILI9341_RST_PIN
+/* Reset pin */
+#define ILI9341_RST_CLK RCC_GPIOD
+#define ILI9341_RST_PORT GPIOD
+#define ILI9341_RST_PIN GPIO12
+#endif
+
+#define ILI9341_RST_SET() { gpio_set(ILI9341_RST_PORT, ILI9341_RST_PIN); }
+#define ILI9341_RST_RESET() { gpio_clear(ILI9341_RST_PORT, ILI9341_RST_PIN); }
+#define ILI9341_SPI_IS_SELECTED() (!gpio_get(ILI9341_CS_PORT, ILI9341_CS_PIN))
+#define ILI9341_SPI_DESELECT() { gpio_set(ILI9341_CS_PORT, ILI9341_CS_PIN); }
+#define ILI9341_SPI_SELECT() { gpio_clear(ILI9341_CS_PORT, ILI9341_CS_PIN); }
+#define ILI9341_WRX_SET() { gpio_set(ILI9341_WRX_PORT, ILI9341_WRX_PIN); }
+#define ILI9341_WRX_RESET() { gpio_clear(ILI9341_WRX_PORT, ILI9341_WRX_PIN); }
+/**/
+
+
+
+/* Commands */
+#define ILI9341_RESET 0x01
+#define ILI9341_SLEEP_OUT 0x11
+#define ILI9341_GAMMA 0x26
+#define ILI9341_DISPLAY_OFF 0x28
+#define ILI9341_DISPLAY_ON 0x29
+#define ILI9341_COLUMN_ADDR 0x2A
+#define ILI9341_PAGE_ADDR 0x2B
+#define ILI9341_GRAM 0x2C
+#define ILI9341_MAC 0x36
+#define ILI9341_PIXEL_FORMAT 0x3A
+#define ILI9341_WDB 0x51
+#define ILI9341_WCD 0x53
+#define ILI9341_RGB_INTERFACE 0xB0
+#define ILI9341_FRC 0xB1
+#define ILI9341_BPC 0xB5
+#define ILI9341_DFC 0xB6
+#define ILI9341_POWER1 0xC0
+#define ILI9341_POWER2 0xC1
+#define ILI9341_VCOM1 0xC5
+#define ILI9341_VCOM2 0xC7
+#define ILI9341_POWERA 0xCB
+#define ILI9341_POWERB 0xCF
+#define ILI9341_PGAMMA 0xE0
+#define ILI9341_NGAMMA 0xE1
+#define ILI9341_DTCA 0xE8
+#define ILI9341_DTCB 0xEA
+#define ILI9341_POWER_SEQ 0xED
+#define ILI9341_3GAMMA_EN 0xF2
+#define ILI9341_INTERFACE 0xF6
+#define ILI9341_PRC 0xF7
+
+
+
+/* LCD settings */
+#define ILI9341_WIDTH 240
+#define ILI9341_HEIGHT 320
+
+
+#define ILI9341_SURFACE_SIZE ((ILI9341_WIDTH*ILI9341_HEIGHT)*sizeof(uint16_t))
+
+
+/* double buffering
+ * (values other than 2 were not tested and make not too much sense..)
+ */
+#define ILI9341_BUFFERS_PER_LAYER 2
+
+
+
+typedef struct {
+ uint16_t width;
+ uint16_t height;
+ uint8_t current_layer;
+ uint8_t layer1_opacity;
+ uint8_t layer2_opacity;
+ uint8_t current_layer1_surface_idx;
+ uint8_t current_layer2_surface_idx;
+ uint16_t *layer1_surface_buffers[ILI9341_BUFFERS_PER_LAYER];
+ uint16_t *layer2_surface_buffers[ILI9341_BUFFERS_PER_LAYER];
+} ili9341_options_t;
+
+extern ili9341_options_t ili9341_opts;
+void ili9341_init(
+ uint16_t *layer1_surface_buffers[],
+ uint16_t *layer2_surface_buffers[]
+ );
+void ili9341_init_pins(void);
+void ili9341_init_ltdc(void);
+void ili9341_init_layers(void);
+void ili9341_init_lcd(void);
+void ili9341_spi5_isr(void);
+
+
+/*static inline void ili9341_set_width(uint16_t width);*/
+
+typedef enum {
+ ILI9341_DRIVER_SPI,
+ ILI9341_DRIVER_LTDC,
+} ili9341_driver_t;
+
+ili9341_driver_t ili9341_get_driver(void);
+
+/* Check if the display is reloading */
+bool ili9341_is_reloading(void);
+
+/* Reload screen */
+void ili9341_reload(uint32_t mode);
+
+/* Wait for vertical synchronisation */
+void ili9341_vsync(void);
+
+static inline
+uint16_t*
+ili9341_get_current_layer_buffer_address(void) {
+ return __gfx_state.surface;
+}
+
+/* Flip the double_buffer */
+void ili9341_flip_layer1_buffer(void);
+void ili9341_flip_layer2_buffer(void);
+
+/* Simple delay */
+/*void ili9341_delay(volatile unsigned int delay);*/
+
+
+void ili9341_set_layer1(void);
+
+void ili9341_set_layer2(void);
+
+void ili9341_set_layer1_opacity(uint8_t opacity);
+
+void ili9341_set_layer2_opacity(uint8_t opacity);
+void ili9341_update_layer_opacity(void);
+
+
+
+#define ili9341_delay(cycles) wait_cycles(cycles);
+
+#endif
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lct-ltdc-touch-game (stlink-v2.1).launch b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lct-ltdc-touch-game (stlink-v2.1).launch
new file mode 100644
index 00000000..01d1a1e1
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/lct-ltdc-touch-game (stlink-v2.1).launch
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.c
new file mode 100644
index 00000000..0a4fc1b1
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.c
@@ -0,0 +1,139 @@
+#include "sdram.h"
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+/*
+ * This then is the initialization code extracted from the
+ * sdram example.
+ */
+#include
+#include
+#include
+#include
+#include "clock.h"
+
+/*
+ * This is just syntactic sugar but it helps, all of these
+ * GPIO pins get configured in exactly the same way.
+ */
+static struct {
+ uint32_t gpio;
+ uint16_t pins;
+} sdram_pins[6] = {
+ {GPIOB, GPIO5 | GPIO6 },
+ {GPIOC, GPIO0 },
+ {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 | GPIO4 | GPIO5 | GPIO8 | GPIO15}
+};
+
+static struct sdram_timing timing = {
+ .trcd = 2, /* RCD Delay */
+ .trp = 2, /* RP Delay */
+ .twr = 2, /* Write Recovery Time */
+ .trc = 7, /* Row Cycle Delay */
+ .tras = 4, /* Self Refresh Time */
+ .txsr = 7, /* Exit Self Refresh Time */
+ .tmrd = 2, /* Load to Active Delay */
+};
+
+/*
+ * Initialize the SD RAM controller.
+ */
+void
+sdram_init(void) {
+ int i;
+ uint32_t cr_tmp, tr_tmp; /* control, timing registers */
+
+ /*
+ * First all the GPIO pins that end up as SDRAM pins
+ */
+ rcc_periph_clock_enable(RCC_GPIOB);
+ rcc_periph_clock_enable(RCC_GPIOC);
+ rcc_periph_clock_enable(RCC_GPIOD);
+ rcc_periph_clock_enable(RCC_GPIOE);
+ rcc_periph_clock_enable(RCC_GPIOF);
+ rcc_periph_clock_enable(RCC_GPIOG);
+
+ for (i = 0; i < 6; i++) {
+ gpio_mode_setup(sdram_pins[i].gpio,
+ GPIO_MODE_AF, GPIO_PUPD_NONE,
+ sdram_pins[i].pins);
+ gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP,
+ GPIO_OSPEED_50MHZ, sdram_pins[i].pins);
+ gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins);
+ }
+
+ /* Enable the SDRAM Controller */
+#if 1
+ rcc_periph_clock_enable(RCC_FSMC);
+#else
+ rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN);
+#endif
+
+ /* Note the STM32F429-DISCO board has the ram attached to bank 2 */
+ /* Timing parameters computed for a 168Mhz clock */
+ /* These parameters are specific to the SDRAM chip on the board */
+
+ cr_tmp = FMC_SDCR_RPIPE_1CLK;
+ cr_tmp |= FMC_SDCR_SDCLK_2HCLK;
+ cr_tmp |= FMC_SDCR_CAS_3CYC;
+ cr_tmp |= FMC_SDCR_NB4;
+ cr_tmp |= FMC_SDCR_MWID_16b;
+ cr_tmp |= FMC_SDCR_NR_12;
+ cr_tmp |= FMC_SDCR_NC_8;
+
+ /* We're programming BANK 2, but per the manual some of the parameters
+ * only work in CR1 and TR1 so we pull those off and put them in the
+ * right place.
+ */
+ FMC_SDCR1 |= (cr_tmp & FMC_SDCR_DNC_MASK);
+ FMC_SDCR2 = cr_tmp;
+
+ tr_tmp = sdram_timing(&timing);
+ FMC_SDTR1 |= (tr_tmp & FMC_SDTR_DNC_MASK);
+ FMC_SDTR2 = tr_tmp;
+
+ /* Now start up the Controller per the manual
+ * - Clock config enable
+ * - PALL state
+ * - set auto refresh
+ * - Load the Mode Register
+ */
+ sdram_command(SDRAM_BANK2, SDRAM_CLK_CONF, 1, 0);
+ msleep_loop(1); /* sleep at least 100uS */
+ sdram_command(SDRAM_BANK2, SDRAM_PALL, 1, 0);
+ sdram_command(SDRAM_BANK2, SDRAM_AUTO_REFRESH, 4, 0);
+ tr_tmp = SDRAM_MODE_BURST_LENGTH_2 |
+ SDRAM_MODE_BURST_TYPE_SEQUENTIAL |
+ SDRAM_MODE_CAS_LATENCY_3 |
+ SDRAM_MODE_OPERATING_MODE_STANDARD |
+ SDRAM_MODE_WRITEBURST_MODE_SINGLE;
+ sdram_command(SDRAM_BANK2, SDRAM_LOAD_MODE, 1, tr_tmp);
+
+ /*
+ * set the refresh counter to insure we kick off an
+ * auto refresh often enough to prevent data loss.
+ */
+ FMC_SDRTR = 683;
+ /* and Poof! a 8 megabytes of ram shows up in the address space */
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.h
new file mode 100644
index 00000000..af97a641
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/sdram.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#ifndef __SDRAM_H
+#define __SDRAM_H
+
+#define SDRAM_BASE_ADDRESS (0xd0000000U)
+
+/* Initialize the SDRAM chip on the board */
+void sdram_init(void);
+
+#ifndef NULL
+#define NULL (void *)(0)
+#endif
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.c
new file mode 100644
index 00000000..2fec08de
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.c
@@ -0,0 +1,386 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "touchscreen_controller_stmpe811.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*static*/
+stmpe811_t stmpe811;
+
+void
+stmpe811_setup_hardware() {
+
+ rcc_periph_clock_enable(STMPE811_I2C_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_SDA_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_SCL_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_INT_CLK);
+
+
+ /* STMPE811 interrupt
+ * - INT (the board has a 4.7k pullup resistor for this pin)
+ */
+ gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO15);
+
+ /* I2C */
+ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
+ gpio_set_output_options(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO8);
+ gpio_set_af(GPIOA, GPIO_AF4, GPIO8);
+
+ gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
+ gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO9);
+ gpio_set_af(GPIOC, GPIO_AF4, GPIO9);
+
+ /* I2C setup */
+ i2c_setup_master(STMPE811_I2C, 400000);
+}
+
+void
+stmpe811_enable_interrupts() {
+ nvic_set_priority(NVIC_EXTI15_10_IRQ, 0xff);
+
+ exti_select_source(EXTI15, GPIOA);
+ exti_set_trigger(EXTI15, EXTI_TRIGGER_FALLING);
+ exti_enable_request(EXTI15);
+ nvic_enable_irq(NVIC_EXTI15_10_IRQ);
+}
+
+void
+stmpe811_setup() {
+ memset((char *)&stmpe811, 0, sizeof(stmpe811_t));
+
+ /** TODO removeme **/
+ stmpe811.last_values_count = 0;
+ stmpe811.touch_interrupts = 0;
+ /*******************/
+
+ /* soft reset */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL1, 2}, 2,
+ NULL, 0);
+ msleep_loop(10);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL1, 0}, 2,
+ NULL, 0);
+ msleep_loop(2);
+
+
+ /* Interrupts */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_EN, 0b00001111}, 2, /* enable FIFO and Touch interrupts */
+ NULL, 0);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_CTRL, 0b011}, 2, /* active low, flank interrupt, global int on */
+ NULL, 0);
+
+
+ /* ADC */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_ADC_CTRL1, 0b00011000}, 2, /* clk sample time 44, 12bit, internal ref */
+ NULL, 0);
+
+ msleep_loop(2);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_ADC_CTRL2, 0b10}, 2, /* ADC clk ~6.5MHz (/44=147kHz) */
+ NULL, 0);
+}
+
+uint8_t
+stmpe811_read_interrupt_status() {
+ uint8_t s;
+ /* read the status */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA}, 1,
+ &s, 1);
+ return s;
+}
+
+void
+stmpe811_start_temp_measurements() {
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /*(uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b0111}, 2,*/ /* turn on temperature sensor */
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b0110}, 2, /* turn on clocks (temp,!gpio,!tsc,adc) */
+ NULL, 0);
+
+ /* Temp */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_CTRL, 0b111}, 2, /* start temp measurement, measure forever (every 10ms) */
+ NULL, 0);
+}
+
+uint16_t
+stmpe811_read_temp_sample() {
+ uint16_t temp;
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_DATA}, 1,
+ (uint8_t *)&temp, 2);
+ temp = (temp<<8)|(temp>>8); /* switch msb/lsb */
+ /* *3Vio/7.51 == 1°C (for some reason this didn't work so i
+ * tinkered with the numbers a little :)) */
+ return (uint16_t)((((uint32_t)temp*30000)/751)>>4);
+}
+
+void
+stmpe811_stop_temp_measuements() {
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b1111}, 2, /* turn on clocks (!temp,!gpio,!tsc,!adc) */
+ NULL, 0);
+
+ /* Temp */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_CTRL, 0b000}, 2, /* stop */
+ NULL, 0);
+}
+
+#define x8(x) x>>8, x&255
+
+void
+stmpe811_start_tsc() {
+
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b1100}, 2, /* turn on clocks (!temp,!gpio,tsc,adc) */
+ NULL, 0);
+
+ /* TSC setup */
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_GPIO_ALT_FUNCT, 0b00001111}, 2, /* disable af on gpio */
+ NULL, 0);
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* 2 samples averaging, 500us touch detect delay, 500us settling time */
+ (uint8_t[]){STMPE811_REG_TSC_CFG, 0b01011010}, 2,
+ /* 2 samples averaging, 100us touch detect delay, 100us settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b01010001}, 2,*/
+ /* no averaging, 1ms touch detect delay, 50us settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b00100001}, 2,*/
+ /* no averaging, 1ms touch detect delay, 1ms settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b00100011}, 2,*/
+ NULL, 0);
+
+ /* Z is not reported, see STMPE811_REG_TSC_CTRL config */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_FRACT_Z, 0b100 }, 2, /* Fraction Z (z accuracy) 4:4 */
+ NULL, 0);
+
+ /* TODO maybe set shield for X- and Y- lines (no improvement..) */
+ /*i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_SHIELD,0b0101 }, 2, // Shield (Ground X- and Y-)
+ NULL, 0);*/
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* Max current on short typ.50mA (max xxxmA)*/
+ (uint8_t[]){STMPE811_REG_TSC_I_DRIVE, 0b1}, 2,
+ /*(typ.20mA (max 35mA))*/
+ /*(uint8_t[]){STMPE811_REG_TSC_I_DRIVE,0b0}, 2,*/
+ NULL, 0);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* No line is connected to GND */
+ (uint8_t[]){STMPE811_REG_TSC_SHIELD, 0b0}, 2,
+ NULL, 0);
+
+ /* setup descriptions for portrait view (0°) */
+ /* bottom left x, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_BL_X, x8(STMPE811_X_MIN)}, 3,
+ NULL, 0);
+ /* bottom left y, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_BL_Y, x8(STMPE811_Y_MIN)}, 3,
+ NULL, 0);
+ /* top right x, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_TR_X, x8(STMPE811_X_MAX)}, 3,
+ NULL, 0);
+ /* top right y, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_TR_Y, x8(STMPE811_Y_MAX)}, 3,
+ NULL, 0);
+
+ /* FIFO interrupt threshold 1 samples */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_TH, 1}, 2,
+ NULL, 0);
+ /* Reset FIFO */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_STA, 0b00000001}, 2,
+ NULL, 0);
+ /*msleep_loop(1);*/
+
+ /* Start FIFO */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_STA, 0x20}, 2,
+ NULL, 0);
+
+ /* Clear all the status pending bits if any */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA, 0xFF}, 2,
+ NULL, 0);
+
+ /* window tracking disabled (generate a sample every n-points move), XY acquisition, Enable */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_CTRL, 0b00000011}, 2,
+ NULL, 0);
+
+ msleep_loop(2);
+
+ stmpe811.sample_read_state = STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT;
+}
+
+
+void
+stmpe811_handle_interrupt() {
+ /* initializations here are not needed.. */
+ uint16_t i;
+ /*uint16_t x,y,xmin=0,xmax=0,ymin=0,ymax=0, u,i,v;*/
+ /*uint32_t all_x,all_y;*/
+
+ /*
+ if (!STMPE811_HAS_INTERRUPT()) {
+ return;
+ }
+ */
+
+ /* read the status */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA}, 1,
+ stmpe811.rb, 1);
+
+ /* clear the interrupts */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA, stmpe811.rb[0]}, 2,
+ NULL, 0);
+
+
+ /* handle touch detected */
+ if (stmpe811.rb[0]&STMPE811_INT__TOUCH_DET) {
+ stmpe811.touch_interrupts++;
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_CTRL}, 1,
+ stmpe811.rb+1, 1);
+
+ /* update touch state */
+ stmpe811.current_touch_state = 0 != (stmpe811.rb[1]&STMPE811_TSC_CTRL__TOUCH_DET) ? STMPE811_TOUCH_STATE__TOUCHED : STMPE811_TOUCH_STATE__UNTOUCHED;
+
+ }
+ switch (stmpe811.sample_read_state) {
+ case STMPE811_TOUCH_STATE__UNTOUCHED:
+ case STMPE811_TOUCH_STATE__TOUCHED:
+ stmpe811.touch.touched = 0;
+ stmpe811.sample_read_state = stmpe811.current_touch_state;
+ break;
+ case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ if (stmpe811.interrupt_timeout < mtime() && stmpe811.touch.touched == 0) {
+ stmpe811.sample_read_state = stmpe811.current_touch_state;
+ } else
+ if (stmpe811.current_touch_state == STMPE811_TOUCH_STATE__TOUCHED) {
+ stmpe811.interrupt_timeout = mtime() + STMPE811_INTERRUPT_TIMEOUT;
+ }
+ break;
+ }
+
+ /* handle fifo data */
+ if (stmpe811.rb[0]&STMPE811_INT__FIFO_HAS_DATA) {
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_SIZE}, 1,
+ stmpe811.rb+1, 1);
+
+ /* fifo has data (rb[1] should never be 0 here!) */
+ if (stmpe811.rb[1]) {
+ stmpe811.last_values_count = stmpe811.rb[1];
+ i = stmpe811.rb[1]*3;
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_DATA_XYZ_NA}, 1,
+ stmpe811.rb+2, i);
+
+ i += 2;
+ /*for (u=2; u>4);
+ y = ((uint16_t)(stmpe811.rb[u+1]&0xf)<<8)|(stmpe811.rb[u+2]>>0);*/
+
+ /* 1st stage of filtering.. last STMPE811_SAMPLES_HISTORY_LENGTH samples max 100 deviation (~3%) */
+ stmpe811.last_valid_sample.x = ((uint16_t)(stmpe811.rb[i-3]) << 4)|(stmpe811.rb[i-2]>>4);
+ stmpe811.last_valid_sample.y = ((uint16_t)(stmpe811.rb[i-2]&0xf) << 8)|(stmpe811.rb[i-1]>>0);
+ stmpe811.last_valid_sample.z = (uint16_t)(stmpe811.rb[i-1] & 0xffff);
+ stmpe811.last_valid_sample.sample_is_fresh = 1;
+ stmpe811.drag_timeout = mtime() + STMPE811_DRAG_TIMEOUT;
+
+ switch (stmpe811.sample_read_state) {
+ case STMPE811_TOUCH_STATE__UNTOUCHED: /* TODO unignore this.. */
+ case STMPE811_TOUCH_STATE__TOUCHED:
+ stmpe811.touch.touched = 1;
+ stmpe811.touch.x = stmpe811.last_drag_sample.x = stmpe811.last_valid_sample.x;
+ stmpe811.touch.y = stmpe811.last_drag_sample.y = stmpe811.last_valid_sample.y;
+ stmpe811.touch.z = stmpe811.last_drag_sample.z = stmpe811.last_valid_sample.z;
+ /*stmpe811.last_valid_sample.sample_is_fresh = 0;*/
+ stmpe811.interrupt_timeout = mtime() + STMPE811_INTERRUPT_TIMEOUT;
+
+ stmpe811.sample_read_state = STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT;
+ break;
+ case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ break;
+ }
+ }
+ }
+}
+
+stmpe811_touch_state_t
+stmpe811_get_current_touch_state(void) {
+ return stmpe811.current_touch_state;
+}
+stmpe811_touch_t
+stmpe811_get_touch_data(void) {
+ stmpe811_touch_t touch = stmpe811.touch;
+ stmpe811.touch.touched = 0;
+ return touch;
+}
+stmpe811_drag_data_t
+stmpe811_get_drag_data(void) {
+ if ((stmpe811.last_valid_sample.sample_is_fresh)
+ && (stmpe811.sample_read_state == STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT)) {
+ stmpe811_drag_data_t drag_data;
+ stmpe811_valid_sample_t sample = stmpe811.last_valid_sample;
+ drag_data.data_is_valid = 1;
+ /* is more precise, because it has no accumulating conversion errors,
+ * but makes gui implementation harder..
+ drag_data.dx = sample.x - stmpe811.touch.x;
+ drag_data.dy = sample.y - stmpe811.touch.y;
+ */
+ drag_data.dx = sample.x - stmpe811.last_drag_sample.x;
+ drag_data.dy = sample.y - stmpe811.last_drag_sample.y;
+ drag_data.dz = sample.z - stmpe811.last_drag_sample.z;
+ stmpe811.last_drag_sample.x = sample.x;
+ stmpe811.last_drag_sample.y = sample.y;
+ stmpe811.last_drag_sample.z = sample.z;
+ stmpe811.last_valid_sample.sample_is_fresh = 0;
+ return drag_data;
+ } else {
+ return (stmpe811_drag_data_t) {
+ .data_is_valid = stmpe811.drag_timeout > mtime(),
+ .dx = 0, .dy = 0, .dz = 0
+ };
+ }
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.h
new file mode 100644
index 00000000..ae43f2fc
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/touchscreen_controller_stmpe811.h
@@ -0,0 +1,221 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#ifndef CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_
+#define CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+
+
+
+
+/**
+ * STMPE811 definitions
+ */
+
+#ifndef STMPE811_I2C
+#define STMPE811_I2C I2C3
+#define STMPE811_I2C_CLK RCC_I2C3
+/*#define STMPE811_I2C_RST RST_I2C3*/
+
+#define STMPE811_I2C_SDA_CLK RCC_GPIOA
+#define STMPE811_I2C_SDA_PORT GPIOA
+#define STMPE811_I2C_SDA_PIN GPIO8
+#define STMPE811_I2C_SCL_CLK RCC_GPIOC
+#define STMPE811_I2C_SCL_PORT GPIOC
+#define STMPE811_I2C_SCL_PIN GPIO9
+#define STMPE811_I2C_INT_CLK RCC_GPIOA
+#define STMPE811_I2C_INT_PORT GPIOA
+#define STMPE811_I2C_INT_PIN GPIO15
+
+#define STMPE811_I2C_ADDRESS (0b1000001)
+
+#endif
+
+/* registers */
+#define STMPE811_REG_CHIP_ID 0x00
+#define STMPE811_REG_ID_VER 0x02
+#define STMPE811_REG_SYS_CTRL1 0x03
+#define STMPE811_REG_SYS_CTRL2 0x04
+#define STMPE811_REG_SPI_CFG 0x08
+#define STMPE811_REG_INT_CTRL 0x09
+#define STMPE811_REG_INT_EN 0x0A
+#define STMPE811_REG_INT_STA 0x0B
+#define STMPE811_REG_GPIO_INT_EN 0x0C
+#define STMPE811_REG_GPIO_INT_STA 0x0D
+#define STMPE811_REG_ADC_INT_EN 0x0E
+#define STMPE811_REG_ADC_INT_STA 0x0F
+#define STMPE811_REG_GPIO_SET_PIN 0x10
+#define STMPE811_REG_GPIO_CLR_PIN 0x11
+#define STMPE811_REG_GPIO_MP_STA 0x12
+#define STMPE811_REG_GPIO_DIR 0x13
+#define STMPE811_REG_GPIO_ED 0x14
+#define STMPE811_REG_GPIO_RE 0x15
+#define STMPE811_REG_GPIO_FE 0x16
+#define STMPE811_REG_GPIO_ALT_FUNCT 0x17
+#define STMPE811_REG_ADC_CTRL1 0x20
+#define STMPE811_REG_ADC_CTRL2 0x21
+#define STMPE811_REG_ADC_CAPT 0x22
+#define STMPE811_REG_ADC_DATA_CH0 0x30
+#define STMPE811_REG_ADC_DATA_CH1 0x32
+#define STMPE811_REG_ADC_DATA_CH2 0x34
+#define STMPE811_REG_ADC_DATA_CH3 0x36
+#define STMPE811_REG_ADC_DATA_CH4 0x38
+#define STMPE811_REG_ADC_DATA_CH5 0x3A
+#define STMPE811_REG_ADC_DATA_CH6 0x3C
+#define STMPE811_REG_ADC_DATA_CH7 0x3E
+#define STMPE811_REG_TSC_CTRL 0x40
+#define STMPE811_REG_TSC_CFG 0x41
+#define STMPE811_REG_WDW_TR_X 0x42
+#define STMPE811_REG_WDW_TR_Y 0x44
+#define STMPE811_REG_WDW_BL_X 0x46
+#define STMPE811_REG_WDW_BL_Y 0x48
+#define STMPE811_REG_FIFO_TH 0x4A
+#define STMPE811_REG_FIFO_STA 0x4B
+#define STMPE811_REG_FIFO_SIZE 0x4C
+#define STMPE811_REG_TSC_DATA_X 0x4D
+#define STMPE811_REG_TSC_DATA_Y 0x4F
+#define STMPE811_REG_TSC_DATA_Z 0x51
+#define STMPE811_REG_TSC_DATA_XYZ 0x52
+#define STMPE811_REG_TSC_DATA_XYZ_NA 0xD7
+#define STMPE811_REG_TSC_FRACT_Z 0x56
+#define STMPE811_REG_TSC_DATA 0x57
+#define STMPE811_REG_TSC_I_DRIVE 0x58
+#define STMPE811_REG_TSC_SHIELD 0x59
+#define STMPE811_REG_TEMP_CTRL 0x60
+#define STMPE811_REG_TEMP_DATA 0x61
+#define STMPE811_REG_TEMP_TH 0x63
+
+/* interesting bitmasks */
+#define STMPE811_INT__TOUCH_DET (1<<0)
+#define STMPE811_INT__FIFO_TH (1<<1)
+#define STMPE811_INT__FIFO_OFLOW (1<<2)
+#define STMPE811_INT__FIFO_FULL (1<<3)
+#define STMPE811_INT__FIFO_EMPTY (1<<4)
+#define STMPE811_INT__TEMP_SENS (1<<5)
+#define STMPE811_INT__ADC (1<<6)
+#define STMPE811_INT__GPIO (1<<7)
+
+#define STMPE811_INT__FIFO_HAS_DATA ( \
+ STMPE811_INT__FIFO_TH | \
+ STMPE811_INT__FIFO_OFLOW | \
+ STMPE811_INT__FIFO_FULL \
+ )
+
+#define STMPE811_TSC_CTRL__TOUCH_DET (1<<7)
+
+
+
+/**
+ * Touch controller setup
+ */
+/*
+ *
+ */
+#define STMPE811_X_MIN 300
+#define STMPE811_X_MAX 3850
+#define STMPE811_Y_MIN 400
+#define STMPE811_Y_MAX 3900
+
+/* STMPE811_INTERRUPT_TIMEOUT ms no stmpe811-interrupt
+ * shall occur until touch data is considered to set touched again :P */
+#define STMPE811_INTERRUPT_TIMEOUT 100
+#define STMPE811_DRAG_TIMEOUT 100 /* values bigger than STMPE811_INTERRUPT_TIMEOUT make no sense..*/
+
+typedef enum {
+ STMPE811_TOUCH_STATE__UNTOUCHED = 0, /* set by init / timeout in interrupt */
+ STMPE811_TOUCH_STATE__TOUCHED, /* set by touch interrupt */
+ STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT, /* set by */
+} stmpe811_touch_state_t;
+
+typedef struct {
+ int16_t x, y, z;
+} stmpe811_xyz_sample_t;
+typedef struct {
+ uint32_t touched;
+ int16_t x, y, z;
+} stmpe811_touch_t;
+typedef struct {
+ uint32_t sample_is_fresh;
+ int16_t x, y, z;
+} stmpe811_valid_sample_t;
+typedef struct {
+ uint32_t data_is_valid;
+ int16_t dx, dy, dz;
+} stmpe811_drag_data_t;
+typedef struct {
+ /*uint8_t init;*/
+ stmpe811_touch_t touch;
+ stmpe811_touch_state_t sample_read_state;
+ stmpe811_touch_state_t current_touch_state;
+ stmpe811_valid_sample_t last_valid_sample;
+ stmpe811_xyz_sample_t last_drag_sample;
+ uint32_t touch_interrupts;
+ uint32_t last_values_count;
+ /*uint16_t xmin,xmax,ymin,ymax; */ /* made this constant */
+ uint64_t interrupt_timeout;
+ uint64_t drag_timeout;
+ uint8_t rb[128*4+2]; /* fifo read buffer */
+} stmpe811_t;
+
+void
+stmpe811_setup_hardware(void);
+void
+stmpe811_enable_interrupts(void);
+
+void
+stmpe811_setup(void); /*, save_data_t *save_data);*/
+uint8_t
+stmpe811_read_interrupt_status(void);
+void
+stmpe811_start_temp_measurements(void);
+uint16_t
+stmpe811_read_temp_sample(void);
+void
+stmpe811_stop_temp_measuements(void);
+void
+stmpe811_start_tsc(void);
+
+void
+stmpe811_handle_interrupt(void);
+stmpe811_touch_state_t
+stmpe811_get_current_touch_state(void);
+stmpe811_touch_t
+stmpe811_get_touch_data(void);
+stmpe811_drag_data_t
+stmpe811_get_drag_data(void);
+
+
+/* REMOVE ME! DEBUG */
+extern stmpe811_t stmpe811;
+
+#endif /* CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.c
new file mode 100644
index 00000000..dcec2875
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.c
@@ -0,0 +1,620 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ */
+
+
+#include "bezier.h"
+
+/**
+ * Interpolate the points to create a smooth curve
+ * for every point which is not the start or end point
+ * first look at the slope between the next and previous points
+ * Then place the handles at 1/tension the way from the point
+ * in the direction of the slope
+ *
+ * fills int_points array of point2d_t with the length (points_length-2)*3+4
+ * in the form :
+ * [ p_start_end,p_control_1,p_control_2,p_start_end, p_control_1, ... ]
+ *
+ * @param int_points
+ * @param points
+ * @param points_length
+ * @param overshoot
+ * @param tension eg. 3
+ * @return
+ */
+void
+bezier_cubic(
+ point2d_t *int_points,
+ point2d_t *points,
+ uint32_t points_length,
+ vector_flt_t overshoot,
+ vector_flt_t tension
+) { /* tension=.3 */
+ uint32_t i;
+
+ /* TODO fill int_points with valid (linear) data */
+ /*assert(points_length >= 3);*/
+ if (points_length < 3) {
+ return;
+ }
+
+ point2d_t *ipp = int_points;
+ *ipp++ = points[0];
+
+ point2d_t p1, p2, p3;
+ point2d_t slope, slope1, slope2;
+ point2d_t offset, offset1, offset2;
+ vector_flt_t dist, dist1, dist2;
+ vector_flt_t ang, ang1, ang2;
+
+ slope = point2d_sub_ts(points[1], points[0]);
+ offset = point2d_div_t(slope, tension);
+
+ *ipp++ = point2d_add_ts(points[0], offset);
+
+ for (i = 1; i < points_length - 1; i++) {
+ p1 = points[i - 1];
+ p2 = points[i];
+ p3 = points[i + 1];
+
+ slope = point2d_sub_ts(p3, p1);
+ slope1 = point2d_sub_ts(p2, p1);
+ slope2 = point2d_sub_ts(p2, p3);
+
+ dist = point2d_norm(slope);
+ dist1 = point2d_norm(slope1);
+ dist2 = point2d_norm(slope2);
+
+ /* TODO use linear.. */
+ ang = vector_flt_atan2(slope.y, slope.x);
+ ang1 = vector_flt_atan2(slope1.y, slope1.x);
+ ang2 = vector_flt_atan2(slope2.y, slope2.x);
+
+ dist1 *= vector_flt_abs(vector_flt_cos(ang1 - ang));
+ dist2 *= vector_flt_abs(vector_flt_cos(ang2 - ang));
+
+ vector_flt_t cos_ang = slope.x/dist;
+ vector_flt_t sin_ang = slope.y/dist;
+
+ offset1 = (point2d_t){
+ dist1 * cos_ang / tension, dist1 * sin_ang / tension
+ };
+ offset2 = (point2d_t){
+ dist2 * cos_ang / tension, dist2 * sin_ang / tension
+ };
+
+ vector_flt_t om1 = point2d_norm(offset1);
+ vector_flt_t om2 = point2d_norm(offset2);
+
+ offset1 = point2d_mul_t(
+ offset1,
+ vector_flt_max(om1, overshoot)/om1
+ );
+
+ offset2 = point2d_mul_t(
+ offset2,
+ vector_flt_max(om2, overshoot)/om2
+ );
+
+ *ipp++ = point2d_sub_ts(p2, offset1);
+ *ipp++ = p2;
+ *ipp++ = point2d_add_ts(p2, offset2);
+ }
+
+ slope = point2d_sub_ts(
+ points[points_length - 1], points[points_length - 2]
+ );
+ offset = point2d_div_t(slope, tension);
+
+ *ipp++ = point2d_sub_ts(points[points_length - 1], offset);
+ *ipp++ = points[points_length - 1];
+}
+
+/**
+ * Interpolate the points to create a smooth curve
+ * for every point which is not the start or end point
+ * first look at the slope between the next and previous points
+ * Then place the handles at 1/tension the way from the point in
+ * the direction of the slope
+ *
+ * Given that all the points are roughly equidistant from the next
+ * (saves some computation time)
+ *
+ * fills int_points array of point2d_t with the length
+ * (points_length-2)*3+4 in the form
+ * [ p_start_end,p_control_1,p_control_2,p_start_end, p_control_1, ... ]
+ *
+ * @param int_points buffer with the size of (points_length-2)*3+4 or h2_bezier_calculate_int_points_length
+ * @param points
+ * @param points_length
+ * @param overshoot
+ * @param tension eg. 3
+ * @return
+ */
+void
+bezier_cubic_symmetric(
+ point2d_t *int_points,
+ point2d_t *points,
+ uint32_t points_length,
+ vector_flt_t overshoot,
+ vector_flt_t tension
+) { /*tension=.3*/
+ uint32_t i;
+ /* TODO fill int_points with valid (linear) data */
+ /*assert(points_length >= 3);*/
+ if (points_length < 3) {
+ return;
+ }
+
+ point2d_t *ipp = int_points;
+
+ *ipp++ = points[0];
+
+ point2d_t p1, p2, p3;
+ point2d_t slope, slope1;
+ point2d_t offset, offset1;
+ vector_flt_t dist, dist1;
+ vector_flt_t ang, ang1;
+
+ slope = point2d_sub_ts(points[1], points[0]);
+ offset = point2d_div_t(slope, tension);
+
+ *ipp++ = point2d_add_ts(points[0], offset);
+
+ for (i = 1; i < points_length - 1; i++) {
+ p1 = points[i - 1];
+ p2 = points[i];
+ p3 = points[i + 1];
+
+ slope = point2d_sub_ts(p3, p1);
+ slope1 = point2d_sub_ts(p2, p1);
+
+ dist = point2d_norm(slope);
+ dist1 = point2d_norm(slope1);
+
+ /* TODO use linear.. */
+ ang = vector_flt_atan2(slope.y, slope.x);
+ ang1 = vector_flt_atan2(slope1.y, slope1.x);
+
+ dist1 *= vector_flt_abs(vector_flt_cos(ang1 - ang));
+
+ vector_flt_t cos_ang = slope.x/dist;
+ vector_flt_t sin_ang = slope.y/dist;
+
+ offset1 = (point2d_t){
+ dist1 * cos_ang / tension, dist1 * sin_ang / tension
+ };
+
+ vector_flt_t om1 = point2d_norm(offset1);
+ offset1 = point2d_mul_t(
+ offset1,
+ vector_flt_max(om1, overshoot)/om1
+ );
+
+ *ipp++ = point2d_sub_ts(p2, offset1);
+ *ipp++ = p2;
+ *ipp++ = point2d_add_ts(p2, offset1);
+ }
+
+
+ slope = point2d_sub_ts(
+ points[points_length - 1], points[points_length - 2]
+ );
+ offset = point2d_div_t(slope, tension);
+
+ *ipp++ = point2d_sub_ts(points[points_length - 1], offset);
+ *ipp++ = points[points_length - 1];
+}
+
+
+
+typedef void(*h2bez_draw_t) (point2d_t p1, point2d_t p2);
+
+/* TODO resolution x/y instead of num_segments */
+void
+bezier_draw_cubic(
+ h2bez_draw_t draw,
+ uint32_t num_segments,
+ point2d_t p0, point2d_t p1, point2d_t p2, point2d_t p3
+) {
+ uint32_t n;
+
+ /* draw a single point.. */
+ /* TODO use better min-value.. (eg 1 instead of e*100) */
+ if (point2d_dist(p0, p1) < vector_flt_EPSILON*100) {
+ draw(p0, p3);
+ return;
+ }
+
+ point2d_t q0, q1, q2;
+ point2d_t r0, r1;
+
+ point2d_t b0, b1;
+ point2d_t p10ns, p21ns, p32ns;
+
+ b1 = p0;
+
+ vector_flt_t nsf = (vector_flt_t)num_segments;
+
+ p10ns = point2d_div_t(point2d_sub_ts(p1, p0), nsf);
+ p21ns = point2d_div_t(point2d_sub_ts(p2, p1), nsf);
+ p32ns = point2d_div_t(point2d_sub_ts(p3, p2), nsf);
+
+ for (n = 1; n < num_segments; n++) {
+ b0 = b1;
+
+ vector_flt_t nf = (vector_flt_t)n;
+
+ vector_flt_t nt = nf/nsf;
+
+ q0 = point2d_add_ts(p0, point2d_mul_t(p10ns, nf));
+ q1 = point2d_add_ts(p1, point2d_mul_t(p21ns, nf));
+ q2 = point2d_add_ts(p2, point2d_mul_t(p32ns, nf));
+
+ r0 = point2d_add_ts(q0,
+ point2d_mul_t(point2d_sub_ts(q1, q0), nt)
+ );
+ r1 = point2d_add_ts(q1,
+ point2d_mul_t(point2d_sub_ts(q2, q1), nt)
+ );
+
+ b1 = point2d_add_ts(r0,
+ point2d_mul_t(point2d_sub_ts(r1, r0), nt)
+ );
+
+ draw(b0, b1);
+ }
+
+ draw(b1, p3);
+}
+
+void
+bezier_draw_cubic2(
+ h2bez_draw_t draw,
+ uint32_t num_segments,
+ point2d_t p0, point2d_t p1, point2d_t p2, point2d_t p3
+) {
+ uint32_t i;
+
+ /* draw a single point.. */
+ /* TODO use better min-value.. (eg 1 instead of e*100) */
+ if (point2d_dist(p0, p3) < vector_flt_EPSILON*100) {
+ draw(p0, p3);
+ return;
+ }
+ point2d_t ps = p0;
+ for (i = 1; i <= num_segments; ++i) {
+ vector_flt_t t = (vector_flt_t)i / (vector_flt_t)num_segments;
+ vector_flt_t a = vector_flt_pow((1 - t), 3);
+ vector_flt_t b = 3 * t * vector_flt_pow((1 - t), 2);
+ vector_flt_t c = 3 * vector_flt_pow(t, 2) * (1 - t);
+ vector_flt_t d = vector_flt_pow(t, 3);
+
+ point2d_t pe = (point2d_t) {
+ .x = a * p0.x + b * p1.x + c * p2.x + d * p3.x,
+ .y = a * p0.y + b * p1.y + c * p2.y + d * p3.y
+ };
+ draw(ps, pe);
+ ps = pe;
+ }
+}
+
+
+
+
+
+
+/* TBD.. converting and drawing with quadratic bezier */
+/*
+
+typedef void(*h2bez_move_to_t) (point2d_t coordinate);
+typedef void(*h2bez_curve_to_t)(point2d_t control, point2d_t end);
+
+
+void
+h2bez_curve_to_2(point2d_t start, point2d_t control, point2d_t end) {
+ int npts = (b.Length) / 2;
+ int icount, jcount;
+ vector_flt_t step, t;
+
+ // Calculate points on curve
+ icount = 0;
+ t = 0;
+ step = (vector_flt_t)1.0 / (cpts - 1);
+
+ for (int i1 = 0; i1 != cpts; i1++) {
+ if ((1.0 - t) < 5e-6);
+ t = 1.0;
+
+ jcount = 0;
+ p[icount] = 0.0;
+ p[icount + 1] = 0.0;
+ for (int i = 0; i != npts; i++) {
+ vector_flt_t basis = Bernstein(npts - 1, i, t);
+ p[icount] += basis * b[jcount];
+ p[icount + 1] += basis * b[jcount + 1];
+ jcount = jcount +2;
+ }
+
+ icount += 2;
+ t += step;
+ }
+}
+
+
+
+void
+drawBeziers(
+ h2bez_move_to_t move_to_fct,
+ h2bez_curve_to_t curve_to_fct,
+ point2d_t *int_points,
+ uint32_t int_points_length
+) {
+ move_to_fct(int_points[0]);
+ for(uint32_t j = 0; j < (int_points_length - 1)/3; j++) { // FIXME make sure the last point is always drawn..
+ drawBezierMidpoint(curve_to_fct, int_points[3*j],int_points[3*j+1],int_points[3*j+2],int_points[3*j+3]);
+ }
+// for(vector_flt_t j = 0; j < (int_points_length - 1)/3; j++) {
+// drawBezierMidpoint(curve_to_fct, int_points[3*j],int_points[3*j+1],int_points[3*j+2],int_points[3*j+3]);
+// }
+}
+
+// Taken from http://www.timotheegroleau.com/Flash/articles/cubic_bezier_in_flash.htm
+// By Timothee Groleau, with much respect
+
+void
+drawBezierMidpoint(
+ h2bez_curve_to_t curve_to_fct,
+ point2d_t p0, point2d_t p1, point2d_t p2, point2d_t p3
+) {
+ // calculates the useful base points
+ point2d_t PA = getPointOnSegment(p0, p1, 3/4);
+ point2d_t PB = getPointOnSegment(p3, p2, 3/4);
+
+ // get 1/16 of the [p3, p0] segment
+ point2d_t diff_16 = point2d_div_t(point2d_sub_ts(p3,p1),16);
+// var dx:vector_flt_t = (p3.x - p0.x)/16;
+// var dy:vector_flt_t = (p3.y - p0.y)/16;
+
+ // calculates control point 1
+ point2d_t Pc_1 = getPointOnSegment(p0, p1, 3/8);
+
+ // calculates control point 2
+ point2d_t Pc_2 = getPointOnSegment(PA, PB, 3/8);
+ point2d_sub_ts(Pc_2,diff_16);
+// Pc_2.x -= dx;
+// Pc_2.y -= dy;
+
+ // calculates control point 3
+ point2d_t Pc_3 = getPointOnSegment(PB, PA, 3/8);
+ point2d_add_ts(Pc_3,diff_16);
+// Pc_3.x += dx;
+// Pc_3.y += dy;
+
+ // calculates control point 4
+ point2d_t Pc_4 = getPointOnSegment(p3, p2, 3/8);
+
+ // calculates the 3 anchor points
+ point2d_t Pa_1 = getMiddle(Pc_1, Pc_2);
+ point2d_t Pa_2 = getMiddle(PA, PB);
+ point2d_t Pa_3 = getMiddle(Pc_3, Pc_4);
+
+ // draw the four quadratic subsegments
+ curve_to_fct(Pc_1, Pa_1);
+ curve_to_fct(Pc_2, Pa_2);
+ curve_to_fct(Pc_3, Pa_3);
+ curve_to_fct(Pc_4, p3);
+}
+
+
+
+///////////// Cheap h2o hack /////////////////////////////////////////////////////
+
+function
+getBeziers(PointMultiplier:vector_flt_t, int_points:Vector.):Vector. {
+ var points:Vector. = new Vector.();
+ points.push(int_points[0]);
+ for(var j:vector_flt_t = 0; j < (int_points.length - 1)/3; j++) {
+ points = points.concat(getBezierMidpoint(PointMultiplier, int_points[3 * j], int_points[3 * j + 1], int_points[3 * j + 2], int_points[3 * j + 3], points[points_length - 1]));
+ }
+ return points;
+}
+
+
+function
+getBezierMidpoint(PointMultiplier:vector_flt_t, p0:Point, p1:Point, p2:Point, p3:Point, oldp3:Point):Vector. {
+ // calculates the useful base points
+ var PA:Point = getPointOnSegment(p0, p1, 3/4);
+ var PB:Point = getPointOnSegment(p3, p2, 3/4);
+
+ // get 1/16 of the [p3, p0] segment
+ var dx:vector_flt_t = (p3.x - p0.x)/16;
+ var dy:vector_flt_t = (p3.y - p0.y)/16;
+
+ // calculates control point 1
+ var Pc_1:Point = getPointOnSegment(p0, p1, 3/8);
+
+ // calculates control point 2
+ var Pc_2:Point = getPointOnSegment(PA, PB, 3/8);
+ Pc_2.x -= dx;
+ Pc_2.y -= dy;
+
+ // calculates control point 3
+ var Pc_3:Point = getPointOnSegment(PB, PA, 3/8);
+ Pc_3.x += dx;
+ Pc_3.y += dy;
+
+ // calculates control point 4
+ var Pc_4:Point = getPointOnSegment(p3, p2, 3/8);
+
+ // calculates the 3 anchor points
+ var Pa_1:Point = getMiddle(Pc_1, Pc_2);
+ var Pa_2:Point = getMiddle(PA, PB);
+ var Pa_3:Point = getMiddle(Pc_3, Pc_4);
+
+ // draw the four quadratic subsegments
+// mc.curveTo(Pc_1.x, Pc_1.y, Pa_1.x, Pa_1.y);
+// mc.curveTo(Pc_2.x, Pc_2.y, Pa_2.x, Pa_2.y);
+// mc.curveTo(Pc_3.x, Pc_3.y, Pa_3.x, Pa_3.y);
+// mc.curveTo(Pc_4.x, Pc_4.y, p3.x, p3.y);
+
+ var points:Vector. = new Vector.();
+ // maybe needs an odd number, maybe not, what do i know
+ points = points.concat(getMultiQuadBezier(PointMultiplier / 4, oldp3, Pc_1, Pa_1));
+ points = points.concat(getMultiQuadBezier(PointMultiplier / 4, Pa_1, Pc_2, Pa_2));
+ points = points.concat(getMultiQuadBezier(PointMultiplier / 4, Pa_2, Pc_3, Pa_3));
+ points = points.concat(getMultiQuadBezier(PointMultiplier / 4, Pa_3, Pc_4, p3 ));
+
+ oldp3 = p3;
+ return points;
+}
+
+
+function
+getMultiQuadBezier(n:vector_flt_t, p0:Point, p1:Point, p2:Point):Vector. {
+ var td:vector_flt_t = 1 / n;
+ var t0:vector_flt_t = td; // !0, >0
+
+ var point:Vector. = new Vector.();
+ for (var i:int = 0; i < n; i++) {
+ point.push(getQuadBezier(t0, p0, p1, p2));
+ t0 += td;
+ //t0 = Math.round(t0 * 1000) / 1000;
+ }
+ return point;
+}
+
+function
+getQuadBezier(t:vector_flt_t, p0:Point, p1:Point, p2:Point):Point {
+ return new Point(
+ Math.pow(1 - t, 2) * p0.x + 2 * t * (1 - t) * p1.x + Math.pow(t, 2) * p2.x,
+ Math.pow(1 - t, 2) * p0.y + 2 * t * (1 - t) * p1.y + Math.pow(t, 2) * p2.y
+ )
+}
+
+
+function
+getMultiCubicBezier(n:vector_flt_t, p0:Point, p1:Point, p2:Point, p3:Point):Vector. {
+ var td:vector_flt_t = 1 / (n + 1);
+ var t0:vector_flt_t = td / 2;
+
+ var point:Vector. = new Vector.();
+ for (var i:int = 0; i < n; i++) {
+ point.push(getQuadBezier(t0, p0, p1, p2));
+ t0 += td;
+ }
+ return point;
+}
+
+function
+getCubicBezier(t:vector_flt_t, p0:Point, p1:Point, p2:Point, p3:Point):Point {
+ return new Point(
+ (-p0.x + 3*p1.x-3*p2.x+p3.x)*Math.pow(t,3)+(3*p0.x-6*p1.x+3*p2.x)*Math.pow(t,2)+(-3*p0.x+3*p1.x)*t+p0.x,
+ (-p0.y + 3*p1.y-3*p2.y+p3.y)*Math.pow(t,3)+(3*p0.y-6*p1.y+3*p2.y)*Math.pow(t,2)+(-3*p0.y+3*p1.y)*t+p0.y
+ )
+}
+
+
+/// other H2O-functions
+
+function
+getAngleAndDistance(p1:Point, p2:Point):Object {
+ var x:vector_flt_t = p2.x - p1.x;
+ var y:vector_flt_t = p2.y - p1.y;
+
+ var AnD:Object = new Object();
+ AnD.beta = vector_flt_atan2(x, y);
+// AnD.beta = Math.atan(AnD.b / AnD.a);
+// // normalizing angles
+// if (AnD.a < 0) { AnD.beta += Math.PI; } else
+// if (AnD.a > 0 && AnD.b < 0) { AnD.beta += Math.PI * 2; }
+
+ AnD.dist = Math.pow(Math.pow(x, 2) + Math.pow(y, 2), .5);
+
+ return AnD;
+}
+
+
+// doesn't work
+
+function
+removePointsByAngleAndDistance(angle:vector_flt_t, distance:vector_flt_t, p:Vector.):Vector. {
+ if (p.length < 3) { return null; }
+ var np:Vector. = new Vector.();
+ np.push(p[0]);
+ var AnD:Object=getAngleAndDistance(p[0], p[1]);
+ var ang:vector_flt_t = AnD.beta; var dist:vector_flt_t = AnD.dist;
+ for (var i:vector_flt_t = 1; i < p.length; i++) {
+ AnD = getAngleAndDistance(p[i-1], p[i]);
+ dist += AnD.dist;
+ if (vector_flt_abs(ang - AnD.beta) >= angle || dist >= distance) {
+ np.push(p[i]);
+ //dist = AnD.dist; ang = AnD.beta;
+ dist = 0; ang = AnD.beta;
+ }
+ }
+ if (p[i-1] != np[np.length - 1]) { np.push(p[i-1]); }
+ return np;
+}
+
+function
+removePointsByDistance(distance:vector_flt_t, p:Vector.):Vector. {
+ if (p.length < 2) { return null; }
+ var np:Vector. = new Vector.();
+ np.push(p[0]);
+ var dist:vector_flt_t = 0;
+ for (var i:vector_flt_t = 1; i < p.length - 1; i++) {
+ var AnD:Object=getAngleAndDistance(p[i], p[i + 1]);
+ dist += AnD.dist;
+ if (dist >= distance) {
+ np.push(p[i]);
+ dist = 0;
+ }
+ }
+ return np;
+}
+
+function
+useEachNthPoint(n:vector_flt_t, p:Vector.):Vector. {
+ var np:Vector. = new Vector.();
+ for (var i:vector_flt_t = 0; i < p.length; i++) {
+ if (p.length / i == Math.floor(p.length / i)) {
+ np.push(p[i]);
+ }
+ }
+ return np;
+}
+
+//////////////////////////////////////////////////////////
+
+
+
+point2d_t
+getPointOnSegment(point2d_t p0, point2d_t p1, vector_flt_t ratio) {
+ return (point2d_t) { p0.x + ((p1.x - p0.x) * ratio), p0.y + ((p1.y - p0.y) * ratio) };
+}
+
+
+point2d_t
+getMiddle(point2d_t p0, point2d_t p1) {
+ return (point2d_t) { (p0.x + p1.x) / 2, (p0.y + p1.y) / 2 };
+}
+*/
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.h
new file mode 100644
index 00000000..82cb54a8
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/bezier.h
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ */
+
+#ifndef BEZIER_H_
+#define BEZIER_H_
+
+#include "vector_gfx.h"
+
+typedef struct {
+ point2d_t p;
+ vector_flt_t a, b;
+ vector_flt_t beta;
+ vector_flt_t dist;
+} bpoint_t;
+
+static inline
+uint32_t
+bezier_calculate_int_points_length(uint32_t points_length) {
+ return (points_length-2)*3+4;
+}
+
+typedef void(*h2bez_draw_t) (point2d_t p1, point2d_t p2);
+
+/**
+ * Interpolate the points to create a smooth curve
+ * for every point which is not the start or end point
+ * first look at the slope between the next and previous points
+ * Then place the handles at 1/tension the way from the point
+ * in the direction of the slope
+ *
+ * fills int_points array of point2d_t with the length (points_length-2)*3+4
+ * in the form :
+ * [ p_start_end,p_control_1,p_control_2,p_start_end, p_control_1, ... ]
+ *
+ * @param int_points
+ * @param points
+ * @param points_length
+ * @param overshoot
+ * @param tension eg. 3
+ * @return
+ */
+
+void
+bezier_cubic(
+ point2d_t *int_points,
+ point2d_t *points,
+ uint32_t points_length,
+ vector_flt_t overshoot,
+ vector_flt_t tension
+ );
+
+/**
+ * Interpolate the points to create a smooth curve
+ * for every point which is not the start or end point
+ * first look at the slope between the next and previous points
+ * Then place the handles at 1/tension the way from the point in
+ * the direction of the slope
+ *
+ * Given that all the points are roughly equidistant from the next
+ * (saves some computation time)
+ *
+ * fills int_points array of point2d_t with the length
+ * (points_length-2)*3+4 in the form
+ * [ p_start_end,p_control_1,p_control_2,p_start_end, p_control_1, ... ]
+ *
+ * @param int_points buffer with the size of (points_length-2)*3+4 or h2_bezier_calculate_int_points_length
+ * @param points
+ * @param points_length
+ * @param overshoot
+ * @param tension eg. 3
+ * @return
+ */
+
+void
+bezier_cubic_symmetric(
+ point2d_t *int_points,
+ point2d_t *points,
+ uint32_t points_length,
+ vector_flt_t overshoot,
+ vector_flt_t tension
+ );
+
+/* TODO resolution x/y instead of num_segments */
+
+void
+bezier_draw_cubic(
+ h2bez_draw_t draw,
+ uint32_t num_segments,
+ point2d_t p0, point2d_t p1, point2d_t p2, point2d_t p3
+ );
+
+
+void
+bezier_draw_cubic2(
+ h2bez_draw_t draw,
+ uint32_t num_segments,
+ point2d_t p0, point2d_t p1, point2d_t p2, point2d_t p3
+ );
+
+
+#endif /* BEZIER_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.c
new file mode 100644
index 00000000..3b7440b3
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.c
@@ -0,0 +1,402 @@
+/*
+ * drawing.c
+ *
+ * Created on: 30 Jul 2017
+ * Author: h2obrain
+ */
+
+#include "drawing.h"
+#include "../gfx_locm3.h"
+
+/* Xiaolin Wu's line algorithm - Thanks Wikipedia! */
+#define darken_color(c,col) ( \
+ ((uint16_t)vector_flt_round((col&0xf800)*c)&0xf800) \
+ | ((uint16_t)vector_flt_round((col&0x07e0)*c)&0x07e0) \
+ | ((uint16_t)vector_flt_round((col&0x001f)*c)&0x001f) \
+ )
+#define plot(x,y,c,col) gfx_draw_pixel(x,y,darken_color(c,col));
+#define fpart(x) vector_flt_mod(x,NULL)
+#define rfpart(x) (1-fpart(x))
+
+void draw_antialised_line(segment2d_t s, uint16_t col) {
+ bool steep = vector_flt_abs(s.p2.y - s.p1.y) > vector_flt_abs(s.p2.x - s.p1.x);
+
+ if (steep) {
+ vector_flt_swap(s.p1.x, s.p1.y);
+ vector_flt_swap(s.p2.x, s.p2.y);
+ }
+ if (s.p1.x > s.p2.x) {
+ vector_flt_swap(s.p1.x, s.p2.x);
+ vector_flt_swap(s.p1.y, s.p2.y);
+ }
+
+ point2d_t d = point2d_sub_ts(s.p2,s.p1);
+ vector_flt_t gradient = d.y / d.x;
+ if (d.x == 0) {
+ gradient = 1;
+ }
+
+ // handle first endpoint
+ vector_flt_t xend = vector_flt_round(s.p1.x);
+ vector_flt_t yend = s.p1.y + gradient * (xend - s.p1.x);
+ vector_flt_t xgap = rfpart(s.p1.x + 0.5);
+ int16_t xpxl1 = xend; // this will be used in the main loop
+ int16_t ypxl1 = vector_flt_floor(yend);
+ if (steep) {
+ plot(ypxl1, xpxl1, rfpart(yend) * xgap, col);
+ plot(ypxl1+1, xpxl1, fpart(yend) * xgap, col);
+ } else {
+ plot(xpxl1, ypxl1 , rfpart(yend) * xgap, col);
+ plot(xpxl1, ypxl1+1, fpart(yend) * xgap, col);
+ }
+ vector_flt_t intery = yend + gradient; // first y-intersection for the main loop
+
+ // handle second endpoint
+ xend = vector_flt_round(s.p2.x);
+ yend = s.p2.y + gradient * (xend - s.p2.x);
+ xgap = fpart(s.p2.x + 0.5);
+ int16_t xpxl2 = xend; //this will be used in the main loop
+ int16_t ypxl2 = vector_flt_floor(yend);
+ if (steep) {
+ plot(ypxl2 , xpxl2, rfpart(yend) * xgap, col);
+ plot(ypxl2+1, xpxl2, fpart(yend) * xgap, col);
+ } else {
+ plot(xpxl2, ypxl2, rfpart(yend) * xgap, col);
+ plot(xpxl2, ypxl2+1, fpart(yend) * xgap, col);
+ }
+
+ // main loop
+ if (steep) {
+ for (int16_t x = xpxl1 + 1; x < xpxl2; x++) {
+ plot(vector_flt_floor(intery) , x, rfpart(intery), col);
+ plot(vector_flt_floor(intery)+1, x, fpart(intery), col);
+ intery = intery + gradient;
+ }
+ } else {
+ for (int16_t x = xpxl1 + 1; x < xpxl2; x++) {
+ plot(x, vector_flt_floor(intery), rfpart(intery), col);
+ plot(x, vector_flt_floor(intery)+1, fpart(intery), col);
+ intery = intery + gradient;
+ }
+ }
+}
+
+#undef darken_color
+#undef plot
+#undef fpart
+#undef rfpart
+
+
+
+/* code borrowed from http://kt8216.unixcab.org/murphy/index.html (thick.c) */
+
+/***********************************************************************
+ * *
+ * X BASED LINES *
+ * *
+ ***********************************************************************/
+
+static
+void x_perpendicular(
+ uint16_t color,
+ int16_t x0,int16_t y0,int16_t dx,int16_t dy,int16_t xstep, int16_t ystep,
+ int16_t einit,int16_t w_left, int16_t w_right,int16_t winit
+) {
+ int16_t x,y,threshold,E_diag,E_square;
+ int16_t tk;
+ int16_t error;
+ int16_t p,q;
+
+ threshold = dx - 2*dy;
+ E_diag= -2*dx;
+ E_square= 2*dy;
+ p=q=0;
+
+ y= y0;
+ x= x0;
+ error= einit;
+ tk= dx+dy-winit;
+
+ while(tk<=w_left)
+ {
+ gfx_draw_pixel(x,y, color);
+ if (error>=threshold)
+ {
+ x= x + xstep;
+ error = error + E_diag;
+ tk= tk + 2*dy;
+ }
+ error = error + E_square;
+ y= y + ystep;
+ tk= tk + 2*dx;
+ q++;
+ }
+
+ y= y0;
+ x= x0;
+ error= -einit;
+ tk= dx+dy+winit;
+
+ while(tk<=w_right)
+ {
+ if (p)
+ gfx_draw_pixel(x,y, color);
+ if (error>threshold)
+ {
+ x= x - xstep;
+ error = error + E_diag;
+ tk= tk + 2*dy;
+ }
+ error = error + E_square;
+ y= y - ystep;
+ tk= tk + 2*dx;
+ p++;
+ }
+
+ if (q==0 && p<2) gfx_draw_pixel(x0,y0,color); // we need this for very thin lines
+}
+
+
+static
+void x_varthick_line(
+ uint16_t color,
+ int16_t x0,int16_t y0,int16_t dx,int16_t dy,int16_t xstep, int16_t ystep,
+ drawing_varthick_fct_t left, void *argL,
+ drawing_varthick_fct_t right,void *argR, int16_t pxstep,int16_t pystep
+) {
+ int16_t p_error, error, x,y, threshold, E_diag, E_square, length, p;
+ int16_t w_left, w_right;
+ vector_flt_t D;
+
+
+ p_error= 0;
+ error= 0;
+ y= y0;
+ x= x0;
+ threshold = dx - 2*dy;
+ E_diag= -2*dx;
+ E_square= 2*dy;
+ length = dx+1;
+ D= vector_flt_sqrt(dx*dx+dy*dy);
+
+ for(p=0;p=threshold)
+ {
+ y= y + ystep;
+ error = error + E_diag;
+ if (p_error>=threshold)
+ {
+ x_perpendicular(color,x,y, dx, dy, pxstep, pystep,
+ (p_error+E_diag+E_square),
+ w_left,w_right,error);
+ p_error= p_error + E_diag;
+ }
+ p_error= p_error + E_square;
+ }
+ error = error + E_square;
+ x= x + xstep;
+ }
+}
+
+/***********************************************************************
+ * *
+ * Y BASED LINES *
+ * *
+ ***********************************************************************/
+
+static
+void y_perpendicular(
+ uint16_t color,
+ int16_t x0,int16_t y0,int16_t dx,int16_t dy,int16_t xstep, int16_t ystep,
+ int16_t einit,int16_t w_left, int16_t w_right,int16_t winit
+) {
+ int16_t x,y,threshold,E_diag,E_square;
+ int16_t tk;
+ int16_t error;
+ int16_t p,q;
+
+ p=q= 0;
+ threshold = dy - 2*dx;
+ E_diag= -2*dy;
+ E_square= 2*dx;
+
+ y= y0;
+ x= x0;
+ error= -einit;
+ tk= dx+dy+winit;
+
+ while(tk<=w_left)
+ {
+ gfx_draw_pixel(x,y, color);
+ if (error>threshold)
+ {
+ y= y + ystep;
+ error = error + E_diag;
+ tk= tk + 2*dx;
+ }
+ error = error + E_square;
+ x = x + xstep;
+ tk = tk + 2*dy;
+ q++;
+ }
+
+
+ y= y0;
+ x= x0;
+ error= einit;
+ tk= dx+dy-winit;
+
+ while(tk<=w_right)
+ {
+ if (p)
+ gfx_draw_pixel(x,y, color);
+ if (error>=threshold)
+ {
+ y= y - ystep;
+ error = error + E_diag;
+ tk= tk + 2*dx;
+ }
+ error = error + E_square;
+ x= x - xstep;
+ tk= tk + 2*dy;
+ p++;
+ }
+
+ if (q==0 && p<2) gfx_draw_pixel(x0,y0,color); // we need this for very thin lines
+}
+
+
+static
+void y_varthick_line(
+ uint16_t color,
+ int16_t x0,int16_t y0,int16_t dx,int16_t dy,int16_t xstep, int16_t ystep,
+ drawing_varthick_fct_t left, void *argL,
+ drawing_varthick_fct_t right,void *argR,int16_t pxstep,int16_t pystep
+) {
+ int16_t p_error, error, x,y, threshold, E_diag, E_square, length, p;
+ int16_t w_left, w_right;
+ vector_flt_t D;
+
+ p_error= 0;
+ error= 0;
+ y= y0;
+ x= x0;
+ threshold = dy - 2*dx;
+ E_diag= -2*dy;
+ E_square= 2*dx;
+ length = dy+1;
+ D = vector_flt_sqrt(dx*dx+dy*dy);
+
+ for(p=0;p=threshold)
+ {
+ x += xstep;
+ error += E_diag;
+ if (p_error>=threshold)
+ {
+ y_perpendicular(color,x,y, dx, dy, pxstep, pystep,
+ p_error+E_diag+E_square,
+ w_left,w_right,error);
+ p_error= p_error + E_diag;
+ }
+ p_error= p_error + E_square;
+ }
+ error += E_square;
+ y += ystep;
+ }
+}
+
+
+/***********************************************************************
+ * *
+ * ENTRY *
+ * *
+ ***********************************************************************/
+
+void draw_varthick_line(
+ int16_t x0,int16_t y0,int16_t x1, int16_t y1,
+ drawing_varthick_fct_t left, void *argL,
+ drawing_varthick_fct_t right, void *argR,
+ uint16_t color
+) {
+ int16_t dx,dy,xstep,ystep;
+ int16_t pxstep=0, pystep=0;
+ int16_t xch; // whether left and right get switched.
+
+ dx= x1-x0;
+ dy= y1-y0;
+ xstep= ystep= 1;
+
+ if (dx<0) { dx= -dx; xstep= -1; }
+ if (dy<0) { dy= -dy; ystep= -1; }
+
+ if (dx==0) xstep= 0;
+ if (dy==0) ystep= 0;
+
+ // TODO FIX THIS CASE!!!
+ if ((dx==0)&&(dy==0)) return;
+
+ xch= 0;
+ switch(xstep + ystep*4)
+ {
+ case -1 + -1*4 : pystep= -1; pxstep= 1; xch= 1; break; // -5
+ case -1 + 0*4 : pystep= -1; pxstep= 0; xch= 1; break; // -1
+ case -1 + 1*4 : pystep= 1; pxstep= 1; break; // 3
+ case 0 + -1*4 : pystep= 0; pxstep= -1; break; // -4
+ case 0 + 0*4 : pystep= 0; pxstep= 0; break; // 0
+ case 0 + 1*4 : pystep= 0; pxstep= 1; break; // 4
+ case 1 + -1*4 : pystep= -1; pxstep= -1; break; // -3
+ case 1 + 0*4 : pystep= -1; pxstep= 0; break; // 1
+ case 1 + 1*4 : pystep= 1; pxstep= -1; xch=1; break; // 5
+ }
+
+ if (xch) {
+ void *K;
+ K= argL; argL= argR; argR= K;
+ K= left; left= right; right= K;
+ }
+
+ if (dx>dy) {
+ x_varthick_line(
+ color,x0,y0,dx,dy,xstep,ystep,
+ left,argL,right,argR,
+ pxstep,pystep
+ );
+ } else {
+ y_varthick_line(
+ color,x0,y0,dx,dy,xstep,ystep,
+ left,argL,right,argR,
+ pxstep,pystep
+ );
+ }
+}
+static vector_flt_t const_thickness(vector_flt_t *arg, int16_t P, int16_t length) {
+ (void)P;(void)length;
+ return *arg;
+}
+void draw_thick_line(
+ int16_t x0,int16_t y0,int16_t x1, int16_t y1,
+ vector_flt_t thickness,
+ uint16_t color
+) {
+ thickness /= 2;
+ draw_varthick_line(
+ x0,y0,x1,y1,
+ (drawing_varthick_fct_t )const_thickness,&thickness,
+ (drawing_varthick_fct_t )const_thickness,&thickness,
+ color
+ );
+}
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.h
new file mode 100644
index 00000000..d579dcca
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/drawing.h
@@ -0,0 +1,28 @@
+/*
+ * drawing.h
+ *
+ * Created on: 29 Jul 2017
+ * Author: h2obrain
+ */
+
+#ifndef VECTOR_GFX_DRAWING_H_
+#define VECTOR_GFX_DRAWING_H_
+
+#include "vector_gfx.h"
+
+void draw_antialised_line(segment2d_t s, uint16_t col);
+
+
+void draw_thick_line(
+ int16_t x0,int16_t y0,int16_t x1, int16_t y1,
+ vector_flt_t thickness,
+ uint16_t color
+ );
+typedef vector_flt_t (*drawing_varthick_fct_t)(void *, int16_t, int16_t);
+void draw_varthick_line(
+ int16_t x0,int16_t y0,int16_t x1, int16_t y1,
+ drawing_varthick_fct_t left, void *argL,
+ drawing_varthick_fct_t right, void *argR,
+ uint16_t color
+ );
+#endif /* VECTOR_GFX_DRAWING_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/matrix.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/matrix.h
new file mode 100644
index 00000000..2d07b40a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/matrix.h
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ *
+ * Warning, those functions are probably not correct!
+ *
+ */
+
+#ifndef MATRIX_H_
+#define MATRIX_H_
+
+#include "vector_gfx.h"
+
+typedef struct {
+ vector_flt_t a, b, c;
+ vector_flt_t p, q, r;
+ vector_flt_t u, v, w;
+} mat3x3_t;
+static inline
+mat3x3_t
+mat3x3_empty(void) {
+ return (mat3x3_t) {
+ .a = 1, .b = 0, .c = 0,
+ .p = 0, .q = 1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_translate(vector_flt_t x, vector_flt_t y) {
+ return (mat3x3_t) {
+ .a = 1, .b = 0, .c = x,
+ .p = 0, .q = 1, .r = y,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_scale(vector_flt_t w, vector_flt_t h) {
+ return (mat3x3_t) {
+ .a = w, .b = 0, .c = 0,
+ .p = 0, .q = h, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_rotate(vector_flt_t angle) {
+ vector_flt_t s, c;
+ s = vector_flt_sin(angle);
+ c = vector_flt_cos(angle);
+ return (mat3x3_t) {
+ .a = c, .b = s, .c = 0,
+ .p = -s, .q = c, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_shear_x(vector_flt_t angle) {
+ return (mat3x3_t) {
+ .a = 1, .b = vector_flt_tan(angle), .c = 0,
+ .p = 0, .q = 1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_shear_y(vector_flt_t angle) {
+ return (mat3x3_t) {
+ .a = 1, .b = 0, .c = 0,
+ .p = vector_flt_tan(angle), .q = 1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_reflect_xy(void) {
+ return (mat3x3_t) {
+ .a = -1, .b = 0, .c = 0,
+ .p = 0, .q = -1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_reflect_x(void) {
+ return (mat3x3_t) {
+ .a = 1, .b = 0, .c = 0,
+ .p = 0, .q = -1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+static inline
+mat3x3_t
+mat3x3_reflect_y(void) {
+ return (mat3x3_t) {
+ .a = -1, .b = 0, .c = 0,
+ .p = 0, .q = 1, .r = 0,
+ .u = 0, .v = 0, .w = 1
+ };
+}
+
+static inline
+mat3x3_t
+mat3x3_mult(mat3x3_t A, mat3x3_t B) {
+ return (mat3x3_t) {
+ .a = A.a*B.a+A.b*B.p+A.c*B.u,
+ .b = A.a*B.b+A.b*B.q+A.c*B.v,
+ .c = A.a*B.c+A.b*B.r+A.c*B.w,
+
+ .p = A.p*B.a+A.q*B.p+A.r*B.u,
+ .q = A.p*B.b+A.q*B.q+A.r*B.v,
+ .r = A.p*B.c+A.q*B.r+A.r*B.w,
+
+ .u = A.u*B.a+A.v*B.p+A.w*B.u,
+ .v = A.u*B.b+A.v*B.q+A.w*B.v,
+ .w = A.u*B.c+A.v*B.r+A.w*B.w
+ };
+}
+
+static inline
+void
+mat3x3_affine_transform(
+ mat3x3_t mat,
+ point2d_t *points_dest, point2d_t *points_src,
+ size_t points_count
+) {
+ while (points_count--) {
+ /* Copy the source point, this allows for src and dest to be
+ * the same array
+ */
+ point2d_t p = *points_src++;
+
+ points_dest->x = mat.a * p.x + mat.b * p.y + mat.c; /* p.z; */
+ points_dest->y = mat.p * p.x + mat.q * p.y + mat.r; /* p.z; */
+ /* points->z = mat.u * p.x + mat.v * p.y + mat.w * p.z; */
+ points_dest++;
+ }
+}
+
+
+#endif /* MATRIX_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector.h
new file mode 100644
index 00000000..b62ebd00
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector.h
@@ -0,0 +1,342 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ *
+ * My old actionscript-library from 2004
+ *
+ * :) http://softsurfer.com/
+ * ? http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm#Distance%20between%20Lines
+ * ?? http://stochastix.wordpress.com/2008/12/28/distance-between-two-lines/
+ * ??? http://www.mc.edu/campus/users/travis/maa/proceedings/spring2001/bard.himel.pdf
+ * http://stackoverflow.com/questions/217578/point-in-polygon-aka-hit-test
+ * http://local.wasp.uwa.edu.au/~pbourke/geometry
+ * http://steve.hollasch.net/cgindex/math/fowler.html
+ */
+
+#ifndef VECTOR_H_
+#define VECTOR_H_
+
+
+#include "vector_gfx.h"
+
+typedef struct {
+ vector_flt_t x, y;
+} point2d_t;
+typedef struct {
+ point2d_t p1, p2;
+} segment2d_t;
+typedef struct {
+ vector_flt_t distance;
+ point2d_t nearest_point;
+} intersection_t;
+
+
+static inline
+point2d_t
+point2d_add_ts(point2d_t p1, point2d_t p2) {
+ return (point2d_t) {p1.x + p2.x, p1.y + p2.y};
+}
+static inline
+point2d_t
+point2d_sub_ts(point2d_t p1, point2d_t p2) {
+ return (point2d_t) {p1.x - p2.x, p1.y - p2.y};
+}
+static inline
+point2d_t
+point2d_mul_ts(point2d_t p1, point2d_t p2) {
+ return (point2d_t) {p1.x * p2.x, p1.y * p2.y};
+}
+static inline
+point2d_t
+point2d_mul_t(point2d_t p, vector_flt_t mul) {
+ return (point2d_t) {mul * p.x, mul * p.y};
+}
+static inline
+point2d_t
+point2d_div_t(point2d_t p, vector_flt_t div) {
+ return (point2d_t) {p.x / div, p.y / div};
+}
+static inline
+vector_flt_t
+point2d_cross(point2d_t p1, point2d_t p2) {
+ return p1.x * p2.y - p1.y * p2.x;
+}
+static inline
+vector_flt_t
+point2d_dot(point2d_t u, point2d_t v) {
+ point2d_t p = point2d_mul_ts(u, v);
+ return p.x + p.y;
+}
+/* norm = length of vector */
+static inline
+vector_flt_t
+point2d_norm(point2d_t v) {
+ return vector_flt_sqrt(point2d_dot(v, v));
+}
+static inline
+point2d_t
+point2d_unit(point2d_t v) {
+ vector_flt_t norm = point2d_norm(v);
+ if (norm != 0) {
+ return point2d_div_t(v, norm);
+ } else {
+ return (point2d_t) {0, 0};
+ }
+}
+static inline
+vector_flt_t
+point2d_dist(point2d_t u, point2d_t v) {
+ return point2d_norm(point2d_sub_ts(u, v));
+}
+static inline
+point2d_t
+point2d_normalize(point2d_t v) {
+ vector_flt_t norm = point2d_norm(v);
+ if (norm <= vector_flt_EPSILON) return (point2d_t){0,0};
+ return point2d_div_t(v, norm);
+}
+static inline
+bool
+point2d_compare(point2d_t p1, point2d_t p2, float resolution) {
+ point2d_t dist = point2d_sub_ts(p1, p2);
+ return (vector_flt_abs(dist.x) < resolution)
+ && (vector_flt_abs(dist.y) < resolution);
+}
+static inline
+point2d_t
+point2d_abs(point2d_t p) {
+ return (point2d_t) {vector_flt_abs(p.x), vector_flt_abs(p.y)};
+}
+
+
+
+static inline
+vector_flt_t
+dist_point_to_line(point2d_t p, segment2d_t s) {
+ point2d_t v = point2d_sub_ts(s.p2, s.p1);
+ point2d_t w = point2d_sub_ts(p , s.p1);
+
+ vector_flt_t c1 = point2d_dot(w, v);
+ vector_flt_t c2 = point2d_dot(v, v);
+ vector_flt_t b = c1 / c2;
+
+ point2d_t pb = point2d_add_ts(s.p1, point2d_mul_t(v, b));
+ return point2d_dist(p, pb);
+}
+static inline
+vector_flt_t
+dist_point_to_segment(point2d_t p, segment2d_t s) {
+ point2d_t n = point2d_sub_ts(s.p2, s.p1);
+ point2d_t pa = point2d_sub_ts(s.p1, p);
+
+ vector_flt_t c = point2d_dot(n, pa);
+
+ // Closest point is a
+ if ( c > 0.0f )
+ return point2d_dot(pa, pa);
+
+ point2d_t bp = point2d_sub_ts(p, s.p2);
+
+ // Closest point is b
+ if ( point2d_dot( n, bp ) > 0.0f )
+ return point2d_dot( bp, bp );
+
+ // Closest point is between a and b
+ point2d_t e = point2d_sub_ts(pa, point2d_mul_t(n, c / point2d_dot( n, n )));
+
+ return point2d_norm(e);
+}
+static inline
+vector_flt_t
+dist_line_to_line(segment2d_t l1, segment2d_t l2) {
+ point2d_t u = point2d_sub_ts(l1.p2, l1.p1);
+ point2d_t v = point2d_sub_ts(l2.p2, l2.p1);
+ point2d_t w = point2d_sub_ts(l1.p1, l2.p1);
+ vector_flt_t a = point2d_dot(u, u); /* always >= 0 */
+ vector_flt_t b = point2d_dot(u, v);
+ vector_flt_t c = point2d_dot(v, v); /* always >= 0 */
+ vector_flt_t d = point2d_dot(u, w);
+ vector_flt_t e = point2d_dot(v, w);
+ vector_flt_t D = a*c - b*b; /* always >= 0 */
+ vector_flt_t sc, tc;
+
+ /* compute the line parameters of the two closest points */
+ if (D < vector_flt_MIN_VALUE) { /* the lines are almost parallel */
+ sc = 0.0;
+ /* use the largest denominator */
+ tc = (b > c ? d/b : e/c);
+ } else {
+ sc = (b*e - c*d) / D;
+ tc = (a*e - b*d) / D;
+ }
+
+ /* get the difference of the two closest points */
+ point2d_t dP =
+ point2d_add_ts(w,
+ point2d_sub_ts(
+ point2d_mul_t(u, sc),
+ point2d_mul_t(v, tc)
+ )
+ ); /* = L1(sc) - L2(tc) */
+ vector_flt_t ndP = point2d_norm(dP);
+
+ return ndP;
+}
+static inline
+intersection_t
+dist_segment_to_segment(segment2d_t s1, segment2d_t s2) {
+ point2d_t u = point2d_sub_ts(s1.p2, s1.p1);
+ point2d_t v = point2d_sub_ts(s2.p2, s2.p1);
+ point2d_t w = point2d_sub_ts(s1.p1, s2.p1);
+ vector_flt_t a = point2d_dot(u, u); /* always >= 0 */
+ vector_flt_t b = point2d_dot(u, v);
+ vector_flt_t c = point2d_dot(v, v); /* always >= 0 */
+ vector_flt_t d = point2d_dot(u, w);
+ vector_flt_t e = point2d_dot(v, w);
+ vector_flt_t D = a*c - b*b; /* always >= 0 */
+ vector_flt_t sc, sN, sD = D; /* sc = sN / sD, default sD = D >= 0 */
+ vector_flt_t tc, tN, tD = D; /* tc = tN / tD, default tD = D >= 0 */
+
+ /* compute the line parameters of the two closest points */
+ if (D < vector_flt_MIN_VALUE) { /* the lines are almost parallel */
+ sN = 0.0; /* force using point P0 on segment S1 */
+ sD = 1.0; /* to prevent possible division by 0.0 later */
+ tN = e;
+ tD = c;
+ } else { /* get the closest points on the infinite lines */
+ sN = (b*e - c*d);
+ tN = (a*e - b*d);
+ if (sN < 0.0) { /* sc < 0 => the s=0 edge is visible */
+ sN = 0.0;
+ tN = e;
+ tD = c;
+ } else
+ if (sN > sD) { /* sc > 1 => the s=1 edge is visible */
+ sN = sD;
+ tN = e + b;
+ tD = c;
+ }
+ }
+
+ if (tN < 0.0) { /* tc < 0 => the t=0 edge is visible */
+ tN = 0.0;
+ /* recompute sc for this edge */
+ if (-d < 0.0) {
+ sN = 0.0;
+ } else
+ if (-d > a) {
+ sN = sD;
+ } else {
+ sN = -d;
+ sD = a;
+ }
+ } else
+ if (tN > tD) { /* tc > 1 => the t=1 edge is visible */
+ tN = tD;
+ /* recompute sc for this edge */
+ if ((-d + b) < 0.0) {
+ sN = 0;
+ } else
+ if ((-d + b) > a) {
+ sN = sD;
+ } else {
+ sN = (-d + b);
+ sD = a;
+ }
+ }
+ /* finally do the division to get sc and tc */
+ if (vector_flt_abs(sN) < vector_flt_MIN_VALUE) {
+ sc = 0;
+ } else {
+ sc = sN / sD;
+ }
+ if (vector_flt_abs(tN) < vector_flt_MIN_VALUE) {
+ tc = 0;
+ } else {
+ tc = tN / tD;
+ }
+
+ /* get the difference of the two closest points */
+ point2d_t scU = point2d_mul_t(u, sc);
+ point2d_t tcV = point2d_mul_t(v, tc);
+ point2d_t dP = point2d_sub_ts(point2d_add_ts(w, scU), tcV);
+ vector_flt_t ndP = point2d_norm(dP);
+
+
+ /* lines are parallel? */
+ if (ndP < vector_flt_MIN_VALUE) {
+ ndP = 0.0;
+ }
+
+ return (intersection_t) {
+ .distance = ndP,
+ .nearest_point = point2d_add_ts(s1.p1, scU)
+ };
+}
+
+/*
+ * Fowler angles can be used to COMPARE angles between points fast
+ *
+This function is due to Rob Fowler. Given dy and dx between 2 points
+p1 and p2, we calculate a number in [0.0, 8.0) which is a monotonic
+function of the direction from A to B.
+
+(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0) correspond to
+( 0, 45, 90, 135, 180, 225, 270, 315, 360) degrees, measured
+counter-clockwise from the positive x axis.
+*/
+static inline
+vector_flt_t
+fowler_angle(point2d_t p1, point2d_t p2) {
+ point2d_t d = point2d_sub_ts(p2, p1);
+ point2d_t dabs = point2d_abs(d);
+
+ int code; /* Angular Region Classification Code */
+
+ code = (dabs.x < dabs.y) ? 1 : 0;
+ if (d.x < 0) {
+ code += 2;
+ }
+ if (d.y < 0) {
+ code += 4;
+ }
+
+ switch (code) {
+ case 0:
+ return (d.x == 0) ? 0 : dabs.y/dabs.x; /* [ 0, 45] */
+ case 1:
+ return (vector_flt_t)2 - (dabs.x/dabs.y); /* ( 45, 90] */
+ case 3:
+ return (vector_flt_t)2 + (dabs.x/dabs.y); /* ( 90,135) */
+ case 2:
+ return (vector_flt_t)4 - (dabs.y/dabs.x); /* [135,180] */
+ case 6:
+ return (vector_flt_t)4 + (dabs.y/dabs.x); /* (180,225] */
+ case 7:
+ return (vector_flt_t)6 - (dabs.x/dabs.y); /* (225,270) */
+ case 5:
+ return (vector_flt_t)6 + (dabs.x/dabs.y); /* [270,315) */
+ case 4:
+ return (vector_flt_t)8 - (dabs.y/dabs.x); /* [315,360) */
+
+ default:
+ return -1; /* hardcore fail */
+ }
+}
+
+#endif /* VECTOR_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector_gfx.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector_gfx.h
new file mode 100644
index 00000000..bdf144b7
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch-game/vector_gfx/vector_gfx.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ */
+
+#ifndef VECTOR_GFX_H_
+#define VECTOR_GFX_H_
+
+#include
+#include
+#include
+#include
+#include
+
+#define vector_flt_t float
+#define vector_flt_MIN FLT_MIN
+#define vector_flt_MAX FLT_MAX
+#define vector_flt_EPSILON FLT_EPSILON
+#define vector_flt_MIN_VALUE 0.00000001
+#define vector_flt_abs fabsf
+#define vector_flt_sqrt sqrtf
+#define vector_flt_pow powf
+#define vector_flt_sin sinf
+#define vector_flt_cos cosf
+#define vector_flt_tan tanf
+#define vector_flt_atan2 atan2f
+#define vector_flt_min fminf
+#define vector_flt_max fmaxf
+#define vector_flt_round roundf
+#define vector_flt_floor floorf
+#define vector_flt_ceil ceilf
+#define vector_flt_mod modf
+#define vector_flt_swap(a,b) { vector_flt_t t = a; a = b; b = t; }
+
+#include "vector.h"
+#include "matrix.h"
+#include "bezier.h"
+#include "drawing.h"
+
+#endif /* VECTOR_GFX_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/Makefile b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/Makefile
new file mode 100644
index 00000000..77b3de4f
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/Makefile
@@ -0,0 +1,15 @@
+OBJS = clock.o gfx_locm3.o lcd_ili9341.o sdram.o
+OBJS += fonts/Tamsyn5x9b_9.o fonts/Tamsyn5x9r_9.o
+OBJS += vector_gfx/bezier.o
+OBJS += i2c.o touchscreen_controller_stmpe811.o
+
+BINARY = application
+
+CFLAGS = -O3 -g
+
+# we use sin/cos from the library
+LDLIBS = -lm
+
+LDSCRIPT = ../stm32f429i-discovery.ld
+
+include ../../Makefile.include
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/README.md b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/README.md
new file mode 100644
index 00000000..a881fd90
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/README.md
@@ -0,0 +1,7 @@
+# README
+
+Small test with minimal graphics lib for ltdc graphics controller.
+
+Two additional python scripts are provided to create your own font and bitmap header files.
+
+06/01/16 H2OBrain
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application.c
new file mode 100644
index 00000000..40b5190d
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application.c
@@ -0,0 +1,987 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "clock.h"
+#include "sdram.h"
+#include "lcd_ili9341.h"
+
+#include "touchscreen_controller_stmpe811.h"
+#include "fonts/Tamsyn5x9r_9.h"
+#include "fonts/Tamsyn5x9b_9.h"
+#include "vector_gfx/vector_gfx.h"
+#include "application_balls.h"
+
+
+/* Blue button interrupt */
+typedef enum {
+ DEMO_MODE_ALL,
+ DEMO_MODE_FLOODFILL4,
+ DEMO_MODE_BEZIER,
+ DEMO_MODE_BEZIER_INTERACTIVE,
+ DEMO_MODE_BALLS,
+} demo_mode_t;
+demo_mode_t new_demo_mode = DEMO_MODE_ALL;
+
+static void next_demo(void) {
+ if (new_demo_mode==DEMO_MODE_BALLS) new_demo_mode = 0;
+ else new_demo_mode++;
+}
+static void previous_demo(void) {
+ if (new_demo_mode==0) new_demo_mode = DEMO_MODE_BALLS;
+ else new_demo_mode--;
+}
+
+
+/**
+ * Update touchscreen input
+ */
+typedef enum {
+ TS_TOUCHED,
+ TS_DRAGGING,
+ TS_DRAGGED,
+ TS_NONE,
+} touchscreen_action_t;
+static
+point2d_t
+touch_data_to_coordinate(stmpe811_touch_t touch_data)
+{
+ point2d_t p = (point2d_t){
+ .x = (vector_flt_t)(touch_data.x-STMPE811_X_MIN)/(STMPE811_X_MAX-STMPE811_X_MIN),
+ .y = (vector_flt_t)(touch_data.y-STMPE811_Y_MIN)/(STMPE811_Y_MAX-STMPE811_Y_MIN)
+ };
+ switch (gfx_get_rotation()) {
+ case GFX_ROTATION_0_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*(1.0f-p.x), .y = gfx_height()* p.y };
+ break;
+ case GFX_ROTATION_180_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.x , .y = gfx_height()*(1.0f-p.y) };
+ break;
+ case GFX_ROTATION_90_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*(1.0f-p.y), .y = gfx_height()*(1.0f-p.x) };
+ break;
+ case GFX_ROTATION_270_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.y , .y = gfx_height()* p.x };
+ break;
+ }
+ return p;
+}
+static
+point2d_t
+drag_data_to_coordinate(stmpe811_drag_data_t drag_data)
+{
+ point2d_t p = (point2d_t){
+ .x = (vector_flt_t)drag_data.dx/(STMPE811_X_MAX-STMPE811_X_MIN),
+ .y = (vector_flt_t)drag_data.dy/(STMPE811_Y_MAX-STMPE811_Y_MIN)
+ };
+ switch (gfx_get_rotation()) {
+ case GFX_ROTATION_0_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*( -p.x), .y = gfx_height()*( p.y) };
+ break;
+ case GFX_ROTATION_180_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.x , .y = gfx_height()* -p.y };
+ break;
+ case GFX_ROTATION_90_DEGREES :
+ p = (point2d_t){ .x = gfx_width()*( -p.y), .y = gfx_height()* -p.x };
+ break;
+ case GFX_ROTATION_270_DEGREES :
+ p = (point2d_t){ .x = gfx_width()* p.y , .y = gfx_height()*( p.x) };
+ break;
+ }
+ return p;
+}
+static
+touchscreen_action_t
+update_touchscreen_data(point2d_t *touch_point, point2d_t *drag_distance)
+{
+ stmpe811_touch_t touch_data = stmpe811_get_touch_data();
+ if (touch_data.touched == 1) {
+ *touch_point = touch_data_to_coordinate(touch_data);
+ return TS_TOUCHED;
+ } else {
+ stmpe811_drag_data_t drag_data = stmpe811_get_drag_data();
+ if (drag_data.data_is_valid) {
+ *drag_distance = drag_data_to_coordinate(drag_data);
+ return TS_DRAGGING;
+ } else {
+ /* stop drag*/
+ return TS_DRAGGED;
+ }
+ }
+ return TS_NONE;
+}
+
+
+static
+void
+print_touchscreen_data(
+ int16_t x, int16_t y, uint16_t color,
+ touchscreen_action_t ts_action,
+ point2d_t touch_point, point2d_t drag_distance
+) {
+ char conv_buf[1024];
+
+ //const char *state;
+ //switch (stmpe811.current_touch_state) {
+ //case STMPE811_TOUCH_STATE__UNTOUCHED:
+ //state = "untouched";
+ //break;
+ //case STMPE811_TOUCH_STATE__TOUCHED:
+ //state = "touched";
+ //break;
+ //case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ //state = "touched waiting";
+ //break;
+ //default:
+ //state = "invalid";
+ //break;
+ //}
+
+ static char *action = "none";
+ switch (ts_action) {
+ case TS_TOUCHED:
+ action = "touched";
+ break;
+ case TS_DRAGGING:
+ action = "dragging";
+ break;
+ case TS_DRAGGED:
+ action = "dragged";
+ break;
+ case TS_NONE:
+ break;
+ }
+
+ sprintf(conv_buf,
+ "action : %s\n"
+ "touch : %5.1f % 5.1f\n"
+ "drag : %+5.1f %+5.1f\n"
+ "ints : %lu\n"
+ "count : %lu",
+ action,
+ (double)touch_point.x, (double)touch_point.y,
+ (double)drag_distance.x, (double)drag_distance.y,
+ stmpe811.touch_interrupts,
+ stmpe811.last_values_count
+ );
+
+ gfx_puts2(x, y, conv_buf, &font_Tamsyn5x9r_9, color);
+}
+
+
+/**
+ * Interrupts
+ */
+
+/* Display SPI interrupt */
+void spi5_isr()
+{
+ if (ILI9341_SPI_IS_SELECTED()) {
+ ili9341_spi5_isr();
+ } else {
+ spi_disable_tx_buffer_empty_interrupt(SPI5);
+ (void)SPI_DR(SPI5);
+ }
+}
+
+/* Touchscreen interrupt */
+void
+exti15_10_isr() {
+ exti_reset_request(EXTI15);
+ stmpe811_handle_interrupt();
+}
+
+void
+exti0_isr()
+{
+ exti_reset_request(EXTI0);
+ next_demo();
+}
+
+
+/**
+ * Flood fill 4 and offscreen rendering demonstration
+ */
+#define FROWNY_WIDTH 101
+#define FROWNY_HEIGHT 121
+uint16_t frowny[FROWNY_WIDTH * FROWNY_HEIGHT];
+static void init_floodfill4(void)
+{
+ /* init flood-fill (also offscreen rendering demo) */
+ gfx_offscreen_rendering_begin(frowny, FROWNY_WIDTH, FROWNY_HEIGHT);
+
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+
+ /*gfx_draw_rect(0,0,100,100, GFX_COLOR_GREEN2);*/
+ /* Frowny */
+ gfx_draw_circle(50, 50, 50, GFX_COLOR_GREEN2);
+ gfx_draw_circle(30, 30, 6, GFX_COLOR_GREEN2);
+ gfx_draw_circle(70, 30, 6, GFX_COLOR_GREEN2);
+ gfx_draw_line(30, 80, 40, 70, GFX_COLOR_GREEN2);
+ gfx_draw_line(40, 70, 50, 80, GFX_COLOR_GREEN2);
+ gfx_draw_line(50, 80, 60, 70, GFX_COLOR_GREEN2);
+ gfx_draw_line(60, 70, 70, 80, GFX_COLOR_GREEN2);
+ /* Goatee */
+ gfx_draw_vline(50, 80, 20, GFX_COLOR_GREEN2);
+ /* 4 Markers */
+ gfx_draw_vline(70, 1, 15, GFX_COLOR_GREEN2);
+ gfx_draw_vline(70, 90, 15, GFX_COLOR_GREEN2);
+ gfx_draw_vline(30, 1, 15, GFX_COLOR_GREEN2);
+ gfx_draw_vline(30, 90, 15, GFX_COLOR_GREEN2);
+ /* Scars */
+ gfx_draw_line(20, 10, 70, 70, GFX_COLOR_GREEN2);
+ gfx_draw_line(10, 75, 90, 30, GFX_COLOR_GREEN2);
+ /* Fly:) */
+ gfx_draw_rect(10, 100, 80, 21, GFX_COLOR_GREEN2);
+ gfx_draw_line(13, 105, 87, 117, GFX_COLOR_GREEN2);
+ gfx_draw_line(20, 117, 70, 100, GFX_COLOR_GREEN2);
+ /* Worst case dots
+ for (int16_t px=1; px<100; px+=4) {
+ for (int16_t py=1; py<120; py+=2) {
+ gfx_draw_pixel(px, py, GFX_COLOR_GREEN2);
+ gfx_draw_pixel(px+2, py+1, GFX_COLOR_GREEN2);
+ }
+ }
+ */
+ /* Head-Fly connection */
+ gfx_draw_vline(50, 99, 3, ILI9341_LAYER2_COLOR_KEY);
+
+ /* resume normal rendering */
+ gfx_offscreen_rendering_end();
+}
+static void draw_floodfill4(demo_mode_t demo_mode)
+{
+ int16_t x, y, px,py;
+ static int16_t scan_x = -1, scan_y = -1;
+
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ x = 10;
+ y = 70;
+ break;
+ case DEMO_MODE_FLOODFILL4:
+ x = (gfx_width()-FROWNY_WIDTH)/2;
+ y = 70;
+ break;
+ default:
+ return;
+ }
+
+ gfx_set_clipping_area(
+ x-20, y-20,
+ x+FROWNY_WIDTH+20, y+FROWNY_HEIGHT+20
+ );
+ /* copy buffered frowny */
+ gfx_draw_raw_rbg565_buffer(x, y, FROWNY_WIDTH, FROWNY_HEIGHT, frowny);
+ /* additional stuff */
+ if (demo_mode == DEMO_MODE_FLOODFILL4) {
+ /* draw barriers */
+ if (scan_y == FROWNY_HEIGHT) {
+ scan_y = -1;
+ } else
+ if (scan_y >= 0) {
+ scan_y++;
+ } else
+ if (scan_x == FROWNY_WIDTH) {
+ scan_x = -1;
+ scan_y++;
+ } else {
+ scan_x++;
+ }
+ if (scan_x >= 0) {
+ gfx_draw_vline(
+ x+scan_x, y,
+ FROWNY_HEIGHT, GFX_COLOR_BLUE2
+ );
+ }
+ if (scan_y >= 0) {
+ gfx_draw_hline(
+ x, y+scan_y,
+ FROWNY_WIDTH , GFX_COLOR_BLUE2
+ );
+ }
+
+ /* Worst case dots */
+ for (px = x+1; px < x+100; px += 4) {
+ for (py = y+1; py < y+120; py += 2) {
+ gfx_draw_pixel(px, py, GFX_COLOR_GREEN2);
+ gfx_draw_pixel(px+2, py+1, GFX_COLOR_GREEN2);
+ }
+ }
+ }
+ /* Flood fill */
+ uint8_t fill_segment_buf[8*2048];
+ fill_segment_queue_statistics_t stats =
+ gfx_flood_fill4(
+ x+40, y+50,
+ ILI9341_LAYER2_COLOR_KEY, GFX_COLOR_RED,
+ fill_segment_buf, sizeof(fill_segment_buf)
+ );
+ gfx_set_clipping_area_max();
+ /* Print statistics */
+ char buf[1024];
+ snprintf(buf, 1023,
+ "flood_fill4 test:\n"
+ "%5d segments stored (max)\n"
+ "%5d segments stored (total)\n"
+ "%5d buffer overflows",
+ stats.count_max,
+ stats.count_total,
+ stats.overflows);
+ buf[1023] = 0;
+ gfx_puts2(10, 198, buf, &font_Tamsyn5x9r_9 , GFX_COLOR_WHITE);
+}
+
+
+/**
+ * Bezier demonstration
+ */
+uint16_t color = GFX_COLOR_BLACK;
+static void draw_segment(point2d_t p1, point2d_t p2)
+{
+ gfx_draw_line(
+ (int16_t)p1.x, (int16_t)p1.y,
+ (int16_t)p2.x, (int16_t)p2.y,
+ color
+ );
+}
+static void draw_point_list(point2d_t *points, size_t points_count, uint16_t _color)
+{
+ unsigned int i;
+ color = _color;
+ for (i = 0; i < points_count-1; i++) {
+ draw_segment(points[i], points[i+1]);
+ }
+}
+point2d_t pentagram[] = {
+ { 0.00000, 1.00000 },
+ { -0.58779, -0.80902 },
+ { 0.95106, 0.30902 },
+ { -0.95106, 0.30902 },
+ { 0.58779, -0.80902 },
+
+ { 0.00000, 1.00000 },
+ { -0.58779, -0.80902 },
+ { 0.95106, 0.30902 },
+ { -0.95106, 0.30902 },
+ { 0.58779, -0.80902 },
+
+ { 0.00000, 1.00000 },
+ { -0.58779, -0.80902 },
+ { 0.95106, 0.30902 },
+ { -0.95106, 0.30902 },
+ { 0.58779, -0.80902 },
+
+ { 0.00000, 1.00000 },
+};
+uint32_t num_points;
+uint32_t num_ipoints;
+static void init_bezier(void)
+{
+ num_points = sizeof(pentagram)/sizeof(pentagram[0]);
+ num_ipoints = bezier_calculate_int_points_length(num_points);
+}
+#define TENSION_MIN 0.15f
+#define TENSION_MAX 3.0f
+static void draw_bezier(demo_mode_t demo_mode)
+{
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ case DEMO_MODE_BEZIER:
+ break;
+ default:
+ return;
+ }
+
+ static vector_flt_t tension = 1.0f;
+ static vector_flt_t tension_change = 1.1f;
+ static vector_flt_t rot = 0.0f;
+ rot += 0.01f;
+ uint32_t i;
+
+ /* transform pentagram */
+ point2d_t pentagram_[num_points];
+
+ vector_flt_t x, y;
+ x = gfx_width() / 2 + 30 * vector_flt_sin(rot * 3);
+ y = 20 + gfx_height() / 2 + 30 * vector_flt_cos(rot * 3);
+
+ gfx_set_clipping_area(1, 41, gfx_width()-1, gfx_height()-1);
+
+
+ mat3x3_t mat;
+
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ break;
+ case DEMO_MODE_BEZIER:
+ /* shear x */
+ mat = mat3x3_translate(40, 100);
+ mat = mat3x3_mult(mat, mat3x3_scale(20, 20));
+ mat = mat3x3_mult(mat, mat3x3_shear_x(rot*2));
+ mat3x3_affine_transform(
+ mat,
+ pentagram_, pentagram, num_points
+ );
+ draw_point_list(
+ pentagram_, num_points,
+ GFX_COLOR_GREEN
+ );
+ /* shear y */
+ mat = mat3x3_translate(280, 100);
+ mat = mat3x3_mult(mat, mat3x3_scale(20, 20));
+ mat = mat3x3_mult(mat, mat3x3_shear_y(rot*2));
+ mat3x3_affine_transform(
+ mat,
+ pentagram_, pentagram, num_points
+ );
+ draw_point_list(
+ pentagram_, num_points,
+ GFX_COLOR_GREEN
+ );
+ /* scale */
+ mat = mat3x3_translate(280, 190);
+ mat = mat3x3_mult(mat, mat3x3_scale(15/tension, 15*tension));
+ mat3x3_affine_transform(
+ mat,
+ pentagram_, pentagram, num_points
+ );
+ draw_point_list(
+ pentagram_, num_points,
+ GFX_COLOR_GREEN
+ );
+ /* scale */
+ mat = mat3x3_translate(40, 190);
+ mat = mat3x3_mult(mat, mat3x3_scale(25, 25));
+ mat = mat3x3_mult(mat, mat3x3_rotate(-rot*6));
+ mat3x3_affine_transform(
+ mat,
+ pentagram_, pentagram, num_points
+ );
+ draw_point_list(
+ pentagram_, num_points,
+ GFX_COLOR_GREEN
+ );
+
+ break;
+ default:
+ return;
+ }
+
+
+
+ mat = mat3x3_translate(x, y);
+ mat = mat3x3_mult(mat, mat3x3_scale(20, 20));
+ mat = mat3x3_mult(mat, mat3x3_rotate(rot));
+ mat3x3_affine_transform(
+ mat,
+ pentagram_, pentagram, num_points
+ );
+ /* draw original form */
+ draw_point_list(pentagram_, num_points, GFX_COLOR_GREEN);
+
+ /* change tension, then redraw bezier curve.. */
+ color = GFX_COLOR_BLUE;
+ tension *= tension_change;
+ if (tension <= TENSION_MIN) {
+ tension = TENSION_MIN;
+ tension_change = 1/tension_change;
+ } else
+ if (tension >= TENSION_MAX) {
+ tension = TENSION_MAX;
+ tension_change = 1/tension_change;
+ }
+ point2d_t pi1[num_ipoints];
+ bezier_cubic(pi1, pentagram_, num_points, 0.0001f, tension);
+ for (i = 0; i < num_ipoints-1; i += 3) {
+ bezier_draw_cubic(
+ draw_segment,
+ 15,
+ pi1[i],
+ pi1[i+1], pi1[i+2],
+ pi1[i+3]
+ );
+ }
+ gfx_set_clipping_area_max();
+}
+
+/**
+ * Bezier interactive demo
+ */
+
+static void draw_bezier_interactive(
+ demo_mode_t demo_mode,
+ touchscreen_action_t ts_action,
+ point2d_t touch_point, point2d_t drag_distance
+
+) {
+ switch (demo_mode) {
+ case DEMO_MODE_BEZIER_INTERACTIVE:
+ break;
+ default:
+ return;
+ }
+
+ uint32_t i;
+ char buf[2];
+ buf[1] = 0;
+
+ const int16_t point_radius = 15;
+
+ /* small demo curve */
+ static point2d_t curve_points[4] = {
+ { 100, 80},
+ { 50, 180},
+ { 270, 180},
+ { 220, 80},
+ };
+ static point2d_t *selected_point;
+
+ switch (ts_action) {
+ case TS_TOUCHED: {
+ /* find nearest point */
+ vector_flt_t min_dist = point2d_dist(curve_points[0], touch_point);
+ selected_point = &curve_points[0];
+ for (i = 1; i < 4; i++) {
+ vector_flt_t dist = point2d_dist(curve_points[i], touch_point);
+ if (min_dist > dist) {
+ min_dist = dist;
+ selected_point = &curve_points[i];
+ }
+ }
+ if (min_dist > point_radius*1.5f) {
+ selected_point = NULL;
+ }
+ } break;
+ case TS_DRAGGING:
+ selected_point->x += drag_distance.x;
+ selected_point->y += drag_distance.y;
+ break;
+ case TS_DRAGGED:
+ selected_point = NULL;
+ break;
+ case TS_NONE:
+ break;
+ }
+
+ /* draw bezier */
+ color = GFX_COLOR_RED;
+ bezier_draw_cubic(
+ draw_segment,
+ 20,
+ curve_points[0],
+ curve_points[1], curve_points[2],
+ curve_points[3]
+ );
+ for (i = 0; i < 4; i++) {
+ gfx_fill_circle(
+ (int16_t)(curve_points[i].x),
+ (int16_t)(curve_points[i].y),
+ (int16_t) point_radius,
+ GFX_COLOR_RED
+ );
+ buf[0] = 48 + (char)(i%10);
+ gfx_set_font_scale(2);
+ gfx_puts2(
+ (int16_t)curve_points[i].x
+ - font_Tamsyn5x9b_9.charwidth
+ *gfx_get_font_scale()/2+1,
+ (int16_t)curve_points[i].y
+ - font_Tamsyn5x9b_9.lineheight
+ *gfx_get_font_scale()/2,
+ buf,
+ &font_Tamsyn5x9b_9,
+ GFX_COLOR_WHITE
+ );
+ }
+
+}
+
+
+/**
+ * Ball simulation
+ */
+balls_t ball_simulation;
+ball_t balls[100];
+uint64_t ball_timeout;
+static void init_balls(void)
+{
+ ball_setup(
+ &ball_simulation,
+ mtime(),
+ /* the walls are changed in the
+ * draw_background function! */
+ (walls_t) {
+ .x1 = 201,
+ .y1 = 61,
+ .x2 = gfx_width()-4,
+ .y2 = 179,
+ .bg_color = GFX_COLOR_GREY2,
+ .fg_color = GFX_COLOR_WHITE
+ },
+ balls, sizeof(balls)/sizeof(ball_t)
+ );
+ /* create some balls */
+ ball_create(&ball_simulation, 5, 5, (point2d_t){ 100, 56 }, (point2d_t){ 30, -20 }, GFX_COLOR_BLUE);
+ ball_create(&ball_simulation, 6, 6, (point2d_t){ 130, 60 }, (point2d_t){ 10, -50 }, GFX_COLOR_BLUE2);
+ ball_create(&ball_simulation, 7, 7, (point2d_t){ 190, 140 }, (point2d_t){ -30, 20 }, GFX_COLOR_ORANGE);
+ ball_create(&ball_simulation, 4, 4, (point2d_t){ 100, 190 }, (point2d_t){ 10, -30 }, GFX_COLOR_YELLOW);
+ ball_create(&ball_simulation, 7, 10, (point2d_t){ 20, 200 }, (point2d_t){ 20, 10 }, GFX_COLOR_GREEN2);
+ ball_create(&ball_simulation, 8, 15, (point2d_t){ 70, 120 }, (point2d_t){ -20, 30 }, GFX_COLOR_BLACK);
+ ball_create(&ball_simulation, 5, 1, (point2d_t){ 180, 90 }, (point2d_t){ 40, 10 }, GFX_COLOR_CYAN);
+ ball_create(&ball_simulation, 5, 1, (point2d_t){ 75, 200 }, (point2d_t){ -20, 20 }, GFX_COLOR_MAGENTA);
+ ball_create(&ball_simulation, 5, 1, (point2d_t){ 250, 210 }, (point2d_t){ 20, -30 }, GFX_COLOR_GREEN);
+
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 10, -20 }, GFX_COLOR_BLACK);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_DARKGREY);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 20, -20 }, GFX_COLOR_GREY);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_BLUE);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 20, -20 }, GFX_COLOR_BLUE2);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 40, -20 }, GFX_COLOR_RED);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_MAGENTA);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 10, -20 }, GFX_COLOR_GREEN);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_GREEN2);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 20, -20 }, GFX_COLOR_CYAN);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_YELLOW);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 10, -20 }, GFX_COLOR_ORANGE);
+ ball_create(&ball_simulation, 3, 1, (point2d_t){ 100, 56 }, (point2d_t){ 50, -20 }, GFX_COLOR_BROWN);
+
+ ball_timeout = mtime() + 5000;
+}
+static void draw_balls(demo_mode_t demo_mode)
+{
+ uint64_t ctime = mtime();
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ case DEMO_MODE_BALLS:
+ break;
+ default:
+ /* this results in a lot of computation after a while */
+ ball_simulation.time_ms_0 = ctime;
+ return;
+ }
+ /* generate a fast heavy ball to get things moving.. */
+ if (ball_timeout < ctime) {
+ ball_timeout = UINT64_MAX;
+ ball_create(
+ &ball_simulation,
+ 6, 30,
+ (point2d_t){ 0, 0 },
+ (point2d_t){ 150, 0 },
+ GFX_COLOR_RED
+ );
+ /* puts this ball outside the area.. */
+ ball_simulation.balls[ball_simulation.balls_count-1].pos =
+ (point2d_t) {10, gfx_height()/2};
+ }
+ /* move balls */
+ ball_move(&ball_simulation, ctime);
+ /* draw balls */
+ ball_draw(&ball_simulation);
+}
+
+
+/**
+ * Re-/draw background
+ */
+static void draw_background(demo_mode_t demo_mode)
+{
+ const char *mode_s;
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ mode_s = "All demos";
+ break;
+ case DEMO_MODE_FLOODFILL4:
+ mode_s = "Floodfill";
+ break;
+ case DEMO_MODE_BEZIER:
+ mode_s = "Animated Vectors";
+ break;
+ case DEMO_MODE_BEZIER_INTERACTIVE:
+ mode_s = "Interactive Bezier";
+ break;
+ case DEMO_MODE_BALLS:
+ mode_s = "Ballz";
+ break;
+ default :
+ mode_s = "Invalid";
+ break;
+ }
+
+ ili9341_set_layer1();
+
+ gfx_fill_screen(GFX_COLOR_BLACK);
+
+ gfx_draw_rect(0,0, 40,40, GFX_COLOR_WHITE);
+ gfx_draw_rect(gfx_width()-40,0, 40,40, GFX_COLOR_WHITE);
+ gfx_set_font_scale(3);
+ gfx_puts2( 14, 7, "<", &font_Tamsyn5x9b_9 , GFX_COLOR_WHITE);
+ gfx_puts2(gfx_width()-26, 7, ">", &font_Tamsyn5x9b_9 , GFX_COLOR_WHITE);
+
+ gfx_draw_rect(40, 0, gfx_width()-80, 40 , GFX_COLOR_DARKGREY);
+ gfx_fill_rect(41, 1, gfx_width()-82, 40-2, GFX_COLOR_BLUE);
+
+ gfx_set_font_scale(2);
+ gfx_set_font(&font_Tamsyn5x9r_9);
+ gfx_set_text_color(GFX_COLOR_WHITE);
+ gfx_puts3(gfx_width()/2, 4, mode_s, GFX_ALIGNMENT_CENTER);
+ gfx_set_font_scale(1);
+ gfx_puts3(
+ gfx_width()/2, 21,
+ "Press the blue button, '<' or '>'\n"
+ "to change the demonstrations",
+ GFX_ALIGNMENT_CENTER
+ );
+
+ /* draw the stage (draw_plane) */
+ if (demo_mode == DEMO_MODE_ALL) {
+ ball_simulation.walls = (walls_t) {
+ .x1 = 201,
+ .y1 = 61,
+ .x2 = gfx_width()-4,
+ .y2 = 179,
+ .bg_color = GFX_COLOR_GREY2, .fg_color = GFX_COLOR_WHITE
+ };
+ ball_draw_walls(&ball_simulation);
+ } else
+ if (demo_mode == DEMO_MODE_BALLS) {
+ ball_simulation.walls = (walls_t) {
+ .x1 = 1,
+ .y1 = 51,
+ .x2 = gfx_width()-1,
+ .y2 = gfx_height()-1,
+ .bg_color = GFX_COLOR_GREY2, .fg_color = GFX_COLOR_WHITE
+ };
+ ball_draw_walls(&ball_simulation);
+ }
+
+ /* flip background buffer */
+ ili9341_flip_layer1_buffer();
+}
+
+/**
+ * Main loop
+ */
+
+#define DISPLAY_TIMEOUT 33 /* ~30fps */
+int main(void)
+{
+ /* init timers. */
+ clock_setup();
+
+ /* setup blue button */
+ rcc_periph_clock_enable(RCC_GPIOA);
+ gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO0);
+ exti_select_source(EXTI0, GPIOA);
+ exti_set_trigger(EXTI0, EXTI_TRIGGER_RISING);
+ exti_enable_request(EXTI0);
+ nvic_enable_irq(NVIC_EXTI0_IRQ);
+
+ /* set up SDRAM. */
+ sdram_init();
+
+ /* init LTDC (gfx
+ * cm3 and spi are also initialized by this function call) */
+ ili9341_init(
+ (uint16_t *[]){
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 0*ILI9341_SURFACE_SIZE
+ ),
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 1*ILI9341_SURFACE_SIZE
+ )
+ },
+ (uint16_t *[]){
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 2*ILI9341_SURFACE_SIZE
+ ),
+ (uint16_t *)(
+ SDRAM_BASE_ADDRESS + 3*ILI9341_SURFACE_SIZE
+ )
+ }
+
+ );
+
+
+ /**
+ * setup stmpe811 touchscreen controller (via i2c)
+ */
+ stmpe811_setup_hardware();
+ stmpe811_setup();
+ /* Temperature readings make no sense!
+ stmpe811_start_temp_measurements();
+ msleep(100);
+ for (i=0; i<100000; i++) {
+ uint16_t temp;
+ msleep(11);
+ temp = stmpe811_read_temp_sample();
+ // do something with temp
+ }
+ stmpe811_stop_temp_measuements();
+ */
+ stmpe811_start_tsc();
+ stmpe811_enable_interrupts();
+
+
+ /*
+ * Application start..
+ */
+
+ /* rotate LCD for 90 degrees */
+ gfx_set_rotation(GFX_ROTATION_270_DEGREES);
+
+ /* set background color */
+ ltdc_set_background_color(0, 0, 0);
+
+ /* clear unused layers */
+ ili9341_set_layer1();
+ gfx_fill_screen(GFX_COLOR_BLACK);
+ ili9341_flip_layer1_buffer();
+
+ ili9341_set_layer2();
+
+ /* color key sets alpha to 0 (aka clear screen) */
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+ ili9341_flip_layer2_buffer();
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+ ili9341_flip_layer2_buffer();
+
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ while (LTDC_SRCR_IS_RELOADING());
+
+ /* draw background */
+ demo_mode_t demo_mode = new_demo_mode;
+ draw_background(demo_mode);
+
+ /* init floodfill4 demo */
+ init_floodfill4();
+
+ /* init/draw bezier */
+ init_bezier();
+
+ /* init balls demo */
+ init_balls();
+
+
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+
+ point2d_t touch_point = {0};
+ point2d_t drag_distance = {0};
+ while (1) {
+ uint64_t ctime = mtime();
+ static uint64_t draw_timeout = 1;
+ static char fps_s[32] = " fps";
+
+ if (!LTDC_SRCR_IS_RELOADING() && (draw_timeout <= ctime)) {
+ if (demo_mode != new_demo_mode) {
+ demo_mode = new_demo_mode;
+ draw_background(demo_mode);
+ }
+
+ /* calculate fps */
+ uint32_t fps;
+ fps = 1000 / (ctime-draw_timeout+DISPLAY_TIMEOUT);
+ /* set next timeout */
+ draw_timeout = ctime+DISPLAY_TIMEOUT;
+
+ /* select layer to draw on */
+ ili9341_set_layer2();
+ /* clear the whole screen */
+ gfx_fill_screen(ILI9341_LAYER2_COLOR_KEY);
+
+ /**
+ * Get touch infos
+ */
+ touchscreen_action_t ts_action = update_touchscreen_data(&touch_point,&drag_distance);
+ switch (ts_action) {
+ case TS_TOUCHED:
+ if (touch_point.y < 40) {
+ if (touch_point.x < 40) {
+ previous_demo();
+ } else
+ if (touch_point.x > gfx_width()-40) {
+ next_demo();
+ }
+ }
+ break;
+ case TS_DRAGGING:
+ break;
+ case TS_DRAGGED:
+ break;
+ case TS_NONE:
+ break;
+ }
+
+ /**
+ * Display touch infos
+ */
+ switch (demo_mode) {
+ case DEMO_MODE_ALL:
+ print_touchscreen_data(200,190,GFX_COLOR_WHITE, ts_action,touch_point,drag_distance);
+ break;
+ case DEMO_MODE_BEZIER_INTERACTIVE:
+ print_touchscreen_data( 10,190,GFX_COLOR_WHITE, ts_action,touch_point,drag_distance);
+ break;
+ default :
+ break;
+ }
+
+
+ /**
+ * Flood fill test
+ */
+ draw_floodfill4(demo_mode);
+
+ /**
+ * Bezier test
+ */
+ draw_bezier(demo_mode);
+
+ /**
+ * Bezier interactive
+ */
+ draw_bezier_interactive(demo_mode, ts_action,touch_point,drag_distance);
+
+ /**
+ * Ball stuff
+ */
+ draw_balls(demo_mode);
+
+ /* draw fps */
+ sprintf(fps_s, "%lu fps", fps);
+ gfx_set_font_scale(1);
+ gfx_set_font(&font_Tamsyn5x9b_9);
+ gfx_set_text_color(GFX_COLOR_WHITE);
+ gfx_puts3(gfx_width()-1, 40, fps_s, GFX_ALIGNMENT_RIGHT);
+
+ /* swap the double buffer */
+ ili9341_flip_layer2_buffer();
+
+ /* update dislay */
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ }
+ }
+}
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application_balls.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application_balls.h
new file mode 100644
index 00000000..8743d5ac
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/application_balls.h
@@ -0,0 +1,523 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ *
+ * This code is based on http://vobarian.com/bouncescope/
+ *
+ */
+
+
+#include
+#include
+
+#include "vector_gfx/vector.h"
+
+typedef struct {
+ vector_flt_t x1, y1, x2, y2;
+ uint16_t bg_color, fg_color;
+} walls_t;
+typedef struct {
+ vector_flt_t radius, mass;
+ point2d_t pos;
+ point2d_t vel;
+ uint16_t color;
+} ball_t;
+typedef struct {
+ uint64_t time_ms_0;
+ walls_t walls;
+ ball_t *balls;
+ size_t balls_size;
+ size_t balls_count;
+} balls_t;
+
+static inline
+void
+ball_setup(
+ balls_t *self,
+ uint64_t time_ms_0,
+ walls_t walls,
+ ball_t balls[], size_t balls_size
+) {
+ self->time_ms_0 = time_ms_0;
+ self->walls = walls;
+ self->balls = balls;
+ self->balls_size = balls_size;
+ self->balls_count = 0;
+}
+
+static inline
+bool
+ball_hittest(ball_t *b1, ball_t *b2) {
+ return point2d_dist(b1->pos, b2->pos) < (b1->radius + b2->radius + 10);
+}
+
+static inline
+void
+ball_create(
+ balls_t *self,
+ vector_flt_t radius,
+ vector_flt_t mass,
+ point2d_t pos,
+ point2d_t vel,
+ uint16_t color
+) {
+ if (self->balls_count >= self->balls_size) {
+ return;
+ }
+
+ ball_t ball;
+ ball = (ball_t) {
+ .radius = radius,
+ .mass = mass,
+ .pos = pos,
+ .vel = vel,
+ .color = color,
+ };
+
+
+ /* try to fit the ball.. */
+ int16_t x = pos.x;
+ int16_t y = pos.y;
+
+ int16_t x_range = self->walls.x2 - self->walls.x1 - 2*radius;
+ int16_t y_range = self->walls.y2 - self->walls.y1 - 2*radius;
+
+ int16_t x_move = 0;
+ int16_t y_move = 0;
+
+
+
+ bool hit = true;
+ while (hit) {
+ /* fit ball into walls */
+ ball.pos.x = (vector_flt_t)((x+x_move) % x_range);
+ ball.pos.y = (vector_flt_t)((y+y_move) % y_range);
+
+ ball.pos.x += self->walls.x1 + radius;
+ ball.pos.y += self->walls.y1 + radius;
+
+ size_t l = self->balls_count;
+ ball_t *b = self->balls;
+
+ hit = false;
+ while (l) {
+ if ((ball_hittest(&ball, b))) {
+ hit = true;
+ if (x_move < x_range) {
+ x_move += 1;
+ } else
+ if (y_move < y_range) {
+ x_move = 0;
+ y_move += 1;
+ } else {
+ /* failed to fit ball into walls! */
+ hit = false;
+ }
+ break;
+ }
+ l--;
+ b++;
+ }
+ }
+
+ self->balls[self->balls_count++] = ball;
+}
+
+
+typedef enum {
+ COLL__NONE,
+ COLL__BALL,
+ COLL__WALL_X1,
+ COLL__WALL_X2,
+ COLL__WALL_Y1,
+ COLL__WALL_Y2
+} collision_type_t;
+typedef struct {
+ collision_type_t type;
+ vector_flt_t time_to;
+} collision_t;
+
+static inline
+collision_t
+ball_to_ball_collision_time(ball_t *b1, ball_t *b2) {
+ point2d_t vdiff = point2d_sub_ts(b2->vel, b1->vel);
+ point2d_t pdiff = point2d_sub_ts(b2->pos, b1->pos);
+ vector_flt_t r = b1->radius + b2->radius;
+
+ /* Compute parts of quadratic formula */
+ /* a = (v2x - v1x) ^ 2 + (v2y - v1y) ^ 2 */
+ vector_flt_t a = point2d_dot(vdiff, vdiff);
+ /* b = 2 * ((x20 - x10) * (v2x - v1x) + (y20 - y10) * (v2y - v1y)) */
+ vector_flt_t b = 2 * point2d_dot(vdiff, pdiff);
+ /* c = (x20 - x10) ^ 2 + (y20 - y10) ^ 2 - (r1 + r2) ^ 2 */
+ vector_flt_t c = point2d_dot(pdiff, pdiff) - r*r;
+
+ /* Determinant = b^2 - 4ac */
+ vector_flt_t det = b*b - 4 * a * c;
+
+ if (a != 0.) { /* If a == 0 then v2x==v1x and v2y==v1y and
+ * there will be no collision */
+ /* Quadratic formula. t = time to collision */
+ vector_flt_t t = (-b - vector_flt_sqrt(det)) / (2. * a);
+ if (t >= 0.) {
+ return (collision_t) {
+ .type = COLL__BALL,
+ .time_to = t
+ };
+ }
+ }
+ return (collision_t) { .type = COLL__NONE };
+}
+
+static inline
+collision_t
+ball_to_wall_collision_time(walls_t *walls, ball_t *b) {
+ collision_t collision = { .type = COLL__NONE };
+
+ /* Check for collision with wall X1 */
+ if (b->vel.x < 0.) {
+ vector_flt_t t = (b->radius - b->pos.x + walls->x1) / b->vel.x;
+ /*if (t >= 0.) {*/ /* If t < 0 then ball is headed away
+ * from wall, we ignore this case to
+ * keep the ball inside the walls..
+ */
+ collision = (collision_t) {
+ .type = COLL__WALL_X1,
+ .time_to = t
+ };
+ /*}*/
+ }
+
+ /* Check for collision with wall Y1 */
+ if (b->vel.y < 0.) {
+ vector_flt_t t = (b->radius - b->pos.y + walls->y1) / b->vel.y;
+ /*if (t >= 0.) {*/
+ if (collision.type == COLL__NONE || (t < collision.time_to)) {
+ collision = (collision_t) {
+ .type = COLL__WALL_Y1,
+ .time_to = t
+ };
+ }
+ /*}*/
+ }
+
+ /* Check for collision with wall X2 */
+ if (b->vel.x > 0.) {
+ vector_flt_t t = (walls->x2 - b->radius - b->pos.x) / b->vel.x;
+ /*if (t >= 0.) {*/
+ if (collision.type == COLL__NONE || (t < collision.time_to)) {
+ collision = (collision_t) {
+ .type = COLL__WALL_X2,
+ .time_to = t
+ };
+ }
+ /*}*/
+ }
+
+ /* Check for collision with wall Y2 */
+ if (b->vel.y > 0.) {
+ vector_flt_t t = (walls->y2 - b->radius - b->pos.y) / b->vel.y;
+ /*if (t >= 0.) {*/
+ if (collision.type == COLL__NONE || (t < collision.time_to)) {
+ collision = (collision_t) {
+ .type = COLL__WALL_Y2,
+ .time_to = t
+ };
+ }
+ /*}*/
+ }
+
+ return collision;
+}
+
+static inline
+void
+ball_to_ball_elastic_collision(ball_t *b1, ball_t *b2) {
+ /* Avoid division by zero below in computing new normal velocities
+ * Doing a collision where both balls have no mass makes no sense anyway
+ */
+ if (b1->mass == 0. && b2->mass == 0.) {
+ return;
+ }
+
+ /* Compute unit normal and unit tangent vectors */
+
+ /* normal vector - a vector normal to the collision surface */
+ point2d_t v_n = point2d_sub_ts(b2->pos, b1->pos);
+ /* unit normal vector */
+ point2d_t v_un = point2d_unit(v_n);
+ /* unit tangent vector */
+ point2d_t v_ut = { -v_un.y, v_un.x };
+
+ /* Compute scalar projections of velocities onto v_un and v_ut */
+ vector_flt_t v1n = point2d_dot(v_un, b1->vel); /* Dot product */
+ vector_flt_t v1t = point2d_dot(v_ut, b1->vel);
+ vector_flt_t v2n = point2d_dot(v_un, b2->vel);
+ vector_flt_t v2t = point2d_dot(v_ut, b2->vel);
+
+ /* Compute new tangential velocities */
+ /* Note: in reality, the tangential velocities
+ * do not change after the collision */
+ vector_flt_t v1t_prime = v1t;
+ vector_flt_t v2t_prime = v2t;
+
+ /* Compute new normal velocities using one-dimensional elastic
+ * collision equations in the normal direction
+ *
+ * Division by zero avoided. See early return above.
+ */
+ vector_flt_t v1n_prime =
+ (v1n * (b1->mass - b2->mass) + 2. * b2->mass * v2n)
+ / (b1->mass + b2->mass);
+ vector_flt_t v2n_prime =
+ (v2n * (b2->mass - b1->mass) + 2. * b1->mass * v1n)
+ / (b1->mass + b2->mass);
+
+ /* Compute new normal and tangential velocity vectors
+ * (Multiplication by a scalar)
+ */
+ point2d_t v_v1nPrime = point2d_mul_t(v_un, v1n_prime);
+ point2d_t v_v1tPrime = point2d_mul_t(v_ut, v1t_prime);
+ point2d_t v_v2nPrime = point2d_mul_t(v_un, v2n_prime);
+ point2d_t v_v2tPrime = point2d_mul_t(v_ut, v2t_prime);
+
+ /* Set new velocities in x and y coordinates */
+ b1->vel = (point2d_t) {
+ v_v1nPrime.x + v_v1tPrime.x, v_v1nPrime.y + v_v1tPrime.y
+ };
+ b2->vel = (point2d_t) {
+ v_v2nPrime.x + v_v2tPrime.x, v_v2nPrime.y + v_v2tPrime.y
+ };
+}
+
+static inline
+void
+ball_to_wall_elastic_collision(ball_t *b, collision_type_t type) {
+ switch (type) {
+ case COLL__WALL_X1:
+ b->vel.x = vector_flt_abs(b->vel.x);
+ break;
+ case COLL__WALL_Y1:
+ b->vel.y = vector_flt_abs(b->vel.y);
+ break;
+ case COLL__WALL_X2:
+ b->vel.x = -vector_flt_abs(b->vel.x);
+ break;
+ case COLL__WALL_Y2:
+ b->vel.y = -vector_flt_abs(b->vel.y);
+ break;
+
+ default:
+ /* invalid! */
+ break;
+ }
+}
+
+static inline
+void
+ball_advance_positions(ball_t *balls, size_t balls_count, vector_flt_t dt) {
+ /* move all balls */
+ while (balls_count) {
+ balls->pos = point2d_add_ts(
+ balls->pos, point2d_mul_t(balls->vel, dt)
+ );
+ balls_count--;
+ balls++;
+ }
+}
+
+static inline
+collision_t
+ball_find_earliest_collision(balls_t *self, ball_t **b1c, ball_t **b2c) {
+ if (self->balls_count == 0) {
+ return (collision_t) { .type = COLL__NONE };
+ }
+
+
+ /* Compare each pair of balls. Index i runs from the first
+ * ball up through the second-to-last ball. For each value of
+ * i, index j runs from the ball after i up through the last ball.
+ */
+
+ collision_t earliest_collision = { .type = COLL__NONE };
+
+ ball_t *b1, *b2;
+ size_t l, ll;
+ b1 = self->balls;
+ l = self->balls_count;
+ while (1) {
+ collision_t c;
+
+ /* check for wall collisions */
+ c = ball_to_wall_collision_time(&self->walls, b1);
+ if (c.type != COLL__NONE) {
+ if (
+ (earliest_collision.type == COLL__NONE)
+ || (c.time_to < earliest_collision.time_to)
+ ) {
+ earliest_collision = c;
+ *b1c = b1;
+ *b2c = NULL;
+ }
+ }
+
+ l--;
+ if (l == 0) {
+ break;
+ }
+
+
+ /* check for ball to ball collisions */
+ ll = l;
+ b2 = b1+1;
+ while (ll) {
+ c = ball_to_ball_collision_time(b1, b2);
+ if (c.type == COLL__BALL) {
+ if (
+ (earliest_collision.type == COLL__NONE)
+ || (c.time_to < earliest_collision.time_to)
+ ) {
+ earliest_collision = c;
+ *b1c = b1;
+ *b2c = b2;
+ }
+ }
+ b2++;
+ ll--;
+ }
+ b1++;
+ }
+
+ return earliest_collision;
+}
+
+static inline
+void
+ball_move(balls_t *self, uint64_t time_ms) {
+ vector_flt_t dt = (vector_flt_t)(time_ms-self->time_ms_0)/1000.;
+ self->time_ms_0 = time_ms;
+
+ collision_t last_collision = { .type = COLL__NONE };
+
+ size_t max_collisions = 1000;
+ while (--max_collisions) {
+ /* Find earliest collision */
+ ball_t *b1c = NULL, *b2c = NULL;
+ collision_t c = ball_find_earliest_collision(self, &b1c, &b2c);
+
+ /* If no collisions, break */
+ if (c.time_to == COLL__NONE) {
+ break;
+ }
+
+ /* Is collision within the time frame?
+ * Note: condition is tElapsed + timeToCollision strictly < dt,
+ * not <=, because if the two were exactly equal, we would
+ * perform the velocity adjustment for collision but not
+ * move the balls any more, so the collision could be
+ * detected again on the next call to advanceSim().
+ */
+ if (c.time_to < dt) {
+ /* Collision is within time frame
+ * Advance balls to point of collision
+ */
+ ball_advance_positions(
+ self->balls, self->balls_count,
+ c.time_to);
+ /* Collision is now occuring.
+ * Do collision calculation
+ */
+ if (c.type == COLL__BALL) {
+ ball_to_ball_elastic_collision(b1c, b2c);
+ } else {
+ ball_to_wall_elastic_collision(b1c, c.type);
+ }
+ /* Move time counter forward */
+ dt -= c.time_to;
+ } else {
+ /* Break if collision is not within this frame */
+ break;
+ }
+
+ /* Update lastCollision */
+ last_collision = c;
+ }
+
+ (void)last_collision;
+
+ /* Advance ball positions further if necessary after any collisions
+ * to complete the time frame
+ */
+ ball_advance_positions(self->balls, self->balls_count, dt);
+}
+
+static inline
+void
+ball_draw_walls(balls_t *self) {
+
+ /* draw walls and background */
+ gfx_draw_rect(
+ (int16_t)(self->walls.x1 - 1),
+ (int16_t)(self->walls.y1 - 1),
+ (int16_t)(self->walls.x2 - self->walls.x1 + 2),
+ (int16_t)(self->walls.y2 - self->walls.y1 + 2),
+ self->walls.fg_color
+ );
+ gfx_fill_rect(
+ (int16_t)(self->walls.x1),
+ (int16_t)(self->walls.y1),
+ (int16_t)(self->walls.x2 - self->walls.x1),
+ (int16_t)(self->walls.y2 - self->walls.y1),
+ self->walls.bg_color
+ );
+
+}
+static inline
+void
+ball_draw(balls_t *self) {
+ /* draw balls */
+
+ char buf[2] = " ";
+ uint32_t b_id = 0;
+ gfx_set_font_scale(1);
+
+ ball_t *b = self->balls;
+ size_t l = self->balls_count;
+ while (l--) {
+ gfx_fill_circle(
+ (int16_t)(b->pos.x),
+ (int16_t)(b->pos.y),
+ (int16_t)(b->radius),
+ b->color
+ );
+ buf[0] = 48+b_id++%10;
+ gfx_puts2(
+ (int16_t)b->pos.x
+ - font_Tamsyn5x9b_9.charwidth
+ * gfx_get_font_scale() / 2
+ + 1,
+ (int16_t)b->pos.y
+ - font_Tamsyn5x9b_9.lineheight
+ * gfx_get_font_scale() / 2,
+ buf,
+ &font_Tamsyn5x9b_9,
+ GFX_COLOR_WHITE
+ );
+ b++;
+ }
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.c
new file mode 100644
index 00000000..f14a2c9f
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+/*
+ * Now this is just the clock setup code from systick-blink as it is the
+ * transferrable part.
+ */
+
+#include
+#include
+
+/* Common function descriptions */
+#include "clock.h"
+
+/* milliseconds since boot */
+static volatile uint64_t system_millis;
+
+/* Called when systick fires */
+void sys_tick_handler(void)
+{
+ system_millis++;
+}
+
+/* simple sleep for delay milliseconds */
+void milli_sleep(uint32_t delay)
+{
+ uint64_t wake = system_millis + delay;
+ while (wake > system_millis) {
+ continue;
+ }
+}
+
+/* Getter function for the current time */
+uint64_t mtime(void)
+{
+ return system_millis;
+}
+
+/*
+ * clock_setup(void)
+ *
+ * This function sets up both the base board clock rate
+ * and a 1khz "system tick" count. The SYSTICK counter is
+ * a standard feature of the Cortex-M series.
+ */
+void clock_setup(void)
+{
+ /* Base board frequency, set to 168Mhz */
+ rcc_clock_setup_hse_3v3(&CLOCK_SETUP);
+
+ /* clock rate / 168000 to get 1mS interrupt rate */
+ systick_set_reload(168000);
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
+ systick_counter_enable();
+
+ /* this done last */
+ systick_interrupt_enable();
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.h
new file mode 100644
index 00000000..45cb11e6
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/clock.h
@@ -0,0 +1,38 @@
+/*
+ * This include file describes the functions exported by clock.c
+ */
+#ifndef __CLOCK_H
+#define __CLOCK_H
+
+#include
+
+#include
+
+#define CLOCK_SETUP rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]
+
+/*
+ * Definitions for functions being abstracted out
+ */
+void milli_sleep(uint32_t);
+uint64_t mtime(void);
+void clock_setup(void);
+
+/*
+ * Delay functions which are not using clock :)
+ */
+#define CYCLES_PER_LOOP 3
+static inline void wait_cycles(uint32_t n)
+{
+ uint32_t l = n/CYCLES_PER_LOOP;
+ //asm volatile("0:" "SUBS %[count], 1;" "BNE 0b;":[count]"+r"(l));
+ __asm__ __volatile__("0:" "SUBS %[count], 1;" "BNE 0b;":[count]"+r"(l));
+}
+
+static inline void msleep_loop(uint32_t ms)
+{
+ wait_cycles(168000000 / 1000 * ms);
+}
+
+
+#endif /* generic header protector */
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.c
new file mode 100644
index 00000000..efd40f67
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.c
@@ -0,0 +1,864 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#include "Tamsyn5x9b_9.h"
+
+static const uint32_t chars_data_Tamsyn5x9b_9[] = {
+ /* ' ' */
+
+ /* '!' */
+ 0x00000cff,
+ /* '"' */
+ 0x000005ff,
+ /* '#' */
+ 0x00affafa,
+ /* '$' */
+ 0x22fc6e44,
+ /* '%' */
+ 0x08936c91,
+ /* '&' */
+ 0x2ebd9966,
+ /* ''' */
+ 0x0000003f,
+ /* '(' */
+ 0x0c63336c,
+ /* ')' */
+ 0x036ccc63,
+ /* '*' */
+ 0x000576f4,
+ /* '+' */
+ 0x00637cc6,
+ /* ',' */
+ 0x000000f6,
+ /* '-' */
+ 0x0000000f,
+ /* '.' */
+ 0x0000000f,
+ /* '/' */
+ 0x003366cc,
+ /* '0' */
+ 0x0006bbb6,
+ /* '1' */
+ 0x000f6676,
+ /* '2' */
+ 0x000f36c7,
+ /* '3' */
+ 0x0007c6c7,
+ /* '4' */
+ 0x000cfdec,
+ /* '5' */
+ 0x0007c73f,
+ /* '6' */
+ 0x0006b736,
+ /* '7' */
+ 0x000336cf,
+ /* '8' */
+ 0x0006b6b6,
+ /* '9' */
+ 0x0006ceb6,
+ /* ':' */
+ 0x000003cf,
+ /* ';' */
+ 0x0001ec36,
+ /* '<' */
+ 0x000c636c,
+ /* '=' */
+ 0x00000f0f,
+ /* '>' */
+ 0x00036c63,
+ /* '?' */
+ 0x00606cd6,
+ /* '@' */
+ 0x0e33bbb6,
+ /* 'A' */
+ 0x000dfde4,
+ /* 'B' */
+ 0x0007b7b7,
+ /* 'C' */
+ 0x000e333e,
+ /* 'D' */
+ 0x0007bbb7,
+ /* 'E' */
+ 0x000f373f,
+ /* 'F' */
+ 0x0003373f,
+ /* 'G' */
+ 0x000ebb3e,
+ /* 'H' */
+ 0x000bbfbb,
+ /* 'I' */
+ 0x000f666f,
+ /* 'J' */
+ 0x0006dccc,
+ /* 'K' */
+ 0x000bb7bb,
+ /* 'L' */
+ 0x000f3333,
+ /* 'M' */
+ 0x00099ff9,
+ /* 'N' */
+ 0x000ddfbb,
+ /* 'O' */
+ 0x0006bbb6,
+ /* 'P' */
+ 0x000337b7,
+ /* 'Q' */
+ 0x00c6bbb6,
+ /* 'R' */
+ 0x000b77b7,
+ /* 'S' */
+ 0x0007c63e,
+ /* 'T' */
+ 0x0006666f,
+ /* 'U' */
+ 0x0006bbbb,
+ /* 'V' */
+ 0x00027bbb,
+ /* 'W' */
+ 0x0009ff99,
+ /* 'X' */
+ 0x000b666b,
+ /* 'Y' */
+ 0x000666bb,
+ /* 'Z' */
+ 0x000f36cf,
+ /* '[' */
+ 0x001db6df,
+ /* '\' */
+ 0x00cc6633,
+ /* ']' */
+ 0x001f6db7,
+ /* '^' */
+ 0x0000017a,
+ /* '_' */
+ 0x0000001f,
+ /* '`' */
+ 0x00000999,
+ /* 'a' */
+ 0x0000edde,
+ /* 'b' */
+ 0x007bb733,
+ /* 'c' */
+ 0x0000e33e,
+ /* 'd' */
+ 0x00eddecc,
+ /* 'e' */
+ 0x0000e7de,
+ /* 'f' */
+ 0x00666f6c,
+ /* 'g' */
+ 0x006cebbe,
+ /* 'h' */
+ 0x00bbb733,
+ /* 'i' */
+ 0x00f66706,
+ /* 'j' */
+ 0x7cccce0c,
+ /* 'k' */
+ 0x00bb7b33,
+ /* 'l' */
+ 0x00f66667,
+ /* 'm' */
+ 0x0000bbfb,
+ /* 'n' */
+ 0x0000bbb7,
+ /* 'o' */
+ 0x00006bb6,
+ /* 'p' */
+ 0x00337bb7,
+ /* 'q' */
+ 0x00ccedde,
+ /* 'r' */
+ 0x0000333f,
+ /* 's' */
+ 0x0000fc6e,
+ /* 't' */
+ 0x000e66f6,
+ /* 'u' */
+ 0x00006bbb,
+ /* 'v' */
+ 0x000027bb,
+ /* 'w' */
+ 0x0000bfbb,
+ /* 'x' */
+ 0x0000b66b,
+ /* 'y' */
+ 0x006cebbb,
+ /* 'z' */
+ 0x0000f36f,
+ /* '{' */
+ 0x18c7b19c, 0x00000007,
+ /* '|' */
+ 0x00003fff,
+ /* '}' */
+ 0xcc6f18c7, 0x00000001,
+ /* '~' */
+ 0x000005fa,
+ /* '¡' */
+ 0x00000ff3,
+ /* '£' */
+ 0x00f66f6c,
+ /* '«' */
+ 0x00004b72,
+ /* '°' */
+ 0x000006b6,
+ /* '»' */
+ 0x00002769,
+ /* '¿' */
+ 0x006b3606,
+ /* 'Ä' */
+ 0x0dfde409,
+ /* 'Å' */
+ 0x00dfd6d6,
+ /* 'Æ' */
+ 0x000d5f5e,
+ /* 'Ç' */
+ 0x064e333e,
+ /* 'É' */
+ 0x0f373f48,
+ /* 'Ñ' */
+ 0x0ddfb0db,
+ /* 'Ö' */
+ 0x06bbb605,
+ /* '¥' */
+ 0x00066f6b,
+ /* 'Ü' */
+ 0x06bbbb05,
+ /* 'ß' */
+ 0x0007b7be,
+ /* 'à' */
+ 0x00edde21,
+ /* 'á' */
+ 0x00edde48,
+ /* 'â' */
+ 0x0edde052,
+ /* 'ä' */
+ 0x00edde05,
+ /* 'å' */
+ 0x00edd6d6,
+ /* 'æ' */
+ 0x0000f5ef,
+ /* 'ç' */
+ 0x0064e33e,
+ /* 'è' */
+ 0x00e7de21,
+ /* 'é' */
+ 0x00e7de48,
+ /* 'ê' */
+ 0x0e7de052,
+ /* 'ë' */
+ 0x00e7de05,
+ /* 'ì' */
+ 0x00f66721,
+ /* 'í' */
+ 0x00f66748,
+ /* 'î' */
+ 0x0f667052,
+ /* 'ï' */
+ 0x00f66705,
+ /* 'ñ' */
+ 0x0bbb70db,
+ /* 'ò' */
+ 0x006bb621,
+ /* 'ó' */
+ 0x006bb648,
+ /* 'ô' */
+ 0x06bb6052,
+ /* 'ö' */
+ 0x006bb605,
+ /* '÷' */
+ 0x00060f06,
+ /* '¢' */
+ 0x004e33e4,
+ /* 'ù' */
+ 0x006bbb21,
+ /* 'ú' */
+ 0x006bbb24,
+ /* 'û' */
+ 0x06bbb052,
+ /* 'ü' */
+ 0x006bbb05,
+ /* 'ÿ' */
+ 0x6cebbb05
+};
+
+static const char_t chars_Tamsyn5x9b_9[] = {
+ {
+ .utf8_value = 32,
+ .bbox = { 0, 0, 0, 0 },
+ .data = &chars_data_Tamsyn5x9b_9[0]
+ }, {
+ .utf8_value = 33,
+ .bbox = { 1, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[0]
+ }, {
+ .utf8_value = 34,
+ .bbox = { 0, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[1]
+ }, {
+ .utf8_value = 35,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[2]
+ }, {
+ .utf8_value = 36,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[3]
+ }, {
+ .utf8_value = 37,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[4]
+ }, {
+ .utf8_value = 38,
+ .bbox = { 0, 1, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[5]
+ }, {
+ .utf8_value = 39,
+ .bbox = { 1, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[6]
+ }, {
+ .utf8_value = 40,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[7]
+ }, {
+ .utf8_value = 41,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[8]
+ }, {
+ .utf8_value = 42,
+ .bbox = { 0, 1, 4, 6 },
+ .data = &chars_data_Tamsyn5x9b_9[9]
+ }, {
+ .utf8_value = 43,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[10]
+ }, {
+ .utf8_value = 44,
+ .bbox = { 1, 5, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[11]
+ }, {
+ .utf8_value = 45,
+ .bbox = { 0, 4, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[12]
+ }, {
+ .utf8_value = 46,
+ .bbox = { 1, 5, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[13]
+ }, {
+ .utf8_value = 47,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[14]
+ }, {
+ .utf8_value = 48,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[15]
+ }, {
+ .utf8_value = 49,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[16]
+ }, {
+ .utf8_value = 50,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[17]
+ }, {
+ .utf8_value = 51,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[18]
+ }, {
+ .utf8_value = 52,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[19]
+ }, {
+ .utf8_value = 53,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[20]
+ }, {
+ .utf8_value = 54,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[21]
+ }, {
+ .utf8_value = 55,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[22]
+ }, {
+ .utf8_value = 56,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[23]
+ }, {
+ .utf8_value = 57,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[24]
+ }, {
+ .utf8_value = 58,
+ .bbox = { 1, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[25]
+ }, {
+ .utf8_value = 59,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[26]
+ }, {
+ .utf8_value = 60,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[27]
+ }, {
+ .utf8_value = 61,
+ .bbox = { 0, 3, 4, 6 },
+ .data = &chars_data_Tamsyn5x9b_9[28]
+ }, {
+ .utf8_value = 62,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[29]
+ }, {
+ .utf8_value = 63,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[30]
+ }, {
+ .utf8_value = 64,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[31]
+ }, {
+ .utf8_value = 65,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[32]
+ }, {
+ .utf8_value = 66,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[33]
+ }, {
+ .utf8_value = 67,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[34]
+ }, {
+ .utf8_value = 68,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[35]
+ }, {
+ .utf8_value = 69,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[36]
+ }, {
+ .utf8_value = 70,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[37]
+ }, {
+ .utf8_value = 71,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[38]
+ }, {
+ .utf8_value = 72,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[39]
+ }, {
+ .utf8_value = 73,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[40]
+ }, {
+ .utf8_value = 74,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[41]
+ }, {
+ .utf8_value = 75,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[42]
+ }, {
+ .utf8_value = 76,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[43]
+ }, {
+ .utf8_value = 77,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[44]
+ }, {
+ .utf8_value = 78,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[45]
+ }, {
+ .utf8_value = 79,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[46]
+ }, {
+ .utf8_value = 80,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[47]
+ }, {
+ .utf8_value = 81,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[48]
+ }, {
+ .utf8_value = 82,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[49]
+ }, {
+ .utf8_value = 83,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[50]
+ }, {
+ .utf8_value = 84,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[51]
+ }, {
+ .utf8_value = 85,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[52]
+ }, {
+ .utf8_value = 86,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[53]
+ }, {
+ .utf8_value = 87,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[54]
+ }, {
+ .utf8_value = 88,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[55]
+ }, {
+ .utf8_value = 89,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[56]
+ }, {
+ .utf8_value = 90,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[57]
+ }, {
+ .utf8_value = 91,
+ .bbox = { 0, 1, 3, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[58]
+ }, {
+ .utf8_value = 92,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[59]
+ }, {
+ .utf8_value = 93,
+ .bbox = { 1, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[60]
+ }, {
+ .utf8_value = 94,
+ .bbox = { 1, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[61]
+ }, {
+ .utf8_value = 95,
+ .bbox = { 0, 7, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[62]
+ }, {
+ .utf8_value = 96,
+ .bbox = { 1, 1, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[63]
+ }, {
+ .utf8_value = 97,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[64]
+ }, {
+ .utf8_value = 98,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[65]
+ }, {
+ .utf8_value = 99,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[66]
+ }, {
+ .utf8_value = 100,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[67]
+ }, {
+ .utf8_value = 101,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[68]
+ }, {
+ .utf8_value = 102,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[69]
+ }, {
+ .utf8_value = 103,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[70]
+ }, {
+ .utf8_value = 104,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[71]
+ }, {
+ .utf8_value = 105,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[72]
+ }, {
+ .utf8_value = 106,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[73]
+ }, {
+ .utf8_value = 107,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[74]
+ }, {
+ .utf8_value = 108,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[75]
+ }, {
+ .utf8_value = 109,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[76]
+ }, {
+ .utf8_value = 110,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[77]
+ }, {
+ .utf8_value = 111,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[78]
+ }, {
+ .utf8_value = 112,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[79]
+ }, {
+ .utf8_value = 113,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[80]
+ }, {
+ .utf8_value = 114,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[81]
+ }, {
+ .utf8_value = 115,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[82]
+ }, {
+ .utf8_value = 116,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[83]
+ }, {
+ .utf8_value = 117,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[84]
+ }, {
+ .utf8_value = 118,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[85]
+ }, {
+ .utf8_value = 119,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[86]
+ }, {
+ .utf8_value = 120,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[87]
+ }, {
+ .utf8_value = 121,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[88]
+ }, {
+ .utf8_value = 122,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[89]
+ }, {
+ .utf8_value = 123,
+ .bbox = { 0, 1, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[90]
+ }, {
+ .utf8_value = 124,
+ .bbox = { 1, 1, 3, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[92]
+ }, {
+ .utf8_value = 125,
+ .bbox = { 0, 1, 5, 8 },
+ .data = &chars_data_Tamsyn5x9b_9[93]
+ }, {
+ .utf8_value = 126,
+ .bbox = { 0, 1, 4, 4 },
+ .data = &chars_data_Tamsyn5x9b_9[95]
+ }, {
+ .utf8_value = 161,
+ .bbox = { 1, 3, 3, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[96]
+ }, {
+ .utf8_value = 163,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[97]
+ }, {
+ .utf8_value = 171,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[98]
+ }, {
+ .utf8_value = 176,
+ .bbox = { 0, 2, 4, 5 },
+ .data = &chars_data_Tamsyn5x9b_9[99]
+ }, {
+ .utf8_value = 187,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[100]
+ }, {
+ .utf8_value = 191,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[101]
+ }, {
+ .utf8_value = 196,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[102]
+ }, {
+ .utf8_value = 197,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[103]
+ }, {
+ .utf8_value = 198,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[104]
+ }, {
+ .utf8_value = 199,
+ .bbox = { 0, 2, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[105]
+ }, {
+ .utf8_value = 201,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[106]
+ }, {
+ .utf8_value = 209,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[107]
+ }, {
+ .utf8_value = 214,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[108]
+ }, {
+ .utf8_value = 165,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[109]
+ }, {
+ .utf8_value = 220,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[110]
+ }, {
+ .utf8_value = 223,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[111]
+ }, {
+ .utf8_value = 224,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[112]
+ }, {
+ .utf8_value = 225,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[113]
+ }, {
+ .utf8_value = 226,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[114]
+ }, {
+ .utf8_value = 228,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[115]
+ }, {
+ .utf8_value = 229,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[116]
+ }, {
+ .utf8_value = 230,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[117]
+ }, {
+ .utf8_value = 231,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[118]
+ }, {
+ .utf8_value = 232,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[119]
+ }, {
+ .utf8_value = 233,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[120]
+ }, {
+ .utf8_value = 234,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[121]
+ }, {
+ .utf8_value = 235,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[122]
+ }, {
+ .utf8_value = 236,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[123]
+ }, {
+ .utf8_value = 237,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[124]
+ }, {
+ .utf8_value = 238,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[125]
+ }, {
+ .utf8_value = 239,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[126]
+ }, {
+ .utf8_value = 241,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[127]
+ }, {
+ .utf8_value = 242,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[128]
+ }, {
+ .utf8_value = 243,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[129]
+ }, {
+ .utf8_value = 244,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[130]
+ }, {
+ .utf8_value = 246,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[131]
+ }, {
+ .utf8_value = 247,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[132]
+ }, {
+ .utf8_value = 162,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[133]
+ }, {
+ .utf8_value = 249,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[134]
+ }, {
+ .utf8_value = 250,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[135]
+ }, {
+ .utf8_value = 251,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[136]
+ }, {
+ .utf8_value = 252,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9b_9[137]
+ }, {
+ .utf8_value = 255,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9b_9[138]
+ }
+};
+
+const font_t font_Tamsyn5x9b_9 = {
+ .fontsize = 9,
+ .lineheight = 9,
+ .ascent = 7,
+ .descent = 2,
+ .charwidth = 5,
+ .char_count = 138,
+ .chars = chars_Tamsyn5x9b_9,
+ .chars_data = chars_data_Tamsyn5x9b_9,
+};
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.h
new file mode 100644
index 00000000..eb91f6ac
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9b_9.h
@@ -0,0 +1,25 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#ifndef _TAMSYN5X9B_9_
+#define _TAMSYN5X9B_9_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_Tamsyn5x9b_9;
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.c
new file mode 100644
index 00000000..b82e9bb1
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.c
@@ -0,0 +1,864 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#include "Tamsyn5x9r_9.h"
+
+static const uint32_t chars_data_Tamsyn5x9r_9[] = {
+ /* ' ' */
+
+ /* '!' */
+ 0x0000002f,
+ /* '"' */
+ 0x0000016d,
+ /* '#' */
+ 0x005f5afa,
+ /* '$' */
+ 0x027861e4,
+ /* '%' */
+ 0x00cd24b3,
+ /* '&' */
+ 0x00b5d256,
+ /* ''' */
+ 0x00000007,
+ /* '(' */
+ 0x00889254,
+ /* ')' */
+ 0x002a4911,
+ /* '*' */
+ 0x000096f4,
+ /* '+' */
+ 0x00427c84,
+ /* ',' */
+ 0x0000001b,
+ /* '-' */
+ 0x0000000f,
+ /* '.' */
+ 0x00000003,
+ /* '/' */
+ 0x000094a4,
+ /* '0' */
+ 0x00069996,
+ /* '1' */
+ 0x0000749a,
+ /* '2' */
+ 0x000f2487,
+ /* '3' */
+ 0x0007864f,
+ /* '4' */
+ 0x0004f564,
+ /* '5' */
+ 0x0007871f,
+ /* '6' */
+ 0x00069716,
+ /* '7' */
+ 0x0002244f,
+ /* '8' */
+ 0x00069696,
+ /* '9' */
+ 0x00068e96,
+ /* ':' */
+ 0x000000c3,
+ /* ';' */
+ 0x000006c3,
+ /* '<' */
+ 0x00004454,
+ /* '=' */
+ 0x00000f0f,
+ /* '>' */
+ 0x00001511,
+ /* '?' */
+ 0x00202487,
+ /* '@' */
+ 0x0e11dd96,
+ /* 'A' */
+ 0x00099f96,
+ /* 'B' */
+ 0x00079797,
+ /* 'C' */
+ 0x000e111e,
+ /* 'D' */
+ 0x00079997,
+ /* 'E' */
+ 0x000f171f,
+ /* 'F' */
+ 0x0001171f,
+ /* 'G' */
+ 0x000e9d1e,
+ /* 'H' */
+ 0x00099f99,
+ /* 'I' */
+ 0x00007497,
+ /* 'J' */
+ 0x00069888,
+ /* 'K' */
+ 0x00095359,
+ /* 'L' */
+ 0x000f1111,
+ /* 'M' */
+ 0x000999f9,
+ /* 'N' */
+ 0x00099db9,
+ /* 'O' */
+ 0x00069996,
+ /* 'P' */
+ 0x00011797,
+ /* 'Q' */
+ 0x00c69996,
+ /* 'R' */
+ 0x00095797,
+ /* 'S' */
+ 0x0007861e,
+ /* 'T' */
+ 0x0042109f,
+ /* 'U' */
+ 0x000e9999,
+ /* 'V' */
+ 0x00066999,
+ /* 'W' */
+ 0x0009f999,
+ /* 'X' */
+ 0x00099699,
+ /* 'Y' */
+ 0x00421151,
+ /* 'Z' */
+ 0x000f124f,
+ /* '[' */
+ 0x00e4924f,
+ /* '\' */
+ 0x00024489,
+ /* ']' */
+ 0x00f24927,
+ /* '^' */
+ 0x0000002a,
+ /* '_' */
+ 0x0000001f,
+ /* '`' */
+ 0x00000111,
+ /* 'a' */
+ 0x0000e99e,
+ /* 'b' */
+ 0x00799711,
+ /* 'c' */
+ 0x00000c4e,
+ /* 'd' */
+ 0x00e99e88,
+ /* 'e' */
+ 0x0000e35e,
+ /* 'f' */
+ 0x00222f2c,
+ /* 'g' */
+ 0x0068e99e,
+ /* 'h' */
+ 0x00999711,
+ /* 'i' */
+ 0x0003a4c2,
+ /* 'j' */
+ 0x00724984,
+ /* 'k' */
+ 0x00953511,
+ /* 'l' */
+ 0x0003a493,
+ /* 'm' */
+ 0x000099fd,
+ /* 'n' */
+ 0x00009997,
+ /* 'o' */
+ 0x00006996,
+ /* 'p' */
+ 0x00117997,
+ /* 'q' */
+ 0x0088e99e,
+ /* 'r' */
+ 0x0000113d,
+ /* 's' */
+ 0x0000f42e,
+ /* 't' */
+ 0x000c22f2,
+ /* 'u' */
+ 0x0000e999,
+ /* 'v' */
+ 0x00006699,
+ /* 'w' */
+ 0x0000ff99,
+ /* 'x' */
+ 0x00009669,
+ /* 'y' */
+ 0x0068e999,
+ /* 'z' */
+ 0x0000f24f,
+ /* '{' */
+ 0x0c44744c,
+ /* '|' */
+ 0x0000007f,
+ /* '}' */
+ 0x0322e223,
+ /* '~' */
+ 0x000000db,
+ /* '¡' */
+ 0x0000003d,
+ /* '£' */
+ 0x00f2272c,
+ /* '«' */
+ 0x00004932,
+ /* '°' */
+ 0x00000696,
+ /* '»' */
+ 0x00002649,
+ /* '¿' */
+ 0x00e12404,
+ /* 'Ä' */
+ 0x009fac0a,
+ /* 'Å' */
+ 0x009fa4ac,
+ /* 'Æ' */
+ 0x000d5f5e,
+ /* 'Ç' */
+ 0x064e111e,
+ /* 'É' */
+ 0x0f171f48,
+ /* 'Ñ' */
+ 0x09db90db,
+ /* 'Ö' */
+ 0x06999609,
+ /* '¥' */
+ 0x084f9151,
+ /* 'Ü' */
+ 0x06999905,
+ /* 'ß' */
+ 0x0005959e,
+ /* 'à' */
+ 0x00e99e21,
+ /* 'á' */
+ 0x00e99e48,
+ /* 'â' */
+ 0x0e99e0a4,
+ /* 'ä' */
+ 0x00e99e0a,
+ /* 'å' */
+ 0x0e99e4ac,
+ /* 'æ' */
+ 0x0000f5ef,
+ /* 'ç' */
+ 0x0001ac4e,
+ /* 'è' */
+ 0x00e35e21,
+ /* 'é' */
+ 0x00e35e48,
+ /* 'ê' */
+ 0x0e35e0a4,
+ /* 'ë' */
+ 0x00e35e0a,
+ /* 'ì' */
+ 0x0003a4d1,
+ /* 'í' */
+ 0x0003a4d4,
+ /* 'î' */
+ 0x001d262a,
+ /* 'ï' */
+ 0x0003a4c5,
+ /* 'ñ' */
+ 0x099970db,
+ /* 'ò' */
+ 0x00699621,
+ /* 'ó' */
+ 0x00699648,
+ /* 'ô' */
+ 0x06996052,
+ /* 'ö' */
+ 0x00699609,
+ /* '÷' */
+ 0x000021c2,
+ /* '¢' */
+ 0x004e55e4,
+ /* 'ù' */
+ 0x00699921,
+ /* 'ú' */
+ 0x00699948,
+ /* 'û' */
+ 0x06999052,
+ /* 'ü' */
+ 0x00699905,
+ /* 'ÿ' */
+ 0x68e99905
+};
+
+static const char_t chars_Tamsyn5x9r_9[] = {
+ {
+ .utf8_value = 32,
+ .bbox = { 0, 0, 0, 0 },
+ .data = &chars_data_Tamsyn5x9r_9[0]
+ }, {
+ .utf8_value = 33,
+ .bbox = { 1, 1, 2, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[0]
+ }, {
+ .utf8_value = 34,
+ .bbox = { 0, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[1]
+ }, {
+ .utf8_value = 35,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[2]
+ }, {
+ .utf8_value = 36,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[3]
+ }, {
+ .utf8_value = 37,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[4]
+ }, {
+ .utf8_value = 38,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[5]
+ }, {
+ .utf8_value = 39,
+ .bbox = { 1, 1, 2, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[6]
+ }, {
+ .utf8_value = 40,
+ .bbox = { 0, 1, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[7]
+ }, {
+ .utf8_value = 41,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[8]
+ }, {
+ .utf8_value = 42,
+ .bbox = { 0, 2, 4, 6 },
+ .data = &chars_data_Tamsyn5x9r_9[9]
+ }, {
+ .utf8_value = 43,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[10]
+ }, {
+ .utf8_value = 44,
+ .bbox = { 1, 6, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[11]
+ }, {
+ .utf8_value = 45,
+ .bbox = { 0, 4, 4, 5 },
+ .data = &chars_data_Tamsyn5x9r_9[12]
+ }, {
+ .utf8_value = 46,
+ .bbox = { 1, 6, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[13]
+ }, {
+ .utf8_value = 47,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[14]
+ }, {
+ .utf8_value = 48,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[15]
+ }, {
+ .utf8_value = 49,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[16]
+ }, {
+ .utf8_value = 50,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[17]
+ }, {
+ .utf8_value = 51,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[18]
+ }, {
+ .utf8_value = 52,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[19]
+ }, {
+ .utf8_value = 53,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[20]
+ }, {
+ .utf8_value = 54,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[21]
+ }, {
+ .utf8_value = 55,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[22]
+ }, {
+ .utf8_value = 56,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[23]
+ }, {
+ .utf8_value = 57,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[24]
+ }, {
+ .utf8_value = 58,
+ .bbox = { 1, 3, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[25]
+ }, {
+ .utf8_value = 59,
+ .bbox = { 1, 3, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[26]
+ }, {
+ .utf8_value = 60,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[27]
+ }, {
+ .utf8_value = 61,
+ .bbox = { 0, 3, 4, 6 },
+ .data = &chars_data_Tamsyn5x9r_9[28]
+ }, {
+ .utf8_value = 62,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[29]
+ }, {
+ .utf8_value = 63,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[30]
+ }, {
+ .utf8_value = 64,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[31]
+ }, {
+ .utf8_value = 65,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[32]
+ }, {
+ .utf8_value = 66,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[33]
+ }, {
+ .utf8_value = 67,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[34]
+ }, {
+ .utf8_value = 68,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[35]
+ }, {
+ .utf8_value = 69,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[36]
+ }, {
+ .utf8_value = 70,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[37]
+ }, {
+ .utf8_value = 71,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[38]
+ }, {
+ .utf8_value = 72,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[39]
+ }, {
+ .utf8_value = 73,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[40]
+ }, {
+ .utf8_value = 74,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[41]
+ }, {
+ .utf8_value = 75,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[42]
+ }, {
+ .utf8_value = 76,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[43]
+ }, {
+ .utf8_value = 77,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[44]
+ }, {
+ .utf8_value = 78,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[45]
+ }, {
+ .utf8_value = 79,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[46]
+ }, {
+ .utf8_value = 80,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[47]
+ }, {
+ .utf8_value = 81,
+ .bbox = { 0, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[48]
+ }, {
+ .utf8_value = 82,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[49]
+ }, {
+ .utf8_value = 83,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[50]
+ }, {
+ .utf8_value = 84,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[51]
+ }, {
+ .utf8_value = 85,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[52]
+ }, {
+ .utf8_value = 86,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[53]
+ }, {
+ .utf8_value = 87,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[54]
+ }, {
+ .utf8_value = 88,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[55]
+ }, {
+ .utf8_value = 89,
+ .bbox = { 0, 2, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[56]
+ }, {
+ .utf8_value = 90,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[57]
+ }, {
+ .utf8_value = 91,
+ .bbox = { 0, 1, 3, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[58]
+ }, {
+ .utf8_value = 92,
+ .bbox = { 1, 2, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[59]
+ }, {
+ .utf8_value = 93,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[60]
+ }, {
+ .utf8_value = 94,
+ .bbox = { 0, 2, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[61]
+ }, {
+ .utf8_value = 95,
+ .bbox = { 0, 7, 5, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[62]
+ }, {
+ .utf8_value = 96,
+ .bbox = { 0, 1, 3, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[63]
+ }, {
+ .utf8_value = 97,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[64]
+ }, {
+ .utf8_value = 98,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[65]
+ }, {
+ .utf8_value = 99,
+ .bbox = { 1, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[66]
+ }, {
+ .utf8_value = 100,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[67]
+ }, {
+ .utf8_value = 101,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[68]
+ }, {
+ .utf8_value = 102,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[69]
+ }, {
+ .utf8_value = 103,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[70]
+ }, {
+ .utf8_value = 104,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[71]
+ }, {
+ .utf8_value = 105,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[72]
+ }, {
+ .utf8_value = 106,
+ .bbox = { 1, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[73]
+ }, {
+ .utf8_value = 107,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[74]
+ }, {
+ .utf8_value = 108,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[75]
+ }, {
+ .utf8_value = 109,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[76]
+ }, {
+ .utf8_value = 110,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[77]
+ }, {
+ .utf8_value = 111,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[78]
+ }, {
+ .utf8_value = 112,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[79]
+ }, {
+ .utf8_value = 113,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[80]
+ }, {
+ .utf8_value = 114,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[81]
+ }, {
+ .utf8_value = 115,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[82]
+ }, {
+ .utf8_value = 116,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[83]
+ }, {
+ .utf8_value = 117,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[84]
+ }, {
+ .utf8_value = 118,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[85]
+ }, {
+ .utf8_value = 119,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[86]
+ }, {
+ .utf8_value = 120,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[87]
+ }, {
+ .utf8_value = 121,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[88]
+ }, {
+ .utf8_value = 122,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[89]
+ }, {
+ .utf8_value = 123,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[90]
+ }, {
+ .utf8_value = 124,
+ .bbox = { 1, 1, 2, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[91]
+ }, {
+ .utf8_value = 125,
+ .bbox = { 0, 1, 4, 8 },
+ .data = &chars_data_Tamsyn5x9r_9[92]
+ }, {
+ .utf8_value = 126,
+ .bbox = { 0, 2, 4, 4 },
+ .data = &chars_data_Tamsyn5x9r_9[93]
+ }, {
+ .utf8_value = 161,
+ .bbox = { 1, 3, 2, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[94]
+ }, {
+ .utf8_value = 163,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[95]
+ }, {
+ .utf8_value = 171,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[96]
+ }, {
+ .utf8_value = 176,
+ .bbox = { 0, 2, 4, 5 },
+ .data = &chars_data_Tamsyn5x9r_9[97]
+ }, {
+ .utf8_value = 187,
+ .bbox = { 0, 4, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[98]
+ }, {
+ .utf8_value = 191,
+ .bbox = { 0, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[99]
+ }, {
+ .utf8_value = 196,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[100]
+ }, {
+ .utf8_value = 197,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[101]
+ }, {
+ .utf8_value = 198,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[102]
+ }, {
+ .utf8_value = 199,
+ .bbox = { 0, 2, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[103]
+ }, {
+ .utf8_value = 201,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[104]
+ }, {
+ .utf8_value = 209,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[105]
+ }, {
+ .utf8_value = 214,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[106]
+ }, {
+ .utf8_value = 165,
+ .bbox = { 0, 1, 5, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[107]
+ }, {
+ .utf8_value = 220,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[108]
+ }, {
+ .utf8_value = 223,
+ .bbox = { 0, 2, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[109]
+ }, {
+ .utf8_value = 224,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[110]
+ }, {
+ .utf8_value = 225,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[111]
+ }, {
+ .utf8_value = 226,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[112]
+ }, {
+ .utf8_value = 228,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[113]
+ }, {
+ .utf8_value = 229,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[114]
+ }, {
+ .utf8_value = 230,
+ .bbox = { 0, 3, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[115]
+ }, {
+ .utf8_value = 231,
+ .bbox = { 1, 3, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[116]
+ }, {
+ .utf8_value = 232,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[117]
+ }, {
+ .utf8_value = 233,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[118]
+ }, {
+ .utf8_value = 234,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[119]
+ }, {
+ .utf8_value = 235,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[120]
+ }, {
+ .utf8_value = 236,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[121]
+ }, {
+ .utf8_value = 237,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[122]
+ }, {
+ .utf8_value = 238,
+ .bbox = { 0, 0, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[123]
+ }, {
+ .utf8_value = 239,
+ .bbox = { 0, 1, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[124]
+ }, {
+ .utf8_value = 241,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[125]
+ }, {
+ .utf8_value = 242,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[126]
+ }, {
+ .utf8_value = 243,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[127]
+ }, {
+ .utf8_value = 244,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[128]
+ }, {
+ .utf8_value = 246,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[129]
+ }, {
+ .utf8_value = 247,
+ .bbox = { 0, 2, 3, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[130]
+ }, {
+ .utf8_value = 162,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[131]
+ }, {
+ .utf8_value = 249,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[132]
+ }, {
+ .utf8_value = 250,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[133]
+ }, {
+ .utf8_value = 251,
+ .bbox = { 0, 0, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[134]
+ }, {
+ .utf8_value = 252,
+ .bbox = { 0, 1, 4, 7 },
+ .data = &chars_data_Tamsyn5x9r_9[135]
+ }, {
+ .utf8_value = 255,
+ .bbox = { 0, 1, 4, 9 },
+ .data = &chars_data_Tamsyn5x9r_9[136]
+ }
+};
+
+const font_t font_Tamsyn5x9r_9 = {
+ .fontsize = 9,
+ .lineheight = 9,
+ .ascent = 7,
+ .descent = 2,
+ .charwidth = 5,
+ .char_count = 138,
+ .chars = chars_Tamsyn5x9r_9,
+ .chars_data = chars_data_Tamsyn5x9r_9,
+};
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.h
new file mode 100644
index 00000000..edb7c8b2
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/Tamsyn5x9r_9.h
@@ -0,0 +1,25 @@
+/*
+ * LICENSE - see http://www.fial.com/~scott/tamsyn-font/
+ *
+ *
+ * Tamsyn font is free. You are hereby granted permission to use, copy,
+ * modify, and distribute it as you see fit.
+ *
+ * Tamsyn font is provided "as is" without any express or implied
+ * warranty.
+ *
+ * The author makes no representations about the suitability of this
+ * font for a particular purpose.
+ * In no event will the author be held liable for damages arising from
+ * the use of this font.
+ */
+
+#ifndef _TAMSYN5X9R_9_
+#define _TAMSYN5X9R_9_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_Tamsyn5x9r_9;
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/fonts.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/fonts.h
new file mode 100644
index 00000000..9e0c157e
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/fonts.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+/**
+ * Fonts library
+ */
+#ifndef FONTS_H
+#define FONTS_H
+
+#include
+#include
+
+/*
+ * the holds the offsets for the data relative to the default char size
+ * and the data width/height
+ * eg. :
+ * m,o = font.getmask2(c, mode="1")
+ * bbox = m.getbbox()
+ * x1 = (charwidth - bbox[2])/2
+ * y1 = (o[1]-offset[1] + bbox[1])
+ * x2 = x1 + bbox[2]-bbox[0]
+ * y2 = y1 + bbox[3]-bbox[1]
+ */
+typedef struct {
+ uint32_t x1, y1, x2, y2;
+} char_data_bbox_t;
+
+typedef struct {
+ uint32_t utf8_value;
+ char_data_bbox_t bbox;
+ const uint32_t *data; /* pointer to char_data_offset */
+} char_t;
+
+typedef struct {
+ uint8_t fontsize;
+ uint8_t lineheight;
+ uint8_t ascent;
+ uint8_t descent;
+ uint8_t charwidth;
+ uint16_t char_count;
+ /* pointer to chars array (sorted by utf8_value) */
+ const char_t *chars;
+ /* pointer to chars_data array */
+ const uint32_t *chars_data;
+} font_t;
+
+/* binary search for char */
+static inline
+const char_t*
+font_get_char_index(uint32_t utf8_value, const font_t *font) {
+ uint32_t s, e, i, j, cc;
+ s = j = 0;
+ e = font->char_count-1;
+ while (1) {
+ i = (s+e)>>1;
+ cc = font->chars[i].utf8_value;
+ if (utf8_value < cc) {
+ e = i;
+ } else
+ if (utf8_value > cc) {
+ s = i;
+ } else {
+ return &font->chars[i];
+ }
+ if (i == j) {
+ return NULL;
+ }
+ j = i;
+ }
+}
+
+#endif
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/create_font.py b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/create_font.py
new file mode 100755
index 00000000..7e6cd7f2
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/create_font.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+# This file is part of the libopencm3 project.
+#
+# Copyright (C) 2016 Oliver Meier
+#
+# This library is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see .
+#
+
+
+from sys import argv,stdout
+from os.path import isfile, dirname, basename, splitext, join
+from PIL import Image, ImageFont, ImageDraw
+import codecs
+
+print len(argv),argv
+
+if len(argv)<3 or len(argv)>4 or (len(argv)==4 and not isfile(argv[3])) :
+ print "usage: ./Create_Font.py ./font.ttf fontsize [charsetfile-utf8.txt]"
+ print " - ./font.ttf can also be ./font.pcf or something like Arial or so
+ exit(0)
+
+fontfile = argv[1]
+fontsize = None
+try :
+ fontsize = int(argv[2])
+except :
+ print "Fontsize is not a number!"
+ exit(0)
+
+if len(argv)==4 :
+ charsetfile = argv[3]
+else :
+ charsetfile = join(dirname(argv[0]),"default_charset.txt")
+
+
+#fontfile = "Tamsyn5x9r.pcf"
+#fontfile = "Tamsyn5x9b.pcf"
+#fontfile = "/usr/share/fonts/liberation/LiberationMono-Regular.ttf"
+#fontfile = "/usr/share/fonts/liberation/LiberationMono-Bold.ttf"
+#fontfile = "/usr/share/fonts/dejavu/DejaVuSansMono.ttf"
+#fontfile = "/usr/share/fonts/dejavu/DejaVuSansMono-Bold.ttf"
+#fontfile = "/usr/share/fonts/gnu-free/FreeMono.ttf"
+#fontfile = "Arial"
+#fontsize = 9
+datasize = 32
+
+charset = codecs.open(charsetfile,'r','utf-8').read().replace('\n','').replace('\r','')
+# sort charset and remove duplicates
+charset = ''.join(sorted(set(charset), key=charset.index))
+font = ImageFont.truetype(fontfile,size=fontsize)
+
+filtered_charset = u""
+for c in charset :
+ if c<>u' ' :
+ m,o = font.getmask2(c, mode="1")
+ if m.getbbox()==None :
+ print "Dropping:",c.encode('utf-8')
+ continue
+ filtered_charset+=c
+charset = filtered_charset
+
+
+
+#render all the text (needed to determine img size)
+dummy_img,offset = font.getmask2(charset, mode="1")
+
+ascent,descent = font.getmetrics()
+lineheight = dummy_img.size[1]+offset[1]
+charwidth = font.getsize("MMM")[0]-font.getsize("MM")[0]
+totalwidth = charwidth*len(charset)
+charset_imgsize = (totalwidth,lineheight)
+
+
+
+charset_image = Image.new(mode="1", size=charset_imgsize)
+d=ImageDraw.Draw(charset_image)
+d.rectangle(((0,0),charset_imgsize), fill=0, outline=None)
+offx=0
+
+
+fontname = splitext(basename(fontfile))[0]+"_"+str(fontsize)
+fontname = fontname.replace("-","_")
+
+print "Creating font", fontname
+
+
+chars_table_name = "chars_"+fontname
+data_table_name = "chars_data_"+fontname
+chars_table = "static const char_t "+chars_table_name+"[] = {\n\t"
+data_table = "static const uint"+str(datasize)+"_t "+data_table_name+"[] = {"
+data_table_offset = 0; v=0; i=0; fmt = "0x%%0%dx,"%(datasize/8*2)
+for c in charset :
+ x1 = y1 = x2 = y2 = 0
+ bbox = (0,0,0,0)
+ if c<>u' ' :
+ m,o = font.getmask2(c, mode="1")
+ bbox = m.getbbox()
+ x1 = (charwidth - bbox[2])/2
+ y1 = (o[1]-offset[1] + bbox[1])
+ x2 = x1 + bbox[2]-bbox[0]
+ y2 = y1 + bbox[3]-bbox[1]
+
+
+ stdout.write((u"%s"%c).encode('utf-8'))
+ #print "",x1,x2,y1,y2
+
+ # dummy image
+ if c<>u' ' :
+ d.draw.draw_bitmap((offx+x1,y1),m.crop(bbox),255)
+ offx += charwidth
+
+ # fill data in chars table
+ chars_table+= """{
+ .utf8_value = %d,
+ .bbox = { % 2d,% 2d,% 2d,% 2d },
+ .data = &%s[%d]
+ }, """ %(
+ ord(c),
+ x1,y1,x2,y2,
+ data_table_name,data_table_offset
+ )
+
+ # fill data in chars data table
+ data_table+= "\n\t/* '%s' */\n\t" %c
+
+ i=0; v=0; lc = 0
+ for y in range(bbox[1],bbox[3]) :
+ for x in range(bbox[0],bbox[2]) :
+ v |= (m.getpixel((x,y))==255) << i
+ i+=1
+ if i==datasize :
+ if lc > 0 : data_table += " "
+ data_table += fmt %v
+ i=0; v=0
+ data_table_offset += 1
+ lc+=1
+ if lc==4 :
+ data_table += "\n\t"
+ lc=0
+
+ # finish last data_table entry
+ if v<>0 :
+ if lc > 0 : data_table += " "
+ data_table += fmt %v
+ data_table_offset += 1
+ elif lc==0 :
+ data_table = data_table[:-1]
+
+data_table = data_table[:-1] + "\n};"
+
+chars_table = chars_table[:-2] + "\n};"
+
+
+charset_image.save(fontname+".pbm")
+
+
+fnu = fontname.upper()
+
+fontsize_definition = "%s %d"%(fnu,fontsize)
+
+header_filename = "%s.h"%fontname
+header_file = """
+#ifndef _%s_
+#define _%s_
+
+#include
+#include "fonts.h"
+
+extern const font_t font_%s;
+
+#endif
+""" %(
+ fnu,fnu,
+ fontname
+)
+
+c_filename = "%s.c"%fontname
+c_file = """
+#include "%s"
+
+%s
+
+%s
+
+const font_t font_%s = {
+ .fontsize = %d,
+ .lineheight = %d,
+ .ascent = %d,
+ .descent = %d,
+ .charwidth = %d,
+ .char_count = %d,
+ .chars = %s,
+ .chars_data = %s,
+};
+
+""" %(
+ header_filename,
+ data_table,
+ chars_table,
+ fontname, fontsize, lineheight, ascent, descent, charwidth,
+ len(charset),chars_table_name, data_table_name,
+)
+
+
+open(header_filename,'w').write(header_file.encode('utf-8'))
+open(c_filename,'w').write(c_file.encode('utf-8'))
+
+print "\ndone."
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/default_charset.txt b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/default_charset.txt
new file mode 100644
index 00000000..9a2864c7
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/default_charset.txt
@@ -0,0 +1 @@
+ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡╜£╧╛▌⌡∙╕ª«¬≡⌐ε°±²ⁿ∩µ⌠·≈√º»¼½≤¿╖╡╢╟ÄÅÆÇ╘É╥╙▐╓╫╪╤ÑπαΓσÖ₧¥δΘΩÜφΦßàáâ╞äåæçèéêëìíîï╨ñòóôΣö÷¢ùúûü∞τÿΩ
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/image_to_rgb565-array.py b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/image_to_rgb565-array.py
new file mode 100755
index 00000000..b55f4f5a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/tools/image_to_rgb565-array.py
@@ -0,0 +1,80 @@
+# This file is part of the libopencm3 project.
+#
+# Copyright (C) 2016 Oliver Meier
+#
+# This library is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see .
+#
+
+from PIL import Image
+from sys import argv
+from os.path import isfile, splitext
+from math import floor
+
+if (not(len(argv)==2 or len(argv)==3)) or not isfile(argv[1]) :
+ print "usage Image...py filename.png width_in_px"
+ exit(0)
+
+infile = argv[1]
+
+basename = splitext(infile)[0]
+outfile = basename+"_RGB565.h"
+if isfile(outfile) :
+ print outfile , "already exists"
+ exit(0)
+
+
+# die here if not an image
+try :
+ img = Image.open(infile)
+except IOError, ex :
+ print "Opening image failed"
+ print "\tPIL(IOError) :",ex.message
+ exit(0)
+
+if len(argv)==3 :
+ try :
+ width = int(argv[2])
+ if img.size[0]<>width :
+ new_size = (width,int(img.size[1]*width/img.size[0]))
+ print "resizing image from",img.size,"to",new_size
+ img = img.resize(new_size,Image.ANTIALIAS)
+ img.show(title="Resized image")
+ except :
+ print "Invalid width"
+ print "usage Image...py filename.png width_in_px"
+ exit(0)
+
+print "image size is",img.size
+width = img.size[0]
+data = img.tobytes(encoder_name='raw')
+
+pixels_per_line = 16
+of = open(outfile,'w')
+of.write("#include \n")
+of.write("#define %s_WIDTH %d\n" %(basename.upper(), width))
+of.write("#define %s_HEIGHT %d\n" %(basename.upper(), len(data)/4/width))
+of.write("const uint16_t %s[] = {" %(basename))
+i = 0
+while i>3); i+=1
+ g = int(ord(data[i])>>2); i+=1
+ b = int(ord(data[i])>>3); i+=1
+ i+=1 # skip alpha
+ i16 = (r<<11) | (g<<5) | b
+ of.write("0x%04x" %(i16))
+of.write("\n};")
+of.close()
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/utf8.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/utf8.h
new file mode 100644
index 00000000..24cf2142
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/fonts/utf8.h
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef UTF8_H_
+#define UTF8_H_
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include
+
+/**
+ *
+ * @param text utf8 string
+ * @param value pointer which holds the utf value after the function returns
+ * @return pointer to the next value in string (-1 for invalid value)
+ */
+static inline
+const char *
+utf8_read_value(const char *text, int32_t *value)
+{
+ char tmp; uint8_t cnt, i;
+
+ tmp = *text++;
+
+ if (!(tmp & 0b10000000)) {
+ *value = tmp;
+ return text;
+ } else
+ if ((tmp & 0b11100000) == 0b11000000) {
+ *value = tmp & ~0b11100000;
+ cnt = 1;
+ } else
+ if ((tmp & 0b11110000) == 0b11100000) {
+ *value = tmp & ~0b11110000;
+ cnt = 2;
+ } else
+ if ((tmp & 0b11111000) == 0b11110000) {
+ *value = tmp & ~0b11111000;
+ cnt = 3;
+ } else {
+ *value = -1;
+ return text;
+ }
+
+ for (i = cnt; i; i--) {
+ tmp = *text++;
+ if ((tmp & 0b11000000) != 0b10000000) {
+ *value = -1;
+ return text;
+ }
+
+ *value = (*value<<6) | (tmp & ~0b11000000);
+ }
+
+ return text;
+}
+
+
+/* utf-8 ... */
+static inline
+const char *
+utf8_find_character_index(
+ int index,
+ const char *text_start, const char *text_end,
+ int *index_rest
+) {
+ const char *result;
+ if (index < 0) {
+ result = text_end;
+ while (index && result != text_start) {
+ index++;
+ result--;
+ /* skip next utf8-character (secondary bytes) */
+ while (((*result)&192) == 128 && result != text_start) {
+ result--;
+ }
+ }
+ } else {
+ result = text_start;
+ while (index && result != text_end) {
+ index--;
+ result++;
+ /* skip last utf8-character (secondary bytes) */
+ while (((*result)&192) == 128 && result != text_end) {
+ result++;
+ }
+ }
+ }
+
+ if (index_rest != NULL) {
+ *index_rest = index;
+ }
+
+ return result;
+}
+
+
+/* untestet! */
+static inline
+const char *utf8_find_character_in_string(
+ const char chr,
+ const char *text_start, const char *text_end
+ /*, int *index_rest */
+) {
+ const char *result = text_start;
+ while (result != text_end) {
+ if (*result == chr) {
+ break;
+ }
+ result = utf8_find_character_index(1, result, text_end, NULL);
+ }
+ return result;
+}
+static inline
+int utf8_find_pointer_diff(const char *text_start, const char *text_end)
+{
+ int diff = 0;
+ while (text_start < text_end) {
+ if (!*text_start) {
+ return -1;
+ }
+
+ text_start++;
+ diff++;
+ /* skip last utf8-character (secondary bytes) */
+ while (((*text_start)&192) == 128 && text_start < text_end) {
+ text_start++;
+ }
+ }
+ return diff;
+}
+
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.c
new file mode 100644
index 00000000..1d1f649a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.c
@@ -0,0 +1,1311 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ *
+ *
+ * This code is based on a fork off a graphics example for libopencm3 made
+ * by Charles McManis in 2014.
+ * The basic drawing functions (circle, line, round-rectangle) are based on
+ * the simple graphics library written by the folks at AdaFruit.
+ * [Adafruit_GFX.cpp](/adafruit/Adafruit-GFX-Library/blob/master/Adafruit_GFX.cpp)
+ *
+ * Graphics lib, possible history
+ * --Probably Knuth, Ada and/or Plato
+ * --WIKIPEDIA
+ * --ADAFRUIT (?, 2013)
+ * --Chuck McManis (2013, 2014)
+ * --Tilen Majerle (2014)
+ * --Oliver Meier (2014+)
+ */
+
+
+#include "gfx_locm3.h"
+
+gfx_state_t __gfx_state = {0};
+
+/*
+ * Make sure the surface is aligned for 32bit!
+ */
+void
+gfx_init(uint16_t *surface, int32_t width, int32_t height)
+{
+ __gfx_state.is_offscreen_rendering = 0;
+
+ *(uint16_t *)&__gfx_state.width_orig = width;
+ *(uint16_t *)&__gfx_state.height_orig = height;
+ *(uint32_t *)&__gfx_state.pixel_count = (uint32_t)width*(uint32_t)height;
+ __gfx_state.width = width;
+ __gfx_state.height = height;
+ __gfx_state.visible_area = (visible_area_t){0, 0, width, height};
+ __gfx_state.rotation = 0;
+ __gfx_state.cursor_y = __gfx_state.cursor_x = __gfx_state.cursor_x_orig
+ = 0;
+ __gfx_state.fontscale = 1;
+ __gfx_state.textcolor = 0;
+ __gfx_state.wrap = true;
+ __gfx_state.surface = surface;
+ __gfx_state.font = NULL;
+}
+
+static gfx_state_t __gfx_state_bkp = {0};
+
+void gfx_set_surface(uint16_t *surface)
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ __gfx_state_bkp.surface = surface;
+ } else {
+ __gfx_state.surface = surface;
+ }
+}
+uint16_t *
+gfx_get_surface()
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ return __gfx_state_bkp.surface;
+ } else {
+ return __gfx_state.surface;
+ }
+}
+
+void gfx_offscreen_rendering_begin(
+ uint16_t *surface,
+ int32_t width,
+ int32_t height
+) {
+ if (!__gfx_state.is_offscreen_rendering) {
+ /*gfx_state_bkp = __gfx_state; ???*/
+ memcpy(&__gfx_state_bkp, &__gfx_state, sizeof(gfx_state_t));
+ }
+ gfx_init(surface, width, height);
+ __gfx_state.is_offscreen_rendering = 1;
+}
+void gfx_offscreen_rendering_end()
+{
+ if (__gfx_state.is_offscreen_rendering) {
+ memcpy(&__gfx_state, &__gfx_state_bkp, sizeof(gfx_state_t));
+ }
+}
+
+void
+gfx_set_clipping_area_max()
+{
+ __gfx_state.visible_area =
+ (visible_area_t){
+ 0, 0, __gfx_state.width, __gfx_state.height
+ };
+}
+void
+gfx_set_clipping_area(int16_t x1, int16_t y1, int16_t x2, int16_t y2) {
+ if (x1 < 0) {
+ x1 = 0;
+ }
+ if (y1 < 0) {
+ y1 = 0;
+ }
+ if (x2 < x1) {
+ x2 = x1;
+ }
+ if (y2 < y1) {
+ y2 = y1;
+ }
+ __gfx_state.visible_area = (visible_area_t){x1, y1, x2, y2};
+}
+visible_area_t
+gfx_get_surface_visible_area() {
+ return __gfx_state.visible_area;
+}
+
+
+/*
+ * just write a RGB565 color to each pixel in the current buffer/surface
+ * this function assumes 32bit aligned buffer!
+ */
+void gfx_fill_screen(uint16_t color)
+{
+ uint32_t color2 = (color<<16)|color;
+
+ uint32_t i; uint32_t *pixel_addr;
+ pixel_addr = (uint32_t *)__gfx_state.surface;
+ for (i = 0; i < __gfx_state.pixel_count/2; i++) {
+ *pixel_addr++ = color2;
+ }
+ if (__gfx_state.pixel_count & 1) {
+ *(__gfx_state.surface+(__gfx_state.pixel_count-1)) = color;
+ }
+
+ /*
+ uint32_t i; uint16_t *pixel_addr;
+ pixel_addr = __gfx_state.surface;
+ for (i = 0; i < __gfx_state.pixel_count&1; i++) {
+ *pixel_addr++ = color;
+ }
+ */
+}
+
+
+
+/* change the rotation and flip width and height accordingly */
+void gfx_set_rotation(gfx_rotation_t rotation)
+{
+ if ((rotation == GFX_ROTATION_0_DEGREES)
+ || (rotation == GFX_ROTATION_180_DEGREES)
+ ) {
+ __gfx_state.width = __gfx_state.width_orig;
+ __gfx_state.height = __gfx_state.height_orig;
+ } else {
+ __gfx_state.width = __gfx_state.height_orig;
+ __gfx_state.height = __gfx_state.width_orig;
+ }
+ __gfx_state.rotation = rotation;
+ gfx_set_clipping_area_max();
+}
+gfx_rotation_t gfx_get_rotation(void)
+{
+ return __gfx_state.rotation;
+}
+/* Return the size of the display (per current rotation) */
+uint16_t gfx_width(void)
+{
+ return __gfx_state.width;
+}
+
+uint16_t gfx_height(void)
+{
+ return __gfx_state.height;
+}
+
+
+/* GFX_GLOBAL_DISPLAY_SCALE can be used as a zoom function
+ * while debugging code..
+ *
+ * NOTE: This breaks offscreen rendering!!
+ */
+#define GFX_GLOBAL_DISPLAY_SCALE 1
+
+static inline uint16_t *gfx_get_pixel_address(int16_t x, int16_t y)
+{
+ uint16_t *pixel_addr;
+ pixel_addr = __gfx_state.surface;
+ switch (__gfx_state.rotation) {
+ case GFX_ROTATION_0_DEGREES:
+ pixel_addr += (x + y*__gfx_state.width_orig);
+ break;
+ case GFX_ROTATION_270_DEGREES:
+ pixel_addr += (x*__gfx_state.width_orig + __gfx_state.width_orig - y) - GFX_GLOBAL_DISPLAY_SCALE;
+ break;
+ case GFX_ROTATION_180_DEGREES:
+ pixel_addr += __gfx_state.pixel_count - (x + (y + (GFX_GLOBAL_DISPLAY_SCALE-1)) * __gfx_state.width_orig) - GFX_GLOBAL_DISPLAY_SCALE;
+ break;
+ case GFX_ROTATION_90_DEGREES:
+ pixel_addr += __gfx_state.pixel_count - ((x + (GFX_GLOBAL_DISPLAY_SCALE-1)) * __gfx_state.width_orig + __gfx_state.width_orig-y);
+ break;
+ }
+ return pixel_addr;
+}
+
+
+#if GFX_GLOBAL_DISPLAY_SCALE > 1
+#define GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X -10
+#define GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y -40
+
+/*
+ * draw a single pixel
+ * changes buffer addressing (surface) according to orientation
+ */
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color)
+{
+ x += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X;
+ y += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y;
+ x *= GFX_GLOBAL_DISPLAY_SCALE;
+ y *= GFX_GLOBAL_DISPLAY_SCALE;
+
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ ) {
+ return;
+ }
+
+ uint16_t *pa = gfx_get_pixel_address(x, y);
+ for (uint32_t sa = 0; sa < GFX_GLOBAL_DISPLAY_SCALE; sa++) {
+ for (uint32_t sb = 0; sb < GFX_GLOBAL_DISPLAY_SCALE; sb++) {
+ *(pa+sb) = color;
+ }
+ pa += __gfx_state.width_orig;
+ }
+
+ return;
+}
+
+/*
+ * get a single pixel
+ */
+int32_t gfx_get_pixel(int16_t x, int16_t y)
+{
+ x += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_X;
+ y += GFX_GLOBAL_DISPLAY_SCALE_OFFSET_Y;
+ x *= GFX_GLOBAL_DISPLAY_SCALE;
+ y *= GFX_GLOBAL_DISPLAY_SCALE;
+
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2 - GFX_GLOBAL_DISPLAY_SCALE+1
+ ) {
+ return -1;
+ }
+
+ return *gfx_get_pixel_address(x, y);
+}
+
+#else
+
+/*
+ * draw a single pixel
+ * changes buffer addressing (surface) according to orientation
+ */
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color)
+{
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2
+ ) {
+ return;
+ }
+
+ *gfx_get_pixel_address(x, y) = color;
+
+ return;
+}
+
+/*
+ * get a single pixel
+ */
+int32_t gfx_get_pixel(int16_t x, int16_t y)
+{
+ if (
+ x < __gfx_state.visible_area.x1
+ || x >= __gfx_state.visible_area.x2
+ || y < __gfx_state.visible_area.y1
+ || y >= __gfx_state.visible_area.y2
+ ) {
+ return -1;
+ }
+
+ return *gfx_get_pixel_address(x, y);
+}
+#endif
+
+typedef struct {
+ int16_t ud_dir;
+ int16_t x0, x1;
+ int16_t y; /* actually y-ud_dir.. */
+} fill_segment_t;
+typedef struct {
+ size_t size;
+ fill_segment_t *data;
+ size_t count;
+ fill_segment_queue_statistics_t stats;
+} fill_segment_queue_t;
+
+//#define SHOW_FILLING
+#ifdef SHOW_FILLING
+#include "lcd_ili9341.h"
+#include
+#include "clock.h"
+#endif
+
+
+static inline void gfx_flood_fill4_add_if_found(
+ fill_segment_queue_t *queue,
+ int16_t ud_dir,
+ int16_t xa0, int16_t xa1,
+ int16_t y,
+ uint16_t old_color
+) {
+ y += ud_dir;
+ while ((xa0 <= xa1)) {
+ if (gfx_get_pixel(xa0, y) == old_color) {
+ if (queue->count < queue->size) {
+ queue->data[queue->count++] =
+ (fill_segment_t) {
+ .ud_dir = ud_dir,
+ .x0 = xa0,
+ .x1 = xa1,
+ .y = y-ud_dir
+ };
+ } else {
+ queue->stats.overflows++;
+ }
+ return;
+ }
+ xa0++;
+ }
+}
+
+/* warning! this function might be very slow and fail:) */
+fill_segment_queue_statistics_t
+gfx_flood_fill4(
+ int16_t x, int16_t y,
+ uint16_t old_color, uint16_t new_color,
+ uint8_t fill_segment_buf[], size_t fill_segment_buf_size
+) {
+ if (old_color == new_color) {
+ return (fill_segment_queue_statistics_t){0};
+ }
+
+ if (gfx_get_pixel(x, y) != old_color) {
+ return (fill_segment_queue_statistics_t){0};
+ }
+
+ fill_segment_queue_t queue = {
+ .size = fill_segment_buf_size/sizeof(fill_segment_t),
+ .data = (fill_segment_t *)fill_segment_buf,
+ .count = 0,
+ .stats = (fill_segment_queue_statistics_t) {
+ .count_max = 0,
+ .count_total = 0,
+ .overflows = 0,
+ }
+ };
+
+
+ int16_t sx, sy;
+
+ int16_t ud_dir_init = 1;
+ int16_t ud_dir = 1;
+
+ int16_t x0, x1, x0l, x1l, x0ll, x1ll;
+
+ bool pixel_drawn = false;
+
+ sx = x;
+ sy = y;
+
+ /* process first line */
+ x--; /* x is always increased first! */
+ while (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+ pixel_drawn = true;
+ }
+ x1l = x1ll = x-1;
+ x = sx;
+ while (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+ pixel_drawn = true;
+ }
+ x0l = x0ll = x+1;
+
+#ifdef SHOW_FILLING
+ ltdc_set_fbuffer_address(LTDC_LAYER_2, (uint32_t)__gfx_state.surface);
+#endif
+
+ while (pixel_drawn) {
+ pixel_drawn = false;
+
+#ifdef SHOW_FILLING
+ if (!LTDC_SRCR_IS_RELOADING()) {
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+ }
+#endif
+ y += ud_dir;
+
+ /* find x start point (must be between x0 and x1 of the last iteration) */
+ sx = x0l;
+ while ((sx < x1l) && (gfx_get_pixel(sx, y) != old_color)) {
+ sx++;
+ }
+
+ bool sx_was_oc = gfx_get_pixel(sx, y) == old_color;
+
+ /** middle to right */
+ x = sx-1;
+ /* fill additional adjacent old-colored pixels */
+ while (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ pixel_drawn = true;
+ }
+ x1 = x-1;
+ /* check if x1 is bigger compared to the last line */
+ if (x1 > x1l+1) {
+ if (queue.count < queue.size) {
+ queue.data[queue.count++] =
+ (fill_segment_t) {
+ .ud_dir = -ud_dir,
+ .x0 = x1l,
+ .x1 = x1,
+ .y = y
+ };
+ } else {
+ queue.stats.overflows++;
+ }
+ } else {
+ /* fill all lastline-adjacent old-colored pixels */
+ bool adjacent_pixel_drawn = false;
+ int16_t xa0=0, xa1;
+ while ((x < x1l) || adjacent_pixel_drawn) {
+ if (gfx_get_pixel(++x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ if (!adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = true;
+ xa0 = x;
+ }
+ } else
+ if (adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = false;
+ xa1 = x-1;
+
+ gfx_flood_fill4_add_if_found(&queue, ud_dir, xa0, xa1, y, old_color);
+ if (xa1 > x1l+1) {
+ gfx_flood_fill4_add_if_found(&queue, -ud_dir, x1l+1, xa1, y, old_color);
+ }
+ }
+ }
+ }
+ x1l = x1;
+
+
+ /** middle-1 to left */
+ x = sx;
+ if ((sx > x0l) || sx_was_oc) {
+ /* fill additional adjacent old-colored pixels */
+ while (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ pixel_drawn = true;
+ }
+ x0 = x+1;
+ } else {
+ x0 = sx;
+ x--;
+ }
+ /* check if x0 is smaller compared to the last line */
+ if (x0 < x0l-1) {
+ if (queue.count < queue.size) {
+ queue.data[queue.count++] =
+ (fill_segment_t) {
+ .ud_dir = -ud_dir,
+ .x0 = x0,
+ .x1 = x0l,
+ .y = y
+ };
+ } else {
+ queue.stats.overflows++;
+ }
+ } else {
+ /* fill all lastline-adjacent old-colored pixels */
+ bool adjacent_pixel_drawn = false;
+ int16_t xa0, xa1 = 0;
+ while ((x > x0l) || adjacent_pixel_drawn) {
+ if (gfx_get_pixel(--x, y) == old_color) {
+ gfx_draw_pixel(x, y, new_color);
+#ifdef SHOW_FILLING
+ msleep_loop(1);
+#endif
+ if (!adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = true;
+ xa1 = x;
+ }
+ } else
+ if (adjacent_pixel_drawn) {
+ adjacent_pixel_drawn = false;
+ xa0 = x+1;
+
+ gfx_flood_fill4_add_if_found(&queue, ud_dir, xa0, xa1, y, old_color);
+ if (xa0 < x0l-1) {
+ gfx_flood_fill4_add_if_found(&queue, -ud_dir, xa0, x0l-1, y, old_color);
+ }
+ }
+ }
+ }
+ x0l = x0;
+
+ /** no pixel draw, check if we're already filling upwards */
+ if (!pixel_drawn) {
+ if (ud_dir == ud_dir_init) {
+ pixel_drawn = true;
+ ud_dir = -1;
+ y = sy;
+ x0l = x0ll;
+ x1l = x1ll;
+ } else {
+ ud_dir_init = 2; /* filling saved segments */
+
+ queue.stats.count_total++;
+ if (queue.stats.count_max < queue.count) {
+ queue.stats.count_max = queue.count;
+ }
+
+ if (queue.count) {
+ queue.count--;
+ ud_dir = queue.data[queue.count].ud_dir;
+ x0l = queue.data[queue.count].x0;
+ x1l = queue.data[queue.count].x1;
+ /* sx = (x0l+x1l)/2; */
+ y = queue.data[queue.count].y;
+ pixel_drawn = true;
+
+#ifdef SHOW_FILLING
+ assert(x0l <= x1l);
+#endif
+ }
+ }
+ }
+ }
+
+#ifdef SHOW_FILLING
+ msleep_loop(5000);
+#endif
+
+ return queue.stats;
+}
+
+
+/* Bresenham's algorithm - thx wikpedia */
+void gfx_draw_line(int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ uint16_t fg) {
+ int16_t steep = abs(y1 - y0) > abs(x1 - x0);
+ if (steep) {
+ swap_i16(x0, y0);
+ swap_i16(x1, y1);
+ }
+
+ if (x0 > x1) {
+ swap_i16(x0, x1);
+ swap_i16(y0, y1);
+ }
+
+ int16_t dx, dy;
+ dx = x1 - x0;
+ dy = abs(y1 - y0);
+
+ int16_t err = dx / 2;
+ int16_t ystep;
+
+ if (y0 < y1) {
+ ystep = 1;
+ } else {
+ ystep = -1;
+ }
+
+ for (; x0 <= x1; x0++) {
+ if (steep) {
+ gfx_draw_pixel(y0, x0, fg);
+ } else {
+ gfx_draw_pixel(x0, y0, fg);
+ }
+ err -= dy;
+ if (err < 0) {
+ y0 += ystep;
+ err += dx;
+ }
+ }
+}
+void gfx_draw_hline(int16_t x, int16_t y, int16_t length, uint16_t color)
+{
+ if (length < 0) {
+ length = -length;
+ x -= length;
+ }
+ while (length--) {
+ gfx_draw_pixel(x++, y, color);
+ }
+}
+void gfx_draw_vline(int16_t x, int16_t y, int16_t length, uint16_t color)
+{
+ if (length < 0) {
+ length = -length;
+ y -= length;
+ }
+ while (length--) {
+ gfx_draw_pixel(x, y++, color);
+ }
+}
+
+void gfx_draw_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
+{
+ int16_t x_s, y_e;
+ if (w < 0) {
+ w = -w;
+ x -= w;
+ }
+ if (h < 0) {
+ h = -h;
+ x -= h;
+ }
+ x_s = x;
+ y_e = y+h-1;
+ while (w-- != 0) {
+ gfx_draw_pixel(x, y , color);
+ gfx_draw_pixel(x, y_e, color);
+ x++;
+ }
+ x--;
+ while (h-- != 0) {
+ gfx_draw_pixel(x_s, y, color);
+ gfx_draw_pixel(x , y, color);
+ y++;
+ }
+}
+
+void gfx_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t fg) {
+
+ int16_t i;
+ for (i = x; i < x+w; i++) {
+ gfx_draw_vline(i, y, h, fg);
+ }
+}
+
+
+
+
+/* Draw RGB565 data */
+void gfx_draw_raw_rbg565_buffer(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img
+) {
+ int16_t x_cp, w_cp;
+ while (h--) {
+ x_cp = x;
+ w_cp = w;
+ while (w_cp--) {
+ gfx_draw_pixel(x_cp, y, *img++);
+ x_cp++;
+ }
+ y++;
+ }
+}
+
+/* Draw RGB565 data, do not draw ignored_color */
+void gfx_draw_raw_rbg565_buffer_ignore_color(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img,
+ uint16_t ignored_color
+) {
+ int16_t x_cp, w_cp;
+ while (h--) {
+ x_cp = x;
+ w_cp = w;
+ while (w_cp--) {
+ if (*img != ignored_color) {
+ gfx_draw_pixel(x_cp, y, *img);
+ }
+ img++;
+
+ x_cp++;
+ }
+ y++;
+ }
+}
+
+/* Draw a circle outline */
+void gfx_draw_circle(int16_t x0, int16_t y0, int16_t r, uint16_t fg)
+{
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ gfx_draw_pixel(x0 , y0+r, fg);
+ gfx_draw_pixel(x0 , y0-r, fg);
+ gfx_draw_pixel(x0+r, y0 , fg);
+ gfx_draw_pixel(x0-r, y0 , fg);
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+
+ gfx_draw_pixel(x0 + x, y0 + y, fg);
+ gfx_draw_pixel(x0 - x, y0 + y, fg);
+ gfx_draw_pixel(x0 + x, y0 - y, fg);
+ gfx_draw_pixel(x0 - x, y0 - y, fg);
+ gfx_draw_pixel(x0 + y, y0 + x, fg);
+ gfx_draw_pixel(x0 - y, y0 + x, fg);
+ gfx_draw_pixel(x0 + y, y0 - x, fg);
+ gfx_draw_pixel(x0 - y, y0 - x, fg);
+ }
+}
+
+void gfx_draw_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername,
+ uint16_t fg
+) {
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+ if (cornername & 0x4) {
+ gfx_draw_pixel(x0 + x, y0 + y, fg);
+ gfx_draw_pixel(x0 + y, y0 + x, fg);
+ }
+ if (cornername & 0x2) {
+ gfx_draw_pixel(x0 + x, y0 - y, fg);
+ gfx_draw_pixel(x0 + y, y0 - x, fg);
+ }
+ if (cornername & 0x8) {
+ gfx_draw_pixel(x0 - y, y0 + x, fg);
+ gfx_draw_pixel(x0 - x, y0 + y, fg);
+ }
+ if (cornername & 0x1) {
+ gfx_draw_pixel(x0 - y, y0 - x, fg);
+ gfx_draw_pixel(x0 - x, y0 - y, fg);
+ }
+ }
+}
+
+void gfx_fill_circle(
+ int16_t x0, int16_t y0,
+ int16_t r,
+ uint16_t fg
+) {
+ gfx_draw_vline(x0, y0-r, 2*r+1, fg);
+ gfx_fill_circle_helper(x0, y0, r, 3, 0, fg);
+}
+
+/* Used to do circles and roundrects */
+void gfx_fill_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername, int16_t delta,
+ uint16_t fg
+) {
+ int16_t f = 1 - r;
+ int16_t dd_f_x = 1;
+ int16_t dd_f_y = -2 * r;
+ int16_t x = 0;
+ int16_t y = r;
+
+ while (x < y) {
+ if (f >= 0) {
+ y--;
+ dd_f_y += 2;
+ f += dd_f_y;
+ }
+ x++;
+ dd_f_x += 2;
+ f += dd_f_x;
+
+ if (cornername & 0x1) {
+ gfx_draw_vline(x0+x, y0-y, 2*y+1+delta, fg);
+ gfx_draw_vline(x0+y, y0-x, 2*x+1+delta, fg);
+ }
+ if (cornername & 0x2) {
+ gfx_draw_vline(x0-x, y0-y, 2*y+1+delta, fg);
+ gfx_draw_vline(x0-y, y0-x, 2*x+1+delta, fg);
+ }
+ }
+}
+
+
+/* Draw a rounded rectangle */
+void gfx_draw_round_rect(
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ int16_t r,
+ uint16_t fg
+) {
+ /* smarter version */
+ gfx_draw_hline(x+r , y , w-2*r, fg); /* Top */
+ gfx_draw_hline(x+r , y+h-1, w-2*r, fg); /* Bottom */
+ gfx_draw_vline(x , y+r , h-2*r, fg); /* Left */
+ gfx_draw_vline(x+w-1, y+r , h-2*r, fg); /* Right */
+ /* draw four corners */
+ gfx_draw_circle_helper(x+r , y+r , r, 1, fg);
+ gfx_draw_circle_helper(x+w-r-1, y+r , r, 2, fg);
+ gfx_draw_circle_helper(x+w-r-1, y+h-r-1, r, 4, fg);
+ gfx_draw_circle_helper(x+r , y+h-r-1, r, 8, fg);
+}
+
+/* Fill a rounded rectangle */
+void gfx_fill_round_rect(
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ int16_t r,
+ uint16_t fg
+) {
+ /* smarter version */
+ gfx_fill_rect(x+r, y, w-2*r, h, fg);
+
+ /* draw four corners */
+ gfx_fill_circle_helper(x+w-r-1, y+r, r, 1, h-2*r-1, fg);
+ gfx_fill_circle_helper(x+r , y+r, r, 2, h-2*r-1, fg);
+}
+
+
+/* Draw a triangle */
+void gfx_draw_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t fg
+) {
+ gfx_draw_line(x0, y0, x1, y1, fg);
+ gfx_draw_line(x1, y1, x2, y2, fg);
+ gfx_draw_line(x2, y2, x0, y0, fg);
+}
+
+/* Fill a triangle */
+void gfx_fill_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t fg
+) {
+ int16_t a, b, y, last;
+
+ /* Sort coordinates by Y order (y2 >= y1 >= y0) */
+ if (y0 > y1) {
+ swap_i16(y0, y1); swap_i16(x0, x1);
+ }
+ if (y1 > y2) {
+ swap_i16(y2, y1); swap_i16(x2, x1);
+ }
+ if (y0 > y1) {
+ swap_i16(y0, y1); swap_i16(x0, x1);
+ }
+
+ /* Handle awkward all-on-same-line case as its own thing */
+ if (y0 == y2) {
+ a = b = x0;
+ if (x1 < a) {
+ a = x1;
+ } else
+ if (x1 > b) {
+ b = x1;
+ }
+ if (x2 < a) {
+ a = x2;
+ } else
+ if (x2 > b) {
+ b = x2;
+ }
+ gfx_draw_hline(a, y0, b-a+1, fg);
+ return;
+ }
+
+ int16_t
+ dx01 = x1 - x0,
+ dy01 = y1 - y0,
+ dx02 = x2 - x0,
+ dy02 = y2 - y0,
+ dx12 = x2 - x1,
+ dy12 = y2 - y1,
+ sa = 0,
+ sb = 0;
+
+ /* For upper part of triangle, find scanline crossings for segments
+ * 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
+ * is included here (and second loop will be skipped, avoiding a /0
+ * error there), otherwise scanline y1 is skipped here and handled
+ * in the second loop...which also avoids a /0 error here if y0=y1
+ * (flat-topped triangle).
+ */
+ if (y1 == y2) {
+ last = y1; /* Include y1 scanline */
+ } else {
+ last = y1-1; /* Skip it */
+ }
+
+ for (y = y0; y <= last; y++) {
+ a = x0 + sa / dy01;
+ b = x0 + sb / dy02;
+ sa += dx01;
+ sb += dx02;
+ /* longhand:
+ a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
+ b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+ */
+ if (a > b) {
+ swap_i16(a, b);
+ }
+ gfx_draw_hline(a, y, b-a+1, fg);
+ }
+
+ /* For lower part of triangle, find scanline crossings for segments
+ * 0-2 and 1-2. This loop is skipped if y1=y2.
+ */
+ sa = dx12 * (y - y1);
+ sb = dx02 * (y - y0);
+ for (; y <= y2; y++) {
+ a = x1 + sa / dy12;
+ b = x0 + sb / dy02;
+ sa += dx12;
+ sb += dx02;
+ /* longhand:
+ a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+ b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+ */
+ if (a > b) {
+ swap_i16(a, b);
+ }
+ gfx_draw_hline(a, y, b-a+1, fg);
+ }
+}
+
+
+
+
+/**
+ * Text functions
+ */
+
+/* Write utf8 text */
+void gfx_write(const uint32_t c)
+{
+ if (!__gfx_state.font) {
+ return;
+ }
+ if (c == '\n') {
+ __gfx_state.cursor_y += gfx_get_line_height();
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ } else if (c == '\r') {
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ } else {
+ if (__gfx_state.wrap
+ && (
+ __gfx_state.cursor_x
+ > (
+ __gfx_state.visible_area.x2
+ - gfx_get_char_width()
+ ))) {
+ __gfx_state.cursor_x = __gfx_state.cursor_x_orig;
+ __gfx_state.cursor_y += gfx_get_line_height();
+ }
+ gfx_draw_char(
+ __gfx_state.cursor_x, __gfx_state.cursor_y,
+ c,
+ __gfx_state.textcolor, __gfx_state.fontscale
+ );
+ __gfx_state.cursor_x += gfx_get_char_width();
+ }
+}
+
+void gfx_puts(const char *s) {
+ while (*s) {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ }
+}
+void gfx_puts4(const char *s, uint32_t max_len) {
+ while (*s && max_len--) {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ }
+}
+void gfx_puts2(
+ int16_t x, int16_t y,
+ const char *s,
+ const font_t *font,
+ uint16_t col
+) {
+ gfx_set_cursor(x, y);
+ gfx_set_font(font);
+ gfx_set_text_color(col);
+ gfx_puts(s);
+}
+/* this is not utf8 right now.. */
+void gfx_puts3(
+ int16_t x, int16_t y,
+ const char *s,
+ const gfx_alignment_t alignment
+) {
+ const char *s_end;
+ const char *next_nl; //, *last_nl;
+
+ switch (alignment) {
+ case GFX_ALIGNMENT_TOP:
+ case GFX_ALIGNMENT_BOTTOM:
+ case GFX_ALIGNMENT_LEFT:
+ gfx_set_cursor(x, y);
+ gfx_puts(s);
+ return;
+
+ case GFX_ALIGNMENT_RIGHT:
+ s_end = utf8_find_character_in_string(0, s, s+1024);
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ if (next_nl == s_end) {
+ gfx_set_cursor(
+ x
+ - utf8_find_pointer_diff(s, s_end)
+ * gfx_get_char_width(),
+ y
+ );
+ gfx_puts(s);
+ } else {
+ uint32_t line_count = 0;
+ while (s < s_end) {
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ gfx_set_cursor(
+ x
+ - utf8_find_pointer_diff(s, next_nl)
+ * gfx_get_char_width(),
+ y
+ + line_count
+ * gfx_get_line_height()
+ );
+ do {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ } while (s != next_nl);
+ s++; line_count++;
+ }
+ }
+ break;
+
+ case GFX_ALIGNMENT_CENTER:
+ /* TODO correct rounding on /2 */
+ s_end = utf8_find_character_in_string(0, s, s+1024);
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ if (0) { //next_nl == s_end) {
+ gfx_set_cursor(
+ x-(utf8_find_pointer_diff(s, s_end)
+ * gfx_get_char_width())/2,
+ y
+ );
+ gfx_puts(s);
+ } else {
+// /* find longest line */
+// uint32_t line_length, longest_line;
+// longest_line = utf8_find_pointer_diff(s, next_nl);
+// last_nl = next_nl+1;
+// while (last_nl < s_end) {
+// next_nl = utf8_find_character_in_string('\n', last_nl, s_end);
+// line_length = utf8_find_pointer_diff(last_nl, next_nl);
+// if (longest_line < line_length) {
+// longest_line = line_length;
+// }
+// last_nl = next_nl+1;
+// }
+
+ /* print lines */
+ uint32_t line_count = 0;
+ while (s < s_end) {
+ next_nl = utf8_find_character_in_string('\n', s, s_end);
+ gfx_set_cursor(
+ x
+ -(utf8_find_pointer_diff(s, next_nl)
+ * gfx_get_char_width())/2,
+ //- (longest_line*gfx_get_char_width())
+// - ((longest_line
+// - utf8_find_pointer_diff(s, next_nl)
+// ) * gfx_get_char_width())/2,
+ y
+ + line_count*gfx_get_line_height());
+ do {
+ int32_t value;
+ s = utf8_read_value(s, &value);
+ gfx_write(value);
+ } while (s != next_nl);
+ s++; line_count++;
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * This function gets the index of the char for the font data
+ * converts it's bit array address to a 32bit and mask
+ * and draws a point of size to it's location
+ *
+ * @param x x position
+ * @param y y position
+ * @param c utf8 char id
+ * @param col RGB565 color
+ * @param size Size in multiples of 1
+ */
+void gfx_draw_char(
+ int16_t x, int16_t y,
+ uint32_t c,
+ uint16_t col,
+ uint8_t size
+) {
+ uint32_t i, j, bm;
+ const char_t *cp;
+ const uint32_t *cp_data_p;
+
+ if (!__gfx_state.font) {
+ return;
+ }
+ /* get the data-index for this char code from the lookup table */
+ cp = font_get_char_index(c, __gfx_state.font);
+ if (cp == NULL) {
+ return;
+ }
+
+ cp_data_p = cp->data;
+ bm = 1; /* bit_mask */
+ for (j = cp->bbox.y1; j < cp->bbox.y2; j++) {
+ for (i = cp->bbox.x1; i < cp->bbox.x2; i++) {
+ if (*cp_data_p & bm) {
+ /* default size */
+ if (size == 1) {
+ gfx_draw_pixel(x+i, y+j, col);
+ } else {
+ /* big size */
+ gfx_fill_rect(x+i*size, y+j*size, size, size, col);
+ }
+ }
+ /* overflow */
+ if (bm == 0x80000000) {
+ bm = 1;
+ cp_data_p++;
+ } else {
+ bm <<= 1;
+ }
+ }
+ }
+}
+
+void gfx_set_cursor(int16_t x, int16_t y)
+{
+ __gfx_state.cursor_x_orig = x;
+ __gfx_state.cursor_x = x;
+ __gfx_state.cursor_y = y;
+}
+
+void gfx_set_font_scale(uint8_t s)
+{
+ __gfx_state.fontscale = (s > 0) ? s : 1;
+}
+uint8_t gfx_get_font_scale()
+{
+ return __gfx_state.fontscale;
+}
+
+void gfx_set_text_color(uint16_t col)
+{
+ __gfx_state.textcolor = col;
+}
+void gfx_set_font(const font_t *font)
+{
+ __gfx_state.font = font;
+}
+
+void gfx_set_text_wrap(bool w)
+{
+ __gfx_state.wrap = w;
+}
+
+uint16_t
+gfx_get_char_width()
+{
+ if (!__gfx_state.font) {
+ return 0;
+ } else {
+ return __gfx_state.font->charwidth*__gfx_state.fontscale;
+ }
+}
+uint16_t
+gfx_get_line_height()
+{
+ if (!__gfx_state.font) {
+ return 0;
+ }
+ return __gfx_state.font->lineheight*__gfx_state.fontscale;
+}
+uint16_t
+gfx_get_string_width(const char *s)
+{
+ uint16_t cnt, cnt_max;
+ cnt = cnt_max = 0;
+ while (1) {
+ if ((*s == 0) || (*s == '\n') || (*s == '\r')) {
+ if (cnt_max < cnt) {
+ cnt_max = cnt;
+ }
+
+ if (*s == 0) {
+ break;
+ }
+ cnt = 0;
+ } else {
+ cnt++;
+ }
+ s++;
+ }
+ return cnt_max * gfx_get_char_width();
+}
+uint16_t
+gfx_get_string_height(const char *s)
+{
+ uint16_t cnt;
+ cnt = 1;
+ while (*s) {
+ if (*s == '\n') {
+ cnt++;
+ }
+ s++;
+ }
+ return cnt * gfx_get_line_height();
+}
+uint8_t
+gfx_get_text_size()
+{
+ return __gfx_state.fontscale;
+}
+uint16_t
+gfx_get_text_color()
+{
+ return __gfx_state.textcolor;
+}
+const font_t *
+gfx_get_font()
+{
+ return __gfx_state.font;
+}
+uint8_t
+gfx_get_text_wrap()
+{
+ return __gfx_state.wrap;
+}
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.h
new file mode 100644
index 00000000..6ca4c36b
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/gfx_locm3.h
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef _GFX_LOCM3_H_
+#define _GFX_LOCM3_H_
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include "fonts/utf8.h"
+#include "fonts/fonts.h"
+
+#define swap_i16(a, b) { int16_t t = a; a = b; b = t; }
+
+/*
+ * Python
+ * def get_rgb565(x) :
+ * return ((x&0xf80000)>>8) | ((x&0xfc00)>>5) | ((x&0xf8)>>3)
+ *
+ * print print "0x%X"%get_rgb565(some_rgb_value)
+ */
+#define GFX_COLOR_WHITE 0xFFFF
+#define GFX_COLOR_BLACK 0x0000
+#define GFX_COLOR_DARKGREY 0x4228
+#define GFX_COLOR_GREY 0xF7DE
+#define GFX_COLOR_GREY2 0x7BEF /*1111 0111 1101 1110*/
+#define GFX_COLOR_BLUE 0x001F
+#define GFX_COLOR_BLUE2 0x051F
+#define GFX_COLOR_RED 0xF800
+#define GFX_COLOR_MAGENTA 0xF81F
+#define GFX_COLOR_GREEN 0x07E0
+#define GFX_COLOR_GREEN2 0xB723
+#define GFX_COLOR_CYAN 0x7FFF
+#define GFX_COLOR_YELLOW 0xFFE0
+#define GFX_COLOR_ORANGE 0xFBE4
+#define GFX_COLOR_BROWN 0xBBCA
+
+typedef enum {
+ GFX_ROTATION_0_DEGREES,
+ GFX_ROTATION_90_DEGREES,
+ GFX_ROTATION_180_DEGREES,
+ GFX_ROTATION_270_DEGREES
+} gfx_rotation_t;
+
+typedef enum {
+ GFX_ALIGNMENT_TOP = 1<<0,
+ GFX_ALIGNMENT_BOTTOM = 1<<1,
+ GFX_ALIGNMENT_LEFT = 1<<2,
+ GFX_ALIGNMENT_RIGHT = 1<<3,
+ GFX_ALIGNMENT_CENTER = 1<<4,
+} gfx_alignment_t;
+
+typedef struct {
+ int16_t x1, y1, x2, y2;
+} visible_area_t;
+
+typedef struct {
+ uint32_t is_offscreen_rendering;
+ const int16_t width_orig, height_orig;
+ const uint32_t pixel_count;
+ int16_t width, height;
+ visible_area_t visible_area;
+ int16_t cursor_x, cursor_y, cursor_x_orig;
+ uint16_t textcolor;
+ uint8_t fontscale;
+ gfx_rotation_t rotation;
+ bool wrap;
+ const font_t *font;
+ uint16_t *surface; /* current pixel buffer */
+} gfx_state_t;
+
+extern gfx_state_t __gfx_state;
+
+
+typedef struct {
+ size_t count_max;
+ size_t count_total;
+ size_t overflows;
+} fill_segment_queue_statistics_t;
+
+
+void gfx_init(uint16_t *surface, int32_t w, int32_t h);
+/**
+ * set pixel buffer address to render graphics on..
+ * @param surface pixel buffer address
+ */
+void gfx_set_surface(uint16_t *surface);
+uint16_t *
+gfx_get_surface(void);
+
+void gfx_offscreen_rendering_begin(
+ uint16_t *surface,
+ int32_t width, int32_t height
+ );
+void gfx_offscreen_rendering_end(void);
+
+void
+gfx_set_clipping_area_max(void);
+void
+gfx_set_clipping_area(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
+visible_area_t
+gfx_get_surface_visible_area(void);
+
+
+void gfx_fill_screen(uint16_t color);
+
+void gfx_set_rotation(gfx_rotation_t rotation);
+uint16_t gfx_height(void);
+uint16_t gfx_width(void);
+gfx_rotation_t gfx_get_rotation(void);
+
+void gfx_draw_pixel(int16_t x, int16_t y, uint16_t color);
+int32_t gfx_get_pixel(int16_t x, int16_t y);
+fill_segment_queue_statistics_t
+gfx_flood_fill4(
+ int16_t x, int16_t y,
+ uint16_t old_color, uint16_t new_color,
+ uint8_t fill_segment_buf[], size_t fill_segment_buf_size
+ );
+
+void gfx_draw_line(
+ int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+ uint16_t color
+ );
+void gfx_draw_hline(int16_t x, int16_t y, int16_t length, uint16_t color);
+void gfx_draw_vline(int16_t x, int16_t y, int16_t length, uint16_t color);
+void gfx_draw_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+void gfx_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+void gfx_draw_raw_rbg565_buffer(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img
+ );
+void gfx_draw_raw_rbg565_buffer_ignore_color(
+ int16_t x, int16_t y, uint16_t w, uint16_t h,
+ const uint16_t *img,
+ uint16_t ignored_color
+ );
+
+void gfx_draw_circle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
+void gfx_draw_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername,
+ uint16_t color
+ );
+void gfx_fill_circle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
+void gfx_fill_circle_helper(
+ int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername, int16_t delta,
+ uint16_t color
+ );
+
+void gfx_draw_round_rect(
+ int16_t x0, int16_t y0, int16_t w, int16_t h,
+ int16_t radius,
+ uint16_t color
+ );
+void gfx_fill_round_rect(
+ int16_t x0, int16_t y0, int16_t w, int16_t h,
+ int16_t radius,
+ uint16_t color
+ );
+
+void gfx_draw_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t color
+ );
+void gfx_fill_triangle(
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint16_t color
+ );
+
+
+void gfx_draw_char(
+ int16_t x, int16_t y,
+ uint32_t c,
+ uint16_t color,
+ uint8_t size
+ );
+void gfx_set_cursor(int16_t x, int16_t y);
+void gfx_set_text_color(uint16_t col);
+void gfx_set_font_scale(uint8_t s);
+uint8_t gfx_get_font_scale(void);
+void gfx_set_text_wrap(bool w);
+void gfx_set_font(const font_t *font);
+void gfx_puts(const char *);
+void gfx_puts4(const char *s, uint32_t max_len);
+void gfx_puts2(
+ int16_t x, int16_t y,
+ const char *s,
+ const font_t *font,
+ uint16_t col
+ );
+void gfx_puts3(
+ int16_t x, int16_t y,
+ const char *s,
+ const gfx_alignment_t alignment
+ );
+void gfx_write(const uint32_t);
+
+
+uint16_t
+gfx_get_char_width(void);
+uint16_t
+gfx_get_line_height(void);
+uint16_t
+gfx_get_string_width(const char *);
+uint16_t
+gfx_get_string_height(const char *s);
+
+uint8_t
+gfx_get_text_size(void);
+uint16_t
+gfx_get_text_color(void);
+const font_t *
+gfx_get_font(void);
+uint8_t
+gfx_get_text_wrap(void);
+
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.c
new file mode 100644
index 00000000..98236efd
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.c
@@ -0,0 +1,334 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "i2c.h"
+
+static uint32_t dummy __attribute__((unused));
+
+volatile uint32_t stummy;
+
+void i2c_setup_master(uint32_t i2c, uint32_t clock_speed)
+{
+ /* Disable the I2C before changing any configuration. */
+ i2c_reset(i2c); /* rcc_periph_reset_pulse(i2c_RST); */
+ i2c_peripheral_disable(i2c);
+
+ /* analog filter enabled, digital filter 4*Tpclk1 */
+#define DIGITAL_FILTER 2
+ I2C_FILTR(i2c) = DIGITAL_FILTER;
+
+ /* TODO fix timing!!!! */
+ /*i2c_set_clock_frequency(i2c, I2C_CR2_FREQ_42MHZ); // APB @42MHz?*/
+ i2c_set_clock_frequency(i2c, CLOCK_SETUP.apb1_frequency/1000000);
+ if (clock_speed <= 100000) { /* <=100000 according to ref. manual,
+ <88000 according to errata sheet */
+ i2c_set_standard_mode(i2c);
+ i2c_set_ccr(i2c, CLOCK_SETUP.apb1_frequency/(clock_speed*2));
+ stummy = CLOCK_SETUP.apb1_frequency/(clock_speed*2);
+ i2c_set_dutycycle(i2c, I2C_CCR_DUTY_DIV2);
+ i2c_set_trise(i2c, (CLOCK_SETUP.apb1_frequency/1000000) + 1 + DIGITAL_FILTER);
+ } else {
+ i2c_set_fast_mode(i2c);
+ i2c_set_ccr(i2c, CLOCK_SETUP.apb1_frequency/(clock_speed*25));
+ stummy = CLOCK_SETUP.apb1_frequency/(clock_speed*25);
+ i2c_set_dutycycle(i2c, I2C_CCR_DUTY_16_DIV_9);
+ i2c_set_trise(i2c, (((CLOCK_SETUP.apb1_frequency/1000000) * 300) / 1000) + 1 + DIGITAL_FILTER);
+ }
+ /*i2c_set_own_7bit_slave_address(i2c, 0); */
+
+
+ i2c_peripheral_enable(i2c);
+}
+
+
+
+/* Clearing ADDR condition sequence. */
+#define i2c_clear_address(i2c) { dummy = I2C_SR1(i2c); dummy = I2C_SR2(i2c); }
+
+static
+void
+i2c_wait_until_probably_safe(uint32_t i2c);
+static
+void
+i2c_send_start_safe(uint32_t i2c);
+static
+void
+i2c_send_stop_safe(uint32_t i2c);
+static
+void
+i2c_recovery(uint32_t i2c);
+
+
+static
+i2c_flag_wait_error
+i2c_wait_for_sr1_flag_set(uint32_t i2c, uint32_t flag);
+static
+i2c_flag_wait_error
+i2c_wait_while_busy(uint32_t i2c);
+
+
+void
+i2c_wait_until_probably_safe(uint32_t i2c) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (
+ (I2C_CR1(i2c) & (I2C_CR1_STOP | I2C_CR1_START | I2C_CR1_PEC))
+ && timeout
+ ) {
+ timeout--;
+ }
+ if (!timeout) {
+ stummy = I2C_CR1(i2c);
+ i2c_recovery(i2c);
+ }
+}
+void
+i2c_send_start_safe(uint32_t i2c) {
+ i2c_wait_until_probably_safe(i2c);
+ i2c_send_start(i2c);
+}
+void
+i2c_send_stop_safe(uint32_t i2c) {
+ /* sending stop is bad most of the time!! */
+ i2c_wait_until_probably_safe(i2c);
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+}
+void
+i2c_recovery(uint32_t i2c) {
+ uint32_t timeout;
+ /* recover from glitch or so */
+ I2C_CR1(i2c) |= I2C_CR1_SWRST;
+ /* wait a long time.. */
+ timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (timeout) {
+ timeout--;
+ }
+ I2C_CR1(i2c) &= ~I2C_CR1_SWRST;
+}
+
+
+i2c_flag_wait_error
+i2c_wait_for_sr1_flag_set(uint32_t i2c, uint32_t flag) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (!(I2C_SR1(i2c) & (flag | I2C_SR1_AF)) && timeout) {
+ timeout--;
+ }
+ stummy = I2C_SR1(i2c);
+ if ((I2C_SR1(i2c) & I2C_SR1_AF) || !timeout) {
+ stummy = I2C_SR2(i2c);
+
+
+ /* TODO <<< check for AF error */
+ /* TODO make a recovery function.. */
+ /*i2c3_setup();*/
+ /*for (timeout=10; timeout; timeout--) {*/
+ if (I2C_SR1(i2c) & I2C_SR1_AF) {
+ i2c_send_start_safe(i2c);
+ while (!(I2C_SR1(i2c) & I2C_SR1_SB));
+ } else {
+ i2c_recovery(i2c);
+ }
+ /*}*/
+
+ /*sending stop is only allowed after a full byte..*/
+ /*i2c_send_stop_safe(i2c);*/
+
+ /*stummy = I2C_SR1(i2c);*/
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+i2c_flag_wait_error
+i2c_wait_while_busy(uint32_t i2c) {
+ uint32_t timeout = I2C_FLAG_WAIT_TIMEOUT;
+ while (i2c_is_busy(i2c) && timeout) {
+ timeout--;
+ }
+ if ((I2C_SR1(i2c) & I2C_SR1_AF) || !timeout) {
+ i2c_recovery(i2c);
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+
+volatile uint32_t i2c_failed_horribly;
+
+void
+i2c_trx_retry(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+) {
+ uint32_t retries = I2C_MAX_RETRIES;
+ while (
+ i2c_trx(i2c, address, write_data, write_len, read_data, read_len)
+ && retries) {
+ retries--;
+ }
+ if (!retries) {
+ i2c_failed_horribly = 1;
+ }
+}
+
+i2c_flag_wait_error
+i2c_trx(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+) {
+ /* TODO make it work :) */
+
+ if (i2c_wait_while_busy(i2c)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* enable error IT */
+ /*I2C_CR2(i2c) |= I2C_CR2_ITERREN;*/
+
+ /* Sending the data_p. */
+ if (write_len) {
+ i2c_wait_until_probably_safe(i2c);
+ /* send start */
+ I2C_CR1(i2c) |= I2C_CR1_START; /*i2c_send_start(i2c);*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_SB)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* send address */
+ i2c_send_7bit_address(i2c, address, I2C_WRITE);
+ /* Waiting for address is transferred. */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_ADDR)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* clear ADDR flag by reading SR2 */
+ dummy = I2C_SR2(i2c);
+ /*i2c_clear_address(i2c);*/
+
+ /*i2c_send_data(i2c, *write_data++); write_len--;*/ /*write first byte*/
+ while (write_len) {
+ /*if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) return I2C_FLAG_WAIT_UNKNOWN_ERROR;*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_TxE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ i2c_send_data(i2c, *write_data++); write_len--;
+ if ((I2C_SR1(i2c) & I2C_SR1_BTF) && write_len) {
+ i2c_send_data(i2c, *write_data++); write_len--;
+ }
+ }
+
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_TxE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ }
+ if (!read_len) {
+ i2c_send_stop_safe(i2c);
+ } else {
+ /* Receiving data_p */
+ i2c_wait_until_probably_safe(i2c);
+ /*I2C_CR1(i2c) |= I2C_CR1_ACK;*/ /*enable ack*/
+ i2c_send_start(i2c); /* send repeated start */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_SB)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ i2c_send_7bit_address(i2c, address, I2C_READ);
+ /* Waiting for address is transferred. */
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_ADDR)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+
+ /* Start receiving */
+ switch (read_len) {
+ case 1:
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK; /* disable ack */
+ /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
+ software sequence must complete before the current byte end of transfer */
+ __disable_irq();
+ i2c_clear_address(i2c);
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+ __enable_irq();
+ break;
+ case 2:
+ I2C_CR1(i2c) |= I2C_CR1_POS; /* this may cause trouble? has it to be set before start? */
+ /* EV6_1: The acknowledge disable should be done just after EV6,
+ that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and
+ ACK clearing */
+ __disable_irq();
+ i2c_clear_address(i2c);
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ __enable_irq();
+ /*
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ I2C_CR1(i2c) |= I2C_CR1_POS;
+ i2c_clear_address(i2c);
+ */
+ break;
+ default:
+ I2C_CR1(i2c) |= I2C_CR1_ACK;
+ i2c_clear_address(i2c);
+ break;
+ }
+ while (read_len) {
+ switch (read_len) {
+ case 1:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_RxNE)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ *read_data++ = I2C_DR(i2c); read_len--;
+ break;
+ case 2:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ /* TODO i2c_send_stop_safe(i2c); */
+ __disable_irq();
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ __enable_irq();
+ *read_data++ = I2C_DR(i2c); read_len--;
+ break;
+ case 3: /*???!*/
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ /* goto case 2 to finish.. */
+ break;
+ default:
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_BTF)) {
+ return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ }
+ *read_data++ = I2C_DR(i2c); read_len--;
+ /*
+ if (i2c_wait_for_sr1_flag_set(i2c, I2C_SR1_RxNE)) return I2C_FLAG_WAIT_UNKNOWN_ERROR;
+ *read_data++ = I2C_DR(i2c); read_len--;
+ if (I2C_SR1(i2c) & I2C_SR1_BTF) { // read another byte
+ *read_data++ = I2C_DR(i2c); read_len--;
+ }
+ */
+ break;
+ }
+ }
+ i2c_wait_until_probably_safe(i2c);
+ I2C_CR1(i2c) &= ~I2C_CR1_POS;
+ }
+
+ /*return i2c_wait_while_busy(i2c);*/ /* busy checking is done at the beginning of this function.. */
+ return I2C_FLAG_WAIT_NO_ERROR;
+}
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.h
new file mode 100644
index 00000000..cdeef6f0
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/i2c.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ *
+ */
+
+
+#ifndef __I2C_H__
+#define __I2C_H__
+
+#include "clock.h"
+#include
+#include
+
+
+
+/**
+ * I2C extensions
+ */
+
+#define I2C_FILTR(i2c_base) MMIO32(i2c_base + 0x24)
+#define I2C_FILTER_ANOFF_DISABLE_ANALOG_FILTER (0b10000)
+
+
+void i2c_setup_master(uint32_t i2c, uint32_t clock_speed);
+
+#define i2c_is_busy(i2c) ((I2C_SR2(i2c)&I2C_SR2_BUSY) == I2C_SR2_BUSY)
+
+/* TODO FIX I2C CLOCK SETUP!!! */
+#define STMPE811_I2C_CLOCK_SPEED 10000
+#define I2C_FLAG_WAIT_TIMEOUT ((uint32_t)(168000000UL*100/STMPE811_I2C_CLOCK_SPEED))
+#define I2C_MAX_RETRIES 10000
+
+typedef enum {
+ I2C_FLAG_WAIT_NO_ERROR = 0,
+ I2C_FLAG_WAIT_UNKNOWN_ERROR
+} i2c_flag_wait_error;
+
+void
+i2c_trx_retry(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+);
+
+i2c_flag_wait_error
+i2c_trx(uint32_t i2c, uint8_t address,
+ const uint8_t *write_data, uint32_t write_len,
+ uint8_t read_data[], uint32_t read_len
+);
+
+
+#endif /*__I2C_H__ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.c
new file mode 100644
index 00000000..17bc5557
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.c
@@ -0,0 +1,753 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "lcd_ili9341.h"
+#include
+
+volatile int rx_pend;
+volatile uint16_t spi_rx_buf;
+
+void ili9341_spi5_isr()
+{
+ spi_rx_buf = SPI_DR(SPI5);
+ --rx_pend;
+}
+
+/* send spi data */
+static inline void ili9341_send_data(uint8_t data);
+
+/* send spi command */
+static inline void ili9341_send_command(uint8_t data);
+
+/* interrupt driven send command via ssp */
+void
+ili9341_send_command(uint8_t data)
+{
+ ILI9341_WRX_RESET();
+ ILI9341_SPI_SELECT();
+
+ rx_pend++;
+ spi_send(ILI9341_SPI, data);
+ while (rx_pend);
+
+ ILI9341_SPI_DESELECT();
+}
+
+/* interrupt driven send data via ssp */
+void
+ili9341_send_data(uint8_t data)
+{
+ ILI9341_WRX_SET();
+ ILI9341_SPI_SELECT();
+
+ rx_pend++;
+ spi_send(ILI9341_SPI, data);
+ while (rx_pend);
+
+ ILI9341_SPI_DESELECT();
+}
+
+
+
+ili9341_options_t ili9341_opts;
+
+/**
+ * Setup LCD screen to be driven by ltdc
+ *
+ * surface buffers have ILI9341_BUFFERS_PER_LAYER elements
+ * which point to memory areas where each have a size of
+ * ILI9341_SURFACE_SIZE
+ *
+ * @param layer1_surface_buffers
+ * @param layer2_surface_buffers
+ */
+void ili9341_init(
+ uint16_t *layer1_surface_buffers[],
+ uint16_t *layer2_surface_buffers[]
+) {
+ int i;
+
+ /* Initialize pins used */
+ ili9341_init_pins();
+ /* SPI chip select high */
+ ILI9341_SPI_DESELECT();
+ /* Initialize LCD for LTDC */
+ ili9341_init_lcd();
+ /* Initialize LTDC */
+ ili9341_init_ltdc();
+ /* Initialize LTDC layers */
+ ili9341_init_layers();
+
+ ili9341_opts.width = ILI9341_WIDTH;
+ ili9341_opts.height = ILI9341_HEIGHT;
+ ili9341_opts.current_layer = 0;
+ ili9341_opts.layer1_opacity = 255;
+ ili9341_opts.layer2_opacity = 0;
+ ili9341_opts.current_layer1_surface_idx = 0;
+ ili9341_opts.current_layer2_surface_idx = 0;
+ for (i = 0; i < ILI9341_BUFFERS_PER_LAYER; i++) {
+ ili9341_opts.layer1_surface_buffers[i] =
+ layer1_surface_buffers[i];
+ ili9341_opts.layer2_surface_buffers[i] =
+ layer2_surface_buffers[i];
+ }
+
+ gfx_init(layer1_surface_buffers[0], ILI9341_WIDTH, ILI9341_HEIGHT);
+
+ /* initially fill the screen white again to confuse people */
+ /*
+ for (i=0; i> 16)&0xff,
+ (rgb888_color_key >> 8)&0xff,
+ (rgb888_color_key >> 0)&0xff
+ );
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_COLKEY_ENABLE);
+
+ /* the length of one line of pixels in bytes + 3 then :
+ Line Lenth = Active high width x number of bytes per pixel + 3
+ Active high width = LCD_PIXEL_WIDTH
+ number of bytes per pixel = 2 (pixel_format : RGB565)
+ */
+ /* the pitch is the increment from the start of one line of pixels
+ * to the start of the next line in bytes, then :
+ * Pitch = Active high width x number of bytes per pixel
+ */
+ /* I was too lazy to add makros for this */
+ ltdc_set_fb_line_length(LTDC_LAYER_1, (240*2+3), (240*2));
+ ltdc_set_fb_line_length(LTDC_LAYER_2, (240*2+3), (240*2));
+
+
+ /* Configure the number of lines */
+ ltdc_set_fb_line_count(LTDC_LAYER_1, 320);
+ ltdc_set_fb_line_count(LTDC_LAYER_2, 320);
+
+ /* Start Address configuration :
+ * the LCD Frame buffer is defined on SDRAM
+ */
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_1,
+ (uint32_t)ili9341_opts.layer1_surface_buffers[0]
+ );
+
+ /* Start Address configuration :
+ * the LCD Frame buffer is defined on SDRAM w/ Offset
+ */
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_2,
+ (uint32_t)ili9341_opts.layer2_surface_buffers[0]
+ );
+
+
+ /* All the layer configs are shadow registers which can be reloaded
+ * either immediately with LTDC_SRCR_RELOAD_IMR or in the vsync phase
+ * (i guess) with LTDC_SRCR_RELOAD_VBR
+ * if you want to do double buffering just set the new buffer address
+ * and say ltdc_reload(LTDC_SRCR_RELOAD_VBR)
+ */
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /* Enable foreground & background Layers */
+ ltdc_layer_ctrl_enable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /* enable dithering to add artsy graphical artifacts */
+ ltdc_ctrl_enable(LTDC_GCR_DITHER_ENABLE);
+
+ /* turn ltdc on, uh yeah! */
+ ltdc_ctrl_enable(LTDC_GCR_LTDC_ENABLE);
+
+ /* finally make both layers visible
+ */
+ ltdc_set_constant_alpha(LTDC_LAYER_1, 255);
+ ltdc_set_constant_alpha(LTDC_LAYER_2, 255);
+ ltdc_reload(LTDC_SRCR_RELOAD_IMR);
+
+ /*
+ * alpha is set by either color_keying, constant_alpha or
+ * layer blending (which probably also includes color_keying)
+ * according to the blending options selected above
+ * color keying is enabled only for layer 2 with the key
+ * ILI9341_LAYER2_COLOR_KEY
+ */
+}
+
+
+
+
+
+
+/*
+ * Interface stuff
+ */
+
+ili9341_driver_t ili9341_get_driver()
+{
+ return ILI9341_DRIVER_LTDC;
+}
+
+
+bool
+ili9341_is_reloading()
+{
+ return LTDC_SRCR_IS_RELOADING();
+}
+
+void
+ili9341_reload(uint32_t mode)
+{
+ ltdc_reload(mode);
+}
+
+
+void
+ili9341_vsync()
+{
+ while (!ltdc_get_display_status(LTDC_CDSR_VSYNCS));
+}
+
+
+/* double buffering feature (2 buffers for each layer makes 2*2) */
+void
+ili9341_flip_layer1_buffer()
+{
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_1,
+ (uint32_t)ili9341_opts.layer1_surface_buffers[ili9341_opts.current_layer1_surface_idx]
+ );
+
+ ili9341_opts.current_layer1_surface_idx = (ili9341_opts.current_layer1_surface_idx + 1) % ILI9341_BUFFERS_PER_LAYER;
+ /*ltdc_set_fbuffer_address(LTDC_LAYER_1, (uint32_t)ili9341_get_current_layer_buffer_address());*/
+ /*ili9341_opts.current_local_layer1_buffer = (ili9341_opts.current_local_layer1_buffer+1)%ILI9341_BUFFERS_PER_LAYER;*/
+
+ /* vsync or so by the controller shadow register update command */
+ /*ltdc_reload(LTDC_SRCR_RELOAD_VBR);*/
+}
+void
+ili9341_flip_layer2_buffer()
+{
+ ltdc_set_fbuffer_address(
+ LTDC_LAYER_2,
+ (uint32_t)ili9341_opts.layer2_surface_buffers[ili9341_opts.current_layer2_surface_idx]
+ );
+
+ ili9341_opts.current_layer2_surface_idx = (ili9341_opts.current_layer2_surface_idx + 1) % ILI9341_BUFFERS_PER_LAYER;
+
+ /* vsync or so by the controller shadow register update command */
+ /*ltdc_reload(LTDC_SRCR_RELOAD_VBR);*/
+}
+
+
+/* draw_pixel and fill draw on layer1 after this is called */
+void
+ili9341_set_layer1(void)
+{
+ /*ili9341_change_current_layer_offset(ILI9341_FRAME_OFFSET*(ili9341_opts.current_local_layer1_buffer));*/
+ __gfx_state.surface = ili9341_opts.layer1_surface_buffers[ili9341_opts.current_layer1_surface_idx];
+ ili9341_opts.current_layer = 0;
+}
+
+/* draw_pixel and fill draw on layer2 after this is called */
+void
+ili9341_set_layer2(void)
+{
+ /*ili9341_change_current_layer_offset(ILI9341_FRAME_OFFSET*(ili9341_opts.current_local_layer2_buffer+ILI9341_BUFFERS_PER_LAYER));*/
+ __gfx_state.surface = ili9341_opts.layer2_surface_buffers[ili9341_opts.current_layer2_surface_idx];
+ ili9341_opts.current_layer = 1;
+}
+
+/* set layer 1 alpha (to hide and stuff) */
+void
+ili9341_set_layer1_opacity(uint8_t opacity)
+{
+ ili9341_opts.layer1_opacity = opacity;
+ ili9341_update_layer_opacity();
+}
+
+/* set layer 2 alpha (to hide and stuff) */
+void
+ili9341_set_layer2_opacity(uint8_t opacity)
+{
+ ili9341_opts.layer2_opacity = opacity;
+ ili9341_update_layer_opacity();
+}
+
+
+/*
+ * set alpha and reload the shadow register after opacity update
+ * disables layer rendering if opacity is 0 (not really worth anything)
+ */
+void
+ili9341_update_layer_opacity(void)
+{
+ if (ili9341_opts.layer1_opacity) {
+ ltdc_layer_ctrl_enable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ } else {
+ ltdc_layer_ctrl_disable(LTDC_LAYER_1, LTDC_LxCR_LAYER_ENABLE);
+ }
+
+ if (ili9341_opts.layer2_opacity) {
+ ltdc_layer_ctrl_enable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ } else {
+ ltdc_layer_ctrl_disable(LTDC_LAYER_2, LTDC_LxCR_LAYER_ENABLE);
+ }
+
+ ltdc_set_constant_alpha(LTDC_LAYER_1, ili9341_opts.layer1_opacity);
+ ltdc_set_constant_alpha(LTDC_LAYER_2, ili9341_opts.layer2_opacity);
+ ltdc_reload(LTDC_SRCR_RELOAD_VBR);
+}
+
+
+
+
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.h
new file mode 100644
index 00000000..ca3b312a
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/lcd_ili9341.h
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+
+#ifndef LTDC_ILI9341_H
+#define LTDC_ILI9341_H
+
+/**
+ * Includes
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "clock.h"
+#include "sdram.h"
+#include "gfx_locm3.h"
+
+#ifndef ILI9341_LAYER2_COLOR_KEY
+#define ILI9341_LAYER2_COLOR_KEY 0x01ad
+/*#define ILI9341_LAYER2_COLOR_KEY 0x000C*/
+#endif
+
+
+
+/**/
+#ifndef ILI9341_SPI
+#define ILI9341_SPI SPI5
+#endif
+
+#ifndef ILI9341_CS_PIN
+/* This pin is used on STM32F429 discovery board */
+#define ILI9341_CS_CLK RCC_GPIOC
+#define ILI9341_CS_PORT GPIOC
+#define ILI9341_CS_PIN GPIO2
+#endif
+
+#ifndef ILI9341_WRX_PIN
+/* This pin is used on STM32F429 discovery board */
+#define ILI9341_WRX_CLK RCC_GPIOD
+#define ILI9341_WRX_PORT GPIOD
+#define ILI9341_WRX_PIN GPIO13
+#endif
+
+/* Reset pin */
+#ifndef ILI9341_RST_PIN
+/* Reset pin */
+#define ILI9341_RST_CLK RCC_GPIOD
+#define ILI9341_RST_PORT GPIOD
+#define ILI9341_RST_PIN GPIO12
+#endif
+
+#define ILI9341_RST_SET() { gpio_set(ILI9341_RST_PORT, ILI9341_RST_PIN); }
+#define ILI9341_RST_RESET() { gpio_clear(ILI9341_RST_PORT, ILI9341_RST_PIN); }
+#define ILI9341_SPI_IS_SELECTED() (!gpio_get(ILI9341_CS_PORT, ILI9341_CS_PIN))
+#define ILI9341_SPI_DESELECT() { gpio_set(ILI9341_CS_PORT, ILI9341_CS_PIN); }
+#define ILI9341_SPI_SELECT() { gpio_clear(ILI9341_CS_PORT, ILI9341_CS_PIN); }
+#define ILI9341_WRX_SET() { gpio_set(ILI9341_WRX_PORT, ILI9341_WRX_PIN); }
+#define ILI9341_WRX_RESET() { gpio_clear(ILI9341_WRX_PORT, ILI9341_WRX_PIN); }
+/**/
+
+
+
+/* Commands */
+#define ILI9341_RESET 0x01
+#define ILI9341_SLEEP_OUT 0x11
+#define ILI9341_GAMMA 0x26
+#define ILI9341_DISPLAY_OFF 0x28
+#define ILI9341_DISPLAY_ON 0x29
+#define ILI9341_COLUMN_ADDR 0x2A
+#define ILI9341_PAGE_ADDR 0x2B
+#define ILI9341_GRAM 0x2C
+#define ILI9341_MAC 0x36
+#define ILI9341_PIXEL_FORMAT 0x3A
+#define ILI9341_WDB 0x51
+#define ILI9341_WCD 0x53
+#define ILI9341_RGB_INTERFACE 0xB0
+#define ILI9341_FRC 0xB1
+#define ILI9341_BPC 0xB5
+#define ILI9341_DFC 0xB6
+#define ILI9341_POWER1 0xC0
+#define ILI9341_POWER2 0xC1
+#define ILI9341_VCOM1 0xC5
+#define ILI9341_VCOM2 0xC7
+#define ILI9341_POWERA 0xCB
+#define ILI9341_POWERB 0xCF
+#define ILI9341_PGAMMA 0xE0
+#define ILI9341_NGAMMA 0xE1
+#define ILI9341_DTCA 0xE8
+#define ILI9341_DTCB 0xEA
+#define ILI9341_POWER_SEQ 0xED
+#define ILI9341_3GAMMA_EN 0xF2
+#define ILI9341_INTERFACE 0xF6
+#define ILI9341_PRC 0xF7
+
+
+
+/* LCD settings */
+#define ILI9341_WIDTH 240
+#define ILI9341_HEIGHT 320
+
+
+#define ILI9341_SURFACE_SIZE ((ILI9341_WIDTH*ILI9341_HEIGHT)*sizeof(uint16_t))
+
+
+/* double buffering
+ * (values other than 2 were not tested and make not too much sense..)
+ */
+#define ILI9341_BUFFERS_PER_LAYER 2
+
+
+
+typedef struct {
+ uint16_t width;
+ uint16_t height;
+ uint8_t current_layer;
+ uint8_t layer1_opacity;
+ uint8_t layer2_opacity;
+ uint8_t current_layer1_surface_idx;
+ uint8_t current_layer2_surface_idx;
+ uint16_t *layer1_surface_buffers[ILI9341_BUFFERS_PER_LAYER];
+ uint16_t *layer2_surface_buffers[ILI9341_BUFFERS_PER_LAYER];
+} ili9341_options_t;
+
+extern ili9341_options_t ili9341_opts;
+void ili9341_init(
+ uint16_t *layer1_surface_buffers[],
+ uint16_t *layer2_surface_buffers[]
+ );
+void ili9341_init_pins(void);
+void ili9341_init_ltdc(void);
+void ili9341_init_layers(void);
+void ili9341_init_lcd(void);
+void ili9341_spi5_isr(void);
+
+
+/*static inline void ili9341_set_width(uint16_t width);*/
+
+typedef enum {
+ ILI9341_DRIVER_SPI,
+ ILI9341_DRIVER_LTDC,
+} ili9341_driver_t;
+
+ili9341_driver_t ili9341_get_driver(void);
+
+/* Check if the display is reloading */
+bool ili9341_is_reloading(void);
+
+/* Reload screen */
+void ili9341_reload(uint32_t mode);
+
+/* Wait for vertical synchronisation */
+void ili9341_vsync(void);
+
+static inline
+uint16_t*
+ili9341_get_current_layer_buffer_address(void) {
+ return __gfx_state.surface;
+}
+
+/* Flip the double_buffer */
+void ili9341_flip_layer1_buffer(void);
+void ili9341_flip_layer2_buffer(void);
+
+/* Simple delay */
+/*void ili9341_delay(volatile unsigned int delay);*/
+
+
+void ili9341_set_layer1(void);
+
+void ili9341_set_layer2(void);
+
+void ili9341_set_layer1_opacity(uint8_t opacity);
+
+void ili9341_set_layer2_opacity(uint8_t opacity);
+void ili9341_update_layer_opacity(void);
+
+
+
+#define ili9341_delay(cycles) wait_cycles(cycles);
+
+#endif
+
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.c
new file mode 100644
index 00000000..0a4fc1b1
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.c
@@ -0,0 +1,139 @@
+#include "sdram.h"
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+/*
+ * This then is the initialization code extracted from the
+ * sdram example.
+ */
+#include
+#include
+#include
+#include
+#include "clock.h"
+
+/*
+ * This is just syntactic sugar but it helps, all of these
+ * GPIO pins get configured in exactly the same way.
+ */
+static struct {
+ uint32_t gpio;
+ uint16_t pins;
+} sdram_pins[6] = {
+ {GPIOB, GPIO5 | GPIO6 },
+ {GPIOC, GPIO0 },
+ {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 | GPIO4 | GPIO5 | GPIO8 | GPIO15}
+};
+
+static struct sdram_timing timing = {
+ .trcd = 2, /* RCD Delay */
+ .trp = 2, /* RP Delay */
+ .twr = 2, /* Write Recovery Time */
+ .trc = 7, /* Row Cycle Delay */
+ .tras = 4, /* Self Refresh Time */
+ .txsr = 7, /* Exit Self Refresh Time */
+ .tmrd = 2, /* Load to Active Delay */
+};
+
+/*
+ * Initialize the SD RAM controller.
+ */
+void
+sdram_init(void) {
+ int i;
+ uint32_t cr_tmp, tr_tmp; /* control, timing registers */
+
+ /*
+ * First all the GPIO pins that end up as SDRAM pins
+ */
+ rcc_periph_clock_enable(RCC_GPIOB);
+ rcc_periph_clock_enable(RCC_GPIOC);
+ rcc_periph_clock_enable(RCC_GPIOD);
+ rcc_periph_clock_enable(RCC_GPIOE);
+ rcc_periph_clock_enable(RCC_GPIOF);
+ rcc_periph_clock_enable(RCC_GPIOG);
+
+ for (i = 0; i < 6; i++) {
+ gpio_mode_setup(sdram_pins[i].gpio,
+ GPIO_MODE_AF, GPIO_PUPD_NONE,
+ sdram_pins[i].pins);
+ gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP,
+ GPIO_OSPEED_50MHZ, sdram_pins[i].pins);
+ gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins);
+ }
+
+ /* Enable the SDRAM Controller */
+#if 1
+ rcc_periph_clock_enable(RCC_FSMC);
+#else
+ rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN);
+#endif
+
+ /* Note the STM32F429-DISCO board has the ram attached to bank 2 */
+ /* Timing parameters computed for a 168Mhz clock */
+ /* These parameters are specific to the SDRAM chip on the board */
+
+ cr_tmp = FMC_SDCR_RPIPE_1CLK;
+ cr_tmp |= FMC_SDCR_SDCLK_2HCLK;
+ cr_tmp |= FMC_SDCR_CAS_3CYC;
+ cr_tmp |= FMC_SDCR_NB4;
+ cr_tmp |= FMC_SDCR_MWID_16b;
+ cr_tmp |= FMC_SDCR_NR_12;
+ cr_tmp |= FMC_SDCR_NC_8;
+
+ /* We're programming BANK 2, but per the manual some of the parameters
+ * only work in CR1 and TR1 so we pull those off and put them in the
+ * right place.
+ */
+ FMC_SDCR1 |= (cr_tmp & FMC_SDCR_DNC_MASK);
+ FMC_SDCR2 = cr_tmp;
+
+ tr_tmp = sdram_timing(&timing);
+ FMC_SDTR1 |= (tr_tmp & FMC_SDTR_DNC_MASK);
+ FMC_SDTR2 = tr_tmp;
+
+ /* Now start up the Controller per the manual
+ * - Clock config enable
+ * - PALL state
+ * - set auto refresh
+ * - Load the Mode Register
+ */
+ sdram_command(SDRAM_BANK2, SDRAM_CLK_CONF, 1, 0);
+ msleep_loop(1); /* sleep at least 100uS */
+ sdram_command(SDRAM_BANK2, SDRAM_PALL, 1, 0);
+ sdram_command(SDRAM_BANK2, SDRAM_AUTO_REFRESH, 4, 0);
+ tr_tmp = SDRAM_MODE_BURST_LENGTH_2 |
+ SDRAM_MODE_BURST_TYPE_SEQUENTIAL |
+ SDRAM_MODE_CAS_LATENCY_3 |
+ SDRAM_MODE_OPERATING_MODE_STANDARD |
+ SDRAM_MODE_WRITEBURST_MODE_SINGLE;
+ sdram_command(SDRAM_BANK2, SDRAM_LOAD_MODE, 1, tr_tmp);
+
+ /*
+ * set the refresh counter to insure we kick off an
+ * auto refresh often enough to prevent data loss.
+ */
+ FMC_SDRTR = 683;
+ /* and Poof! a 8 megabytes of ram shows up in the address space */
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.h
new file mode 100644
index 00000000..af97a641
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/sdram.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Chuck McManis
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#ifndef __SDRAM_H
+#define __SDRAM_H
+
+#define SDRAM_BASE_ADDRESS (0xd0000000U)
+
+/* Initialize the SDRAM chip on the board */
+void sdram_init(void);
+
+#ifndef NULL
+#define NULL (void *)(0)
+#endif
+
+#endif
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.c
new file mode 100644
index 00000000..2fec08de
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.c
@@ -0,0 +1,386 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "touchscreen_controller_stmpe811.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*static*/
+stmpe811_t stmpe811;
+
+void
+stmpe811_setup_hardware() {
+
+ rcc_periph_clock_enable(STMPE811_I2C_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_SDA_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_SCL_CLK);
+ rcc_periph_clock_enable(STMPE811_I2C_INT_CLK);
+
+
+ /* STMPE811 interrupt
+ * - INT (the board has a 4.7k pullup resistor for this pin)
+ */
+ gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO15);
+
+ /* I2C */
+ gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
+ gpio_set_output_options(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO8);
+ gpio_set_af(GPIOA, GPIO_AF4, GPIO8);
+
+ gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
+ gpio_set_output_options(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO9);
+ gpio_set_af(GPIOC, GPIO_AF4, GPIO9);
+
+ /* I2C setup */
+ i2c_setup_master(STMPE811_I2C, 400000);
+}
+
+void
+stmpe811_enable_interrupts() {
+ nvic_set_priority(NVIC_EXTI15_10_IRQ, 0xff);
+
+ exti_select_source(EXTI15, GPIOA);
+ exti_set_trigger(EXTI15, EXTI_TRIGGER_FALLING);
+ exti_enable_request(EXTI15);
+ nvic_enable_irq(NVIC_EXTI15_10_IRQ);
+}
+
+void
+stmpe811_setup() {
+ memset((char *)&stmpe811, 0, sizeof(stmpe811_t));
+
+ /** TODO removeme **/
+ stmpe811.last_values_count = 0;
+ stmpe811.touch_interrupts = 0;
+ /*******************/
+
+ /* soft reset */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL1, 2}, 2,
+ NULL, 0);
+ msleep_loop(10);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL1, 0}, 2,
+ NULL, 0);
+ msleep_loop(2);
+
+
+ /* Interrupts */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_EN, 0b00001111}, 2, /* enable FIFO and Touch interrupts */
+ NULL, 0);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_CTRL, 0b011}, 2, /* active low, flank interrupt, global int on */
+ NULL, 0);
+
+
+ /* ADC */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_ADC_CTRL1, 0b00011000}, 2, /* clk sample time 44, 12bit, internal ref */
+ NULL, 0);
+
+ msleep_loop(2);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_ADC_CTRL2, 0b10}, 2, /* ADC clk ~6.5MHz (/44=147kHz) */
+ NULL, 0);
+}
+
+uint8_t
+stmpe811_read_interrupt_status() {
+ uint8_t s;
+ /* read the status */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA}, 1,
+ &s, 1);
+ return s;
+}
+
+void
+stmpe811_start_temp_measurements() {
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /*(uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b0111}, 2,*/ /* turn on temperature sensor */
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b0110}, 2, /* turn on clocks (temp,!gpio,!tsc,adc) */
+ NULL, 0);
+
+ /* Temp */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_CTRL, 0b111}, 2, /* start temp measurement, measure forever (every 10ms) */
+ NULL, 0);
+}
+
+uint16_t
+stmpe811_read_temp_sample() {
+ uint16_t temp;
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_DATA}, 1,
+ (uint8_t *)&temp, 2);
+ temp = (temp<<8)|(temp>>8); /* switch msb/lsb */
+ /* *3Vio/7.51 == 1°C (for some reason this didn't work so i
+ * tinkered with the numbers a little :)) */
+ return (uint16_t)((((uint32_t)temp*30000)/751)>>4);
+}
+
+void
+stmpe811_stop_temp_measuements() {
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b1111}, 2, /* turn on clocks (!temp,!gpio,!tsc,!adc) */
+ NULL, 0);
+
+ /* Temp */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TEMP_CTRL, 0b000}, 2, /* stop */
+ NULL, 0);
+}
+
+#define x8(x) x>>8, x&255
+
+void
+stmpe811_start_tsc() {
+
+ /* clock setup */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_SYS_CTRL2, 0b1100}, 2, /* turn on clocks (!temp,!gpio,tsc,adc) */
+ NULL, 0);
+
+ /* TSC setup */
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_GPIO_ALT_FUNCT, 0b00001111}, 2, /* disable af on gpio */
+ NULL, 0);
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* 2 samples averaging, 500us touch detect delay, 500us settling time */
+ (uint8_t[]){STMPE811_REG_TSC_CFG, 0b01011010}, 2,
+ /* 2 samples averaging, 100us touch detect delay, 100us settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b01010001}, 2,*/
+ /* no averaging, 1ms touch detect delay, 50us settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b00100001}, 2,*/
+ /* no averaging, 1ms touch detect delay, 1ms settling time */
+ /*(uint8_t[]){STMPE811_REG_TSC_CFG,0b00100011}, 2,*/
+ NULL, 0);
+
+ /* Z is not reported, see STMPE811_REG_TSC_CTRL config */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_FRACT_Z, 0b100 }, 2, /* Fraction Z (z accuracy) 4:4 */
+ NULL, 0);
+
+ /* TODO maybe set shield for X- and Y- lines (no improvement..) */
+ /*i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_SHIELD,0b0101 }, 2, // Shield (Ground X- and Y-)
+ NULL, 0);*/
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* Max current on short typ.50mA (max xxxmA)*/
+ (uint8_t[]){STMPE811_REG_TSC_I_DRIVE, 0b1}, 2,
+ /*(typ.20mA (max 35mA))*/
+ /*(uint8_t[]){STMPE811_REG_TSC_I_DRIVE,0b0}, 2,*/
+ NULL, 0);
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ /* No line is connected to GND */
+ (uint8_t[]){STMPE811_REG_TSC_SHIELD, 0b0}, 2,
+ NULL, 0);
+
+ /* setup descriptions for portrait view (0°) */
+ /* bottom left x, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_BL_X, x8(STMPE811_X_MIN)}, 3,
+ NULL, 0);
+ /* bottom left y, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_BL_Y, x8(STMPE811_Y_MIN)}, 3,
+ NULL, 0);
+ /* top right x, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_TR_X, x8(STMPE811_X_MAX)}, 3,
+ NULL, 0);
+ /* top right y, */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_WDW_TR_Y, x8(STMPE811_Y_MAX)}, 3,
+ NULL, 0);
+
+ /* FIFO interrupt threshold 1 samples */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_TH, 1}, 2,
+ NULL, 0);
+ /* Reset FIFO */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_STA, 0b00000001}, 2,
+ NULL, 0);
+ /*msleep_loop(1);*/
+
+ /* Start FIFO */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_STA, 0x20}, 2,
+ NULL, 0);
+
+ /* Clear all the status pending bits if any */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA, 0xFF}, 2,
+ NULL, 0);
+
+ /* window tracking disabled (generate a sample every n-points move), XY acquisition, Enable */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_CTRL, 0b00000011}, 2,
+ NULL, 0);
+
+ msleep_loop(2);
+
+ stmpe811.sample_read_state = STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT;
+}
+
+
+void
+stmpe811_handle_interrupt() {
+ /* initializations here are not needed.. */
+ uint16_t i;
+ /*uint16_t x,y,xmin=0,xmax=0,ymin=0,ymax=0, u,i,v;*/
+ /*uint32_t all_x,all_y;*/
+
+ /*
+ if (!STMPE811_HAS_INTERRUPT()) {
+ return;
+ }
+ */
+
+ /* read the status */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA}, 1,
+ stmpe811.rb, 1);
+
+ /* clear the interrupts */
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_INT_STA, stmpe811.rb[0]}, 2,
+ NULL, 0);
+
+
+ /* handle touch detected */
+ if (stmpe811.rb[0]&STMPE811_INT__TOUCH_DET) {
+ stmpe811.touch_interrupts++;
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_CTRL}, 1,
+ stmpe811.rb+1, 1);
+
+ /* update touch state */
+ stmpe811.current_touch_state = 0 != (stmpe811.rb[1]&STMPE811_TSC_CTRL__TOUCH_DET) ? STMPE811_TOUCH_STATE__TOUCHED : STMPE811_TOUCH_STATE__UNTOUCHED;
+
+ }
+ switch (stmpe811.sample_read_state) {
+ case STMPE811_TOUCH_STATE__UNTOUCHED:
+ case STMPE811_TOUCH_STATE__TOUCHED:
+ stmpe811.touch.touched = 0;
+ stmpe811.sample_read_state = stmpe811.current_touch_state;
+ break;
+ case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ if (stmpe811.interrupt_timeout < mtime() && stmpe811.touch.touched == 0) {
+ stmpe811.sample_read_state = stmpe811.current_touch_state;
+ } else
+ if (stmpe811.current_touch_state == STMPE811_TOUCH_STATE__TOUCHED) {
+ stmpe811.interrupt_timeout = mtime() + STMPE811_INTERRUPT_TIMEOUT;
+ }
+ break;
+ }
+
+ /* handle fifo data */
+ if (stmpe811.rb[0]&STMPE811_INT__FIFO_HAS_DATA) {
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_FIFO_SIZE}, 1,
+ stmpe811.rb+1, 1);
+
+ /* fifo has data (rb[1] should never be 0 here!) */
+ if (stmpe811.rb[1]) {
+ stmpe811.last_values_count = stmpe811.rb[1];
+ i = stmpe811.rb[1]*3;
+
+ i2c_trx_retry(STMPE811_I2C, STMPE811_I2C_ADDRESS,
+ (uint8_t[]){STMPE811_REG_TSC_DATA_XYZ_NA}, 1,
+ stmpe811.rb+2, i);
+
+ i += 2;
+ /*for (u=2; u>4);
+ y = ((uint16_t)(stmpe811.rb[u+1]&0xf)<<8)|(stmpe811.rb[u+2]>>0);*/
+
+ /* 1st stage of filtering.. last STMPE811_SAMPLES_HISTORY_LENGTH samples max 100 deviation (~3%) */
+ stmpe811.last_valid_sample.x = ((uint16_t)(stmpe811.rb[i-3]) << 4)|(stmpe811.rb[i-2]>>4);
+ stmpe811.last_valid_sample.y = ((uint16_t)(stmpe811.rb[i-2]&0xf) << 8)|(stmpe811.rb[i-1]>>0);
+ stmpe811.last_valid_sample.z = (uint16_t)(stmpe811.rb[i-1] & 0xffff);
+ stmpe811.last_valid_sample.sample_is_fresh = 1;
+ stmpe811.drag_timeout = mtime() + STMPE811_DRAG_TIMEOUT;
+
+ switch (stmpe811.sample_read_state) {
+ case STMPE811_TOUCH_STATE__UNTOUCHED: /* TODO unignore this.. */
+ case STMPE811_TOUCH_STATE__TOUCHED:
+ stmpe811.touch.touched = 1;
+ stmpe811.touch.x = stmpe811.last_drag_sample.x = stmpe811.last_valid_sample.x;
+ stmpe811.touch.y = stmpe811.last_drag_sample.y = stmpe811.last_valid_sample.y;
+ stmpe811.touch.z = stmpe811.last_drag_sample.z = stmpe811.last_valid_sample.z;
+ /*stmpe811.last_valid_sample.sample_is_fresh = 0;*/
+ stmpe811.interrupt_timeout = mtime() + STMPE811_INTERRUPT_TIMEOUT;
+
+ stmpe811.sample_read_state = STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT;
+ break;
+ case STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT:
+ break;
+ }
+ }
+ }
+}
+
+stmpe811_touch_state_t
+stmpe811_get_current_touch_state(void) {
+ return stmpe811.current_touch_state;
+}
+stmpe811_touch_t
+stmpe811_get_touch_data(void) {
+ stmpe811_touch_t touch = stmpe811.touch;
+ stmpe811.touch.touched = 0;
+ return touch;
+}
+stmpe811_drag_data_t
+stmpe811_get_drag_data(void) {
+ if ((stmpe811.last_valid_sample.sample_is_fresh)
+ && (stmpe811.sample_read_state == STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT)) {
+ stmpe811_drag_data_t drag_data;
+ stmpe811_valid_sample_t sample = stmpe811.last_valid_sample;
+ drag_data.data_is_valid = 1;
+ /* is more precise, because it has no accumulating conversion errors,
+ * but makes gui implementation harder..
+ drag_data.dx = sample.x - stmpe811.touch.x;
+ drag_data.dy = sample.y - stmpe811.touch.y;
+ */
+ drag_data.dx = sample.x - stmpe811.last_drag_sample.x;
+ drag_data.dy = sample.y - stmpe811.last_drag_sample.y;
+ drag_data.dz = sample.z - stmpe811.last_drag_sample.z;
+ stmpe811.last_drag_sample.x = sample.x;
+ stmpe811.last_drag_sample.y = sample.y;
+ stmpe811.last_drag_sample.z = sample.z;
+ stmpe811.last_valid_sample.sample_is_fresh = 0;
+ return drag_data;
+ } else {
+ return (stmpe811_drag_data_t) {
+ .data_is_valid = stmpe811.drag_timeout > mtime(),
+ .dx = 0, .dy = 0, .dz = 0
+ };
+ }
+}
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.h
new file mode 100644
index 00000000..11cd6842
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/touchscreen_controller_stmpe811.h
@@ -0,0 +1,221 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#ifndef CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_
+#define CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "i2c.h"
+
+
+
+
+/**
+ * STMPE811 definitions
+ */
+
+#ifndef STMPE811_I2C
+#define STMPE811_I2C I2C3
+#define STMPE811_I2C_CLK RCC_I2C3
+/*#define STMPE811_I2C_RST RST_I2C3*/
+
+#define STMPE811_I2C_SDA_CLK RCC_GPIOA
+#define STMPE811_I2C_SDA_PORT GPIOA
+#define STMPE811_I2C_SDA_PIN GPIO8
+#define STMPE811_I2C_SCL_CLK RCC_GPIOC
+#define STMPE811_I2C_SCL_PORT GPIOC
+#define STMPE811_I2C_SCL_PIN GPIO9
+#define STMPE811_I2C_INT_CLK RCC_GPIOA
+#define STMPE811_I2C_INT_PORT GPIOA
+#define STMPE811_I2C_INT_PIN GPIO15
+
+#define STMPE811_I2C_ADDRESS (0b1000001)
+
+#endif
+
+/* registers */
+#define STMPE811_REG_CHIP_ID 0x00
+#define STMPE811_REG_ID_VER 0x02
+#define STMPE811_REG_SYS_CTRL1 0x03
+#define STMPE811_REG_SYS_CTRL2 0x04
+#define STMPE811_REG_SPI_CFG 0x08
+#define STMPE811_REG_INT_CTRL 0x09
+#define STMPE811_REG_INT_EN 0x0A
+#define STMPE811_REG_INT_STA 0x0B
+#define STMPE811_REG_GPIO_INT_EN 0x0C
+#define STMPE811_REG_GPIO_INT_STA 0x0D
+#define STMPE811_REG_ADC_INT_EN 0x0E
+#define STMPE811_REG_ADC_INT_STA 0x0F
+#define STMPE811_REG_GPIO_SET_PIN 0x10
+#define STMPE811_REG_GPIO_CLR_PIN 0x11
+#define STMPE811_REG_GPIO_MP_STA 0x12
+#define STMPE811_REG_GPIO_DIR 0x13
+#define STMPE811_REG_GPIO_ED 0x14
+#define STMPE811_REG_GPIO_RE 0x15
+#define STMPE811_REG_GPIO_FE 0x16
+#define STMPE811_REG_GPIO_ALT_FUNCT 0x17
+#define STMPE811_REG_ADC_CTRL1 0x20
+#define STMPE811_REG_ADC_CTRL2 0x21
+#define STMPE811_REG_ADC_CAPT 0x22
+#define STMPE811_REG_ADC_DATA_CH0 0x30
+#define STMPE811_REG_ADC_DATA_CH1 0x32
+#define STMPE811_REG_ADC_DATA_CH2 0x34
+#define STMPE811_REG_ADC_DATA_CH3 0x36
+#define STMPE811_REG_ADC_DATA_CH4 0x38
+#define STMPE811_REG_ADC_DATA_CH5 0x3A
+#define STMPE811_REG_ADC_DATA_CH6 0x3C
+#define STMPE811_REG_ADC_DATA_CH7 0x3E
+#define STMPE811_REG_TSC_CTRL 0x40
+#define STMPE811_REG_TSC_CFG 0x41
+#define STMPE811_REG_WDW_TR_X 0x42
+#define STMPE811_REG_WDW_TR_Y 0x44
+#define STMPE811_REG_WDW_BL_X 0x46
+#define STMPE811_REG_WDW_BL_Y 0x48
+#define STMPE811_REG_FIFO_TH 0x4A
+#define STMPE811_REG_FIFO_STA 0x4B
+#define STMPE811_REG_FIFO_SIZE 0x4C
+#define STMPE811_REG_TSC_DATA_X 0x4D
+#define STMPE811_REG_TSC_DATA_Y 0x4F
+#define STMPE811_REG_TSC_DATA_Z 0x51
+#define STMPE811_REG_TSC_DATA_XYZ 0x52
+#define STMPE811_REG_TSC_DATA_XYZ_NA 0xD7
+#define STMPE811_REG_TSC_FRACT_Z 0x56
+#define STMPE811_REG_TSC_DATA 0x57
+#define STMPE811_REG_TSC_I_DRIVE 0x58
+#define STMPE811_REG_TSC_SHIELD 0x59
+#define STMPE811_REG_TEMP_CTRL 0x60
+#define STMPE811_REG_TEMP_DATA 0x61
+#define STMPE811_REG_TEMP_TH 0x63
+
+/* interesting bitmasks */
+#define STMPE811_INT__TOUCH_DET (1<<0)
+#define STMPE811_INT__FIFO_TH (1<<1)
+#define STMPE811_INT__FIFO_OFLOW (1<<2)
+#define STMPE811_INT__FIFO_FULL (1<<3)
+#define STMPE811_INT__FIFO_EMPTY (1<<4)
+#define STMPE811_INT__TEMP_SENS (1<<5)
+#define STMPE811_INT__ADC (1<<6)
+#define STMPE811_INT__GPIO (1<<7)
+
+#define STMPE811_INT__FIFO_HAS_DATA ( \
+ STMPE811_INT__FIFO_TH | \
+ STMPE811_INT__FIFO_OFLOW | \
+ STMPE811_INT__FIFO_FULL \
+ )
+
+#define STMPE811_TSC_CTRL__TOUCH_DET (1<<7)
+
+
+
+/**
+ * Touch controller setup
+ */
+/*
+ *
+ */
+#define STMPE811_X_MIN 300
+#define STMPE811_X_MAX 3850
+#define STMPE811_Y_MIN 400
+#define STMPE811_Y_MAX 3900
+
+/* STMPE811_INTERRUPT_TIMEOUT ms no stmpe811-interrupt
+ * shall occur until touch data is considered to set touched again :P */
+#define STMPE811_INTERRUPT_TIMEOUT 300
+#define STMPE811_DRAG_TIMEOUT 300 /* values bigger than STMPE811_INTERRUPT_TIMEOUT make no sense..*/
+
+typedef enum {
+ STMPE811_TOUCH_STATE__UNTOUCHED = 0, /* set by init / timeout in interrupt */
+ STMPE811_TOUCH_STATE__TOUCHED, /* set by touch interrupt */
+ STMPE811_TOUCH_STATE__TOUCHED_WAITING_FOR_TIMEOUT, /* set by */
+} stmpe811_touch_state_t;
+
+typedef struct {
+ int16_t x, y, z;
+} stmpe811_xyz_sample_t;
+typedef struct {
+ uint32_t touched;
+ int16_t x, y, z;
+} stmpe811_touch_t;
+typedef struct {
+ uint32_t sample_is_fresh;
+ int16_t x, y, z;
+} stmpe811_valid_sample_t;
+typedef struct {
+ uint32_t data_is_valid;
+ int16_t dx, dy, dz;
+} stmpe811_drag_data_t;
+typedef struct {
+ /*uint8_t init;*/
+ stmpe811_touch_t touch;
+ stmpe811_touch_state_t sample_read_state;
+ stmpe811_touch_state_t current_touch_state;
+ stmpe811_valid_sample_t last_valid_sample;
+ stmpe811_xyz_sample_t last_drag_sample;
+ uint32_t touch_interrupts;
+ uint32_t last_values_count;
+ /*uint16_t xmin,xmax,ymin,ymax; */ /* made this constant */
+ uint64_t interrupt_timeout;
+ uint64_t drag_timeout;
+ uint8_t rb[128*4+2]; /* fifo read buffer */
+} stmpe811_t;
+
+void
+stmpe811_setup_hardware(void);
+void
+stmpe811_enable_interrupts(void);
+
+void
+stmpe811_setup(void); /*, save_data_t *save_data);*/
+uint8_t
+stmpe811_read_interrupt_status(void);
+void
+stmpe811_start_temp_measurements(void);
+uint16_t
+stmpe811_read_temp_sample(void);
+void
+stmpe811_stop_temp_measuements(void);
+void
+stmpe811_start_tsc(void);
+
+void
+stmpe811_handle_interrupt(void);
+stmpe811_touch_state_t
+stmpe811_get_current_touch_state(void);
+stmpe811_touch_t
+stmpe811_get_touch_data(void);
+stmpe811_drag_data_t
+stmpe811_get_drag_data(void);
+
+
+/* REMOVE ME! DEBUG */
+extern stmpe811_t stmpe811;
+
+#endif /* CODEBASE_DRIVERS_TOUCHSCREEN_CONTROLLER_STMPE811_H_ */
diff --git a/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/bezier.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/bezier.c
new file mode 100644
index 00000000..dcec2875
--- /dev/null
+++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/bezier.c
@@ -0,0 +1,620 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2016 Oliver Meier
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see