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 . + * + */ + + +#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/vector_gfx/bezier.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/bezier.h new file mode 100644 index 00000000..82cb54a8 --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/vector_gfx/drawing.c b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/drawing.c new file mode 100644 index 00000000..3b7440b3 --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/vector_gfx/drawing.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/drawing.h new file mode 100644 index 00000000..d579dcca --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/vector_gfx/matrix.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/matrix.h new file mode 100644 index 00000000..2d07b40a --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/vector_gfx/vector.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/vector.h new file mode 100644 index 00000000..b62ebd00 --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/vector_gfx/vector_gfx.h b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/vector_gfx/vector_gfx.h new file mode 100644 index 00000000..bdf144b7 --- /dev/null +++ b/examples/stm32/f4/stm32f429i-discovery/lcd-ltdc-touch/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/stm32f429i-discovery.ld b/examples/stm32/f4/stm32f429i-discovery/stm32f429i-discovery.ld index 8137997d..b2e5ab2c 100644 --- a/examples/stm32/f4/stm32f429i-discovery/stm32f429i-discovery.ld +++ b/examples/stm32/f4/stm32f429i-discovery/stm32f429i-discovery.ld @@ -25,9 +25,10 @@ MEMORY { rom (rx) : ORIGIN = 0x08000000, LENGTH = 2048K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K /* (esden) This should be 256 but I get segfault. :( */ + ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 192K } /* Include the common ld script. */ -INCLUDE libopencm3_stm32f4.ld +INCLUDE cortex-m-generic.ld diff --git a/examples/stm32/f4/stm32f429i-discovery/usb_cdcacm/cdcacm.c b/examples/stm32/f4/stm32f429i-discovery/usb_cdcacm/cdcacm.c index 9c6bc3ce..fe3ebbd9 100644 --- a/examples/stm32/f4/stm32f429i-discovery/usb_cdcacm/cdcacm.c +++ b/examples/stm32/f4/stm32f429i-discovery/usb_cdcacm/cdcacm.c @@ -168,7 +168,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)) { @@ -183,16 +183,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) @@ -232,9 +232,8 @@ int main(void) rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_OTGHS); - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, - GPIO13 | GPIO14 | GPIO15); - gpio_set_af(GPIOB, GPIO_AF12, GPIO13 | GPIO14 | GPIO15); + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14 | GPIO15); + gpio_set_af(GPIOB, GPIO_AF12, GPIO14 | GPIO15); usbd_dev = usbd_init(&otghs_usb_driver, &dev, &config, usb_strings, 3, diff --git a/examples/stm32/f4/stm32f429i-discovery/usb_midi/usbmidi.c b/examples/stm32/f4/stm32f429i-discovery/usb_midi/usbmidi.c index 64251b0a..359e5063 100644 --- a/examples/stm32/f4/stm32f429i-discovery/usb_midi/usbmidi.c +++ b/examples/stm32/f4/stm32f429i-discovery/usb_midi/usbmidi.c @@ -373,9 +373,8 @@ int main(void) rcc_periph_clock_enable(RCC_OTGHS); /* USB pins */ - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, - GPIO13 | GPIO14 | GPIO15); - gpio_set_af(GPIOB, GPIO_AF12, GPIO13 | GPIO14 | GPIO15); + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14 | GPIO15); + gpio_set_af(GPIOB, GPIO_AF12, GPIO14 | GPIO15); desig_get_unique_id_as_string(usb_serial_number, sizeof(usb_serial_number)); diff --git a/examples/stm32/f4/stm32f429i-discovery/usb_msc/msc.c b/examples/stm32/f4/stm32f429i-discovery/usb_msc/msc.c index 8f59f065..ff0b7a0d 100644 --- a/examples/stm32/f4/stm32f429i-discovery/usb_msc/msc.c +++ b/examples/stm32/f4/stm32f429i-discovery/usb_msc/msc.c @@ -110,9 +110,8 @@ int main(void) rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_OTGHS); - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, - GPIO13 | GPIO14 | GPIO15); - gpio_set_af(GPIOB, GPIO_AF12, GPIO13 | GPIO14 | GPIO15); + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO14 | GPIO15); + gpio_set_af(GPIOB, GPIO_AF12, GPIO14 | GPIO15); msc_dev = usbd_init(&otghs_usb_driver, &dev_descr, &config_descr, usb_strings, 3, diff --git a/examples/stm32/l0/Makefile.include b/examples/stm32/l0/Makefile.include index eeb2680f..5cad08e7 100644 --- a/examples/stm32/l0/Makefile.include +++ b/examples/stm32/l0/Makefile.include @@ -29,7 +29,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m0plus $(FP_FLAGS) OOCD ?= openocd OOCD_INTERFACE ?= stlink-v2-1 -OOCD_BOARD ?= stm32l0discovery +OOCD_TARGET ?= stm32l0 ################################################################################ # 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/l1/Makefile.include b/examples/stm32/l1/Makefile.include index eb5a5f6c..4af62a47 100644 --- a/examples/stm32/l1/Makefile.include +++ b/examples/stm32/l1/Makefile.include @@ -29,7 +29,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd OOCD ?= openocd OOCD_INTERFACE ?= stlink-v2 -OOCD_BOARD ?= stm32ldiscovery +OOCD_TARGET ?= stm32l1 ################################################################################ # 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/l1/stm32l-discovery/button-irq-printf-lowpower/main.c b/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/main.c index ce67b25c..2d051499 100644 --- a/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/main.c +++ b/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/main.c @@ -131,7 +131,7 @@ int _write(int file, char *ptr, int len) */ static void setup_button_press_timer(void) { - timer_reset(TIMER_BUTTON_PRESS); + rcc_periph_reset_pulse(TIMER_BUTTON_PRESS_RST); timer_set_prescaler(TIMER_BUTTON_PRESS, 3999); /* 4Mhz/1000hz - 1 */ timer_set_period(TIMER_BUTTON_PRESS, 0xffff); timer_enable_counter(TIMER_BUTTON_PRESS); @@ -265,7 +265,7 @@ static void reset_clocks(void) .ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV, .ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV, .voltage_scale = PWR_SCALE2, - .flash_config = FLASH_ACR_LATENCY_0WS, + .flash_waitstates = FLASH_ACR_LATENCY_0WS, .apb1_frequency = 4194000, .apb2_frequency = 4194000, .msi_range = RCC_ICSCR_MSIRANGE_4MHZ, diff --git a/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/syscfg.h b/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/syscfg.h index 8ca634ba..86e713b7 100644 --- a/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/syscfg.h +++ b/examples/stm32/l1/stm32l-discovery/button-irq-printf-lowpower/syscfg.h @@ -44,6 +44,7 @@ extern "C" { #define BUTTON_DISCO_USER_isr exti0_isr #define BUTTON_DISCO_USER_NVIC NVIC_EXTI0_IRQ #define TIMER_BUTTON_PRESS TIM7 +#define TIMER_BUTTON_PRESS_RST RST_TIM7 struct state_t { bool falling; diff --git a/examples/stm32/l1/stm32l-discovery/button-irq-printf/main.c b/examples/stm32/l1/stm32l-discovery/button-irq-printf/main.c index 4f5d64fb..acbb987f 100644 --- a/examples/stm32/l1/stm32l-discovery/button-irq-printf/main.c +++ b/examples/stm32/l1/stm32l-discovery/button-irq-printf/main.c @@ -137,7 +137,7 @@ void tim6_isr(void) */ static void setup_tim6(void) { - timer_reset(TIM6); + rcc_periph_reset_pulse(RST_TIM6); /* 24Mhz / 10khz -1. */ timer_set_prescaler(TIM6, 2399); /* 24Mhz/10000hz - 1 */ /* 10khz for 10 ticks = 1 khz overflow = 1ms overflow interrupts */ @@ -154,7 +154,7 @@ static void setup_tim6(void) */ static void setup_tim7(void) { - timer_reset(TIM7); + rcc_periph_reset_pulse(RST_TIM7); timer_set_prescaler(TIM7, 23999); /* 24Mhz/1000hz - 1 */ timer_set_period(TIM7, 0xffff); timer_enable_counter(TIM7); diff --git a/examples/stm32/l4/stm32l476g-disco/basics/Makefile b/examples/stm32/l4/stm32l476g-disco/basics/Makefile new file mode 100644 index 00000000..5a639f9e --- /dev/null +++ b/examples/stm32/l4/stm32l476g-disco/basics/Makefile @@ -0,0 +1,21 @@ +## +## 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 . +## + +BINARY=basics +DEVICE=stm32l476vg + +include ../../Makefile.include diff --git a/examples/stm32/l4/stm32l476g-disco/basics/README.md b/examples/stm32/l4/stm32l476g-disco/basics/README.md new file mode 100644 index 00000000..1961d844 --- /dev/null +++ b/examples/stm32/l4/stm32l476g-disco/basics/README.md @@ -0,0 +1,8 @@ +This demonstrates some basics on the L476G disco board. + +* printf via usart2 to the attached stlink virtual com port. 115200@8n1 +* pll configuration from hsi +* flash wait state configuration +* basic led blinking +* exti interrupts for buttons +* simple timer usage. diff --git a/examples/stm32/l4/stm32l476g-disco/basics/basics.c b/examples/stm32/l4/stm32l476g-disco/basics/basics.c new file mode 100644 index 00000000..6ae272e7 --- /dev/null +++ b/examples/stm32/l4/stm32l476g-disco/basics/basics.c @@ -0,0 +1,199 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2018 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define LED_GREEN_PORT GPIOE +#define LED_GREEN_PIN GPIO8 +#define LED_RED_PORT GPIOB +#define LED_RED_PIN GPIO2 + +/* joysticks are on PA0,1,2,3,5 (center, left, right, up, down) */ +#define JOY_PORT GPIOA +#define JOYC_EXTI EXTI0 +#define JOYC_PIN GPIO0 +#define JOYC_NVIC NVIC_EXTI0_IRQ + +#define USART_CONSOLE USART2 /* PD5/6 , af7 */ + +int _write(int file, char *ptr, int len); + +struct state_t { + bool falling; + int last_hold; + //int tickcount; +}; + +static struct state_t state; + + +static void clock_setup(void) +{ + /* FIXME - this should eventually become a clock struct helper setup */ + rcc_osc_on(RCC_HSI16); + + flash_prefetch_enable(); + flash_set_ws(4); + flash_dcache_enable(); + flash_icache_enable(); + /* 16MHz / 4 = > 4 * 40 = 160MHz VCO => 80MHz main pll */ + rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_HSI16, 4, 40, + 0, 0, RCC_PLLCFGR_PLLR_DIV2); + rcc_osc_on(RCC_PLL); + /* either rcc_wait_for_osc_ready() or do other things */ + + /* Enable clocks for the ports we need */ + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOD); + rcc_periph_clock_enable(RCC_GPIOE); + + /* Enable clocks for peripherals we need */ + rcc_periph_clock_enable(RCC_USART2); + rcc_periph_clock_enable(RCC_TIM7); + rcc_periph_clock_enable(RCC_SYSCFG); + + rcc_set_sysclk_source(RCC_CFGR_SW_PLL); /* careful with the param here! */ + rcc_wait_for_sysclk_status(RCC_PLL); + /* FIXME - eventually handled internally */ + rcc_ahb_frequency = 80e6; + rcc_apb1_frequency = 80e6; + rcc_apb2_frequency = 80e6; +} + +static void usart_setup(void) +{ + /* Setup GPIO pins for USART2 transmit. */ + gpio_mode_setup(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5|GPIO6); + + /* Setup USART2 TX pin as alternate function. */ + gpio_set_af(GPIOD, GPIO_AF7, GPIO5); + + usart_set_baudrate(USART_CONSOLE, 115200); + usart_set_databits(USART_CONSOLE, 8); + usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); + usart_set_mode(USART_CONSOLE, USART_MODE_TX); + usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); + usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); + + /* Finally enable the USART. */ + usart_enable(USART_CONSOLE); +} + +/** + * Use USART_CONSOLE as a console. + * This is a syscall for newlib + * @param file + * @param ptr + * @param len + * @return + */ +int _write(int file, char *ptr, int len) +{ + int i; + + if (file == STDOUT_FILENO || file == STDERR_FILENO) { + for (i = 0; i < len; i++) { + if (ptr[i] == '\n') { + usart_send_blocking(USART_CONSOLE, '\r'); + } + usart_send_blocking(USART_CONSOLE, ptr[i]); + } + return i; + } + errno = EIO; + return -1; +} + +void exti0_isr(void) +{ + exti_reset_request(JOYC_EXTI); + if (state.falling) { + gpio_clear(LED_RED_PORT, LED_RED_PIN); + state.falling = false; + state.last_hold = TIM_CNT(TIM7); + exti_set_trigger(JOYC_EXTI, EXTI_TRIGGER_RISING); + } else { + /* pushed */ + gpio_set(LED_RED_PORT, LED_RED_PIN); + state.falling = true; + TIM_CNT(TIM7) = 0; + state.last_hold = 0; + exti_set_trigger(JOYC_EXTI, EXTI_TRIGGER_FALLING); + } +} + +/* + * Free running ms timer. + */ +static void setup_tim7(void) +{ + rcc_periph_reset_pulse(RST_TIM7); + timer_set_prescaler(TIM7, rcc_apb1_frequency / 1e3 - 1); + timer_set_period(TIM7, 0xffff); + timer_enable_counter(TIM7); +} + + +int main(void) +{ + int j = 0; + clock_setup(); + usart_setup(); + printf("hi guys!\n"); + + /* green led for ticking */ + gpio_mode_setup(LED_GREEN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + LED_GREEN_PIN); + /* red led for buttons */ + gpio_mode_setup(LED_RED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + LED_RED_PIN); + + setup_tim7(); + gpio_mode_setup(JOY_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, JOYC_PIN); + nvic_enable_irq(JOYC_NVIC); + exti_select_source(JOYC_EXTI, JOY_PORT); + state.falling = false; + exti_set_trigger(JOYC_EXTI, EXTI_TRIGGER_RISING); + exti_enable_request(JOYC_EXTI); + + while (1) { + printf("tick: %d\n", j++); + if (state.last_hold) { + printf("button was held for %d ms\n", state.last_hold); + state.last_hold = 0; + } + gpio_toggle(LED_GREEN_PORT, LED_GREEN_PIN); + + for (int i = 0; i < 4000000; i++) { /* Wait a bit. */ + __asm__("NOP"); + } + } + + return 0; +} diff --git a/examples/tiva/lm3s/Makefile.include b/examples/tiva/lm3s/Makefile.include index c0f2c740..34bb24d7 100644 --- a/examples/tiva/lm3s/Makefile.include +++ b/examples/tiva/lm3s/Makefile.include @@ -29,7 +29,7 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) OOCD ?= openocd OOCD_INTERFACE ?= flossjtag -OOCD_BOARD ?= olimex_stm32_h103 +OOCD_TARGET ?= stellaris ################################################################################ # Black Magic Probe specific variables @@ -41,4 +41,4 @@ BMP_PORT ?= #STLINK_PORT ?= :4242 -include ../../../../Makefile.rules +include ../../../../rules.mk diff --git a/examples/tiva/lm3s/lm3s3748-evb/lm3s3748-evb.ld b/examples/tiva/lm3s/lm3s3748-evb/lm3s3748-evb.ld index 66bcbc77..b5b3d8a1 100644 --- a/examples/tiva/lm3s/lm3s3748-evb/lm3s3748-evb.ld +++ b/examples/tiva/lm3s/lm3s3748-evb/lm3s3748-evb.ld @@ -27,4 +27,4 @@ MEMORY } /* Include the common ld script. */ -INCLUDE libopencm3_lm3s.ld +INCLUDE cortex-m-generic.ld diff --git a/examples/tiva/lm3s/lm3s811-evb/lm3s811-evb.ld b/examples/tiva/lm3s/lm3s811-evb/lm3s811-evb.ld index f9a48b15..964d5726 100644 --- a/examples/tiva/lm3s/lm3s811-evb/lm3s811-evb.ld +++ b/examples/tiva/lm3s/lm3s811-evb/lm3s811-evb.ld @@ -27,4 +27,4 @@ MEMORY } /* Include the common ld script. */ -INCLUDE libopencm3_lm3s.ld +INCLUDE cortex-m-generic.ld diff --git a/examples/tiva/lm4f/Makefile.include b/examples/tiva/lm4f/Makefile.include index 3217a06b..c93af2a8 100644 --- a/examples/tiva/lm4f/Makefile.include +++ b/examples/tiva/lm4f/Makefile.include @@ -29,10 +29,11 @@ ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS) # OpenOCD specific variables # Support for ICDI is available starting with openocd 0.7.0 +# but a board file maybe required to select jtag/swd transport OOCD ?= openocd OOCD_INTERFACE ?= ti-icdi -OOCD_BOARD ?= ek-lm4f120xl +OOCD_TARGET ?= stellaris ################################################################################ # Black Magic Probe specific variables @@ -44,4 +45,4 @@ BMP_PORT ?= #STLINK_PORT ?= :4242 -include ../../../../Makefile.rules +include ../../../../rules.mk diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/ek-lm4f120xl.ld b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/ek-lm4f120xl.ld index 4e975eba..dae99054 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/ek-lm4f120xl.ld +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/ek-lm4f120xl.ld @@ -27,4 +27,4 @@ MEMORY } /* Include the common ld script. */ -INCLUDE libopencm3_lm4f.ld +INCLUDE cortex-m-generic.ld diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/miniblink/Makefile b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/miniblink/Makefile index 0dead65e..16169acc 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/miniblink/Makefile +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/miniblink/Makefile @@ -18,7 +18,7 @@ ## BINARY = miniblink - +OOCD_FILE = board/ek-lm4f120xl.cfg LDSCRIPT = ../ek-lm4f120xl.ld include ../../Makefile.include diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_interrupt/Makefile b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_interrupt/Makefile index e3a5a626..c8d4d057 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_interrupt/Makefile +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_interrupt/Makefile @@ -18,7 +18,7 @@ ## BINARY = uart_echo_interrupt - +OOCD_FILE = board/ek-lm4f120xl.cfg LDSCRIPT = ../ek-lm4f120xl.ld include ../../Makefile.include diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_simple/Makefile b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_simple/Makefile index b8e172a9..2551ff90 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_simple/Makefile +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/uart_echo_simple/Makefile @@ -18,7 +18,7 @@ ## BINARY = uart_echo_simple - +OOCD_FILE = board/ek-lm4f120xl.cfg LDSCRIPT = ../ek-lm4f120xl.ld include ../../Makefile.include diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile index 34585121..362ae8f7 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile @@ -18,7 +18,7 @@ ## BINARY = usb_bulk_dev - +OOCD_FILE = board/ek-lm4f120xl.cfg LDSCRIPT = ../ek-lm4f120xl.ld include ../../Makefile.include diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c index 01800e0c..76163606 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c @@ -176,7 +176,6 @@ static const struct usb_config_descriptor config_descr = { .interface = ifaces, }; -extern usbd_driver lm4f_usb_driver; static usbd_device *bulk_dev; static uint8_t usbd_control_buffer[128]; static uint8_t config_set = 0; diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/Makefile b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/Makefile index 14df7a73..b784d668 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/Makefile +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/Makefile @@ -18,7 +18,7 @@ ## BINARY = usb_to_serial_cdcacm - +OOCD_FILE = board/ek-lm4f120xl.cfg LDSCRIPT = ../ek-lm4f120xl.ld diff --git a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/usb_cdcacm.c b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/usb_cdcacm.c index cb42e781..4fcb4c3d 100644 --- a/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/usb_cdcacm.c +++ b/examples/tiva/lm4f/stellaris-ek-lm4f120xl/usb_to_serial_cdcacm/usb_cdcacm.c @@ -171,9 +171,8 @@ static const char *usb_strings[] = { usbd_device *acm_dev; uint8_t usbd_control_buffer[128]; -extern usbd_driver lm4f_usb_driver; -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, @@ -199,13 +198,13 @@ static int cdcacm_control_request(usbd_device * usbd_dev, glue_set_line_state_cb(dtr, rts); - return 1; + return USBD_REQ_HANDLED; } case USB_CDC_REQ_SET_LINE_CODING:{ struct usb_cdc_line_coding *coding; if (*len < sizeof(struct usb_cdc_line_coding)) - return 0; + return USBD_REQ_NOTSUPP; coding = (struct usb_cdc_line_coding *)*buf; return glue_set_line_coding_cb(coding->dwDTERate, @@ -214,7 +213,7 @@ static int cdcacm_control_request(usbd_device * usbd_dev, coding->bCharFormat); } } - return 0; + return USBD_REQ_NOTSUPP; } static void cdcacm_data_rx_cb(usbd_device * usbd_dev, uint8_t ep) diff --git a/examples/vf6xx/colibri-vf61/Makefile.include b/examples/vf6xx/colibri-vf61/Makefile.include index 31bece74..0e30b7d9 100644 --- a/examples/vf6xx/colibri-vf61/Makefile.include +++ b/examples/vf6xx/colibri-vf61/Makefile.include @@ -26,7 +26,4 @@ DEFS += -DVF6XX FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS) -include ../../../Makefile.rules - - - +include ../../../rules.mk diff --git a/examples/vf6xx/colibri-vf61/colibri-vf61.ld b/examples/vf6xx/colibri-vf61/colibri-vf61.ld index 2b1a7fc1..d8296f0c 100644 --- a/examples/vf6xx/colibri-vf61/colibri-vf61.ld +++ b/examples/vf6xx/colibri-vf61/colibri-vf61.ld @@ -34,5 +34,5 @@ MEMORY } /* Include the common ld script. */ -INCLUDE libopencm3_vf6xx.ld +INCLUDE vf6xx/libopencm3_vf6xx.ld diff --git a/libopencm3 b/libopencm3 index 28592a7c..e2b67d72 160000 --- a/libopencm3 +++ b/libopencm3 @@ -1 +1 @@ -Subproject commit 28592a7ca38cdea18028df1b58df38f30d9d14d2 +Subproject commit e2b67d7264b30c02dd534202dd2ff82283e76762