1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-20 06:45:16 +03:00

Merge pull request #32 from betaflight/development

Development
This commit is contained in:
4712betaflight 2016-09-18 17:21:53 +02:00 committed by GitHub
commit c647e2b220
422 changed files with 14521 additions and 7900 deletions

6
.gitignore vendored
View file

@ -18,3 +18,9 @@ startup_stm32f10x_md_gcc.s
docs/Manual.pdf docs/Manual.pdf
README.pdf README.pdf
# artifacts of top-level Makefile
/downloads
/tools
/build
# local changes only
make/local.mk

View file

@ -4,7 +4,7 @@ REVISION=$(git rev-parse --short HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD) BRANCH=$(git rev-parse --abbrev-ref HEAD)
REVISION=$(git rev-parse --short HEAD) REVISION=$(git rev-parse --short HEAD)
LAST_COMMIT_DATE=$(git log -1 --date=short --format="%cd") LAST_COMMIT_DATE=$(git log -1 --date=short --format="%cd")
TARGET_FILE=obj/cleanflight_${TARGET} TARGET_FILE=obj/betaflight_${TARGET}
TRAVIS_REPO_SLUG=${TRAVIS_REPO_SLUG:=$USER/undefined} TRAVIS_REPO_SLUG=${TRAVIS_REPO_SLUG:=$USER/undefined}
BUILDNAME=${BUILDNAME:=travis} BUILDNAME=${BUILDNAME:=travis}
TRAVIS_BUILD_NUMBER=${TRAVIS_BUILD_NUMBER:=undefined} TRAVIS_BUILD_NUMBER=${TRAVIS_BUILD_NUMBER:=undefined}

View file

@ -1,26 +1,58 @@
env: env:
- RUNTESTS=True # - RUNTESTS=True
- PUBLISHMETA=True # - PUBLISHMETA=True
- PUBLISHDOCS=True # - PUBLISHDOCS=True
# - TARGET=AFROMINI
# - TARGET=AIORACERF3
# - TARGET=AIR32
# - TARGET=AIRHEROF3
# - TARGET=ALIENFLIGHTF1
- TARGET=ALIENFLIGHTF3
- TARGET=ALIENFLIGHTF4
- TARGET=BETAFLIGHTF3
- TARGET=BLUEJAYF4
- TARGET=CC3D - TARGET=CC3D
- TARGET=CC3D_OPBL - TARGET=CC3D_OPBL
- TARGET=CC3D_BP6 # - TARGET=CHEBUZZF3
- TARGET=CC3D_OPBL_BP6 # - TARGET=CJMCU
- TARGET=COLIBRI_RACE # - TARGET=COLIBRI
- TARGET=LUX_RACE # - TARGET=COLIBRI_OPBL
- TARGET=CHEBUZZF3 # - TARGET=COLIBRI_RACE
- TARGET=CJMCU # - TARGET=DOGE
- TARGET=EUSTM32F103RC # - TARGET=EUSTM32F103RC
- TARGET=SPRACINGF3 # - TARGET=F4BY
# - TARGET=FURYF3
- TARGET=FURYF4
# - TARGET=IRCFUSIONF3
# - TARGET=ISHAPEDF3
# - TARGET=KISSFC
# - TARGET=LUX_RACE
# - TARGET=MICROSCISKY
# - TARGET=MOTOLAB
- TARGET=NAZE - TARGET=NAZE
- TARGET=NAZE32PRO # - TARGET=OLIMEXINO
- TARGET=OLIMEXINO # - TARGET=OMNIBUS
- TARGET=RMDO # - TARGET=OMNIBUSF4
- TARGET=PORT103R # - TARGET=PIKOBLX
# - TARGET=PORT103R
# - TARGET=RACEBASE
- TARGET=REVO
# - TARGET=REVONANO
# - TARGET=REVO_OPBL
# - TARGET=RMDO
# - TARGET=SINGULARITY
# - TARGET=SIRINFPV
- TARGET=SPARKY - TARGET=SPARKY
# - TARGET=SPARKY2
# - TARGET=SPARKY_OPBL
- TARGET=SPRACINGF3
- TARGET=SPRACINGF3EVO
# - TARGET=SPRACINGF3MINI
- TARGET=STM32F3DISCOVERY - TARGET=STM32F3DISCOVERY
- TARGET=ALIENFLIGHTF1 # - TARGET=VRRACE
- TARGET=ALIENFLIGHTF3 # - TARGET=X_RACERSPI
# - TARGET=ZCOREF3
# - TARGET=RCEXPLORERF3
# use new docker environment # use new docker environment
sudo: false sudo: false
@ -41,18 +73,24 @@ addons:
language: cpp language: cpp
compiler: clang compiler: clang
before_install:
- curl --retry 10 --retry-max-time 120 -L "https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q2-update/+download/gcc-arm-none-eabi-4_9-2015q2-20150609-linux.tar.bz2" | tar xfj -
install: install:
- export PATH=$PATH:$PWD/gcc-arm-none-eabi-4_9-2015q2/bin - make arm_sdk_install
before_script: arm-none-eabi-gcc --version before_script: tools/gcc-arm-none-eabi-5_4-2016q2/bin/arm-none-eabi-gcc --version
script: ./.travis.sh script: ./.travis.sh
cache: apt cache: apt
#notifications:
# irc: "chat.freenode.net#cleanflight"
# use_notice: true
# skip_join: true
notifications: notifications:
irc: "chat.freenode.net#cleanflight" webhooks:
use_notice: true urls:
skip_join: true - https://webhooks.gitter.im/e/0c20f7a1a7e311499a88
on_success: always # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: always # options: [always|never|change] default: always

185
Makefile
View file

@ -37,6 +37,20 @@ SERIAL_DEVICE ?= $(firstword $(wildcard /dev/ttyUSB*) no-port-found)
# Flash size (KB). Some low-end chips actually have more flash than advertised, use this to override. # Flash size (KB). Some low-end chips actually have more flash than advertised, use this to override.
FLASH_SIZE ?= FLASH_SIZE ?=
## Set verbosity level based on the V= parameter
## V=0 Low
## v=1 High
export AT := @
ifndef V
export V0 :=
export V1 := $(AT)
else ifeq ($(V), 0)
export V0 := $(AT)
export V1 := $(AT)
else ifeq ($(V), 1)
endif
############################################################################### ###############################################################################
# Things that need to be maintained as the source changes # Things that need to be maintained as the source changes
# #
@ -53,6 +67,25 @@ INCLUDE_DIRS = $(SRC_DIR) \
$(ROOT)/src/main/target $(ROOT)/src/main/target
LINKER_DIR = $(ROOT)/src/main/target LINKER_DIR = $(ROOT)/src/main/target
## Build tools, so we all share the same versions
# import macros common to all supported build systems
include $(ROOT)/make/system-id.mk
# developer preferences, edit these at will, they'll be gitignored
include $(ROOT)/make/local.mk
# configure some directories that are relative to wherever ROOT_DIR is located
TOOLS_DIR := $(ROOT)/tools
BUILD_DIR := $(ROOT)/build
DL_DIR := $(ROOT)/downloads
export RM := rm
# import macros that are OS specific
include $(ROOT)/make/$(OSFAMILY).mk
# include the tools makefile
include $(ROOT)/make/tools.mk
# default xtal value for F4 targets # default xtal value for F4 targets
HSE_VALUE = 8000000 HSE_VALUE = 8000000
@ -122,9 +155,9 @@ endif
REVISION = $(shell git log -1 --format="%h") REVISION = $(shell git log -1 --format="%h")
FC_VER_MAJOR := $(shell grep " FC_VERSION_MAJOR" src/main/version.h | awk '{print $$3}' ) FC_VER_MAJOR := $(shell grep " FC_VERSION_MAJOR" src/main/build/version.h | awk '{print $$3}' )
FC_VER_MINOR := $(shell grep " FC_VERSION_MINOR" src/main/version.h | awk '{print $$3}' ) FC_VER_MINOR := $(shell grep " FC_VERSION_MINOR" src/main/build/version.h | awk '{print $$3}' )
FC_VER_PATCH := $(shell grep " FC_VERSION_PATCH" src/main/version.h | awk '{print $$3}' ) FC_VER_PATCH := $(shell grep " FC_VERSION_PATCH" src/main/build/version.h | awk '{print $$3}' )
FC_VER := $(FC_VER_MAJOR).$(FC_VER_MINOR).$(FC_VER_PATCH) FC_VER := $(FC_VER_MAJOR).$(FC_VER_MINOR).$(FC_VER_PATCH)
@ -179,7 +212,6 @@ LD_SCRIPT = $(LINKER_DIR)/stm32_flash_f303_$(FLASH_SIZE)k.ld
ARCH_FLAGS = -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wdouble-promotion ARCH_FLAGS = -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wdouble-promotion
DEVICE_FLAGS = -DSTM32F303xC -DSTM32F303 DEVICE_FLAGS = -DSTM32F303xC -DSTM32F303
TARGET_FLAGS = -D$(TARGET)
# End F3 targets # End F3 targets
# #
# Start F4 targets # Start F4 targets
@ -273,7 +305,6 @@ $(error Unknown MCU for F4 target)
endif endif
DEVICE_FLAGS += -DHSE_VALUE=$(HSE_VALUE) DEVICE_FLAGS += -DHSE_VALUE=$(HSE_VALUE)
TARGET_FLAGS = -D$(TARGET)
# End F4 targets # End F4 targets
# #
# Start F1 targets # Start F1 targets
@ -313,7 +344,6 @@ endif
LD_SCRIPT = $(LINKER_DIR)/stm32_flash_f103_$(FLASH_SIZE)k.ld LD_SCRIPT = $(LINKER_DIR)/stm32_flash_f103_$(FLASH_SIZE)k.ld
ARCH_FLAGS = -mthumb -mcpu=cortex-m3 ARCH_FLAGS = -mthumb -mcpu=cortex-m3
TARGET_FLAGS := -D$(TARGET) -pedantic $(TARGET_FLAGS)
ifeq ($(DEVICE_FLAGS),) ifeq ($(DEVICE_FLAGS),)
DEVICE_FLAGS = -DSTM32F10X_MD DEVICE_FLAGS = -DSTM32F10X_MD
@ -332,6 +362,10 @@ ifneq ($(FLASH_SIZE),)
DEVICE_FLAGS := $(DEVICE_FLAGS) -DFLASH_SIZE=$(FLASH_SIZE) DEVICE_FLAGS := $(DEVICE_FLAGS) -DFLASH_SIZE=$(FLASH_SIZE)
endif endif
ifneq ($(HSE_VALUE),)
DEVICE_FLAGS := $(DEVICE_FLAGS) -DHSE_VALUE=$(HSE_VALUE)
endif
TARGET_DIR = $(ROOT)/src/main/target/$(BASE_TARGET) TARGET_DIR = $(ROOT)/src/main/target/$(BASE_TARGET)
TARGET_DIR_SRC = $(notdir $(wildcard $(TARGET_DIR)/*.c)) TARGET_DIR_SRC = $(notdir $(wildcard $(TARGET_DIR)/*.c))
@ -357,19 +391,22 @@ INCLUDE_DIRS := $(INCLUDE_DIRS) \
VPATH := $(VPATH):$(TARGET_DIR) VPATH := $(VPATH):$(TARGET_DIR)
COMMON_SRC = \ COMMON_SRC = \
build_config.c \ build/build_config.c \
debug.c \ build/debug.c \
version.c \ build/version.c \
$(TARGET_DIR_SRC) \ $(TARGET_DIR_SRC) \
main.c \ main.c \
mw.c \ fc/mw.c \
common/encoding.c \ common/encoding.c \
common/filter.c \ common/filter.c \
common/maths.c \ common/maths.c \
common/printf.c \ common/printf.c \
common/streambuf.c \
common/typeconversion.c \ common/typeconversion.c \
config/config.c \ config/config.c \
config/runtime_config.c \ config/config_eeprom.c \
config/feature.c \
fc/runtime_config.c \
drivers/adc.c \ drivers/adc.c \
drivers/buf_writer.c \ drivers/buf_writer.c \
drivers/bus_i2c_soft.c \ drivers/bus_i2c_soft.c \
@ -392,9 +429,11 @@ COMMON_SRC = \
flight/imu.c \ flight/imu.c \
flight/mixer.c \ flight/mixer.c \
flight/pid.c \ flight/pid.c \
flight/pid_legacy.c \
flight/pid_betaflight.c \
io/beeper.c \ io/beeper.c \
io/rc_controls.c \ fc/rc_controls.c \
io/rc_curves.c \ fc/rc_curves.c \
io/serial.c \ io/serial.c \
io/serial_4way.c \ io/serial_4way.c \
io/serial_4way_avrootloader.c \ io/serial_4way_avrootloader.c \
@ -546,10 +585,18 @@ VPATH := $(VPATH):$(STDPERIPH_DIR)/src
# Things that might need changing to use different tools # Things that might need changing to use different tools
# #
# Find out if ccache is installed on the system
CCACHE := ccache
RESULT = $(shell (which $(CCACHE) > /dev/null 2>&1; echo $$?) )
ifneq ($(RESULT),0)
CCACHE :=
endif
# Tool names # Tool names
CC = arm-none-eabi-gcc CC := $(CCACHE) $(ARM_SDK_PREFIX)gcc
OBJCOPY = arm-none-eabi-objcopy CPP := $(CCACHE) $(ARM_SDK_PREFIX)g++
SIZE = arm-none-eabi-size OBJCOPY := $(ARM_SDK_PREFIX)objcopy
SIZE := $(ARM_SDK_PREFIX)size
# #
# Tool options. # Tool options.
@ -574,8 +621,10 @@ CFLAGS += $(ARCH_FLAGS) \
-Wall -Wextra -Wunsafe-loop-optimizations -Wdouble-promotion \ -Wall -Wextra -Wunsafe-loop-optimizations -Wdouble-promotion \
-ffunction-sections \ -ffunction-sections \
-fdata-sections \ -fdata-sections \
-pedantic \
$(DEVICE_FLAGS) \ $(DEVICE_FLAGS) \
-DUSE_STDPERIPH_DRIVER \ -DUSE_STDPERIPH_DRIVER \
-D$(TARGET) \
$(TARGET_FLAGS) \ $(TARGET_FLAGS) \
-D'__FORKNAME__="$(FORKNAME)"' \ -D'__FORKNAME__="$(FORKNAME)"' \
-D'__TARGET__="$(TARGET)"' \ -D'__TARGET__="$(TARGET)"' \
@ -631,39 +680,39 @@ CLEAN_ARTIFACTS += $(TARGET_ELF) $(TARGET_OBJS) $(TARGET_MAP)
# It would be nice to compute these lists, but that seems to be just beyond make. # It would be nice to compute these lists, but that seems to be just beyond make.
$(TARGET_HEX): $(TARGET_ELF) $(TARGET_HEX): $(TARGET_ELF)
$(OBJCOPY) -O ihex --set-start 0x8000000 $< $@ $(V0) $(OBJCOPY) -O ihex --set-start 0x8000000 $< $@
$(TARGET_BIN): $(TARGET_ELF) $(TARGET_BIN): $(TARGET_ELF)
$(OBJCOPY) -O binary $< $@ $(V0) $(OBJCOPY) -O binary $< $@
$(TARGET_ELF): $(TARGET_OBJS) $(TARGET_ELF): $(TARGET_OBJS)
@echo LD $(notdir $@) $(V1) echo LD $(notdir $@)
@$(CC) -o $@ $^ $(LDFLAGS) $(V1) $(CC) -o $@ $^ $(LDFLAGS)
$(SIZE) $(TARGET_ELF) $(V0) $(SIZE) $(TARGET_ELF)
# Compile # Compile
$(OBJECT_DIR)/$(TARGET)/%.o: %.c $(OBJECT_DIR)/$(TARGET)/%.o: %.c
@mkdir -p $(dir $@) $(V1) mkdir -p $(dir $@)
@echo %% $(notdir $<) $(V1) echo %% $(notdir $<)
@$(CC) -c -o $@ $(CFLAGS) $< $(V1) $(CC) -c -o $@ $(CFLAGS) $<
# Assemble # Assemble
$(OBJECT_DIR)/$(TARGET)/%.o: %.s $(OBJECT_DIR)/$(TARGET)/%.o: %.s
@mkdir -p $(dir $@) $(V1) mkdir -p $(dir $@)
@echo %% $(notdir $<) $(V1) echo %% $(notdir $<)
@$(CC) -c -o $@ $(ASFLAGS) $< $(V1) $(CC) -c -o $@ $(ASFLAGS) $<
$(OBJECT_DIR)/$(TARGET)/%.o: %.S $(OBJECT_DIR)/$(TARGET)/%.o: %.S
@mkdir -p $(dir $@) $(V1) mkdir -p $(dir $@)
@echo %% $(notdir $<) $(V1) echo %% $(notdir $<)
@$(CC) -c -o $@ $(ASFLAGS) $< $(V1) $(CC) -c -o $@ $(ASFLAGS) $<
## all : Build all valid targets ## all : Build all valid targets
all: $(VALID_TARGETS) all: $(VALID_TARGETS)
$(VALID_TARGETS): $(VALID_TARGETS):
echo "" && \ $(V0) echo "" && \
echo "Building $@" && \ echo "Building $@" && \
$(MAKE) binary hex TARGET=$@ && \ $(MAKE) binary hex TARGET=$@ && \
echo "Building $@ succeeded." echo "Building $@ succeeded."
@ -675,22 +724,22 @@ TARGETS_CLEAN = $(addsuffix _clean,$(VALID_TARGETS) )
## clean : clean up temporary / machine-generated files ## clean : clean up temporary / machine-generated files
clean: clean:
echo "Cleaning $(TARGET)" $(V0) echo "Cleaning $(TARGET)"
rm -f $(CLEAN_ARTIFACTS) $(V0) rm -f $(CLEAN_ARTIFACTS)
rm -rf $(OBJECT_DIR)/$(TARGET) $(V0) rm -rf $(OBJECT_DIR)/$(TARGET)
echo "Cleaning $(TARGET) succeeded." $(V0) echo "Cleaning $(TARGET) succeeded."
## clean_test : clean up temporary / machine-generated files (tests) ## clean_test : clean up temporary / machine-generated files (tests)
clean_test: clean_test:
cd src/test && $(MAKE) clean || true $(V0) cd src/test && $(MAKE) clean || true
## clean_<TARGET> : clean up one specific target ## clean_<TARGET> : clean up one specific target
$(CLEAN_TARGETS) : $(CLEAN_TARGETS) :
$(MAKE) -j TARGET=$(subst clean_,,$@) clean $(V0) $(MAKE) -j TARGET=$(subst clean_,,$@) clean
## <TARGET>_clean : clean up one specific target (alias for above) ## <TARGET>_clean : clean up one specific target (alias for above)
$(TARGETS_CLEAN) : $(TARGETS_CLEAN) :
$(MAKE) -j TARGET=$(subst _clean,,$@) clean $(V0) $(MAKE) -j TARGET=$(subst _clean,,$@) clean
## clean_all : clean all valid targets ## clean_all : clean all valid targets
clean_all:$(CLEAN_TARGETS) clean_all:$(CLEAN_TARGETS)
@ -700,62 +749,72 @@ all_clean:$(TARGETS_CLEAN)
flash_$(TARGET): $(TARGET_HEX) flash_$(TARGET): $(TARGET_HEX)
stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon $(V0) stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon
echo -n 'R' >$(SERIAL_DEVICE) $(V0) echo -n 'R' >$(SERIAL_DEVICE)
stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE) $(V0) stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE)
## flash : flash firmware (.hex) onto flight controller ## flash : flash firmware (.hex) onto flight controller
flash: flash_$(TARGET) flash: flash_$(TARGET)
st-flash_$(TARGET): $(TARGET_BIN) st-flash_$(TARGET): $(TARGET_BIN)
st-flash --reset write $< 0x08000000 $(V0) st-flash --reset write $< 0x08000000
## st-flash : flash firmware (.bin) onto flight controller ## st-flash : flash firmware (.bin) onto flight controller
st-flash: st-flash_$(TARGET) st-flash: st-flash_$(TARGET)
binary: binary:
$(MAKE) -j $(TARGET_BIN) $(V0) $(MAKE) -j $(TARGET_BIN)
hex: hex:
$(MAKE) -j $(TARGET_HEX) $(V0) $(MAKE) -j $(TARGET_HEX)
unbrick_$(TARGET): $(TARGET_HEX) unbrick_$(TARGET): $(TARGET_HEX)
stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon $(V0) stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon
stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE) $(V0) stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE)
## unbrick : unbrick flight controller ## unbrick : unbrick flight controller
unbrick: unbrick_$(TARGET) unbrick: unbrick_$(TARGET)
## cppcheck : run static analysis on C source code ## cppcheck : run static analysis on C source code
cppcheck: $(CSOURCES) cppcheck: $(CSOURCES)
$(CPPCHECK) $(V0) $(CPPCHECK)
cppcheck-result.xml: $(CSOURCES) cppcheck-result.xml: $(CSOURCES)
$(CPPCHECK) --xml-version=2 2> cppcheck-result.xml $(V0) $(CPPCHECK) --xml-version=2 2> cppcheck-result.xml
## mkdirs
$(DL_DIR):
mkdir -p $@
$(TOOLS_DIR):
mkdir -p $@
$(BUILD_DIR):
mkdir -p $@
## help : print this help message and exit ## help : print this help message and exit
help: Makefile help: Makefile
@echo "" $(V0) @echo ""
@echo "Makefile for the $(FORKNAME) firmware" $(V0) @echo "Makefile for the $(FORKNAME) firmware"
@echo "" $(V0) @echo ""
@echo "Usage:" $(V0) @echo "Usage:"
@echo " make [TARGET=<target>] [OPTIONS=\"<options>\"]" $(V0) @echo " make [V=<verbosity>] [TARGET=<target>] [OPTIONS=\"<options>\"]"
@echo "Or:" $(V0) @echo "Or:"
@echo " make <target> [OPTIONS=\"<options>\"]" $(V0) @echo " make <target> [V=<verbosity>] [OPTIONS=\"<options>\"]"
@echo "" $(V0) @echo ""
@echo "Valid TARGET values are: $(VALID_TARGETS)" $(V0) @echo "Valid TARGET values are: $(VALID_TARGETS)"
@echo "" $(V0) @echo ""
@sed -n 's/^## //p' $< $(V0) @sed -n 's/^## //p' $<
## targets : print a list of all valid target platforms (for consumption by scripts) ## targets : print a list of all valid target platforms (for consumption by scripts)
targets: targets:
@echo "Valid targets: $(VALID_TARGETS)" $(V0) @echo "Valid targets: $(VALID_TARGETS)"
@echo "Target: $(TARGET)" $(V0) @echo "Target: $(TARGET)"
@echo "Base target: $(BASE_TARGET)" $(V0) @echo "Base target: $(BASE_TARGET)"
## test : run the cleanflight test suite ## test : run the cleanflight test suite
test: test:
cd src/test && $(MAKE) test || true $(V0) cd src/test && $(MAKE) test || true
# rebuild everything when makefile changes # rebuild everything when makefile changes
$(TARGET_OBJS) : Makefile $(TARGET_OBJS) : Makefile

View file

@ -61,11 +61,9 @@ If what you need is not covered then refer to the baseflight documentation. If y
## IRC Support and Developers Channel ## IRC Support and Developers Channel
There's a dedicated IRC channel here: There's a dedicated IRCgitter chat channel here:
irc://irc.freenode.net/#cleanflight https://gitter.im/betaflight/betaflight
If you are using windows and don't have an IRC client installed then take a look at HydraIRC - here: http://hydrairc.com/
Etiquette: Don't ask to ask and please wait around long enough for a reply - sometimes people are out flying, asleep or at work and can't answer immediately. Etiquette: Don't ask to ask and please wait around long enough for a reply - sometimes people are out flying, asleep or at work and can't answer immediately.
@ -79,13 +77,13 @@ Please subscribe and '+1' the videos if you find them useful.
## Configuration Tool ## Configuration Tool
To configure Cleanflight you should use the Cleanflight-configurator GUI tool (Windows/OSX/Linux) that can be found here: To configure Betaflight you should use the Betaflight-configurator GUI tool (Windows/OSX/Linux) that can be found here:
https://chrome.google.com/webstore/detail/cleanflight-configurator/enacoimjcgeinfnnnpajinjgmkahmfgb https://chrome.google.com/webstore/detail/betaflight-configurator/kdaghagfopacdngbohiknlhcocjccjao
The source for it is here: The source for it is here:
https://github.com/cleanflight/cleanflight-configurator https://github.com/betaflight/betaflight-configurator
## Contributing ## Contributing
@ -97,10 +95,10 @@ Contributions are welcome and encouraged. You can contribute in many ways:
* New features. * New features.
* Telling us your ideas and suggestions. * Telling us your ideas and suggestions.
The best place to start is the IRC channel on freenode (see above), drop in, say hi. Next place is the github issue tracker: The best place to start is the IRC channel on gitter (see above), drop in, say hi. Next place is the github issue tracker:
https://github.com/cleanflight/cleanflight/issues https://github.com/betaflight/betaflight/issues
https://github.com/cleanflight/cleanflight-configurator/issues https://github.com/betaflight/betaflight-configurator/issues
Before creating new issues please check to see if there is an existing one, search first otherwise you waste peoples time when they could be coding instead! Before creating new issues please check to see if there is an existing one, search first otherwise you waste peoples time when they could be coding instead!
@ -110,11 +108,48 @@ Please refer to the development section in the `docs/development` folder.
TravisCI is used to run automatic builds TravisCI is used to run automatic builds
https://travis-ci.org/cleanflight/cleanflight https://travis-ci.org/betaflight/betaflight
[![Build Status](https://travis-ci.org/cleanflight/cleanflight.svg?branch=master)](https://travis-ci.org/cleanflight/cleanflight) [![Build Status](https://travis-ci.org/betaflight/betaflight.svg?branch=master)](https://travis-ci.org/betaflight/betaflight)
## Cleanflight Releases ## Betaflight Releases
https://github.com/cleanflight/cleanflight/releases https://github.com/betaflight/betaflight/releases
## Open Source / Contributors
Betaflight is software that is **open source** and is available free of charge without warranty to all users.
Betaflight is forked from Cleanflight, so thanks goes to all those whom have contributed to Cleanflight and its origins.
Origins for this fork (Thanks!):
* **Alexinparis** (for MultiWii),
* **timecop** (for Baseflight),
* **Dominic Clifton** (for Cleanflight), and
* **Sambas** (for the original STM32F4 port).
The Betaflight Configurator is forked from Cleanflight Configurator and its origins.
Origins for Betaflight Configurator:
* **Dominic Clifton** (for Cleanflight configurator), and
* **ctn** (for the original Configurator).
Big thanks to current and past contributors:
* Budden, Martin (martinbudden)
* Bardwell, Joshua (joshuabardwell)
* Blackman, Jason (blckmn)
* ctzsnooze
* Höglund, Anders (andershoglund)
* Ledvin, Peter (ledvinap) - **IO code awesomeness!**
* kc10kevin
* Keeble, Gary (MadmanK)
* Keller, Michael (mikeller) - **Configurator brilliance**
* Kravcov, Albert (skaman82) - **Configurator brilliance**
* MJ666
* Nathan (nathantsoi)
* ravnav
* sambas - **bringing us the F4**
* savaga
* Stålheim, Anton (KiteAnton)
And many many others who haven't been mentioned....

14
Vagrantfile vendored
View file

@ -19,8 +19,18 @@ Vagrant.configure(2) do |config|
# documentation for more information about their specific syntax and use. # documentation for more information about their specific syntax and use.
config.vm.provision "shell", inline: <<-SHELL config.vm.provision "shell", inline: <<-SHELL
apt-get remove -y binutils-arm-none-eabi gcc-arm-none-eabi apt-get remove -y binutils-arm-none-eabi gcc-arm-none-eabi
add-apt-repository ppa:terry.guo/gcc-arm-embedded add-apt-repository ppa:team-gcc-arm-embedded/ppa
apt-get update apt-get update
apt-get install -y git gcc-arm-none-eabi=4.9.3.2015q3-1trusty1 apt-get install -y git ccache gcc-arm-embedded=5-2016q2-1~trusty1
SHELL SHELL
end end
# Usage
# On windows start a command shell in the project root directory, where the "Vagrantfile" exists.
# "vagrant up" to start the VM. First time it takes a while.....
# "vagrant ssh" to log into your VM.
# "cd /vagrant" Here are the windows project directory mounted with all your files.
# "make all" Start working, building all targets for example.
# "exit" when done
# vagrant halt to stop your VM
# vagrant --help for more....

View file

@ -21,8 +21,8 @@ targets=("PUBLISHMETA=True" \
"TARGET=DOGE" \ "TARGET=DOGE" \
"TARGET=SINGULARITY" \ "TARGET=SINGULARITY" \
"TARGET=SIRINFPV" \ "TARGET=SIRINFPV" \
"TARGET=X_RACERSPI") "TARGET=X_RACERSPI" \
"TARGET=RCEXPLORERF3")
#fake a travis build environment #fake a travis build environment

35
make/linux.mk Normal file
View file

@ -0,0 +1,35 @@
# linux.mk
#
# Goals:
# Configure an environment that will allow Taulabs GCS and firmware to be built
# on a Linux system. The environment will support the current versions of Qt SDK
# and the ARM toolchain installed to either the Taulabs/tools directory, their
# respective default installation locations, or made available on the system path.
# Check for and find Python 2
# Get Python version, separate major/minor/patch, then put into wordlist
PYTHON_VERSION_=$(wordlist 2,4,$(subst ., ,$(shell python -V 2>&1)))
# Get major version from aforementioned list
PYTHON_MAJOR_VERSION_=$(word 1,$(PYTHON_VERSION_))
# Just in case Make has some weird scope stuff
PYTHON=0
# If the major Python version is the one we want..
ifeq ($(PYTHON_MAJOR_VERSION_),2)
# Then we can just use the normal Python executable
PYTHON:=python
else
# However, this isn't always the case..
# Let's look for `python2`. If `which` doesn't return a null value, then
# it exists!
ifneq ($(shell which python2), "")
PYTHON:=python2
else
# And if it doesn't exist, let's use the default Python, and warn the user.
# PYTHON NOT FOUND.
PYTHON:=python
echo "Python not found."
endif
endif
export PYTHON

2
make/local.mk Normal file
View file

@ -0,0 +1,2 @@
# override the toolchain version, should match the output from of your version of the toolchain: $(arm-none-eabi-gcc -dumpversion)
#GCC_REQUIRED_VERSION=5.4.1

35
make/macosx.mk Normal file
View file

@ -0,0 +1,35 @@
# macosx.mk
#
# Goals:
# Configure an environment that will allow Taulabs GCS and firmware to be built
# on a Mac OSX system. The environment will support the current version of the
# ARM toolchain installed to either their respective default installation
# locations, the tools directory or made available on the system path.
# Check for and find Python 2
# Get Python version, separate major/minor/patch, then put into wordlist
PYTHON_VERSION_=$(wordlist 2,4,$(subst ., ,$(shell python -V 2>&1)))
# Get major version from aforementioned list
PYTHON_MAJOR_VERSION_=$(word 1,$(PYTHON_VERSION_))
# Just in case Make has some weird scope stuff
PYTHON=0
# If the major Python version is the one we want..
ifeq ($(PYTHON_MAJOR_VERSION_),2)
# Then we can just use the normal Python executable
PYTHON:=python
else
# However, this isn't always the case..
# Let's look for `python2`. If `which` doesn't return a null value, then
# it exists!
ifneq ($(shell which python2), "")
PYTHON:=python2
else
# And if it doesn't exist, let's use the default Python, and warn the user.
# PYTHON NOT FOUND.
PYTHON:=python
echo "Python not found."
endif
endif
export PYTHON

50
make/system-id.mk Normal file
View file

@ -0,0 +1,50 @@
# shared.mk
#
# environment variables common to all operating systems supported by the make system
# Make sure we know a few things about the architecture
UNAME := $(shell uname)
ARCH := $(shell uname -m)
ifneq (,$(filter $(ARCH), x86_64 amd64))
X86-64 := 1
X86_64 := 1
AMD64 := 1
ARCHFAMILY := x86_64
else
ARCHFAMILY := $(ARCH)
endif
# configure some variables dependent upon what type of system this is
# Linux
ifeq ($(UNAME), Linux)
OSFAMILY := linux
LINUX := 1
endif
# Mac OSX
ifeq ($(UNAME), Darwin)
OSFAMILY := macosx
MACOSX := 1
endif
# Windows using MinGW shell
ifeq (MINGW, $(findstring MINGW,$(UNAME)))
OSFAMILY := windows
MINGW := 1
WINDOWS := 1
endif
# Windows using Cygwin shell
ifeq (CYGWIN ,$(findstring CYGWIN,$(UNAME)))
OSFAMILY := windows
WINDOWS := 1
CYGWIN := 1
endif
# report an error if we couldn't work out what OS this is running on
ifndef OSFAMILY
$(info uname reports $(UNAME))
$(info uname -m reports $(ARCH))
$(error failed to detect operating system)
endif

331
make/tools.mk Normal file
View file

@ -0,0 +1,331 @@
###############################################################
#
# Installers for tools
#
# NOTE: These are not tied to the default goals
# and must be invoked manually
#
###############################################################
##############################
#
# Check that environmental variables are sane
#
##############################
# Set up ARM (STM32) SDK
ARM_SDK_DIR := $(TOOLS_DIR)/gcc-arm-none-eabi-5_4-2016q2
# Checked below, Should match the output of $(shell arm-none-eabi-gcc -dumpversion)
GCC_REQUIRED_VERSION := 5.4.1
.PHONY: arm_sdk_install
# source: https://launchpad.net/gcc-arm-embedded/5.0/
ifdef LINUX
arm_sdk_install: ARM_SDK_URL := https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-linux.tar.bz2
endif
ifdef MACOSX
arm_sdk_install: ARM_SDK_URL := https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-mac.tar.bz2
endif
ifdef WINDOWS
arm_sdk_install: ARM_SDK_URL := https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-win32.zip
endif
arm_sdk_install: ARM_SDK_FILE := $(notdir $(ARM_SDK_URL))
# order-only prereq on directory existance:
arm_sdk_install: | $(DL_DIR) $(TOOLS_DIR)
arm_sdk_install: arm_sdk_clean
ifneq ($(OSFAMILY), windows)
# download the source only if it's newer than what we already have
$(V1) curl -L -k -o "$(DL_DIR)/$(ARM_SDK_FILE)" "$(ARM_SDK_URL)"
# binary only release so just extract it
$(V1) tar -C $(TOOLS_DIR) -xjf "$(DL_DIR)/$(ARM_SDK_FILE)"
else
$(V1) curl -L -k -o "$(DL_DIR)/$(ARM_SDK_FILE)" "$(ARM_SDK_URL)"
$(V1) unzip -q -d $(ARM_SDK_DIR) "$(DL_DIR)/$(ARM_SDK_FILE)"
endif
.PHONY: arm_sdk_clean
arm_sdk_clean:
$(V1) [ ! -d "$(ARM_SDK_DIR)" ] || $(RM) -r $(ARM_SDK_DIR)
.PHONY: openocd_win_install
openocd_win_install: | $(DL_DIR) $(TOOLS_DIR)
openocd_win_install: OPENOCD_URL := git://git.code.sf.net/p/openocd/code
openocd_win_install: OPENOCD_REV := cf1418e9a85013bbf8dbcc2d2e9985695993d9f4
openocd_win_install: OPENOCD_OPTIONS :=
ifeq ($(OPENOCD_FTDI), yes)
openocd_win_install: OPENOCD_OPTIONS := $(OPENOCD_OPTIONS) --enable-ft2232_ftd2xx --with-ftd2xx-win32-zipdir=$(FTD2XX_DIR)
endif
openocd_win_install: openocd_win_clean libusb_win_install ftd2xx_install
# download the source
$(V0) @echo " DOWNLOAD $(OPENOCD_URL) @ $(OPENOCD_REV)"
$(V1) [ ! -d "$(OPENOCD_BUILD_DIR)" ] || $(RM) -rf "$(OPENOCD_BUILD_DIR)"
$(V1) mkdir -p "$(OPENOCD_BUILD_DIR)"
$(V1) git clone --no-checkout $(OPENOCD_URL) "$(DL_DIR)/openocd-build"
$(V1) ( \
cd $(OPENOCD_BUILD_DIR) ; \
git checkout -q $(OPENOCD_REV) ; \
)
# apply patches
$(V0) @echo " PATCH $(OPENOCD_BUILD_DIR)"
$(V1) ( \
cd $(OPENOCD_BUILD_DIR) ; \
git apply < $(ROOT_DIR)/flight/Project/OpenOCD/0003-freertos-cm4f-fpu-support.patch ; \
git apply < $(ROOT_DIR)/flight/Project/OpenOCD/0004-st-icdi-disable.patch ; \
)
# build and install
$(V0) @echo " BUILD $(OPENOCD_WIN_DIR)"
$(V1) mkdir -p "$(OPENOCD_WIN_DIR)"
$(V1) ( \
cd $(OPENOCD_BUILD_DIR) ; \
./bootstrap ; \
./configure --enable-maintainer-mode --prefix="$(OPENOCD_WIN_DIR)" \
--build=i686-pc-linux-gnu --host=i586-mingw32msvc \
CPPFLAGS=-I$(LIBUSB_WIN_DIR)/include \
LDFLAGS=-L$(LIBUSB_WIN_DIR)/lib/gcc \
$(OPENOCD_OPTIONS) \
--disable-werror \
--enable-stlink ; \
$(MAKE) ; \
$(MAKE) install ; \
)
# delete the extracted source when we're done
$(V1) [ ! -d "$(OPENOCD_BUILD_DIR)" ] || $(RM) -rf "$(OPENOCD_BUILD_DIR)"
.PHONY: openocd_win_clean
openocd_win_clean:
$(V0) @echo " CLEAN $(OPENOCD_WIN_DIR)"
$(V1) [ ! -d "$(OPENOCD_WIN_DIR)" ] || $(RM) -r "$(OPENOCD_WIN_DIR)"
# Set up openocd tools
OPENOCD_DIR := $(TOOLS_DIR)/openocd
OPENOCD_WIN_DIR := $(TOOLS_DIR)/openocd_win
OPENOCD_BUILD_DIR := $(DL_DIR)/openocd-build
.PHONY: openocd_install
openocd_install: | $(DL_DIR) $(TOOLS_DIR)
openocd_install: OPENOCD_URL := git://git.code.sf.net/p/openocd/code
openocd_install: OPENOCD_TAG := v0.9.0
openocd_install: OPENOCD_OPTIONS := --enable-maintainer-mode --prefix="$(OPENOCD_DIR)" --enable-buspirate --enable-stlink
ifeq ($(OPENOCD_FTDI), yes)
openocd_install: OPENOCD_OPTIONS := $(OPENOCD_OPTIONS) --enable-ftdi
endif
ifeq ($(UNAME), Darwin)
openocd_install: OPENOCD_OPTIONS := $(OPENOCD_OPTIONS) --disable-option-checking
endif
openocd_install: openocd_clean
# download the source
$(V0) @echo " DOWNLOAD $(OPENOCD_URL) @ $(OPENOCD_TAG)"
$(V1) [ ! -d "$(OPENOCD_BUILD_DIR)" ] || $(RM) -rf "$(OPENOCD_BUILD_DIR)"
$(V1) mkdir -p "$(OPENOCD_BUILD_DIR)"
$(V1) git clone --no-checkout $(OPENOCD_URL) "$(OPENOCD_BUILD_DIR)"
$(V1) ( \
cd $(OPENOCD_BUILD_DIR) ; \
git checkout -q tags/$(OPENOCD_TAG) ; \
)
# build and install
$(V0) @echo " BUILD $(OPENOCD_DIR)"
$(V1) mkdir -p "$(OPENOCD_DIR)"
$(V1) ( \
cd $(OPENOCD_BUILD_DIR) ; \
./bootstrap ; \
./configure $(OPENOCD_OPTIONS) ; \
$(MAKE) ; \
$(MAKE) install ; \
)
# delete the extracted source when we're done
$(V1) [ ! -d "$(OPENOCD_BUILD_DIR)" ] || $(RM) -rf "$(OPENOCD_BUILD_DIR)"
.PHONY: openocd_clean
openocd_clean:
$(V0) @echo " CLEAN $(OPENOCD_DIR)"
$(V1) [ ! -d "$(OPENOCD_DIR)" ] || $(RM) -r "$(OPENOCD_DIR)"
STM32FLASH_DIR := $(TOOLS_DIR)/stm32flash
.PHONY: stm32flash_install
stm32flash_install: STM32FLASH_URL := http://stm32flash.googlecode.com/svn/trunk
stm32flash_install: STM32FLASH_REV := 61
stm32flash_install: stm32flash_clean
# download the source
$(V0) @echo " DOWNLOAD $(STM32FLASH_URL) @ r$(STM32FLASH_REV)"
$(V1) svn export -q -r "$(STM32FLASH_REV)" "$(STM32FLASH_URL)" "$(STM32FLASH_DIR)"
# build
$(V0) @echo " BUILD $(STM32FLASH_DIR)"
$(V1) $(MAKE) --silent -C $(STM32FLASH_DIR) all
.PHONY: stm32flash_clean
stm32flash_clean:
$(V0) @echo " CLEAN $(STM32FLASH_DIR)"
$(V1) [ ! -d "$(STM32FLASH_DIR)" ] || $(RM) -r "$(STM32FLASH_DIR)"
DFUUTIL_DIR := $(TOOLS_DIR)/dfu-util
.PHONY: dfuutil_install
dfuutil_install: DFUUTIL_URL := http://dfu-util.sourceforge.net/releases/dfu-util-0.8.tar.gz
dfuutil_install: DFUUTIL_FILE := $(notdir $(DFUUTIL_URL))
dfuutil_install: | $(DL_DIR) $(TOOLS_DIR)
dfuutil_install: dfuutil_clean
# download the source
$(V0) @echo " DOWNLOAD $(DFUUTIL_URL)"
$(V1) curl -L -k -o "$(DL_DIR)/$(DFUUTIL_FILE)" "$(DFUUTIL_URL)"
# extract the source
$(V0) @echo " EXTRACT $(DFUUTIL_FILE)"
$(V1) [ ! -d "$(DL_DIR)/dfuutil-build" ] || $(RM) -r "$(DL_DIR)/dfuutil-build"
$(V1) mkdir -p "$(DL_DIR)/dfuutil-build"
$(V1) tar -C $(DL_DIR)/dfuutil-build -xf "$(DL_DIR)/$(DFUUTIL_FILE)"
# build
$(V0) @echo " BUILD $(DFUUTIL_DIR)"
$(V1) mkdir -p "$(DFUUTIL_DIR)"
$(V1) ( \
cd $(DL_DIR)/dfuutil-build/dfu-util-0.8 ; \
./configure --prefix="$(DFUUTIL_DIR)" ; \
$(MAKE) ; \
$(MAKE) install ; \
)
.PHONY: dfuutil_clean
dfuutil_clean:
$(V0) @echo " CLEAN $(DFUUTIL_DIR)"
$(V1) [ ! -d "$(DFUUTIL_DIR)" ] || $(RM) -r "$(DFUUTIL_DIR)"
# Set up uncrustify tools
UNCRUSTIFY_DIR := $(TOOLS_DIR)/uncrustify-0.61
UNCRUSTIFY_BUILD_DIR := $(DL_DIR)/uncrustify
.PHONY: uncrustify_install
uncrustify_install: | $(DL_DIR) $(TOOLS_DIR)
uncrustify_install: UNCRUSTIFY_URL := http://downloads.sourceforge.net/project/uncrustify/uncrustify/uncrustify-0.61/uncrustify-0.61.tar.gz
uncrustify_install: UNCRUSTIFY_FILE := uncrustify-0.61.tar.gz
uncrustify_install: UNCRUSTIFY_OPTIONS := prefix=$(UNCRUSTIFY_DIR)
uncrustify_install: uncrustify_clean
ifneq ($(OSFAMILY), windows)
$(V0) @echo " DOWNLOAD $(UNCRUSTIFY_URL)"
$(V1) curl -L -k -o "$(DL_DIR)/$(UNCRUSTIFY_FILE)" "$(UNCRUSTIFY_URL)"
endif
# extract the src
$(V0) @echo " EXTRACT $(UNCRUSTIFY_FILE)"
$(V1) tar -C $(TOOLS_DIR) -xf "$(DL_DIR)/$(UNCRUSTIFY_FILE)"
$(V0) @echo " BUILD $(UNCRUSTIFY_DIR)"
$(V1) ( \
cd $(UNCRUSTIFY_DIR) ; \
./configure --prefix="$(UNCRUSTIFY_DIR)" ; \
$(MAKE) ; \
$(MAKE) install ; \
)
# delete the extracted source when we're done
$(V1) [ ! -d "$(UNCRUSTIFY_BUILD_DIR)" ] || $(RM) -r "$(UNCRUSTIFY_BUILD_DIR)"
.PHONY: uncrustify_clean
uncrustify_clean:
$(V0) @echo " CLEAN $(UNCRUSTIFY_DIR)"
$(V1) [ ! -d "$(UNCRUSTIFY_DIR)" ] || $(RM) -r "$(UNCRUSTIFY_DIR)"
$(V0) @echo " CLEAN $(UNCRUSTIFY_BUILD_DIR)"
$(V1) [ ! -d "$(UNCRUSTIFY_BUILD_DIR)" ] || $(RM) -r "$(UNCRUSTIFY_BUILD_DIR)"
# ZIP download URL
zip_install: ZIP_URL := http://pkgs.fedoraproject.org/repo/pkgs/zip/zip30.tar.gz/7b74551e63f8ee6aab6fbc86676c0d37/zip30.tar.gz
zip_install: ZIP_FILE := $(notdir $(ZIP_URL))
ZIP_DIR = $(TOOLS_DIR)/zip30
# order-only prereq on directory existance:
zip_install : | $(DL_DIR) $(TOOLS_DIR)
zip_install: zip_clean
$(V1) curl -L -k -o "$(DL_DIR)/$(ZIP_FILE)" "$(ZIP_URL)"
$(V1) tar --force-local -C $(TOOLS_DIR) -xzf "$(DL_DIR)/$(ZIP_FILE)"
ifneq ($(OSFAMILY), windows)
$(V1) cd "$(ZIP_DIR)" && $(MAKE) -f unix/Makefile generic_gcc
else
$(V1) cd "$(ZIP_DIR)" && $(MAKE) -f win32/makefile.gcc
endif
.PHONY: zip_clean
zip_clean:
$(V1) [ ! -d "$(ZIP_DIR)" ] || $(RM) -rf $(ZIP_DIR)
##############################
#
# Set up paths to tools
#
##############################
GCC_VERSION=$(shell arm-none-eabi-gcc -dumpversion)
ifeq ($(shell [ -d "$(ARM_SDK_DIR)" ] && echo "exists"), exists)
ARM_SDK_PREFIX := $(ARM_SDK_DIR)/bin/arm-none-eabi-
else ifeq (,$(findstring _install,$(MAKECMDGOALS)))
ifeq ($(GCC_VERSION),)
$(error **ERROR** arm-none-eabi-gcc not in the PATH. Run 'make arm_sdk_install' to install automatically in the tools folder of this repo)
else ifneq ($(GCC_VERSION), $(GCC_REQUIRED_VERSION))
$(error **ERROR** your arm-none-eabi-gcc is '$(GCC_VERSION)', but '$(GCC_REQUIRED_VERSION)' is expected. Override with 'GCC_REQUIRED_VERSION' in make/local.mk or run 'make arm_sdk_install' to install the right version automatically in the tools folder of this repo)
endif
# not installed, hope it's in the path...
ARM_SDK_PREFIX ?= arm-none-eabi-
endif
ifeq ($(shell [ -d "$(ZIP_DIR)" ] && echo "exists"), exists)
export ZIPBIN := $(ZIP_DIR)/zip
else
export ZIPBIN := zip
endif
ifeq ($(shell [ -d "$(OPENOCD_DIR)" ] && echo "exists"), exists)
OPENOCD := $(OPENOCD_DIR)/bin/openocd
else
# not installed, hope it's in the path...
OPENOCD ?= openocd
endif
ifeq ($(shell [ -d "$(UNCRUSTIFY_DIR)" ] && echo "exists"), exists)
UNCRUSTIFY := $(UNCRUSTIFY_DIR)/bin/uncrustify
else
# not installed, hope it's in the path...
UNCRUSTIFY ?= uncrustify
endif
# Google Breakpad
DUMP_SYMBOLS_TOOL := $(TOOLS_DIR)/breakpad/$(OSFAMILY)-$(ARCHFAMILY)/dump_syms
BREAKPAD_URL := http://dronin.tracer.nz/tools/breakpad.zip
BREAKPAD_DL_FILE := $(DL_DIR)/$(notdir $(BREAKPAD_URL))
BREAKPAD_DIR := $(TOOLS_DIR)/breakpad
.PHONY: breakpad_install
breakpad_install: | $(DL_DIR) $(TOOLS_DIR)
breakpad_install: breakpad_clean
$(V0) @echo " DOWNLOAD $(BREAKPAD_URL)"
$(V1) $(V1) curl -L -k -z "$(BREAKPAD_DL_FILE)" -o "$(BREAKPAD_DL_FILE)" "$(BREAKPAD_URL)"
$(V0) @echo " EXTRACT $(notdir $(BREAKPAD_DL_FILE))"
$(V1) mkdir -p "$(BREAKPAD_DIR)"
$(V1) unzip -q -d $(BREAKPAD_DIR) "$(BREAKPAD_DL_FILE)"
ifeq ($(OSFAMILY), windows)
$(V1) ln -s "$(TOOLS_DIR)/breakpad/$(OSFAMILY)-i686" "$(TOOLS_DIR)/breakpad/$(OSFAMILY)-x86_64"
endif
.PHONY: breakpad_clean
breakpad_clean:
$(V0) @echo " CLEAN $(BREAKPAD_DIR)"
$(V1) [ ! -d "$(BREAKPAD_DIR)" ] || $(RM) -rf $(BREAKPAD_DIR)
$(V0) @echo " CLEAN $(BREAKPAD_DL_FILE)"
$(V1) $(RM) -f $(BREAKPAD_DL_FILE)

14
make/windows.mk Normal file
View file

@ -0,0 +1,14 @@
# windows.mk
#
# Goals:
# Configure an environment that will allow Taulabs GCS and firmware to be built
# on a Windows system. The environment will support the current version of the
# ARM toolchain installed to either their respective default installation
# locations, the tools directory or made available on the system path.
#
# Requirements:
# msysGit
# Python
PYTHON := python
export PYTHON

View file

@ -19,11 +19,12 @@
#include <string.h> #include <string.h>
#include "platform.h" #include "platform.h"
#include "version.h"
#include "debug.h"
#ifdef BLACKBOX #ifdef BLACKBOX
#include "build/version.h"
#include "build/debug.h"
#include "common/maths.h" #include "common/maths.h"
#include "common/axis.h" #include "common/axis.h"
#include "common/color.h" #include "common/color.h"
@ -52,7 +53,7 @@
#include "io/beeper.h" #include "io/beeper.h"
#include "io/display.h" #include "io/display.h"
#include "io/escservo.h" #include "io/escservo.h"
#include "io/rc_controls.h" #include "fc/rc_controls.h"
#include "io/gimbal.h" #include "io/gimbal.h"
#include "io/gps.h" #include "io/gps.h"
#include "io/ledstrip.h" #include "io/ledstrip.h"
@ -72,12 +73,15 @@
#include "flight/altitudehold.h" #include "flight/altitudehold.h"
#include "flight/failsafe.h" #include "flight/failsafe.h"
#include "flight/imu.h" #include "flight/imu.h"
#include "flight/pid.h"
#include "flight/navigation.h" #include "flight/navigation.h"
#include "config/runtime_config.h" #include "fc/runtime_config.h"
#include "config/config.h" #include "config/config.h"
#include "config/config_profile.h" #include "config/config_profile.h"
#include "config/config_master.h" #include "config/config_master.h"
#include "config/feature.h"
#include "blackbox.h" #include "blackbox.h"
#include "blackbox_io.h" #include "blackbox_io.h"
@ -893,6 +897,61 @@ void finishBlackbox(void)
} }
} }
/**
* Test Motors Blackbox Logging
*/
bool startedLoggingInTestMode = false;
void startInTestMode(void)
{
if(!startedLoggingInTestMode) {
if (masterConfig.blackbox_device == BLACKBOX_DEVICE_SERIAL) {
serialPort_t *sharedBlackboxAndMspPort = findSharedSerialPort(FUNCTION_BLACKBOX, FUNCTION_MSP);
if (sharedBlackboxAndMspPort) {
return; // When in test mode, we cannot share the MSP and serial logger port!
}
}
startBlackbox();
startedLoggingInTestMode = true;
}
}
void stopInTestMode(void)
{
if(startedLoggingInTestMode) {
finishBlackbox();
startedLoggingInTestMode = false;
}
}
/**
* We are going to monitor the MSP_SET_MOTOR target variables motor_disarmed[] for values other than minthrottle
* on reading a value (i.e. the user is testing the motors), then we enable test mode logging;
* we monitor when the values return to minthrottle and start a delay timer (5 seconds); if
* the test motors are left at minimum throttle for this delay timer, then we assume we are done testing and
* shutdown the logger.
*
* Of course, after the 5 seconds and shutdown of the logger, the system will be re-enabled to allow the
* test mode to trigger again; its just that the data will be in a second, third, fourth etc log file.
*/
bool inMotorTestMode(void) {
static uint32_t resetTime = 0;
uint16_t inactiveMotorCommand = (feature(FEATURE_3D) ? masterConfig.flight3DConfig.neutral3d : masterConfig.escAndServoConfig.mincommand);
int i;
bool atLeastOneMotorActivated = false;
// set disarmed motor values
for (i = 0; i < MAX_SUPPORTED_MOTORS; i++)
atLeastOneMotorActivated |= (motor_disarmed[i] != inactiveMotorCommand);
if(atLeastOneMotorActivated) {
resetTime = millis() + 5000; // add 5 seconds
return true;
} else {
// Monitor the duration at minimum
return (millis() < resetTime);
}
return false;
}
#ifdef GPS #ifdef GPS
static void writeGPSHomeFrame() static void writeGPSHomeFrame()
{ {
@ -1140,6 +1199,7 @@ static bool blackboxWriteSysinfo()
BLACKBOX_PRINT_HEADER_LINE("Firmware type:%s", "Cleanflight"); BLACKBOX_PRINT_HEADER_LINE("Firmware type:%s", "Cleanflight");
BLACKBOX_PRINT_HEADER_LINE("Firmware revision:Betaflight %s (%s) %s", FC_VERSION_STRING, shortGitRevision, targetName); BLACKBOX_PRINT_HEADER_LINE("Firmware revision:Betaflight %s (%s) %s", FC_VERSION_STRING, shortGitRevision, targetName);
BLACKBOX_PRINT_HEADER_LINE("Firmware date:%s %s", buildDate, buildTime); BLACKBOX_PRINT_HEADER_LINE("Firmware date:%s %s", buildDate, buildTime);
BLACKBOX_PRINT_HEADER_LINE("Craft name:%s", masterConfig.name);
BLACKBOX_PRINT_HEADER_LINE("P interval:%d/%d", masterConfig.blackbox_rate_num, masterConfig.blackbox_rate_denom); BLACKBOX_PRINT_HEADER_LINE("P interval:%d/%d", masterConfig.blackbox_rate_num, masterConfig.blackbox_rate_denom);
BLACKBOX_PRINT_HEADER_LINE("minthrottle:%d", masterConfig.escAndServoConfig.minthrottle); BLACKBOX_PRINT_HEADER_LINE("minthrottle:%d", masterConfig.escAndServoConfig.minthrottle);
BLACKBOX_PRINT_HEADER_LINE("maxthrottle:%d", masterConfig.escAndServoConfig.maxthrottle); BLACKBOX_PRINT_HEADER_LINE("maxthrottle:%d", masterConfig.escAndServoConfig.maxthrottle);
@ -1167,6 +1227,8 @@ static bool blackboxWriteSysinfo()
); );
BLACKBOX_PRINT_HEADER_LINE("looptime:%d", gyro.targetLooptime); BLACKBOX_PRINT_HEADER_LINE("looptime:%d", gyro.targetLooptime);
BLACKBOX_PRINT_HEADER_LINE("gyro_sync_denom:%d", masterConfig.gyro_sync_denom);
BLACKBOX_PRINT_HEADER_LINE("pid_process_denom:%d", masterConfig.pid_process_denom);
BLACKBOX_PRINT_HEADER_LINE("rcRate:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcRate8); BLACKBOX_PRINT_HEADER_LINE("rcRate:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcRate8);
BLACKBOX_PRINT_HEADER_LINE("rcExpo:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcExpo8); BLACKBOX_PRINT_HEADER_LINE("rcExpo:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcExpo8);
BLACKBOX_PRINT_HEADER_LINE("rcYawRate:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcYawRate8); BLACKBOX_PRINT_HEADER_LINE("rcYawRate:%d", masterConfig.profile[masterConfig.current_profile_index].controlRateProfile[masterConfig.profile[masterConfig.current_profile_index].activeRateProfile].rcYawRate8);
@ -1207,25 +1269,47 @@ static bool blackboxWriteSysinfo()
BLACKBOX_PRINT_HEADER_LINE("velPID:%d,%d,%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.P8[PIDVEL], BLACKBOX_PRINT_HEADER_LINE("velPID:%d,%d,%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.P8[PIDVEL],
masterConfig.profile[masterConfig.current_profile_index].pidProfile.I8[PIDVEL], masterConfig.profile[masterConfig.current_profile_index].pidProfile.I8[PIDVEL],
masterConfig.profile[masterConfig.current_profile_index].pidProfile.D8[PIDVEL]); masterConfig.profile[masterConfig.current_profile_index].pidProfile.D8[PIDVEL]);
BLACKBOX_PRINT_HEADER_LINE("yaw_p_limit:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.yaw_p_limit); BLACKBOX_PRINT_HEADER_LINE("dterm_filter_type:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_filter_type);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf_hz:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_lpf_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("yaw_lpf_hz:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.yaw_lpf_hz * 100.0f)); BLACKBOX_PRINT_HEADER_LINE("yaw_lpf_hz:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.yaw_lpf_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("dterm_average_count:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_average_count); BLACKBOX_PRINT_HEADER_LINE("dterm_notch_hz:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_notch_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("dynamic_pid:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.dynamic_pid); BLACKBOX_PRINT_HEADER_LINE("dterm_notch_cutoff:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_notch_cutoff * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("deltaMethod:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.deltaMethod);
BLACKBOX_PRINT_HEADER_LINE("rollPitchItermIgnoreRate:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.rollPitchItermIgnoreRate); BLACKBOX_PRINT_HEADER_LINE("rollPitchItermIgnoreRate:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.rollPitchItermIgnoreRate);
BLACKBOX_PRINT_HEADER_LINE("yawItermIgnoreRate:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.yawItermIgnoreRate); BLACKBOX_PRINT_HEADER_LINE("yawItermIgnoreRate:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.yawItermIgnoreRate);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf_hz:%d", (int)(masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_lpf_hz * 100.0f)); BLACKBOX_PRINT_HEADER_LINE("yaw_p_limit:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.yaw_p_limit);
BLACKBOX_PRINT_HEADER_LINE("dterm_average_count:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.dterm_average_count);
BLACKBOX_PRINT_HEADER_LINE("vbat_pid_compensation:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.vbatPidCompensation);
BLACKBOX_PRINT_HEADER_LINE("pidAtMinThrottle:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.pidAtMinThrottle);
// Betaflight PID controller parameters
BLACKBOX_PRINT_HEADER_LINE("itermThrottleGain:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.itermThrottleGain);
BLACKBOX_PRINT_HEADER_LINE("ptermSRateWeight:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.ptermSRateWeight);
BLACKBOX_PRINT_HEADER_LINE("dtermSetpointWeight:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.dtermSetpointWeight);
BLACKBOX_PRINT_HEADER_LINE("yawRateAccelLimit:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.yawRateAccelLimit);
BLACKBOX_PRINT_HEADER_LINE("rateAccelLimit:%d", masterConfig.profile[masterConfig.current_profile_index].pidProfile.rateAccelLimit);
// End of Betaflight controller parameters
BLACKBOX_PRINT_HEADER_LINE("deadband:%d", masterConfig.rcControlsConfig.deadband); BLACKBOX_PRINT_HEADER_LINE("deadband:%d", masterConfig.rcControlsConfig.deadband);
BLACKBOX_PRINT_HEADER_LINE("yaw_deadband:%d", masterConfig.rcControlsConfig.yaw_deadband); BLACKBOX_PRINT_HEADER_LINE("yaw_deadband:%d", masterConfig.rcControlsConfig.yaw_deadband);
BLACKBOX_PRINT_HEADER_LINE("gyro_lpf:%d", masterConfig.gyro_lpf); BLACKBOX_PRINT_HEADER_LINE("gyro_lpf:%d", masterConfig.gyro_lpf);
BLACKBOX_PRINT_HEADER_LINE("gyro_soft_type:%d", masterConfig.gyro_soft_type);
BLACKBOX_PRINT_HEADER_LINE("gyro_lowpass_hz:%d", (int)(masterConfig.gyro_soft_lpf_hz * 100.0f)); BLACKBOX_PRINT_HEADER_LINE("gyro_lowpass_hz:%d", (int)(masterConfig.gyro_soft_lpf_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("gyro_notch_hz:%d", (int)(masterConfig.gyro_soft_notch_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("gyro_notch_cutoff:%d", (int)(masterConfig.gyro_soft_notch_cutoff * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("acc_lpf_hz:%d", (int)(masterConfig.acc_lpf_hz * 100.0f)); BLACKBOX_PRINT_HEADER_LINE("acc_lpf_hz:%d", (int)(masterConfig.acc_lpf_hz * 100.0f));
BLACKBOX_PRINT_HEADER_LINE("acc_hardware:%d", masterConfig.acc_hardware); BLACKBOX_PRINT_HEADER_LINE("acc_hardware:%d", masterConfig.acc_hardware);
BLACKBOX_PRINT_HEADER_LINE("baro_hardware:%d", masterConfig.baro_hardware); BLACKBOX_PRINT_HEADER_LINE("baro_hardware:%d", masterConfig.baro_hardware);
BLACKBOX_PRINT_HEADER_LINE("mag_hardware:%d", masterConfig.mag_hardware); BLACKBOX_PRINT_HEADER_LINE("mag_hardware:%d", masterConfig.mag_hardware);
BLACKBOX_PRINT_HEADER_LINE("gyro_cal_on_first_arm:%d", masterConfig.gyro_cal_on_first_arm); BLACKBOX_PRINT_HEADER_LINE("gyro_cal_on_first_arm:%d", masterConfig.gyro_cal_on_first_arm);
BLACKBOX_PRINT_HEADER_LINE("vbat_pid_compensation:%d", masterConfig.batteryConfig.vbatPidCompensation); BLACKBOX_PRINT_HEADER_LINE("rc_interpolation:%d", masterConfig.rxConfig.rcInterpolation);
BLACKBOX_PRINT_HEADER_LINE("rc_smooth_interval:%d", masterConfig.rxConfig.rcSmoothInterval); BLACKBOX_PRINT_HEADER_LINE("rc_interpolation_interval:%d", masterConfig.rxConfig.rcInterpolationInterval);
BLACKBOX_PRINT_HEADER_LINE("airmode_activate_throttle:%d", masterConfig.rxConfig.airModeActivateThreshold); BLACKBOX_PRINT_HEADER_LINE("airmode_activate_throttle:%d", masterConfig.rxConfig.airModeActivateThreshold);
BLACKBOX_PRINT_HEADER_LINE("serialrx_provider:%d", masterConfig.rxConfig.serialrx_provider);
BLACKBOX_PRINT_HEADER_LINE("unsynced_fast_pwm:%d", masterConfig.use_unsyncedPwm);
BLACKBOX_PRINT_HEADER_LINE("fast_pwm_protocol:%d", masterConfig.motor_pwm_protocol);
BLACKBOX_PRINT_HEADER_LINE("motor_pwm_rate:%d", masterConfig.motor_pwm_rate);
BLACKBOX_PRINT_HEADER_LINE("debug_mode:%d", masterConfig.debug_mode);
BLACKBOX_PRINT_HEADER_LINE("features:%d", masterConfig.enabledFeatures); BLACKBOX_PRINT_HEADER_LINE("features:%d", masterConfig.enabledFeatures);
default: default:
@ -1505,7 +1589,8 @@ void handleBlackbox(void)
break; break;
case BLACKBOX_STATE_RUNNING: case BLACKBOX_STATE_RUNNING:
// On entry to this state, blackboxIteration, blackboxPFrameIndex and blackboxIFrameIndex are reset to 0 // On entry to this state, blackboxIteration, blackboxPFrameIndex and blackboxIFrameIndex are reset to 0
if (blackboxModeActivationConditionPresent && !IS_RC_MODE_ACTIVE(BOXBLACKBOX)) { // Prevent the Pausing of the log on the mode switch if in Motor Test Mode
if (blackboxModeActivationConditionPresent && !IS_RC_MODE_ACTIVE(BOXBLACKBOX) && !startedLoggingInTestMode) {
blackboxSetState(BLACKBOX_STATE_PAUSED); blackboxSetState(BLACKBOX_STATE_PAUSED);
} else { } else {
blackboxLogIteration(); blackboxLogIteration();
@ -1534,6 +1619,20 @@ void handleBlackbox(void)
// Did we run out of room on the device? Stop! // Did we run out of room on the device? Stop!
if (isBlackboxDeviceFull()) { if (isBlackboxDeviceFull()) {
blackboxSetState(BLACKBOX_STATE_STOPPED); blackboxSetState(BLACKBOX_STATE_STOPPED);
// ensure we reset the test mode flag if we stop due to full memory card
if (startedLoggingInTestMode) startedLoggingInTestMode = false;
} else { // Only log in test mode if there is room!
if(masterConfig.blackbox_on_motor_test) {
// Handle Motor Test Mode
if(inMotorTestMode()) {
if(blackboxState==BLACKBOX_STATE_STOPPED)
startInTestMode();
} else {
if(blackboxState!=BLACKBOX_STATE_STOPPED)
stopInTestMode();
}
}
} }
} }

View file

@ -4,8 +4,8 @@
#include "blackbox_io.h" #include "blackbox_io.h"
#include "version.h" #include "build/version.h"
#include "build_config.h" #include "build/build_config.h"
#include "common/maths.h" #include "common/maths.h"
#include "common/axis.h" #include "common/axis.h"
@ -34,7 +34,7 @@
#include "io/display.h" #include "io/display.h"
#include "io/escservo.h" #include "io/escservo.h"
#include "rx/rx.h" #include "rx/rx.h"
#include "io/rc_controls.h" #include "fc/rc_controls.h"
#include "io/osd.h" #include "io/osd.h"
#include "io/vtx.h" #include "io/vtx.h"
@ -53,9 +53,11 @@
#include "flight/altitudehold.h" #include "flight/altitudehold.h"
#include "flight/failsafe.h" #include "flight/failsafe.h"
#include "flight/imu.h" #include "flight/imu.h"
#include "flight/pid.h"
#include "flight/navigation.h" #include "flight/navigation.h"
#include "config/runtime_config.h" #include "fc/runtime_config.h"
#include "config/config.h" #include "config/config.h"
#include "config/config_profile.h" #include "config/config_profile.h"
#include "config/config_master.h" #include "config/config_master.h"
@ -648,7 +650,7 @@ void blackboxDeviceClose(void)
* of time to shut down asynchronously, we're the only ones that know when to call it. * of time to shut down asynchronously, we're the only ones that know when to call it.
*/ */
if (blackboxPortSharing == PORTSHARING_SHARED) { if (blackboxPortSharing == PORTSHARING_SHARED) {
mspAllocateSerialPorts(&masterConfig.serialConfig); mspSerialAllocatePorts(&masterConfig.serialConfig);
} }
break; break;
default: default:

View file

@ -15,6 +15,8 @@
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>. * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#define DEBUG16_VALUE_COUNT 4 #define DEBUG16_VALUE_COUNT 4
extern int16_t debug[DEBUG16_VALUE_COUNT]; extern int16_t debug[DEBUG16_VALUE_COUNT];
extern uint8_t debugMode; extern uint8_t debugMode;
@ -50,5 +52,10 @@ typedef enum {
DEBUG_MIXER, DEBUG_MIXER,
DEBUG_AIRMODE, DEBUG_AIRMODE,
DEBUG_PIDLOOP, DEBUG_PIDLOOP,
DEBUG_NOTCH,
DEBUG_RC_INTERPOLATION,
DEBUG_VELOCITY,
DEBUG_DTERM_FILTER,
DEBUG_ANGLERATE,
DEBUG_COUNT DEBUG_COUNT
} debugType_e; } debugType_e;

View file

@ -16,7 +16,7 @@
*/ */
#define FC_VERSION_MAJOR 3 // increment when a major release is made (big new feature, etc) #define FC_VERSION_MAJOR 3 // increment when a major release is made (big new feature, etc)
#define FC_VERSION_MINOR 0 // increment when a minor release is made (small new feature, change etc) #define FC_VERSION_MINOR 1 // increment when a minor release is made (small new feature, change etc)
#define FC_VERSION_PATCH_LEVEL 0 // increment when a bug is fixed #define FC_VERSION_PATCH_LEVEL 0 // increment when a bug is fixed
#define STR_HELPER(x) #x #define STR_HELPER(x) #x

View file

@ -17,6 +17,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <math.h> #include <math.h>
#include "common/filter.h" #include "common/filter.h"
@ -55,25 +56,45 @@ float pt1FilterApply4(pt1Filter_t *filter, float input, uint8_t f_cut, float dT)
return filter->state; return filter->state;
} }
/* sets up a biquad Filter */ float filterGetNotchQ(uint16_t centerFreq, uint16_t cutoff) {
void biquadFilterInit(biquadFilter_t *filter, float filterCutFreq, uint32_t refreshRate) float octaves = log2f((float) centerFreq / (float) cutoff) * 2;
{ return sqrtf(powf(2, octaves)) / (powf(2, octaves) - 1);
const float sampleRate = 1 / ((float)refreshRate * 0.000001f); }
/* sets up a biquad Filter */
void biquadFilterInitLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate)
{
biquadFilterInit(filter, filterFreq, refreshRate, BIQUAD_Q, FILTER_LPF);
}
void biquadFilterInit(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType)
{
// setup variables // setup variables
const float omega = 2 * M_PI_FLOAT * filterCutFreq / sampleRate; const float sampleRate = 1 / ((float)refreshRate * 0.000001f);
const float omega = 2 * M_PI_FLOAT * filterFreq / sampleRate;
const float sn = sinf(omega); const float sn = sinf(omega);
const float cs = cosf(omega); const float cs = cosf(omega);
//this is wrong, should be hyperbolic sine const float alpha = sn / (2 * Q);
//alpha = sn * sinf(M_LN2_FLOAT /2 * BIQUAD_BANDWIDTH * omega /sn);
const float alpha = sn / (2 * BIQUAD_Q);
const float b0 = (1 - cs) / 2; float b0, b1, b2, a0, a1, a2;
const float b1 = 1 - cs;
const float b2 = (1 - cs) / 2; switch (filterType) {
const float a0 = 1 + alpha; case FILTER_LPF:
const float a1 = -2 * cs; b0 = (1 - cs) / 2;
const float a2 = 1 - alpha; b1 = 1 - cs;
b2 = (1 - cs) / 2;
a0 = 1 + alpha;
a1 = -2 * cs;
a2 = 1 - alpha;
break;
case FILTER_NOTCH:
b0 = 1;
b1 = -2 * cs;
b2 = 1;
a0 = 1 + alpha;
a1 = -2 * cs;
a2 = 1 - alpha;
break;
}
// precompute the coefficients // precompute the coefficients
filter->b0 = b0 / a0; filter->b0 = b0 / a0;
@ -95,25 +116,124 @@ float biquadFilterApply(biquadFilter_t *filter, float input)
return result; return result;
} }
int32_t filterApplyAverage(int32_t input, uint8_t averageCount, int32_t averageState[DELTA_MAX_SAMPLES]) { /*
int count; * FIR filter
int32_t averageSum = 0; */
void firFilterInit2(firFilter_t *filter, float *buf, uint8_t bufLength, const float *coeffs, uint8_t coeffsLength)
for (count = averageCount-1; count > 0; count--) averageState[count] = averageState[count-1]; {
averageState[0] = input; filter->buf = buf;
for (count = 0; count < averageCount; count++) averageSum += averageState[count]; filter->bufLength = bufLength;
filter->coeffs = coeffs;
return averageSum / averageCount; filter->coeffsLength = coeffsLength;
memset(filter->buf, 0, sizeof(float) * filter->bufLength);
} }
float filterApplyAveragef(float input, uint8_t averageCount, float averageState[DELTA_MAX_SAMPLES]) { /*
int count; * FIR filter initialisation
float averageSum = 0.0f; * If FIR filter is just used for averaging, coeffs can be set to NULL
*/
for (count = averageCount-1; count > 0; count--) averageState[count] = averageState[count-1]; void firFilterInit(firFilter_t *filter, float *buf, uint8_t bufLength, const float *coeffs)
averageState[0] = input; {
for (count = 0; count < averageCount; count++) averageSum += averageState[count]; firFilterInit2(filter, buf, bufLength, coeffs, bufLength);
}
return averageSum / averageCount;
void firFilterUpdate(firFilter_t *filter, float input)
{
memmove(&filter->buf[1], &filter->buf[0], (filter->bufLength-1) * sizeof(input));
filter->buf[0] = input;
}
float firFilterApply(const firFilter_t *filter)
{
float ret = 0.0f;
for (int ii = 0; ii < filter->coeffsLength; ++ii) {
ret += filter->coeffs[ii] * filter->buf[ii];
}
return ret;
}
float firFilterCalcPartialAverage(const firFilter_t *filter, uint8_t count)
{
float ret = 0.0f;
for (int ii = 0; ii < count; ++ii) {
ret += filter->buf[ii];
}
return ret / count;
}
float firFilterCalcAverage(const firFilter_t *filter)
{
return firFilterCalcPartialAverage(filter, filter->coeffsLength);
}
float firFilterLastInput(const firFilter_t *filter)
{
return filter->buf[0];
}
float firFilterGet(const firFilter_t *filter, int index)
{
return filter->buf[index];
}
/*
* int16_t based FIR filter
* Can be directly updated from devices that produce 16-bit data, eg gyros and accelerometers
*/
void firFilterInt16Init2(firFilterInt16_t *filter, int16_t *buf, uint8_t bufLength, const float *coeffs, uint8_t coeffsLength)
{
filter->buf = buf;
filter->bufLength = bufLength;
filter->coeffs = coeffs;
filter->coeffsLength = coeffsLength;
memset(filter->buf, 0, sizeof(int16_t) * filter->bufLength);
}
/*
* FIR filter initialisation
* If FIR filter is just used for averaging, coeffs can be set to NULL
*/
void firFilterInt16Init(firFilterInt16_t *filter, int16_t *buf, uint8_t bufLength, const float *coeffs)
{
firFilterInt16Init2(filter, buf, bufLength, coeffs, bufLength);
}
void firFilterInt16Update(firFilterInt16_t *filter, int16_t input)
{
memmove(&filter->buf[1], &filter->buf[0], (filter->bufLength-1) * sizeof(input));
filter->buf[0] = input;
}
float firFilterInt16Apply(const firFilterInt16_t *filter)
{
float ret = 0.0f;
for (int ii = 0; ii < filter->coeffsLength; ++ii) {
ret += filter->coeffs[ii] * filter->buf[ii];
}
return ret;
}
float firFilterInt16CalcPartialAverage(const firFilterInt16_t *filter, uint8_t count)
{
float ret = 0;
for (int ii = 0; ii < count; ++ii) {
ret += filter->buf[ii];
}
return ret / count;
}
float firFilterInt16CalcAverage(const firFilterInt16_t *filter)
{
return firFilterInt16CalcPartialAverage(filter, filter->coeffsLength);
}
int16_t firFilterInt16LastInput(const firFilterInt16_t *filter)
{
return filter->buf[0];
}
int16_t firFilterInt16Get(const firFilter_t *filter, int index)
{
return filter->buf[index];
} }

View file

@ -29,14 +29,56 @@ typedef struct biquadFilter_s {
float d1, d2; float d1, d2;
} biquadFilter_t; } biquadFilter_t;
typedef enum {
FILTER_PT1 = 0,
FILTER_BIQUAD,
FILTER_FIR,
} filterType_e;
void biquadFilterInit(biquadFilter_t *filter, float filterCutFreq, uint32_t refreshRate); typedef enum {
FILTER_LPF,
FILTER_NOTCH
} biquadFilterType_e;
typedef struct firFilter_s {
float *buf;
const float *coeffs;
uint8_t bufLength;
uint8_t coeffsLength;
} firFilter_t;
typedef struct firFilterInt16_s {
int16_t *buf;
const float *coeffs;
uint8_t bufLength;
uint8_t coeffsLength;
} firFilterInt16_t;
void biquadFilterInitLPF(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate);
void biquadFilterInit(biquadFilter_t *filter, float filterFreq, uint32_t refreshRate, float Q, biquadFilterType_e filterType);
float biquadFilterApply(biquadFilter_t *filter, float input); float biquadFilterApply(biquadFilter_t *filter, float input);
float filterGetNotchQ(uint16_t centerFreq, uint16_t cutoff);
void pt1FilterInit(pt1Filter_t *filter, uint8_t f_cut, float dT); void pt1FilterInit(pt1Filter_t *filter, uint8_t f_cut, float dT);
float pt1FilterApply(pt1Filter_t *filter, float input); float pt1FilterApply(pt1Filter_t *filter, float input);
float pt1FilterApply4(pt1Filter_t *filter, float input, uint8_t f_cut, float dT); float pt1FilterApply4(pt1Filter_t *filter, float input, uint8_t f_cut, float dT);
int32_t filterApplyAverage(int32_t input, uint8_t averageCount, int32_t averageState[DELTA_MAX_SAMPLES]); void firFilterInit(firFilter_t *filter, float *buf, uint8_t bufLength, const float *coeffs);
float filterApplyAveragef(float input, uint8_t averageCount, float averageState[DELTA_MAX_SAMPLES]); void firFilterInit2(firFilter_t *filter, float *buf, uint8_t bufLength, const float *coeffs, uint8_t coeffsLength);
void firFilterUpdate(firFilter_t *filter, float input);
float firFilterApply(const firFilter_t *filter);
float firFilterCalcPartialAverage(const firFilter_t *filter, uint8_t count);
float firFilterCalcAverage(const firFilter_t *filter);
float firFilterLastInput(const firFilter_t *filter);
float firFilterGet(const firFilter_t *filter, int index);
void firFilterInt16Init(firFilterInt16_t *filter, int16_t *buf, uint8_t bufLength, const float *coeffs);
void firFilterInt16Init2(firFilterInt16_t *filter, int16_t *buf, uint8_t bufLength, const float *coeffs, uint8_t coeffsLength);
void firFilterInt16Update(firFilterInt16_t *filter, int16_t input);
float firFilterInt16Apply(const firFilterInt16_t *filter);
float firFilterInt16CalcPartialAverage(const firFilterInt16_t *filter, uint8_t count);
float firFilterInt16CalcAverage(const firFilterInt16_t *filter);
int16_t firFilterInt16LastInput(const firFilterInt16_t *filter);
int16_t firFilterInt16Get(const firFilter_t *filter, int index);

View file

@ -99,6 +99,13 @@ float acos_approx(float x)
} }
#endif #endif
float powerf(float base, int exp) {
float result = base;
for (int count = 1; count < exp; count++) result *= base;
return result;
}
int32_t applyDeadband(int32_t value, int32_t deadband) int32_t applyDeadband(int32_t value, int32_t deadband)
{ {
if (ABS(value) < deadband) { if (ABS(value) < deadband) {

View file

@ -69,6 +69,7 @@ typedef union {
fp_angles_def angles; fp_angles_def angles;
} fp_angles_t; } fp_angles_t;
float powerf(float base, int exp);
int32_t applyDeadband(int32_t value, int32_t deadband); int32_t applyDeadband(int32_t value, int32_t deadband);
void devClear(stdev_t *dev); void devClear(stdev_t *dev);

View file

@ -36,12 +36,11 @@
#include "platform.h" #include "platform.h"
#include "build_config.h" #include "build/build_config.h"
#include "drivers/serial.h" #include "drivers/serial.h"
#include "io/serial.h" #include "io/serial.h"
#include "build_config.h"
#include "printf.h" #include "printf.h"
#ifdef REQUIRE_PRINTF_LONG_SUPPORT #ifdef REQUIRE_PRINTF_LONG_SUPPORT

View file

@ -102,13 +102,10 @@ For further details see source code.
regs Kusti, 23.10.2004 regs Kusti, 23.10.2004
*/ */
#ifndef __TFP_PRINTF__ #pragma once
#define __TFP_PRINTF__
#include <stdarg.h> #include <stdarg.h>
#include "drivers/serial.h"
void init_printf(void *putp, void (*putf) (void *, char)); void init_printf(void *putp, void (*putf) (void *, char));
int tfp_printf(const char *fmt, ...); int tfp_printf(const char *fmt, ...);
@ -119,6 +116,6 @@ int tfp_format(void *putp, void (*putf) (void *, char), const char *fmt, va_list
#define printf tfp_printf #define printf tfp_printf
#define sprintf tfp_sprintf #define sprintf tfp_sprintf
void setPrintfSerialPort(serialPort_t *serialPort); struct serialPort_s;
void setPrintfSerialPort(struct serialPort_s *serialPort);
#endif void printfSupportInit(void);

106
src/main/common/streambuf.c Normal file
View file

@ -0,0 +1,106 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdint.h>
#include "streambuf.h"
void sbufWriteU8(sbuf_t *dst, uint8_t val)
{
*dst->ptr++ = val;
}
void sbufWriteU16(sbuf_t *dst, uint16_t val)
{
sbufWriteU8(dst, val >> 0);
sbufWriteU8(dst, val >> 8);
}
void sbufWriteU32(sbuf_t *dst, uint32_t val)
{
sbufWriteU8(dst, val >> 0);
sbufWriteU8(dst, val >> 8);
sbufWriteU8(dst, val >> 16);
sbufWriteU8(dst, val >> 24);
}
void sbufWriteData(sbuf_t *dst, const void *data, int len)
{
memcpy(dst->ptr, data, len);
dst->ptr += len;
}
void sbufWriteString(sbuf_t *dst, const char *string)
{
sbufWriteData(dst, string, strlen(string));
}
uint8_t sbufReadU8(sbuf_t *src)
{
return *src->ptr++;
}
uint16_t sbufReadU16(sbuf_t *src)
{
uint16_t ret;
ret = sbufReadU8(src);
ret |= sbufReadU8(src) << 8;
return ret;
}
uint32_t sbufReadU32(sbuf_t *src)
{
uint32_t ret;
ret = sbufReadU8(src);
ret |= sbufReadU8(src) << 8;
ret |= sbufReadU8(src) << 16;
ret |= sbufReadU8(src) << 24;
return ret;
}
void sbufReadData(sbuf_t *src, void *data, int len)
{
memcpy(data, src->ptr, len);
}
// reader - return bytes remaining in buffer
// writer - return available space
int sbufBytesRemaining(sbuf_t *buf)
{
return buf->end - buf->ptr;
}
uint8_t* sbufPtr(sbuf_t *buf)
{
return buf->ptr;
}
// advance buffer pointer
// reader - skip data
// writer - commit written data
void sbufAdvance(sbuf_t *buf, int size)
{
buf->ptr += size;
}
// modifies streambuf so that written data are prepared for reading
void sbufSwitchToReader(sbuf_t *buf, uint8_t *base)
{
buf->end = buf->ptr;
buf->ptr = base;
}

View file

@ -0,0 +1,45 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
// simple buffer-based serializer/deserializer without implicit size check
// little-endian encoding implemneted now
typedef struct sbuf_s {
uint8_t *ptr; // data pointer must be first (sbuff_t* is equivalent to uint8_t **)
uint8_t *end;
} sbuf_t;
void sbufWriteU8(sbuf_t *dst, uint8_t val);
void sbufWriteU16(sbuf_t *dst, uint16_t val);
void sbufWriteU32(sbuf_t *dst, uint32_t val);
void sbufWriteData(sbuf_t *dst, const void *data, int len);
void sbufWriteString(sbuf_t *dst, const char *string);
uint8_t sbufReadU8(sbuf_t *src);
uint16_t sbufReadU16(sbuf_t *src);
uint32_t sbufReadU32(sbuf_t *src);
void sbufReadData(sbuf_t *dst, void *data, int len);
int sbufBytesRemaining(sbuf_t *buf);
uint8_t* sbufPtr(sbuf_t *buf);
void sbufAdvance(sbuf_t *buf, int size);
void sbufSwitchToReader(sbuf_t *buf, uint8_t * base);

View file

@ -17,7 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "build_config.h" #include "build/build_config.h"
#include "maths.h" #include "maths.h"
#ifdef REQUIRE_PRINTF_LONG_SUPPORT #ifdef REQUIRE_PRINTF_LONG_SUPPORT

View file

@ -71,4 +71,15 @@ http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
static inline int16_t cmp16(uint16_t a, uint16_t b) { return a-b; } static inline int16_t cmp16(uint16_t a, uint16_t b) { return a-b; }
static inline int32_t cmp32(uint32_t a, uint32_t b) { return a-b; } static inline int32_t cmp32(uint32_t a, uint32_t b) { return a-b; }
// using memcpy_fn will force memcpy function call, instead of inlining it. In most cases function call takes fewer instructions
// than inlined version (inlining is cheaper for very small moves < 8 bytes / 2 store instructions)
#ifdef UNIT_TEST
// Call memcpy when building unittest - this is easier that asm symbol name mangling (symbols start with _underscore on win32)
#include <string.h>
static inline void memcpy_fn ( void * destination, const void * source, size_t num ) { memcpy(destination, source, num); };
#else
void * memcpy_fn ( void * destination, const void * source, size_t num ) asm("memcpy");
#endif
#endif #endif

View file

@ -21,7 +21,8 @@
#include "platform.h" #include "platform.h"
#include "build_config.h" #include "build/build_config.h"
#include "build/debug.h"
#include "blackbox/blackbox_io.h" #include "blackbox/blackbox_io.h"
@ -34,6 +35,7 @@
#include "drivers/accgyro.h" #include "drivers/accgyro.h"
#include "drivers/compass.h" #include "drivers/compass.h"
#include "drivers/system.h" #include "drivers/system.h"
#include "drivers/io.h"
#include "drivers/gpio.h" #include "drivers/gpio.h"
#include "drivers/timer.h" #include "drivers/timer.h"
#include "drivers/pwm_rx.h" #include "drivers/pwm_rx.h"
@ -53,8 +55,8 @@
#include "io/serial.h" #include "io/serial.h"
#include "io/gimbal.h" #include "io/gimbal.h"
#include "io/escservo.h" #include "io/escservo.h"
#include "io/rc_controls.h" #include "fc/rc_controls.h"
#include "io/rc_curves.h" #include "fc/rc_curves.h"
#include "io/ledstrip.h" #include "io/ledstrip.h"
#include "io/gps.h" #include "io/gps.h"
#include "io/osd.h" #include "io/osd.h"
@ -71,11 +73,14 @@
#include "flight/altitudehold.h" #include "flight/altitudehold.h"
#include "flight/navigation.h" #include "flight/navigation.h"
#include "config/runtime_config.h" #include "fc/runtime_config.h"
#include "config/config.h" #include "config/config.h"
#include "config/config_eeprom.h"
#include "config/config_profile.h" #include "config/config_profile.h"
#include "config/config_master.h" #include "config/config_master.h"
#include "config/feature.h"
#ifndef DEFAULT_RX_FEATURE #ifndef DEFAULT_RX_FEATURE
#define DEFAULT_RX_FEATURE FEATURE_RX_PARALLEL_PWM #define DEFAULT_RX_FEATURE FEATURE_RX_PARALLEL_PWM
@ -89,89 +94,18 @@
#endif #endif
void useRcControlsConfig(modeActivationCondition_t *modeActivationConditions, escAndServoConfig_t *escAndServoConfigToUse, pidProfile_t *pidProfileToUse); void useRcControlsConfig(modeActivationCondition_t *modeActivationConditions, escAndServoConfig_t *escAndServoConfigToUse, pidProfile_t *pidProfileToUse);
void targetConfiguration(void); void targetConfiguration(master_t *config);
#if !defined(FLASH_SIZE)
#error "Flash size not defined for target. (specify in KB)"
#endif
#ifndef FLASH_PAGE_SIZE
#ifdef STM32F303xC
#define FLASH_PAGE_SIZE ((uint16_t)0x800)
#endif
#ifdef STM32F10X_MD
#define FLASH_PAGE_SIZE ((uint16_t)0x400)
#endif
#ifdef STM32F10X_HD
#define FLASH_PAGE_SIZE ((uint16_t)0x800)
#endif
#if defined(STM32F40_41xxx)
#define FLASH_PAGE_SIZE ((uint32_t)0x20000)
#endif
#if defined (STM32F411xE)
#define FLASH_PAGE_SIZE ((uint32_t)0x20000)
#endif
#endif
#if !defined(FLASH_SIZE) && !defined(FLASH_PAGE_COUNT)
#ifdef STM32F10X_MD
#define FLASH_PAGE_COUNT 128
#endif
#ifdef STM32F10X_HD
#define FLASH_PAGE_COUNT 128
#endif
#endif
#if defined(FLASH_SIZE)
#if defined(STM32F40_41xxx)
#define FLASH_PAGE_COUNT 4 // just to make calculations work
#elif defined (STM32F411xE)
#define FLASH_PAGE_COUNT 4 // just to make calculations work
#else
#define FLASH_PAGE_COUNT ((FLASH_SIZE * 0x400) / FLASH_PAGE_SIZE)
#endif
#endif
#if !defined(FLASH_PAGE_SIZE)
#error "Flash page size not defined for target."
#endif
#if !defined(FLASH_PAGE_COUNT)
#error "Flash page count not defined for target."
#endif
#if FLASH_SIZE <= 128
#define FLASH_TO_RESERVE_FOR_CONFIG 0x800
#else
#define FLASH_TO_RESERVE_FOR_CONFIG 0x1000
#endif
// use the last flash pages for storage
#ifdef CUSTOM_FLASH_MEMORY_ADDRESS
size_t custom_flash_memory_address = 0;
#define CONFIG_START_FLASH_ADDRESS (custom_flash_memory_address)
#else
// use the last flash pages for storage
#ifndef CONFIG_START_FLASH_ADDRESS
#define CONFIG_START_FLASH_ADDRESS (0x08000000 + (uint32_t)((FLASH_PAGE_SIZE * FLASH_PAGE_COUNT) - FLASH_TO_RESERVE_FOR_CONFIG))
#endif
#endif
master_t masterConfig; // master config struct with data independent from profiles master_t masterConfig; // master config struct with data independent from profiles
profile_t *currentProfile; profile_t *currentProfile;
static uint32_t activeFeaturesLatch = 0;
static uint8_t currentControlRateProfileIndex = 0; static uint8_t currentControlRateProfileIndex = 0;
controlRateConfig_t *currentControlRateProfile; controlRateConfig_t *currentControlRateProfile;
static const uint8_t EEPROM_CONF_VERSION = 141;
void intFeatureClearAll(master_t *config);
void intFeatureSet(uint32_t mask, master_t *config);
void intFeatureClear(uint32_t mask, master_t *config);
static void resetAccelerometerTrims(flightDynamicsTrims_t *accelerometerTrims) static void resetAccelerometerTrims(flightDynamicsTrims_t *accelerometerTrims)
{ {
@ -180,22 +114,37 @@ static void resetAccelerometerTrims(flightDynamicsTrims_t *accelerometerTrims)
accelerometerTrims->values.yaw = 0; accelerometerTrims->values.yaw = 0;
} }
void resetPidProfile(pidProfile_t *pidProfile) static void resetControlRateConfig(controlRateConfig_t *controlRateConfig)
{ {
controlRateConfig->rcRate8 = 100;
controlRateConfig->rcYawRate8 = 100;
controlRateConfig->rcExpo8 = 0;
controlRateConfig->thrMid8 = 50;
controlRateConfig->thrExpo8 = 0;
controlRateConfig->dynThrPID = 10;
controlRateConfig->rcYawExpo8 = 0;
controlRateConfig->tpa_breakpoint = 1650;
#if (defined(STM32F10X)) for (uint8_t axis = 0; axis < FLIGHT_DYNAMICS_INDEX_COUNT; axis++) {
pidProfile->pidController = PID_CONTROLLER_INTEGER; controlRateConfig->rates[axis] = 70;
}
}
static void resetPidProfile(pidProfile_t *pidProfile)
{
#if defined(SKIP_PID_FLOAT)
pidProfile->pidController = PID_CONTROLLER_LEGACY;
#else #else
pidProfile->pidController = PID_CONTROLLER_FLOAT; pidProfile->pidController = PID_CONTROLLER_BETAFLIGHT;
#endif #endif
pidProfile->P8[ROLL] = 45; pidProfile->P8[ROLL] = 45;
pidProfile->I8[ROLL] = 40; pidProfile->I8[ROLL] = 40;
pidProfile->D8[ROLL] = 18; pidProfile->D8[ROLL] = 20;
pidProfile->P8[PITCH] = 50; pidProfile->P8[PITCH] = 60;
pidProfile->I8[PITCH] = 40; pidProfile->I8[PITCH] = 65;
pidProfile->D8[PITCH] = 18; pidProfile->D8[PITCH] = 22;
pidProfile->P8[YAW] = 80; pidProfile->P8[YAW] = 70;
pidProfile->I8[YAW] = 45; pidProfile->I8[YAW] = 45;
pidProfile->D8[YAW] = 20; pidProfile->D8[YAW] = 20;
pidProfile->P8[PIDALT] = 50; pidProfile->P8[PIDALT] = 50;
@ -219,12 +168,23 @@ void resetPidProfile(pidProfile_t *pidProfile)
pidProfile->D8[PIDVEL] = 75; pidProfile->D8[PIDVEL] = 75;
pidProfile->yaw_p_limit = YAW_P_LIMIT_MAX; pidProfile->yaw_p_limit = YAW_P_LIMIT_MAX;
pidProfile->yaw_lpf_hz = 80; pidProfile->yaw_lpf_hz = 0;
pidProfile->rollPitchItermIgnoreRate = 180; pidProfile->rollPitchItermIgnoreRate = 130;
pidProfile->yawItermIgnoreRate = 35; pidProfile->yawItermIgnoreRate = 32;
pidProfile->dterm_filter_type = FILTER_BIQUAD;
pidProfile->dterm_lpf_hz = 100; // filtering ON by default pidProfile->dterm_lpf_hz = 100; // filtering ON by default
pidProfile->dterm_notch_hz = 260;
pidProfile->dterm_notch_cutoff = 160;
pidProfile->deltaMethod = DELTA_FROM_MEASUREMENT; pidProfile->deltaMethod = DELTA_FROM_MEASUREMENT;
pidProfile->dynamic_pid = 1; pidProfile->vbatPidCompensation = 0;
pidProfile->pidAtMinThrottle = PID_STABILISATION_ON;
// Betaflight PID controller parameters
pidProfile->ptermSRateWeight = 85;
pidProfile->dtermSetpointWeight = 150;
pidProfile->yawRateAccelLimit = 220;
pidProfile->rateAccelLimit = 0;
pidProfile->itermThrottleGain = 0;
#ifdef GTUNE #ifdef GTUNE
pidProfile->gtune_lolimP[ROLL] = 10; // [0..200] Lower limit of ROLL P during G tune. pidProfile->gtune_lolimP[ROLL] = 10; // [0..200] Lower limit of ROLL P during G tune.
@ -239,6 +199,17 @@ void resetPidProfile(pidProfile_t *pidProfile)
#endif #endif
} }
void resetProfile(profile_t *profile)
{
resetPidProfile(&profile->pidProfile);
for (int rI = 0; rI<MAX_RATEPROFILES; rI++) {
resetControlRateConfig(&profile->controlRateProfile[rI]);
}
profile->activeRateProfile = 0;
}
#ifdef GPS #ifdef GPS
void resetGpsProfile(gpsProfile_t *gpsProfile) void resetGpsProfile(gpsProfile_t *gpsProfile)
{ {
@ -252,6 +223,7 @@ void resetGpsProfile(gpsProfile_t *gpsProfile)
} }
#endif #endif
#ifdef BARO
void resetBarometerConfig(barometerConfig_t *barometerConfig) void resetBarometerConfig(barometerConfig_t *barometerConfig)
{ {
barometerConfig->baro_sample_count = 21; barometerConfig->baro_sample_count = 21;
@ -259,6 +231,7 @@ void resetBarometerConfig(barometerConfig_t *barometerConfig)
barometerConfig->baro_cf_vel = 0.985f; barometerConfig->baro_cf_vel = 0.985f;
barometerConfig->baro_cf_alt = 0.965f; barometerConfig->baro_cf_alt = 0.965f;
} }
#endif
void resetSensorAlignment(sensorAlignmentConfig_t *sensorAlignmentConfig) void resetSensorAlignment(sensorAlignmentConfig_t *sensorAlignmentConfig)
{ {
@ -271,14 +244,13 @@ void resetEscAndServoConfig(escAndServoConfig_t *escAndServoConfig)
{ {
#ifdef BRUSHED_MOTORS #ifdef BRUSHED_MOTORS
escAndServoConfig->minthrottle = 1000; escAndServoConfig->minthrottle = 1000;
escAndServoConfig->maxthrottle = 2000;
#else #else
escAndServoConfig->minthrottle = 1150; escAndServoConfig->minthrottle = 1070;
escAndServoConfig->maxthrottle = 1850;
#endif #endif
escAndServoConfig->maxthrottle = 2000;
escAndServoConfig->mincommand = 1000; escAndServoConfig->mincommand = 1000;
escAndServoConfig->servoCenterPulse = 1500; escAndServoConfig->servoCenterPulse = 1500;
escAndServoConfig->escDesyncProtection = 0; escAndServoConfig->maxEscThrottleJumpMs = 0;
} }
void resetFlight3DConfig(flight3DConfig_t *flight3DConfig) void resetFlight3DConfig(flight3DConfig_t *flight3DConfig)
@ -289,9 +261,10 @@ void resetFlight3DConfig(flight3DConfig_t *flight3DConfig)
flight3DConfig->deadband3d_throttle = 50; flight3DConfig->deadband3d_throttle = 50;
} }
#ifdef TELEMETRY
void resetTelemetryConfig(telemetryConfig_t *telemetryConfig) void resetTelemetryConfig(telemetryConfig_t *telemetryConfig)
{ {
telemetryConfig->telemetry_inversion = 0; telemetryConfig->telemetry_inversion = 1;
telemetryConfig->telemetry_switch = 0; telemetryConfig->telemetry_switch = 0;
telemetryConfig->gpsNoFixLatitude = 0; telemetryConfig->gpsNoFixLatitude = 0;
telemetryConfig->gpsNoFixLongitude = 0; telemetryConfig->gpsNoFixLongitude = 0;
@ -300,7 +273,9 @@ void resetTelemetryConfig(telemetryConfig_t *telemetryConfig)
telemetryConfig->frsky_vfas_precision = 0; telemetryConfig->frsky_vfas_precision = 0;
telemetryConfig->frsky_vfas_cell_voltage = 0; telemetryConfig->frsky_vfas_cell_voltage = 0;
telemetryConfig->hottAlarmSoundInterval = 5; telemetryConfig->hottAlarmSoundInterval = 5;
telemetryConfig->pidValuesAsTelemetry = 0;
} }
#endif
void resetBatteryConfig(batteryConfig_t *batteryConfig) void resetBatteryConfig(batteryConfig_t *batteryConfig)
{ {
@ -311,11 +286,11 @@ void resetBatteryConfig(batteryConfig_t *batteryConfig)
batteryConfig->vbatmincellvoltage = 33; batteryConfig->vbatmincellvoltage = 33;
batteryConfig->vbatwarningcellvoltage = 35; batteryConfig->vbatwarningcellvoltage = 35;
batteryConfig->vbathysteresis = 1; batteryConfig->vbathysteresis = 1;
batteryConfig->vbatPidCompensation = 0;
batteryConfig->currentMeterOffset = 0; batteryConfig->currentMeterOffset = 0;
batteryConfig->currentMeterScale = 400; // for Allegro ACS758LCB-100U (40mV/A) batteryConfig->currentMeterScale = 400; // for Allegro ACS758LCB-100U (40mV/A)
batteryConfig->batteryCapacity = 0; batteryConfig->batteryCapacity = 0;
batteryConfig->currentMeterType = CURRENT_SENSOR_ADC; batteryConfig->currentMeterType = CURRENT_SENSOR_ADC;
batteryConfig->batterynotpresentlevel = 55; // VBAT below 5.5 V will be igonored
} }
#ifdef SWAP_SERIAL_PORT_0_AND_1_DEFAULTS #ifdef SWAP_SERIAL_PORT_0_AND_1_DEFAULTS
@ -333,7 +308,7 @@ void resetSerialConfig(serialConfig_t *serialConfig)
for (index = 0; index < SERIAL_PORT_COUNT; index++) { for (index = 0; index < SERIAL_PORT_COUNT; index++) {
serialConfig->portConfigs[index].identifier = serialPortIdentifiers[index]; serialConfig->portConfigs[index].identifier = serialPortIdentifiers[index];
serialConfig->portConfigs[index].msp_baudrateIndex = BAUD_115200; serialConfig->portConfigs[index].msp_baudrateIndex = BAUD_500000;
serialConfig->portConfigs[index].gps_baudrateIndex = BAUD_57600; serialConfig->portConfigs[index].gps_baudrateIndex = BAUD_57600;
serialConfig->portConfigs[index].telemetry_baudrateIndex = BAUD_AUTO; serialConfig->portConfigs[index].telemetry_baudrateIndex = BAUD_AUTO;
serialConfig->portConfigs[index].blackbox_baudrateIndex = BAUD_115200; serialConfig->portConfigs[index].blackbox_baudrateIndex = BAUD_115200;
@ -349,23 +324,6 @@ void resetSerialConfig(serialConfig_t *serialConfig)
serialConfig->reboot_character = 'R'; serialConfig->reboot_character = 'R';
} }
static void resetControlRateConfig(controlRateConfig_t *controlRateConfig)
{
controlRateConfig->rcRate8 = 100;
controlRateConfig->rcYawRate8 = 100;
controlRateConfig->rcExpo8 = 10;
controlRateConfig->thrMid8 = 50;
controlRateConfig->thrExpo8 = 0;
controlRateConfig->dynThrPID = 20;
controlRateConfig->rcYawExpo8 = 10;
controlRateConfig->tpa_breakpoint = 1650;
for (uint8_t axis = 0; axis < FLIGHT_DYNAMICS_INDEX_COUNT; axis++) {
controlRateConfig->rates[axis] = 70;
}
}
void resetRcControlsConfig(rcControlsConfig_t *rcControlsConfig) void resetRcControlsConfig(rcControlsConfig_t *rcControlsConfig)
{ {
rcControlsConfig->deadband = 0; rcControlsConfig->deadband = 0;
@ -389,7 +347,7 @@ uint8_t getCurrentProfile(void)
return masterConfig.current_profile_index; return masterConfig.current_profile_index;
} }
static void setProfile(uint8_t profileIndex) void setProfile(uint8_t profileIndex)
{ {
currentProfile = &masterConfig.profile[profileIndex]; currentProfile = &masterConfig.profile[profileIndex];
currentControlRateProfileIndex = currentProfile->activeRateProfile; currentControlRateProfileIndex = currentProfile->activeRateProfile;
@ -419,281 +377,269 @@ uint16_t getCurrentMinthrottle(void)
} }
// Default settings // Default settings
static void resetConf(void) void createDefaultConfig(master_t *config)
{ {
// Clear all configuration // Clear all configuration
memset(&masterConfig, 0, sizeof(master_t)); memset(config, 0, sizeof(master_t));
setProfile(0);
featureClearAll(); intFeatureClearAll(config);
featureSet(DEFAULT_RX_FEATURE | FEATURE_FAILSAFE | FEATURE_SUPEREXPO_RATES); intFeatureSet(DEFAULT_RX_FEATURE | FEATURE_FAILSAFE , config);
#ifdef DEFAULT_FEATURES #ifdef DEFAULT_FEATURES
featureSet(DEFAULT_FEATURES); intFeatureSet(DEFAULT_FEATURES, config);
#endif #endif
#ifdef OSD #ifdef OSD
resetOsdConfig(); intFeatureSet(FEATURE_OSD, config);
resetOsdConfig(&config->osdProfile);
#endif #endif
#ifdef BOARD_HAS_VOLTAGE_DIVIDER #ifdef BOARD_HAS_VOLTAGE_DIVIDER
// only enable the VBAT feature by default if the board has a voltage divider otherwise // only enable the VBAT feature by default if the board has a voltage divider otherwise
// the user may see incorrect readings and unexpected issues with pin mappings may occur. // the user may see incorrect readings and unexpected issues with pin mappings may occur.
featureSet(FEATURE_VBAT); intFeatureSet(FEATURE_VBAT, config);
#endif #endif
masterConfig.version = EEPROM_CONF_VERSION; config->version = EEPROM_CONF_VERSION;
masterConfig.mixerMode = MIXER_QUADX; config->mixerMode = MIXER_QUADX;
// global settings // global settings
masterConfig.current_profile_index = 0; // default profile config->current_profile_index = 0; // default profile
masterConfig.dcm_kp = 2500; // 1.0 * 10000 config->dcm_kp = 2500; // 1.0 * 10000
masterConfig.dcm_ki = 0; // 0.003 * 10000 config->dcm_ki = 0; // 0.003 * 10000
masterConfig.gyro_lpf = 0; // 256HZ default config->gyro_lpf = 0; // 256HZ default
#ifdef STM32F10X #ifdef STM32F10X
masterConfig.gyro_sync_denom = 8; config->gyro_sync_denom = 8;
config->pid_process_denom = 1;
#elif defined(USE_GYRO_SPI_MPU6000) || defined(USE_GYRO_SPI_MPU6500)
config->gyro_sync_denom = 1;
config->pid_process_denom = 4;
#else #else
masterConfig.gyro_sync_denom = 4; config->gyro_sync_denom = 4;
config->pid_process_denom = 2;
#endif #endif
masterConfig.gyro_soft_lpf_hz = 100; config->gyro_soft_type = FILTER_PT1;
config->gyro_soft_lpf_hz = 90;
config->gyro_soft_notch_hz = 0;
config->gyro_soft_notch_cutoff = 130;
masterConfig.pid_process_denom = 2; config->debug_mode = DEBUG_NONE;
masterConfig.debug_mode = 0; resetAccelerometerTrims(&config->accZero);
resetAccelerometerTrims(&masterConfig.accZero); resetSensorAlignment(&config->sensorAlignmentConfig);
resetSensorAlignment(&masterConfig.sensorAlignmentConfig); config->boardAlignment.rollDegrees = 0;
config->boardAlignment.pitchDegrees = 0;
masterConfig.boardAlignment.rollDegrees = 0; config->boardAlignment.yawDegrees = 0;
masterConfig.boardAlignment.pitchDegrees = 0; config->acc_hardware = ACC_DEFAULT; // default/autodetect
masterConfig.boardAlignment.yawDegrees = 0; config->max_angle_inclination = 700; // 70 degrees
masterConfig.acc_hardware = ACC_DEFAULT; // default/autodetect config->yaw_control_direction = 1;
masterConfig.max_angle_inclination = 700; // 70 degrees config->gyroConfig.gyroMovementCalibrationThreshold = 32;
masterConfig.yaw_control_direction = 1;
masterConfig.gyroConfig.gyroMovementCalibrationThreshold = 32;
// xxx_hardware: 0:default/autodetect, 1: disable // xxx_hardware: 0:default/autodetect, 1: disable
masterConfig.mag_hardware = 0; config->mag_hardware = 1;
masterConfig.baro_hardware = 0; config->baro_hardware = 1;
resetBatteryConfig(&masterConfig.batteryConfig); resetBatteryConfig(&config->batteryConfig);
resetTelemetryConfig(&masterConfig.telemetryConfig); #ifdef TELEMETRY
resetTelemetryConfig(&config->telemetryConfig);
#endif
#ifdef SERIALRX_PROVIDER #ifdef SERIALRX_PROVIDER
masterConfig.rxConfig.serialrx_provider = SERIALRX_PROVIDER; config->rxConfig.serialrx_provider = SERIALRX_PROVIDER;
#else #else
masterConfig.rxConfig.serialrx_provider = 0; config->rxConfig.serialrx_provider = 0;
#endif #endif
masterConfig.rxConfig.sbus_inversion = 1; config->rxConfig.sbus_inversion = 1;
masterConfig.rxConfig.spektrum_sat_bind = 0; config->rxConfig.spektrum_sat_bind = 0;
masterConfig.rxConfig.spektrum_sat_bind_autoreset = 1; config->rxConfig.spektrum_sat_bind_autoreset = 1;
masterConfig.rxConfig.midrc = 1500; config->rxConfig.midrc = 1500;
masterConfig.rxConfig.mincheck = 1100; config->rxConfig.mincheck = 1100;
masterConfig.rxConfig.maxcheck = 1900; config->rxConfig.maxcheck = 1900;
masterConfig.rxConfig.rx_min_usec = 885; // any of first 4 channels below this value will trigger rx loss detection config->rxConfig.rx_min_usec = 885; // any of first 4 channels below this value will trigger rx loss detection
masterConfig.rxConfig.rx_max_usec = 2115; // any of first 4 channels above this value will trigger rx loss detection config->rxConfig.rx_max_usec = 2115; // any of first 4 channels above this value will trigger rx loss detection
for (int i = 0; i < MAX_SUPPORTED_RC_CHANNEL_COUNT; i++) { for (int i = 0; i < MAX_SUPPORTED_RC_CHANNEL_COUNT; i++) {
rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &masterConfig.rxConfig.failsafe_channel_configurations[i]; rxFailsafeChannelConfiguration_t *channelFailsafeConfiguration = &config->rxConfig.failsafe_channel_configurations[i];
channelFailsafeConfiguration->mode = (i < NON_AUX_CHANNEL_COUNT) ? RX_FAILSAFE_MODE_AUTO : RX_FAILSAFE_MODE_HOLD; channelFailsafeConfiguration->mode = (i < NON_AUX_CHANNEL_COUNT) ? RX_FAILSAFE_MODE_AUTO : RX_FAILSAFE_MODE_HOLD;
channelFailsafeConfiguration->step = (i == THROTTLE) ? CHANNEL_VALUE_TO_RXFAIL_STEP(masterConfig.rxConfig.rx_min_usec) : CHANNEL_VALUE_TO_RXFAIL_STEP(masterConfig.rxConfig.midrc); channelFailsafeConfiguration->step = (i == THROTTLE) ? CHANNEL_VALUE_TO_RXFAIL_STEP(config->rxConfig.rx_min_usec) : CHANNEL_VALUE_TO_RXFAIL_STEP(config->rxConfig.midrc);
} }
masterConfig.rxConfig.rssi_channel = 0; config->rxConfig.rssi_channel = 0;
masterConfig.rxConfig.rssi_scale = RSSI_SCALE_DEFAULT; config->rxConfig.rssi_scale = RSSI_SCALE_DEFAULT;
masterConfig.rxConfig.rssi_ppm_invert = 0; config->rxConfig.rssi_ppm_invert = 0;
masterConfig.rxConfig.rcSmoothInterval = 0; // 0 is predefined config->rxConfig.rcInterpolation = RC_SMOOTHING_AUTO;
masterConfig.rxConfig.fpvCamAngleDegrees = 0; config->rxConfig.rcInterpolationInterval = 19;
#ifdef STM32F4 config->rxConfig.fpvCamAngleDegrees = 0;
masterConfig.rxConfig.max_aux_channel = 99; config->rxConfig.max_aux_channel = MAX_AUX_CHANNELS;
#else config->rxConfig.airModeActivateThreshold = 1350;
masterConfig.rxConfig.max_aux_channel = 6;
#endif
masterConfig.rxConfig.airModeActivateThreshold = 1350;
resetAllRxChannelRangeConfigurations(masterConfig.rxConfig.channelRanges); resetAllRxChannelRangeConfigurations(config->rxConfig.channelRanges);
masterConfig.inputFilteringMode = INPUT_FILTERING_DISABLED; config->inputFilteringMode = INPUT_FILTERING_DISABLED;
masterConfig.gyro_cal_on_first_arm = 0; // TODO - Cleanup retarded arm support config->gyro_cal_on_first_arm = 0; // TODO - Cleanup retarded arm support
masterConfig.disarm_kill_switch = 1; config->disarm_kill_switch = 1;
masterConfig.auto_disarm_delay = 5; config->auto_disarm_delay = 5;
masterConfig.small_angle = 25; config->small_angle = 25;
resetMixerConfig(&masterConfig.mixerConfig); resetMixerConfig(&config->mixerConfig);
masterConfig.airplaneConfig.fixedwing_althold_dir = 1; config->airplaneConfig.fixedwing_althold_dir = 1;
// Motor/ESC/Servo // Motor/ESC/Servo
resetEscAndServoConfig(&masterConfig.escAndServoConfig); resetEscAndServoConfig(&config->escAndServoConfig);
resetFlight3DConfig(&masterConfig.flight3DConfig); resetFlight3DConfig(&config->flight3DConfig);
#ifdef BRUSHED_MOTORS #ifdef BRUSHED_MOTORS
masterConfig.motor_pwm_rate = BRUSHED_MOTORS_PWM_RATE; config->motor_pwm_rate = BRUSHED_MOTORS_PWM_RATE;
masterConfig.motor_pwm_protocol = PWM_TYPE_BRUSHED; config->motor_pwm_protocol = PWM_TYPE_BRUSHED;
config->use_unsyncedPwm = true;
#else #else
masterConfig.motor_pwm_rate = BRUSHLESS_MOTORS_PWM_RATE; config->motor_pwm_rate = BRUSHLESS_MOTORS_PWM_RATE;
masterConfig.motor_pwm_protocol = PWM_TYPE_ONESHOT125; config->motor_pwm_protocol = PWM_TYPE_ONESHOT125;
#endif #endif
masterConfig.servo_pwm_rate = 50;
config->servo_pwm_rate = 50;
#ifdef CC3D #ifdef CC3D
masterConfig.use_buzzer_p6 = 0; config->use_buzzer_p6 = 0;
#endif #endif
#ifdef GPS #ifdef GPS
// gps/nav stuff // gps/nav stuff
masterConfig.gpsConfig.provider = GPS_NMEA; config->gpsConfig.provider = GPS_NMEA;
masterConfig.gpsConfig.sbasMode = SBAS_AUTO; config->gpsConfig.sbasMode = SBAS_AUTO;
masterConfig.gpsConfig.autoConfig = GPS_AUTOCONFIG_ON; config->gpsConfig.autoConfig = GPS_AUTOCONFIG_ON;
masterConfig.gpsConfig.autoBaud = GPS_AUTOBAUD_OFF; config->gpsConfig.autoBaud = GPS_AUTOBAUD_OFF;
#endif #endif
resetSerialConfig(&masterConfig.serialConfig); resetSerialConfig(&config->serialConfig);
masterConfig.emf_avoidance = 0; // TODO - needs removal resetProfile(&config->profile[0]);
resetPidProfile(&currentProfile->pidProfile); resetRollAndPitchTrims(&config->accelerometerTrims);
for (int rI = 0; rI<MAX_RATEPROFILES; rI++) { config->mag_declination = 0;
resetControlRateConfig(&masterConfig.profile[0].controlRateProfile[rI]); config->acc_lpf_hz = 10.0f;
} config->accDeadband.xy = 40;
resetRollAndPitchTrims(&masterConfig.accelerometerTrims); config->accDeadband.z = 40;
config->acc_unarmedcal = 1;
masterConfig.mag_declination = 0; #ifdef BARO
masterConfig.acc_lpf_hz = 10.0f; resetBarometerConfig(&config->barometerConfig);
masterConfig.accDeadband.xy = 40; #endif
masterConfig.accDeadband.z = 40;
masterConfig.acc_unarmedcal = 1;
resetBarometerConfig(&masterConfig.barometerConfig);
// Radio // Radio
parseRcChannels("AETR1234", &masterConfig.rxConfig); #ifdef RX_CHANNELS_TAER
parseRcChannels("TAER1234", &config->rxConfig);
#else
parseRcChannels("AETR1234", &config->rxConfig);
#endif
resetRcControlsConfig(&masterConfig.rcControlsConfig); resetRcControlsConfig(&config->rcControlsConfig);
masterConfig.throttle_correction_value = 0; // could 10 with althold or 40 for fpv config->throttle_correction_value = 0; // could 10 with althold or 40 for fpv
masterConfig.throttle_correction_angle = 800; // could be 80.0 deg with atlhold or 45.0 for fpv config->throttle_correction_angle = 800; // could be 80.0 deg with atlhold or 45.0 for fpv
// Failsafe Variables // Failsafe Variables
masterConfig.failsafeConfig.failsafe_delay = 10; // 1sec config->failsafeConfig.failsafe_delay = 10; // 1sec
masterConfig.failsafeConfig.failsafe_off_delay = 10; // 1sec config->failsafeConfig.failsafe_off_delay = 10; // 1sec
masterConfig.failsafeConfig.failsafe_throttle = 1000; // default throttle off. config->failsafeConfig.failsafe_throttle = 1000; // default throttle off.
masterConfig.failsafeConfig.failsafe_kill_switch = 0; // default failsafe switch action is identical to rc link loss config->failsafeConfig.failsafe_kill_switch = 0; // default failsafe switch action is identical to rc link loss
masterConfig.failsafeConfig.failsafe_throttle_low_delay = 100; // default throttle low delay for "just disarm" on failsafe condition config->failsafeConfig.failsafe_throttle_low_delay = 100; // default throttle low delay for "just disarm" on failsafe condition
masterConfig.failsafeConfig.failsafe_procedure = 0; // default full failsafe procedure is 0: auto-landing config->failsafeConfig.failsafe_procedure = FAILSAFE_PROCEDURE_DROP_IT;// default full failsafe procedure is 0: auto-landing
#ifdef USE_SERVOS #ifdef USE_SERVOS
// servos // servos
for (int i = 0; i < MAX_SUPPORTED_SERVOS; i++) { for (int i = 0; i < MAX_SUPPORTED_SERVOS; i++) {
masterConfig.servoConf[i].min = DEFAULT_SERVO_MIN; config->servoConf[i].min = DEFAULT_SERVO_MIN;
masterConfig.servoConf[i].max = DEFAULT_SERVO_MAX; config->servoConf[i].max = DEFAULT_SERVO_MAX;
masterConfig.servoConf[i].middle = DEFAULT_SERVO_MIDDLE; config->servoConf[i].middle = DEFAULT_SERVO_MIDDLE;
masterConfig.servoConf[i].rate = 100; config->servoConf[i].rate = 100;
masterConfig.servoConf[i].angleAtMin = DEFAULT_SERVO_MIN_ANGLE; config->servoConf[i].angleAtMin = DEFAULT_SERVO_MIN_ANGLE;
masterConfig.servoConf[i].angleAtMax = DEFAULT_SERVO_MAX_ANGLE; config->servoConf[i].angleAtMax = DEFAULT_SERVO_MAX_ANGLE;
masterConfig.servoConf[i].forwardFromChannel = CHANNEL_FORWARDING_DISABLED; config->servoConf[i].forwardFromChannel = CHANNEL_FORWARDING_DISABLED;
} }
// gimbal // gimbal
masterConfig.gimbalConfig.mode = GIMBAL_MODE_NORMAL; config->gimbalConfig.mode = GIMBAL_MODE_NORMAL;
#endif #endif
#ifdef GPS #ifdef GPS
resetGpsProfile(&masterConfig.gpsProfile); resetGpsProfile(&config->gpsProfile);
#endif #endif
// custom mixer. clear by defaults. // custom mixer. clear by defaults.
for (int i = 0; i < MAX_SUPPORTED_MOTORS; i++) { for (int i = 0; i < MAX_SUPPORTED_MOTORS; i++) {
masterConfig.customMotorMixer[i].throttle = 0.0f; config->customMotorMixer[i].throttle = 0.0f;
} }
#ifdef LED_STRIP #ifdef LED_STRIP
applyDefaultColors(masterConfig.colors, CONFIGURABLE_COLOR_COUNT); applyDefaultColors(config->colors);
applyDefaultLedStripConfig(masterConfig.ledConfigs); applyDefaultLedStripConfig(config->ledConfigs);
masterConfig.ledstrip_visual_beeper = 0; applyDefaultModeColors(config->modeColors);
applyDefaultSpecialColors(&(config->specialColors));
config->ledstrip_visual_beeper = 0;
#endif #endif
#ifdef VTX #ifdef VTX
masterConfig.vtx_band = 4; //Fatshark/Airwaves config->vtx_band = 4; //Fatshark/Airwaves
masterConfig.vtx_channel = 1; //CH1 config->vtx_channel = 1; //CH1
masterConfig.vtx_mode = 0; //CH+BAND mode config->vtx_mode = 0; //CH+BAND mode
masterConfig.vtx_mhz = 5740; //F0 config->vtx_mhz = 5740; //F0
#endif #endif
#ifdef TRANSPONDER #ifdef TRANSPONDER
static const uint8_t defaultTransponderData[6] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }; // Note, this is NOT a valid transponder code, it's just for testing production hardware static const uint8_t defaultTransponderData[6] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }; // Note, this is NOT a valid transponder code, it's just for testing production hardware
memcpy(masterConfig.transponderData, &defaultTransponderData, sizeof(defaultTransponderData)); memcpy(config->transponderData, &defaultTransponderData, sizeof(defaultTransponderData));
#endif #endif
#ifdef BLACKBOX #ifdef BLACKBOX
#if defined(ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT) #if defined(ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT)
featureSet(FEATURE_BLACKBOX); intFeatureSet(FEATURE_BLACKBOX, config);
masterConfig.blackbox_device = BLACKBOX_DEVICE_FLASH; config->blackbox_device = BLACKBOX_DEVICE_FLASH;
#elif defined(ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT) #elif defined(ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT)
featureSet(FEATURE_BLACKBOX); intFeatureSet(FEATURE_BLACKBOX, config);
masterConfig.blackbox_device = BLACKBOX_DEVICE_SDCARD; config->blackbox_device = BLACKBOX_DEVICE_SDCARD;
#else #else
masterConfig.blackbox_device = BLACKBOX_DEVICE_SERIAL; config->blackbox_device = BLACKBOX_DEVICE_SERIAL;
#endif #endif
masterConfig.blackbox_rate_num = 1; config->blackbox_rate_num = 1;
masterConfig.blackbox_rate_denom = 1; config->blackbox_rate_denom = 1;
config->blackbox_on_motor_test = 0; // default off
#endif // BLACKBOX #endif // BLACKBOX
#ifdef SERIALRX_UART #ifdef SERIALRX_UART
if (featureConfigured(FEATURE_RX_SERIAL)) { if (featureConfigured(FEATURE_RX_SERIAL)) {
masterConfig.serialConfig.portConfigs[SERIALRX_UART].functionMask = FUNCTION_RX_SERIAL; config->serialConfig.portConfigs[SERIALRX_UART].functionMask = FUNCTION_RX_SERIAL;
} }
#endif #endif
#if defined(TARGET_CONFIG) #if defined(TARGET_CONFIG)
targetConfiguration(); targetConfiguration(config);
#endif #endif
// copy first profile into remaining profile // copy first profile into remaining profile
for (int i = 1; i < MAX_PROFILE_COUNT; i++) { for (int i = 1; i < MAX_PROFILE_COUNT; i++) {
memcpy(&masterConfig.profile[i], currentProfile, sizeof(profile_t)); memcpy(&config->profile[i], &config->profile[0], sizeof(profile_t));
} }
} }
static uint8_t calculateChecksum(const uint8_t *data, uint32_t length) static void resetConf(void)
{ {
uint8_t checksum = 0; createDefaultConfig(&masterConfig);
const uint8_t *byteOffset;
for (byteOffset = data; byteOffset < (data + length); byteOffset++) setProfile(0);
checksum ^= *byteOffset;
return checksum;
}
static bool isEEPROMContentValid(void) #ifdef LED_STRIP
{ reevaluateLedConfig();
const master_t *temp = (const master_t *) CONFIG_START_FLASH_ADDRESS; #endif
uint8_t checksum = 0;
// check version number
if (EEPROM_CONF_VERSION != temp->version)
return false;
// check size and magic numbers
if (temp->size != sizeof(master_t) || temp->magic_be != 0xBE || temp->magic_ef != 0xEF)
return false;
// verify integrity of temporary copy
checksum = calculateChecksum((const uint8_t *) temp, sizeof(master_t));
if (checksum != 0)
return false;
// looks good, let's roll!
return true;
} }
void activateControlRateConfig(void) void activateControlRateConfig(void)
@ -715,7 +661,7 @@ void activateConfig(void)
&currentProfile->pidProfile &currentProfile->pidProfile
); );
gyroUseConfig(&masterConfig.gyroConfig, masterConfig.gyro_soft_lpf_hz); gyroUseConfig(&masterConfig.gyroConfig, masterConfig.gyro_soft_lpf_hz, masterConfig.gyro_soft_notch_hz, masterConfig.gyro_soft_notch_cutoff, masterConfig.gyro_soft_type);
#ifdef TELEMETRY #ifdef TELEMETRY
telemetryUseConfig(&masterConfig.telemetryConfig); telemetryUseConfig(&masterConfig.telemetryConfig);
@ -732,10 +678,6 @@ void activateConfig(void)
setAccelerationFilter(masterConfig.acc_lpf_hz); setAccelerationFilter(masterConfig.acc_lpf_hz);
mixerUseConfigs( mixerUseConfigs(
#ifdef USE_SERVOS
masterConfig.servoConf,
&masterConfig.gimbalConfig,
#endif
&masterConfig.flight3DConfig, &masterConfig.flight3DConfig,
&masterConfig.escAndServoConfig, &masterConfig.escAndServoConfig,
&masterConfig.mixerConfig, &masterConfig.mixerConfig,
@ -743,6 +685,10 @@ void activateConfig(void)
&masterConfig.rxConfig &masterConfig.rxConfig
); );
#ifdef USE_SERVOS
servoUseConfigs(masterConfig.servoConf, &masterConfig.gimbalConfig);
#endif
imuRuntimeConfig.dcm_kp = masterConfig.dcm_kp / 10000.0f; imuRuntimeConfig.dcm_kp = masterConfig.dcm_kp / 10000.0f;
imuRuntimeConfig.dcm_ki = masterConfig.dcm_ki / 10000.0f; imuRuntimeConfig.dcm_ki = masterConfig.dcm_ki / 10000.0f;
imuRuntimeConfig.acc_unarmedcal = masterConfig.acc_unarmedcal; imuRuntimeConfig.acc_unarmedcal = masterConfig.acc_unarmedcal;
@ -841,12 +787,6 @@ void validateAndFixConfig(void)
} }
#endif #endif
#ifdef STM32F303xC
// hardware supports serial port inversion, make users life easier for those that want to connect SBus RX's
masterConfig.telemetryConfig.telemetry_inversion = 1;
#endif
/*#if defined(LED_STRIP) && defined(TRANSPONDER) // TODO - Add transponder feature /*#if defined(LED_STRIP) && defined(TRANSPONDER) // TODO - Add transponder feature
if ((WS2811_DMA_TC_FLAG == TRANSPONDER_DMA_TC_FLAG) && featureConfigured(FEATURE_TRANSPONDER) && featureConfigured(FEATURE_LED_STRIP)) { if ((WS2811_DMA_TC_FLAG == TRANSPONDER_DMA_TC_FLAG) && featureConfigured(FEATURE_TRANSPONDER) && featureConfigured(FEATURE_LED_STRIP)) {
featureClear(FEATURE_LED_STRIP); featureClear(FEATURE_LED_STRIP);
@ -881,32 +821,6 @@ void validateAndFixConfig(void)
} }
} }
void initEEPROM(void)
{
}
void readEEPROM(void)
{
// Sanity check
if (!isEEPROMContentValid())
failureMode(FAILURE_INVALID_EEPROM_CONTENTS);
suspendRxSignal();
// Read flash
memcpy(&masterConfig, (char *) CONFIG_START_FLASH_ADDRESS, sizeof(master_t));
if (masterConfig.current_profile_index > MAX_PROFILE_COUNT - 1) // sanity check
masterConfig.current_profile_index = 0;
setProfile(masterConfig.current_profile_index);
validateAndFixConfig();
activateConfig();
resumeRxSignal();
}
void readEEPROMAndNotify(void) void readEEPROMAndNotify(void)
{ {
// re-read written data // re-read written data
@ -914,69 +828,6 @@ void readEEPROMAndNotify(void)
beeperConfirmationBeeps(1); beeperConfirmationBeeps(1);
} }
void writeEEPROM(void)
{
// Generate compile time error if the config does not fit in the reserved area of flash.
BUILD_BUG_ON(sizeof(master_t) > FLASH_TO_RESERVE_FOR_CONFIG);
FLASH_Status status = 0;
uint32_t wordOffset;
int8_t attemptsRemaining = 3;
suspendRxSignal();
// prepare checksum/version constants
masterConfig.version = EEPROM_CONF_VERSION;
masterConfig.size = sizeof(master_t);
masterConfig.magic_be = 0xBE;
masterConfig.magic_ef = 0xEF;
masterConfig.chk = 0; // erase checksum before recalculating
masterConfig.chk = calculateChecksum((const uint8_t *) &masterConfig, sizeof(master_t));
// write it
FLASH_Unlock();
while (attemptsRemaining--) {
#if defined(STM32F4)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#elif defined(STM32F303)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
#elif defined(STM32F10X)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
#endif
for (wordOffset = 0; wordOffset < sizeof(master_t); wordOffset += 4) {
if (wordOffset % FLASH_PAGE_SIZE == 0) {
#if defined(STM32F40_41xxx)
status = FLASH_EraseSector(FLASH_Sector_8, VoltageRange_3); //0x08080000 to 0x080A0000
#elif defined (STM32F411xE)
status = FLASH_EraseSector(FLASH_Sector_7, VoltageRange_3); //0x08060000 to 0x08080000
#else
status = FLASH_ErasePage(CONFIG_START_FLASH_ADDRESS + wordOffset);
#endif
if (status != FLASH_COMPLETE) {
break;
}
}
status = FLASH_ProgramWord(CONFIG_START_FLASH_ADDRESS + wordOffset,
*(uint32_t *) ((char *) &masterConfig + wordOffset));
if (status != FLASH_COMPLETE) {
break;
}
}
if (status == FLASH_COMPLETE) {
break;
}
}
FLASH_Lock();
// Flash write failed - just die now
if (status != FLASH_COMPLETE || !isEEPROMContentValid()) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
}
resumeRxSignal();
}
void ensureEEPROMContainsValidData(void) void ensureEEPROMContainsValidData(void)
{ {
if (isEEPROMContentValid()) { if (isEEPROMContentValid()) {
@ -1015,41 +866,6 @@ void changeControlRateProfile(uint8_t profileIndex)
activateControlRateConfig(); activateControlRateConfig();
} }
void latchActiveFeatures()
{
activeFeaturesLatch = masterConfig.enabledFeatures;
}
bool featureConfigured(uint32_t mask)
{
return masterConfig.enabledFeatures & mask;
}
bool feature(uint32_t mask)
{
return activeFeaturesLatch & mask;
}
void featureSet(uint32_t mask)
{
masterConfig.enabledFeatures |= mask;
}
void featureClear(uint32_t mask)
{
masterConfig.enabledFeatures &= ~(mask);
}
void featureClearAll()
{
masterConfig.enabledFeatures = 0;
}
uint32_t featureMask(void)
{
return masterConfig.enabledFeatures;
}
void beeperOffSet(uint32_t mask) void beeperOffSet(uint32_t mask)
{ {
masterConfig.beeper_off_flags |= mask; masterConfig.beeper_off_flags |= mask;

View file

@ -23,7 +23,7 @@
#define MAX_PROFILE_COUNT 3 #define MAX_PROFILE_COUNT 3
#endif #endif
#define MAX_RATEPROFILES 3 #define MAX_RATEPROFILES 3
#define ONESHOT_FEATURE_CHANGED_DELAY_ON_BOOT_MS 1500 #define MAX_NAME_LENGTH 16
typedef enum { typedef enum {
FEATURE_RX_PPM = 1 << 0, FEATURE_RX_PPM = 1 << 0,
@ -44,23 +44,17 @@ typedef enum {
FEATURE_RSSI_ADC = 1 << 15, FEATURE_RSSI_ADC = 1 << 15,
FEATURE_LED_STRIP = 1 << 16, FEATURE_LED_STRIP = 1 << 16,
FEATURE_DISPLAY = 1 << 17, FEATURE_DISPLAY = 1 << 17,
FEATURE_ONESHOT125 = 1 << 18, FEATURE_OSD = 1 << 18,
FEATURE_BLACKBOX = 1 << 19, FEATURE_BLACKBOX = 1 << 19,
FEATURE_CHANNEL_FORWARDING = 1 << 20, FEATURE_CHANNEL_FORWARDING = 1 << 20,
FEATURE_TRANSPONDER = 1 << 21, FEATURE_TRANSPONDER = 1 << 21,
FEATURE_AIRMODE = 1 << 22, FEATURE_AIRMODE = 1 << 22,
FEATURE_SUPEREXPO_RATES = 1 << 23, //FEATURE_SUPEREXPO_RATES = 1 << 23,
FEATURE_OSD = 1 << 24, FEATURE_VTX = 1 << 24,
FEATURE_VTX = 1 << 25, FEATURE_RX_NRF24 = 1 << 25,
FEATURE_SOFTSPI = 1 << 26,
} features_e; } features_e;
void latchActiveFeatures(void);
bool featureConfigured(uint32_t mask);
bool feature(uint32_t mask);
void featureSet(uint32_t mask);
void featureClear(uint32_t mask);
void featureClearAll(void);
uint32_t featureMask(void);
void beeperOffSet(uint32_t mask); void beeperOffSet(uint32_t mask);
void beeperOffSetAll(uint8_t beeperCount); void beeperOffSetAll(uint8_t beeperCount);
void beeperOffClear(uint32_t mask); void beeperOffClear(uint32_t mask);
@ -72,16 +66,17 @@ void setPreferredBeeperOffMask(uint32_t mask);
void copyCurrentProfileToProfileSlot(uint8_t profileSlotIndex); void copyCurrentProfileToProfileSlot(uint8_t profileSlotIndex);
void initEEPROM(void);
void resetEEPROM(void); void resetEEPROM(void);
void readEEPROM(void);
void readEEPROMAndNotify(void); void readEEPROMAndNotify(void);
void writeEEPROM();
void ensureEEPROMContainsValidData(void); void ensureEEPROMContainsValidData(void);
void saveConfigAndNotify(void); void saveConfigAndNotify(void);
void validateAndFixConfig(void);
void activateConfig(void);
uint8_t getCurrentProfile(void); uint8_t getCurrentProfile(void);
void changeProfile(uint8_t profileIndex); void changeProfile(uint8_t profileIndex);
void setProfile(uint8_t profileIndex);
uint8_t getCurrentControlRateProfile(void); uint8_t getCurrentControlRateProfile(void);
void changeControlRateProfile(uint8_t profileIndex); void changeControlRateProfile(uint8_t profileIndex);

View file

@ -0,0 +1,266 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "platform.h"
#include "build/build_config.h"
#include "common/color.h"
#include "common/axis.h"
#include "drivers/sensor.h"
#include "drivers/accgyro.h"
#include "drivers/compass.h"
#include "drivers/system.h"
#include "drivers/timer.h"
#include "drivers/pwm_rx.h"
#include "drivers/serial.h"
#include "sensors/sensors.h"
#include "sensors/gyro.h"
#include "sensors/compass.h"
#include "sensors/acceleration.h"
#include "sensors/barometer.h"
#include "sensors/boardalignment.h"
#include "sensors/battery.h"
#include "io/beeper.h"
#include "io/serial.h"
#include "io/gimbal.h"
#include "io/escservo.h"
#include "fc/rc_controls.h"
#include "fc/rc_curves.h"
#include "io/ledstrip.h"
#include "io/gps.h"
#include "io/osd.h"
#include "io/vtx.h"
#include "rx/rx.h"
#include "telemetry/telemetry.h"
#include "flight/mixer.h"
#include "flight/pid.h"
#include "flight/imu.h"
#include "flight/failsafe.h"
#include "flight/altitudehold.h"
#include "flight/navigation.h"
#include "config/config.h"
#include "config/config_eeprom.h"
#include "config/config_profile.h"
#include "config/config_master.h"
#if !defined(FLASH_SIZE)
#error "Flash size not defined for target. (specify in KB)"
#endif
#ifndef FLASH_PAGE_SIZE
#ifdef STM32F303xC
#define FLASH_PAGE_SIZE ((uint16_t)0x800)
#endif
#ifdef STM32F10X_MD
#define FLASH_PAGE_SIZE ((uint16_t)0x400)
#endif
#ifdef STM32F10X_HD
#define FLASH_PAGE_SIZE ((uint16_t)0x800)
#endif
#if defined(STM32F40_41xxx)
#define FLASH_PAGE_SIZE ((uint32_t)0x20000)
#endif
#if defined (STM32F411xE)
#define FLASH_PAGE_SIZE ((uint32_t)0x20000)
#endif
#endif
#if !defined(FLASH_SIZE) && !defined(FLASH_PAGE_COUNT)
#ifdef STM32F10X_MD
#define FLASH_PAGE_COUNT 128
#endif
#ifdef STM32F10X_HD
#define FLASH_PAGE_COUNT 128
#endif
#endif
#if defined(FLASH_SIZE)
#if defined(STM32F40_41xxx)
#define FLASH_PAGE_COUNT 4 // just to make calculations work
#elif defined (STM32F411xE)
#define FLASH_PAGE_COUNT 4 // just to make calculations work
#else
#define FLASH_PAGE_COUNT ((FLASH_SIZE * 0x400) / FLASH_PAGE_SIZE)
#endif
#endif
#if !defined(FLASH_PAGE_SIZE)
#error "Flash page size not defined for target."
#endif
#if !defined(FLASH_PAGE_COUNT)
#error "Flash page count not defined for target."
#endif
#if FLASH_SIZE <= 128
#define FLASH_TO_RESERVE_FOR_CONFIG 0x800
#else
#define FLASH_TO_RESERVE_FOR_CONFIG 0x1000
#endif
// use the last flash pages for storage
#ifdef CUSTOM_FLASH_MEMORY_ADDRESS
size_t custom_flash_memory_address = 0;
#define CONFIG_START_FLASH_ADDRESS (custom_flash_memory_address)
#else
// use the last flash pages for storage
#ifndef CONFIG_START_FLASH_ADDRESS
#define CONFIG_START_FLASH_ADDRESS (0x08000000 + (uint32_t)((FLASH_PAGE_SIZE * FLASH_PAGE_COUNT) - FLASH_TO_RESERVE_FOR_CONFIG))
#endif
#endif
void initEEPROM(void)
{
}
static uint8_t calculateChecksum(const uint8_t *data, uint32_t length)
{
uint8_t checksum = 0;
const uint8_t *byteOffset;
for (byteOffset = data; byteOffset < (data + length); byteOffset++)
checksum ^= *byteOffset;
return checksum;
}
bool isEEPROMContentValid(void)
{
const master_t *temp = (const master_t *) CONFIG_START_FLASH_ADDRESS;
uint8_t checksum = 0;
// check version number
if (EEPROM_CONF_VERSION != temp->version)
return false;
// check size and magic numbers
if (temp->size != sizeof(master_t) || temp->magic_be != 0xBE || temp->magic_ef != 0xEF)
return false;
// verify integrity of temporary copy
checksum = calculateChecksum((const uint8_t *) temp, sizeof(master_t));
if (checksum != 0)
return false;
// looks good, let's roll!
return true;
}
void writeEEPROM(void)
{
// Generate compile time error if the config does not fit in the reserved area of flash.
BUILD_BUG_ON(sizeof(master_t) > FLASH_TO_RESERVE_FOR_CONFIG);
FLASH_Status status = 0;
uint32_t wordOffset;
int8_t attemptsRemaining = 3;
suspendRxSignal();
// prepare checksum/version constants
masterConfig.version = EEPROM_CONF_VERSION;
masterConfig.size = sizeof(master_t);
masterConfig.magic_be = 0xBE;
masterConfig.magic_ef = 0xEF;
masterConfig.chk = 0; // erase checksum before recalculating
masterConfig.chk = calculateChecksum((const uint8_t *) &masterConfig, sizeof(master_t));
// write it
FLASH_Unlock();
while (attemptsRemaining--) {
#if defined(STM32F4)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#elif defined(STM32F303)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
#elif defined(STM32F10X)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
#endif
for (wordOffset = 0; wordOffset < sizeof(master_t); wordOffset += 4) {
if (wordOffset % FLASH_PAGE_SIZE == 0) {
#if defined(STM32F40_41xxx)
status = FLASH_EraseSector(FLASH_Sector_8, VoltageRange_3); //0x08080000 to 0x080A0000
#elif defined (STM32F411xE)
status = FLASH_EraseSector(FLASH_Sector_7, VoltageRange_3); //0x08060000 to 0x08080000
#else
status = FLASH_ErasePage(CONFIG_START_FLASH_ADDRESS + wordOffset);
#endif
if (status != FLASH_COMPLETE) {
break;
}
}
status = FLASH_ProgramWord(CONFIG_START_FLASH_ADDRESS + wordOffset,
*(uint32_t *) ((char *) &masterConfig + wordOffset));
if (status != FLASH_COMPLETE) {
break;
}
}
if (status == FLASH_COMPLETE) {
break;
}
}
FLASH_Lock();
// Flash write failed - just die now
if (status != FLASH_COMPLETE || !isEEPROMContentValid()) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
}
resumeRxSignal();
}
void readEEPROM(void)
{
// Sanity check
if (!isEEPROMContentValid())
failureMode(FAILURE_INVALID_EEPROM_CONTENTS);
suspendRxSignal();
// Read flash
memcpy(&masterConfig, (char *) CONFIG_START_FLASH_ADDRESS, sizeof(master_t));
if (masterConfig.current_profile_index > MAX_PROFILE_COUNT - 1) // sanity check
masterConfig.current_profile_index = 0;
setProfile(masterConfig.current_profile_index);
validateAndFixConfig();
activateConfig();
resumeRxSignal();
}

View file

@ -0,0 +1,26 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define EEPROM_CONF_VERSION 143
void initEEPROM(void);
void writeEEPROM();
void readEEPROM(void);
bool isEEPROMContentValid(void);

View file

@ -25,7 +25,6 @@ typedef struct master_t {
uint8_t mixerMode; uint8_t mixerMode;
uint32_t enabledFeatures; uint32_t enabledFeatures;
uint8_t emf_avoidance; // change pll settings to avoid noise in the uhf band
// motor/esc/servo related stuff // motor/esc/servo related stuff
motorMixer_t customMotorMixer[MAX_SUPPORTED_MOTORS]; motorMixer_t customMotorMixer[MAX_SUPPORTED_MOTORS];
@ -58,7 +57,10 @@ typedef struct master_t {
uint8_t acc_for_fast_looptime; // shorten acc processing time by using 1 out of 9 samples. For combination with fast looptimes. uint8_t acc_for_fast_looptime; // shorten acc processing time by using 1 out of 9 samples. For combination with fast looptimes.
uint16_t gyro_lpf; // gyro LPF setting - values are driver specific, in case of invalid number, a reasonable default ~30-40HZ is chosen. uint16_t gyro_lpf; // gyro LPF setting - values are driver specific, in case of invalid number, a reasonable default ~30-40HZ is chosen.
uint8_t gyro_sync_denom; // Gyro sample divider uint8_t gyro_sync_denom; // Gyro sample divider
uint8_t gyro_soft_lpf_hz; // Biqyad gyro lpf hz uint8_t gyro_soft_type; // Gyro Filter Type
uint8_t gyro_soft_lpf_hz; // Biquad gyro lpf hz
uint16_t gyro_soft_notch_hz; // Biquad gyro notch hz
uint16_t gyro_soft_notch_cutoff; // Biquad gyro notch low cutoff
uint16_t dcm_kp; // DCM filter proportional gain ( x 10000) uint16_t dcm_kp; // DCM filter proportional gain ( x 10000)
uint16_t dcm_ki; // DCM filter integral gain ( x 10000) uint16_t dcm_ki; // DCM filter integral gain ( x 10000)
@ -75,7 +77,7 @@ typedef struct master_t {
rollAndPitchTrims_t accelerometerTrims; // accelerometer trim rollAndPitchTrims_t accelerometerTrims; // accelerometer trim
float acc_lpf_hz; // cutoff frequency for the low pass filter used on the acc z-axis for althold in Hz uint16_t acc_lpf_hz; // cutoff frequency for the low pass filter used on the acc z-axis for althold in Hz
accDeadband_t accDeadband; accDeadband_t accDeadband;
barometerConfig_t barometerConfig; barometerConfig_t barometerConfig;
uint8_t acc_unarmedcal; // turn automatic acc compensation on/off uint8_t acc_unarmedcal; // turn automatic acc compensation on/off
@ -117,8 +119,10 @@ typedef struct master_t {
telemetryConfig_t telemetryConfig; telemetryConfig_t telemetryConfig;
#ifdef LED_STRIP #ifdef LED_STRIP
ledConfig_t ledConfigs[MAX_LED_STRIP_LENGTH]; ledConfig_t ledConfigs[LED_MAX_STRIP_LENGTH];
hsvColor_t colors[CONFIGURABLE_COLOR_COUNT]; hsvColor_t colors[LED_CONFIGURABLE_COLOR_COUNT];
modeColorIndexes_t modeColors[LED_MODE_COUNT];
specialColorIndexes_t specialColors;
uint8_t ledstrip_visual_beeper; // suppress LEDLOW mode if beeper is on uint8_t ledstrip_visual_beeper; // suppress LEDLOW mode if beeper is on
#endif #endif
@ -154,6 +158,7 @@ typedef struct master_t {
uint8_t blackbox_rate_num; uint8_t blackbox_rate_num;
uint8_t blackbox_rate_denom; uint8_t blackbox_rate_denom;
uint8_t blackbox_device; uint8_t blackbox_device;
uint8_t blackbox_on_motor_test;
#endif #endif
uint32_t beeper_off_flags; uint32_t beeper_off_flags;
@ -161,8 +166,13 @@ typedef struct master_t {
uint8_t magic_ef; // magic number, should be 0xEF uint8_t magic_ef; // magic number, should be 0xEF
uint8_t chk; // XOR checksum uint8_t chk; // XOR checksum
char name[MAX_NAME_LENGTH+1];
} master_t; } master_t;
extern master_t masterConfig; extern master_t masterConfig;
extern profile_t *currentProfile; extern profile_t *currentProfile;
extern controlRateConfig_t *currentControlRateProfile; extern controlRateConfig_t *currentControlRateProfile;
void createDefaultConfig(master_t *config);

124
src/main/config/feature.c Normal file
View file

@ -0,0 +1,124 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "platform.h"
#include "build/build_config.h"
#include "common/color.h"
#include "common/axis.h"
#include "drivers/sensor.h"
#include "drivers/accgyro.h"
#include "drivers/compass.h"
#include "drivers/system.h"
#include "drivers/timer.h"
#include "drivers/pwm_rx.h"
#include "drivers/serial.h"
#include "sensors/sensors.h"
#include "sensors/gyro.h"
#include "sensors/compass.h"
#include "sensors/acceleration.h"
#include "sensors/barometer.h"
#include "sensors/boardalignment.h"
#include "sensors/battery.h"
#include "io/beeper.h"
#include "io/serial.h"
#include "io/gimbal.h"
#include "io/escservo.h"
#include "fc/rc_controls.h"
#include "fc/rc_curves.h"
#include "io/ledstrip.h"
#include "io/gps.h"
#include "io/osd.h"
#include "io/vtx.h"
#include "rx/rx.h"
#include "telemetry/telemetry.h"
#include "flight/mixer.h"
#include "flight/pid.h"
#include "flight/imu.h"
#include "flight/failsafe.h"
#include "flight/altitudehold.h"
#include "flight/navigation.h"
#include "config/config.h"
#include "config/config_profile.h"
#include "config/config_master.h"
#include "config/feature.h"
static uint32_t activeFeaturesLatch = 0;
void intFeatureSet(uint32_t mask, master_t *config)
{
config->enabledFeatures |= mask;
}
void intFeatureClear(uint32_t mask, master_t *config)
{
config->enabledFeatures &= ~(mask);
}
void intFeatureClearAll(master_t *config)
{
config->enabledFeatures = 0;
}
void latchActiveFeatures()
{
activeFeaturesLatch = masterConfig.enabledFeatures;
}
bool featureConfigured(uint32_t mask)
{
return masterConfig.enabledFeatures & mask;
}
bool feature(uint32_t mask)
{
return activeFeaturesLatch & mask;
}
void featureSet(uint32_t mask)
{
intFeatureSet(mask, &masterConfig);
}
void featureClear(uint32_t mask)
{
intFeatureClear(mask, &masterConfig);
}
void featureClearAll()
{
intFeatureClearAll(&masterConfig);
}
uint32_t featureMask(void)
{
return masterConfig.enabledFeatures;
}

26
src/main/config/feature.h Normal file
View file

@ -0,0 +1,26 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cleanflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
void latchActiveFeatures(void);
bool featureConfigured(uint32_t mask);
bool feature(uint32_t mask);
void featureSet(uint32_t mask);
void featureClear(uint32_t mask);
void featureClearAll(void);
uint32_t featureMask(void);

View file

@ -19,8 +19,8 @@
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "build_config.h" #include "build/build_config.h"
#include "debug.h" #include "build/debug.h"
#include "common/maths.h" #include "common/maths.h"

View file

@ -19,7 +19,10 @@
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "debug.h"
#ifdef USE_ACC_LSM303DLHC
#include "build/debug.h"
#include "common/maths.h" #include "common/maths.h"
#include "common/axis.h" #include "common/axis.h"
@ -167,4 +170,4 @@ bool lsm303dlhcAccDetect(acc_t *acc)
acc->read = lsm303dlhcAccRead; acc->read = lsm303dlhcAccRead;
return true; return true;
} }
#endif

View file

@ -21,7 +21,7 @@
#include "platform.h" #include "platform.h"
#include "system.h" #include "system.h"
#include "gpio.h" #include "io.h"
#include "bus_i2c.h" #include "bus_i2c.h"
#include "sensor.h" #include "sensor.h"

View file

@ -21,15 +21,16 @@
#include <string.h> #include <string.h>
#include "platform.h" #include "platform.h"
#include "build_config.h"
#include "debug.h" #include "build/build_config.h"
#include "build/debug.h"
#include "common/maths.h" #include "common/maths.h"
#include "nvic.h" #include "nvic.h"
#include "system.h" #include "system.h"
#include "gpio.h" #include "io.h"
#include "exti.h" #include "exti.h"
#include "bus_i2c.h" #include "bus_i2c.h"

View file

@ -17,6 +17,7 @@
#pragma once #pragma once
#include "io_types.h"
#include "exti.h" #include "exti.h"
// MPU6050 // MPU6050

View file

@ -20,8 +20,9 @@
#include <stdlib.h> #include <stdlib.h>
#include "platform.h" #include "platform.h"
#include "build_config.h"
#include "debug.h" #include "build/build_config.h"
#include "build/debug.h"
#include "common/maths.h" #include "common/maths.h"

View file

@ -73,21 +73,6 @@ void mpu6500GyroInit(uint8_t lpf)
{ {
mpuIntExtiInit(); mpuIntExtiInit();
#ifdef NAZE
// FIXME target specific code in driver code.
gpio_config_t gpio;
// MPU_INT output on rev5 hardware (PC13). rev4 was on PB13, conflicts with SPI devices
if (hse_value == 12000000) {
gpio.pin = Pin_13;
gpio.speed = Speed_2MHz;
gpio.mode = Mode_IN_FLOATING;
gpioInit(GPIOC, &gpio);
}
#endif
mpuIntExtiInit();
mpuConfiguration.write(MPU_RA_PWR_MGMT_1, MPU6500_BIT_RESET); mpuConfiguration.write(MPU_RA_PWR_MGMT_1, MPU6500_BIT_RESET);
delay(100); delay(100);
mpuConfiguration.write(MPU_RA_SIGNAL_PATH_RESET, 0x07); mpuConfiguration.write(MPU_RA_SIGNAL_PATH_RESET, 0x07);
@ -107,11 +92,14 @@ void mpu6500GyroInit(uint8_t lpf)
// Data ready interrupt configuration // Data ready interrupt configuration
#ifdef USE_MPU9250_MAG #ifdef USE_MPU9250_MAG
mpuConfiguration.write(MPU_RA_INT_PIN_CFG, 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 1 << 1 | 0 << 0); // INT_ANYRD_2CLEAR, BYPASS_EN mpuConfiguration.write(MPU_RA_INT_PIN_CFG, MPU6500_BIT_INT_ANYRD_2CLEAR | MPU6500_BIT_BYPASS_EN); // INT_ANYRD_2CLEAR, BYPASS_EN
#else #else
mpuConfiguration.write(MPU_RA_INT_PIN_CFG, 0 << 7 | 0 << 6 | 0 << 5 | 1 << 4 | 0 << 3 | 0 << 2 | 0 << 1 | 0 << 0); // INT_ANYRD_2CLEAR, BYPASS_EN mpuConfiguration.write(MPU_RA_INT_PIN_CFG, MPU6500_BIT_INT_ANYRD_2CLEAR); // INT_ANYRD_2CLEAR
#endif #endif
delay(15);
#ifdef USE_MPU_DATA_READY_SIGNAL #ifdef USE_MPU_DATA_READY_SIGNAL
mpuConfiguration.write(MPU_RA_INT_ENABLE, 0x01); // RAW_RDY_EN interrupt enable mpuConfiguration.write(MPU_RA_INT_ENABLE, MPU6500_BIT_RAW_RDY_EN); // RAW_RDY_EN interrupt enable
#endif #endif
delay(15);
} }

View file

@ -20,6 +20,10 @@
#define ICM20608G_WHO_AM_I_CONST (0xAF) #define ICM20608G_WHO_AM_I_CONST (0xAF)
#define MPU6500_BIT_RESET (0x80) #define MPU6500_BIT_RESET (0x80)
#define MPU6500_BIT_INT_ANYRD_2CLEAR (1 << 4)
#define MPU6500_BIT_BYPASS_EN (1 << 0)
#define MPU6500_BIT_I2C_IF_DIS (1 << 4)
#define MPU6500_BIT_RAW_RDY_EN (0x01)
#pragma once #pragma once

View file

@ -205,8 +205,8 @@ bool mpu6000SpiDetect(void)
return false; return false;
} }
static void mpu6000AccAndGyroInit(void) { static void mpu6000AccAndGyroInit(void)
{
if (mpuSpi6000InitDone) { if (mpuSpi6000InitDone) {
return; return;
} }

View file

@ -91,13 +91,33 @@ bool mpu6500SpiDetect(void)
return false; return false;
} }
void mpu6500SpiAccInit(acc_t *acc)
{
mpu6500AccInit(acc);
}
void mpu6500SpiGyroInit(uint8_t lpf)
{
spiSetDivisor(MPU6500_SPI_INSTANCE, SPI_CLOCK_SLOW);
delayMicroseconds(1);
mpu6500GyroInit(lpf);
// Disable Primary I2C Interface
mpu6500WriteRegister(MPU_RA_USER_CTRL, MPU6500_BIT_I2C_IF_DIS);
delay(100);
spiSetDivisor(MPU6500_SPI_INSTANCE, SPI_CLOCK_FAST);
delayMicroseconds(1);
}
bool mpu6500SpiAccDetect(acc_t *acc) bool mpu6500SpiAccDetect(acc_t *acc)
{ {
if (mpuDetectionResult.sensor != MPU_65xx_SPI) { if (mpuDetectionResult.sensor != MPU_65xx_SPI) {
return false; return false;
} }
acc->init = mpu6500AccInit; acc->init = mpu6500SpiAccInit;
acc->read = mpuAccRead; acc->read = mpuAccRead;
return true; return true;
@ -109,7 +129,7 @@ bool mpu6500SpiGyroDetect(gyro_t *gyro)
return false; return false;
} }
gyro->init = mpu6500GyroInit; gyro->init = mpu6500SpiGyroInit;
gyro->read = mpuGyroRead; gyro->read = mpuGyroRead;
gyro->intStatus = checkMPUDataReady; gyro->intStatus = checkMPUDataReady;

View file

@ -19,6 +19,9 @@
bool mpu6500SpiDetect(void); bool mpu6500SpiDetect(void);
void mpu6500SpiAccInit(acc_t *acc);
void mpu6500SpiGyroInit(uint8_t lpf);
bool mpu6500SpiAccDetect(acc_t *acc); bool mpu6500SpiAccDetect(acc_t *acc);
bool mpu6500SpiGyroDetect(gyro_t *gyro); bool mpu6500SpiGyroDetect(gyro_t *gyro);

View file

@ -27,7 +27,8 @@
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "light_led.h"
#include "build/debug.h"
#include "common/axis.h" #include "common/axis.h"
#include "common/maths.h" #include "common/maths.h"
@ -38,7 +39,7 @@
#include "exti.h" #include "exti.h"
#include "bus_spi.h" #include "bus_spi.h"
#include "gyro_sync.h" #include "gyro_sync.h"
#include "debug.h" #include "light_led.h"
#include "sensor.h" #include "sensor.h"
#include "accgyro.h" #include "accgyro.h"

View file

@ -19,14 +19,17 @@
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "build_config.h"
#include "debug.h" #include "build/build_config.h"
#include "build/debug.h"
#include "system.h" #include "system.h"
#include "adc.h" #include "adc.h"
#include "adc_impl.h" #include "adc_impl.h"
#include "common/utils.h"
//#define DEBUG_ADC_CHANNELS //#define DEBUG_ADC_CHANNELS
#ifdef USE_ADC #ifdef USE_ADC

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include "io.h" #include "io_types.h"
typedef enum { typedef enum {
ADC_BATTERY = 0, ADC_BATTERY = 0,

View file

@ -17,8 +17,8 @@
#pragma once #pragma once
#include "io.h" #include "io_types.h"
#include "rcc.h" #include "rcc_types.h"
#if defined(STM32F4) #if defined(STM32F4)
#define ADC_TAG_MAP_COUNT 16 #define ADC_TAG_MAP_COUNT 16

View file

@ -21,12 +21,11 @@
#include "platform.h" #include "platform.h"
#include "build_config.h" #ifdef USE_ADC
#include "build/build_config.h"
#include "system.h" #include "system.h"
#include "sensors/sensors.h" // FIXME dependency into the main code
#include "sensor.h" #include "sensor.h"
#include "accgyro.h" #include "accgyro.h"
#include "adc.h" #include "adc.h"
@ -84,7 +83,6 @@ void adcInit(drv_adc_config_t *init)
UNUSED(init); UNUSED(init);
#endif #endif
uint8_t i;
uint8_t configuredAdcChannels = 0; uint8_t configuredAdcChannels = 0;
memset(&adcConfig, 0, sizeof(adcConfig)); memset(&adcConfig, 0, sizeof(adcConfig));
@ -117,9 +115,9 @@ void adcInit(drv_adc_config_t *init)
if (device == ADCINVALID) if (device == ADCINVALID)
return; return;
adcDevice_t adc = adcHardware[device]; const adcDevice_t adc = adcHardware[device];
for (uint8_t i = 0; i < ADC_CHANNEL_COUNT; i++) { for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
if (!adcConfig[i].tag) if (!adcConfig[i].tag)
continue; continue;
@ -163,7 +161,7 @@ void adcInit(drv_adc_config_t *init)
ADC_Init(adc.ADCx, &ADC_InitStructure); ADC_Init(adc.ADCx, &ADC_InitStructure);
uint8_t rank = 1; uint8_t rank = 1;
for (i = 0; i < ADC_CHANNEL_COUNT; i++) { for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
if (!adcConfig[i].enabled) { if (!adcConfig[i].enabled) {
continue; continue;
} }
@ -180,3 +178,4 @@ void adcInit(drv_adc_config_t *init)
ADC_SoftwareStartConvCmd(adc.ADCx, ENABLE); ADC_SoftwareStartConvCmd(adc.ADCx, ENABLE);
} }
#endif

View file

@ -21,7 +21,6 @@
#include "platform.h" #include "platform.h"
#include "system.h" #include "system.h"
#include "common/utils.h"
#include "gpio.h" #include "gpio.h"
#include "sensor.h" #include "sensor.h"
@ -32,6 +31,8 @@
#include "io.h" #include "io.h"
#include "rcc.h" #include "rcc.h"
#include "common/utils.h"
#ifndef ADC_INSTANCE #ifndef ADC_INSTANCE
#define ADC_INSTANCE ADC1 #define ADC_INSTANCE ADC1
#endif #endif
@ -100,7 +101,6 @@ void adcInit(drv_adc_config_t *init)
ADC_InitTypeDef ADC_InitStructure; ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure; DMA_InitTypeDef DMA_InitStructure;
uint8_t i;
uint8_t adcChannelCount = 0; uint8_t adcChannelCount = 0;
memset(&adcConfig, 0, sizeof(adcConfig)); memset(&adcConfig, 0, sizeof(adcConfig));
@ -135,7 +135,7 @@ void adcInit(drv_adc_config_t *init)
adcDevice_t adc = adcHardware[device]; adcDevice_t adc = adcHardware[device];
for (uint8_t i = 0; i < ADC_CHANNEL_COUNT; i++) { for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
if (!adcConfig[i].tag) if (!adcConfig[i].tag)
continue; continue;
@ -203,7 +203,7 @@ void adcInit(drv_adc_config_t *init)
ADC_Init(adc.ADCx, &ADC_InitStructure); ADC_Init(adc.ADCx, &ADC_InitStructure);
uint8_t rank = 1; uint8_t rank = 1;
for (i = 0; i < ADC_CHANNEL_COUNT; i++) { for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
if (!adcConfig[i].enabled) { if (!adcConfig[i].enabled) {
continue; continue;
} }

View file

@ -26,8 +26,6 @@
#include "io_impl.h" #include "io_impl.h"
#include "rcc.h" #include "rcc.h"
#include "sensors/sensors.h" // FIXME dependency into the main code
#include "sensor.h" #include "sensor.h"
#include "accgyro.h" #include "accgyro.h"

View file

@ -20,7 +20,7 @@
#include <platform.h> #include <platform.h>
#include "build_config.h" #include "build/build_config.h"
#include "barometer.h" #include "barometer.h"

View file

@ -20,7 +20,7 @@
#include <platform.h> #include <platform.h>
#include "build_config.h" #include "build/build_config.h"
#include "barometer.h" #include "barometer.h"

View file

@ -20,14 +20,14 @@
#include <platform.h> #include <platform.h>
#include "build/build_config.h"
#include "barometer.h" #include "barometer.h"
#include "gpio.h" #include "gpio.h"
#include "system.h" #include "system.h"
#include "bus_i2c.h" #include "bus_i2c.h"
#include "build_config.h"
// MS5611, Standard address 0x77 // MS5611, Standard address 0x77
#define MS5611_ADDR 0x77 #define MS5611_ADDR 0x77

View file

@ -15,6 +15,7 @@
* along with Betaflight. If not, see <http://www.gnu.org/licenses/>. * along with Betaflight. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -24,6 +25,7 @@
#include "barometer.h" #include "barometer.h"
#include "barometer_bmp280.h" #include "barometer_bmp280.h"
#include "io.h"
#ifdef USE_BARO_SPI_BMP280 #ifdef USE_BARO_SPI_BMP280
#define DISABLE_BMP280 IOHi(bmp280CsPin) #define DISABLE_BMP280 IOHi(bmp280CsPin)

View file

@ -21,8 +21,8 @@
#define I2C_LONG_TIMEOUT ((uint32_t)(10 * I2C_SHORT_TIMEOUT)) #define I2C_LONG_TIMEOUT ((uint32_t)(10 * I2C_SHORT_TIMEOUT))
#define I2C_DEFAULT_TIMEOUT I2C_SHORT_TIMEOUT #define I2C_DEFAULT_TIMEOUT I2C_SHORT_TIMEOUT
#include "drivers/io.h" #include "io_types.h"
#include "drivers/rcc.h" #include "rcc_types.h"
#ifndef I2C_DEVICE #ifndef I2C_DEVICE
#define I2C_DEVICE I2CINVALID #define I2C_DEVICE I2CINVALID

View file

@ -20,9 +20,10 @@
#include <platform.h> #include <platform.h>
#include "build_config.h" #include "build/build_config.h"
#include "bus_i2c.h" #include "bus_i2c.h"
#include "drivers/io.h" #include "io.h"
// Software I2C driver, using same pins as hardware I2C, with hw i2c module disabled. // Software I2C driver, using same pins as hardware I2C, with hw i2c module disabled.
// Can be configured for I2C2 pinout (SCL: PB10, SDA: PB11) or I2C1 pinout (SCL: PB6, SDA: PB7) // Can be configured for I2C2 pinout (SCL: PB10, SDA: PB11) or I2C1 pinout (SCL: PB6, SDA: PB7)

View file

@ -53,19 +53,23 @@ static void i2cUnstick(IO_t scl, IO_t sda);
#ifndef I2C1_SDA #ifndef I2C1_SDA
#define I2C1_SDA PB9 #define I2C1_SDA PB9
#endif #endif
#else #else
#ifndef I2C1_SCL #ifndef I2C1_SCL
#define I2C1_SCL PB6 #define I2C1_SCL PB6
#endif #endif
#ifndef I2C1_SDA #ifndef I2C1_SDA
#define I2C1_SDA PB7 #define I2C1_SDA PB7
#endif #endif
#define IOCFG_I2C IO_CONFIG(GPIO_Mode_AF_OD, GPIO_Speed_50MHz)
#endif #endif
#ifndef I2C2_SCL #ifndef I2C2_SCL
#define I2C2_SCL PB10 #define I2C2_SCL PB10
#endif #endif
#ifndef I2C2_SDA #ifndef I2C2_SDA
#define I2C2_SDA PB11 #define I2C2_SDA PB11
#endif #endif
@ -398,8 +402,8 @@ void i2cInit(I2CDevice device)
IOConfigGPIOAF(scl, IOCFG_I2C, GPIO_AF_I2C); IOConfigGPIOAF(scl, IOCFG_I2C, GPIO_AF_I2C);
IOConfigGPIOAF(sda, IOCFG_I2C, GPIO_AF_I2C); IOConfigGPIOAF(sda, IOCFG_I2C, GPIO_AF_I2C);
#else #else
IOConfigGPIO(scl, IOCFG_AF_OD); IOConfigGPIO(scl, IOCFG_I2C);
IOConfigGPIO(sda, IOCFG_AF_OD); IOConfigGPIO(sda, IOCFG_I2C);
#endif #endif
I2C_DeInit(i2c->dev); I2C_DeInit(i2c->dev);

View file

@ -20,18 +20,19 @@
#include <platform.h> #include <platform.h>
#include "gpio.h"
#include "system.h" #include "system.h"
#include "drivers/io_impl.h" #include "io.h"
#include "io_impl.h"
#include "rcc.h"
#include "bus_i2c.h" #include "bus_i2c.h"
#ifndef SOFT_I2C #ifndef SOFT_I2C
#if defined(USE_I2C_PULLUP) #if defined(USE_I2C_PULLUP)
#define IOCFG_I2C IO_CONFIG(GPIO_Mode_AF, 0, GPIO_OType_OD, GPIO_PuPd_UP) #define IOCFG_I2C IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_UP)
#else #else
#define IOCFG_I2C IOCFG_AF_OD #define IOCFG_I2C IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_NOPULL)
#endif #endif
#define I2C_HIGHSPEED_TIMING 0x00500E30 // 1000 Khz, 72Mhz Clock, Analog Filter Delay ON, Setup 40, Hold 4. #define I2C_HIGHSPEED_TIMING 0x00500E30 // 1000 Khz, 72Mhz Clock, Analog Filter Delay ON, Setup 40, Hold 4.

View file

@ -21,6 +21,7 @@
#include <platform.h> #include <platform.h>
#include "bus_spi.h" #include "bus_spi.h"
#include "exti.h"
#include "io.h" #include "io.h"
#include "io_impl.h" #include "io_impl.h"
#include "rcc.h" #include "rcc.h"

View file

@ -17,9 +17,8 @@
#pragma once #pragma once
#include <stdint.h> #include "io_types.h"
#include "io.h" #include "rcc_types.h"
#include "rcc.h"
#if defined(STM32F4) || defined(STM32F3) #if defined(STM32F4) || defined(STM32F3)
#define SPI_IO_AF_CFG IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL) #define SPI_IO_AF_CFG IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL)
@ -31,8 +30,6 @@
#define SPI_IO_AF_MOSI_CFG IO_CONFIG(GPIO_Mode_AF_PP, GPIO_Speed_50MHz) #define SPI_IO_AF_MOSI_CFG IO_CONFIG(GPIO_Mode_AF_PP, GPIO_Speed_50MHz)
#define SPI_IO_AF_MISO_CFG IO_CONFIG(GPIO_Mode_IN_FLOATING, GPIO_Speed_50MHz) #define SPI_IO_AF_MISO_CFG IO_CONFIG(GPIO_Mode_IN_FLOATING, GPIO_Speed_50MHz)
#define SPI_IO_CS_CFG IO_CONFIG(GPIO_Mode_Out_PP, GPIO_Speed_50MHz) #define SPI_IO_CS_CFG IO_CONFIG(GPIO_Mode_Out_PP, GPIO_Speed_50MHz)
#else
#error "Unknown processor"
#endif #endif
/* /*

View file

@ -20,11 +20,10 @@
#include <math.h> #include <math.h>
#include "build_config.h"
#include "platform.h" #include "platform.h"
#include "debug.h" #include "build/build_config.h"
#include "build/debug.h"
#include "common/axis.h" #include "common/axis.h"
#include "common/maths.h" #include "common/maths.h"
@ -33,9 +32,6 @@
#include "bus_i2c.h" #include "bus_i2c.h"
#include "bus_spi.h" #include "bus_spi.h"
#include "sensors/boardalignment.h"
#include "sensors/sensors.h"
#include "sensor.h" #include "sensor.h"
#include "compass.h" #include "compass.h"

View file

@ -20,10 +20,12 @@
#include <math.h> #include <math.h>
#include "build_config.h"
#include "platform.h" #include "platform.h"
#ifdef USE_MAG_AK8975
#include "build/build_config.h"
#include "common/axis.h" #include "common/axis.h"
#include "common/maths.h" #include "common/maths.h"
@ -31,9 +33,6 @@
#include "gpio.h" #include "gpio.h"
#include "bus_i2c.h" #include "bus_i2c.h"
#include "sensors/boardalignment.h"
#include "sensors/sensors.h"
#include "sensor.h" #include "sensor.h"
#include "compass.h" #include "compass.h"
@ -59,7 +58,7 @@
#define AK8975_MAG_REG_CNTL 0x0a #define AK8975_MAG_REG_CNTL 0x0a
#define AK8975_MAG_REG_ASCT 0x0c // self test #define AK8975_MAG_REG_ASCT 0x0c // self test
bool ak8975detect(mag_t *mag) bool ak8975Detect(mag_t *mag)
{ {
bool ack = false; bool ack = false;
uint8_t sig = 0; uint8_t sig = 0;
@ -155,3 +154,4 @@ bool ak8975Read(int16_t *magData)
ack = i2cWrite(MAG_I2C_INSTANCE, AK8975_MAG_I2C_ADDRESS, AK8975_MAG_REG_CNTL, 0x01); // start reading again ack = i2cWrite(MAG_I2C_INSTANCE, AK8975_MAG_I2C_ADDRESS, AK8975_MAG_REG_CNTL, 0x01); // start reading again
return true; return true;
} }
#endif

View file

@ -17,6 +17,6 @@
#pragma once #pragma once
bool ak8975detect(mag_t *mag); bool ak8975Detect(mag_t *mag);
void ak8975Init(void); void ak8975Init(void);
bool ak8975Read(int16_t *magData); bool ak8975Read(int16_t *magData);

View file

@ -21,7 +21,10 @@
#include <math.h> #include <math.h>
#include "platform.h" #include "platform.h"
#include "debug.h"
#ifdef USE_MAG_HMC5883
#include "build/debug.h"
#include "common/axis.h" #include "common/axis.h"
#include "common/maths.h" #include "common/maths.h"
@ -36,8 +39,6 @@
#include "sensor.h" #include "sensor.h"
#include "compass.h" #include "compass.h"
#include "sensors/sensors.h"
#include "compass_hmc5883l.h" #include "compass_hmc5883l.h"
//#define DEBUG_MAG_DATA_READY_INTERRUPT //#define DEBUG_MAG_DATA_READY_INTERRUPT
@ -271,3 +272,4 @@ bool hmc5883lRead(int16_t *magData)
return true; return true;
} }
#endif

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include "io.h" #include "io_types.h"
typedef struct hmc5883Config_s { typedef struct hmc5883Config_s {
ioTag_t intTag; ioTag_t intTag;

View file

@ -21,8 +21,8 @@
#include <platform.h> #include <platform.h>
#include "drivers/nvic.h" #include "nvic.h"
#include "drivers/dma.h" #include "dma.h"
/* /*
* DMA descriptors. * DMA descriptors.

View file

@ -22,13 +22,15 @@ typedef void (*dmaCallbackHandlerFuncPtr)(struct dmaChannelDescriptor_s *channel
#ifdef STM32F4 #ifdef STM32F4
typedef enum { typedef enum {
DMA1_ST1_HANDLER = 0, DMA1_ST0_HANDLER = 0,
DMA1_ST1_HANDLER,
DMA1_ST2_HANDLER, DMA1_ST2_HANDLER,
DMA1_ST3_HANDLER, DMA1_ST3_HANDLER,
DMA1_ST4_HANDLER, DMA1_ST4_HANDLER,
DMA1_ST5_HANDLER, DMA1_ST5_HANDLER,
DMA1_ST6_HANDLER, DMA1_ST6_HANDLER,
DMA1_ST7_HANDLER, DMA1_ST7_HANDLER,
DMA2_ST0_HANDLER,
DMA2_ST1_HANDLER, DMA2_ST1_HANDLER,
DMA2_ST2_HANDLER, DMA2_ST2_HANDLER,
DMA2_ST3_HANDLER, DMA2_ST3_HANDLER,

View file

@ -21,8 +21,8 @@
#include <platform.h> #include <platform.h>
#include "drivers/nvic.h" #include "nvic.h"
#include "drivers/dma.h" #include "dma.h"
/* /*
* DMA descriptors. * DMA descriptors.
@ -45,12 +45,12 @@ static dmaChannelDescriptor_t dmaDescriptors[] = {
DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream5, 38, DMA2_Stream5_IRQn, RCC_AHB1Periph_DMA2), DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream5, 38, DMA2_Stream5_IRQn, RCC_AHB1Periph_DMA2),
DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream6, 48, DMA2_Stream6_IRQn, RCC_AHB1Periph_DMA2), DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream6, 48, DMA2_Stream6_IRQn, RCC_AHB1Periph_DMA2),
DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream7, 54, DMA2_Stream7_IRQn, RCC_AHB1Periph_DMA2), DEFINE_DMA_CHANNEL(DMA2, DMA2_Stream7, 54, DMA2_Stream7_IRQn, RCC_AHB1Periph_DMA2),
}; };
/* /*
* DMA IRQ Handlers * DMA IRQ Handlers
*/ */
DEFINE_DMA_IRQ_HANDLER(1, 0, DMA1_ST0_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 1, DMA1_ST1_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 1, DMA1_ST1_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 2, DMA1_ST2_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 2, DMA1_ST2_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 3, DMA1_ST3_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 3, DMA1_ST3_HANDLER)
@ -58,12 +58,14 @@ DEFINE_DMA_IRQ_HANDLER(1, 4, DMA1_ST4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 5, DMA1_ST5_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 5, DMA1_ST5_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 6, DMA1_ST6_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 6, DMA1_ST6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 7, DMA1_ST7_HANDLER) DEFINE_DMA_IRQ_HANDLER(1, 7, DMA1_ST7_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 0, DMA2_ST0_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 1, DMA2_ST1_HANDLER) DEFINE_DMA_IRQ_HANDLER(2, 1, DMA2_ST1_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 2, DMA2_ST2_HANDLER) DEFINE_DMA_IRQ_HANDLER(2, 2, DMA2_ST2_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 3, DMA2_ST3_HANDLER) DEFINE_DMA_IRQ_HANDLER(2, 3, DMA2_ST3_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_ST4_HANDLER) DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_ST4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER) DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_ST7_HANDLER)
void dmaInit(void) void dmaInit(void)
{ {

View file

@ -18,7 +18,7 @@
#pragma once #pragma once
#include "drivers/io.h" #include "io_types.h"
// old EXTI interface, to be replaced // old EXTI interface, to be replaced
typedef struct extiConfig_s { typedef struct extiConfig_s {

View file

@ -22,9 +22,10 @@
#ifdef USE_FLASH_M25P16 #ifdef USE_FLASH_M25P16
#include "drivers/flash_m25p16.h" #include "flash_m25p16.h"
#include "drivers/bus_spi.h" #include "io.h"
#include "drivers/system.h" #include "bus_spi.h"
#include "system.h"
#define M25P16_INSTRUCTION_RDID 0x9F #define M25P16_INSTRUCTION_RDID 0x9F
#define M25P16_INSTRUCTION_READ_BYTES 0x03 #define M25P16_INSTRUCTION_READ_BYTES 0x03
@ -43,6 +44,7 @@
#define JEDEC_ID_MICRON_M25P16 0x202015 #define JEDEC_ID_MICRON_M25P16 0x202015
#define JEDEC_ID_MICRON_N25Q064 0x20BA17 #define JEDEC_ID_MICRON_N25Q064 0x20BA17
#define JEDEC_ID_WINBOND_W25Q64 0xEF4017 #define JEDEC_ID_WINBOND_W25Q64 0xEF4017
#define JEDEC_ID_MACRONIX_MX25L3206E 0xC22016
#define JEDEC_ID_MACRONIX_MX25L6406E 0xC22017 #define JEDEC_ID_MACRONIX_MX25L6406E 0xC22017
#define JEDEC_ID_MICRON_N25Q128 0x20ba18 #define JEDEC_ID_MICRON_N25Q128 0x20ba18
#define JEDEC_ID_WINBOND_W25Q128 0xEF4018 #define JEDEC_ID_WINBOND_W25Q128 0xEF4018
@ -161,6 +163,10 @@ static bool m25p16_readIdentification()
geometry.sectors = 32; geometry.sectors = 32;
geometry.pagesPerSector = 256; geometry.pagesPerSector = 256;
break; break;
case JEDEC_ID_MACRONIX_MX25L3206E:
geometry.sectors = 64;
geometry.pagesPerSector = 256;
break;
case JEDEC_ID_MICRON_N25Q064: case JEDEC_ID_MICRON_N25Q064:
case JEDEC_ID_WINBOND_W25Q64: case JEDEC_ID_WINBOND_W25Q64:
case JEDEC_ID_MACRONIX_MX25L6406E: case JEDEC_ID_MACRONIX_MX25L6406E:
@ -196,12 +202,27 @@ static bool m25p16_readIdentification()
* Attempts to detect a connected m25p16. If found, true is returned and device capacity can be fetched with * Attempts to detect a connected m25p16. If found, true is returned and device capacity can be fetched with
* m25p16_getGeometry(). * m25p16_getGeometry().
*/ */
bool m25p16_init() bool m25p16_init(ioTag_t csTag)
{ {
/*
if we have already detected a flash device we can simply exit
TODO: change the init param in favour of flash CFG when ParamGroups work is done
then cs pin can be specified in hardware_revision.c or config.c (dependent on revision).
*/
if (geometry.sectors) {
return true;
}
if (csTag) {
m25p16CsPin = IOGetByTag(csTag);
} else {
#ifdef M25P16_CS_PIN #ifdef M25P16_CS_PIN
m25p16CsPin = IOGetByTag(IO_TAG(M25P16_CS_PIN)); m25p16CsPin = IOGetByTag(IO_TAG(M25P16_CS_PIN));
#else
return false;
#endif #endif
}
IOInit(m25p16CsPin, OWNER_FLASH, RESOURCE_SPI_CS, 0); IOInit(m25p16CsPin, OWNER_FLASH, RESOURCE_SPI_CS, 0);
IOConfigGPIO(m25p16CsPin, SPI_IO_CS_CFG); IOConfigGPIO(m25p16CsPin, SPI_IO_CS_CFG);

View file

@ -19,10 +19,11 @@
#include <stdint.h> #include <stdint.h>
#include "flash.h" #include "flash.h"
#include "io_types.h"
#define M25P16_PAGESIZE 256 #define M25P16_PAGESIZE 256
bool m25p16_init(); bool m25p16_init(ioTag_t csTag);
void m25p16_eraseSector(uint32_t address); void m25p16_eraseSector(uint32_t address);
void m25p16_eraseCompletely(); void m25p16_eraseCompletely();

View file

@ -20,7 +20,7 @@
#include "platform.h" #include "platform.h"
#include "build_config.h" #include "build/build_config.h"
#include "gpio.h" #include "gpio.h"

View file

@ -10,9 +10,9 @@
#include "platform.h" #include "platform.h"
#include "drivers/sensor.h" #include "sensor.h"
#include "drivers/accgyro.h" #include "accgyro.h"
#include "drivers/gyro_sync.h" #include "gyro_sync.h"
static uint8_t mpuDividerDrops; static uint8_t mpuDividerDrops;

View file

@ -27,11 +27,16 @@
#include "inverter.h" #include "inverter.h"
static const IO_t pin = DEFIO_IO(INVERTER); /*
TODO: move this to support multiple inverters on different UARTs etc
possibly move to put it in the UART driver itself.
*/
static IO_t pin = IO_NONE;
void initInverter(void) void initInverter(void)
{ {
IOInit(pin, OWNER_INVERTER, RESOURCE_OUTPUT, 0); pin = IOGetByTag(IO_TAG(INVERTER));
IOInit(pin, OWNER_INVERTER, RESOURCE_OUTPUT, 1);
IOConfigGPIO(pin, IOCFG_OUT_PP); IOConfigGPIO(pin, IOCFG_OUT_PP);
inverterSet(false); inverterSet(false);

View file

@ -28,5 +28,3 @@ void inverterSet(bool on);
void initInverter(void); void initInverter(void);

View file

@ -65,7 +65,6 @@ const char * const resourceNames[RESOURCE_TOTAL_COUNT] = {
"SDA", "SCK","MOSI","MISO","CS","BATTERY","RSSI","EXT","CURRENT" "SDA", "SCK","MOSI","MISO","CS","BATTERY","RSSI","EXT","CURRENT"
}; };
ioRec_t* IO_Rec(IO_t io) ioRec_t* IO_Rec(IO_t io)
{ {
return io; return io;

View file

@ -6,13 +6,7 @@
#include <platform.h> #include <platform.h>
#include "resource.h" #include "resource.h"
// IO pin identification #include "io_types.h"
// make sure that ioTag_t can't be assigned into IO_t without warning
typedef uint8_t ioTag_t; // packet tag to specify IO pin
typedef void* IO_t; // type specifying IO pin. Currently ioRec_t pointer, but this may change
// NONE initializer for IO_t variable
#define IO_NONE ((IO_t)0)
// preprocessor is used to convert pinid to requested C data value // preprocessor is used to convert pinid to requested C data value
// compile-time error is generated if requested pin is not available (not set in TARGET_IO_PORTx) // compile-time error is generated if requested pin is not available (not set in TARGET_IO_PORTx)
@ -21,19 +15,6 @@ typedef void* IO_t; // type specifying IO pin. Currently ioRec_t poin
// expand pinid to to ioTag_t // expand pinid to to ioTag_t
#define IO_TAG(pinid) DEFIO_TAG(pinid) #define IO_TAG(pinid) DEFIO_TAG(pinid)
// both ioTag_t and IO_t are guarantied to be zero if pinid is NONE (no pin)
// this simplifies initialization (globals are zeroed on start) and allows
// omitting unused fields in structure initializers.
// it is also possible to use IO_t and ioTag_t as boolean value
// TODO - this may conflict with requirement to generate warning/error on IO_t - ioTag_t assignment
// IO_t being pointer is only possibility I know of ..
// pin config handling
// pin config is packed into ioConfig_t to decrease memory requirements
// IOCFG_x macros are defined for common combinations for all CPUs; this
// helps masking CPU differences
typedef uint8_t ioConfig_t; // packed IO configuration
#if defined(STM32F1) #if defined(STM32F1)
// mode is using only bits 6-2 // mode is using only bits 6-2

View file

@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
// IO pin identification
// make sure that ioTag_t can't be assigned into IO_t without warning
typedef uint8_t ioTag_t; // packet tag to specify IO pin
typedef void* IO_t; // type specifying IO pin. Currently ioRec_t pointer, but this may change
// NONE initializer for ioTag_t variables
#define IOTAG_NONE ((ioTag_t)0)
// NONE initializer for IO_t variable
#define IO_NONE ((IO_t)0)
// both ioTag_t and IO_t are guarantied to be zero if pinid is NONE (no pin)
// this simplifies initialization (globals are zeroed on start) and allows
// omitting unused fields in structure initializers.
// it is also possible to use IO_t and ioTag_t as boolean value
// TODO - this may conflict with requirement to generate warning/error on IO_t - ioTag_t assignment
// IO_t being pointer is only possibility I know of ..
// pin config handling
// pin config is packed into ioConfig_t to decrease memory requirements
// IOCFG_x macros are defined for common combinations for all CPUs; this
// helps masking CPU differences
typedef uint8_t ioConfig_t; // packed IO configuration

View file

@ -78,15 +78,14 @@ uint8_t ledPolarity = 0
#endif #endif
; ;
uint8_t ledOffset = 0; static uint8_t ledOffset = 0;
void ledInit(bool alternative_led) void ledInit(bool alternative_led)
{ {
uint32_t i;
#if defined(LED0_A) || defined(LED1_A) || defined(LED2_A) #if defined(LED0_A) || defined(LED1_A) || defined(LED2_A)
if (alternative_led) if (alternative_led) {
ledOffset = LED_NUMBER; ledOffset = LED_NUMBER;
}
#else #else
UNUSED(alternative_led); UNUSED(alternative_led);
#endif #endif
@ -95,7 +94,7 @@ void ledInit(bool alternative_led)
LED1_OFF; LED1_OFF;
LED2_OFF; LED2_OFF;
for (i = 0; i < LED_NUMBER; i++) { for (int i = 0; i < LED_NUMBER; i++) {
if (leds[i + ledOffset]) { if (leds[i + ledOffset]) {
IOInit(leds[i + ledOffset], OWNER_LED, RESOURCE_OUTPUT, RESOURCE_INDEX(i)); IOInit(leds[i + ledOffset], OWNER_LED, RESOURCE_OUTPUT, RESOURCE_INDEX(i));
IOConfigGPIO(leds[i + ledOffset], IOCFG_OUT_PP); IOConfigGPIO(leds[i + ledOffset], IOCFG_OUT_PP);
@ -114,6 +113,6 @@ void ledToggle(int led)
void ledSet(int led, bool on) void ledSet(int led, bool on)
{ {
bool inverted = (1 << (led + ledOffset)) & ledPolarity; const bool inverted = (1 << (led + ledOffset)) & ledPolarity;
IOWrite(leds[led + ledOffset], on ? inverted : !inverted); IOWrite(leds[led + ledOffset], on ? inverted : !inverted);
} }

View file

@ -30,16 +30,20 @@
#include <platform.h> #include <platform.h>
#include "build_config.h" #ifdef LED_STRIP
#include "build/build_config.h"
#include "common/color.h" #include "common/color.h"
#include "common/colorconversion.h" #include "common/colorconversion.h"
#include "drivers/dma.h" #include "dma.h"
#include "drivers/light_ws2811strip.h" #include "light_ws2811strip.h"
#ifdef LED_STRIP
#if defined(STM32F4)
uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#else
uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#endif
volatile uint8_t ws2811LedDataTransferInProgress = 0; volatile uint8_t ws2811LedDataTransferInProgress = 0;
static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH]; static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH];

View file

@ -51,8 +51,9 @@ void setStripColors(const hsvColor_t *colors);
bool isWS2811LedStripReady(void); bool isWS2811LedStripReady(void);
#if defined(STM32F4)
extern uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#else
extern uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; extern uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#endif
extern volatile uint8_t ws2811LedDataTransferInProgress; extern volatile uint8_t ws2811LedDataTransferInProgress;
extern const hsvColor_t hsv_white;
extern const hsvColor_t hsv_black;

View file

@ -20,15 +20,16 @@
#include <platform.h> #include <platform.h>
#ifdef LED_STRIP
#include "common/color.h" #include "common/color.h"
#include "drivers/light_ws2811strip.h" #include "light_ws2811strip.h"
#include "nvic.h" #include "nvic.h"
#include "io.h" #include "io.h"
#include "dma.h" #include "dma.h"
#include "rcc.h"
#include "timer.h" #include "timer.h"
#ifdef LED_STRIP
static IO_t ws2811IO = IO_NONE; static IO_t ws2811IO = IO_NONE;
bool ws2811Initialised = false; bool ws2811Initialised = false;
@ -105,6 +106,7 @@ void ws2811LedStripHardwareInit(void)
DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE); DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
const hsvColor_t hsv_white = { 0, 255, 255};
ws2811Initialised = true; ws2811Initialised = true;
setStripColor(&hsv_white); setStripColor(&hsv_white);
ws2811UpdateStrip(); ws2811UpdateStrip();

View file

@ -20,17 +20,17 @@
#include <platform.h> #include <platform.h>
#ifdef LED_STRIP
#include "io.h" #include "io.h"
#include "nvic.h" #include "nvic.h"
#include "common/color.h" #include "common/color.h"
#include "drivers/light_ws2811strip.h" #include "light_ws2811strip.h"
#include "dma.h" #include "dma.h"
#include "rcc.h" #include "rcc.h"
#include "timer.h" #include "timer.h"
#ifdef LED_STRIP
#ifndef WS2811_PIN #ifndef WS2811_PIN
#define WS2811_PIN PB8 // TIM16_CH1 #define WS2811_PIN PB8 // TIM16_CH1
#define WS2811_TIMER TIM16 #define WS2811_TIMER TIM16
@ -111,6 +111,7 @@ void ws2811LedStripHardwareInit(void)
DMA_ITConfig(WS2811_DMA_CHANNEL, DMA_IT_TC, ENABLE); DMA_ITConfig(WS2811_DMA_CHANNEL, DMA_IT_TC, ENABLE);
const hsvColor_t hsv_white = { 0, 255, 255};
ws2811Initialised = true; ws2811Initialised = true;
setStripColor(&hsv_white); setStripColor(&hsv_white);
ws2811UpdateStrip(); ws2811UpdateStrip();

View file

@ -20,6 +20,8 @@
#include "platform.h" #include "platform.h"
#ifdef LED_STRIP
#include "common/color.h" #include "common/color.h"
#include "light_ws2811strip.h" #include "light_ws2811strip.h"
#include "nvic.h" #include "nvic.h"
@ -29,8 +31,6 @@
#include "rcc.h" #include "rcc.h"
#include "timer.h" #include "timer.h"
#ifdef LED_STRIP
#if !defined(WS2811_PIN) #if !defined(WS2811_PIN)
#define WS2811_PIN PA0 #define WS2811_PIN PA0
#define WS2811_TIMER TIM5 #define WS2811_TIMER TIM5
@ -50,7 +50,7 @@ static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) { if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
ws2811LedDataTransferInProgress = 0; ws2811LedDataTransferInProgress = 0;
DMA_Cmd(descriptor->stream, DISABLE); DMA_Cmd(descriptor->stream, DISABLE);
TIM_DMACmd(TIM5, TIM_DMA_CC1, DISABLE); TIM_DMACmd(WS2811_TIMER, timDMASource, DISABLE);
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF); DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
} }
} }
@ -154,6 +154,7 @@ void ws2811LedStripHardwareInit(void)
dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0); dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
const hsvColor_t hsv_white = { 0, 255, 255};
ws2811Initialised = true; ws2811Initialised = true;
setStripColor(&hsv_white); setStripColor(&hsv_white);
ws2811UpdateStrip(); ws2811UpdateStrip();

33
src/main/drivers/max7456.c Normal file → Executable file
View file

@ -19,16 +19,17 @@
#include <stdint.h> #include <stdint.h>
#include "platform.h" #include "platform.h"
#include "version.h"
#ifdef USE_MAX7456 #ifdef USE_MAX7456
#include "common/printf.h" #include "common/printf.h"
#include "drivers/bus_spi.h"
#include "drivers/light_led.h" #include "bus_spi.h"
#include "drivers/system.h" #include "light_led.h"
#include "drivers/nvic.h" #include "io.h"
#include "drivers/dma.h" #include "system.h"
#include "nvic.h"
#include "dma.h"
#include "max7456.h" #include "max7456.h"
#include "max7456_symbols.h" #include "max7456_symbols.h"
@ -75,6 +76,7 @@ static void max7456_send_dma(void* tx_buffer, void* rx_buffer, uint16_t buffer_s
#endif #endif
// Common to both channels // Common to both channels
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(MAX7456_SPI_INSTANCE->DR)); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(MAX7456_SPI_INSTANCE->DR));
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
@ -82,22 +84,31 @@ static void max7456_send_dma(void* tx_buffer, void* rx_buffer, uint16_t buffer_s
DMA_InitStructure.DMA_BufferSize = buffer_size; DMA_InitStructure.DMA_BufferSize = buffer_size;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low; DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
#ifdef MAX7456_DMA_CHANNEL_RX #ifdef MAX7456_DMA_CHANNEL_RX
// Rx Channel // Rx Channel
#ifdef STM32F4
DMA_InitStructure.DMA_Memory0BaseAddr = rx_buffer ? (uint32_t)rx_buffer : (uint32_t)(dummy);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
#else
DMA_InitStructure.DMA_MemoryBaseAddr = rx_buffer ? (uint32_t)rx_buffer : (uint32_t)(dummy); DMA_InitStructure.DMA_MemoryBaseAddr = rx_buffer ? (uint32_t)rx_buffer : (uint32_t)(dummy);
DMA_InitStructure.DMA_MemoryInc = rx_buffer ? DMA_MemoryInc_Enable : DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
#endif
DMA_InitStructure.DMA_MemoryInc = rx_buffer ? DMA_MemoryInc_Enable : DMA_MemoryInc_Disable;
DMA_Init(MAX7456_DMA_CHANNEL_RX, &DMA_InitStructure); DMA_Init(MAX7456_DMA_CHANNEL_RX, &DMA_InitStructure);
DMA_Cmd(MAX7456_DMA_CHANNEL_RX, ENABLE); DMA_Cmd(MAX7456_DMA_CHANNEL_RX, ENABLE);
#endif #endif
// Tx channel // Tx channel
#ifdef STM32F4
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)tx_buffer; //max7456_screen;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
#else
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)tx_buffer; //max7456_screen; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)tx_buffer; //max7456_screen;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
#endif
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Init(MAX7456_DMA_CHANNEL_TX, &DMA_InitStructure); DMA_Init(MAX7456_DMA_CHANNEL_TX, &DMA_InitStructure);
DMA_Cmd(MAX7456_DMA_CHANNEL_TX, ENABLE); DMA_Cmd(MAX7456_DMA_CHANNEL_TX, ENABLE);
@ -247,7 +258,7 @@ void max7456_draw_screen(void) {
max7456_send(MAX7456ADD_DMM, 1); max7456_send(MAX7456ADD_DMM, 1);
for (xx = 0; xx < max_screen_size; ++xx) { for (xx = 0; xx < max_screen_size; ++xx) {
max7456_send(MAX7456ADD_DMDI, SCREEN_BUFFER[xx]); max7456_send(MAX7456ADD_DMDI, SCREEN_BUFFER[xx]);
SCREEN_BUFFER[xx] = MAX7456_CHAR(0); SCREEN_BUFFER[xx] = MAX7456_CHAR(' ');
} }
max7456_send(MAX7456ADD_DMDI, 0xFF); max7456_send(MAX7456ADD_DMDI, 0xFF);
max7456_send(MAX7456ADD_DMM, 0); max7456_send(MAX7456ADD_DMM, 0);
@ -286,7 +297,7 @@ void max7456_write_nvm(uint8_t char_address, uint8_t *font_data) {
max7456_send(MAX7456ADD_CMM, WRITE_NVR); max7456_send(MAX7456ADD_CMM, WRITE_NVR);
// wait until bit 5 in the status register returns to 0 (12ms) // wait until bit 5 in the status register returns to 0 (12ms)
while ((spiTransferByte(MAX7456_SPI_INSTANCE, MAX7456ADD_STAT) & STATUS_REG_NVR_BUSY) != 0); while ((max7456_send(MAX7456ADD_STAT, 0) & STATUS_REG_NVR_BUSY) != 0x00);
max7456_send(VM0_REG, video_signal_type | 0x0C); max7456_send(VM0_REG, video_signal_type | 0x0C);
DISABLE_MAX7456; DISABLE_MAX7456;

View file

@ -178,7 +178,7 @@
// Voltage and amperage // Voltage and amperage
#define SYM_VOLT 0x06 #define SYM_VOLT 0x06
#define SYM_AMP 0x9A #define SYM_AMP 0x9A
#define SYM_MAH 0xA4 #define SYM_MAH 0x07
#define SYM_WATT 0x57 #define SYM_WATT 0x57
// Flying Mode // Flying Mode

View file

@ -30,11 +30,6 @@
#include "pwm_rx.h" #include "pwm_rx.h"
#include "pwm_mapping.h" #include "pwm_mapping.h"
void pwmBrushedMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate);
void pwmBrushlessMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse);
void pwmFastPwmMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint8_t fastPwmProtocolType, uint16_t motorPwmRate, uint16_t idlePulse);
void pwmServoConfig(const timerHardware_t *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
/* /*
Configuration maps Configuration maps
@ -94,14 +89,16 @@ pwmOutputConfiguration_t *pwmGetOutputConfiguration(void)
pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init) pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
{ {
int i = 0;
const uint16_t *setup; const uint16_t *setup;
#ifndef SKIP_RX_PWM_PPM
int channelIndex = 0; int channelIndex = 0;
#endif
memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration)); memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration));
// this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ]
int i = 0;
if (init->airplane) if (init->airplane)
i = 2; // switch to air hardware config i = 2; // switch to air hardware config
if (init->usePPM || init->useSerialRx) if (init->usePPM || init->useSerialRx)
@ -112,7 +109,7 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
#else #else
setup = hardwareMaps[i]; setup = hardwareMaps[i];
#endif #endif
TIM_TypeDef* ppmTimer = NULL;
for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) {
uint8_t timerIndex = setup[i] & 0x00FF; uint8_t timerIndex = setup[i] & 0x00FF;
uint8_t type = (setup[i] & 0xFF00) >> 8; uint8_t type = (setup[i] & 0xFF00) >> 8;
@ -165,13 +162,13 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
} }
#endif #endif
#ifdef RSSI_ADC_GPIO #ifdef RSSI_ADC_PIN
if (init->useRSSIADC && timerHardwarePtr->tag == IO_TAG(RSSI_ADC_PIN)) { if (init->useRSSIADC && timerHardwarePtr->tag == IO_TAG(RSSI_ADC_PIN)) {
continue; continue;
} }
#endif #endif
#ifdef CURRENT_METER_ADC_GPIO #ifdef CURRENT_METER_ADC_PIN
if (init->useCurrentMeterADC && timerHardwarePtr->tag == IO_TAG(CURRENT_METER_ADC_PIN)) { if (init->useCurrentMeterADC && timerHardwarePtr->tag == IO_TAG(CURRENT_METER_ADC_PIN)) {
continue; continue;
} }
@ -180,8 +177,8 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
#ifdef SONAR #ifdef SONAR
if (init->useSonar && if (init->useSonar &&
( (
timerHardwarePtr->tag == init->sonarConfig.triggerTag || timerHardwarePtr->tag == init->sonarIOConfig.triggerTag ||
timerHardwarePtr->tag == init->sonarConfig.echoTag timerHardwarePtr->tag == init->sonarIOConfig.echoTag
)) { )) {
continue; continue;
} }
@ -238,6 +235,19 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
type = MAP_TO_SERVO_OUTPUT; type = MAP_TO_SERVO_OUTPUT;
#endif #endif
#if defined(RCEXPLORERF3)
if (timerIndex == PWM2)
{
type = MAP_TO_SERVO_OUTPUT;
}
#endif
#if defined(SPRACINGF3EVO)
// remap PWM6+7 as servos
if ((timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM3)
type = MAP_TO_SERVO_OUTPUT;
#endif
#if (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) #if (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3))
// remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer
if (init->useSoftSerial) { if (init->useSoftSerial) {
@ -294,33 +304,42 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
#endif #endif
if (type == MAP_TO_PPM_INPUT) { if (type == MAP_TO_PPM_INPUT) {
#if defined(SPARKY) || defined(ALIENFLIGHTF3) #ifndef SKIP_RX_PWM_PPM
if (init->useFastPwm || init->pwmProtocolType == PWM_TYPE_BRUSHED) { ppmTimer = timerHardwarePtr->tim;
ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2);
}
#endif
ppmInConfig(timerHardwarePtr); ppmInConfig(timerHardwarePtr);
#endif
} else if (type == MAP_TO_PWM_INPUT) { } else if (type == MAP_TO_PWM_INPUT) {
#ifndef SKIP_RX_PWM_PPM
pwmInConfig(timerHardwarePtr, channelIndex); pwmInConfig(timerHardwarePtr, channelIndex);
channelIndex++; channelIndex++;
#endif
} else if (type == MAP_TO_MOTOR_OUTPUT) { } else if (type == MAP_TO_MOTOR_OUTPUT) {
// Check if we already configured maximum supported number of motors or output ports and skip the rest
if (pwmOutputConfiguration.motorCount >= MAX_MOTORS || pwmOutputConfiguration.outputCount >= MAX_PWM_OUTPUT_PORTS) {
continue;
}
#ifdef CC3D #ifdef CC3D
if (init->useFastPwm || init->pwmProtocolType == PWM_TYPE_BRUSHED) { if (!(init->pwmProtocolType == PWM_TYPE_CONVENTIONAL)) {
// Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed
if (timerHardwarePtr->tim == TIM2) if (timerHardwarePtr->tim == TIM2)
continue; continue;
} }
#endif #endif
if (init->usePPM) {
if (init->pwmProtocolType != PWM_TYPE_CONVENTIONAL && timerHardwarePtr->tim == ppmTimer) {
ppmAvoidPWMTimerClash(timerHardwarePtr, ppmTimer, init->pwmProtocolType);
}
}
if (init->useFastPwm) { if (init->useFastPwm) {
pwmFastPwmMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->pwmProtocolType, init->motorPwmRate, init->idlePulse); pwmFastPwmMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse, init->pwmProtocolType);
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_ONESHOT|PWM_PF_OUTPUT_PROTOCOL_PWM ; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM | PWM_PF_OUTPUT_PROTOCOL_ONESHOT;
} else if (init->pwmProtocolType == PWM_TYPE_BRUSHED) { } else if (init->pwmProtocolType == PWM_TYPE_BRUSHED) {
pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate); pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate);
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_MOTOR_MODE_BRUSHED | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM | PWM_PF_MOTOR_MODE_BRUSHED;
} else { } else {
pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM ; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM;
} }
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.motorCount; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.motorCount;
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].timerHardware = timerHardwarePtr; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].timerHardware = timerHardwarePtr;
@ -328,6 +347,9 @@ pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
pwmOutputConfiguration.outputCount++; pwmOutputConfiguration.outputCount++;
} else if (type == MAP_TO_SERVO_OUTPUT) { } else if (type == MAP_TO_SERVO_OUTPUT) {
#ifdef USE_SERVOS #ifdef USE_SERVOS
if (pwmOutputConfiguration.servoCount >= MAX_SERVOS || pwmOutputConfiguration.outputCount >= MAX_PWM_OUTPUT_PORTS) {
continue;
}
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.servoCount; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.servoCount;
pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse); pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse);
pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM;

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include "timer.h" #include "io_types.h"
#define MAX_PWM_MOTORS 12 #define MAX_PWM_MOTORS 12
#define MAX_PWM_SERVOS 8 #define MAX_PWM_SERVOS 8
@ -30,24 +30,8 @@
#error Invalid motor/servo/port configuration #error Invalid motor/servo/port configuration
#endif #endif
#define PULSE_1MS (1000) // 1ms pulse width
#define MAX_INPUTS 8
#define PWM_TIMER_MHZ 1 #define PWM_TIMER_MHZ 1
#if defined(STM32F40_41xxx) // must be multiples of timer clock
#define ONESHOT42_TIMER_MHZ 21
#define ONESHOT125_TIMER_MHZ 12
#define PWM_BRUSHED_TIMER_MHZ 21
#define MULTISHOT_TIMER_MHZ 84
#else
#define PWM_BRUSHED_TIMER_MHZ 24
#define MULTISHOT_TIMER_MHZ 72
#define ONESHOT42_TIMER_MHZ 24
#define ONESHOT125_TIMER_MHZ 8
#endif
#define MULTISHOT_5US_PW (MULTISHOT_TIMER_MHZ * 5)
#define MULTISHOT_20US_MULT (MULTISHOT_TIMER_MHZ * 20 / 1000.0f)
typedef struct sonarIOConfig_s { typedef struct sonarIOConfig_s {
ioTag_t triggerTag; ioTag_t triggerTag;
@ -84,9 +68,10 @@ typedef struct drv_pwm_config_s {
uint16_t motorPwmRate; uint16_t motorPwmRate;
uint16_t idlePulse; // PWM value to use when initializing the driver. set this to either PULSE_1MS (regular pwm), uint16_t idlePulse; // PWM value to use when initializing the driver. set this to either PULSE_1MS (regular pwm),
// some higher value (used by 3d mode), or 0, for brushed pwm drivers. // some higher value (used by 3d mode), or 0, for brushed pwm drivers.
sonarIOConfig_t sonarConfig; sonarIOConfig_t sonarIOConfig;
} drv_pwm_config_t; } drv_pwm_config_t;
enum { enum {
MAP_TO_PPM_INPUT = 1, MAP_TO_PPM_INPUT = 1,
MAP_TO_PWM_INPUT, MAP_TO_PWM_INPUT,
@ -103,10 +88,11 @@ typedef enum {
PWM_PF_OUTPUT_PROTOCOL_ONESHOT = (1 << 4) PWM_PF_OUTPUT_PROTOCOL_ONESHOT = (1 << 4)
} pwmPortFlags_e; } pwmPortFlags_e;
struct timerHardware_s;
typedef struct pwmPortConfiguration_s { typedef struct pwmPortConfiguration_s {
uint8_t index; uint8_t index;
pwmPortFlags_e flags; pwmPortFlags_e flags;
const timerHardware_t *timerHardware; const struct timerHardware_s *timerHardware;
} pwmPortConfiguration_t; } pwmPortConfiguration_t;
typedef struct pwmOutputConfiguration_s { typedef struct pwmOutputConfiguration_s {
@ -152,4 +138,5 @@ extern const uint16_t airPPM_BP6[];
extern const uint16_t airPWM_BP6[]; extern const uint16_t airPWM_BP6[];
#endif #endif
pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init);
pwmOutputConfiguration_t *pwmGetOutputConfiguration(void); pwmOutputConfiguration_t *pwmGetOutputConfiguration(void);

View file

@ -17,21 +17,19 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <math.h> #include <math.h>
#include "platform.h" #include "platform.h"
#include "io.h" #include "io.h"
#include "timer.h" #include "timer.h"
#include "flight/failsafe.h" // FIXME dependency into the main code from a driver
#include "pwm_mapping.h" #include "pwm_mapping.h"
#include "pwm_output.h" #include "pwm_output.h"
#define MULTISHOT_5US_PW (MULTISHOT_TIMER_MHZ * 5)
#define MULTISHOT_20US_MULT (MULTISHOT_TIMER_MHZ * 20 / 1000.0f)
typedef void (*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors typedef void (*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors
typedef struct { typedef struct {
@ -52,16 +50,23 @@ static pwmOutputPort_t *servos[MAX_PWM_SERVOS];
static uint8_t allocatedOutputPortCount = 0; static uint8_t allocatedOutputPortCount = 0;
static bool pwmMotorsEnabled = true; static bool pwmMotorsEnabled = true;
static void pwmOCConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t value, uint8_t ouputPolarity)
static void pwmOCConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t value, uint8_t output)
{ {
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
if (output & TIMER_OUTPUT_N_CHANNEL) {
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
} else {
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
}
TIM_OCInitStructure.TIM_Pulse = value; TIM_OCInitStructure.TIM_Pulse = value;
TIM_OCInitStructure.TIM_OCPolarity = ouputPolarity ? TIM_OCPolarity_High : TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OCPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
switch (channel) { switch (channel) {
@ -90,11 +95,11 @@ static pwmOutputPort_t *pwmOutConfig(const timerHardware_t *timerHardware, uint8
configTimeBase(timerHardware->tim, period, mhz); configTimeBase(timerHardware->tim, period, mhz);
IO_t io = IOGetByTag(timerHardware->tag); const IO_t io = IOGetByTag(timerHardware->tag);
IOInit(io, OWNER_MOTOR, RESOURCE_OUTPUT, allocatedOutputPortCount); IOInit(io, OWNER_MOTOR, RESOURCE_OUTPUT, allocatedOutputPortCount);
IOConfigGPIO(io, IOCFG_AF_PP); IOConfigGPIO(io, IOCFG_AF_PP);
pwmOCConfig(timerHardware->tim, timerHardware->channel, value, timerHardware->output & TIMER_OUTPUT_INVERTED); pwmOCConfig(timerHardware->tim, timerHardware->channel, value, timerHardware->output);
if (timerHardware->output & TIMER_OUTPUT_ENABLED) { if (timerHardware->output & TIMER_OUTPUT_ENABLED) {
TIM_CtrlPWMOutputs(timerHardware->tim, ENABLE); TIM_CtrlPWMOutputs(timerHardware->tim, ENABLE);
@ -118,6 +123,8 @@ static pwmOutputPort_t *pwmOutConfig(const timerHardware_t *timerHardware, uint8
p->period = period; p->period = period;
p->tim = timerHardware->tim; p->tim = timerHardware->tim;
*p->ccr = 0;
return p; return p;
} }
@ -131,16 +138,16 @@ static void pwmWriteStandard(uint8_t index, uint16_t value)
*motors[index]->ccr = value; *motors[index]->ccr = value;
} }
static void pwmWriteOneShot42(uint8_t index, uint16_t value)
{
*motors[index]->ccr = lrintf((float)(value * ONESHOT42_TIMER_MHZ/24.0f));
}
static void pwmWriteOneShot125(uint8_t index, uint16_t value) static void pwmWriteOneShot125(uint8_t index, uint16_t value)
{ {
*motors[index]->ccr = lrintf((float)(value * ONESHOT125_TIMER_MHZ/8.0f)); *motors[index]->ccr = lrintf((float)(value * ONESHOT125_TIMER_MHZ/8.0f));
} }
static void pwmWriteOneShot42(uint8_t index, uint16_t value)
{
*motors[index]->ccr = lrintf((float)(value * ONESHOT42_TIMER_MHZ/24.0f));
}
static void pwmWriteMultiShot(uint8_t index, uint16_t value) static void pwmWriteMultiShot(uint8_t index, uint16_t value)
{ {
*motors[index]->ccr = lrintf(((float)(value-1000) * MULTISHOT_20US_MULT) + MULTISHOT_5US_PW); *motors[index]->ccr = lrintf(((float)(value-1000) * MULTISHOT_20US_MULT) + MULTISHOT_5US_PW);
@ -148,15 +155,14 @@ static void pwmWriteMultiShot(uint8_t index, uint16_t value)
void pwmWriteMotor(uint8_t index, uint16_t value) void pwmWriteMotor(uint8_t index, uint16_t value)
{ {
if (motors[index] && index < MAX_MOTORS && pwmMotorsEnabled) if (motors[index] && index < MAX_MOTORS && pwmMotorsEnabled) {
motors[index]->pwmWritePtr(index, value); motors[index]->pwmWritePtr(index, value);
}
} }
void pwmShutdownPulsesForAllMotors(uint8_t motorCount) void pwmShutdownPulsesForAllMotors(uint8_t motorCount)
{ {
uint8_t index; for (int index = 0; index < motorCount; index++) {
for(index = 0; index < motorCount; index++){
// Set the compare register to 0, which stops the output pulsing if the timer overflows // Set the compare register to 0, which stops the output pulsing if the timer overflows
*motors[index]->ccr = 0; *motors[index]->ccr = 0;
} }
@ -174,17 +180,18 @@ void pwmEnableMotors(void)
void pwmCompleteOneshotMotorUpdate(uint8_t motorCount) void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
{ {
uint8_t index; for (int index = 0; index < motorCount; index++) {
TIM_TypeDef *lastTimerPtr = NULL; bool overflowed = false;
// If we have not already overflowed this timer
for (index = 0; index < motorCount; index++) { for (int j = 0; j < index; j++) {
if (motors[j]->tim == motors[index]->tim) {
// Force the timer to overflow if it's the first motor to output, or if we change timers overflowed = true;
if (motors[index]->tim != lastTimerPtr) { break;
lastTimerPtr = motors[index]->tim; }
}
if (!overflowed) {
timerForceOverflow(motors[index]->tim); timerForceOverflow(motors[index]->tim);
} }
// Set the compare register to 0, which stops the output pulsing if the timer overflows before the main loop completes again. // Set the compare register to 0, which stops the output pulsing if the timer overflows before the main loop completes again.
// This compare register will be set to the output value on the next main loop. // This compare register will be set to the output value on the next main loop.
*motors[index]->ccr = 0; *motors[index]->ccr = 0;
@ -193,44 +200,46 @@ void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
void pwmBrushedMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate) void pwmBrushedMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate)
{ {
uint32_t hz = PWM_BRUSHED_TIMER_MHZ * 1000000; const uint32_t hz = PWM_BRUSHED_TIMER_MHZ * 1000000;
motors[motorIndex] = pwmOutConfig(timerHardware, PWM_BRUSHED_TIMER_MHZ, hz / motorPwmRate, 0); motors[motorIndex] = pwmOutConfig(timerHardware, PWM_BRUSHED_TIMER_MHZ, hz / motorPwmRate, 0);
motors[motorIndex]->pwmWritePtr = pwmWriteBrushed; motors[motorIndex]->pwmWritePtr = pwmWriteBrushed;
} }
void pwmBrushlessMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse) void pwmBrushlessMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse)
{ {
uint32_t hz = PWM_TIMER_MHZ * 1000000; const uint32_t hz = PWM_TIMER_MHZ * 1000000;
motors[motorIndex] = pwmOutConfig(timerHardware, PWM_TIMER_MHZ, hz / motorPwmRate, idlePulse); motors[motorIndex] = pwmOutConfig(timerHardware, PWM_TIMER_MHZ, hz / motorPwmRate, idlePulse);
motors[motorIndex]->pwmWritePtr = pwmWriteStandard; motors[motorIndex]->pwmWritePtr = pwmWriteStandard;
} }
void pwmFastPwmMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint8_t fastPwmProtocolType, uint16_t motorPwmRate, uint16_t idlePulse) void pwmFastPwmMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse, uint8_t fastPwmProtocolType)
{ {
uint32_t timerMhzCounter; uint32_t timerMhzCounter;
pwmWriteFuncPtr pwmWritePtr;
switch (fastPwmProtocolType) { switch (fastPwmProtocolType) {
default: default:
case (PWM_TYPE_ONESHOT125): case (PWM_TYPE_ONESHOT125):
timerMhzCounter = ONESHOT125_TIMER_MHZ; timerMhzCounter = ONESHOT125_TIMER_MHZ;
pwmWritePtr = pwmWriteOneShot125;
break; break;
case (PWM_TYPE_ONESHOT42): case (PWM_TYPE_ONESHOT42):
timerMhzCounter = ONESHOT42_TIMER_MHZ; timerMhzCounter = ONESHOT42_TIMER_MHZ;
pwmWritePtr = pwmWriteOneShot42;
break; break;
case (PWM_TYPE_MULTISHOT): case (PWM_TYPE_MULTISHOT):
timerMhzCounter = MULTISHOT_TIMER_MHZ; timerMhzCounter = MULTISHOT_TIMER_MHZ;
pwmWritePtr = pwmWriteMultiShot;
break;
} }
if (motorPwmRate > 0) { if (motorPwmRate > 0) {
uint32_t hz = timerMhzCounter * 1000000; const uint32_t hz = timerMhzCounter * 1000000;
motors[motorIndex] = pwmOutConfig(timerHardware, timerMhzCounter, hz / motorPwmRate, idlePulse); motors[motorIndex] = pwmOutConfig(timerHardware, timerMhzCounter, hz / motorPwmRate, idlePulse);
} else { } else {
motors[motorIndex] = pwmOutConfig(timerHardware, timerMhzCounter, 0xFFFF, 0); motors[motorIndex] = pwmOutConfig(timerHardware, timerMhzCounter, 0xFFFF, 0);
} }
motors[motorIndex]->pwmWritePtr = pwmWritePtr;
motors[motorIndex]->pwmWritePtr = (fastPwmProtocolType == PWM_TYPE_MULTISHOT) ? pwmWriteMultiShot :
((fastPwmProtocolType == PWM_TYPE_ONESHOT125) ? pwmWriteOneShot125 :
pwmWriteOneShot42);
} }
#ifdef USE_SERVOS #ifdef USE_SERVOS
@ -241,7 +250,8 @@ void pwmServoConfig(const timerHardware_t *timerHardware, uint8_t servoIndex, ui
void pwmWriteServo(uint8_t index, uint16_t value) void pwmWriteServo(uint8_t index, uint16_t value)
{ {
if (servos[index] && index < MAX_SERVOS) if (servos[index] && index < MAX_SERVOS) {
*servos[index]->ccr = value; *servos[index]->ccr = value;
}
} }
#endif #endif

View file

@ -25,6 +25,24 @@ typedef enum {
PWM_TYPE_BRUSHED PWM_TYPE_BRUSHED
} motorPwmProtocolTypes_e; } motorPwmProtocolTypes_e;
#if defined(STM32F40_41xxx) // must be multiples of timer clock
#define ONESHOT125_TIMER_MHZ 12
#define ONESHOT42_TIMER_MHZ 21
#define MULTISHOT_TIMER_MHZ 84
#define PWM_BRUSHED_TIMER_MHZ 21
#else
#define ONESHOT125_TIMER_MHZ 8
#define ONESHOT42_TIMER_MHZ 24
#define MULTISHOT_TIMER_MHZ 72
#define PWM_BRUSHED_TIMER_MHZ 24
#endif
struct timerHardware_s;
void pwmBrushedMotorConfig(const struct timerHardware_s *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate);
void pwmBrushlessMotorConfig(const struct timerHardware_s *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse);
void pwmFastPwmMotorConfig(const struct timerHardware_s *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse, uint8_t fastPwmProtocolType);
void pwmServoConfig(const struct timerHardware_s *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
void pwmWriteMotor(uint8_t index, uint16_t value); void pwmWriteMotor(uint8_t index, uint16_t value);
void pwmShutdownPulsesForAllMotors(uint8_t motorCount); void pwmShutdownPulsesForAllMotors(uint8_t motorCount);
void pwmCompleteOneshotMotorUpdate(uint8_t motorCount); void pwmCompleteOneshotMotorUpdate(uint8_t motorCount);

View file

@ -20,17 +20,20 @@
#include <platform.h> #include <platform.h>
#include "build_config.h" #ifndef SKIP_RX_PWM_PPM
#include "debug.h"
#include "build/build_config.h"
#include "build/debug.h"
#include "common/utils.h" #include "common/utils.h"
#include "system.h" #include "system.h"
#include "nvic.h" #include "nvic.h"
#include "gpio.h" #include "io.h"
#include "timer.h" #include "timer.h"
#include "pwm_output.h"
#include "pwm_mapping.h" #include "pwm_mapping.h"
#include "pwm_rx.h" #include "pwm_rx.h"
@ -83,7 +86,7 @@ static uint16_t captures[PWM_PORTS_OR_PPM_CAPTURE_COUNT];
static uint8_t ppmFrameCount = 0; static uint8_t ppmFrameCount = 0;
static uint8_t lastPPMFrameCount = 0; static uint8_t lastPPMFrameCount = 0;
static uint8_t ppmCountShift = 0; static uint8_t ppmCountDivisor = 1;
typedef struct ppmDevice_s { typedef struct ppmDevice_s {
uint8_t pulseIndex; uint8_t pulseIndex;
@ -177,7 +180,6 @@ static void ppmOverflowCallback(timerOvrHandlerRec_t* cbRec, captureCompare_t ca
if (capture == PPM_TIMER_PERIOD - 1) { if (capture == PPM_TIMER_PERIOD - 1) {
ppmDev.overflowed = true; ppmDev.overflowed = true;
} }
} }
static void ppmEdgeCallback(timerCCHandlerRec_t* cbRec, captureCompare_t capture) static void ppmEdgeCallback(timerCCHandlerRec_t* cbRec, captureCompare_t capture)
@ -202,14 +204,14 @@ static void ppmEdgeCallback(timerCCHandlerRec_t* cbRec, captureCompare_t capture
} }
} }
// Divide by 8 if Oneshot125 is active and this is a CC3D board // Divide value if Oneshot, Multishot or brushed motors are active and the timer is shared
currentTime = currentTime >> ppmCountShift; currentTime = currentTime / ppmCountDivisor;
/* Capture computation */ /* Capture computation */
if (currentTime > previousTime) { if (currentTime > previousTime) {
ppmDev.deltaTime = currentTime - (previousTime + (ppmDev.overflowed ? (PPM_TIMER_PERIOD >> ppmCountShift) : 0)); ppmDev.deltaTime = currentTime - (previousTime + (ppmDev.overflowed ? (PPM_TIMER_PERIOD / ppmCountDivisor) : 0));
} else { } else {
ppmDev.deltaTime = (PPM_TIMER_PERIOD >> ppmCountShift) + currentTime - previousTime; ppmDev.deltaTime = (PPM_TIMER_PERIOD / ppmCountDivisor) + currentTime - previousTime;
} }
ppmDev.overflowed = false; ppmDev.overflowed = false;
@ -381,10 +383,24 @@ void pwmInConfig(const timerHardware_t *timerHardwarePtr, uint8_t channel)
#define UNUSED_PPM_TIMER_REFERENCE 0 #define UNUSED_PPM_TIMER_REFERENCE 0
#define FIRST_PWM_PORT 0 #define FIRST_PWM_PORT 0
void ppmAvoidPWMTimerClash(const timerHardware_t *timerHardwarePtr, TIM_TypeDef *sharedPwmTimer) void ppmAvoidPWMTimerClash(const timerHardware_t *timerHardwarePtr, TIM_TypeDef *sharedPwmTimer, uint8_t pwmProtocol)
{ {
if (timerHardwarePtr->tim == sharedPwmTimer) { if (timerHardwarePtr->tim == sharedPwmTimer) {
ppmCountShift = 3; // Divide by 8 if the timer is running at 8 MHz switch (pwmProtocol)
{
case PWM_TYPE_ONESHOT125:
ppmCountDivisor = ONESHOT125_TIMER_MHZ;
break;
case PWM_TYPE_ONESHOT42:
ppmCountDivisor = ONESHOT42_TIMER_MHZ;
break;
case PWM_TYPE_MULTISHOT:
ppmCountDivisor = MULTISHOT_TIMER_MHZ;
break;
case PWM_TYPE_BRUSHED:
ppmCountDivisor = PWM_BRUSHED_TIMER_MHZ;
break;
}
} }
} }
@ -419,3 +435,4 @@ uint16_t pwmRead(uint8_t channel)
{ {
return captures[channel]; return captures[channel];
} }
#endif

View file

@ -26,7 +26,7 @@ typedef enum {
void ppmInConfig(const timerHardware_t *timerHardwarePtr); void ppmInConfig(const timerHardware_t *timerHardwarePtr);
void ppmAvoidPWMTimerClash(const timerHardware_t *timerHardwarePtr, TIM_TypeDef *sharedPwmTimer); void ppmAvoidPWMTimerClash(const timerHardware_t *timerHardwarePtr, TIM_TypeDef *sharedPwmTimer, uint8_t pwmProtocol);
void pwmInConfig(const timerHardware_t *timerHardwarePtr, uint8_t channel); void pwmInConfig(const timerHardware_t *timerHardwarePtr, uint8_t channel);
uint16_t pwmRead(uint8_t channel); uint16_t pwmRead(uint8_t channel);

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "platform.h" #include "rcc_types.h"
#include "common/utils.h"
enum rcc_reg { enum rcc_reg {
RCC_EMPTY = 0, // make sure that default value (0) does not enable anything RCC_EMPTY = 0, // make sure that default value (0) does not enable anything
@ -17,9 +16,6 @@ enum rcc_reg {
#define RCC_APB1(periph) RCC_ENCODE(RCC_APB1, RCC_APB1ENR_ ## periph ## EN) #define RCC_APB1(periph) RCC_ENCODE(RCC_APB1, RCC_APB1ENR_ ## periph ## EN)
#define RCC_AHB1(periph) RCC_ENCODE(RCC_AHB1, RCC_AHB1ENR_ ## periph ## EN) #define RCC_AHB1(periph) RCC_ENCODE(RCC_AHB1, RCC_AHB1ENR_ ## periph ## EN)
typedef uint8_t rccPeriphTag_t;
void RCC_ClockCmd(rccPeriphTag_t periphTag, FunctionalState NewState); void RCC_ClockCmd(rccPeriphTag_t periphTag, FunctionalState NewState);
void RCC_ResetCmd(rccPeriphTag_t periphTag, FunctionalState NewState); void RCC_ResetCmd(rccPeriphTag_t periphTag, FunctionalState NewState);

Some files were not shown because too many files have changed in this diff Show more