mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-19 14:25:20 +03:00
Merge branch 'master' into target_pico
This commit is contained in:
commit
6bef8e5616
222 changed files with 7590 additions and 3531 deletions
17
.travis.sh
17
.travis.sh
|
@ -8,7 +8,6 @@ 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}
|
||||||
MAKEFILE="-f Makefile"
|
|
||||||
|
|
||||||
CURL_BASEOPTS=(
|
CURL_BASEOPTS=(
|
||||||
"--retry" "10"
|
"--retry" "10"
|
||||||
|
@ -22,12 +21,8 @@ CURL_PUB_BASEOPTS=(
|
||||||
"--form" "github_repo=${TRAVIS_REPO_SLUG}"
|
"--form" "github_repo=${TRAVIS_REPO_SLUG}"
|
||||||
"--form" "build_name=${BUILDNAME}" )
|
"--form" "build_name=${BUILDNAME}" )
|
||||||
|
|
||||||
# A hacky way of running the unit tests at the same time as the normal builds.
|
|
||||||
if [ $RUNTESTS ] ; then
|
|
||||||
cd ./src/test && make test
|
|
||||||
|
|
||||||
# A hacky way of building the docs at the same time as the normal builds.
|
# A hacky way of building the docs at the same time as the normal builds.
|
||||||
elif [ $PUBLISHDOCS ] ; then
|
if [ $PUBLISHDOCS ] ; then
|
||||||
if [ $PUBLISH_URL ] ; then
|
if [ $PUBLISH_URL ] ; then
|
||||||
|
|
||||||
# Patch Gimli to fix underscores_inside_words
|
# Patch Gimli to fix underscores_inside_words
|
||||||
|
@ -50,9 +45,9 @@ elif [ $PUBLISHMETA ] ; then
|
||||||
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "recent_commits=${RECENT_COMMITS}" ${PUBLISH_URL} || true
|
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "recent_commits=${RECENT_COMMITS}" ${PUBLISH_URL} || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
elif [ $TARGET ] ; then
|
||||||
|
make $TARGET
|
||||||
if [ $PUBLISH_URL ] ; then
|
if [ $PUBLISH_URL ] ; then
|
||||||
make -j2 $MAKEFILE
|
|
||||||
if [ -f ${TARGET_FILE}.bin ] ; then
|
if [ -f ${TARGET_FILE}.bin ] ; then
|
||||||
TARGET_FILE=${TARGET_FILE}.bin
|
TARGET_FILE=${TARGET_FILE}.bin
|
||||||
elif [ -f ${TARGET_FILE}.hex ] ; then
|
elif [ -f ${TARGET_FILE}.hex ] ; then
|
||||||
|
@ -64,7 +59,9 @@ else
|
||||||
|
|
||||||
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "file=@${TARGET_FILE}" ${PUBLISH_URL} || true
|
curl -k "${CURL_BASEOPTS[@]}" "${CURL_PUB_BASEOPTS[@]}" --form "file=@${TARGET_FILE}" ${PUBLISH_URL} || true
|
||||||
exit 0;
|
exit 0;
|
||||||
|
fi
|
||||||
|
elif [ $GOAL ] ; then
|
||||||
|
make V=0 $GOAL
|
||||||
else
|
else
|
||||||
make -j2 $MAKEFILE
|
make V=0 all
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
70
.travis.yml
70
.travis.yml
|
@ -1,20 +1,25 @@
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# - RUNTESTS=True
|
|
||||||
# - PUBLISHMETA=True
|
# - PUBLISHMETA=True
|
||||||
# - PUBLISHDOCS=True
|
# - PUBLISHDOCS=True
|
||||||
|
# Specify the main Mafile supported goals.
|
||||||
|
- GOAL=test
|
||||||
|
- GOAL=all
|
||||||
|
# Or specify targets to run.
|
||||||
# - TARGET=AFROMINI
|
# - TARGET=AFROMINI
|
||||||
# - TARGET=BEEBRAIN
|
|
||||||
# - TARGET=AIORACERF3
|
# - TARGET=AIORACERF3
|
||||||
# - TARGET=AIR32
|
# - TARGET=AIR32
|
||||||
|
# - TARGET=AIRBOTF4
|
||||||
# - TARGET=AIRHEROF3
|
# - TARGET=AIRHEROF3
|
||||||
# - TARGET=ALIENFLIGHTF1
|
# - TARGET=ALIENFLIGHTF1
|
||||||
- TARGET=ALIENFLIGHTF3
|
# - TARGET=ALIENFLIGHTF3
|
||||||
- TARGET=ALIENFLIGHTF4
|
# - TARGET=ALIENFLIGHTF4
|
||||||
- TARGET=ANYFCF7
|
# - TARGET=ANYFCF7
|
||||||
- TARGET=BETAFLIGHTF3
|
# - TARGET=BEEBRAIN
|
||||||
- TARGET=BLUEJAYF4
|
# - TARGET=BETAFLIGHTF3
|
||||||
- TARGET=CC3D
|
# - TARGET=BLUEJAYF4
|
||||||
- TARGET=CC3D_OPBL
|
# - TARGET=CC3D
|
||||||
|
# - TARGET=CC3D_OPBL
|
||||||
# - TARGET=CHEBUZZF3
|
# - TARGET=CHEBUZZF3
|
||||||
# - TARGET=CJMCU
|
# - TARGET=CJMCU
|
||||||
# - TARGET=COLIBRI
|
# - TARGET=COLIBRI
|
||||||
|
@ -23,50 +28,51 @@ env:
|
||||||
# - TARGET=DOGE
|
# - TARGET=DOGE
|
||||||
# - TARGET=F4BY
|
# - TARGET=F4BY
|
||||||
# - TARGET=FURYF3
|
# - TARGET=FURYF3
|
||||||
- TARGET=FURYF4
|
# - TARGET=FURYF4
|
||||||
|
# - TARGET=FURYF7
|
||||||
|
# - TARGET=IMPULSERCF3
|
||||||
# - TARGET=IRCFUSIONF3
|
# - TARGET=IRCFUSIONF3
|
||||||
# - TARGET=ISHAPEDF3
|
# - TARGET=ISHAPEDF3
|
||||||
# - TARGET=KISSFC
|
# - TARGET=KISSFC
|
||||||
|
# - TARGET=LUXV2_RACE
|
||||||
# - TARGET=LUX_RACE
|
# - TARGET=LUX_RACE
|
||||||
# - TARGET=MICROSCISKY
|
# - TARGET=MICROSCISKY
|
||||||
# - TARGET=MOTOLAB
|
# - TARGET=MOTOLAB
|
||||||
- TARGET=NAZE
|
# - TARGET=NAZE
|
||||||
# - TARGET=OMNIBUS
|
# - TARGET=OMNIBUS
|
||||||
# - TARGET=OMNIBUSF4
|
# - TARGET=OMNIBUSF4
|
||||||
# - TARGET=PIKOBLX
|
# - TARGET=PIKOBLX
|
||||||
# - TARGET=RACEBASE
|
# - TARGET=RACEBASE
|
||||||
- TARGET=REVO
|
# - TARGET=RCEXPLORERF3
|
||||||
|
# - TARGET=REVO
|
||||||
|
# - TARGET=REVOLT
|
||||||
# - TARGET=REVONANO
|
# - TARGET=REVONANO
|
||||||
# - TARGET=REVO_OPBL
|
# - TARGET=REVO_OPBL
|
||||||
# - TARGET=RMDO
|
# - TARGET=RMDO
|
||||||
# - TARGET=SINGULARITY
|
# - TARGET=SINGULARITY
|
||||||
- TARGET=SIRINFPV
|
# - TARGET=SIRINFPV
|
||||||
- TARGET=SPARKY
|
# - TARGET=SOULF4
|
||||||
|
# - TARGET=SPARKY
|
||||||
# - TARGET=SPARKY2
|
# - TARGET=SPARKY2
|
||||||
# - TARGET=SPARKY_OPBL
|
# - TARGET=SPRACINGF3
|
||||||
- TARGET=SPRACINGF3
|
# - TARGET=SPRACINGF3EVO
|
||||||
- TARGET=SPRACINGF3EVO
|
|
||||||
# - TARGET=SPRACINGF3MINI
|
# - TARGET=SPRACINGF3MINI
|
||||||
- TARGET=STM32F3DISCOVERY
|
# - TARGET=STM32F3DISCOVERY
|
||||||
# - TARGET=VRRACE
|
# - TARGET=VRRACE
|
||||||
# - TARGET=X_RACERSPI
|
# - TARGET=X_RACERSPI
|
||||||
|
# - TARGET=YUPIF4
|
||||||
# - TARGET=ZCOREF3
|
# - TARGET=ZCOREF3
|
||||||
# - TARGET=RCEXPLORERF3
|
|
||||||
|
|
||||||
# use new docker environment
|
# use new docker environment
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: 5
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- build-essential
|
|
||||||
- git
|
|
||||||
- libc6-i386
|
- libc6-i386
|
||||||
- zlib1g-dev
|
|
||||||
- libssl-dev
|
|
||||||
- wkhtmltopdf
|
|
||||||
- libxml2-dev
|
|
||||||
- libxslt-dev
|
|
||||||
|
|
||||||
# We use cpp for unit tests, and c for the main project.
|
# We use cpp for unit tests, and c for the main project.
|
||||||
language: cpp
|
language: cpp
|
||||||
|
@ -75,10 +81,17 @@ compiler: clang
|
||||||
install:
|
install:
|
||||||
- make arm_sdk_install
|
- make arm_sdk_install
|
||||||
|
|
||||||
before_script: tools/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gcc --version
|
before_script:
|
||||||
|
- tools/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gcc --version
|
||||||
|
- clang --version
|
||||||
|
- clang++ --version
|
||||||
|
|
||||||
script: ./.travis.sh
|
script: ./.travis.sh
|
||||||
|
|
||||||
cache: apt
|
cache:
|
||||||
|
directories:
|
||||||
|
- downloads
|
||||||
|
- tools
|
||||||
|
|
||||||
#notifications:
|
#notifications:
|
||||||
# irc: "chat.freenode.net#cleanflight"
|
# irc: "chat.freenode.net#cleanflight"
|
||||||
|
@ -93,4 +106,3 @@ notifications:
|
||||||
on_success: always # options: [always|never|change] default: always
|
on_success: always # options: [always|never|change] default: always
|
||||||
on_failure: 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
|
on_start: always # options: [always|never|change] default: always
|
||||||
|
|
||||||
|
|
49
Makefile
49
Makefile
|
@ -45,10 +45,16 @@ export AT := @
|
||||||
ifndef V
|
ifndef V
|
||||||
export V0 :=
|
export V0 :=
|
||||||
export V1 := $(AT)
|
export V1 := $(AT)
|
||||||
|
export STDOUT :=
|
||||||
else ifeq ($(V), 0)
|
else ifeq ($(V), 0)
|
||||||
export V0 := $(AT)
|
export V0 := $(AT)
|
||||||
export V1 := $(AT)
|
export V1 := $(AT)
|
||||||
|
export STDOUT:= "> /dev/null"
|
||||||
|
export MAKE := $(MAKE) --no-print-directory
|
||||||
else ifeq ($(V), 1)
|
else ifeq ($(V), 1)
|
||||||
|
export V0 :=
|
||||||
|
export V1 :=
|
||||||
|
export STDOUT :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -158,6 +164,10 @@ else
|
||||||
STM32F30x_COMMON_SRC = startup_stm32f30x_md_gcc.S
|
STM32F30x_COMMON_SRC = startup_stm32f30x_md_gcc.S
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DEBUG_HARDFAULTS),F7)
|
||||||
|
CFLAGS += -DDEBUG_HARDFAULTS
|
||||||
|
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/build/version.h | awk '{print $$3}' )
|
FC_VER_MAJOR := $(shell grep " FC_VERSION_MAJOR" src/main/build/version.h | awk '{print $$3}' )
|
||||||
|
@ -364,7 +374,7 @@ endif
|
||||||
ARCH_FLAGS = -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -fsingle-precision-constant -Wdouble-promotion
|
ARCH_FLAGS = -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -fsingle-precision-constant -Wdouble-promotion
|
||||||
|
|
||||||
ifeq ($(TARGET),$(filter $(TARGET),$(F7X5XG_TARGETS)))
|
ifeq ($(TARGET),$(filter $(TARGET),$(F7X5XG_TARGETS)))
|
||||||
DEVICE_FLAGS = -DSTM32F745xx -DUSE_HAL_DRIVER -D__FPU_PRESENT -DDEBUG_HARDFAULTS
|
DEVICE_FLAGS = -DSTM32F745xx -DUSE_HAL_DRIVER -D__FPU_PRESENT
|
||||||
LD_SCRIPT = $(LINKER_DIR)/stm32_flash_f745.ld
|
LD_SCRIPT = $(LINKER_DIR)/stm32_flash_f745.ld
|
||||||
else
|
else
|
||||||
$(error Unknown MCU for F7 target)
|
$(error Unknown MCU for F7 target)
|
||||||
|
@ -481,6 +491,7 @@ COMMON_SRC = \
|
||||||
drivers/bus_i2c_soft.c \
|
drivers/bus_i2c_soft.c \
|
||||||
drivers/bus_spi.c \
|
drivers/bus_spi.c \
|
||||||
drivers/bus_spi_soft.c \
|
drivers/bus_spi_soft.c \
|
||||||
|
drivers/display.c \
|
||||||
drivers/exti.c \
|
drivers/exti.c \
|
||||||
drivers/gyro_sync.c \
|
drivers/gyro_sync.c \
|
||||||
drivers/io.c \
|
drivers/io.c \
|
||||||
|
@ -546,6 +557,14 @@ COMMON_SRC = \
|
||||||
HIGHEND_SRC = \
|
HIGHEND_SRC = \
|
||||||
blackbox/blackbox.c \
|
blackbox/blackbox.c \
|
||||||
blackbox/blackbox_io.c \
|
blackbox/blackbox_io.c \
|
||||||
|
cms/cms.c \
|
||||||
|
cms/cms_menu_blackbox.c \
|
||||||
|
cms/cms_menu_builtin.c \
|
||||||
|
cms/cms_menu_imu.c \
|
||||||
|
cms/cms_menu_ledstrip.c \
|
||||||
|
cms/cms_menu_misc.c \
|
||||||
|
cms/cms_menu_osd.c \
|
||||||
|
cms/cms_menu_vtx.c \
|
||||||
common/colorconversion.c \
|
common/colorconversion.c \
|
||||||
drivers/display_ug2864hsweg01.c \
|
drivers/display_ug2864hsweg01.c \
|
||||||
drivers/light_ws2811strip.c \
|
drivers/light_ws2811strip.c \
|
||||||
|
@ -555,9 +574,13 @@ HIGHEND_SRC = \
|
||||||
flight/gtune.c \
|
flight/gtune.c \
|
||||||
flight/navigation.c \
|
flight/navigation.c \
|
||||||
flight/gps_conversion.c \
|
flight/gps_conversion.c \
|
||||||
|
io/dashboard.c \
|
||||||
|
io/displayport_max7456.c \
|
||||||
|
io/displayport_msp.c \
|
||||||
|
io/displayport_oled.c \
|
||||||
io/gps.c \
|
io/gps.c \
|
||||||
io/ledstrip.c \
|
io/ledstrip.c \
|
||||||
io/display.c \
|
io/osd.c \
|
||||||
sensors/sonar.c \
|
sensors/sonar.c \
|
||||||
sensors/barometer.c \
|
sensors/barometer.c \
|
||||||
telemetry/telemetry.c \
|
telemetry/telemetry.c \
|
||||||
|
@ -716,8 +739,8 @@ CCACHE :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Tool names
|
# Tool names
|
||||||
CC := $(CCACHE) $(ARM_SDK_PREFIX)gcc
|
CROSS_CC := $(CCACHE) $(ARM_SDK_PREFIX)gcc
|
||||||
CPP := $(CCACHE) $(ARM_SDK_PREFIX)g++
|
CROSS_CXX := $(CCACHE) $(ARM_SDK_PREFIX)g++
|
||||||
OBJCOPY := $(ARM_SDK_PREFIX)objcopy
|
OBJCOPY := $(ARM_SDK_PREFIX)objcopy
|
||||||
SIZE := $(ARM_SDK_PREFIX)size
|
SIZE := $(ARM_SDK_PREFIX)size
|
||||||
|
|
||||||
|
@ -809,26 +832,26 @@ $(TARGET_BIN): $(TARGET_ELF)
|
||||||
$(V0) $(OBJCOPY) -O binary $< $@
|
$(V0) $(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
$(TARGET_ELF): $(TARGET_OBJS)
|
$(TARGET_ELF): $(TARGET_OBJS)
|
||||||
$(V1) echo LD $(notdir $@)
|
$(V1) echo Linking $(TARGET)
|
||||||
$(V1) $(CC) -o $@ $^ $(LDFLAGS)
|
$(V1) $(CROSS_CC) -o $@ $^ $(LDFLAGS)
|
||||||
$(V0) $(SIZE) $(TARGET_ELF)
|
$(V0) $(SIZE) $(TARGET_ELF)
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
$(OBJECT_DIR)/$(TARGET)/%.o: %.c
|
$(OBJECT_DIR)/$(TARGET)/%.o: %.c
|
||||||
$(V1) mkdir -p $(dir $@)
|
$(V1) mkdir -p $(dir $@)
|
||||||
$(V1) echo %% $(notdir $<)
|
$(V1) echo "%% $(notdir $<)" "$(STDOUT)"
|
||||||
$(V1) $(CC) -c -o $@ $(CFLAGS) $<
|
$(V1) $(CROSS_CC) -c -o $@ $(CFLAGS) $<
|
||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
$(OBJECT_DIR)/$(TARGET)/%.o: %.s
|
$(OBJECT_DIR)/$(TARGET)/%.o: %.s
|
||||||
$(V1) mkdir -p $(dir $@)
|
$(V1) mkdir -p $(dir $@)
|
||||||
$(V1) echo %% $(notdir $<)
|
$(V1) echo "%% $(notdir $<)" "$(STDOUT)"
|
||||||
$(V1) $(CC) -c -o $@ $(ASFLAGS) $<
|
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
|
||||||
|
|
||||||
$(OBJECT_DIR)/$(TARGET)/%.o: %.S
|
$(OBJECT_DIR)/$(TARGET)/%.o: %.S
|
||||||
$(V1) mkdir -p $(dir $@)
|
$(V1) mkdir -p $(dir $@)
|
||||||
$(V1) echo %% $(notdir $<)
|
$(V1) echo "%% $(notdir $<)" "$(STDOUT)"
|
||||||
$(V1) $(CC) -c -o $@ $(ASFLAGS) $<
|
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
|
||||||
|
|
||||||
## sample : Build all sample (travis) targets
|
## sample : Build all sample (travis) targets
|
||||||
sample: $(SAMPLE_TARGETS)
|
sample: $(SAMPLE_TARGETS)
|
||||||
|
@ -940,7 +963,7 @@ targets:
|
||||||
## test : run the cleanflight test suite
|
## test : run the cleanflight test suite
|
||||||
## junittest : run the cleanflight test suite, producing Junit XML result files.
|
## junittest : run the cleanflight test suite, producing Junit XML result files.
|
||||||
test junittest:
|
test junittest:
|
||||||
$(V0) cd src/test && $(MAKE) $@ || true
|
$(V0) cd src/test && $(MAKE) $@
|
||||||
|
|
||||||
# rebuild everything when makefile changes
|
# rebuild everything when makefile changes
|
||||||
$(TARGET_OBJS) : Makefile
|
$(TARGET_OBJS) : Makefile
|
||||||
|
|
|
@ -475,6 +475,7 @@ __ALIGN_BEGIN uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIG
|
||||||
static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
||||||
uint8_t cfgidx)
|
uint8_t cfgidx)
|
||||||
{
|
{
|
||||||
|
(void)cfgidx;
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
USBD_CDC_HandleTypeDef *hcdc;
|
USBD_CDC_HandleTypeDef *hcdc;
|
||||||
|
|
||||||
|
@ -563,6 +564,7 @@ static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
|
||||||
static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
|
static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
|
||||||
uint8_t cfgidx)
|
uint8_t cfgidx)
|
||||||
{
|
{
|
||||||
|
(void)cfgidx;
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
|
|
||||||
/* Open EP IN */
|
/* Open EP IN */
|
||||||
|
@ -663,6 +665,7 @@ static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
|
||||||
*/
|
*/
|
||||||
static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
||||||
{
|
{
|
||||||
|
(void)epnum;
|
||||||
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
|
||||||
|
|
||||||
if(pdev->pClassData != NULL)
|
if(pdev->pClassData != NULL)
|
||||||
|
|
|
@ -212,6 +212,7 @@ USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev)
|
||||||
*/
|
*/
|
||||||
USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
|
USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
|
(void)pdev;
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,6 +509,8 @@ USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
|
||||||
*/
|
*/
|
||||||
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
||||||
{
|
{
|
||||||
|
(void)pdev;
|
||||||
|
(void)epnum;
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,6 +522,8 @@ USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t ep
|
||||||
*/
|
*/
|
||||||
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
||||||
{
|
{
|
||||||
|
(void)pdev;
|
||||||
|
(void)epnum;
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,6 +535,7 @@ USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t e
|
||||||
*/
|
*/
|
||||||
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
|
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
|
||||||
{
|
{
|
||||||
|
(void)pdev;
|
||||||
return USBD_OK;
|
return USBD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -716,6 +716,7 @@ void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
|
||||||
void USBD_CtlError( USBD_HandleTypeDef *pdev ,
|
void USBD_CtlError( USBD_HandleTypeDef *pdev ,
|
||||||
USBD_SetupReqTypedef *req)
|
USBD_SetupReqTypedef *req)
|
||||||
{
|
{
|
||||||
|
(void)req;
|
||||||
USBD_LL_StallEP(pdev , 0x80);
|
USBD_LL_StallEP(pdev , 0x80);
|
||||||
USBD_LL_StallEP(pdev , 0);
|
USBD_LL_StallEP(pdev , 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -756,6 +756,7 @@ HAL_StatusTypeDef HAL_ADCEx_MultiModeStop_DMA(ADC_HandleTypeDef* hadc)
|
||||||
*/
|
*/
|
||||||
uint32_t HAL_ADCEx_MultiModeGetValue(ADC_HandleTypeDef* hadc)
|
uint32_t HAL_ADCEx_MultiModeGetValue(ADC_HandleTypeDef* hadc)
|
||||||
{
|
{
|
||||||
|
(void)hadc;
|
||||||
/* Return the multi mode conversion value */
|
/* Return the multi mode conversion value */
|
||||||
return ADC->CDR;
|
return ADC->CDR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2845,6 +2845,7 @@ HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c)
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress)
|
HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress)
|
||||||
{
|
{
|
||||||
|
(void)DevAddress;
|
||||||
if(hi2c->Mode == HAL_I2C_MODE_MASTER)
|
if(hi2c->Mode == HAL_I2C_MODE_MASTER)
|
||||||
{
|
{
|
||||||
/* Process Locked */
|
/* Process Locked */
|
||||||
|
@ -3684,6 +3685,7 @@ static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t
|
||||||
*/
|
*/
|
||||||
static void I2C_ITAddrCplt(I2C_HandleTypeDef *hi2c, uint32_t ITFlags)
|
static void I2C_ITAddrCplt(I2C_HandleTypeDef *hi2c, uint32_t ITFlags)
|
||||||
{
|
{
|
||||||
|
(void)ITFlags;
|
||||||
uint8_t transferdirection = 0;
|
uint8_t transferdirection = 0;
|
||||||
uint16_t slaveaddrcode = 0;
|
uint16_t slaveaddrcode = 0;
|
||||||
uint16_t ownadd1code = 0;
|
uint16_t ownadd1code = 0;
|
||||||
|
@ -4254,6 +4256,7 @@ static void I2C_DMASlaveTransmitCplt(DMA_HandleTypeDef *hdma)
|
||||||
/* No specific action, Master fully manage the generation of STOP condition */
|
/* No specific action, Master fully manage the generation of STOP condition */
|
||||||
/* Mean that this generation can arrive at any time, at the end or during DMA process */
|
/* Mean that this generation can arrive at any time, at the end or during DMA process */
|
||||||
/* So STOP condition should be manage through Interrupt treatment */
|
/* So STOP condition should be manage through Interrupt treatment */
|
||||||
|
(void)hdma;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4308,6 +4311,7 @@ static void I2C_DMASlaveReceiveCplt(DMA_HandleTypeDef *hdma)
|
||||||
/* No specific action, Master fully manage the generation of STOP condition */
|
/* No specific action, Master fully manage the generation of STOP condition */
|
||||||
/* Mean that this generation can arrive at any time, at the end or during DMA process */
|
/* Mean that this generation can arrive at any time, at the end or during DMA process */
|
||||||
/* So STOP condition should be manage through Interrupt treatment */
|
/* So STOP condition should be manage through Interrupt treatment */
|
||||||
|
(void)hdma;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -404,6 +404,7 @@ void HAL_PWR_DisableWakeUpPin(uint32_t WakeUpPinx)
|
||||||
*/
|
*/
|
||||||
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
|
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
|
||||||
{
|
{
|
||||||
|
(void)Regulator;
|
||||||
/* Check the parameters */
|
/* Check the parameters */
|
||||||
assert_param(IS_PWR_REGULATOR(Regulator));
|
assert_param(IS_PWR_REGULATOR(Regulator));
|
||||||
assert_param(IS_PWR_SLEEP_ENTRY(SLEEPEntry));
|
assert_param(IS_PWR_SLEEP_ENTRY(SLEEPEntry));
|
||||||
|
|
|
@ -2118,7 +2118,7 @@ HAL_StatusTypeDef HAL_TIM_OnePulse_Start(TIM_HandleTypeDef *htim, uint32_t Outpu
|
||||||
|
|
||||||
No need to enable the counter, it's enabled automatically by hardware
|
No need to enable the counter, it's enabled automatically by hardware
|
||||||
(the counter starts in response to a stimulus and generate a pulse */
|
(the counter starts in response to a stimulus and generate a pulse */
|
||||||
|
(void)OutputChannel;
|
||||||
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
|
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
|
||||||
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
|
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);
|
||||||
|
|
||||||
|
@ -2150,6 +2150,7 @@ HAL_StatusTypeDef HAL_TIM_OnePulse_Stop(TIM_HandleTypeDef *htim, uint32_t Output
|
||||||
if TIM_CHANNEL_1 is used as input, the TIM_CHANNEL_2 will be used as output
|
if TIM_CHANNEL_1 is used as input, the TIM_CHANNEL_2 will be used as output
|
||||||
in all combinations, the TIM_CHANNEL_1 and TIM_CHANNEL_2 should be disabled together */
|
in all combinations, the TIM_CHANNEL_1 and TIM_CHANNEL_2 should be disabled together */
|
||||||
|
|
||||||
|
(void)OutputChannel;
|
||||||
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
|
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
|
||||||
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_DISABLE);
|
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_DISABLE);
|
||||||
|
|
||||||
|
@ -2187,6 +2188,7 @@ HAL_StatusTypeDef HAL_TIM_OnePulse_Start_IT(TIM_HandleTypeDef *htim, uint32_t Ou
|
||||||
No need to enable the counter, it's enabled automatically by hardware
|
No need to enable the counter, it's enabled automatically by hardware
|
||||||
(the counter starts in response to a stimulus and generate a pulse */
|
(the counter starts in response to a stimulus and generate a pulse */
|
||||||
|
|
||||||
|
(void)OutputChannel;
|
||||||
/* Enable the TIM Capture/Compare 1 interrupt */
|
/* Enable the TIM Capture/Compare 1 interrupt */
|
||||||
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
|
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
|
||||||
|
|
||||||
|
@ -2218,6 +2220,7 @@ HAL_StatusTypeDef HAL_TIM_OnePulse_Start_IT(TIM_HandleTypeDef *htim, uint32_t Ou
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef HAL_TIM_OnePulse_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
|
HAL_StatusTypeDef HAL_TIM_OnePulse_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
|
||||||
{
|
{
|
||||||
|
(void)OutputChannel;
|
||||||
/* Disable the TIM Capture/Compare 1 interrupt */
|
/* Disable the TIM Capture/Compare 1 interrupt */
|
||||||
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
|
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
|
||||||
|
|
||||||
|
|
|
@ -25,36 +25,47 @@ ARM_SDK_URL_BASE := https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update
|
||||||
|
|
||||||
# source: https://launchpad.net/gcc-arm-embedded/5.0/
|
# source: https://launchpad.net/gcc-arm-embedded/5.0/
|
||||||
ifdef LINUX
|
ifdef LINUX
|
||||||
arm_sdk_install: ARM_SDK_URL := $(ARM_SDK_URL_BASE)-linux.tar.bz2
|
ARM_SDK_URL := $(ARM_SDK_URL_BASE)-linux.tar.bz2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef MACOSX
|
ifdef MACOSX
|
||||||
arm_sdk_install: ARM_SDK_URL := $(ARM_SDK_URL_BASE)-mac.tar.bz2
|
ARM_SDK_URL := $(ARM_SDK_URL_BASE)-mac.tar.bz2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef WINDOWS
|
ifdef WINDOWS
|
||||||
arm_sdk_install: ARM_SDK_URL := $(ARM_SDK_URL_BASE)-win32.zip
|
ARM_SDK_URL := $(ARM_SDK_URL_BASE)-win32.zip
|
||||||
endif
|
endif
|
||||||
|
|
||||||
arm_sdk_install: ARM_SDK_FILE := $(notdir $(ARM_SDK_URL))
|
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)"
|
|
||||||
|
|
||||||
|
SDK_INSTALL_MARKER := $(ARM_SDK_DIR)/bin/arm-none-eabi-gcc-$(GCC_REQUIRED_VERSION)
|
||||||
|
|
||||||
|
# order-only prereq on directory existance:
|
||||||
|
arm_sdk_install: | $(TOOLS_DIR)
|
||||||
|
|
||||||
|
arm_sdk_install: arm_sdk_download $(SDK_INSTALL_MARKER)
|
||||||
|
|
||||||
|
$(SDK_INSTALL_MARKER):
|
||||||
|
ifneq ($(OSFAMILY), windows)
|
||||||
# binary only release so just extract it
|
# binary only release so just extract it
|
||||||
$(V1) tar -C $(TOOLS_DIR) -xjf "$(DL_DIR)/$(ARM_SDK_FILE)"
|
$(V1) tar -C $(TOOLS_DIR) -xjf "$(DL_DIR)/$(ARM_SDK_FILE)"
|
||||||
else
|
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)"
|
$(V1) unzip -q -d $(ARM_SDK_DIR) "$(DL_DIR)/$(ARM_SDK_FILE)"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
.PHONY: arm_sdk_download
|
||||||
|
arm_sdk_download: | $(DL_DIR)
|
||||||
|
arm_sdk_download: $(DL_DIR)/$(ARM_SDK_FILE)
|
||||||
|
$(DL_DIR)/$(ARM_SDK_FILE):
|
||||||
|
# download the source only if it's newer than what we already have
|
||||||
|
$(V1) curl -L -k -o "$(DL_DIR)/$(ARM_SDK_FILE)" -z "$(DL_DIR)/$(ARM_SDK_FILE)" "$(ARM_SDK_URL)"
|
||||||
|
|
||||||
|
|
||||||
## arm_sdk_clean : Uninstall Arm SDK
|
## arm_sdk_clean : Uninstall Arm SDK
|
||||||
.PHONY: arm_sdk_clean
|
.PHONY: arm_sdk_clean
|
||||||
arm_sdk_clean:
|
arm_sdk_clean:
|
||||||
$(V1) [ ! -d "$(ARM_SDK_DIR)" ] || $(RM) -r $(ARM_SDK_DIR)
|
$(V1) [ ! -d "$(ARM_SDK_DIR)" ] || $(RM) -r $(ARM_SDK_DIR)
|
||||||
|
$(V1) [ ! -d "$(DL_DIR)" ] || $(RM) -r $(DL_DIR)
|
||||||
|
|
||||||
.PHONY: openocd_win_install
|
.PHONY: openocd_win_install
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "drivers/sensor.h"
|
#include "drivers/sensor.h"
|
||||||
#include "drivers/compass.h"
|
#include "drivers/compass.h"
|
||||||
#include "drivers/system.h"
|
#include "drivers/system.h"
|
||||||
|
#include "drivers/pwm_output.h"
|
||||||
|
|
||||||
#include "fc/config.h"
|
#include "fc/config.h"
|
||||||
#include "fc/rc_controls.h"
|
#include "fc/rc_controls.h"
|
||||||
|
@ -895,7 +896,17 @@ void stopInTestMode(void)
|
||||||
*/
|
*/
|
||||||
bool inMotorTestMode(void) {
|
bool inMotorTestMode(void) {
|
||||||
static uint32_t resetTime = 0;
|
static uint32_t resetTime = 0;
|
||||||
uint16_t inactiveMotorCommand = (feature(FEATURE_3D) ? masterConfig.flight3DConfig.neutral3d : masterConfig.motorConfig.mincommand);
|
uint16_t inactiveMotorCommand;
|
||||||
|
if (feature(FEATURE_3D)) {
|
||||||
|
inactiveMotorCommand = masterConfig.flight3DConfig.neutral3d;
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
} else if (isMotorProtocolDshot()) {
|
||||||
|
inactiveMotorCommand = DSHOT_DISARM_COMMAND;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
inactiveMotorCommand = masterConfig.motorConfig.mincommand;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
bool atLeastOneMotorActivated = false;
|
bool atLeastOneMotorActivated = false;
|
||||||
|
|
||||||
|
@ -1158,7 +1169,7 @@ static bool blackboxWriteSysinfo()
|
||||||
|
|
||||||
switch (xmitState.headerIndex) {
|
switch (xmitState.headerIndex) {
|
||||||
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:%s %s (%s) %s", FC_FIRMWARE_NAME, 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("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);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FC_FIRMWARE_NAME "Betaflight"
|
||||||
#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 1 // 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
|
||||||
|
|
871
src/main/cms/cms.c
Normal file
871
src/main/cms/cms.c
Normal file
|
@ -0,0 +1,871 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Original OSD code created by Marcin Baliniak
|
||||||
|
OSD-CMS separation by jflyper
|
||||||
|
CMS-displayPort separation by jflyper and martinbudden
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define CMS_MENU_DEBUG // For external menu content creators
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "build/build_config.h"
|
||||||
|
#include "build/debug.h"
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_menu_builtin.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
|
||||||
|
#include "common/typeconversion.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
// For 'ARM' related
|
||||||
|
#include "fc/config.h"
|
||||||
|
#include "fc/rc_controls.h"
|
||||||
|
#include "fc/runtime_config.h"
|
||||||
|
|
||||||
|
// For rcData, stopAllMotors, stopPwmAllMotors
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
// For VISIBLE* (Actually, included by config_master.h)
|
||||||
|
#include "io/osd.h"
|
||||||
|
|
||||||
|
// DisplayPort management
|
||||||
|
|
||||||
|
#ifndef CMS_MAX_DEVICE
|
||||||
|
#define CMS_MAX_DEVICE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static displayPort_t *pCurrentDisplay;
|
||||||
|
|
||||||
|
static displayPort_t *cmsDisplayPorts[CMS_MAX_DEVICE];
|
||||||
|
static int cmsDeviceCount;
|
||||||
|
static int cmsCurrentDevice = -1;
|
||||||
|
|
||||||
|
bool cmsDisplayPortRegister(displayPort_t *pDisplay)
|
||||||
|
{
|
||||||
|
if (cmsDeviceCount == CMS_MAX_DEVICE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cmsDisplayPorts[cmsDeviceCount++] = pDisplay;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static displayPort_t *cmsDisplayPortSelectCurrent(void)
|
||||||
|
{
|
||||||
|
if (cmsDeviceCount == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (cmsCurrentDevice < 0)
|
||||||
|
cmsCurrentDevice = 0;
|
||||||
|
|
||||||
|
return cmsDisplayPorts[cmsCurrentDevice];
|
||||||
|
}
|
||||||
|
|
||||||
|
static displayPort_t *cmsDisplayPortSelectNext(void)
|
||||||
|
{
|
||||||
|
if (cmsDeviceCount == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cmsCurrentDevice = (cmsCurrentDevice + 1) % cmsDeviceCount; // -1 Okay
|
||||||
|
|
||||||
|
return cmsDisplayPorts[cmsCurrentDevice];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CMS_UPDATE_INTERVAL_US 50000 // Interval of key scans (microsec)
|
||||||
|
#define CMS_POLL_INTERVAL_US 100000 // Interval of polling dynamic values (microsec)
|
||||||
|
|
||||||
|
// XXX LEFT_MENU_COLUMN and RIGHT_MENU_COLUMN must be adjusted
|
||||||
|
// dynamically depending on size of the active output device,
|
||||||
|
// or statically to accomodate sizes of all supported devices.
|
||||||
|
//
|
||||||
|
// Device characteristics
|
||||||
|
// OLED
|
||||||
|
// 21 cols x 8 rows
|
||||||
|
// 128x64 with 5x7 (6x8) : 21 cols x 8 rows
|
||||||
|
// MAX7456 (PAL)
|
||||||
|
// 30 cols x 16 rows
|
||||||
|
// MAX7456 (NTSC)
|
||||||
|
// 30 cols x 13 rows
|
||||||
|
// HoTT Telemetry Screen
|
||||||
|
// 21 cols x 8 rows
|
||||||
|
//
|
||||||
|
|
||||||
|
#define LEFT_MENU_COLUMN 1
|
||||||
|
#define RIGHT_MENU_COLUMN(p) ((p)->cols - 8)
|
||||||
|
#define MAX_MENU_ITEMS(p) ((p)->rows - 2)
|
||||||
|
|
||||||
|
static bool cmsInMenu = false;
|
||||||
|
|
||||||
|
STATIC_UNIT_TESTED const CMS_Menu *currentMenu; // Points to top entry of the current page
|
||||||
|
|
||||||
|
// XXX Does menu backing support backing into second page???
|
||||||
|
|
||||||
|
static const CMS_Menu *menuStack[10]; // Stack to save menu transition
|
||||||
|
static uint8_t menuStackHistory[10];// cursorRow in a stacked menu
|
||||||
|
static uint8_t menuStackIdx = 0;
|
||||||
|
|
||||||
|
static OSD_Entry *pageTop; // Points to top entry of the current page
|
||||||
|
static OSD_Entry *pageTopAlt; // Only 2 pages are allowed (for now)
|
||||||
|
static uint8_t maxRow; // Max row in the current page
|
||||||
|
|
||||||
|
static int8_t cursorRow;
|
||||||
|
|
||||||
|
#ifdef CMS_MENU_DEBUG // For external menu content creators
|
||||||
|
|
||||||
|
static char menuErrLabel[21 + 1] = "RANDOM DATA";
|
||||||
|
|
||||||
|
static OSD_Entry menuErrEntries[] = {
|
||||||
|
{ "BROKEN MENU", OME_Label, NULL, NULL, 0 },
|
||||||
|
{ menuErrLabel, OME_Label, NULL, NULL, 0 },
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu menuErr = {
|
||||||
|
"MENUERR",
|
||||||
|
OME_MENU,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
menuErrEntries,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Stick/key detection
|
||||||
|
|
||||||
|
#define IS_HI(X) (rcData[X] > 1750)
|
||||||
|
#define IS_LO(X) (rcData[X] < 1250)
|
||||||
|
#define IS_MID(X) (rcData[X] > 1250 && rcData[X] < 1750)
|
||||||
|
|
||||||
|
//key definiotion because API provide menu navigation over MSP/GUI app - not used NOW
|
||||||
|
#define KEY_ENTER 0
|
||||||
|
#define KEY_UP 1
|
||||||
|
#define KEY_DOWN 2
|
||||||
|
#define KEY_LEFT 3
|
||||||
|
#define KEY_RIGHT 4
|
||||||
|
#define KEY_ESC 5
|
||||||
|
|
||||||
|
#define BUTTON_TIME 250 // msec
|
||||||
|
#define BUTTON_PAUSE 500 // msec
|
||||||
|
|
||||||
|
static void cmsUpdateMaxRow(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
maxRow = 0;
|
||||||
|
|
||||||
|
for (const OSD_Entry *ptr = pageTop; ptr->type != OME_END; ptr++) {
|
||||||
|
maxRow++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxRow > MAX_MENU_ITEMS(instance)) {
|
||||||
|
maxRow = MAX_MENU_ITEMS(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
maxRow--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsFormatFloat(int32_t value, char *floatString)
|
||||||
|
{
|
||||||
|
uint8_t k;
|
||||||
|
// np. 3450
|
||||||
|
|
||||||
|
itoa(100000 + value, floatString, 10); // Create string from abs of integer value
|
||||||
|
|
||||||
|
// 103450
|
||||||
|
|
||||||
|
floatString[0] = floatString[1];
|
||||||
|
floatString[1] = floatString[2];
|
||||||
|
floatString[2] = '.';
|
||||||
|
|
||||||
|
// 03.450
|
||||||
|
// usuwam koncowe zera i kropke
|
||||||
|
// Keep the first decimal place
|
||||||
|
for (k = 5; k > 3; k--)
|
||||||
|
if (floatString[k] == '0' || floatString[k] == '.')
|
||||||
|
floatString[k] = 0;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
// oraz zero wiodonce
|
||||||
|
if (floatString[0] == '0')
|
||||||
|
floatString[0] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsPadToSize(char *buf, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < size ; i++) {
|
||||||
|
if (buf[i] == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; i < size ; i++) {
|
||||||
|
buf[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmsDrawMenuEntry(displayPort_t *pDisplay, OSD_Entry *p, uint8_t row)
|
||||||
|
{
|
||||||
|
char buff[10];
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
switch (p->type) {
|
||||||
|
case OME_String:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, p->data);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_Submenu:
|
||||||
|
case OME_Funcall:
|
||||||
|
if (IS_PRINTVALUE(p)) {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, ">");
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_Bool:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
if (*((uint8_t *)(p->data))) {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "YES");
|
||||||
|
} else {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "NO ");
|
||||||
|
}
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_TAB: {
|
||||||
|
if (IS_PRINTVALUE(p)) {
|
||||||
|
OSD_TAB_t *ptr = p->data;
|
||||||
|
//cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay) - 5, row, (char *)ptr->names[*ptr->val]);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, (char *)ptr->names[*ptr->val]);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef OSD
|
||||||
|
case OME_VISIBLE:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
uint32_t address = (uint32_t)p->data;
|
||||||
|
uint16_t *val;
|
||||||
|
|
||||||
|
val = (uint16_t *)address;
|
||||||
|
|
||||||
|
if (VISIBLE(*val)) {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "YES");
|
||||||
|
} else {
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "NO ");
|
||||||
|
}
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case OME_UINT8:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
OSD_UINT8_t *ptr = p->data;
|
||||||
|
itoa(*ptr->val, buff, 10);
|
||||||
|
cmsPadToSize(buff, 5);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, buff);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_INT8:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
OSD_INT8_t *ptr = p->data;
|
||||||
|
itoa(*ptr->val, buff, 10);
|
||||||
|
cmsPadToSize(buff, 5);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, buff);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_UINT16:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
OSD_UINT16_t *ptr = p->data;
|
||||||
|
itoa(*ptr->val, buff, 10);
|
||||||
|
cmsPadToSize(buff, 5);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, buff);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_INT16:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
OSD_UINT16_t *ptr = p->data;
|
||||||
|
itoa(*ptr->val, buff, 10);
|
||||||
|
cmsPadToSize(buff, 5);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, buff);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_FLOAT:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
OSD_FLOAT_t *ptr = p->data;
|
||||||
|
cmsFormatFloat(*ptr->val * ptr->multipler, buff);
|
||||||
|
cmsPadToSize(buff, 5);
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay) - 1, row, buff); // XXX One char left ???
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_Label:
|
||||||
|
if (IS_PRINTVALUE(p) && p->data) {
|
||||||
|
// A label with optional string, immediately following text
|
||||||
|
cnt = displayWrite(pDisplay, LEFT_MENU_COLUMN + 2 + strlen(p->text), row, p->data);
|
||||||
|
CLR_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_OSD_Exit:
|
||||||
|
case OME_END:
|
||||||
|
case OME_Back:
|
||||||
|
break;
|
||||||
|
case OME_MENU:
|
||||||
|
// Fall through
|
||||||
|
default:
|
||||||
|
#ifdef CMS_MENU_DEBUG
|
||||||
|
// Shouldn't happen. Notify creator of this menu content.
|
||||||
|
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "BADENT");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs)
|
||||||
|
{
|
||||||
|
if (!pageTop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t i;
|
||||||
|
OSD_Entry *p;
|
||||||
|
uint8_t top = (pDisplay->rows - maxRow) / 2 - 1;
|
||||||
|
|
||||||
|
// Polled (dynamic) value display denominator.
|
||||||
|
|
||||||
|
bool drawPolled = false;
|
||||||
|
static uint32_t lastPolledUs = 0;
|
||||||
|
|
||||||
|
if (currentTimeUs > lastPolledUs + CMS_POLL_INTERVAL_US) {
|
||||||
|
drawPolled = true;
|
||||||
|
lastPolledUs = currentTimeUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t room = displayTxBytesFree(pDisplay);
|
||||||
|
|
||||||
|
if (pDisplay->cleared) {
|
||||||
|
for (p = pageTop, i= 0; p->type != OME_END; p++, i++) {
|
||||||
|
SET_PRINTLABEL(p);
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > MAX_MENU_ITEMS(pDisplay)) // max per page
|
||||||
|
{
|
||||||
|
pageTopAlt = pageTop + MAX_MENU_ITEMS(pDisplay);
|
||||||
|
if (pageTopAlt->type == OME_END)
|
||||||
|
pageTopAlt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDisplay->cleared = false;
|
||||||
|
} else if (drawPolled) {
|
||||||
|
for (p = pageTop ; p <= pageTop + maxRow ; p++) {
|
||||||
|
if (IS_DYNAMIC(p))
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cursor manipulation
|
||||||
|
|
||||||
|
while ((pageTop + cursorRow)->type == OME_Label) // skip label
|
||||||
|
cursorRow++;
|
||||||
|
|
||||||
|
if (pDisplay->cursorRow >= 0 && cursorRow != pDisplay->cursorRow) {
|
||||||
|
room -= displayWrite(pDisplay, LEFT_MENU_COLUMN, pDisplay->cursorRow + top, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (room < 30)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pDisplay->cursorRow != cursorRow) {
|
||||||
|
room -= displayWrite(pDisplay, LEFT_MENU_COLUMN, cursorRow + top, " >");
|
||||||
|
pDisplay->cursorRow = cursorRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (room < 30)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Print text labels
|
||||||
|
for (i = 0, p = pageTop; i < MAX_MENU_ITEMS(pDisplay) && p->type != OME_END; i++, p++) {
|
||||||
|
if (IS_PRINTLABEL(p)) {
|
||||||
|
uint8_t coloff = LEFT_MENU_COLUMN;
|
||||||
|
coloff += (p->type == OME_Label) ? 1 : 2;
|
||||||
|
room -= displayWrite(pDisplay, coloff, i + top, p->text);
|
||||||
|
CLR_PRINTLABEL(p);
|
||||||
|
if (room < 30)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print values
|
||||||
|
|
||||||
|
// XXX Polled values at latter positions in the list may not be
|
||||||
|
// XXX printed if not enough room in the middle of the list.
|
||||||
|
|
||||||
|
for (i = 0, p = pageTop; i < MAX_MENU_ITEMS(pDisplay) && p->type != OME_END; i++, p++) {
|
||||||
|
if (IS_PRINTVALUE(p)) {
|
||||||
|
room -= cmsDrawMenuEntry(pDisplay, p, top + i);
|
||||||
|
if (room < 30)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long cmsMenuChange(displayPort_t *pDisplay, const void *ptr)
|
||||||
|
{
|
||||||
|
CMS_Menu *pMenu = (CMS_Menu *)ptr;
|
||||||
|
|
||||||
|
if (pMenu) {
|
||||||
|
#ifdef CMS_MENU_DEBUG
|
||||||
|
if (pMenu->GUARD_type != OME_MENU) {
|
||||||
|
// ptr isn't pointing to a CMS_Menu.
|
||||||
|
if (pMenu->GUARD_type <= OME_MAX) {
|
||||||
|
strncpy(menuErrLabel, pMenu->GUARD_text, sizeof(menuErrLabel) - 1);
|
||||||
|
} else {
|
||||||
|
strncpy(menuErrLabel, "LABEL UNKNOWN", sizeof(menuErrLabel) - 1);
|
||||||
|
}
|
||||||
|
pMenu = &menuErr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Stack the current menu and move to a new menu.
|
||||||
|
// The (pMenu == curretMenu) case occurs when reopening for display sw
|
||||||
|
|
||||||
|
if (pMenu != currentMenu) {
|
||||||
|
menuStack[menuStackIdx] = currentMenu;
|
||||||
|
cursorRow += pageTop - currentMenu->entries; // Convert cursorRow to absolute value
|
||||||
|
menuStackHistory[menuStackIdx] = cursorRow;
|
||||||
|
menuStackIdx++;
|
||||||
|
|
||||||
|
currentMenu = pMenu;
|
||||||
|
cursorRow = 0;
|
||||||
|
|
||||||
|
if (pMenu->onEnter)
|
||||||
|
pMenu->onEnter();
|
||||||
|
}
|
||||||
|
|
||||||
|
pageTop = currentMenu->entries;
|
||||||
|
pageTopAlt = NULL;
|
||||||
|
|
||||||
|
displayClear(pDisplay);
|
||||||
|
cmsUpdateMaxRow(pDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_UNIT_TESTED long cmsMenuBack(displayPort_t *pDisplay)
|
||||||
|
{
|
||||||
|
// Let onExit function decide whether to allow exit or not.
|
||||||
|
|
||||||
|
if (currentMenu->onExit && currentMenu->onExit(pageTop + cursorRow) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (menuStackIdx) {
|
||||||
|
displayClear(pDisplay);
|
||||||
|
menuStackIdx--;
|
||||||
|
currentMenu = menuStack[menuStackIdx];
|
||||||
|
cursorRow = menuStackHistory[menuStackIdx];
|
||||||
|
|
||||||
|
// cursorRow is absolute offset of a focused entry when stacked.
|
||||||
|
// Convert it back to page and relative offset.
|
||||||
|
|
||||||
|
pageTop = currentMenu->entries; // Temporary for cmsUpdateMaxRow()
|
||||||
|
cmsUpdateMaxRow(pDisplay);
|
||||||
|
|
||||||
|
if (cursorRow > maxRow) {
|
||||||
|
// Cursor was in the second page.
|
||||||
|
pageTopAlt = currentMenu->entries;
|
||||||
|
pageTop = pageTopAlt + maxRow + 1;
|
||||||
|
cursorRow -= (maxRow + 1);
|
||||||
|
cmsUpdateMaxRow(pDisplay); // Update maxRow for the second page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_UNIT_TESTED void cmsMenuOpen(void)
|
||||||
|
{
|
||||||
|
if (!cmsInMenu) {
|
||||||
|
// New open
|
||||||
|
pCurrentDisplay = cmsDisplayPortSelectCurrent();
|
||||||
|
if (!pCurrentDisplay)
|
||||||
|
return;
|
||||||
|
cmsInMenu = true;
|
||||||
|
currentMenu = &menuMain;
|
||||||
|
DISABLE_ARMING_FLAG(OK_TO_ARM);
|
||||||
|
} else {
|
||||||
|
// Switch display
|
||||||
|
displayPort_t *pNextDisplay = cmsDisplayPortSelectNext();
|
||||||
|
if (pNextDisplay != pCurrentDisplay) {
|
||||||
|
displayRelease(pCurrentDisplay);
|
||||||
|
pCurrentDisplay = pNextDisplay;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayGrab(pCurrentDisplay); // grab the display for use by the CMS
|
||||||
|
cmsMenuChange(pCurrentDisplay, currentMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsTraverseGlobalExit(const CMS_Menu *pMenu)
|
||||||
|
{
|
||||||
|
debug[0]++;
|
||||||
|
|
||||||
|
for (const OSD_Entry *p = pMenu->entries; p->type != OME_END ; p++) {
|
||||||
|
if (p->type == OME_Submenu) {
|
||||||
|
cmsTraverseGlobalExit(p->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pMenu->onGlobalExit) {
|
||||||
|
debug[1]++;
|
||||||
|
pMenu->onGlobalExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long cmsMenuExit(displayPort_t *pDisplay, const void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr) {
|
||||||
|
displayClear(pDisplay);
|
||||||
|
|
||||||
|
displayWrite(pDisplay, 5, 3, "REBOOTING...");
|
||||||
|
displayResync(pDisplay); // Was max7456RefreshAll(); why at this timing?
|
||||||
|
|
||||||
|
stopMotors();
|
||||||
|
stopPwmAllMotors();
|
||||||
|
delay(200);
|
||||||
|
|
||||||
|
cmsTraverseGlobalExit(&menuMain);
|
||||||
|
|
||||||
|
if (currentMenu->onExit)
|
||||||
|
currentMenu->onExit((OSD_Entry *)NULL); // Forced exit
|
||||||
|
|
||||||
|
saveConfigAndNotify();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsInMenu = false;
|
||||||
|
|
||||||
|
displayRelease(pDisplay);
|
||||||
|
currentMenu = NULL;
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
systemReset();
|
||||||
|
|
||||||
|
ENABLE_ARMING_FLAG(OK_TO_ARM);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_UNIT_TESTED uint16_t cmsHandleKey(displayPort_t *pDisplay, uint8_t key)
|
||||||
|
{
|
||||||
|
uint16_t res = BUTTON_TIME;
|
||||||
|
OSD_Entry *p;
|
||||||
|
|
||||||
|
if (!currentMenu)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (key == KEY_ESC) {
|
||||||
|
cmsMenuBack(pDisplay);
|
||||||
|
return BUTTON_PAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == KEY_DOWN) {
|
||||||
|
if (cursorRow < maxRow) {
|
||||||
|
cursorRow++;
|
||||||
|
} else {
|
||||||
|
if (pageTopAlt) { // we have another page
|
||||||
|
displayClear(pDisplay);
|
||||||
|
p = pageTopAlt;
|
||||||
|
pageTopAlt = pageTop;
|
||||||
|
pageTop = (OSD_Entry *)p;
|
||||||
|
cmsUpdateMaxRow(pDisplay);
|
||||||
|
}
|
||||||
|
cursorRow = 0; // Goto top in any case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == KEY_UP) {
|
||||||
|
cursorRow--;
|
||||||
|
|
||||||
|
if ((pageTop + cursorRow)->type == OME_Label && cursorRow > 0)
|
||||||
|
cursorRow--;
|
||||||
|
|
||||||
|
if (cursorRow == -1 || (pageTop + cursorRow)->type == OME_Label) {
|
||||||
|
if (pageTopAlt) {
|
||||||
|
displayClear(pDisplay);
|
||||||
|
p = pageTopAlt;
|
||||||
|
pageTopAlt = pageTop;
|
||||||
|
pageTop = (OSD_Entry *)p;
|
||||||
|
cmsUpdateMaxRow(pDisplay);
|
||||||
|
}
|
||||||
|
cursorRow = maxRow; // Goto bottom in any case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == KEY_DOWN || key == KEY_UP)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
p = pageTop + cursorRow;
|
||||||
|
|
||||||
|
switch (p->type) {
|
||||||
|
case OME_Submenu:
|
||||||
|
case OME_Funcall:
|
||||||
|
case OME_OSD_Exit:
|
||||||
|
if (p->func && key == KEY_RIGHT) {
|
||||||
|
p->func(pDisplay, p->data);
|
||||||
|
res = BUTTON_PAUSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_Back:
|
||||||
|
cmsMenuBack(pDisplay);
|
||||||
|
res = BUTTON_PAUSE;
|
||||||
|
break;
|
||||||
|
case OME_Bool:
|
||||||
|
if (p->data) {
|
||||||
|
uint8_t *val = p->data;
|
||||||
|
if (key == KEY_RIGHT)
|
||||||
|
*val = 1;
|
||||||
|
else
|
||||||
|
*val = 0;
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef OSD
|
||||||
|
case OME_VISIBLE:
|
||||||
|
if (p->data) {
|
||||||
|
uint32_t address = (uint32_t)p->data;
|
||||||
|
uint16_t *val;
|
||||||
|
|
||||||
|
val = (uint16_t *)address;
|
||||||
|
|
||||||
|
if (key == KEY_RIGHT)
|
||||||
|
*val |= VISIBLE_FLAG;
|
||||||
|
else
|
||||||
|
*val %= ~VISIBLE_FLAG;
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case OME_UINT8:
|
||||||
|
case OME_FLOAT:
|
||||||
|
if (p->data) {
|
||||||
|
OSD_UINT8_t *ptr = p->data;
|
||||||
|
if (key == KEY_RIGHT) {
|
||||||
|
if (*ptr->val < ptr->max)
|
||||||
|
*ptr->val += ptr->step;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*ptr->val > ptr->min)
|
||||||
|
*ptr->val -= ptr->step;
|
||||||
|
}
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
if (p->func) {
|
||||||
|
p->func(pDisplay, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_TAB:
|
||||||
|
if (p->type == OME_TAB) {
|
||||||
|
OSD_TAB_t *ptr = p->data;
|
||||||
|
|
||||||
|
if (key == KEY_RIGHT) {
|
||||||
|
if (*ptr->val < ptr->max)
|
||||||
|
*ptr->val += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*ptr->val > 0)
|
||||||
|
*ptr->val -= 1;
|
||||||
|
}
|
||||||
|
if (p->func)
|
||||||
|
p->func(pDisplay, p->data);
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_INT8:
|
||||||
|
if (p->data) {
|
||||||
|
OSD_INT8_t *ptr = p->data;
|
||||||
|
if (key == KEY_RIGHT) {
|
||||||
|
if (*ptr->val < ptr->max)
|
||||||
|
*ptr->val += ptr->step;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*ptr->val > ptr->min)
|
||||||
|
*ptr->val -= ptr->step;
|
||||||
|
}
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
if (p->func) {
|
||||||
|
p->func(pDisplay, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_UINT16:
|
||||||
|
if (p->data) {
|
||||||
|
OSD_UINT16_t *ptr = p->data;
|
||||||
|
if (key == KEY_RIGHT) {
|
||||||
|
if (*ptr->val < ptr->max)
|
||||||
|
*ptr->val += ptr->step;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*ptr->val > ptr->min)
|
||||||
|
*ptr->val -= ptr->step;
|
||||||
|
}
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
if (p->func) {
|
||||||
|
p->func(pDisplay, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_INT16:
|
||||||
|
if (p->data) {
|
||||||
|
OSD_INT16_t *ptr = p->data;
|
||||||
|
if (key == KEY_RIGHT) {
|
||||||
|
if (*ptr->val < ptr->max)
|
||||||
|
*ptr->val += ptr->step;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*ptr->val > ptr->min)
|
||||||
|
*ptr->val -= ptr->step;
|
||||||
|
}
|
||||||
|
SET_PRINTVALUE(p);
|
||||||
|
if (p->func) {
|
||||||
|
p->func(pDisplay, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OME_String:
|
||||||
|
break;
|
||||||
|
case OME_Label:
|
||||||
|
case OME_END:
|
||||||
|
break;
|
||||||
|
case OME_MENU:
|
||||||
|
// Shouldn't happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsUpdate(uint32_t currentTimeUs)
|
||||||
|
{
|
||||||
|
static int16_t rcDelayMs = BUTTON_TIME;
|
||||||
|
static uint32_t lastCalledMs = 0;
|
||||||
|
static uint32_t lastCmsHeartBeatMs = 0;
|
||||||
|
|
||||||
|
const uint32_t currentTimeMs = currentTimeUs / 1000;
|
||||||
|
|
||||||
|
if (!cmsInMenu) {
|
||||||
|
// Detect menu invocation
|
||||||
|
if (IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) && !ARMING_FLAG(ARMED)) {
|
||||||
|
cmsMenuOpen();
|
||||||
|
rcDelayMs = BUTTON_PAUSE; // Tends to overshoot if BUTTON_TIME
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t key = 0;
|
||||||
|
if (rcDelayMs > 0) {
|
||||||
|
rcDelayMs -= (currentTimeMs - lastCalledMs);
|
||||||
|
}
|
||||||
|
else if (IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) && !ARMING_FLAG(ARMED)) {
|
||||||
|
// Double enter = display switching
|
||||||
|
cmsMenuOpen();
|
||||||
|
rcDelayMs = BUTTON_PAUSE;
|
||||||
|
}
|
||||||
|
else if (IS_HI(PITCH)) {
|
||||||
|
key = KEY_UP;
|
||||||
|
rcDelayMs = BUTTON_TIME;
|
||||||
|
}
|
||||||
|
else if (IS_LO(PITCH)) {
|
||||||
|
key = KEY_DOWN;
|
||||||
|
rcDelayMs = BUTTON_TIME;
|
||||||
|
}
|
||||||
|
else if (IS_LO(ROLL)) {
|
||||||
|
key = KEY_LEFT;
|
||||||
|
rcDelayMs = BUTTON_TIME;
|
||||||
|
}
|
||||||
|
else if (IS_HI(ROLL)) {
|
||||||
|
key = KEY_RIGHT;
|
||||||
|
rcDelayMs = BUTTON_TIME;
|
||||||
|
}
|
||||||
|
else if (IS_HI(YAW) || IS_LO(YAW))
|
||||||
|
{
|
||||||
|
key = KEY_ESC;
|
||||||
|
rcDelayMs = BUTTON_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
//lastCalled = currentTime;
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
rcDelayMs = cmsHandleKey(pCurrentDisplay, key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsDrawMenu(pCurrentDisplay, currentTimeUs);
|
||||||
|
|
||||||
|
if (currentTimeMs > lastCmsHeartBeatMs + 500) {
|
||||||
|
// Heart beat for external CMS display device @ 500msec
|
||||||
|
// (Timeout @ 1000msec)
|
||||||
|
displayHeartbeat(pCurrentDisplay);
|
||||||
|
lastCmsHeartBeatMs = currentTimeMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastCalledMs = currentTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmsHandler(uint32_t currentTime)
|
||||||
|
{
|
||||||
|
if (cmsDeviceCount < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static uint32_t lastCalled = 0;
|
||||||
|
|
||||||
|
if (currentTime >= lastCalled + CMS_UPDATE_INTERVAL_US) {
|
||||||
|
lastCalled = currentTime;
|
||||||
|
cmsUpdate(currentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is initializing with menuMain better?
|
||||||
|
// Can it be done with the current main()?
|
||||||
|
void cmsInit(void)
|
||||||
|
{
|
||||||
|
cmsDeviceCount = 0;
|
||||||
|
cmsCurrentDevice = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CMS
|
17
src/main/cms/cms.h
Normal file
17
src/main/cms/cms.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "drivers/display.h"
|
||||||
|
|
||||||
|
// Device management
|
||||||
|
bool cmsDisplayPortRegister(displayPort_t *pDisplay);
|
||||||
|
|
||||||
|
// For main.c and scheduler
|
||||||
|
void cmsInit(void);
|
||||||
|
void cmsHandler(uint32_t currentTime);
|
||||||
|
|
||||||
|
long cmsMenuChange(displayPort_t *pPort, const void *ptr);
|
||||||
|
long cmsMenuExit(displayPort_t *pPort, const void *ptr);
|
||||||
|
|
||||||
|
#define CMS_STARTUP_HELP_TEXT1 "MENU: THR MID"
|
||||||
|
#define CMS_STARTUP_HELP_TEXT2 "+ YAW LEFT"
|
||||||
|
#define CMS_STARTUP_HELP_TEXT3 "+ PITCH UP"
|
111
src/main/cms/cms_menu_blackbox.c
Normal file
111
src/main/cms/cms_menu_blackbox.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMS things for blackbox and flashfs.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_blackbox.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
#include "io/flashfs.h"
|
||||||
|
|
||||||
|
#ifdef USE_FLASHFS
|
||||||
|
static long cmsx_EraseFlash(displayPort_t *pDisplay, const void *ptr)
|
||||||
|
{
|
||||||
|
UNUSED(ptr);
|
||||||
|
|
||||||
|
displayClear(pDisplay);
|
||||||
|
displayWrite(pDisplay, 5, 3, "ERASING FLASH...");
|
||||||
|
displayResync(pDisplay); // Was max7456RefreshAll(); Why at this timing?
|
||||||
|
|
||||||
|
flashfsEraseCompletely();
|
||||||
|
while (!flashfsIsReady()) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayClear(pDisplay);
|
||||||
|
displayResync(pDisplay); // Was max7456RefreshAll(); wedges during heavy SPI?
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // USE_FLASHFS
|
||||||
|
|
||||||
|
static bool featureRead = false;
|
||||||
|
static uint8_t cmsx_FeatureBlackbox;
|
||||||
|
|
||||||
|
static long cmsx_Blackbox_FeatureRead(void)
|
||||||
|
{
|
||||||
|
if (!featureRead) {
|
||||||
|
cmsx_FeatureBlackbox = feature(FEATURE_BLACKBOX) ? 1 : 0;
|
||||||
|
featureRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_Blackbox_FeatureWriteback(void)
|
||||||
|
{
|
||||||
|
if (cmsx_FeatureBlackbox)
|
||||||
|
featureSet(FEATURE_BLACKBOX);
|
||||||
|
else
|
||||||
|
featureClear(FEATURE_BLACKBOX);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuBlackboxEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- BLACKBOX --", OME_Label, NULL, NULL, 0},
|
||||||
|
{ "ENABLED", OME_Bool, NULL, &cmsx_FeatureBlackbox, 0 },
|
||||||
|
{ "RATE DENOM", OME_UINT8, NULL, &(OSD_UINT8_t){ &masterConfig.blackbox_rate_denom,1,32,1 }, 0 },
|
||||||
|
|
||||||
|
#ifdef USE_FLASHFS
|
||||||
|
{ "ERASE FLASH", OME_Funcall, cmsx_EraseFlash, NULL, 0 },
|
||||||
|
#endif // USE_FLASHFS
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuBlackbox = {
|
||||||
|
.GUARD_text = "MENUBB",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_Blackbox_FeatureRead,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = cmsx_Blackbox_FeatureWriteback,
|
||||||
|
.entries = cmsx_menuBlackboxEntries
|
||||||
|
};
|
||||||
|
#endif
|
20
src/main/cms/cms_menu_blackbox.h
Normal file
20
src/main/cms/cms_menu_blackbox.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuBlackbox;
|
143
src/main/cms/cms_menu_builtin.c
Normal file
143
src/main/cms/cms_menu_builtin.c
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Built-in menu contents and support functions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_builtin.h"
|
||||||
|
|
||||||
|
// Sub menus
|
||||||
|
|
||||||
|
#include "cms/cms_menu_imu.h"
|
||||||
|
#include "cms/cms_menu_blackbox.h"
|
||||||
|
#include "cms/cms_menu_vtx.h"
|
||||||
|
#include "cms/cms_menu_osd.h"
|
||||||
|
#include "cms/cms_menu_ledstrip.h"
|
||||||
|
#include "cms/cms_menu_misc.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Info
|
||||||
|
|
||||||
|
static char infoGitRev[GIT_SHORT_REVISION_LENGTH];
|
||||||
|
static char infoTargetName[] = __TARGET__;
|
||||||
|
|
||||||
|
#include "msp/msp_protocol.h" // XXX for FC identification... not available elsewhere
|
||||||
|
|
||||||
|
static long cmsx_InfoInit(void)
|
||||||
|
{
|
||||||
|
for (int i = 0 ; i < GIT_SHORT_REVISION_LENGTH ; i++) {
|
||||||
|
if (shortGitRevision[i] >= 'a' && shortGitRevision[i] <= 'f')
|
||||||
|
infoGitRev[i] = shortGitRevision[i] - 'a' + 'A';
|
||||||
|
else
|
||||||
|
infoGitRev[i] = shortGitRevision[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry menuInfoEntries[] = {
|
||||||
|
{ "--- INFO ---", OME_Label, NULL, NULL, 0 },
|
||||||
|
{ "FWID", OME_String, NULL, BETAFLIGHT_IDENTIFIER, 0 },
|
||||||
|
{ "FWVER", OME_String, NULL, FC_VERSION_STRING, 0 },
|
||||||
|
{ "GITREV", OME_String, NULL, infoGitRev, 0 },
|
||||||
|
{ "TARGET", OME_String, NULL, infoTargetName, 0 },
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu menuInfo = {
|
||||||
|
.GUARD_text = "MENUINFO",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_InfoInit,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = menuInfoEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
// Features
|
||||||
|
|
||||||
|
static OSD_Entry menuFeaturesEntries[] =
|
||||||
|
{
|
||||||
|
{"--- FEATURES ---", OME_Label, NULL, NULL, 0},
|
||||||
|
{"BLACKBOX", OME_Submenu, cmsMenuChange, &cmsx_menuBlackbox, 0},
|
||||||
|
#if defined(VTX) || defined(USE_RTC6705)
|
||||||
|
{"VTX", OME_Submenu, cmsMenuChange, &cmsx_menuVtx, 0},
|
||||||
|
#endif // VTX || USE_RTC6705
|
||||||
|
#ifdef LED_STRIP
|
||||||
|
{"LED STRIP", OME_Submenu, cmsMenuChange, &cmsx_menuLedstrip, 0},
|
||||||
|
#endif // LED_STRIP
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu menuFeatures = {
|
||||||
|
.GUARD_text = "MENUFEATURES",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = menuFeaturesEntries,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main
|
||||||
|
|
||||||
|
static OSD_Entry menuMainEntries[] =
|
||||||
|
{
|
||||||
|
{"-- MAIN --", OME_Label, NULL, NULL, 0},
|
||||||
|
|
||||||
|
{"PROFILE", OME_Submenu, cmsMenuChange, &cmsx_menuImu, 0},
|
||||||
|
{"FEATURES", OME_Submenu, cmsMenuChange, &menuFeatures, 0},
|
||||||
|
#ifdef OSD
|
||||||
|
{"SCR LAYOUT", OME_Submenu, cmsMenuChange, &cmsx_menuOsdLayout, 0},
|
||||||
|
{"ALARMS", OME_Submenu, cmsMenuChange, &cmsx_menuAlarms, 0},
|
||||||
|
#endif
|
||||||
|
{"FC&FW INFO", OME_Submenu, cmsMenuChange, &menuInfo, 0},
|
||||||
|
{"MISC", OME_Submenu, cmsMenuChange, &cmsx_menuMisc, 0},
|
||||||
|
{"SAVE&REBOOT", OME_OSD_Exit, cmsMenuExit, (void*)1, 0},
|
||||||
|
{"EXIT", OME_OSD_Exit, cmsMenuExit, (void*)0, 0},
|
||||||
|
#ifdef CMS_MENU_DEBUG
|
||||||
|
{"ERR SAMPLE", OME_Submenu, cmsMenuChange, &menuInfoEntries[0], 0},
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{NULL,OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu menuMain = {
|
||||||
|
.GUARD_text = "MENUMAIN",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = menuMainEntries,
|
||||||
|
};
|
||||||
|
#endif
|
22
src/main/cms/cms_menu_builtin.h
Normal file
22
src/main/cms/cms_menu_builtin.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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 "cms/cms_types.h"
|
||||||
|
|
||||||
|
extern CMS_Menu menuMain;
|
384
src/main/cms/cms_menu_imu.c
Normal file
384
src/main/cms/cms_menu_imu.c
Normal file
|
@ -0,0 +1,384 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Menu contents for PID, RATES, RC preview, misc
|
||||||
|
// Should be part of the relevant .c file.
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
//#include "common/typeconversion.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_imu.h"
|
||||||
|
|
||||||
|
#include "fc/config.h"
|
||||||
|
#include "fc/rc_controls.h"
|
||||||
|
#include "fc/runtime_config.h"
|
||||||
|
|
||||||
|
#include "flight/pid.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// PID
|
||||||
|
//
|
||||||
|
static uint8_t tmpProfileIndex;
|
||||||
|
static uint8_t profileIndex;
|
||||||
|
static char profileIndexString[] = " p";
|
||||||
|
static uint8_t tempPid[3][3];
|
||||||
|
|
||||||
|
static uint8_t tmpRateProfileIndex;
|
||||||
|
static uint8_t rateProfileIndex;
|
||||||
|
static char rateProfileIndexString[] = " p-r";
|
||||||
|
static controlRateConfig_t rateProfile;
|
||||||
|
|
||||||
|
static long cmsx_menuImu_onEnter(void)
|
||||||
|
{
|
||||||
|
profileIndex = masterConfig.current_profile_index;
|
||||||
|
tmpProfileIndex = profileIndex + 1;
|
||||||
|
|
||||||
|
rateProfileIndex = masterConfig.profile[profileIndex].activeRateProfile;
|
||||||
|
tmpRateProfileIndex = rateProfileIndex + 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_menuImu_onExit(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
masterConfig.current_profile_index = profileIndex;
|
||||||
|
masterConfig.profile[profileIndex].activeRateProfile = rateProfileIndex;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_profileIndexOnChange(displayPort_t *displayPort, const void *ptr)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
UNUSED(ptr);
|
||||||
|
|
||||||
|
profileIndex = tmpProfileIndex - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_rateProfileIndexOnChange(displayPort_t *displayPort, const void *ptr)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
UNUSED(ptr);
|
||||||
|
|
||||||
|
rateProfileIndex = tmpRateProfileIndex - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_PidRead(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
tempPid[i][0] = masterConfig.profile[profileIndex].pidProfile.P8[i];
|
||||||
|
tempPid[i][1] = masterConfig.profile[profileIndex].pidProfile.I8[i];
|
||||||
|
tempPid[i][2] = masterConfig.profile[profileIndex].pidProfile.D8[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_PidOnEnter(void)
|
||||||
|
{
|
||||||
|
profileIndexString[1] = '0' + tmpProfileIndex;
|
||||||
|
cmsx_PidRead();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_PidWriteback(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.P8[i] = tempPid[i][0];
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.I8[i] = tempPid[i][1];
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.D8[i] = tempPid[i][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuPidEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- PID --", OME_Label, NULL, profileIndexString, 0},
|
||||||
|
|
||||||
|
{ "ROLL P", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDROLL][0], 0, 200, 1 }, 0 },
|
||||||
|
{ "ROLL I", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDROLL][1], 0, 200, 1 }, 0 },
|
||||||
|
{ "ROLL D", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDROLL][2], 0, 200, 1 }, 0 },
|
||||||
|
|
||||||
|
{ "PITCH P", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDPITCH][0], 0, 200, 1 }, 0 },
|
||||||
|
{ "PITCH I", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDPITCH][1], 0, 200, 1 }, 0 },
|
||||||
|
{ "PITCH D", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDPITCH][2], 0, 200, 1 }, 0 },
|
||||||
|
|
||||||
|
{ "YAW P", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDYAW][0], 0, 200, 1 }, 0 },
|
||||||
|
{ "YAW I", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDYAW][1], 0, 200, 1 }, 0 },
|
||||||
|
{ "YAW D", OME_UINT8, NULL, &(OSD_UINT8_t){ &tempPid[PIDYAW][2], 0, 200, 1 }, 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu cmsx_menuPid = {
|
||||||
|
.GUARD_text = "XPID",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_PidOnEnter,
|
||||||
|
.onExit = cmsx_PidWriteback,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuPidEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Rate & Expo
|
||||||
|
//
|
||||||
|
|
||||||
|
static long cmsx_RateProfileRead(void)
|
||||||
|
{
|
||||||
|
memcpy(&rateProfile, &masterConfig.profile[profileIndex].controlRateProfile[rateProfileIndex], sizeof(controlRateConfig_t));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_RateProfileWriteback(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
memcpy(&masterConfig.profile[profileIndex].controlRateProfile[rateProfileIndex], &rateProfile, sizeof(controlRateConfig_t));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_RateProfileOnEnter(void)
|
||||||
|
{
|
||||||
|
rateProfileIndexString[1] = '0' + tmpProfileIndex;
|
||||||
|
rateProfileIndexString[3] = '0' + tmpRateProfileIndex;
|
||||||
|
cmsx_RateProfileRead();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuRateProfileEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- RATE --", OME_Label, NULL, rateProfileIndexString, 0 },
|
||||||
|
|
||||||
|
{ "RC RATE", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rcRate8, 0, 255, 1, 10 }, 0 },
|
||||||
|
{ "RC YAW RATE", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rcYawRate8, 0, 255, 1, 10 }, 0 },
|
||||||
|
|
||||||
|
{ "ROLL SUPER", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rates[0], 0, 100, 1, 10 }, 0 },
|
||||||
|
{ "PITCH SUPER", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rates[1], 0, 100, 1, 10 }, 0 },
|
||||||
|
{ "YAW SUPER", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rates[2], 0, 100, 1, 10 }, 0 },
|
||||||
|
|
||||||
|
{ "RC EXPO", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rcExpo8, 0, 100, 1, 10 }, 0 },
|
||||||
|
{ "RC YAW EXP", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.rcYawExpo8, 0, 100, 1, 10 }, 0 },
|
||||||
|
|
||||||
|
{ "THRPID ATT", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &rateProfile.dynThrPID, 0, 100, 1, 10}, 0 },
|
||||||
|
{ "TPA BRKPT", OME_UINT16, NULL, &(OSD_UINT16_t){ &rateProfile.tpa_breakpoint, 1000, 2000, 10}, 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu cmsx_menuRateProfile = {
|
||||||
|
.GUARD_text = "MENURATE",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_RateProfileOnEnter,
|
||||||
|
.onExit = cmsx_RateProfileWriteback,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuRateProfileEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t cmsx_dtermSetpointWeight;
|
||||||
|
static uint8_t cmsx_setpointRelaxRatio;
|
||||||
|
static uint8_t cmsx_angleStrength;
|
||||||
|
static uint8_t cmsx_horizonStrength;
|
||||||
|
static uint8_t cmsx_horizonTransition;
|
||||||
|
|
||||||
|
static long cmsx_profileOtherOnEnter(void)
|
||||||
|
{
|
||||||
|
profileIndexString[1] = '0' + tmpProfileIndex;
|
||||||
|
|
||||||
|
cmsx_dtermSetpointWeight = masterConfig.profile[profileIndex].pidProfile.dtermSetpointWeight;
|
||||||
|
cmsx_setpointRelaxRatio = masterConfig.profile[profileIndex].pidProfile.setpointRelaxRatio;
|
||||||
|
|
||||||
|
cmsx_angleStrength = masterConfig.profile[profileIndex].pidProfile.P8[PIDLEVEL];
|
||||||
|
cmsx_horizonStrength = masterConfig.profile[profileIndex].pidProfile.I8[PIDLEVEL];
|
||||||
|
cmsx_horizonTransition = masterConfig.profile[profileIndex].pidProfile.D8[PIDLEVEL];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_profileOtherOnExit(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.dtermSetpointWeight = cmsx_dtermSetpointWeight;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.setpointRelaxRatio = cmsx_setpointRelaxRatio;
|
||||||
|
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.P8[PIDLEVEL] = cmsx_angleStrength;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.I8[PIDLEVEL] = cmsx_horizonStrength;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.D8[PIDLEVEL] = cmsx_horizonTransition;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuProfileOtherEntries[] = {
|
||||||
|
{ "-- OTHER PP --", OME_Label, NULL, profileIndexString, 0 },
|
||||||
|
|
||||||
|
{ "D SETPT WT", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_dtermSetpointWeight, 0, 255, 1, 10 }, 0 },
|
||||||
|
{ "SETPT TRS", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_setpointRelaxRatio, 0, 100, 1, 10 }, 0 },
|
||||||
|
{ "ANGLE STR", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_angleStrength, 0, 200, 1 } , 0 },
|
||||||
|
{ "HORZN STR", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_horizonStrength, 0, 200, 1 } , 0 },
|
||||||
|
{ "HORZN TRS", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_horizonTransition, 0, 200, 1 } , 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu cmsx_menuProfileOther = {
|
||||||
|
.GUARD_text = "XPROFOTHER",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_profileOtherOnEnter,
|
||||||
|
.onExit = cmsx_profileOtherOnExit,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuProfileOtherEntries,
|
||||||
|
};
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuFilterGlobalEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- FILTER GLB --", OME_Label, NULL, NULL, 0 },
|
||||||
|
|
||||||
|
{ "GYRO LPF", OME_UINT8, NULL, &(OSD_UINT8_t) { &masterConfig.gyro_soft_lpf_hz, 0, 255, 1 }, 0 },
|
||||||
|
{ "GYRO NF1", OME_UINT16, NULL, &(OSD_UINT16_t) { &masterConfig.gyro_soft_notch_hz_1, 0, 500, 1 }, 0 },
|
||||||
|
{ "GYRO NF1C", OME_UINT16, NULL, &(OSD_UINT16_t) { &masterConfig.gyro_soft_notch_cutoff_1, 0, 500, 1 }, 0 },
|
||||||
|
{ "GYRO NF2", OME_UINT16, NULL, &(OSD_UINT16_t) { &masterConfig.gyro_soft_notch_hz_2, 0, 500, 1 }, 0 },
|
||||||
|
{ "GYRO NF2C", OME_UINT16, NULL, &(OSD_UINT16_t) { &masterConfig.gyro_soft_notch_cutoff_2, 0, 500, 1 }, 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu cmsx_menuFilterGlobal = {
|
||||||
|
.GUARD_text = "XFLTGLB",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuFilterGlobalEntries,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t cmsx_dterm_lpf_hz;
|
||||||
|
static uint16_t cmsx_dterm_notch_hz;
|
||||||
|
static uint16_t cmsx_dterm_notch_cutoff;
|
||||||
|
static uint16_t cmsx_yaw_lpf_hz;
|
||||||
|
static uint16_t cmsx_yaw_p_limit;
|
||||||
|
|
||||||
|
static long cmsx_FilterPerProfileRead(void)
|
||||||
|
{
|
||||||
|
cmsx_dterm_lpf_hz = masterConfig.profile[profileIndex].pidProfile.dterm_lpf_hz;
|
||||||
|
cmsx_dterm_notch_hz = masterConfig.profile[profileIndex].pidProfile.dterm_notch_hz;
|
||||||
|
cmsx_dterm_notch_cutoff = masterConfig.profile[profileIndex].pidProfile.dterm_notch_cutoff;
|
||||||
|
cmsx_yaw_lpf_hz = masterConfig.profile[profileIndex].pidProfile.yaw_lpf_hz;
|
||||||
|
cmsx_yaw_p_limit = masterConfig.profile[profileIndex].pidProfile.yaw_p_limit;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_FilterPerProfileWriteback(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.dterm_lpf_hz = cmsx_dterm_lpf_hz;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.dterm_notch_hz = cmsx_dterm_notch_hz;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.dterm_notch_cutoff = cmsx_dterm_notch_cutoff;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.yaw_lpf_hz = cmsx_yaw_lpf_hz;
|
||||||
|
masterConfig.profile[profileIndex].pidProfile.yaw_p_limit = cmsx_yaw_p_limit;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuFilterPerProfileEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- FILTER PP --", OME_Label, NULL, NULL, 0 },
|
||||||
|
|
||||||
|
{ "DTERM LPF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_lpf_hz, 0, 500, 1 }, 0 },
|
||||||
|
{ "DTERM NF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_hz, 0, 500, 1 }, 0 },
|
||||||
|
{ "DTERM NFCO", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_cutoff, 0, 500, 1 }, 0 },
|
||||||
|
{ "YAW LPF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_yaw_lpf_hz, 0, 500, 1 }, 0 },
|
||||||
|
{ "YAW P LIM", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_yaw_p_limit, 100, 500, 1 }, 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CMS_Menu cmsx_menuFilterPerProfile = {
|
||||||
|
.GUARD_text = "XFLTPP",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_FilterPerProfileRead,
|
||||||
|
.onExit = cmsx_FilterPerProfileWriteback,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuFilterPerProfileEntries,
|
||||||
|
};
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuImuEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- IMU --", OME_Label, NULL, NULL, 0},
|
||||||
|
|
||||||
|
{"PID PROF", OME_UINT8, cmsx_profileIndexOnChange, &(OSD_UINT8_t){ &tmpProfileIndex, 1, MAX_PROFILE_COUNT, 1}, 0},
|
||||||
|
{"PID", OME_Submenu, cmsMenuChange, &cmsx_menuPid, 0},
|
||||||
|
{"OTHER PP", OME_Submenu, cmsMenuChange, &cmsx_menuProfileOther, 0},
|
||||||
|
|
||||||
|
{"RATE PROF", OME_UINT8, cmsx_rateProfileIndexOnChange, &(OSD_UINT8_t){ &tmpRateProfileIndex, 1, MAX_RATEPROFILES, 1}, 0},
|
||||||
|
{"RATE", OME_Submenu, cmsMenuChange, &cmsx_menuRateProfile, 0},
|
||||||
|
|
||||||
|
{"FLT PP", OME_Submenu, cmsMenuChange, &cmsx_menuFilterPerProfile, 0},
|
||||||
|
|
||||||
|
{"FLT GLB", OME_Submenu, cmsMenuChange, &cmsx_menuFilterGlobal, 0},
|
||||||
|
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuImu = {
|
||||||
|
.GUARD_text = "XIMU",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_menuImu_onEnter,
|
||||||
|
.onExit = cmsx_menuImu_onExit,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuImuEntries,
|
||||||
|
};
|
||||||
|
#endif // CMS
|
20
src/main/cms/cms_menu_imu.h
Normal file
20
src/main/cms/cms_menu_imu.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuImu;
|
82
src/main/cms/cms_menu_ledstrip.c
Normal file
82
src/main/cms/cms_menu_ledstrip.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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 <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_ledstrip.h"
|
||||||
|
|
||||||
|
#ifdef LED_STRIP
|
||||||
|
|
||||||
|
static bool featureRead = false;
|
||||||
|
static uint8_t cmsx_FeatureLedstrip;
|
||||||
|
|
||||||
|
static long cmsx_Ledstrip_FeatureRead(void)
|
||||||
|
{
|
||||||
|
if (!featureRead) {
|
||||||
|
cmsx_FeatureLedstrip = feature(FEATURE_LED_STRIP) ? 1 : 0;
|
||||||
|
featureRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_Ledstrip_FeatureWriteback(void)
|
||||||
|
{
|
||||||
|
if (cmsx_FeatureLedstrip)
|
||||||
|
featureSet(FEATURE_LED_STRIP);
|
||||||
|
else
|
||||||
|
featureClear(FEATURE_LED_STRIP);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuLedstripEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- LED STRIP --", OME_Label, NULL, NULL, 0 },
|
||||||
|
{ "ENABLED", OME_Bool, NULL, &cmsx_FeatureLedstrip, 0 },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0 },
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuLedstrip = {
|
||||||
|
.GUARD_text = "MENULED",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_Ledstrip_FeatureRead,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = cmsx_Ledstrip_FeatureWriteback,
|
||||||
|
.entries = cmsx_menuLedstripEntries
|
||||||
|
};
|
||||||
|
#endif // LED_STRIP
|
||||||
|
#endif // CMS
|
20
src/main/cms/cms_menu_ledstrip.h
Normal file
20
src/main/cms/cms_menu_ledstrip.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuLedstrip;
|
104
src/main/cms/cms_menu_misc.c
Normal file
104
src/main/cms/cms_menu_misc.c
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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 <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_ledstrip.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Misc
|
||||||
|
//
|
||||||
|
|
||||||
|
static long cmsx_menuRcConfirmBack(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
if (self && self->type == OME_Back)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// RC preview
|
||||||
|
//
|
||||||
|
static OSD_Entry cmsx_menuRcEntries[] =
|
||||||
|
{
|
||||||
|
{ "-- RC PREV --", OME_Label, NULL, NULL, 0},
|
||||||
|
|
||||||
|
{ "ROLL", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[ROLL], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "PITCH", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[PITCH], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "THR", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[THROTTLE], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "YAW", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[YAW], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
|
||||||
|
{ "AUX1", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[AUX1], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "AUX2", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[AUX2], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "AUX3", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[AUX3], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
{ "AUX4", OME_INT16, NULL, &(OSD_INT16_t){ &rcData[AUX4], 1, 2500, 0 }, DYNAMIC },
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuRcPreview = {
|
||||||
|
.GUARD_text = "XRCPREV",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = cmsx_menuRcConfirmBack,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuRcEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static OSD_Entry menuMiscEntries[]=
|
||||||
|
{
|
||||||
|
{ "-- MISC --", OME_Label, NULL, NULL, 0 },
|
||||||
|
|
||||||
|
{ "MIN THR", OME_UINT16, NULL, &(OSD_UINT16_t){ &masterConfig.motorConfig.minthrottle, 1000, 2000, 1 }, 0 },
|
||||||
|
{ "VBAT SCALE", OME_UINT8, NULL, &(OSD_UINT8_t) { &masterConfig.batteryConfig.vbatscale, 1, 250, 1 }, 0 },
|
||||||
|
{ "VBAT CLMAX", OME_UINT8, NULL, &(OSD_UINT8_t) { &masterConfig.batteryConfig.vbatmaxcellvoltage, 10, 50, 1 }, 0 },
|
||||||
|
{ "RC PREV", OME_Submenu, cmsMenuChange, &cmsx_menuRcPreview, 0},
|
||||||
|
|
||||||
|
{ "BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{ NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuMisc = {
|
||||||
|
.GUARD_text = "XMISC",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = menuMiscEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CMS
|
20
src/main/cms/cms_menu_misc.h
Normal file
20
src/main/cms/cms_menu_misc.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuMisc;
|
112
src/main/cms/cms_menu_osd.c
Normal file
112
src/main/cms/cms_menu_osd.c
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* 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 <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_osd.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
#if defined(OSD) && defined(CMS)
|
||||||
|
|
||||||
|
OSD_UINT8_t entryAlarmRssi = {&masterConfig.osdProfile.rssi_alarm, 5, 90, 5};
|
||||||
|
OSD_UINT16_t entryAlarmCapacity = {&masterConfig.osdProfile.cap_alarm, 50, 30000, 50};
|
||||||
|
OSD_UINT16_t enryAlarmFlyTime = {&masterConfig.osdProfile.time_alarm, 1, 200, 1};
|
||||||
|
OSD_UINT16_t entryAlarmAltitude = {&masterConfig.osdProfile.alt_alarm, 1, 200, 1};
|
||||||
|
|
||||||
|
OSD_Entry cmsx_menuAlarmsEntries[] =
|
||||||
|
{
|
||||||
|
{"--- ALARMS ---", OME_Label, NULL, NULL, 0},
|
||||||
|
{"RSSI", OME_UINT8, NULL, &entryAlarmRssi, 0},
|
||||||
|
{"MAIN BAT", OME_UINT16, NULL, &entryAlarmCapacity, 0},
|
||||||
|
{"FLY TIME", OME_UINT16, NULL, &enryAlarmFlyTime, 0},
|
||||||
|
{"MAX ALT", OME_UINT16, NULL, &entryAlarmAltitude, 0},
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuAlarms = {
|
||||||
|
.GUARD_text = "MENUALARMS",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuAlarmsEntries,
|
||||||
|
};
|
||||||
|
|
||||||
|
OSD_Entry menuOsdActiveElemsEntries[] =
|
||||||
|
{
|
||||||
|
{"--- ACTIV ELEM ---", OME_Label, NULL, NULL, 0},
|
||||||
|
{"RSSI", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_RSSI_VALUE], 0},
|
||||||
|
{"MAIN BATTERY", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_MAIN_BATT_VOLTAGE], 0},
|
||||||
|
{"HORIZON", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_ARTIFICIAL_HORIZON], 0},
|
||||||
|
{"HORIZON SIDEBARS", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_HORIZON_SIDEBARS], 0},
|
||||||
|
{"UPTIME", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_ONTIME], 0},
|
||||||
|
{"FLY TIME", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_FLYTIME], 0},
|
||||||
|
{"FLY MODE", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_FLYMODE], 0},
|
||||||
|
{"NAME", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_CRAFT_NAME], 0},
|
||||||
|
{"THROTTLE", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_THROTTLE_POS], 0},
|
||||||
|
#ifdef VTX
|
||||||
|
{"VTX CHAN", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_VTX_CHANNEL]},
|
||||||
|
#endif // VTX
|
||||||
|
{"CURRENT (A)", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_CURRENT_DRAW], 0},
|
||||||
|
{"USED MAH", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_MAH_DRAWN], 0},
|
||||||
|
#ifdef GPS
|
||||||
|
{"GPS SPEED", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_GPS_SPEED], 0},
|
||||||
|
{"GPS SATS.", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_GPS_SATS], 0},
|
||||||
|
#endif // GPS
|
||||||
|
{"ALTITUDE", OME_VISIBLE, NULL, &masterConfig.osdProfile.item_pos[OSD_ALTITUDE], 0},
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu menuOsdActiveElems = {
|
||||||
|
.GUARD_text = "MENUOSDACT",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = menuOsdActiveElemsEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
OSD_Entry cmsx_menuOsdLayoutEntries[] =
|
||||||
|
{
|
||||||
|
{"---SCREEN LAYOUT---", OME_Label, NULL, NULL, 0},
|
||||||
|
{"ACTIVE ELEM", OME_Submenu, cmsMenuChange, &menuOsdActiveElems, 0},
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuOsdLayout = {
|
||||||
|
.GUARD_text = "MENULAYOUT",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = NULL,
|
||||||
|
.onExit = NULL,
|
||||||
|
.onGlobalExit = NULL,
|
||||||
|
.entries = cmsx_menuOsdLayoutEntries
|
||||||
|
};
|
||||||
|
#endif // CMS
|
21
src/main/cms/cms_menu_osd.h
Normal file
21
src/main/cms/cms_menu_osd.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuAlarms;
|
||||||
|
extern CMS_Menu cmsx_menuOsdLayout;
|
146
src/main/cms/cms_menu_vtx.c
Normal file
146
src/main/cms/cms_menu_vtx.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* 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 <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/version.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
#include "cms/cms_types.h"
|
||||||
|
#include "cms/cms_menu_vtx.h"
|
||||||
|
|
||||||
|
#include "config/config_profile.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
#include "config/feature.h"
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
|
||||||
|
#if defined(VTX) || defined(USE_RTC6705)
|
||||||
|
|
||||||
|
static bool featureRead = false;
|
||||||
|
static uint8_t cmsx_featureVtx = 0, cmsx_vtxBand, cmsx_vtxChannel;
|
||||||
|
|
||||||
|
static long cmsx_Vtx_FeatureRead(void)
|
||||||
|
{
|
||||||
|
if (!featureRead) {
|
||||||
|
cmsx_featureVtx = feature(FEATURE_VTX) ? 1 : 0;
|
||||||
|
featureRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_Vtx_FeatureWriteback(void)
|
||||||
|
{
|
||||||
|
if (cmsx_featureVtx)
|
||||||
|
featureSet(FEATURE_VTX);
|
||||||
|
else
|
||||||
|
featureClear(FEATURE_VTX);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const vtxBandNames[] = {
|
||||||
|
"BOSCAM A",
|
||||||
|
"BOSCAM B",
|
||||||
|
"BOSCAM E",
|
||||||
|
"FATSHARK",
|
||||||
|
"RACEBAND",
|
||||||
|
};
|
||||||
|
|
||||||
|
static OSD_TAB_t entryVtxBand = {&cmsx_vtxBand,4,&vtxBandNames[0]};
|
||||||
|
static OSD_UINT8_t entryVtxChannel = {&cmsx_vtxChannel, 1, 8, 1};
|
||||||
|
|
||||||
|
static void cmsx_Vtx_ConfigRead(void)
|
||||||
|
{
|
||||||
|
#ifdef VTX
|
||||||
|
cmsx_vtxBand = masterConfig.vtx_band;
|
||||||
|
cmsx_vtxChannel = masterConfig.vtx_channel + 1;
|
||||||
|
#endif // VTX
|
||||||
|
|
||||||
|
#ifdef USE_RTC6705
|
||||||
|
cmsx_vtxBand = masterConfig.vtx_channel / 8;
|
||||||
|
cmsx_vtxChannel = masterConfig.vtx_channel % 8 + 1;
|
||||||
|
#endif // USE_RTC6705
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmsx_Vtx_ConfigWriteback(void)
|
||||||
|
{
|
||||||
|
#ifdef VTX
|
||||||
|
masterConfig.vtx_band = cmsx_vtxBand;
|
||||||
|
masterConfig.vtx_channel = cmsx_vtxChannel - 1;
|
||||||
|
#endif // VTX
|
||||||
|
|
||||||
|
#ifdef USE_RTC6705
|
||||||
|
masterConfig.vtx_channel = cmsx_vtxBand * 8 + cmsx_vtxChannel - 1;
|
||||||
|
#endif // USE_RTC6705
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_Vtx_onEnter(void)
|
||||||
|
{
|
||||||
|
cmsx_Vtx_FeatureRead();
|
||||||
|
cmsx_Vtx_ConfigRead();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long cmsx_Vtx_onExit(const OSD_Entry *self)
|
||||||
|
{
|
||||||
|
UNUSED(self);
|
||||||
|
|
||||||
|
cmsx_Vtx_ConfigWriteback();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VTX
|
||||||
|
static OSD_UINT8_t entryVtxMode = {&masterConfig.vtx_mode, 0, 2, 1};
|
||||||
|
static OSD_UINT16_t entryVtxMhz = {&masterConfig.vtx_mhz, 5600, 5950, 1};
|
||||||
|
#endif // VTX
|
||||||
|
|
||||||
|
static OSD_Entry cmsx_menuVtxEntries[] =
|
||||||
|
{
|
||||||
|
{"--- VTX ---", OME_Label, NULL, NULL, 0},
|
||||||
|
{"ENABLED", OME_Bool, NULL, &cmsx_featureVtx, 0},
|
||||||
|
#ifdef VTX
|
||||||
|
{"VTX MODE", OME_UINT8, NULL, &entryVtxMode, 0},
|
||||||
|
{"VTX MHZ", OME_UINT16, NULL, &entryVtxMhz, 0},
|
||||||
|
#endif // VTX
|
||||||
|
{"BAND", OME_TAB, NULL, &entryVtxBand, 0},
|
||||||
|
{"CHANNEL", OME_UINT8, NULL, &entryVtxChannel, 0},
|
||||||
|
#ifdef USE_RTC6705
|
||||||
|
{"LOW POWER", OME_Bool, NULL, &masterConfig.vtx_power, 0},
|
||||||
|
#endif // USE_RTC6705
|
||||||
|
{"BACK", OME_Back, NULL, NULL, 0},
|
||||||
|
{NULL, OME_END, NULL, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
CMS_Menu cmsx_menuVtx = {
|
||||||
|
.GUARD_text = "MENUVTX",
|
||||||
|
.GUARD_type = OME_MENU,
|
||||||
|
.onEnter = cmsx_Vtx_onEnter,
|
||||||
|
.onExit= cmsx_Vtx_onExit,
|
||||||
|
.onGlobalExit = cmsx_Vtx_FeatureWriteback,
|
||||||
|
.entries = cmsx_menuVtxEntries
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VTX || USE_RTC6705
|
||||||
|
#endif // CMS
|
20
src/main/cms/cms_menu_vtx.h
Normal file
20
src/main/cms/cms_menu_vtx.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
extern CMS_Menu cmsx_menuVtx;
|
155
src/main/cms/cms_types.h
Normal file
155
src/main/cms/cms_types.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Menu element types
|
||||||
|
// XXX Upon separation, all OME would be renamed to CME_ or similar.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//type of elements
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
OME_Label,
|
||||||
|
OME_Back,
|
||||||
|
OME_OSD_Exit,
|
||||||
|
OME_Submenu,
|
||||||
|
OME_Funcall,
|
||||||
|
OME_Bool,
|
||||||
|
OME_INT8,
|
||||||
|
OME_UINT8,
|
||||||
|
OME_UINT16,
|
||||||
|
OME_INT16,
|
||||||
|
OME_String,
|
||||||
|
OME_FLOAT, //only up to 255 value and cant be 2.55 or 25.5, just for PID's
|
||||||
|
//wlasciwosci elementow
|
||||||
|
#ifdef OSD
|
||||||
|
OME_VISIBLE,
|
||||||
|
#endif
|
||||||
|
OME_TAB,
|
||||||
|
OME_END,
|
||||||
|
|
||||||
|
// Debug aid
|
||||||
|
OME_MENU,
|
||||||
|
|
||||||
|
OME_MAX = OME_MENU
|
||||||
|
} OSD_MenuElement;
|
||||||
|
|
||||||
|
typedef long (*CMSEntryFuncPtr)(displayPort_t *displayPort, const void *ptr);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *text;
|
||||||
|
const OSD_MenuElement type;
|
||||||
|
const CMSEntryFuncPtr func;
|
||||||
|
void *data;
|
||||||
|
uint8_t flags;
|
||||||
|
} OSD_Entry;
|
||||||
|
|
||||||
|
// Bits in flags
|
||||||
|
#define PRINT_VALUE 0x01 // Value has been changed, need to redraw
|
||||||
|
#define PRINT_LABEL 0x02 // Text label should be printed
|
||||||
|
#define DYNAMIC 0x04 // Value should be updated dynamically
|
||||||
|
|
||||||
|
#define IS_PRINTVALUE(p) ((p)->flags & PRINT_VALUE)
|
||||||
|
#define SET_PRINTVALUE(p) { (p)->flags |= PRINT_VALUE; }
|
||||||
|
#define CLR_PRINTVALUE(p) { (p)->flags &= ~PRINT_VALUE; }
|
||||||
|
|
||||||
|
#define IS_PRINTLABEL(p) ((p)->flags & PRINT_LABEL)
|
||||||
|
#define SET_PRINTLABEL(p) { (p)->flags |= PRINT_LABEL; }
|
||||||
|
#define CLR_PRINTLABEL(p) { (p)->flags &= ~PRINT_LABEL; }
|
||||||
|
|
||||||
|
#define IS_DYNAMIC(p) ((p)->flags & DYNAMIC)
|
||||||
|
|
||||||
|
|
||||||
|
typedef long (*CMSMenuFuncPtr)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
onExit function is called with self:
|
||||||
|
(1) Pointer to an OSD_Entry when cmsMenuBack() was called.
|
||||||
|
Point to an OSD_Entry with type == OME_Back if BACK was selected.
|
||||||
|
(2) NULL if called from menu exit (forced exit at top level).
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef long (*CMSMenuOnExitPtr)(const OSD_Entry *self);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// These two are debug aids for menu content creators.
|
||||||
|
const char *GUARD_text;
|
||||||
|
const OSD_MenuElement GUARD_type;
|
||||||
|
|
||||||
|
const CMSMenuFuncPtr onEnter;
|
||||||
|
const CMSMenuOnExitPtr onExit;
|
||||||
|
const CMSMenuFuncPtr onGlobalExit;
|
||||||
|
OSD_Entry *entries;
|
||||||
|
} CMS_Menu;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t *val;
|
||||||
|
uint8_t min;
|
||||||
|
uint8_t max;
|
||||||
|
uint8_t step;
|
||||||
|
} OSD_UINT8_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int8_t *val;
|
||||||
|
int8_t min;
|
||||||
|
int8_t max;
|
||||||
|
int8_t step;
|
||||||
|
} OSD_INT8_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int16_t *val;
|
||||||
|
int16_t min;
|
||||||
|
int16_t max;
|
||||||
|
int16_t step;
|
||||||
|
} OSD_INT16_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t *val;
|
||||||
|
uint16_t min;
|
||||||
|
uint16_t max;
|
||||||
|
uint16_t step;
|
||||||
|
} OSD_UINT16_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t *val;
|
||||||
|
uint8_t min;
|
||||||
|
uint8_t max;
|
||||||
|
uint8_t step;
|
||||||
|
uint16_t multipler;
|
||||||
|
} OSD_FLOAT_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t *val;
|
||||||
|
uint8_t max;
|
||||||
|
const char * const *names;
|
||||||
|
} OSD_TAB_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *val;
|
||||||
|
} OSD_String_t;
|
|
@ -75,7 +75,7 @@ void biquadFilterInit(biquadFilter_t *filter, float filterFreq, uint32_t refresh
|
||||||
const float cs = cosf(omega);
|
const float cs = cosf(omega);
|
||||||
const float alpha = sn / (2 * Q);
|
const float alpha = sn / (2 * Q);
|
||||||
|
|
||||||
float b0, b1, b2, a0, a1, a2;
|
float b0 = 0, b1 = 0, b2 = 0, a0 = 0, a1 = 0, a2 = 0;
|
||||||
|
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
case FILTER_LPF:
|
case FILTER_LPF:
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
#if defined(STM32F40_41xxx)
|
#if defined(STM32F40_41xxx)
|
||||||
#define FLASH_PAGE_COUNT 4 // just to make calculations work
|
#define FLASH_PAGE_COUNT 4 // just to make calculations work
|
||||||
#elif defined (STM32F411xE)
|
#elif defined (STM32F411xE)
|
||||||
#define FLASH_PAGE_COUNT 4 // just to make calculations work
|
#define FLASH_PAGE_COUNT 3 // just to make calculations work
|
||||||
#elif defined (STM32F745xx)
|
#elif defined (STM32F745xx)
|
||||||
#define FLASH_PAGE_COUNT 4 // just to make calculations work
|
#define FLASH_PAGE_COUNT 4 // just to make calculations work
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
#include "config/config_profile.h"
|
#include "config/config_profile.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
|
||||||
#include "drivers/pwm_rx.h"
|
#include "drivers/pwm_rx.h"
|
||||||
#include "drivers/sound_beeper.h"
|
#include "drivers/sound_beeper.h"
|
||||||
#include "drivers/sonar_hcsr04.h"
|
#include "drivers/sonar_hcsr04.h"
|
||||||
|
@ -161,11 +163,7 @@ typedef struct master_s {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LED_STRIP
|
#ifdef LED_STRIP
|
||||||
ledConfig_t ledConfigs[LED_MAX_STRIP_LENGTH];
|
ledStripConfig_t ledStripConfig;
|
||||||
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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TRANSPONDER
|
#ifdef TRANSPONDER
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
* 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 MPU6500_WHO_AM_I_CONST (0x70)
|
#define MPU6500_WHO_AM_I_CONST (0x70)
|
||||||
#define MPU9250_WHO_AM_I_CONST (0x71)
|
#define MPU9250_WHO_AM_I_CONST (0x71)
|
||||||
#define ICM20608G_WHO_AM_I_CONST (0xAF)
|
#define ICM20608G_WHO_AM_I_CONST (0xAF)
|
||||||
|
#define ICM20602_WHO_AM_I_CONST (0x12)
|
||||||
|
|
||||||
#define MPU6500_BIT_RESET (0x80)
|
#define MPU6500_BIT_RESET (0x80)
|
||||||
#define MPU6500_BIT_INT_ANYRD_2CLEAR (1 << 4)
|
#define MPU6500_BIT_INT_ANYRD_2CLEAR (1 << 4)
|
||||||
|
@ -25,8 +28,6 @@
|
||||||
#define MPU6500_BIT_I2C_IF_DIS (1 << 4)
|
#define MPU6500_BIT_I2C_IF_DIS (1 << 4)
|
||||||
#define MPU6500_BIT_RAW_RDY_EN (0x01)
|
#define MPU6500_BIT_RAW_RDY_EN (0x01)
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
bool mpu6500AccDetect(acc_t *acc);
|
bool mpu6500AccDetect(acc_t *acc);
|
||||||
bool mpu6500GyroDetect(gyro_t *gyro);
|
bool mpu6500GyroDetect(gyro_t *gyro);
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ static void icm20689SpiInit(void)
|
||||||
IOInit(icmSpi20689CsPin, OWNER_MPU, RESOURCE_SPI_CS, 0);
|
IOInit(icmSpi20689CsPin, OWNER_MPU, RESOURCE_SPI_CS, 0);
|
||||||
IOConfigGPIO(icmSpi20689CsPin, SPI_IO_CS_CFG);
|
IOConfigGPIO(icmSpi20689CsPin, SPI_IO_CS_CFG);
|
||||||
|
|
||||||
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_FAST);
|
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_STANDARD);
|
||||||
|
|
||||||
hardwareInitialised = true;
|
hardwareInitialised = true;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ bool icm20689SpiDetect(void)
|
||||||
}
|
}
|
||||||
} while (attemptsRemaining--);
|
} while (attemptsRemaining--);
|
||||||
|
|
||||||
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_FAST);
|
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_STANDARD);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -175,6 +175,6 @@ void icm20689GyroInit(uint8_t lpf)
|
||||||
mpuConfiguration.write(MPU_RA_INT_ENABLE, 0x01); // RAW_RDY_EN interrupt enable
|
mpuConfiguration.write(MPU_RA_INT_ENABLE, 0x01); // RAW_RDY_EN interrupt enable
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_FAST);
|
spiSetDivisor(ICM20689_SPI_INSTANCE, SPI_CLOCK_STANDARD);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,10 @@ bool mpu6500SpiDetect(void)
|
||||||
|
|
||||||
mpu6500ReadRegister(MPU_RA_WHO_AM_I, 1, &tmp);
|
mpu6500ReadRegister(MPU_RA_WHO_AM_I, 1, &tmp);
|
||||||
|
|
||||||
if (tmp == MPU6500_WHO_AM_I_CONST || tmp == MPU9250_WHO_AM_I_CONST || tmp == ICM20608G_WHO_AM_I_CONST) {
|
if (tmp == MPU6500_WHO_AM_I_CONST ||
|
||||||
|
tmp == MPU9250_WHO_AM_I_CONST ||
|
||||||
|
tmp == ICM20608G_WHO_AM_I_CONST ||
|
||||||
|
tmp == ICM20602_WHO_AM_I_CONST) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ typedef struct adcTagMap_s {
|
||||||
typedef struct adcDevice_s {
|
typedef struct adcDevice_s {
|
||||||
ADC_TypeDef* ADCx;
|
ADC_TypeDef* ADCx;
|
||||||
rccPeriphTag_t rccADC;
|
rccPeriphTag_t rccADC;
|
||||||
rccPeriphTag_t rccDMA;
|
|
||||||
#if defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F4) || defined(STM32F7)
|
||||||
DMA_Stream_TypeDef* DMAy_Streamx;
|
DMA_Stream_TypeDef* DMAy_Streamx;
|
||||||
uint32_t channel;
|
uint32_t channel;
|
||||||
|
|
|
@ -32,13 +32,14 @@
|
||||||
#include "adc_impl.h"
|
#include "adc_impl.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
#ifndef ADC_INSTANCE
|
#ifndef ADC_INSTANCE
|
||||||
#define ADC_INSTANCE ADC1
|
#define ADC_INSTANCE ADC1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const adcDevice_t adcHardware[] = {
|
const adcDevice_t adcHardware[] = {
|
||||||
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .rccDMA = RCC_AHB(DMA1), .DMAy_Channelx = DMA1_Channel1 }
|
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .DMAy_Channelx = DMA1_Channel1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
ADCDevice adcDeviceByInstance(ADC_TypeDef *instance)
|
ADCDevice adcDeviceByInstance(ADC_TypeDef *instance)
|
||||||
|
@ -131,7 +132,8 @@ void adcInit(drv_adc_config_t *init)
|
||||||
|
|
||||||
RCC_ADCCLKConfig(RCC_PCLK2_Div8); // 9MHz from 72MHz APB2 clock(HSE), 8MHz from 64MHz (HSI)
|
RCC_ADCCLKConfig(RCC_PCLK2_Div8); // 9MHz from 72MHz APB2 clock(HSE), 8MHz from 64MHz (HSI)
|
||||||
RCC_ClockCmd(adc.rccADC, ENABLE);
|
RCC_ClockCmd(adc.rccADC, ENABLE);
|
||||||
RCC_ClockCmd(adc.rccDMA, ENABLE);
|
|
||||||
|
dmaInit(dmaGetIdentifier(adc.DMAy_Channelx), OWNER_ADC, RESOURCE_INDEX(device));
|
||||||
|
|
||||||
DMA_DeInit(adc.DMAy_Channelx);
|
DMA_DeInit(adc.DMAy_Channelx);
|
||||||
DMA_InitTypeDef DMA_InitStructure;
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "adc_impl.h"
|
#include "adc_impl.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
#include "common/utils.h"
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
@ -38,8 +39,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const adcDevice_t adcHardware[] = {
|
const adcDevice_t adcHardware[] = {
|
||||||
{ .ADCx = ADC1, .rccADC = RCC_AHB(ADC12), .rccDMA = RCC_AHB(DMA1), .DMAy_Channelx = DMA1_Channel1 },
|
{ .ADCx = ADC1, .rccADC = RCC_AHB(ADC12), .DMAy_Channelx = DMA1_Channel1 },
|
||||||
{ .ADCx = ADC2, .rccADC = RCC_AHB(ADC12), .rccDMA = RCC_AHB(DMA2), .DMAy_Channelx = DMA2_Channel1 }
|
#ifdef ADC24_DMA_REMAP
|
||||||
|
{ .ADCx = ADC2, .rccADC = RCC_AHB(ADC12), .DMAy_Channelx = DMA2_Channel3 }
|
||||||
|
#else
|
||||||
|
{ .ADCx = ADC2, .rccADC = RCC_AHB(ADC12), .DMAy_Channelx = DMA2_Channel1 }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const adcTagMap_t adcTagMap[] = {
|
const adcTagMap_t adcTagMap[] = {
|
||||||
|
@ -133,6 +138,9 @@ void adcInit(drv_adc_config_t *init)
|
||||||
if (device == ADCINVALID)
|
if (device == ADCINVALID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef ADC24_DMA_REMAP
|
||||||
|
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_ADC2ADC4, ENABLE);
|
||||||
|
#endif
|
||||||
adcDevice_t adc = adcHardware[device];
|
adcDevice_t adc = adcHardware[device];
|
||||||
|
|
||||||
for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < ADC_CHANNEL_COUNT; i++) {
|
||||||
|
@ -149,7 +157,8 @@ void adcInit(drv_adc_config_t *init)
|
||||||
|
|
||||||
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div256); // 72 MHz divided by 256 = 281.25 kHz
|
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div256); // 72 MHz divided by 256 = 281.25 kHz
|
||||||
RCC_ClockCmd(adc.rccADC, ENABLE);
|
RCC_ClockCmd(adc.rccADC, ENABLE);
|
||||||
RCC_ClockCmd(adc.rccDMA, ENABLE);
|
|
||||||
|
dmaInit(dmaGetIdentifier(adc.DMAy_Channelx), OWNER_ADC, RESOURCE_INDEX(device));
|
||||||
|
|
||||||
DMA_DeInit(adc.DMAy_Channelx);
|
DMA_DeInit(adc.DMAy_Channelx);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "io_impl.h"
|
#include "io_impl.h"
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#include "accgyro.h"
|
#include "accgyro.h"
|
||||||
|
@ -37,8 +38,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const adcDevice_t adcHardware[] = {
|
const adcDevice_t adcHardware[] = {
|
||||||
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .rccDMA = RCC_AHB1(DMA2), .DMAy_Streamx = DMA2_Stream4, .channel = DMA_Channel_0 },
|
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .DMAy_Streamx = DMA2_Stream4, .channel = DMA_Channel_0 },
|
||||||
//{ .ADCx = ADC2, .rccADC = RCC_APB2(ADC2), .rccDMA = RCC_AHB1(DMA2), .DMAy_Streamx = DMA2_Stream1, .channel = DMA_Channel_0 }
|
//{ .ADCx = ADC2, .rccADC = RCC_APB2(ADC2), .DMAy_Streamx = DMA2_Stream1, .channel = DMA_Channel_0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* note these could be packed up for saving space */
|
/* note these could be packed up for saving space */
|
||||||
|
@ -140,9 +141,10 @@ void adcInit(drv_adc_config_t *init)
|
||||||
adcConfig[i].enabled = true;
|
adcConfig[i].enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCC_ClockCmd(adc.rccDMA, ENABLE);
|
|
||||||
RCC_ClockCmd(adc.rccADC, ENABLE);
|
RCC_ClockCmd(adc.rccADC, ENABLE);
|
||||||
|
|
||||||
|
dmaInit(dmaGetIdentifier(adc.DMAy_Streamx), OWNER_ADC, RESOURCE_INDEX(device));
|
||||||
|
|
||||||
DMA_DeInit(adc.DMAy_Streamx);
|
DMA_DeInit(adc.DMAy_Streamx);
|
||||||
|
|
||||||
DMA_StructInit(&DMA_InitStructure);
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "io_impl.h"
|
#include "io_impl.h"
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#include "accgyro.h"
|
#include "accgyro.h"
|
||||||
|
@ -37,8 +38,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const adcDevice_t adcHardware[] = {
|
const adcDevice_t adcHardware[] = {
|
||||||
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .rccDMA = RCC_AHB1(DMA2), .DMAy_Streamx = DMA2_Stream4, .channel = DMA_CHANNEL_0 },
|
{ .ADCx = ADC1, .rccADC = RCC_APB2(ADC1), .DMAy_Streamx = DMA2_Stream4, .channel = DMA_CHANNEL_0 },
|
||||||
//{ .ADCx = ADC2, .rccADC = RCC_APB2(ADC2), .rccDMA = RCC_AHB1(DMA2), .DMAy_Streamx = DMA2_Stream1, .channel = DMA_Channel_0 }
|
//{ .ADCx = ADC2, .rccADC = RCC_APB2(ADC2), .DMAy_Streamx = DMA2_Stream1, .channel = DMA_Channel_0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* note these could be packed up for saving space */
|
/* note these could be packed up for saving space */
|
||||||
|
@ -138,8 +139,9 @@ void adcInit(drv_adc_config_t *init)
|
||||||
adcConfig[i].enabled = true;
|
adcConfig[i].enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCC_ClockCmd(adc.rccDMA, ENABLE);
|
|
||||||
RCC_ClockCmd(adc.rccADC, ENABLE);
|
RCC_ClockCmd(adc.rccADC, ENABLE);
|
||||||
|
dmaInit(dmaGetIdentifier(adc.DMAy_Streamx), OWNER_ADC, RESOURCE_INDEX(device));
|
||||||
|
|
||||||
ADCHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
|
ADCHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
|
||||||
ADCHandle.Init.ContinuousConvMode = ENABLE;
|
ADCHandle.Init.ContinuousConvMode = ENABLE;
|
||||||
|
|
72
src/main/drivers/display.c
Normal file
72
src/main/drivers/display.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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 "platform.h"
|
||||||
|
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
void displayClear(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
instance->vTable->clear(instance);
|
||||||
|
instance->cleared = true;
|
||||||
|
instance->cursorRow = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayGrab(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
instance->vTable->grab(instance);
|
||||||
|
instance->vTable->clear(instance);
|
||||||
|
instance->isGrabbed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayRelease(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
instance->vTable->release(instance);
|
||||||
|
instance->isGrabbed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool displayIsGrabbed(const displayPort_t *instance)
|
||||||
|
{
|
||||||
|
// can be called before initialised
|
||||||
|
return (instance && instance->isGrabbed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, const char *s)
|
||||||
|
{
|
||||||
|
return instance->vTable->write(instance, x, y, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayHeartbeat(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
instance->vTable->heartbeat(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayResync(displayPort_t *instance)
|
||||||
|
{
|
||||||
|
instance->vTable->resync(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t displayTxBytesFree(const displayPort_t *instance)
|
||||||
|
{
|
||||||
|
return instance->vTable->txBytesFree(instance);
|
||||||
|
}
|
||||||
|
|
49
src/main/drivers/display.h
Normal file
49
src/main/drivers/display.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
struct displayPortVTable_s;
|
||||||
|
typedef struct displayPort_s {
|
||||||
|
const struct displayPortVTable_s *vTable;
|
||||||
|
uint8_t rows;
|
||||||
|
uint8_t cols;
|
||||||
|
|
||||||
|
// CMS state
|
||||||
|
bool cleared;
|
||||||
|
int8_t cursorRow;
|
||||||
|
bool isGrabbed;
|
||||||
|
} displayPort_t;
|
||||||
|
|
||||||
|
typedef struct displayPortVTable_s {
|
||||||
|
int (*grab)(displayPort_t *displayPort);
|
||||||
|
int (*release)(displayPort_t *displayPort);
|
||||||
|
int (*clear)(displayPort_t *displayPort);
|
||||||
|
int (*write)(displayPort_t *displayPort, uint8_t x, uint8_t y, const char *text);
|
||||||
|
int (*heartbeat)(displayPort_t *displayPort);
|
||||||
|
void (*resync)(displayPort_t *displayPort);
|
||||||
|
uint32_t (*txBytesFree)(const displayPort_t *displayPort);
|
||||||
|
} displayPortVTable_t;
|
||||||
|
|
||||||
|
void displayGrab(displayPort_t *instance);
|
||||||
|
void displayRelease(displayPort_t *instance);
|
||||||
|
bool displayIsGrabbed(const displayPort_t *instance);
|
||||||
|
void displayClear(displayPort_t *instance);
|
||||||
|
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, const char *s);
|
||||||
|
void displayHeartbeat(displayPort_t *instance);
|
||||||
|
void displayResync(displayPort_t *instance);
|
||||||
|
uint16_t displayTxBytesFree(const displayPort_t *instance);
|
|
@ -63,16 +63,18 @@ DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_CH4_HANDLER)
|
||||||
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_CH5_HANDLER)
|
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_CH5_HANDLER)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void dmaInit(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex)
|
||||||
void dmaInit(void)
|
|
||||||
{
|
{
|
||||||
// TODO: Do we need this?
|
RCC_AHBPeriphClockCmd(dmaDescriptors[identifier].rcc, ENABLE);
|
||||||
|
dmaDescriptors[identifier].owner = owner;
|
||||||
|
dmaDescriptors[identifier].resourceIndex = resourceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmaSetHandler(dmaHandlerIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
||||||
{
|
{
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
|
/* TODO: remove this - enforce the init */
|
||||||
RCC_AHBPeriphClockCmd(dmaDescriptors[identifier].rcc, ENABLE);
|
RCC_AHBPeriphClockCmd(dmaDescriptors[identifier].rcc, ENABLE);
|
||||||
dmaDescriptors[identifier].irqHandlerCallback = callback;
|
dmaDescriptors[identifier].irqHandlerCallback = callback;
|
||||||
dmaDescriptors[identifier].userParam = userParam;
|
dmaDescriptors[identifier].userParam = userParam;
|
||||||
|
@ -84,3 +86,22 @@ void dmaSetHandler(dmaHandlerIdentifier_e identifier, dmaCallbackHandlerFuncPtr
|
||||||
NVIC_Init(&NVIC_InitStructure);
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resourceOwner_e dmaGetOwner(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dmaGetResourceIndex(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].resourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmaIdentifier_e dmaGetIdentifier(const DMA_Channel_TypeDef* channel)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DMA_MAX_DESCRIPTORS; i++) {
|
||||||
|
if (dmaDescriptors[i].channel == channel) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -15,10 +15,29 @@
|
||||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
struct dmaChannelDescriptor_s;
|
struct dmaChannelDescriptor_s;
|
||||||
typedef void (*dmaCallbackHandlerFuncPtr)(struct dmaChannelDescriptor_s *channelDescriptor);
|
typedef void (*dmaCallbackHandlerFuncPtr)(struct dmaChannelDescriptor_s *channelDescriptor);
|
||||||
|
|
||||||
|
typedef struct dmaChannelDescriptor_s {
|
||||||
|
DMA_TypeDef* dma;
|
||||||
|
#if defined(STM32F4) || defined(STM32F7)
|
||||||
|
DMA_Stream_TypeDef* stream;
|
||||||
|
#else
|
||||||
|
DMA_Channel_TypeDef* channel;
|
||||||
|
#endif
|
||||||
|
dmaCallbackHandlerFuncPtr irqHandlerCallback;
|
||||||
|
uint8_t flagsShift;
|
||||||
|
IRQn_Type irqN;
|
||||||
|
uint32_t rcc;
|
||||||
|
uint32_t userParam;
|
||||||
|
resourceOwner_e owner;
|
||||||
|
uint8_t resourceIndex;
|
||||||
|
} dmaChannelDescriptor_t;
|
||||||
|
|
||||||
#if defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F4) || defined(STM32F7)
|
||||||
|
|
||||||
uint32_t dmaFlag_IT_TCIF(const DMA_Stream_TypeDef *stream);
|
uint32_t dmaFlag_IT_TCIF(const DMA_Stream_TypeDef *stream);
|
||||||
|
@ -40,19 +59,15 @@ typedef enum {
|
||||||
DMA2_ST5_HANDLER,
|
DMA2_ST5_HANDLER,
|
||||||
DMA2_ST6_HANDLER,
|
DMA2_ST6_HANDLER,
|
||||||
DMA2_ST7_HANDLER,
|
DMA2_ST7_HANDLER,
|
||||||
} dmaHandlerIdentifier_e;
|
DMA_MAX_DESCRIPTORS
|
||||||
|
} dmaIdentifier_e;
|
||||||
|
|
||||||
typedef struct dmaChannelDescriptor_s {
|
#define DMA_MOD_VALUE 8
|
||||||
DMA_TypeDef* dma;
|
#define DMA_MOD_OFFSET 0
|
||||||
DMA_Stream_TypeDef* stream;
|
#define DMA_OUTPUT_INDEX 0
|
||||||
dmaCallbackHandlerFuncPtr irqHandlerCallback;
|
#define DMA_OUTPUT_STRING "DMA%d Stream %d:"
|
||||||
uint8_t flagsShift;
|
|
||||||
IRQn_Type irqN;
|
|
||||||
uint32_t rcc;
|
|
||||||
uint32_t userParam;
|
|
||||||
} dmaChannelDescriptor_t;
|
|
||||||
|
|
||||||
#define DEFINE_DMA_CHANNEL(d, s, f, i, r) {.dma = d, .stream = s, .irqHandlerCallback = NULL, .flagsShift = f, .irqN = i, .rcc = r, .userParam = 0}
|
#define DEFINE_DMA_CHANNEL(d, s, f, i, r) {.dma = d, .stream = s, .irqHandlerCallback = NULL, .flagsShift = f, .irqN = i, .rcc = r, .userParam = 0, .owner = 0, .resourceIndex = 0 }
|
||||||
#define DEFINE_DMA_IRQ_HANDLER(d, s, i) void DMA ## d ## _Stream ## s ## _IRQHandler(void) {\
|
#define DEFINE_DMA_IRQ_HANDLER(d, s, i) void DMA ## d ## _Stream ## s ## _IRQHandler(void) {\
|
||||||
if (dmaDescriptors[i].irqHandlerCallback)\
|
if (dmaDescriptors[i].irqHandlerCallback)\
|
||||||
dmaDescriptors[i].irqHandlerCallback(&dmaDescriptors[i]);\
|
dmaDescriptors[i].irqHandlerCallback(&dmaDescriptors[i]);\
|
||||||
|
@ -68,6 +83,8 @@ typedef struct dmaChannelDescriptor_s {
|
||||||
#define DMA_IT_DMEIF ((uint32_t)0x00000004)
|
#define DMA_IT_DMEIF ((uint32_t)0x00000004)
|
||||||
#define DMA_IT_FEIF ((uint32_t)0x00000001)
|
#define DMA_IT_FEIF ((uint32_t)0x00000001)
|
||||||
|
|
||||||
|
dmaIdentifier_e dmaGetIdentifier(const DMA_Stream_TypeDef* stream);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -78,24 +95,22 @@ typedef enum {
|
||||||
DMA1_CH5_HANDLER,
|
DMA1_CH5_HANDLER,
|
||||||
DMA1_CH6_HANDLER,
|
DMA1_CH6_HANDLER,
|
||||||
DMA1_CH7_HANDLER,
|
DMA1_CH7_HANDLER,
|
||||||
|
#if defined(STM32F3) || defined(STM32F10X_CL)
|
||||||
DMA2_CH1_HANDLER,
|
DMA2_CH1_HANDLER,
|
||||||
DMA2_CH2_HANDLER,
|
DMA2_CH2_HANDLER,
|
||||||
DMA2_CH3_HANDLER,
|
DMA2_CH3_HANDLER,
|
||||||
DMA2_CH4_HANDLER,
|
DMA2_CH4_HANDLER,
|
||||||
DMA2_CH5_HANDLER,
|
DMA2_CH5_HANDLER,
|
||||||
} dmaHandlerIdentifier_e;
|
#endif
|
||||||
|
DMA_MAX_DESCRIPTORS
|
||||||
|
} dmaIdentifier_e;
|
||||||
|
|
||||||
typedef struct dmaChannelDescriptor_s {
|
#define DMA_MOD_VALUE 7
|
||||||
DMA_TypeDef* dma;
|
#define DMA_MOD_OFFSET 1
|
||||||
DMA_Channel_TypeDef* channel;
|
#define DMA_OUTPUT_INDEX 0
|
||||||
dmaCallbackHandlerFuncPtr irqHandlerCallback;
|
#define DMA_OUTPUT_STRING "DMA%d Channel %d:"
|
||||||
uint8_t flagsShift;
|
|
||||||
IRQn_Type irqN;
|
|
||||||
uint32_t rcc;
|
|
||||||
uint32_t userParam;
|
|
||||||
} dmaChannelDescriptor_t;
|
|
||||||
|
|
||||||
#define DEFINE_DMA_CHANNEL(d, c, f, i, r) {.dma = d, .channel = c, .irqHandlerCallback = NULL, .flagsShift = f, .irqN = i, .rcc = r, .userParam = 0}
|
#define DEFINE_DMA_CHANNEL(d, c, f, i, r) {.dma = d, .channel = c, .irqHandlerCallback = NULL, .flagsShift = f, .irqN = i, .rcc = r, .userParam = 0, .owner = 0, .resourceIndex = 0 }
|
||||||
#define DEFINE_DMA_IRQ_HANDLER(d, c, i) void DMA ## d ## _Channel ## c ## _IRQHandler(void) {\
|
#define DEFINE_DMA_IRQ_HANDLER(d, c, i) void DMA ## d ## _Channel ## c ## _IRQHandler(void) {\
|
||||||
if (dmaDescriptors[i].irqHandlerCallback)\
|
if (dmaDescriptors[i].irqHandlerCallback)\
|
||||||
dmaDescriptors[i].irqHandlerCallback(&dmaDescriptors[i]);\
|
dmaDescriptors[i].irqHandlerCallback(&dmaDescriptors[i]);\
|
||||||
|
@ -108,8 +123,12 @@ typedef struct dmaChannelDescriptor_s {
|
||||||
#define DMA_IT_HTIF ((uint32_t)0x00000004)
|
#define DMA_IT_HTIF ((uint32_t)0x00000004)
|
||||||
#define DMA_IT_TEIF ((uint32_t)0x00000008)
|
#define DMA_IT_TEIF ((uint32_t)0x00000008)
|
||||||
|
|
||||||
|
dmaIdentifier_e dmaGetIdentifier(const DMA_Channel_TypeDef* channel);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void dmaInit(void);
|
void dmaInit(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex);
|
||||||
void dmaSetHandler(dmaHandlerIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam);
|
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam);
|
||||||
|
|
||||||
|
resourceOwner_e dmaGetOwner(dmaIdentifier_e identifier);
|
||||||
|
uint8_t dmaGetResourceIndex(dmaIdentifier_e identifier);
|
||||||
|
|
|
@ -23,11 +23,12 @@
|
||||||
|
|
||||||
#include "nvic.h"
|
#include "nvic.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DMA descriptors.
|
* DMA descriptors.
|
||||||
*/
|
*/
|
||||||
static dmaChannelDescriptor_t dmaDescriptors[] = {
|
static dmaChannelDescriptor_t dmaDescriptors[DMA_MAX_DESCRIPTORS] = {
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream0, 0, DMA1_Stream0_IRQn, RCC_AHB1Periph_DMA1),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream0, 0, DMA1_Stream0_IRQn, RCC_AHB1Periph_DMA1),
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream1, 6, DMA1_Stream1_IRQn, RCC_AHB1Periph_DMA1),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream1, 6, DMA1_Stream1_IRQn, RCC_AHB1Periph_DMA1),
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream2, 16, DMA1_Stream2_IRQn, RCC_AHB1Periph_DMA1),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream2, 16, DMA1_Stream2_IRQn, RCC_AHB1Periph_DMA1),
|
||||||
|
@ -67,12 +68,14 @@ DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER)
|
||||||
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
|
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
|
||||||
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_ST7_HANDLER)
|
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_ST7_HANDLER)
|
||||||
|
|
||||||
void dmaInit(void)
|
void dmaInit(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex)
|
||||||
{
|
{
|
||||||
// TODO: Do we need this?
|
RCC_AHB1PeriphClockCmd(dmaDescriptors[identifier].rcc, ENABLE);
|
||||||
|
dmaDescriptors[identifier].owner = owner;
|
||||||
|
dmaDescriptors[identifier].resourceIndex = resourceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmaSetHandler(dmaHandlerIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
||||||
{
|
{
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
|
@ -101,3 +104,23 @@ uint32_t dmaFlag_IT_TCIF(const DMA_Stream_TypeDef *stream)
|
||||||
RETURN_TCIF_FLAG(stream, 7);
|
RETURN_TCIF_FLAG(stream, 7);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resourceOwner_e dmaGetOwner(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dmaGetResourceIndex(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].resourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmaIdentifier_e dmaGetIdentifier(const DMA_Stream_TypeDef* stream)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DMA_MAX_DESCRIPTORS; i++) {
|
||||||
|
if (dmaDescriptors[i].stream == stream) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -23,11 +23,12 @@
|
||||||
|
|
||||||
#include "drivers/nvic.h"
|
#include "drivers/nvic.h"
|
||||||
#include "drivers/dma.h"
|
#include "drivers/dma.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DMA descriptors.
|
* DMA descriptors.
|
||||||
*/
|
*/
|
||||||
static dmaChannelDescriptor_t dmaDescriptors[] = {
|
static dmaChannelDescriptor_t dmaDescriptors[DMA_MAX_DESCRIPTORS] = {
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream0, 0, DMA1_Stream0_IRQn, RCC_AHB1ENR_DMA1EN),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream0, 0, DMA1_Stream0_IRQn, RCC_AHB1ENR_DMA1EN),
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream1, 6, DMA1_Stream1_IRQn, RCC_AHB1ENR_DMA1EN),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream1, 6, DMA1_Stream1_IRQn, RCC_AHB1ENR_DMA1EN),
|
||||||
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream2, 16, DMA1_Stream2_IRQn, RCC_AHB1ENR_DMA1EN),
|
DEFINE_DMA_CHANNEL(DMA1, DMA1_Stream2, 16, DMA1_Stream2_IRQn, RCC_AHB1ENR_DMA1EN),
|
||||||
|
@ -68,30 +69,50 @@ DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_ST5_HANDLER)
|
||||||
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
|
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_ST6_HANDLER)
|
||||||
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_ST7_HANDLER)
|
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_ST7_HANDLER)
|
||||||
|
|
||||||
|
static void enableDmaClock(uint32_t rcc)
|
||||||
void dmaInit(void)
|
|
||||||
{
|
{
|
||||||
// TODO: Do we need this?
|
|
||||||
}
|
|
||||||
|
|
||||||
void dmaSetHandler(dmaHandlerIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
|
||||||
{
|
|
||||||
//clock
|
|
||||||
//RCC_AHB1PeriphClockCmd(dmaDescriptors[identifier].rcc, ENABLE);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
__IO uint32_t tmpreg;
|
__IO uint32_t tmpreg;
|
||||||
SET_BIT(RCC->AHB1ENR, dmaDescriptors[identifier].rcc);
|
SET_BIT(RCC->AHB1ENR, rcc);
|
||||||
/* Delay after an RCC peripheral clock enabling */
|
/* Delay after an RCC peripheral clock enabling */
|
||||||
tmpreg = READ_BIT(RCC->AHB1ENR, dmaDescriptors[identifier].rcc);
|
tmpreg = READ_BIT(RCC->AHB1ENR, rcc);
|
||||||
UNUSED(tmpreg);
|
UNUSED(tmpreg);
|
||||||
} while(0);
|
} while(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmaInit(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex)
|
||||||
|
{
|
||||||
|
enableDmaClock(dmaDescriptors[identifier].rcc);
|
||||||
|
dmaDescriptors[identifier].owner = owner;
|
||||||
|
dmaDescriptors[identifier].resourceIndex = resourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
|
||||||
|
{
|
||||||
|
enableDmaClock(dmaDescriptors[identifier].rcc);
|
||||||
dmaDescriptors[identifier].irqHandlerCallback = callback;
|
dmaDescriptors[identifier].irqHandlerCallback = callback;
|
||||||
dmaDescriptors[identifier].userParam = userParam;
|
dmaDescriptors[identifier].userParam = userParam;
|
||||||
|
|
||||||
|
|
||||||
HAL_NVIC_SetPriority(dmaDescriptors[identifier].irqN, NVIC_PRIORITY_BASE(priority), NVIC_PRIORITY_SUB(priority));
|
HAL_NVIC_SetPriority(dmaDescriptors[identifier].irqN, NVIC_PRIORITY_BASE(priority), NVIC_PRIORITY_SUB(priority));
|
||||||
HAL_NVIC_EnableIRQ(dmaDescriptors[identifier].irqN);
|
HAL_NVIC_EnableIRQ(dmaDescriptors[identifier].irqN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resourceOwner_e dmaGetOwner(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dmaGetResourceIndex(dmaIdentifier_e identifier)
|
||||||
|
{
|
||||||
|
return dmaDescriptors[identifier].resourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmaIdentifier_e dmaGetIdentifier(const DMA_Stream_TypeDef* stream)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DMA_MAX_DESCRIPTORS; i++) {
|
||||||
|
if (dmaDescriptors[i].stream == stream) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -56,6 +56,12 @@ void EXTIInit(void)
|
||||||
#if defined(STM32F3) || defined(STM32F4)
|
#if defined(STM32F3) || defined(STM32F4)
|
||||||
/* Enable SYSCFG clock otherwise the EXTI irq handlers are not called */
|
/* Enable SYSCFG clock otherwise the EXTI irq handlers are not called */
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
|
||||||
|
#ifdef REMAP_TIM16_DMA
|
||||||
|
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM16, ENABLE);
|
||||||
|
#endif
|
||||||
|
#ifdef REMAP_TIM17_DMA
|
||||||
|
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17, ENABLE);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
memset(extiChannelRecs, 0, sizeof(extiChannelRecs));
|
memset(extiChannelRecs, 0, sizeof(extiChannelRecs));
|
||||||
memset(extiGroupPriority, 0xff, sizeof(extiGroupPriority));
|
memset(extiGroupPriority, 0xff, sizeof(extiGroupPriority));
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 "common/utils.h"
|
#include "common/utils.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
@ -65,7 +82,7 @@ const struct ioPortDef_s ioPortDefs[] = {
|
||||||
const char * const ownerNames[OWNER_TOTAL_COUNT] = {
|
const char * const ownerNames[OWNER_TOTAL_COUNT] = {
|
||||||
"FREE", "PWM", "PPM", "MOTOR", "SERVO", "SOFTSERIAL", "ADC", "SERIAL", "DEBUG", "TIMER",
|
"FREE", "PWM", "PPM", "MOTOR", "SERVO", "SOFTSERIAL", "ADC", "SERIAL", "DEBUG", "TIMER",
|
||||||
"SONAR_TRIGGER", "SONAR_ECHO", "SYSTEM", "SPI", "I2C", "SDCARD", "FLASH", "USB", "BEEPER", "OSD",
|
"SONAR_TRIGGER", "SONAR_ECHO", "SYSTEM", "SPI", "I2C", "SDCARD", "FLASH", "USB", "BEEPER", "OSD",
|
||||||
"BARO", "MPU", "INVERTER", "LED_STRIP", "LED", "RX", "TX", "SOFT_SPI", "RX_SPI"
|
"BARO", "MPU", "INVERTER", "LED_STRIP", "LED", "RX", "TX", "SOFT_SPI", "RX_SPI", "MAX7456"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char * const resourceNames[RESOURCE_TOTAL_COUNT] = {
|
const char * const resourceNames[RESOURCE_TOTAL_COUNT] = {
|
||||||
|
@ -231,7 +248,7 @@ void IOToggle(IO_t io)
|
||||||
}
|
}
|
||||||
|
|
||||||
// claim IO pin, set owner and resources
|
// claim IO pin, set owner and resources
|
||||||
void IOInit(IO_t io, resourceOwner_t owner, resourceType_t resource, uint8_t index)
|
void IOInit(IO_t io, resourceOwner_e owner, resourceType_e resource, uint8_t index)
|
||||||
{
|
{
|
||||||
ioRec_t *ioRec = IO_Rec(io);
|
ioRec_t *ioRec = IO_Rec(io);
|
||||||
ioRec->owner = owner;
|
ioRec->owner = owner;
|
||||||
|
@ -245,13 +262,13 @@ void IORelease(IO_t io)
|
||||||
ioRec->owner = OWNER_FREE;
|
ioRec->owner = OWNER_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceOwner_t IOGetOwner(IO_t io)
|
resourceOwner_e IOGetOwner(IO_t io)
|
||||||
{
|
{
|
||||||
ioRec_t *ioRec = IO_Rec(io);
|
ioRec_t *ioRec = IO_Rec(io);
|
||||||
return ioRec->owner;
|
return ioRec->owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceType_t IOGetResource(IO_t io)
|
resourceType_e IOGetResource(IO_t io)
|
||||||
{
|
{
|
||||||
ioRec_t *ioRec = IO_Rec(io);
|
ioRec_t *ioRec = IO_Rec(io);
|
||||||
return ioRec->resource;
|
return ioRec->resource;
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -84,10 +101,10 @@ void IOHi(IO_t io);
|
||||||
void IOLo(IO_t io);
|
void IOLo(IO_t io);
|
||||||
void IOToggle(IO_t io);
|
void IOToggle(IO_t io);
|
||||||
|
|
||||||
void IOInit(IO_t io, resourceOwner_t owner, resourceType_t resource, uint8_t index);
|
void IOInit(IO_t io, resourceOwner_e owner, resourceType_e resource, uint8_t index);
|
||||||
void IORelease(IO_t io); // unimplemented
|
void IORelease(IO_t io); // unimplemented
|
||||||
resourceOwner_t IOGetOwner(IO_t io);
|
resourceOwner_e IOGetOwner(IO_t io);
|
||||||
resourceType_t IOGetResources(IO_t io);
|
resourceType_e IOGetResources(IO_t io);
|
||||||
IO_t IOGetByTag(ioTag_t tag);
|
IO_t IOGetByTag(ioTag_t tag);
|
||||||
|
|
||||||
void IOConfigGPIO(IO_t io, ioConfig_t cfg);
|
void IOConfigGPIO(IO_t io, ioConfig_t cfg);
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
#pragma once
|
||||||
|
|
||||||
#include "common/utils.h"
|
#include "common/utils.h"
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
#pragma once
|
||||||
// this file is automatically generated by def_generated.pl script
|
// this file is automatically generated by def_generated.pl script
|
||||||
// do not modify this file directly, your changes will be lost
|
// do not modify this file directly, your changes will be lost
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
#pragma once
|
||||||
|
|
||||||
// TODO - GPIO_TypeDef include
|
// TODO - GPIO_TypeDef include
|
||||||
|
@ -11,8 +28,8 @@ typedef struct ioDef_s {
|
||||||
typedef struct ioRec_s {
|
typedef struct ioRec_s {
|
||||||
GPIO_TypeDef *gpio;
|
GPIO_TypeDef *gpio;
|
||||||
uint16_t pin;
|
uint16_t pin;
|
||||||
resourceOwner_t owner;
|
resourceOwner_e owner;
|
||||||
resourceType_t resource;
|
resourceType_e resource;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
} ioRec_t;
|
} ioRec_t;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -8,7 +25,7 @@ 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
|
typedef void* IO_t; // type specifying IO pin. Currently ioRec_t pointer, but this may change
|
||||||
|
|
||||||
// NONE initializer for ioTag_t variables
|
// NONE initializer for ioTag_t variables
|
||||||
#define IO_TAG_NONE ((ioTag_t)0)
|
#define IO_TAG_NONE IO_TAG(NONE)
|
||||||
|
|
||||||
// NONE initializer for IO_t variable
|
// NONE initializer for IO_t variable
|
||||||
#define IO_NONE ((IO_t)0)
|
#define IO_NONE ((IO_t)0)
|
||||||
|
|
|
@ -37,12 +37,13 @@
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "common/colorconversion.h"
|
#include "common/colorconversion.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
#include "io.h"
|
||||||
#include "light_ws2811strip.h"
|
#include "light_ws2811strip.h"
|
||||||
|
|
||||||
#if defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F1)
|
||||||
uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
|
|
||||||
#else
|
|
||||||
uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
|
uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
|
||||||
|
#else
|
||||||
|
uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
|
||||||
#endif
|
#endif
|
||||||
volatile uint8_t ws2811LedDataTransferInProgress = 0;
|
volatile uint8_t ws2811LedDataTransferInProgress = 0;
|
||||||
|
|
||||||
|
@ -84,10 +85,13 @@ void setStripColors(const hsvColor_t *colors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripInit(void)
|
void ws2811LedStripInit(ioTag_t ioTag)
|
||||||
{
|
{
|
||||||
memset(&ledStripDMABuffer, 0, WS2811_DMA_BUFFER_SIZE);
|
memset(&ledStripDMABuffer, 0, WS2811_DMA_BUFFER_SIZE);
|
||||||
ws2811LedStripHardwareInit();
|
ws2811LedStripHardwareInit(ioTag);
|
||||||
|
|
||||||
|
const hsvColor_t hsv_white = { 0, 255, 255};
|
||||||
|
setStripColor(&hsv_white);
|
||||||
ws2811UpdateStrip();
|
ws2811UpdateStrip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,28 +17,41 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "io_types.h"
|
||||||
|
|
||||||
#define WS2811_LED_STRIP_LENGTH 32
|
#define WS2811_LED_STRIP_LENGTH 32
|
||||||
#define WS2811_BITS_PER_LED 24
|
#define WS2811_BITS_PER_LED 24
|
||||||
#define WS2811_DELAY_BUFFER_LENGTH 42 // for 50us delay
|
// for 50us delay
|
||||||
|
#define WS2811_DELAY_BUFFER_LENGTH 42
|
||||||
|
|
||||||
#define WS2811_DATA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH)
|
#define WS2811_DATA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH)
|
||||||
|
// number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
|
||||||
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE + WS2811_DELAY_BUFFER_LENGTH) // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
|
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE + WS2811_DELAY_BUFFER_LENGTH)
|
||||||
|
|
||||||
#if defined(STM32F40_41xxx)
|
#if defined(STM32F40_41xxx)
|
||||||
#define BIT_COMPARE_1 67 // timer compare value for logical 1
|
#define WS2811_TIMER_HZ 84000000
|
||||||
#define BIT_COMPARE_0 33 // timer compare value for logical 0
|
#define WS2811_TIMER_PERIOD 104
|
||||||
|
// timer compare value for logical 1
|
||||||
|
#define BIT_COMPARE_1 67
|
||||||
|
// timer compare value for logical 0
|
||||||
|
#define BIT_COMPARE_0 33
|
||||||
#elif defined(STM32F7)
|
#elif defined(STM32F7)
|
||||||
#define BIT_COMPARE_1 76 // timer compare value for logical 1
|
// timer compare value for logical 1
|
||||||
#define BIT_COMPARE_0 38 // timer compare value for logical 0
|
#define BIT_COMPARE_1 76
|
||||||
|
// timer compare value for logical 0
|
||||||
|
#define BIT_COMPARE_0 38
|
||||||
#else
|
#else
|
||||||
#define BIT_COMPARE_1 17 // timer compare value for logical 1
|
#define WS2811_TIMER_HZ 24000000
|
||||||
#define BIT_COMPARE_0 9 // timer compare value for logical 0
|
#define WS2811_TIMER_PERIOD 29
|
||||||
|
// timer compare value for logical 1
|
||||||
|
#define BIT_COMPARE_1 17
|
||||||
|
// timer compare value for logical 0
|
||||||
|
#define BIT_COMPARE_0 9
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ws2811LedStripInit(void);
|
void ws2811LedStripInit(ioTag_t ioTag);
|
||||||
|
|
||||||
void ws2811LedStripHardwareInit(void);
|
void ws2811LedStripHardwareInit(ioTag_t ioTag);
|
||||||
void ws2811LedStripDMAEnable(void);
|
void ws2811LedStripDMAEnable(void);
|
||||||
|
|
||||||
void ws2811UpdateStrip(void);
|
void ws2811UpdateStrip(void);
|
||||||
|
@ -54,9 +67,9 @@ void setStripColors(const hsvColor_t *colors);
|
||||||
|
|
||||||
bool isWS2811LedStripReady(void);
|
bool isWS2811LedStripReady(void);
|
||||||
|
|
||||||
#if defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F1)
|
||||||
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];
|
||||||
|
#else
|
||||||
|
extern uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
|
||||||
#endif
|
#endif
|
||||||
extern volatile uint8_t ws2811LedDataTransferInProgress;
|
extern volatile uint8_t ws2811LedDataTransferInProgress;
|
||||||
|
|
|
@ -31,26 +31,15 @@
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
#if !defined(WS2811_PIN)
|
|
||||||
#define WS2811_PIN PA0
|
|
||||||
#define WS2811_TIMER TIM5
|
|
||||||
#define WS2811_DMA_HANDLER_IDENTIFER DMA1_ST2_HANDLER
|
|
||||||
#define WS2811_DMA_STREAM DMA1_Stream2
|
|
||||||
#define WS2811_DMA_IT DMA_IT_TCIF2
|
|
||||||
#define WS2811_DMA_CHANNEL DMA_Channel_6
|
|
||||||
#define WS2811_TIMER_CHANNEL TIM_Channel_1
|
|
||||||
#define WS2811_TIMER_GPIO_AF GPIO_AF2_TIM5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static IO_t ws2811IO = IO_NONE;
|
static IO_t ws2811IO = IO_NONE;
|
||||||
static uint16_t timDMASource = 0;
|
|
||||||
bool ws2811Initialised = false;
|
bool ws2811Initialised = false;
|
||||||
|
|
||||||
static TIM_HandleTypeDef TimHandle;
|
static TIM_HandleTypeDef TimHandle;
|
||||||
|
static uint16_t timerChannel = 0;
|
||||||
|
|
||||||
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
|
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
|
||||||
{
|
{
|
||||||
if(htim->Instance==WS2811_TIMER)
|
if(htim->Instance == TimHandle.Instance)
|
||||||
{
|
{
|
||||||
//HAL_TIM_PWM_Stop_DMA(&TimHandle,WS2811_TIMER_CHANNEL);
|
//HAL_TIM_PWM_Stop_DMA(&TimHandle,WS2811_TIMER_CHANNEL);
|
||||||
ws2811LedDataTransferInProgress = 0;
|
ws2811LedDataTransferInProgress = 0;
|
||||||
|
@ -62,9 +51,20 @@ void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t* descriptor)
|
||||||
HAL_DMA_IRQHandler(TimHandle.hdma[descriptor->userParam]);
|
HAL_DMA_IRQHandler(TimHandle.hdma[descriptor->userParam]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripHardwareInit(void)
|
void ws2811LedStripHardwareInit(ioTag_t ioTag)
|
||||||
{
|
{
|
||||||
TimHandle.Instance = WS2811_TIMER;
|
if (!ioTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timerHardware_t *timerHardware = timerGetByTag(ioTag, TIM_USE_ANY);
|
||||||
|
TIM_TypeDef *timer = timerHardware->tim;
|
||||||
|
timerChannel = timerHardware->channel;
|
||||||
|
|
||||||
|
if (timerHardware->dmaStream == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TimHandle.Instance = timer;
|
||||||
|
|
||||||
TimHandle.Init.Prescaler = 1;
|
TimHandle.Init.Prescaler = 1;
|
||||||
TimHandle.Init.Period = 135; // 800kHz
|
TimHandle.Init.Period = 135; // 800kHz
|
||||||
|
@ -78,16 +78,14 @@ void ws2811LedStripHardwareInit(void)
|
||||||
|
|
||||||
static DMA_HandleTypeDef hdma_tim;
|
static DMA_HandleTypeDef hdma_tim;
|
||||||
|
|
||||||
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
ws2811IO = IOGetByTag(ioTag);
|
||||||
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
|
|
||||||
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
||||||
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP), WS2811_TIMER_GPIO_AF);
|
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP), timerHardware->alternateFunction);
|
||||||
|
|
||||||
__DMA1_CLK_ENABLE();
|
__DMA1_CLK_ENABLE();
|
||||||
|
|
||||||
|
|
||||||
/* Set the parameters to be configured */
|
/* Set the parameters to be configured */
|
||||||
hdma_tim.Init.Channel = WS2811_DMA_CHANNEL;
|
hdma_tim.Init.Channel = timerHardware->dmaChannel;
|
||||||
hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||||
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
|
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
|
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
|
@ -101,35 +99,18 @@ void ws2811LedStripHardwareInit(void)
|
||||||
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
||||||
|
|
||||||
/* Set hdma_tim instance */
|
/* Set hdma_tim instance */
|
||||||
hdma_tim.Instance = WS2811_DMA_STREAM;
|
hdma_tim.Instance = timerHardware->dmaStream;
|
||||||
|
|
||||||
uint32_t channelAddress = 0;
|
uint16_t dmaSource = timerDmaSource(timerChannel);
|
||||||
switch (WS2811_TIMER_CHANNEL) {
|
|
||||||
case TIM_CHANNEL_1:
|
|
||||||
timDMASource = TIM_DMA_ID_CC1;
|
|
||||||
channelAddress = (uint32_t)(&WS2811_TIMER->CCR1);
|
|
||||||
break;
|
|
||||||
case TIM_CHANNEL_2:
|
|
||||||
timDMASource = TIM_DMA_ID_CC2;
|
|
||||||
channelAddress = (uint32_t)(&WS2811_TIMER->CCR2);
|
|
||||||
break;
|
|
||||||
case TIM_CHANNEL_3:
|
|
||||||
timDMASource = TIM_DMA_ID_CC3;
|
|
||||||
channelAddress = (uint32_t)(&WS2811_TIMER->CCR3);
|
|
||||||
break;
|
|
||||||
case TIM_CHANNEL_4:
|
|
||||||
timDMASource = TIM_DMA_ID_CC4;
|
|
||||||
channelAddress = (uint32_t)(&WS2811_TIMER->CCR4);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link hdma_tim to hdma[x] (channelx) */
|
/* Link hdma_tim to hdma[x] (channelx) */
|
||||||
__HAL_LINKDMA(&TimHandle, hdma[timDMASource], hdma_tim);
|
__HAL_LINKDMA(&TimHandle, hdma[dmaSource], hdma_tim);
|
||||||
|
|
||||||
dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, timDMASource);
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_LED_STRIP, 0);
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, dmaSource);
|
||||||
|
|
||||||
/* Initialize TIMx DMA handle */
|
/* Initialize TIMx DMA handle */
|
||||||
if(HAL_DMA_Init(TimHandle.hdma[timDMASource]) != HAL_OK)
|
if(HAL_DMA_Init(TimHandle.hdma[dmaSource]) != HAL_OK)
|
||||||
{
|
{
|
||||||
/* Initialization Error */
|
/* Initialization Error */
|
||||||
return;
|
return;
|
||||||
|
@ -145,15 +126,13 @@ void ws2811LedStripHardwareInit(void)
|
||||||
TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||||
TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
|
TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
|
||||||
|
|
||||||
if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &TIM_OCInitStructure, WS2811_TIMER_CHANNEL) != HAL_OK)
|
if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &TIM_OCInitStructure, timerChannel) != HAL_OK)
|
||||||
{
|
{
|
||||||
/* Configuration Error */
|
/* Configuration Error */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hsvColor_t hsv_white = { 0, 255, 255};
|
|
||||||
ws2811Initialised = true;
|
ws2811Initialised = true;
|
||||||
setStripColor(&hsv_white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,7 +144,7 @@ void ws2811LedStripDMAEnable(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( HAL_TIM_PWM_Start_DMA(&TimHandle, WS2811_TIMER_CHANNEL, ledStripDMABuffer, WS2811_DMA_BUFFER_SIZE) != HAL_OK)
|
if (HAL_TIM_PWM_Start_DMA(&TimHandle, timerChannel, ledStripDMABuffer, WS2811_DMA_BUFFER_SIZE) != HAL_OK)
|
||||||
{
|
{
|
||||||
/* Starting PWM generation Error */
|
/* Starting PWM generation Error */
|
||||||
ws2811LedDataTransferInProgress = 0;
|
ws2811LedDataTransferInProgress = 0;
|
||||||
|
|
|
@ -32,8 +32,11 @@
|
||||||
|
|
||||||
static IO_t ws2811IO = IO_NONE;
|
static IO_t ws2811IO = IO_NONE;
|
||||||
bool ws2811Initialised = false;
|
bool ws2811Initialised = false;
|
||||||
|
static DMA_Channel_TypeDef *dmaChannel = NULL;
|
||||||
|
static TIM_TypeDef *timer = NULL;
|
||||||
|
|
||||||
static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) {
|
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->channel, DISABLE);
|
DMA_Cmd(descriptor->channel, DISABLE);
|
||||||
|
@ -41,32 +44,38 @@ static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripHardwareInit(void)
|
void ws2811LedStripHardwareInit(ioTag_t ioTag)
|
||||||
{
|
{
|
||||||
|
if (!ioTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
TIM_OCInitTypeDef TIM_OCInitStructure;
|
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||||
DMA_InitTypeDef DMA_InitStructure;
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
||||||
uint16_t prescalerValue;
|
const timerHardware_t *timerHardware = timerGetByTag(ioTag, TIM_USE_ANY);
|
||||||
|
timer = timerHardware->tim;
|
||||||
|
|
||||||
dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
if (timerHardware->dmaChannel == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
ws2811IO = IOGetByTag(ioTag);
|
||||||
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
|
|
||||||
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
||||||
IOConfigGPIO(ws2811IO, IO_CONFIG(GPIO_Speed_50MHz, GPIO_Mode_AF_PP));
|
IOConfigGPIO(ws2811IO, IO_CONFIG(GPIO_Speed_50MHz, GPIO_Mode_AF_PP));
|
||||||
|
|
||||||
RCC_ClockCmd(timerRCC(WS2811_TIMER), ENABLE);
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
|
|
||||||
/* Compute the prescaler value */
|
/* Compute the prescaler value */
|
||||||
prescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
|
uint16_t prescalerValue = (uint16_t) (SystemCoreClock / WS2811_TIMER_HZ) - 1;
|
||||||
/* Time base configuration */
|
/* Time base configuration */
|
||||||
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
||||||
TIM_TimeBaseStructure.TIM_Period = 29; // 800kHz
|
TIM_TimeBaseStructure.TIM_Period = WS2811_TIMER_PERIOD; // 800kHz
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
|
|
||||||
/* PWM1 Mode configuration: Channel1 */
|
/* PWM1 Mode configuration: Channel1 */
|
||||||
TIM_OCStructInit(&TIM_OCInitStructure);
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
|
@ -74,20 +83,18 @@ void ws2811LedStripHardwareInit(void)
|
||||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
||||||
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
|
TIM_OC1Init(timer, &TIM_OCInitStructure);
|
||||||
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
|
TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
|
||||||
TIM_CtrlPWMOutputs(TIM3, ENABLE);
|
TIM_CtrlPWMOutputs(timer, ENABLE);
|
||||||
|
|
||||||
/* configure DMA */
|
/* configure DMA */
|
||||||
/* DMA clock enable */
|
|
||||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
|
||||||
|
|
||||||
/* DMA1 Channel6 Config */
|
/* DMA1 Channel6 Config */
|
||||||
DMA_DeInit(DMA1_Channel6);
|
dmaChannel = timerHardware->dmaChannel;
|
||||||
|
DMA_DeInit(dmaChannel);
|
||||||
|
|
||||||
DMA_StructInit(&DMA_InitStructure);
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM3->CCR1;
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerCCR(timer, timerHardware->channel);
|
||||||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ledStripDMABuffer;
|
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ledStripDMABuffer;
|
||||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||||
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
||||||
|
@ -99,17 +106,17 @@ void ws2811LedStripHardwareInit(void)
|
||||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||||
|
|
||||||
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
|
DMA_Init(dmaChannel, &DMA_InitStructure);
|
||||||
|
|
||||||
/* TIM3 CC1 DMA Request enable */
|
/* TIM3 CC1 DMA Request enable */
|
||||||
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
|
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
|
||||||
|
|
||||||
DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
|
DMA_ITConfig(dmaChannel, DMA_IT_TC, ENABLE);
|
||||||
|
|
||||||
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_LED_STRIP, 0);
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
||||||
|
|
||||||
const hsvColor_t hsv_white = { 0, 255, 255};
|
|
||||||
ws2811Initialised = true;
|
ws2811Initialised = true;
|
||||||
setStripColor(&hsv_white);
|
|
||||||
ws2811UpdateStrip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripDMAEnable(void)
|
void ws2811LedStripDMAEnable(void)
|
||||||
|
@ -117,10 +124,10 @@ void ws2811LedStripDMAEnable(void)
|
||||||
if (!ws2811Initialised)
|
if (!ws2811Initialised)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DMA_SetCurrDataCounter(DMA1_Channel6, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
DMA_SetCurrDataCounter(dmaChannel, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
||||||
TIM_SetCounter(TIM3, 0);
|
TIM_SetCounter(timer, 0);
|
||||||
TIM_Cmd(TIM3, ENABLE);
|
TIM_Cmd(timer, ENABLE);
|
||||||
DMA_Cmd(DMA1_Channel6, ENABLE);
|
DMA_Cmd(dmaChannel, ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,18 +31,13 @@
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
#ifndef WS2811_PIN
|
|
||||||
#define WS2811_PIN PB8 // TIM16_CH1
|
|
||||||
#define WS2811_TIMER TIM16
|
|
||||||
#define WS2811_DMA_CHANNEL DMA1_Channel3
|
|
||||||
#define WS2811_DMA_HANDLER_IDENTIFER DMA1_CH3_HANDLER
|
|
||||||
#define WS2811_TIMER_GPIO_AF GPIO_AF_1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static IO_t ws2811IO = IO_NONE;
|
static IO_t ws2811IO = IO_NONE;
|
||||||
bool ws2811Initialised = false;
|
bool ws2811Initialised = false;
|
||||||
|
static DMA_Channel_TypeDef *dmaChannel = NULL;
|
||||||
|
static TIM_TypeDef *timer = NULL;
|
||||||
|
|
||||||
static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) {
|
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->channel, DISABLE);
|
DMA_Cmd(descriptor->channel, DISABLE);
|
||||||
|
@ -50,72 +45,85 @@ static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripHardwareInit(void)
|
void ws2811LedStripHardwareInit(ioTag_t ioTag)
|
||||||
{
|
{
|
||||||
|
if (!ioTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
TIM_OCInitTypeDef TIM_OCInitStructure;
|
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||||
DMA_InitTypeDef DMA_InitStructure;
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
||||||
uint16_t prescalerValue;
|
const timerHardware_t *timerHardware = timerGetByTag(ioTag, TIM_USE_ANY);
|
||||||
|
timer = timerHardware->tim;
|
||||||
|
|
||||||
dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
if (timerHardware->dmaChannel == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
ws2811IO = IOGetByTag(ioTag);
|
||||||
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
|
|
||||||
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
||||||
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), WS2811_TIMER_GPIO_AF);
|
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
|
||||||
|
|
||||||
RCC_ClockCmd(timerRCC(WS2811_TIMER), ENABLE);
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
|
|
||||||
/* Compute the prescaler value */
|
/* Compute the prescaler value */
|
||||||
prescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
|
uint16_t prescalerValue = (uint16_t) (SystemCoreClock / WS2811_TIMER_HZ) - 1;
|
||||||
|
|
||||||
/* Time base configuration */
|
/* Time base configuration */
|
||||||
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
||||||
TIM_TimeBaseStructure.TIM_Period = 29; // 800kHz
|
TIM_TimeBaseStructure.TIM_Period = WS2811_TIMER_PERIOD; // 800kHz
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
TIM_TimeBaseInit(WS2811_TIMER, &TIM_TimeBaseStructure);
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
|
|
||||||
/* PWM1 Mode configuration */
|
/* PWM1 Mode configuration */
|
||||||
TIM_OCStructInit(&TIM_OCInitStructure);
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
|
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
|
} else {
|
||||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
|
||||||
|
}
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
|
||||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
TIM_OC1Init(timer, &TIM_OCInitStructure);
|
||||||
TIM_OC1Init(WS2811_TIMER, &TIM_OCInitStructure);
|
TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
TIM_OC1PreloadConfig(WS2811_TIMER, TIM_OCPreload_Enable);
|
|
||||||
|
|
||||||
|
TIM_CtrlPWMOutputs(timer, ENABLE);
|
||||||
TIM_CtrlPWMOutputs(WS2811_TIMER, ENABLE);
|
|
||||||
|
|
||||||
/* configure DMA */
|
/* configure DMA */
|
||||||
/* DMA1 Channel Config */
|
/* DMA1 Channel Config */
|
||||||
DMA_DeInit(WS2811_DMA_CHANNEL);
|
dmaChannel = timerHardware->dmaChannel;
|
||||||
|
DMA_DeInit(dmaChannel);
|
||||||
|
|
||||||
DMA_StructInit(&DMA_InitStructure);
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&WS2811_TIMER->CCR1;
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerCCR(timer, timerHardware->channel);
|
||||||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ledStripDMABuffer;
|
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ledStripDMABuffer;
|
||||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||||
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
||||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
|
||||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
|
||||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||||
|
|
||||||
DMA_Init(WS2811_DMA_CHANNEL, &DMA_InitStructure);
|
DMA_Init(dmaChannel, &DMA_InitStructure);
|
||||||
|
|
||||||
TIM_DMACmd(WS2811_TIMER, TIM_DMA_CC1, ENABLE);
|
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
|
||||||
|
|
||||||
DMA_ITConfig(WS2811_DMA_CHANNEL, DMA_IT_TC, ENABLE);
|
DMA_ITConfig(dmaChannel, DMA_IT_TC, ENABLE);
|
||||||
|
|
||||||
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_LED_STRIP, 0);
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
||||||
|
|
||||||
const hsvColor_t hsv_white = { 0, 255, 255};
|
|
||||||
ws2811Initialised = true;
|
ws2811Initialised = true;
|
||||||
setStripColor(&hsv_white);
|
|
||||||
ws2811UpdateStrip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripDMAEnable(void)
|
void ws2811LedStripDMAEnable(void)
|
||||||
|
@ -123,10 +131,10 @@ void ws2811LedStripDMAEnable(void)
|
||||||
if (!ws2811Initialised)
|
if (!ws2811Initialised)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DMA_SetCurrDataCounter(WS2811_DMA_CHANNEL, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
DMA_SetCurrDataCounter(dmaChannel, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
||||||
TIM_SetCounter(WS2811_TIMER, 0);
|
TIM_SetCounter(timer, 0);
|
||||||
TIM_Cmd(WS2811_TIMER, ENABLE);
|
TIM_Cmd(timer, ENABLE);
|
||||||
DMA_Cmd(WS2811_DMA_CHANNEL, ENABLE);
|
DMA_Cmd(dmaChannel, ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,85 +31,89 @@
|
||||||
#include "rcc.h"
|
#include "rcc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "timer_stm32f4xx.h"
|
#include "timer_stm32f4xx.h"
|
||||||
|
#include "io.h"
|
||||||
#if !defined(WS2811_PIN)
|
|
||||||
#define WS2811_PIN PA0
|
|
||||||
#define WS2811_TIMER TIM5
|
|
||||||
#define WS2811_DMA_HANDLER_IDENTIFER DMA1_ST2_HANDLER
|
|
||||||
#define WS2811_DMA_STREAM DMA1_Stream2
|
|
||||||
#define WS2811_DMA_CHANNEL DMA_Channel_6
|
|
||||||
#define WS2811_TIMER_CHANNEL TIM_Channel_1
|
|
||||||
#define WS2811_TIMER_GPIO_AF GPIO_AF_TIM5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static IO_t ws2811IO = IO_NONE;
|
static IO_t ws2811IO = IO_NONE;
|
||||||
static uint16_t timDMASource = 0;
|
|
||||||
bool ws2811Initialised = false;
|
bool ws2811Initialised = false;
|
||||||
|
static DMA_Stream_TypeDef *stream = NULL;
|
||||||
|
static TIM_TypeDef *timer = NULL;
|
||||||
|
|
||||||
static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
|
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(WS2811_TIMER, timDMASource, DISABLE);
|
|
||||||
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
|
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripHardwareInit(void)
|
void ws2811LedStripHardwareInit(ioTag_t ioTag)
|
||||||
{
|
{
|
||||||
|
if (!ioTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
TIM_OCInitTypeDef TIM_OCInitStructure;
|
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||||
DMA_InitTypeDef DMA_InitStructure;
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
||||||
uint16_t prescalerValue;
|
const timerHardware_t *timerHardware = timerGetByTag(ioTag, TIM_USE_ANY);
|
||||||
|
timer = timerHardware->tim;
|
||||||
|
|
||||||
RCC_ClockCmd(timerRCC(WS2811_TIMER), ENABLE);
|
if (timerHardware->dmaStream == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
|
|
||||||
|
ws2811IO = IOGetByTag(ioTag);
|
||||||
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
|
/* GPIOA Configuration: TIM5 Channel 1 as alternate function push-pull */
|
||||||
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
||||||
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), WS2811_TIMER_GPIO_AF);
|
IOConfigGPIOAF(ws2811IO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
|
||||||
|
|
||||||
// Stop timer
|
// Stop timer
|
||||||
TIM_Cmd(WS2811_TIMER, DISABLE);
|
TIM_Cmd(timer, DISABLE);
|
||||||
|
|
||||||
/* Compute the prescaler value */
|
/* Compute the prescaler value */
|
||||||
prescalerValue = (uint16_t)(SystemCoreClock / 2 / 84000000) - 1;
|
uint16_t prescalerValue = (uint16_t)(SystemCoreClock / timerClockDivisor(timer) / WS2811_TIMER_HZ) - 1;
|
||||||
|
|
||||||
/* Time base configuration */
|
/* Time base configuration */
|
||||||
TIM_TimeBaseStructure.TIM_Period = 104; // 800kHz
|
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
||||||
|
TIM_TimeBaseStructure.TIM_Period = WS2811_TIMER_PERIOD; // 800kHz
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
TIM_TimeBaseInit(WS2811_TIMER, &TIM_TimeBaseStructure);
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
|
|
||||||
/* PWM1 Mode configuration: Channel1 */
|
/* PWM1 Mode configuration: Channel1 */
|
||||||
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
|
} 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_OCIdleState = TIM_OCIdleState_Set;
|
||||||
|
}
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
|
||||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
|
|
||||||
timerOCInit(WS2811_TIMER, WS2811_TIMER_CHANNEL, &TIM_OCInitStructure);
|
timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure);
|
||||||
timerOCPreloadConfig(WS2811_TIMER, WS2811_TIMER_CHANNEL, TIM_OCPreload_Enable);
|
timerOCPreloadConfig(timer, timerHardware->channel, TIM_OCPreload_Enable);
|
||||||
timDMASource = timerDmaSource(WS2811_TIMER_CHANNEL);
|
|
||||||
|
|
||||||
TIM_CtrlPWMOutputs(WS2811_TIMER, ENABLE);
|
TIM_CtrlPWMOutputs(timer, ENABLE);
|
||||||
TIM_ARRPreloadConfig(WS2811_TIMER, ENABLE);
|
TIM_ARRPreloadConfig(timer, ENABLE);
|
||||||
|
|
||||||
TIM_CCxCmd(WS2811_TIMER, WS2811_TIMER_CHANNEL, TIM_CCx_Enable);
|
TIM_CCxCmd(timer, timerHardware->channel, TIM_CCx_Enable);
|
||||||
TIM_Cmd(WS2811_TIMER, ENABLE);
|
TIM_Cmd(timer, ENABLE);
|
||||||
|
|
||||||
|
stream = timerHardware->dmaStream;
|
||||||
/* configure DMA */
|
/* configure DMA */
|
||||||
DMA_Cmd(WS2811_DMA_STREAM, DISABLE);
|
DMA_Cmd(stream, DISABLE);
|
||||||
DMA_DeInit(WS2811_DMA_STREAM);
|
DMA_DeInit(stream);
|
||||||
DMA_StructInit(&DMA_InitStructure);
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
DMA_InitStructure.DMA_Channel = WS2811_DMA_CHANNEL;
|
DMA_InitStructure.DMA_Channel = timerHardware->dmaChannel;
|
||||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerCCR(WS2811_TIMER, WS2811_TIMER_CHANNEL);
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerCCR(timer, timerHardware->channel);
|
||||||
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ledStripDMABuffer;
|
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ledStripDMABuffer;
|
||||||
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
||||||
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
|
||||||
|
@ -124,17 +128,16 @@ void ws2811LedStripHardwareInit(void)
|
||||||
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
|
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
|
||||||
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
|
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
|
||||||
|
|
||||||
DMA_Init(WS2811_DMA_STREAM, &DMA_InitStructure);
|
DMA_Init(stream, &DMA_InitStructure);
|
||||||
|
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
|
||||||
|
|
||||||
DMA_ITConfig(WS2811_DMA_STREAM, DMA_IT_TC, ENABLE);
|
DMA_ITConfig(stream, DMA_IT_TC, ENABLE);
|
||||||
DMA_ClearITPendingBit(WS2811_DMA_STREAM, dmaFlag_IT_TCIF(WS2811_DMA_STREAM));
|
DMA_ClearITPendingBit(stream, dmaFlag_IT_TCIF(stream));
|
||||||
|
|
||||||
dmaSetHandler(WS2811_DMA_HANDLER_IDENTIFER, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_LED_STRIP, 0);
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, WS2811_DMA_IRQHandler, NVIC_PRIO_WS2811_DMA, 0);
|
||||||
|
|
||||||
const hsvColor_t hsv_white = { 0, 255, 255};
|
|
||||||
ws2811Initialised = true;
|
ws2811Initialised = true;
|
||||||
setStripColor(&hsv_white);
|
|
||||||
ws2811UpdateStrip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2811LedStripDMAEnable(void)
|
void ws2811LedStripDMAEnable(void)
|
||||||
|
@ -142,10 +145,10 @@ void ws2811LedStripDMAEnable(void)
|
||||||
if (!ws2811Initialised)
|
if (!ws2811Initialised)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DMA_SetCurrDataCounter(WS2811_DMA_STREAM, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
DMA_SetCurrDataCounter(stream, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
|
||||||
TIM_SetCounter(WS2811_TIMER, 0);
|
TIM_SetCounter(timer, 0);
|
||||||
DMA_Cmd(WS2811_DMA_STREAM, ENABLE);
|
TIM_Cmd(timer, ENABLE);
|
||||||
TIM_DMACmd(WS2811_TIMER, timDMASource, ENABLE);
|
DMA_Cmd(stream, ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -294,7 +294,7 @@ void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c)
|
||||||
screenBuffer[y*30+x] = c;
|
screenBuffer[y*30+x] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void max7456Write(uint8_t x, uint8_t y, char *buff)
|
void max7456Write(uint8_t x, uint8_t y, const char *buff)
|
||||||
{
|
{
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
for (i = 0; *(buff+i); i++)
|
for (i = 0; *(buff+i); i++)
|
||||||
|
@ -387,7 +387,7 @@ void max7456RefreshAll(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void max7456WriteNvm(uint8_t char_address, uint8_t *font_data)
|
void max7456WriteNvm(uint8_t char_address, const uint8_t *font_data)
|
||||||
{
|
{
|
||||||
uint8_t x;
|
uint8_t x;
|
||||||
|
|
||||||
|
|
|
@ -146,9 +146,9 @@ extern uint16_t maxScreenSize;
|
||||||
|
|
||||||
void max7456Init(uint8_t system);
|
void max7456Init(uint8_t system);
|
||||||
void max7456DrawScreen(void);
|
void max7456DrawScreen(void);
|
||||||
void max7456WriteNvm(uint8_t char_address, uint8_t *font_data);
|
void max7456WriteNvm(uint8_t char_address, const uint8_t *font_data);
|
||||||
uint8_t max7456GetRowsCount(void);
|
uint8_t max7456GetRowsCount(void);
|
||||||
void max7456Write(uint8_t x, uint8_t y, char *buff);
|
void max7456Write(uint8_t x, uint8_t y, const char *buff);
|
||||||
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c);
|
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c);
|
||||||
void max7456ClearScreen(void);
|
void max7456ClearScreen(void);
|
||||||
void max7456RefreshAll(void);
|
void max7456RefreshAll(void);
|
||||||
|
|
|
@ -42,17 +42,18 @@ static void pwmOCConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t value, uint8
|
||||||
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_PWM1;
|
||||||
|
|
||||||
if (output & TIMER_OUTPUT_N_CHANNEL) {
|
if (output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
|
|
||||||
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
|
TIM_OCInitStructure.TIM_OCNPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPolarity_High : TIM_OCNPolarity_Low;
|
||||||
} else {
|
} 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_OCIdleState = TIM_OCIdleState_Set;
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
|
||||||
}
|
}
|
||||||
TIM_OCInitStructure.TIM_Pulse = value;
|
TIM_OCInitStructure.TIM_Pulse = value;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
|
|
||||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
|
|
||||||
|
|
||||||
timerOCInit(tim, channel, &TIM_OCInitStructure);
|
timerOCInit(tim, channel, &TIM_OCInitStructure);
|
||||||
timerOCPreloadConfig(tim, channel, TIM_OCPreload_Enable);
|
timerOCPreloadConfig(tim, channel, TIM_OCPreload_Enable);
|
||||||
|
@ -156,7 +157,7 @@ void pwmCompleteMotorUpdate(uint8_t motorCount)
|
||||||
|
|
||||||
void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount)
|
void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount)
|
||||||
{
|
{
|
||||||
uint32_t timerMhzCounter;
|
uint32_t timerMhzCounter = 0;
|
||||||
pwmWriteFuncPtr pwmWritePtr;
|
pwmWriteFuncPtr pwmWritePtr;
|
||||||
bool useUnsyncedPwm = motorConfig->useUnsyncedPwm;
|
bool useUnsyncedPwm = motorConfig->useUnsyncedPwm;
|
||||||
bool isDigital = false;
|
bool isDigital = false;
|
||||||
|
@ -208,7 +209,7 @@ void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t mot
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timerHardware_t *timerHardware = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
|
const timerHardware_t *timerHardware = timerGetByTag(tag, TIM_USE_ANY);
|
||||||
|
|
||||||
if (timerHardware == NULL) {
|
if (timerHardware == NULL) {
|
||||||
/* flag failure and disable ability to arm */
|
/* flag failure and disable ability to arm */
|
||||||
|
@ -271,7 +272,7 @@ void servoInit(const servoConfig_t *servoConfig)
|
||||||
IOInit(servos[servoIndex].io, OWNER_SERVO, RESOURCE_OUTPUT, RESOURCE_INDEX(servoIndex));
|
IOInit(servos[servoIndex].io, OWNER_SERVO, RESOURCE_OUTPUT, RESOURCE_INDEX(servoIndex));
|
||||||
IOConfigGPIO(servos[servoIndex].io, IOCFG_AF_PP);
|
IOConfigGPIO(servos[servoIndex].io, IOCFG_AF_PP);
|
||||||
|
|
||||||
const timerHardware_t *timer = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
|
const timerHardware_t *timer = timerGetByTag(tag, TIM_USE_ANY);
|
||||||
|
|
||||||
if (timer == NULL) {
|
if (timer == NULL) {
|
||||||
/* flag failure and disable ability to arm */
|
/* flag failure and disable ability to arm */
|
||||||
|
|
|
@ -71,7 +71,7 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
#if defined(STM32F7)
|
#if defined(STM32F7)
|
||||||
TIM_HandleTypeDef TimHandle;
|
TIM_HandleTypeDef TimHandle;
|
||||||
uint32_t Channel;
|
DMA_HandleTypeDef hdma_tim;
|
||||||
#endif
|
#endif
|
||||||
} motorDmaOutput_t;
|
} motorDmaOutput_t;
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,7 @@ void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t mot
|
||||||
break;
|
break;
|
||||||
#ifdef USE_DSHOT
|
#ifdef USE_DSHOT
|
||||||
case PWM_TYPE_DSHOT600:
|
case PWM_TYPE_DSHOT600:
|
||||||
|
case PWM_TYPE_DSHOT300:
|
||||||
case PWM_TYPE_DSHOT150:
|
case PWM_TYPE_DSHOT150:
|
||||||
pwmCompleteWritePtr = pwmCompleteDigitalMotorUpdate;
|
pwmCompleteWritePtr = pwmCompleteDigitalMotorUpdate;
|
||||||
isDigital = true;
|
isDigital = true;
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "build/debug.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "pwm_output.h"
|
#include "pwm_output.h"
|
||||||
|
@ -84,7 +86,7 @@ void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
|
||||||
{
|
{
|
||||||
UNUSED(motorCount);
|
UNUSED(motorCount);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
|
for (int i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
||||||
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +121,7 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
if (configureTimer) {
|
if (configureTimer) {
|
||||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
|
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
||||||
|
|
||||||
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
TIM_Cmd(timer, DISABLE);
|
TIM_Cmd(timer, DISABLE);
|
||||||
|
@ -139,6 +142,7 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock / timerClockDivisor(timer) / hz) - 1);
|
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock / timerClockDivisor(timer) / hz) - 1);
|
||||||
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
|
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
}
|
}
|
||||||
|
@ -146,19 +150,13 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
TIM_OCStructInit(&TIM_OCInitStructure);
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
|
|
||||||
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
|
|
||||||
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;
|
TIM_OCInitStructure.TIM_OCNPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPolarity_Low : TIM_OCNPolarity_High;
|
||||||
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
|
|
||||||
} else {
|
} 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_OCIdleState = TIM_OCIdleState_Set;
|
||||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
|
||||||
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
|
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
|
|
||||||
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
|
|
||||||
}
|
}
|
||||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
|
|
||||||
|
@ -177,6 +175,7 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
DMA_Channel_TypeDef *channel = timerHardware->dmaChannel;
|
DMA_Channel_TypeDef *channel = timerHardware->dmaChannel;
|
||||||
|
|
||||||
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex));
|
||||||
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
||||||
|
|
||||||
DMA_Cmd(channel, DISABLE);
|
DMA_Cmd(channel, DISABLE);
|
||||||
|
|
|
@ -85,7 +85,7 @@ void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
|
||||||
{
|
{
|
||||||
UNUSED(motorCount);
|
UNUSED(motorCount);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
|
for (int i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
||||||
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,7 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
if (configureTimer) {
|
if (configureTimer) {
|
||||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
|
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
|
||||||
|
|
||||||
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
TIM_Cmd(timer, DISABLE);
|
TIM_Cmd(timer, DISABLE);
|
||||||
|
@ -140,17 +141,22 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;
|
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;
|
||||||
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
|
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
|
TIM_OCInitStructure.TIM_OCNPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPolarity_High : TIM_OCNPolarity_Low;
|
||||||
|
} 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_OCIdleState = TIM_OCIdleState_Set;
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
|
||||||
|
}
|
||||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
|
|
||||||
timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure);
|
timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure);
|
||||||
|
@ -168,8 +174,12 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
DMA_Stream_TypeDef *stream = timerHardware->dmaStream;
|
DMA_Stream_TypeDef *stream = timerHardware->dmaStream;
|
||||||
|
|
||||||
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex));
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
||||||
|
|
||||||
DMA_Cmd(stream, DISABLE);
|
DMA_Cmd(stream, DISABLE);
|
||||||
DMA_DeInit(stream);
|
DMA_DeInit(stream);
|
||||||
|
|
||||||
DMA_StructInit(&DMA_InitStructure);
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
DMA_InitStructure.DMA_Channel = timerHardware->dmaChannel;
|
DMA_InitStructure.DMA_Channel = timerHardware->dmaChannel;
|
||||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerChCCR(timerHardware);
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerChCCR(timerHardware);
|
||||||
|
@ -191,8 +201,6 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
DMA_ITConfig(stream, DMA_IT_TC, ENABLE);
|
DMA_ITConfig(stream, DMA_IT_TC, ENABLE);
|
||||||
DMA_ClearITPendingBit(stream, dmaFlag_IT_TCIF(timerHardware->dmaStream));
|
DMA_ClearITPendingBit(stream, dmaFlag_IT_TCIF(timerHardware->dmaStream));
|
||||||
|
|
||||||
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -145,6 +145,7 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
motor->TimHandle.Instance = timerHardware->tim;
|
motor->TimHandle.Instance = timerHardware->tim;
|
||||||
motor->TimHandle.Init.Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;;
|
motor->TimHandle.Init.Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;;
|
||||||
motor->TimHandle.Init.Period = MOTOR_BITLENGTH;
|
motor->TimHandle.Init.Period = MOTOR_BITLENGTH;
|
||||||
|
motor->TimHandle.Init.RepetitionCounter = 0;
|
||||||
motor->TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
motor->TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
motor->TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
|
motor->TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
if(HAL_TIM_PWM_Init(&motor->TimHandle) != HAL_OK)
|
if(HAL_TIM_PWM_Init(&motor->TimHandle) != HAL_OK)
|
||||||
|
@ -176,22 +177,19 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
|
|
||||||
dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
|
dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
|
||||||
|
|
||||||
|
|
||||||
static DMA_HandleTypeDef hdma_tim;
|
|
||||||
|
|
||||||
/* Set the parameters to be configured */
|
/* Set the parameters to be configured */
|
||||||
hdma_tim.Init.Channel = timerHardware->dmaChannel;
|
motor->hdma_tim.Init.Channel = timerHardware->dmaChannel;
|
||||||
hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
motor->hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||||
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
|
motor->hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||||
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
|
motor->hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
|
||||||
hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD ;
|
motor->hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||||
hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;
|
motor->hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||||
hdma_tim.Init.Mode = DMA_NORMAL;
|
motor->hdma_tim.Init.Mode = DMA_NORMAL;
|
||||||
hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
|
motor->hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
|
||||||
hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
motor->hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||||
hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
motor->hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||||
hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
|
motor->hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
|
||||||
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
motor->hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
|
||||||
|
|
||||||
/* Set hdma_tim instance */
|
/* Set hdma_tim instance */
|
||||||
if(timerHardware->dmaStream == NULL)
|
if(timerHardware->dmaStream == NULL)
|
||||||
|
@ -199,11 +197,12 @@ void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t
|
||||||
/* Initialization Error */
|
/* Initialization Error */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hdma_tim.Instance = timerHardware->dmaStream;
|
motor->hdma_tim.Instance = timerHardware->dmaStream;
|
||||||
|
|
||||||
/* Link hdma_tim to hdma[x] (channelx) */
|
/* Link hdma_tim to hdma[x] (channelx) */
|
||||||
__HAL_LINKDMA(&motor->TimHandle, hdma[motor->timerDmaSource], hdma_tim);
|
__HAL_LINKDMA(&motor->TimHandle, hdma[motor->timerDmaSource], motor->hdma_tim);
|
||||||
|
|
||||||
|
dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex));
|
||||||
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
||||||
|
|
||||||
/* Initialize TIMx DMA handle */
|
/* Initialize TIMx DMA handle */
|
||||||
|
|
|
@ -393,7 +393,7 @@ void pwmRxInit(const pwmConfig_t *pwmConfig)
|
||||||
|
|
||||||
pwmInputPort_t *port = &pwmInputPorts[channel];
|
pwmInputPort_t *port = &pwmInputPorts[channel];
|
||||||
|
|
||||||
const timerHardware_t *timer = timerGetByTag(pwmConfig->ioTags[channel], TIMER_INPUT_ENABLED);
|
const timerHardware_t *timer = timerGetByTag(pwmConfig->ioTags[channel], TIM_USE_PWM);
|
||||||
|
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
/* TODO: maybe fail here if not enough channels? */
|
/* TODO: maybe fail here if not enough channels? */
|
||||||
|
@ -408,7 +408,7 @@ void pwmRxInit(const pwmConfig_t *pwmConfig)
|
||||||
|
|
||||||
IO_t io = IOGetByTag(pwmConfig->ioTags[channel]);
|
IO_t io = IOGetByTag(pwmConfig->ioTags[channel]);
|
||||||
IOInit(io, OWNER_PWMINPUT, RESOURCE_INPUT, RESOURCE_INDEX(channel));
|
IOInit(io, OWNER_PWMINPUT, RESOURCE_INPUT, RESOURCE_INDEX(channel));
|
||||||
IOConfigGPIO(io, timer->ioMode);
|
IOConfigGPIO(io, IOCFG_IPD);
|
||||||
|
|
||||||
#if defined(USE_HAL_DRIVER)
|
#if defined(USE_HAL_DRIVER)
|
||||||
pwmICConfig(timer->tim, timer->channel, TIM_ICPOLARITY_RISING);
|
pwmICConfig(timer->tim, timer->channel, TIM_ICPOLARITY_RISING);
|
||||||
|
@ -459,7 +459,7 @@ void ppmRxInit(const ppmConfig_t *ppmConfig, uint8_t pwmProtocol)
|
||||||
|
|
||||||
pwmInputPort_t *port = &pwmInputPorts[FIRST_PWM_PORT];
|
pwmInputPort_t *port = &pwmInputPorts[FIRST_PWM_PORT];
|
||||||
|
|
||||||
const timerHardware_t *timer = timerGetByTag(ppmConfig->ioTag, TIMER_INPUT_ENABLED);
|
const timerHardware_t *timer = timerGetByTag(ppmConfig->ioTag, TIM_USE_PPM);
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
/* TODO: fail here? */
|
/* TODO: fail here? */
|
||||||
return;
|
return;
|
||||||
|
@ -472,7 +472,7 @@ void ppmRxInit(const ppmConfig_t *ppmConfig, uint8_t pwmProtocol)
|
||||||
|
|
||||||
IO_t io = IOGetByTag(ppmConfig->ioTag);
|
IO_t io = IOGetByTag(ppmConfig->ioTag);
|
||||||
IOInit(io, OWNER_PPMINPUT, RESOURCE_INPUT, 0);
|
IOInit(io, OWNER_PPMINPUT, RESOURCE_INPUT, 0);
|
||||||
IOConfigGPIO(io, timer->ioMode);
|
IOConfigGPIO(io, IOCFG_IPD);
|
||||||
|
|
||||||
#if defined(USE_HAL_DRIVER)
|
#if defined(USE_HAL_DRIVER)
|
||||||
pwmICConfig(timer->tim, timer->channel, TIM_ICPOLARITY_RISING);
|
pwmICConfig(timer->tim, timer->channel, TIM_ICPOLARITY_RISING);
|
||||||
|
|
|
@ -33,8 +33,9 @@ typedef enum {
|
||||||
OWNER_TX,
|
OWNER_TX,
|
||||||
OWNER_SOFTSPI,
|
OWNER_SOFTSPI,
|
||||||
OWNER_RX_SPI,
|
OWNER_RX_SPI,
|
||||||
|
OWNER_MAX7456,
|
||||||
OWNER_TOTAL_COUNT
|
OWNER_TOTAL_COUNT
|
||||||
} resourceOwner_t;
|
} resourceOwner_e;
|
||||||
|
|
||||||
extern const char * const ownerNames[OWNER_TOTAL_COUNT];
|
extern const char * const ownerNames[OWNER_TOTAL_COUNT];
|
||||||
|
|
||||||
|
@ -51,6 +52,6 @@ typedef enum {
|
||||||
RESOURCE_ADC_BATTERY, RESOURCE_ADC_RSSI, RESOURCE_ADC_EXTERNAL1, RESOURCE_ADC_CURRENT,
|
RESOURCE_ADC_BATTERY, RESOURCE_ADC_RSSI, RESOURCE_ADC_EXTERNAL1, RESOURCE_ADC_CURRENT,
|
||||||
RESOURCE_RX_CE,
|
RESOURCE_RX_CE,
|
||||||
RESOURCE_TOTAL_COUNT
|
RESOURCE_TOTAL_COUNT
|
||||||
} resourceType_t;
|
} resourceType_e;
|
||||||
|
|
||||||
extern const char * const resourceNames[RESOURCE_TOTAL_COUNT];
|
extern const char * const resourceNames[RESOURCE_TOTAL_COUNT];
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
@ -25,6 +26,13 @@ typedef enum {
|
||||||
BAUDRATE_KISS = 38400
|
BAUDRATE_KISS = 38400
|
||||||
} escBaudRate_e;
|
} escBaudRate_e;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PROTOCOL_SIMONK = 0,
|
||||||
|
PROTOCOL_BLHELI = 1,
|
||||||
|
PROTOCOL_KISS = 2,
|
||||||
|
PROTOCOL_KISSALL = 3
|
||||||
|
} escProtocol_e;
|
||||||
|
|
||||||
#if defined(USE_ESCSERIAL)
|
#if defined(USE_ESCSERIAL)
|
||||||
|
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
|
@ -80,11 +88,19 @@ typedef struct escSerial_s {
|
||||||
|
|
||||||
uint8_t escSerialPortIndex;
|
uint8_t escSerialPortIndex;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
uint8_t outputCount;
|
||||||
|
|
||||||
timerCCHandlerRec_t timerCb;
|
timerCCHandlerRec_t timerCb;
|
||||||
timerCCHandlerRec_t edgeCb;
|
timerCCHandlerRec_t edgeCb;
|
||||||
} escSerial_t;
|
} escSerial_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IO_t io;
|
||||||
|
uint8_t inverted;
|
||||||
|
} escOutputs_t;
|
||||||
|
|
||||||
|
escOutputs_t escOutputs[MAX_SUPPORTED_MOTORS];
|
||||||
|
|
||||||
extern timerHardware_t* serialTimerHardware;
|
extern timerHardware_t* serialTimerHardware;
|
||||||
extern escSerial_t escSerialPorts[];
|
extern escSerial_t escSerialPorts[];
|
||||||
|
|
||||||
|
@ -97,16 +113,38 @@ void onSerialTimerEsc(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||||
void onSerialRxPinChangeEsc(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
void onSerialRxPinChangeEsc(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||||
void onSerialTimerBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
void onSerialTimerBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||||
void onSerialRxPinChangeBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
void onSerialRxPinChangeBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||||
static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity);
|
static void escSerialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity);
|
||||||
|
|
||||||
void setTxSignalEsc(escSerial_t *escSerial, uint8_t state)
|
void setTxSignalEsc(escSerial_t *escSerial, uint8_t state)
|
||||||
{
|
{
|
||||||
|
if((escSerial->mode = PROTOCOL_KISSALL))
|
||||||
|
{
|
||||||
|
for (volatile uint8_t i = 0; i < escSerial->outputCount; i++) {
|
||||||
|
uint8_t state_temp = state;
|
||||||
|
if(escOutputs[i].inverted) {
|
||||||
|
state_temp ^= ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_temp) {
|
||||||
|
IOHi(escOutputs[i].io);
|
||||||
|
} else {
|
||||||
|
IOLo(escOutputs[i].io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(escSerial->rxTimerHardware->output & TIMER_OUTPUT_INVERTED) {
|
||||||
|
state ^= ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
IOHi(escSerial->txIO);
|
IOHi(escSerial->txIO);
|
||||||
} else {
|
} else {
|
||||||
IOLo(escSerial->txIO);
|
IOLo(escSerial->txIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void escSerialGPIOConfig(ioTag_t tag, ioConfig_t cfg)
|
static void escSerialGPIOConfig(ioTag_t tag, ioConfig_t cfg)
|
||||||
{
|
{
|
||||||
|
@ -118,7 +156,7 @@ static void escSerialGPIOConfig(ioTag_t tag, ioConfig_t cfg)
|
||||||
IOConfigGPIO(IOGetByTag(tag), cfg);
|
IOConfigGPIO(IOGetByTag(tag), cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialInputPortConfigEsc(const timerHardware_t *timerHardwarePtr)
|
void escSerialInputPortConfig(const timerHardware_t *timerHardwarePtr)
|
||||||
{
|
{
|
||||||
#ifdef STM32F10X
|
#ifdef STM32F10X
|
||||||
escSerialGPIOConfig(timerHardwarePtr->tag, IOCFG_IPU);
|
escSerialGPIOConfig(timerHardwarePtr->tag, IOCFG_IPU);
|
||||||
|
@ -164,12 +202,12 @@ static void serialTimerRxConfigBL(const timerHardware_t *timerHardwarePtr, uint8
|
||||||
uint8_t mhz = SystemCoreClock / 2000000;
|
uint8_t mhz = SystemCoreClock / 2000000;
|
||||||
TIM_DeInit(timerHardwarePtr->tim);
|
TIM_DeInit(timerHardwarePtr->tim);
|
||||||
timerConfigure(timerHardwarePtr, 0xFFFF, mhz);
|
timerConfigure(timerHardwarePtr, 0xFFFF, mhz);
|
||||||
serialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
escSerialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||||
timerChCCHandlerInit(&escSerialPorts[reference].edgeCb, onSerialRxPinChangeBL);
|
timerChCCHandlerInit(&escSerialPorts[reference].edgeCb, onSerialRxPinChangeBL);
|
||||||
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].edgeCb, NULL);
|
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].edgeCb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference)
|
static void escSerialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference)
|
||||||
{
|
{
|
||||||
uint32_t timerPeriod=34;
|
uint32_t timerPeriod=34;
|
||||||
TIM_DeInit(timerHardwarePtr->tim);
|
TIM_DeInit(timerHardwarePtr->tim);
|
||||||
|
@ -178,7 +216,7 @@ static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t
|
||||||
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].timerCb, NULL);
|
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].timerCb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
static void escSerialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
||||||
{
|
{
|
||||||
TIM_ICInitTypeDef TIM_ICInitStructure;
|
TIM_ICInitTypeDef TIM_ICInitStructure;
|
||||||
|
|
||||||
|
@ -192,17 +230,17 @@ static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
||||||
TIM_ICInit(tim, &TIM_ICInitStructure);
|
TIM_ICInit(tim, &TIM_ICInitStructure);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serialTimerRxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference)
|
static void escSerialTimerRxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference)
|
||||||
{
|
{
|
||||||
// start bit is usually a FALLING signal
|
// start bit is usually a FALLING signal
|
||||||
TIM_DeInit(timerHardwarePtr->tim);
|
TIM_DeInit(timerHardwarePtr->tim);
|
||||||
timerConfigure(timerHardwarePtr, 0xFFFF, 1);
|
timerConfigure(timerHardwarePtr, 0xFFFF, 1);
|
||||||
serialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, TIM_ICPolarity_Falling);
|
escSerialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, TIM_ICPolarity_Falling);
|
||||||
timerChCCHandlerInit(&escSerialPorts[reference].edgeCb, onSerialRxPinChangeEsc);
|
timerChCCHandlerInit(&escSerialPorts[reference].edgeCb, onSerialRxPinChangeEsc);
|
||||||
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].edgeCb, NULL);
|
timerChConfigCallbacks(timerHardwarePtr, &escSerialPorts[reference].edgeCb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serialOutputPortConfig(const timerHardware_t *timerHardwarePtr)
|
static void escSerialOutputPortConfig(const timerHardware_t *timerHardwarePtr)
|
||||||
{
|
{
|
||||||
escSerialGPIOConfig(timerHardwarePtr->tag, IOCFG_OUT_PP);
|
escSerialGPIOConfig(timerHardwarePtr->tag, IOCFG_OUT_PP);
|
||||||
timerChITConfig(timerHardwarePtr,DISABLE);
|
timerChITConfig(timerHardwarePtr,DISABLE);
|
||||||
|
@ -225,7 +263,11 @@ serialPort_t *openEscSerial(escSerialPortIndex_e portIndex, serialReceiveCallbac
|
||||||
{
|
{
|
||||||
escSerial_t *escSerial = &(escSerialPorts[portIndex]);
|
escSerial_t *escSerial = &(escSerialPorts[portIndex]);
|
||||||
|
|
||||||
|
if(mode != PROTOCOL_KISSALL){
|
||||||
escSerial->rxTimerHardware = &(timerHardware[output]);
|
escSerial->rxTimerHardware = &(timerHardware[output]);
|
||||||
|
}
|
||||||
|
|
||||||
|
escSerial->mode = mode;
|
||||||
escSerial->txTimerHardware = &(timerHardware[ESCSERIAL_TIMER_TX_HARDWARE]);
|
escSerial->txTimerHardware = &(timerHardware[ESCSERIAL_TIMER_TX_HARDWARE]);
|
||||||
|
|
||||||
escSerial->port.vTable = escSerialVTable;
|
escSerial->port.vTable = escSerialVTable;
|
||||||
|
@ -247,30 +289,56 @@ serialPort_t *openEscSerial(escSerialPortIndex_e portIndex, serialReceiveCallbac
|
||||||
|
|
||||||
escSerial->escSerialPortIndex = portIndex;
|
escSerial->escSerialPortIndex = portIndex;
|
||||||
|
|
||||||
|
if(mode != PROTOCOL_KISSALL)
|
||||||
|
{
|
||||||
escSerial->txIO = IOGetByTag(escSerial->rxTimerHardware->tag);
|
escSerial->txIO = IOGetByTag(escSerial->rxTimerHardware->tag);
|
||||||
serialInputPortConfigEsc(escSerial->rxTimerHardware);
|
escSerialInputPortConfig(escSerial->rxTimerHardware);
|
||||||
|
|
||||||
setTxSignalEsc(escSerial, ENABLE);
|
setTxSignalEsc(escSerial, ENABLE);
|
||||||
|
}
|
||||||
delay(50);
|
delay(50);
|
||||||
|
|
||||||
if(mode==0){
|
if(mode==PROTOCOL_SIMONK){
|
||||||
serialTimerTxConfig(escSerial->txTimerHardware, portIndex);
|
escSerialTimerTxConfig(escSerial->txTimerHardware, portIndex);
|
||||||
serialTimerRxConfig(escSerial->rxTimerHardware, portIndex);
|
escSerialTimerRxConfig(escSerial->rxTimerHardware, portIndex);
|
||||||
}
|
}
|
||||||
else if(mode==1){
|
else if(mode==PROTOCOL_BLHELI){
|
||||||
serialTimerTxConfigBL(escSerial->txTimerHardware, portIndex, baud);
|
serialTimerTxConfigBL(escSerial->txTimerHardware, portIndex, baud);
|
||||||
serialTimerRxConfigBL(escSerial->rxTimerHardware, portIndex, options);
|
serialTimerRxConfigBL(escSerial->rxTimerHardware, portIndex, options);
|
||||||
}
|
}
|
||||||
else if(mode==2) {
|
else if(mode==PROTOCOL_KISS) {
|
||||||
serialOutputPortConfig(escSerial->rxTimerHardware); // rx is the pin used
|
escSerialOutputPortConfig(escSerial->rxTimerHardware); // rx is the pin used
|
||||||
|
serialTimerTxConfigBL(escSerial->txTimerHardware, portIndex, baud);
|
||||||
|
}
|
||||||
|
else if(mode==PROTOCOL_KISSALL) {
|
||||||
|
escSerial->outputCount = 0;
|
||||||
|
memset(&escOutputs, 0, sizeof(escOutputs));
|
||||||
|
pwmOutputPort_t *pwmMotors = pwmGetMotors();
|
||||||
|
for (volatile uint8_t i = 0; i < MAX_SUPPORTED_MOTORS; i++) {
|
||||||
|
if (pwmMotors[i].enabled) {
|
||||||
|
if (pwmMotors[i].io != IO_NONE) {
|
||||||
|
for (volatile uint8_t j = 0; j < USABLE_TIMER_CHANNEL_COUNT; j++) {
|
||||||
|
if(pwmMotors[i].io == IOGetByTag(timerHardware[j].tag))
|
||||||
|
{
|
||||||
|
escSerialOutputPortConfig(&timerHardware[j]);
|
||||||
|
if(timerHardware[j].output & TIMER_OUTPUT_INVERTED) {
|
||||||
|
escOutputs[escSerial->outputCount].inverted = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
escOutputs[escSerial->outputCount].io = pwmMotors[i].io;
|
||||||
|
escSerial->outputCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTxSignalEsc(escSerial, ENABLE);
|
||||||
serialTimerTxConfigBL(escSerial->txTimerHardware, portIndex, baud);
|
serialTimerTxConfigBL(escSerial->txTimerHardware, portIndex, baud);
|
||||||
}
|
}
|
||||||
escSerial->mode = mode;
|
|
||||||
return &escSerial->port;
|
return &escSerial->port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void serialInputPortDeConfig(const timerHardware_t *timerHardwarePtr)
|
void escSerialInputPortDeConfig(const timerHardware_t *timerHardwarePtr)
|
||||||
{
|
{
|
||||||
timerChClearCCFlag(timerHardwarePtr);
|
timerChClearCCFlag(timerHardwarePtr);
|
||||||
timerChITConfig(timerHardwarePtr,DISABLE);
|
timerChITConfig(timerHardwarePtr,DISABLE);
|
||||||
|
@ -284,7 +352,7 @@ void closeEscSerial(escSerialPortIndex_e portIndex, uint16_t output)
|
||||||
|
|
||||||
escSerial->rxTimerHardware = &(timerHardware[output]);
|
escSerial->rxTimerHardware = &(timerHardware[output]);
|
||||||
escSerial->txTimerHardware = &(timerHardware[ESCSERIAL_TIMER_TX_HARDWARE]);
|
escSerial->txTimerHardware = &(timerHardware[ESCSERIAL_TIMER_TX_HARDWARE]);
|
||||||
serialInputPortDeConfig(escSerial->rxTimerHardware);
|
escSerialInputPortDeConfig(escSerial->rxTimerHardware);
|
||||||
timerChConfigCallbacks(escSerial->txTimerHardware,NULL,NULL);
|
timerChConfigCallbacks(escSerial->txTimerHardware,NULL,NULL);
|
||||||
timerChConfigCallbacks(escSerial->rxTimerHardware,NULL,NULL);
|
timerChConfigCallbacks(escSerial->rxTimerHardware,NULL,NULL);
|
||||||
TIM_DeInit(escSerial->txTimerHardware->tim);
|
TIM_DeInit(escSerial->txTimerHardware->tim);
|
||||||
|
@ -339,7 +407,7 @@ reload:
|
||||||
escSerial->isTransmittingData = true;
|
escSerial->isTransmittingData = true;
|
||||||
|
|
||||||
//set output
|
//set output
|
||||||
serialOutputPortConfig(escSerial->rxTimerHardware);
|
escSerialOutputPortConfig(escSerial->rxTimerHardware);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +451,7 @@ reload:
|
||||||
|
|
||||||
if (isEscSerialTransmitBufferEmpty((serialPort_t *)escSerial)) {
|
if (isEscSerialTransmitBufferEmpty((serialPort_t *)escSerial)) {
|
||||||
escSerial->isTransmittingData = false;
|
escSerial->isTransmittingData = false;
|
||||||
serialInputPortConfigEsc(escSerial->rxTimerHardware);
|
escSerialInputPortConfig(escSerial->rxTimerHardware);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +485,9 @@ void processTxStateBL(escSerial_t *escSerial)
|
||||||
|
|
||||||
|
|
||||||
//set output
|
//set output
|
||||||
serialOutputPortConfig(escSerial->rxTimerHardware);
|
if(escSerial->mode==PROTOCOL_BLHELI) {
|
||||||
|
escSerialOutputPortConfig(escSerial->rxTimerHardware);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,9 +502,9 @@ void processTxStateBL(escSerial_t *escSerial)
|
||||||
|
|
||||||
escSerial->isTransmittingData = false;
|
escSerial->isTransmittingData = false;
|
||||||
if (isEscSerialTransmitBufferEmpty((serialPort_t *)escSerial)) {
|
if (isEscSerialTransmitBufferEmpty((serialPort_t *)escSerial)) {
|
||||||
if(escSerial->mode==1)
|
if(escSerial->mode==PROTOCOL_BLHELI)
|
||||||
{
|
{
|
||||||
serialInputPortConfigEsc(escSerial->rxTimerHardware);
|
escSerialInputPortConfig(escSerial->rxTimerHardware);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +533,7 @@ void prepareForNextRxByteBL(escSerial_t *escSerial)
|
||||||
escSerial->isSearchingForStartBit = true;
|
escSerial->isSearchingForStartBit = true;
|
||||||
if (escSerial->rxEdge == LEADING) {
|
if (escSerial->rxEdge == LEADING) {
|
||||||
escSerial->rxEdge = TRAILING;
|
escSerial->rxEdge = TRAILING;
|
||||||
serialICConfig(
|
escSerialICConfig(
|
||||||
escSerial->rxTimerHardware->tim,
|
escSerial->rxTimerHardware->tim,
|
||||||
escSerial->rxTimerHardware->channel,
|
escSerial->rxTimerHardware->channel,
|
||||||
(escSerial->port.options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling
|
(escSerial->port.options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling
|
||||||
|
@ -551,7 +621,7 @@ void onSerialRxPinChangeBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||||
escSerial->transmissionErrors++;
|
escSerial->transmissionErrors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
serialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
escSerialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||||
escSerial->rxEdge = LEADING;
|
escSerial->rxEdge = LEADING;
|
||||||
|
|
||||||
escSerial->rxBitIndex = 0;
|
escSerial->rxBitIndex = 0;
|
||||||
|
@ -569,10 +639,10 @@ void onSerialRxPinChangeBL(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||||
|
|
||||||
if (escSerial->rxEdge == TRAILING) {
|
if (escSerial->rxEdge == TRAILING) {
|
||||||
escSerial->rxEdge = LEADING;
|
escSerial->rxEdge = LEADING;
|
||||||
serialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
escSerialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||||
} else {
|
} else {
|
||||||
escSerial->rxEdge = TRAILING;
|
escSerial->rxEdge = TRAILING;
|
||||||
serialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
escSerialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*-------------------------BL*/
|
/*-------------------------BL*/
|
||||||
|
@ -605,7 +675,7 @@ void onSerialTimerEsc(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||||
{
|
{
|
||||||
escSerial->isReceivingData=0;
|
escSerial->isReceivingData=0;
|
||||||
escSerial->receiveTimeout=0;
|
escSerial->receiveTimeout=0;
|
||||||
serialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, TIM_ICPolarity_Falling);
|
escSerialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, TIM_ICPolarity_Falling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,7 +725,7 @@ void onSerialRxPinChangeEsc(timerCCHandlerRec_t *cbRec, captureCompare_t capture
|
||||||
bits=1;
|
bits=1;
|
||||||
escSerial->internalRxBuffer = 0x80;
|
escSerial->internalRxBuffer = 0x80;
|
||||||
|
|
||||||
serialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, TIM_ICPolarity_Rising);
|
escSerialICConfig(escSerial->rxTimerHardware->tim, escSerial->rxTimerHardware->channel, TIM_ICPolarity_Rising);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
escSerial->receiveTimeout = 0;
|
escSerial->receiveTimeout = 0;
|
||||||
|
@ -763,7 +833,7 @@ void escSerialInitialize()
|
||||||
|
|
||||||
for (volatile uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (volatile uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
// set outputs to pullup
|
// set outputs to pullup
|
||||||
if(timerHardware[i].output==1)
|
if(timerHardware[i].output & TIMER_OUTPUT_ENABLED)
|
||||||
{
|
{
|
||||||
escSerialGPIOConfig(timerHardware[i].tag, IOCFG_IPU); //GPIO_Mode_IPU
|
escSerialGPIOConfig(timerHardware[i].tag, IOCFG_IPU); //GPIO_Mode_IPU
|
||||||
}
|
}
|
||||||
|
@ -844,15 +914,23 @@ static bool ProcessExitCommand(uint8_t c)
|
||||||
void escEnablePassthrough(serialPort_t *escPassthroughPort, uint16_t output, uint8_t mode)
|
void escEnablePassthrough(serialPort_t *escPassthroughPort, uint16_t output, uint8_t mode)
|
||||||
{
|
{
|
||||||
bool exitEsc = false;
|
bool exitEsc = false;
|
||||||
|
uint8_t motor_output = 0;
|
||||||
LED0_OFF;
|
LED0_OFF;
|
||||||
LED1_OFF;
|
LED1_OFF;
|
||||||
//StopPwmAllMotors();
|
//StopPwmAllMotors();
|
||||||
pwmDisableMotors();
|
pwmDisableMotors();
|
||||||
passPort = escPassthroughPort;
|
passPort = escPassthroughPort;
|
||||||
|
|
||||||
|
uint32_t escBaudrate = (mode == PROTOCOL_KISS) ? BAUDRATE_KISS : BAUDRATE_NORMAL;
|
||||||
|
|
||||||
|
if((mode == PROTOCOL_KISS) && (output == 255)){
|
||||||
|
motor_output = 255;
|
||||||
|
mode = PROTOCOL_KISSALL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
uint8_t first_output = 0;
|
uint8_t first_output = 0;
|
||||||
for (volatile uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (volatile uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
if(timerHardware[i].output==1)
|
if(timerHardware[i].output & TIMER_OUTPUT_ENABLED)
|
||||||
{
|
{
|
||||||
first_output=i;
|
first_output=i;
|
||||||
break;
|
break;
|
||||||
|
@ -860,11 +938,10 @@ void escEnablePassthrough(serialPort_t *escPassthroughPort, uint16_t output, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
//doesn't work with messy timertable
|
//doesn't work with messy timertable
|
||||||
uint8_t motor_output=first_output+output-1;
|
motor_output=first_output+output-1;
|
||||||
if(motor_output >=USABLE_TIMER_CHANNEL_COUNT)
|
if(motor_output >=USABLE_TIMER_CHANNEL_COUNT)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
uint32_t escBaudrate = (mode == 2) ? BAUDRATE_KISS : BAUDRATE_NORMAL;
|
|
||||||
|
|
||||||
escPort = openEscSerial(ESCSERIAL1, NULL, motor_output, escBaudrate, 0, mode);
|
escPort = openEscSerial(ESCSERIAL1, NULL, motor_output, escBaudrate, 0, mode);
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
|
@ -898,7 +975,7 @@ void escEnablePassthrough(serialPort_t *escPassthroughPort, uint16_t output, uin
|
||||||
closeEscSerial(ESCSERIAL1, output);
|
closeEscSerial(ESCSERIAL1, output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(mode==1){
|
if(mode==PROTOCOL_BLHELI){
|
||||||
serialWrite(escPassthroughPort, ch); // blheli loopback
|
serialWrite(escPassthroughPort, ch); // blheli loopback
|
||||||
}
|
}
|
||||||
serialWrite(escPort, ch);
|
serialWrite(escPort, ch);
|
||||||
|
|
|
@ -57,7 +57,6 @@ static void usartConfigurePinInversion(uartPort_t *uartPort) {
|
||||||
|
|
||||||
static void uartReconfigure(uartPort_t *uartPort)
|
static void uartReconfigure(uartPort_t *uartPort)
|
||||||
{
|
{
|
||||||
HAL_StatusTypeDef status = HAL_ERROR;
|
|
||||||
/*RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
|
/*RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
|
||||||
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_USART3|
|
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_USART3|
|
||||||
RCC_PERIPHCLK_UART4|RCC_PERIPHCLK_UART5|RCC_PERIPHCLK_USART6|RCC_PERIPHCLK_UART7|RCC_PERIPHCLK_UART8;
|
RCC_PERIPHCLK_UART4|RCC_PERIPHCLK_UART5|RCC_PERIPHCLK_USART6|RCC_PERIPHCLK_UART7|RCC_PERIPHCLK_UART8;
|
||||||
|
@ -90,11 +89,11 @@ static void uartReconfigure(uartPort_t *uartPort)
|
||||||
|
|
||||||
if(uartPort->port.options & SERIAL_BIDIR)
|
if(uartPort->port.options & SERIAL_BIDIR)
|
||||||
{
|
{
|
||||||
status = HAL_HalfDuplex_Init(&uartPort->Handle);
|
HAL_HalfDuplex_Init(&uartPort->Handle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
status = HAL_UART_Init(&uartPort->Handle);
|
HAL_UART_Init(&uartPort->Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive DMA or IRQ
|
// Receive DMA or IRQ
|
||||||
|
@ -387,4 +386,3 @@ const struct serialPortVTable uartVTable[] = {
|
||||||
.endWrite = NULL,
|
.endWrite = NULL,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,8 @@ uartPort_t *serialUART1(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
|
|
||||||
s->USARTx = USART1;
|
s->USARTx = USART1;
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_UART1_RX_DMA
|
#ifdef USE_UART1_RX_DMA
|
||||||
|
dmaInit(DMA1_CH5_HANDLER, OWNER_SERIAL, 1);
|
||||||
s->rxDMAChannel = DMA1_Channel5;
|
s->rxDMAChannel = DMA1_Channel5;
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
||||||
#endif
|
#endif
|
||||||
|
@ -118,7 +118,6 @@ uartPort_t *serialUART1(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
||||||
|
|
||||||
RCC_ClockCmd(RCC_APB2(USART1), ENABLE);
|
RCC_ClockCmd(RCC_APB2(USART1), ENABLE);
|
||||||
RCC_ClockCmd(RCC_AHB(DMA1), ENABLE);
|
|
||||||
|
|
||||||
// UART1_TX PA9
|
// UART1_TX PA9
|
||||||
// UART1_RX PA10
|
// UART1_RX PA10
|
||||||
|
@ -138,6 +137,7 @@ uartPort_t *serialUART1(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
}
|
}
|
||||||
|
|
||||||
// DMA TX Interrupt
|
// DMA TX Interrupt
|
||||||
|
dmaInit(DMA1_CH4_HANDLER, OWNER_SERIAL, 1);
|
||||||
dmaSetHandler(DMA1_CH4_HANDLER, uart_tx_dma_IRQHandler, NVIC_PRIO_SERIALUART1_TXDMA, (uint32_t)&uartPort1);
|
dmaSetHandler(DMA1_CH4_HANDLER, uart_tx_dma_IRQHandler, NVIC_PRIO_SERIALUART1_TXDMA, (uint32_t)&uartPort1);
|
||||||
|
|
||||||
#ifndef USE_UART1_RX_DMA
|
#ifndef USE_UART1_RX_DMA
|
||||||
|
@ -189,7 +189,6 @@ uartPort_t *serialUART2(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
||||||
|
|
||||||
RCC_ClockCmd(RCC_APB1(USART2), ENABLE);
|
RCC_ClockCmd(RCC_APB1(USART2), ENABLE);
|
||||||
RCC_ClockCmd(RCC_AHB(DMA1), ENABLE);
|
|
||||||
|
|
||||||
// UART2_TX PA2
|
// UART2_TX PA2
|
||||||
// UART2_RX PA3
|
// UART2_RX PA3
|
||||||
|
|
|
@ -99,6 +99,7 @@ static uartPort_t uartPort4;
|
||||||
static uartPort_t uartPort5;
|
static uartPort_t uartPort5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_UART1_TX_DMA) || defined(USE_UART2_TX_DMA) || defined(USE_UART3_TX_DMA)
|
||||||
static void handleUsartTxDma(dmaChannelDescriptor_t* descriptor)
|
static void handleUsartTxDma(dmaChannelDescriptor_t* descriptor)
|
||||||
{
|
{
|
||||||
uartPort_t *s = (uartPort_t*)(descriptor->userParam);
|
uartPort_t *s = (uartPort_t*)(descriptor->userParam);
|
||||||
|
@ -110,6 +111,7 @@ static void handleUsartTxDma(dmaChannelDescriptor_t* descriptor)
|
||||||
else
|
else
|
||||||
s->txDMAEmpty = true;
|
s->txDMAEmpty = true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void serialUARTInit(IO_t tx, IO_t rx, portMode_t mode, portOptions_t options, uint8_t af, uint8_t index)
|
void serialUARTInit(IO_t tx, IO_t rx, portMode_t mode, portOptions_t options, uint8_t af, uint8_t index)
|
||||||
{
|
{
|
||||||
|
@ -150,27 +152,35 @@ uartPort_t *serialUART1(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
|
|
||||||
s->port.baudRate = baudRate;
|
s->port.baudRate = baudRate;
|
||||||
|
|
||||||
s->port.rxBuffer = rx1Buffer;
|
|
||||||
s->port.txBuffer = tx1Buffer;
|
|
||||||
s->port.rxBufferSize = UART1_RX_BUFFER_SIZE;
|
s->port.rxBufferSize = UART1_RX_BUFFER_SIZE;
|
||||||
s->port.txBufferSize = UART1_TX_BUFFER_SIZE;
|
s->port.txBufferSize = UART1_TX_BUFFER_SIZE;
|
||||||
|
s->port.rxBuffer = rx1Buffer;
|
||||||
#ifdef USE_UART1_RX_DMA
|
s->port.txBuffer = tx1Buffer;
|
||||||
s->rxDMAChannel = DMA1_Channel5;
|
|
||||||
#endif
|
|
||||||
s->txDMAChannel = DMA1_Channel4;
|
|
||||||
|
|
||||||
s->USARTx = USART1;
|
s->USARTx = USART1;
|
||||||
|
|
||||||
|
#ifdef USE_UART1_RX_DMA
|
||||||
|
dmaInit(DMA1_CH5_HANDLER, OWNER_SERIAL, 1);
|
||||||
|
s->rxDMAChannel = DMA1_Channel5;
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_UART1_TX_DMA
|
||||||
|
s->txDMAChannel = DMA1_Channel4;
|
||||||
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
||||||
|
#endif
|
||||||
|
|
||||||
RCC_ClockCmd(RCC_APB2(USART1), ENABLE);
|
RCC_ClockCmd(RCC_APB2(USART1), ENABLE);
|
||||||
|
|
||||||
|
#if defined(USE_UART1_TX_DMA) || defined(USE_UART1_RX_DMA)
|
||||||
RCC_ClockCmd(RCC_AHB(DMA1), ENABLE);
|
RCC_ClockCmd(RCC_AHB(DMA1), ENABLE);
|
||||||
|
#endif
|
||||||
|
|
||||||
serialUARTInit(IOGetByTag(IO_TAG(UART1_TX_PIN)), IOGetByTag(IO_TAG(UART1_RX_PIN)), mode, options, GPIO_AF_7, 1);
|
serialUARTInit(IOGetByTag(IO_TAG(UART1_TX_PIN)), IOGetByTag(IO_TAG(UART1_RX_PIN)), mode, options, GPIO_AF_7, 1);
|
||||||
|
|
||||||
|
#ifdef USE_UART1_TX_DMA
|
||||||
|
dmaInit(DMA1_CH4_HANDLER, OWNER_SERIAL, 1);
|
||||||
dmaSetHandler(DMA1_CH4_HANDLER, handleUsartTxDma, NVIC_PRIO_SERIALUART1_TXDMA, (uint32_t)&uartPort1);
|
dmaSetHandler(DMA1_CH4_HANDLER, handleUsartTxDma, NVIC_PRIO_SERIALUART1_TXDMA, (uint32_t)&uartPort1);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef USE_UART1_RX_DMA
|
#ifndef USE_UART1_RX_DMA
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
@ -206,10 +216,12 @@ uartPort_t *serialUART2(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
s->USARTx = USART2;
|
s->USARTx = USART2;
|
||||||
|
|
||||||
#ifdef USE_UART2_RX_DMA
|
#ifdef USE_UART2_RX_DMA
|
||||||
|
dmaInit(DMA1_CH6_HANDLER, OWNER_SERIAL, 2);
|
||||||
s->rxDMAChannel = DMA1_Channel6;
|
s->rxDMAChannel = DMA1_Channel6;
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_UART2_TX_DMA
|
#ifdef USE_UART2_TX_DMA
|
||||||
|
dmaInit(DMA1_CH7_HANDLER, OWNER_SERIAL, 2);
|
||||||
s->txDMAChannel = DMA1_Channel7;
|
s->txDMAChannel = DMA1_Channel7;
|
||||||
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
||||||
#endif
|
#endif
|
||||||
|
@ -261,10 +273,12 @@ uartPort_t *serialUART3(uint32_t baudRate, portMode_t mode, portOptions_t option
|
||||||
s->USARTx = USART3;
|
s->USARTx = USART3;
|
||||||
|
|
||||||
#ifdef USE_UART3_RX_DMA
|
#ifdef USE_UART3_RX_DMA
|
||||||
|
dmaInit(DMA1_CH3_HANDLER, OWNER_SERIAL, 3);
|
||||||
s->rxDMAChannel = DMA1_Channel3;
|
s->rxDMAChannel = DMA1_Channel3;
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->RDR;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_UART3_TX_DMA
|
#ifdef USE_UART3_TX_DMA
|
||||||
|
dmaInit(DMA1_CH2_HANDLER, OWNER_SERIAL, 3);
|
||||||
s->txDMAChannel = DMA1_Channel2;
|
s->txDMAChannel = DMA1_Channel2;
|
||||||
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->TDR;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -315,9 +315,13 @@ uartPort_t *serialUART(UARTDevice device, uint32_t baudRate, portMode_t mode, po
|
||||||
if (uart->rxDMAStream) {
|
if (uart->rxDMAStream) {
|
||||||
s->rxDMAChannel = uart->DMAChannel;
|
s->rxDMAChannel = uart->DMAChannel;
|
||||||
s->rxDMAStream = uart->rxDMAStream;
|
s->rxDMAStream = uart->rxDMAStream;
|
||||||
|
dmaInit(dmaGetIdentifier(uart->rxDMAStream), OWNER_SERIAL, RESOURCE_INDEX(device));
|
||||||
}
|
}
|
||||||
|
if (uart->txDMAStream) {
|
||||||
s->txDMAChannel = uart->DMAChannel;
|
s->txDMAChannel = uart->DMAChannel;
|
||||||
s->txDMAStream = uart->txDMAStream;
|
s->txDMAStream = uart->txDMAStream;
|
||||||
|
dmaInit(dmaGetIdentifier(uart->txDMAStream), OWNER_SERIAL, RESOURCE_INDEX(device));
|
||||||
|
}
|
||||||
|
|
||||||
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
s->txDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
||||||
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
s->rxDMAPeripheralBaseAddr = (uint32_t)&s->USARTx->DR;
|
||||||
|
|
|
@ -199,7 +199,7 @@ static inline uint8_t lookupChannelIndex(const uint16_t channel)
|
||||||
|
|
||||||
rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
for (int i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
||||||
if (timerDefinitions[i].TIMx == tim) {
|
if (timerDefinitions[i].TIMx == tim) {
|
||||||
return timerDefinitions[i].rcc;
|
return timerDefinitions[i].rcc;
|
||||||
}
|
}
|
||||||
|
@ -207,6 +207,16 @@ rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t timerInputIrq(TIM_TypeDef *tim)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
||||||
|
if (timerDefinitions[i].TIMx == tim) {
|
||||||
|
return timerDefinitions[i].inputIrq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void timerNVICConfigure(uint8_t irq)
|
void timerNVICConfigure(uint8_t irq)
|
||||||
{
|
{
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
@ -239,9 +249,11 @@ void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, ui
|
||||||
{
|
{
|
||||||
configTimeBase(timerHardwarePtr->tim, period, mhz);
|
configTimeBase(timerHardwarePtr->tim, period, mhz);
|
||||||
TIM_Cmd(timerHardwarePtr->tim, ENABLE);
|
TIM_Cmd(timerHardwarePtr->tim, ENABLE);
|
||||||
timerNVICConfigure(timerHardwarePtr->irq);
|
|
||||||
|
uint8_t irq = timerInputIrq(timerHardwarePtr->tim);
|
||||||
|
timerNVICConfigure(irq);
|
||||||
// HACK - enable second IRQ on timers that need it
|
// HACK - enable second IRQ on timers that need it
|
||||||
switch(timerHardwarePtr->irq) {
|
switch(irq) {
|
||||||
#if defined(STM32F10X)
|
#if defined(STM32F10X)
|
||||||
case TIM1_CC_IRQn:
|
case TIM1_CC_IRQn:
|
||||||
timerNVICConfigure(TIM1_UP_IRQn);
|
timerNVICConfigure(TIM1_UP_IRQn);
|
||||||
|
@ -271,7 +283,7 @@ void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate and configure timer channel. Timer priority is set to highest priority of its channels
|
// allocate and configure timer channel. Timer priority is set to highest priority of its channels
|
||||||
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority)
|
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority, uint8_t irq)
|
||||||
{
|
{
|
||||||
unsigned channel = timHw - timerHardware;
|
unsigned channel = timHw - timerHardware;
|
||||||
if(channel >= USABLE_TIMER_CHANNEL_COUNT)
|
if(channel >= USABLE_TIMER_CHANNEL_COUNT)
|
||||||
|
@ -288,7 +300,7 @@ void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriori
|
||||||
|
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
NVIC_InitStructure.NVIC_IRQChannel = timHw->irq;
|
NVIC_InitStructure.NVIC_IRQChannel = irq;
|
||||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(irqPriority);
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(irqPriority);
|
||||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(irqPriority);
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(irqPriority);
|
||||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
@ -686,14 +698,14 @@ void timerInit(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* enable the timer peripherals */
|
/* enable the timer peripherals */
|
||||||
for (uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
RCC_ClockCmd(timerRCC(timerHardware[i].tim), ENABLE);
|
RCC_ClockCmd(timerRCC(timerHardware[i].tim), ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(STM32F3) || defined(STM32F4)
|
#if defined(STM32F3) || defined(STM32F4)
|
||||||
for (uint8_t timerIndex = 0; timerIndex < USABLE_TIMER_CHANNEL_COUNT; timerIndex++) {
|
for (int timerIndex = 0; timerIndex < USABLE_TIMER_CHANNEL_COUNT; timerIndex++) {
|
||||||
const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
|
const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
|
||||||
IOConfigGPIOAF(IOGetByTag(timerHardwarePtr->tag), timerHardwarePtr->ioMode, timerHardwarePtr->alternateFunction);
|
IOConfigGPIOAF(IOGetByTag(timerHardwarePtr->tag), IOCFG_AF_PP, timerHardwarePtr->alternateFunction);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -755,14 +767,11 @@ void timerForceOverflow(TIM_TypeDef *tim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const timerHardware_t *timerGetByTag(ioTag_t tag, timerFlag_e flag)
|
const timerHardware_t *timerGetByTag(ioTag_t tag, timerUsageFlag_e flag)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
if (timerHardware[i].tag == tag) {
|
if (timerHardware[i].tag == tag) {
|
||||||
if (flag && (timerHardware[i].output & flag) == flag) {
|
if (timerHardware[i].usageFlags & flag || flag == 0) {
|
||||||
return &timerHardware[i];
|
|
||||||
} else if (!flag && timerHardware[i].output == flag) {
|
|
||||||
// TODO: shift flag by one so not to be 0
|
|
||||||
return &timerHardware[i];
|
return &timerHardware[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,6 +822,7 @@ volatile timCCR_t* timerCCR(TIM_TypeDef *tim, uint8_t channel)
|
||||||
return (volatile timCCR_t*)((volatile char*)&tim->CCR1 + channel);
|
return (volatile timCCR_t*)((volatile char*)&tim->CCR1 + channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_HAL_DRIVER
|
||||||
uint16_t timerDmaSource(uint8_t channel)
|
uint16_t timerDmaSource(uint8_t channel)
|
||||||
{
|
{
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
|
@ -827,3 +837,4 @@ uint16_t timerDmaSource(uint8_t channel)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -54,6 +54,14 @@ typedef uint32_t timCNT_t;
|
||||||
#error "Unknown CPU defined"
|
#error "Unknown CPU defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TIM_USE_ANY = 0x0,
|
||||||
|
TIM_USE_PPM = 0x1,
|
||||||
|
TIM_USE_PWM = 0x2,
|
||||||
|
TIM_USE_MOTOR = 0x4,
|
||||||
|
TIM_USE_SERVO = 0x8,
|
||||||
|
TIM_USE_LED = 0x10
|
||||||
|
} timerUsageFlag_e;
|
||||||
|
|
||||||
// use different types from capture and overflow - multiple overflow handlers are implemented as linked list
|
// use different types from capture and overflow - multiple overflow handlers are implemented as linked list
|
||||||
struct timerCCHandlerRec_s;
|
struct timerCCHandlerRec_s;
|
||||||
|
@ -73,23 +81,23 @@ typedef struct timerOvrHandlerRec_s {
|
||||||
typedef struct timerDef_s {
|
typedef struct timerDef_s {
|
||||||
TIM_TypeDef *TIMx;
|
TIM_TypeDef *TIMx;
|
||||||
rccPeriphTag_t rcc;
|
rccPeriphTag_t rcc;
|
||||||
|
uint8_t inputIrq;
|
||||||
} timerDef_t;
|
} timerDef_t;
|
||||||
|
|
||||||
typedef struct timerHardware_s {
|
typedef struct timerHardware_s {
|
||||||
TIM_TypeDef *tim;
|
TIM_TypeDef *tim;
|
||||||
ioTag_t tag;
|
ioTag_t tag;
|
||||||
uint8_t channel;
|
uint8_t channel;
|
||||||
uint8_t irq;
|
timerUsageFlag_e usageFlags;
|
||||||
uint8_t output;
|
uint8_t output;
|
||||||
ioConfig_t ioMode;
|
|
||||||
#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7)
|
||||||
uint8_t alternateFunction;
|
uint8_t alternateFunction;
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_DSHOT)
|
#if defined(USE_DSHOT) || defined(LED_STRIP)
|
||||||
#if defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F4) || defined(STM32F7)
|
||||||
DMA_Stream_TypeDef *dmaStream;
|
DMA_Stream_TypeDef *dmaStream;
|
||||||
uint32_t dmaChannel;
|
uint32_t dmaChannel;
|
||||||
#elif defined(STM32F3)
|
#elif defined(STM32F3) || defined(STM32F1)
|
||||||
DMA_Channel_TypeDef *dmaChannel;
|
DMA_Channel_TypeDef *dmaChannel;
|
||||||
#endif
|
#endif
|
||||||
uint8_t dmaIrqHandler;
|
uint8_t dmaIrqHandler;
|
||||||
|
@ -97,6 +105,7 @@ typedef struct timerHardware_s {
|
||||||
} timerHardware_t;
|
} timerHardware_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
TIMER_OUTPUT_NONE = 0x00,
|
||||||
TIMER_INPUT_ENABLED = 0x00,
|
TIMER_INPUT_ENABLED = 0x00,
|
||||||
TIMER_OUTPUT_ENABLED = 0x01,
|
TIMER_OUTPUT_ENABLED = 0x01,
|
||||||
TIMER_OUTPUT_INVERTED = 0x02,
|
TIMER_OUTPUT_INVERTED = 0x02,
|
||||||
|
@ -113,6 +122,8 @@ typedef enum {
|
||||||
#endif
|
#endif
|
||||||
#elif defined(STM32F3)
|
#elif defined(STM32F3)
|
||||||
#define HARDWARE_TIMER_DEFINITION_COUNT 10
|
#define HARDWARE_TIMER_DEFINITION_COUNT 10
|
||||||
|
#elif defined(STM32F411xE)
|
||||||
|
#define HARDWARE_TIMER_DEFINITION_COUNT 10
|
||||||
#elif defined(STM32F4)
|
#elif defined(STM32F4)
|
||||||
#define HARDWARE_TIMER_DEFINITION_COUNT 14
|
#define HARDWARE_TIMER_DEFINITION_COUNT 14
|
||||||
#elif defined(STM32F7)
|
#elif defined(STM32F7)
|
||||||
|
@ -159,7 +170,7 @@ void timerChITConfigDualLo(const timerHardware_t* timHw, FunctionalState newStat
|
||||||
void timerChITConfig(const timerHardware_t* timHw, FunctionalState newState);
|
void timerChITConfig(const timerHardware_t* timHw, FunctionalState newState);
|
||||||
void timerChClearCCFlag(const timerHardware_t* timHw);
|
void timerChClearCCFlag(const timerHardware_t* timHw);
|
||||||
|
|
||||||
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority);
|
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority, uint8_t irq);
|
||||||
|
|
||||||
void timerInit(void);
|
void timerInit(void);
|
||||||
void timerStart(void);
|
void timerStart(void);
|
||||||
|
@ -170,8 +181,9 @@ uint8_t timerClockDivisor(TIM_TypeDef *tim);
|
||||||
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz); // TODO - just for migration
|
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz); // TODO - just for migration
|
||||||
|
|
||||||
rccPeriphTag_t timerRCC(TIM_TypeDef *tim);
|
rccPeriphTag_t timerRCC(TIM_TypeDef *tim);
|
||||||
|
uint8_t timerInputIrq(TIM_TypeDef *tim);
|
||||||
|
|
||||||
const timerHardware_t *timerGetByTag(ioTag_t tag, timerFlag_e flag);
|
const timerHardware_t *timerGetByTag(ioTag_t tag, timerUsageFlag_e flag);
|
||||||
|
|
||||||
#if defined(USE_HAL_DRIVER)
|
#if defined(USE_HAL_DRIVER)
|
||||||
TIM_HandleTypeDef* timerFindTimerHandle(TIM_TypeDef *tim);
|
TIM_HandleTypeDef* timerFindTimerHandle(TIM_TypeDef *tim);
|
||||||
|
|
395
src/main/drivers/timer_def.h
Normal file
395
src/main/drivers/timer_def.h
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
/*
|
||||||
|
* 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 <platform.h>
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#if defined(STM32F3)
|
||||||
|
|
||||||
|
#define DEF_TIM(tim, chan, pin, flags, out) {\
|
||||||
|
tim,\
|
||||||
|
IO_TAG(pin),\
|
||||||
|
EXPAND(DEF_CHAN_ ## chan),\
|
||||||
|
flags,\
|
||||||
|
(DEF_CHAN_ ## chan ## _OUTPUT | out),\
|
||||||
|
EXPAND(GPIO_AF__ ## pin ## _ ## tim ## _ ## chan),\
|
||||||
|
CONCAT(EXPAND(DEF_TIM_DMA__ ## tim ## _ ## chan), _CHANNEL),\
|
||||||
|
CONCAT(EXPAND(DEF_TIM_DMA__ ## tim ## _ ## chan), _HANDLER)\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEF_DMA_CHANNEL(tim, chan) CONCAT(EXPAND(DEF_TIM_DMA__ ## tim ## _ ## chan), _CHANNEL)
|
||||||
|
#define DEF_DMA_HANDLER(tim, chan) CONCAT(EXPAND(DEF_TIM_DMA__ ## tim ## _ ## chan), _HANDLER)
|
||||||
|
|
||||||
|
/* add the DMA mappings here */
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH1 DMA1_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH2 DMA1_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH4 DMA1_CH4
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH1N DMA1_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH2N DMA1_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM1_TRIG DMA1_CH4
|
||||||
|
#define DEF_TIM_DMA__TIM1_COM DMA1_CH4
|
||||||
|
#define DEF_TIM_DMA__TIM1_UP DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM1_CH3 DMA1_CH6
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA__TIM2_CH3 DMA1_CH1
|
||||||
|
#define DEF_TIM_DMA__TIM2_UP DMA1_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM2_CH1 DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM2_CH2 DMA1_CH7
|
||||||
|
#define DEF_TIM_DMA__TIM2_CH4 DMA1_CH7
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA__TIM3_CH2 DMA_NONE
|
||||||
|
#define DEF_TIM_DMA__TIM3_CH3 DMA1_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM3_CH4 DMA1_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM3_UP DMA1_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM3_CH1 DMA1_CH6
|
||||||
|
#define DEF_TIM_DMA__TIM3_TRIG DMA1_CH6
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA__TIM4_CH1 DMA1_CH1
|
||||||
|
#define DEF_TIM_DMA__TIM4_CH2 DMA1_CH4
|
||||||
|
#define DEF_TIM_DMA__TIM4_CH3 DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM4_UP DMA1_CH7
|
||||||
|
#define DEF_TIM_DMA__TIM4_CH4 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA__TIM15_CH1 DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM15_CH2 DMA_NONE
|
||||||
|
#define DEF_TIM_DMA__TIM15_UP DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM15_TRIG DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM15_COM DMA1_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM15_CH1N DMA1_CH5
|
||||||
|
|
||||||
|
#ifdef REMAP_TIM16_DMA
|
||||||
|
#define DEF_TIM_DMA__TIM16_CH1 DMA1_CH6
|
||||||
|
#define DEF_TIM_DMA__TIM16_UP DMA1_CH6
|
||||||
|
#else
|
||||||
|
#define DEF_TIM_DMA__TIM16_CH1 DMA1_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM16_UP DMA1_CH3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef REMAP_TIM17_DMA
|
||||||
|
#define DEF_TIM_DMA__TIM17_CH1 DMA1_CH7
|
||||||
|
#define DEF_TIM_DMA__TIM17_UP DMA1_CH7
|
||||||
|
#else
|
||||||
|
#define DEF_TIM_DMA__TIM17_CH1 DMA1_CH1
|
||||||
|
#define DEF_TIM_DMA__TIM17_UP DMA1_CH1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH3 DMA2_CH1
|
||||||
|
#define DEF_TIM_DMA__TIM8_UP DMA2_CH1
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH4 DMA2_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM8_TRIG DMA2_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM8_COM DMA2_CH2
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH1 DMA2_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH1N DMA2_CH3
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH2 DMA2_CH5
|
||||||
|
#define DEF_TIM_DMA__TIM8_CH2N DMA2_CH5
|
||||||
|
|
||||||
|
|
||||||
|
#define DMA1_CH1_CHANNEL DMA1_Channel1
|
||||||
|
#define DMA1_CH2_CHANNEL DMA1_Channel2
|
||||||
|
#define DMA1_CH3_CHANNEL DMA1_Channel3
|
||||||
|
#define DMA1_CH4_CHANNEL DMA1_Channel4
|
||||||
|
#define DMA1_CH5_CHANNEL DMA1_Channel5
|
||||||
|
#define DMA1_CH6_CHANNEL DMA1_Channel6
|
||||||
|
#define DMA1_CH7_CHANNEL DMA1_Channel7
|
||||||
|
#define DMA2_CH1_CHANNEL DMA2_Channel1
|
||||||
|
#define DMA2_CH2_CHANNEL DMA2_Channel2
|
||||||
|
#define DMA2_CH3_CHANNEL DMA2_Channel3
|
||||||
|
#define DMA2_CH4_CHANNEL DMA2_Channel4
|
||||||
|
#define DMA2_CH5_CHANNEL DMA2_Channel5
|
||||||
|
#define DMA2_CH6_CHANNEL DMA2_Channel6
|
||||||
|
#define DMA2_CH7_CHANNEL DMA2_Channel7
|
||||||
|
|
||||||
|
#define GPIO_AF(p, t) CONCAT(GPIO_AF__, p, _, t)
|
||||||
|
|
||||||
|
#define GPIO_AF__PA0_TIM2_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA1_TIM2_CH2 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA2_TIM2_CH3 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA3_TIM2_CH3 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA5_TIM2_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA6_TIM16_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA7_TIM17_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA12_TIM16_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA13_TIM16_CH1N GPIO_AF_1
|
||||||
|
#define GPIO_AF__PA15_TIM2_CH1 GPIO_AF_1
|
||||||
|
|
||||||
|
#define GPIO_AF__PA4_TIM3_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PA6_TIM3_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PA7_TIM3_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PA15_TIM8_CH1 GPIO_AF_2
|
||||||
|
|
||||||
|
#define GPIO_AF__PA7_TIM8_CH1N GPIO_AF_4
|
||||||
|
|
||||||
|
#define GPIO_AF__PA14_TIM4_CH2 GPIO_AF_5
|
||||||
|
|
||||||
|
#define GPIO_AF__PA7_TIM1_CH1N GPIO_AF_6
|
||||||
|
#define GPIO_AF__PA8_TIM1_CH1 GPIO_AF_6
|
||||||
|
#define GPIO_AF__PA9_TIM1_CH2 GPIO_AF_6
|
||||||
|
#define GPIO_AF__PA10_TIM1_CH3 GPIO_AF_6
|
||||||
|
#define GPIO_AF__PA11_TIM1_CH1N GPIO_AF_6
|
||||||
|
#define GPIO_AF__PA12_TIM1_CH2N GPIO_AF_6
|
||||||
|
|
||||||
|
#define GPIO_AF__PA1_TIM15_CH1N GPIO_AF_9
|
||||||
|
#define GPIO_AF__PA2_TIM15_CH1 GPIO_AF_9
|
||||||
|
#define GPIO_AF__PA3_TIM15_CH2 GPIO_AF_9
|
||||||
|
|
||||||
|
#define GPIO_AF__PA9_TIM2_CH3 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PA10_TIM2_CH4 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PA11_TIM4_CH1 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PA12_TIM4_CH2 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PA13_TIM4_CH3 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PA11_TIM1_CH4 GPIO_AF_11
|
||||||
|
|
||||||
|
#define GPIO_AF__PB3_TIM2_CH2 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB4_TIM16_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB6_TIM16_CH1N GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB7_TIM17_CH1N GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB8_TIM16_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB9_TIM17_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB10_TIM2_CH3 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB11_TIM2_CH4 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB14_TIM15_CH1 GPIO_AF_1
|
||||||
|
#define GPIO_AF__PB15_TIM15_CH2 GPIO_AF_1
|
||||||
|
|
||||||
|
#define GPIO_AF__PB0_TIM3_CH3 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB1_TIM3_CH4 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB4_TIM3_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB5_TIM3_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB6_TIM4_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB7_TIM4_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB8_TIM4_CH3 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB9_TIM4_CH4 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PB15_TIM15_CH1N GPIO_AF_2
|
||||||
|
|
||||||
|
#define GPIO_AF__PB0_TIM8_CH2N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PB1_TIM8_CH3N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PB3_TIM8_CH1N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PB4_TIM8_CH2N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PB15_TIM1_CH3N GPIO_AF_4
|
||||||
|
|
||||||
|
#define GPIO_AF__PB6_TIM8_CH1 GPIO_AF_5
|
||||||
|
|
||||||
|
#define GPIO_AF__PB0_TIM1_CH2N GPIO_AF_6
|
||||||
|
#define GPIO_AF__PB1_TIM1_CH3N GPIO_AF_6
|
||||||
|
#define GPIO_AF__PB13_TIM1_CH1N GPIO_AF_6
|
||||||
|
#define GPIO_AF__PB14_TIM1_CH2N GPIO_AF_6
|
||||||
|
|
||||||
|
#define GPIO_AF__PB5_TIM17_CH1 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PB7_TIM3_CH4 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PB8_TIM8_CH2 GPIO_AF_10
|
||||||
|
#define GPIO_AF__PB9_TIM8_CH3 GPIO_AF_10
|
||||||
|
|
||||||
|
#define GPIO_AF__PC6_TIM3_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PC7_TIM3_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PC8_TIM3_CH3 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PC9_TIM3_CH4 GPIO_AF_2
|
||||||
|
|
||||||
|
#define GPIO_AF__PC6_TIM8_CH1 GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC7_TIM8_CH2 GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC8_TIM8_CH3 GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC9_TIM8_CH4 GPIO_AF_4
|
||||||
|
|
||||||
|
#define GPIO_AF__PC10_TIM8_CH1N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC11_TIM8_CH2N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC12_TIM8_CH3N GPIO_AF_4
|
||||||
|
#define GPIO_AF__PC13_TIM8_CH1N GPIO_AF_4
|
||||||
|
|
||||||
|
#define GPIO_AF__PD3_TIM2_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD4_TIM2_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD6_TIM2_CH4 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD7_TIM2_CH3 GPIO_AF_2
|
||||||
|
|
||||||
|
#define GPIO_AF__PD12_TIM4_CH1 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD13_TIM4_CH2 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD14_TIM4_CH3 GPIO_AF_2
|
||||||
|
#define GPIO_AF__PD15_TIM4_CH4 GPIO_AF_2
|
||||||
|
|
||||||
|
#define GPIO_AF__PD1_TIM8_CH4 GPIO_AF_4
|
||||||
|
|
||||||
|
#elif defined(STM32F4)
|
||||||
|
|
||||||
|
#define DEF_TIM(tim, chan, pin, flags, out, dmaopt) {\
|
||||||
|
tim,\
|
||||||
|
IO_TAG(pin),\
|
||||||
|
EXPAND(DEF_CHAN_ ## chan),\
|
||||||
|
flags,\
|
||||||
|
(DEF_CHAN_ ## chan ## _OUTPUT | out),\
|
||||||
|
EXPAND(GPIO_AF_## tim),\
|
||||||
|
CONCAT(EXPAND(DEF_TIM_DMA_STR_ ## dmaopt ## __ ## tim ## _ ## chan), _STREAM),\
|
||||||
|
EXPAND(DEF_TIM_DMA_CHN_ ## dmaopt ## __ ## tim ## _ ## chan),\
|
||||||
|
CONCAT(EXPAND(DEF_TIM_DMA_STR_ ## dmaopt ## __ ## tim ## _ ## chan), _HANDLER)\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEF_DMA_CHANNEL(tim, chan, dmaopt) EXPAND(DEF_TIM_DMA_CHN_ ## dmaopt ## __ ## tim ## _ ## chan)
|
||||||
|
#define DEF_DMA_STREAM(tim, chan, dmaopt) CONCAT(EXPAND(DEF_TIM_DMA_STR_ ## dmaopt ## __ ## tim ## _ ## chan), _STREAM)
|
||||||
|
#define DEF_DMA_HANDLER(tim, chan, dmaopt) CONCAT(EXPAND(DEF_TIM_DMA_STR_ ## dmaopt ## __ ## tim ## _ ## chan), _HANDLER)
|
||||||
|
|
||||||
|
/* F4 Stream Mappings */
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM1_CH1 DMA2_ST6
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM1_CH1 DMA2_ST1
|
||||||
|
#define DEF_TIM_DMA_STR_2__TIM1_CH1 DMA2_ST3
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM1_CH2 DMA2_ST6
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM1_CH2 DMA2_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM1_CH3 DMA2_ST6
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM1_CH3 DMA2_ST6
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM1_CH4 DMA2_ST4
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM2_CH1 DMA1_ST5
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM2_CH2 DMA1_ST6
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM2_CH3 DMA1_ST1
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM2_CH4 DMA1_ST7
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM2_CH4 DMA1_ST6
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM3_CH1 DMA1_ST4
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM3_CH2 DMA1_ST5
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM3_CH3 DMA1_ST7
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM3_CH4 DMA1_ST2
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM4_CH1 DMA1_ST0
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM4_CH2 DMA1_ST4
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM4_CH3 DMA1_ST7
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM4_CH4 DMA1_ST3
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM5_CH1 DMA1_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM5_CH2 DMA1_ST4
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM5_CH3 DMA1_ST0
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM5_CH4 DMA1_ST1
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM5_CH4 DMA1_ST3
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM8_CH1 DMA2_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM8_CH1 DMA2_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM8_CH2 DMA2_ST3
|
||||||
|
#define DEF_TIM_DMA_STR_1__TIM8_CH2 DMA2_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM8_CH3 DMA2_ST2
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM8_CH4 DMA2_ST7
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM9_CH1 DMA_NONE
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM9_CH2 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM10_CH1 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM11_CH1 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM12_CH1 DMA_NONE
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM12_CH2 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM13_CH1 DMA_NONE
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_STR_0__TIM14_CH1 DMA_NONE
|
||||||
|
|
||||||
|
/* F4 Channel Mappings */
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM1_CH1 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM1_CH1 DMA_Channel_6
|
||||||
|
#define DEF_TIM_DMA_CHN_2__TIM1_CH1 DMA_Channel_6
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM1_CH2 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM1_CH2 DMA_Channel_6
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM1_CH3 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM1_CH3 DMA_Channel_6
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM1_CH4 DMA_Channel_6
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM2_CH1 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM2_CH2 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM2_CH3 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM2_CH4 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM2_CH4 DMA_Channel_3
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM3_CH1 DMA_Channel_5
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM3_CH2 DMA_Channel_5
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM3_CH3 DMA_Channel_5
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM3_CH4 DMA_Channel_5
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM4_CH1 DMA_Channel_2
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM4_CH2 DMA_Channel_2
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM4_CH3 DMA_Channel_2
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM4_CH4 DMA_Channel_2
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM5_CH1 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM5_CH2 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM5_CH3 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM5_CH4 DMA_Channel_3
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM5_CH4 DMA_Channel_3
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM8_CH1 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM8_CH1 DMA_Channel_7
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM8_CH2 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_1__TIM8_CH2 DMA_Channel_7
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM8_CH3 DMA_Channel_0
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM8_CH4 DMA_Channel_7
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM9_CH1 0
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM9_CH2 0
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM10_CH1 0
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM11_CH1 0
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM12_CH1 0
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM12_CH2 0
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM13_CH1 0
|
||||||
|
|
||||||
|
#define DEF_TIM_DMA_CHN_0__TIM14_CH1 0
|
||||||
|
|
||||||
|
#define DMA1_ST0_STREAM DMA1_Stream0
|
||||||
|
#define DMA1_ST1_STREAM DMA1_Stream1
|
||||||
|
#define DMA1_ST2_STREAM DMA1_Stream2
|
||||||
|
#define DMA1_ST3_STREAM DMA1_Stream3
|
||||||
|
#define DMA1_ST4_STREAM DMA1_Stream4
|
||||||
|
#define DMA1_ST5_STREAM DMA1_Stream5
|
||||||
|
#define DMA1_ST6_STREAM DMA1_Stream6
|
||||||
|
#define DMA1_ST7_STREAM DMA1_Stream7
|
||||||
|
#define DMA2_ST0_STREAM DMA2_Stream0
|
||||||
|
#define DMA2_ST1_STREAM DMA2_Stream1
|
||||||
|
#define DMA2_ST2_STREAM DMA2_Stream2
|
||||||
|
#define DMA2_ST3_STREAM DMA2_Stream3
|
||||||
|
#define DMA2_ST4_STREAM DMA2_Stream4
|
||||||
|
#define DMA2_ST5_STREAM DMA2_Stream5
|
||||||
|
#define DMA2_ST6_STREAM DMA2_Stream6
|
||||||
|
#define DMA2_ST7_STREAM DMA2_Stream7
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**** Common Defines across all targets ****/
|
||||||
|
#define DMA_NONE_CHANNEL NULL
|
||||||
|
#define DMA_NONE_STREAM NULL
|
||||||
|
|
||||||
|
|
||||||
|
#define DEF_TIM_CHAN(chan) DEF_CHAN_ ## chan
|
||||||
|
#define DEF_TIM_OUTPUT(chan, out) ( DEF_CHAN_ ## chan ## _OUTPUT | out )
|
||||||
|
|
||||||
|
#define DMA_NONE_HANDLER 0
|
||||||
|
|
||||||
|
#define DEF_CHAN_CH1 TIM_Channel_1
|
||||||
|
#define DEF_CHAN_CH2 TIM_Channel_2
|
||||||
|
#define DEF_CHAN_CH3 TIM_Channel_3
|
||||||
|
#define DEF_CHAN_CH4 TIM_Channel_4
|
||||||
|
#define DEF_CHAN_CH1N TIM_Channel_1
|
||||||
|
#define DEF_CHAN_CH2N TIM_Channel_2
|
||||||
|
#define DEF_CHAN_CH3N TIM_Channel_3
|
||||||
|
#define DEF_CHAN_CH4N TIM_Channel_4
|
||||||
|
|
||||||
|
#define DEF_CHAN_CH1_OUTPUT TIMER_OUTPUT_NONE
|
||||||
|
#define DEF_CHAN_CH2_OUTPUT TIMER_OUTPUT_NONE
|
||||||
|
#define DEF_CHAN_CH3_OUTPUT TIMER_OUTPUT_NONE
|
||||||
|
#define DEF_CHAN_CH4_OUTPUT TIMER_OUTPUT_NONE
|
||||||
|
#define DEF_CHAN_CH1N_OUTPUT TIMER_OUTPUT_N_CHANNEL
|
||||||
|
#define DEF_CHAN_CH2N_OUTPUT TIMER_OUTPUT_N_CHANNEL
|
||||||
|
#define DEF_CHAN_CH3N_OUTPUT TIMER_OUTPUT_N_CHANNEL
|
||||||
|
#define DEF_CHAN_CH4N_OUTPUT TIMER_OUTPUT_N_CHANNEL
|
|
@ -208,7 +208,7 @@ static inline uint8_t lookupChannelIndex(const uint16_t channel)
|
||||||
|
|
||||||
rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
for (int i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
||||||
if (timerDefinitions[i].TIMx == tim) {
|
if (timerDefinitions[i].TIMx == tim) {
|
||||||
return timerDefinitions[i].rcc;
|
return timerDefinitions[i].rcc;
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,16 @@ rccPeriphTag_t timerRCC(TIM_TypeDef *tim)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t timerInputIrq(TIM_TypeDef *tim)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < HARDWARE_TIMER_DEFINITION_COUNT; i++) {
|
||||||
|
if (timerDefinitions[i].TIMx == tim) {
|
||||||
|
return timerDefinitions[i].inputIrq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void timerNVICConfigure(uint8_t irq)
|
void timerNVICConfigure(uint8_t irq)
|
||||||
{
|
{
|
||||||
HAL_NVIC_SetPriority(irq, NVIC_PRIORITY_BASE(NVIC_PRIO_TIMER), NVIC_PRIORITY_SUB(NVIC_PRIO_TIMER));
|
HAL_NVIC_SetPriority(irq, NVIC_PRIORITY_BASE(NVIC_PRIO_TIMER), NVIC_PRIORITY_SUB(NVIC_PRIO_TIMER));
|
||||||
|
@ -285,9 +295,11 @@ void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, ui
|
||||||
|
|
||||||
configTimeBase(timerHardwarePtr->tim, period, mhz);
|
configTimeBase(timerHardwarePtr->tim, period, mhz);
|
||||||
HAL_TIM_Base_Start(&timerHandle[timerIndex].Handle);
|
HAL_TIM_Base_Start(&timerHandle[timerIndex].Handle);
|
||||||
timerNVICConfigure(timerHardwarePtr->irq);
|
|
||||||
|
uint8_t irq = timerInputIrq(timerHardwarePtr->tim);
|
||||||
|
timerNVICConfigure(irq);
|
||||||
// HACK - enable second IRQ on timers that need it
|
// HACK - enable second IRQ on timers that need it
|
||||||
switch(timerHardwarePtr->irq) {
|
switch(irq) {
|
||||||
|
|
||||||
case TIM1_CC_IRQn:
|
case TIM1_CC_IRQn:
|
||||||
timerNVICConfigure(TIM1_UP_TIM10_IRQn);
|
timerNVICConfigure(TIM1_UP_TIM10_IRQn);
|
||||||
|
@ -300,7 +312,7 @@ void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate and configure timer channel. Timer priority is set to highest priority of its channels
|
// allocate and configure timer channel. Timer priority is set to highest priority of its channels
|
||||||
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority)
|
void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriority, uint8_t irq)
|
||||||
{
|
{
|
||||||
uint8_t timerIndex = lookupTimerIndex(timHw->tim);
|
uint8_t timerIndex = lookupTimerIndex(timHw->tim);
|
||||||
if (timerIndex >= USED_TIMER_COUNT) {
|
if (timerIndex >= USED_TIMER_COUNT) {
|
||||||
|
@ -320,8 +332,8 @@ void timerChInit(const timerHardware_t *timHw, channelType_t type, int irqPriori
|
||||||
HAL_TIM_Base_Start(&timerHandle[timerIndex].Handle);
|
HAL_TIM_Base_Start(&timerHandle[timerIndex].Handle);
|
||||||
|
|
||||||
|
|
||||||
HAL_NVIC_SetPriority(timHw->irq, NVIC_PRIORITY_BASE(irqPriority), NVIC_PRIORITY_SUB(irqPriority));
|
HAL_NVIC_SetPriority(irq, NVIC_PRIORITY_BASE(irqPriority), NVIC_PRIORITY_SUB(irqPriority));
|
||||||
HAL_NVIC_EnableIRQ(timHw->irq);
|
HAL_NVIC_EnableIRQ(irq);
|
||||||
|
|
||||||
timerInfo[timer].priority = irqPriority;
|
timerInfo[timer].priority = irqPriority;
|
||||||
}
|
}
|
||||||
|
@ -787,14 +799,14 @@ void timerInit(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* enable the timer peripherals */
|
/* enable the timer peripherals */
|
||||||
for (uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
RCC_ClockCmd(timerRCC(timerHardware[i].tim), ENABLE);
|
RCC_ClockCmd(timerRCC(timerHardware[i].tim), ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7)
|
#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7)
|
||||||
for (uint8_t timerIndex = 0; timerIndex < USABLE_TIMER_CHANNEL_COUNT; timerIndex++) {
|
for (int timerIndex = 0; timerIndex < USABLE_TIMER_CHANNEL_COUNT; timerIndex++) {
|
||||||
const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
|
const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
|
||||||
IOConfigGPIOAF(IOGetByTag(timerHardwarePtr->tag), timerHardwarePtr->ioMode, timerHardwarePtr->alternateFunction);
|
IOConfigGPIOAF(IOGetByTag(timerHardwarePtr->tag), IOCFG_AF_PP, timerHardwarePtr->alternateFunction);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -856,17 +868,29 @@ void timerForceOverflow(TIM_TypeDef *tim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const timerHardware_t *timerGetByTag(ioTag_t tag, timerFlag_e flag)
|
const timerHardware_t *timerGetByTag(ioTag_t tag, timerUsageFlag_e flag)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
if (timerHardware[i].tag == tag) {
|
if (timerHardware[i].tag == tag) {
|
||||||
if (flag && (timerHardware[i].output & flag) == flag) {
|
if (timerHardware[i].output & flag) {
|
||||||
return &timerHardware[i];
|
|
||||||
} else if (!flag && timerHardware[i].output == flag) {
|
|
||||||
// TODO: shift flag by one so not to be 0
|
|
||||||
return &timerHardware[i];
|
return &timerHardware[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t timerDmaSource(uint8_t channel)
|
||||||
|
{
|
||||||
|
switch (channel) {
|
||||||
|
case TIM_CHANNEL_1:
|
||||||
|
return TIM_DMA_ID_CC1;
|
||||||
|
case TIM_CHANNEL_2:
|
||||||
|
return TIM_DMA_ID_CC2;
|
||||||
|
case TIM_CHANNEL_3:
|
||||||
|
return TIM_DMA_ID_CC3;
|
||||||
|
case TIM_CHANNEL_4:
|
||||||
|
return TIM_DMA_ID_CC4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1) },
|
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1), .inputIrq = TIM1_CC_IRQn },
|
||||||
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2) },
|
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2), .inputIrq = TIM2_IRQn },
|
||||||
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3) },
|
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3), .inputIrq = TIM3_IRQn },
|
||||||
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4) },
|
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4), .inputIrq = TIM4_IRQn },
|
||||||
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6) },
|
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6), .inputIrq = 0 },
|
||||||
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7) },
|
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7), .inputIrq = 0 },
|
||||||
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8) },
|
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8), .inputIrq = TIM8_CC_IRQn },
|
||||||
{ .TIMx = TIM15, .rcc = RCC_APB2(TIM15) },
|
{ .TIMx = TIM15, .rcc = RCC_APB2(TIM15), .inputIrq = TIM1_BRK_TIM15_IRQn },
|
||||||
{ .TIMx = TIM16, .rcc = RCC_APB2(TIM16) },
|
{ .TIMx = TIM16, .rcc = RCC_APB2(TIM16), .inputIrq = TIM1_UP_TIM16_IRQn },
|
||||||
{ .TIMx = TIM17, .rcc = RCC_APB2(TIM17) },
|
{ .TIMx = TIM17, .rcc = RCC_APB2(TIM17), .inputIrq = TIM1_TRG_COM_TIM17_IRQn },
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
||||||
|
|
|
@ -42,20 +42,24 @@
|
||||||
#define CCMR_Offset ((uint16_t)0x0018)
|
#define CCMR_Offset ((uint16_t)0x0018)
|
||||||
|
|
||||||
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1) },
|
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1), .inputIrq = TIM1_CC_IRQn},
|
||||||
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2) },
|
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2), .inputIrq = TIM2_IRQn},
|
||||||
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3) },
|
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3), .inputIrq = TIM3_IRQn},
|
||||||
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4) },
|
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4), .inputIrq = TIM4_IRQn},
|
||||||
{ .TIMx = TIM5, .rcc = RCC_APB1(TIM5) },
|
{ .TIMx = TIM5, .rcc = RCC_APB1(TIM5), .inputIrq = TIM5_IRQn},
|
||||||
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6) },
|
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6), .inputIrq = 0},
|
||||||
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7) },
|
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7), .inputIrq = 0},
|
||||||
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8) },
|
#ifndef STM32F411xE
|
||||||
{ .TIMx = TIM9, .rcc = RCC_APB2(TIM9) },
|
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8), .inputIrq = TIM8_CC_IRQn},
|
||||||
{ .TIMx = TIM10, .rcc = RCC_APB2(TIM10) },
|
#endif
|
||||||
{ .TIMx = TIM11, .rcc = RCC_APB2(TIM11) },
|
{ .TIMx = TIM9, .rcc = RCC_APB2(TIM9), .inputIrq = TIM1_BRK_TIM9_IRQn},
|
||||||
{ .TIMx = TIM12, .rcc = RCC_APB1(TIM12) },
|
{ .TIMx = TIM10, .rcc = RCC_APB2(TIM10), .inputIrq = TIM1_UP_TIM10_IRQn},
|
||||||
{ .TIMx = TIM13, .rcc = RCC_APB1(TIM13) },
|
{ .TIMx = TIM11, .rcc = RCC_APB2(TIM11), .inputIrq = TIM1_TRG_COM_TIM11_IRQn},
|
||||||
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14) },
|
#ifndef STM32F411xE
|
||||||
|
{ .TIMx = TIM12, .rcc = RCC_APB1(TIM12), .inputIrq = TIM8_BRK_TIM12_IRQn},
|
||||||
|
{ .TIMx = TIM13, .rcc = RCC_APB1(TIM13), .inputIrq = TIM8_UP_TIM13_IRQn},
|
||||||
|
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14), .inputIrq = TIM8_TRG_COM_TIM14_IRQn},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -42,20 +42,20 @@
|
||||||
#define CCMR_Offset ((uint16_t)0x0018)
|
#define CCMR_Offset ((uint16_t)0x0018)
|
||||||
|
|
||||||
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1) },
|
{ .TIMx = TIM1, .rcc = RCC_APB2(TIM1), .inputIrq = TIM1_CC_IRQn},
|
||||||
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2) },
|
{ .TIMx = TIM2, .rcc = RCC_APB1(TIM2), .inputIrq = TIM2_IRQn},
|
||||||
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3) },
|
{ .TIMx = TIM3, .rcc = RCC_APB1(TIM3), .inputIrq = TIM3_IRQn},
|
||||||
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4) },
|
{ .TIMx = TIM4, .rcc = RCC_APB1(TIM4), .inputIrq = TIM4_IRQn},
|
||||||
{ .TIMx = TIM5, .rcc = RCC_APB1(TIM5) },
|
{ .TIMx = TIM5, .rcc = RCC_APB1(TIM5), .inputIrq = TIM5_IRQn},
|
||||||
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6) },
|
{ .TIMx = TIM6, .rcc = RCC_APB1(TIM6), .inputIrq = 0},
|
||||||
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7) },
|
{ .TIMx = TIM7, .rcc = RCC_APB1(TIM7), .inputIrq = 0},
|
||||||
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8) },
|
{ .TIMx = TIM8, .rcc = RCC_APB2(TIM8), .inputIrq = TIM8_CC_IRQn},
|
||||||
{ .TIMx = TIM9, .rcc = RCC_APB2(TIM9) },
|
{ .TIMx = TIM9, .rcc = RCC_APB2(TIM9), .inputIrq = TIM1_BRK_TIM9_IRQn},
|
||||||
{ .TIMx = TIM10, .rcc = RCC_APB2(TIM10) },
|
{ .TIMx = TIM10, .rcc = RCC_APB2(TIM10), .inputIrq = TIM1_UP_TIM10_IRQn},
|
||||||
{ .TIMx = TIM11, .rcc = RCC_APB2(TIM11) },
|
{ .TIMx = TIM11, .rcc = RCC_APB2(TIM11), .inputIrq = TIM1_TRG_COM_TIM11_IRQn},
|
||||||
{ .TIMx = TIM12, .rcc = RCC_APB1(TIM12) },
|
{ .TIMx = TIM12, .rcc = RCC_APB1(TIM12), .inputIrq = TIM8_BRK_TIM12_IRQn},
|
||||||
{ .TIMx = TIM13, .rcc = RCC_APB1(TIM13) },
|
{ .TIMx = TIM13, .rcc = RCC_APB1(TIM13), .inputIrq = TIM8_UP_TIM13_IRQn},
|
||||||
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14) },
|
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14), .inputIrq = TIM8_TRG_COM_TIM14_IRQn},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -96,6 +96,7 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
|
|
||||||
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
||||||
{
|
{
|
||||||
|
UNUSED(tim);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include "blackbox/blackbox_io.h"
|
#include "blackbox/blackbox_io.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "common/axis.h"
|
#include "common/axis.h"
|
||||||
#include "common/maths.h"
|
#include "common/maths.h"
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
#include "drivers/pwm_output.h"
|
#include "drivers/pwm_output.h"
|
||||||
#include "drivers/max7456.h"
|
#include "drivers/max7456.h"
|
||||||
#include "drivers/sound_beeper.h"
|
#include "drivers/sound_beeper.h"
|
||||||
|
#include "drivers/light_ws2811strip.h"
|
||||||
|
|
||||||
#include "fc/config.h"
|
#include "fc/config.h"
|
||||||
#include "fc/rc_controls.h"
|
#include "fc/rc_controls.h"
|
||||||
|
@ -238,11 +241,39 @@ void resetSensorAlignment(sensorAlignmentConfig_t *sensorAlignmentConfig)
|
||||||
sensorAlignmentConfig->mag_align = ALIGN_DEFAULT;
|
sensorAlignmentConfig->mag_align = ALIGN_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LED_STRIP
|
||||||
|
void resetLedStripConfig(ledStripConfig_t *ledStripConfig)
|
||||||
|
{
|
||||||
|
applyDefaultColors(ledStripConfig->colors);
|
||||||
|
applyDefaultLedStripConfig(ledStripConfig->ledConfigs);
|
||||||
|
applyDefaultModeColors(ledStripConfig->modeColors);
|
||||||
|
applyDefaultSpecialColors(&(ledStripConfig->specialColors));
|
||||||
|
ledStripConfig->ledstrip_visual_beeper = 0;
|
||||||
|
ledStripConfig->ledstrip_aux_channel = THROTTLE;
|
||||||
|
|
||||||
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
|
if (timerHardware[i].usageFlags & TIM_USE_LED) {
|
||||||
|
ledStripConfig->ioTag = timerHardware[i].tag;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ledStripConfig->ioTag = IO_TAG_NONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SERVOS
|
#ifdef USE_SERVOS
|
||||||
void resetServoConfig(servoConfig_t *servoConfig)
|
void resetServoConfig(servoConfig_t *servoConfig)
|
||||||
{
|
{
|
||||||
servoConfig->servoCenterPulse = 1500;
|
servoConfig->servoCenterPulse = 1500;
|
||||||
servoConfig->servoPwmRate = 50;
|
servoConfig->servoPwmRate = 50;
|
||||||
|
|
||||||
|
int servoIndex = 0;
|
||||||
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT && servoIndex < MAX_SUPPORTED_SERVOS; i++) {
|
||||||
|
if (timerHardware[i].usageFlags & TIM_USE_SERVO) {
|
||||||
|
servoConfig->ioTags[servoIndex] = timerHardware[i].tag;
|
||||||
|
servoIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -262,9 +293,9 @@ void resetMotorConfig(motorConfig_t *motorConfig)
|
||||||
motorConfig->mincommand = 1000;
|
motorConfig->mincommand = 1000;
|
||||||
motorConfig->digitalIdleOffset = 40;
|
motorConfig->digitalIdleOffset = 40;
|
||||||
|
|
||||||
uint8_t motorIndex = 0;
|
int motorIndex = 0;
|
||||||
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT && i < MAX_SUPPORTED_MOTORS; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT && motorIndex < MAX_SUPPORTED_MOTORS; i++) {
|
||||||
if ((timerHardware[i].output & TIMER_OUTPUT_ENABLED) == TIMER_OUTPUT_ENABLED) {
|
if (timerHardware[i].usageFlags & TIM_USE_MOTOR) {
|
||||||
motorConfig->ioTags[motorIndex] = timerHardware[i].tag;
|
motorConfig->ioTags[motorIndex] = timerHardware[i].tag;
|
||||||
motorIndex++;
|
motorIndex++;
|
||||||
}
|
}
|
||||||
|
@ -304,7 +335,7 @@ void resetPpmConfig(ppmConfig_t *ppmConfig)
|
||||||
ppmConfig->ioTag = IO_TAG(PPM_PIN);
|
ppmConfig->ioTag = IO_TAG(PPM_PIN);
|
||||||
#else
|
#else
|
||||||
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
|
||||||
if ((timerHardware[i].output == TIMER_INPUT_ENABLED)) {
|
if (timerHardware[i].usageFlags & TIM_USE_PPM) {
|
||||||
ppmConfig->ioTag = timerHardware[i].tag;
|
ppmConfig->ioTag = timerHardware[i].tag;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -316,9 +347,9 @@ void resetPpmConfig(ppmConfig_t *ppmConfig)
|
||||||
|
|
||||||
void resetPwmConfig(pwmConfig_t *pwmConfig)
|
void resetPwmConfig(pwmConfig_t *pwmConfig)
|
||||||
{
|
{
|
||||||
uint8_t inputIndex = 0;
|
int inputIndex = 0;
|
||||||
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT && inputIndex < PWM_INPUT_PORT_COUNT; i++) {
|
for (int i = 0; i < USABLE_TIMER_CHANNEL_COUNT && inputIndex < PWM_INPUT_PORT_COUNT; i++) {
|
||||||
if ((timerHardware[i].output == TIMER_INPUT_ENABLED)) {
|
if (timerHardware[i].usageFlags & TIM_USE_PWM) {
|
||||||
pwmConfig->ioTags[inputIndex] = timerHardware[i].tag;
|
pwmConfig->ioTags[inputIndex] = timerHardware[i].tag;
|
||||||
inputIndex++;
|
inputIndex++;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +498,7 @@ void createDefaultConfig(master_t *config)
|
||||||
|
|
||||||
#ifdef OSD
|
#ifdef OSD
|
||||||
intFeatureSet(FEATURE_OSD, config);
|
intFeatureSet(FEATURE_OSD, config);
|
||||||
resetOsdConfig(&config->osdProfile);
|
osdResetConfig(&config->osdProfile);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BOARD_HAS_VOLTAGE_DIVIDER
|
#ifdef BOARD_HAS_VOLTAGE_DIVIDER
|
||||||
|
@ -589,6 +620,10 @@ void createDefaultConfig(master_t *config)
|
||||||
#endif
|
#endif
|
||||||
resetFlight3DConfig(&config->flight3DConfig);
|
resetFlight3DConfig(&config->flight3DConfig);
|
||||||
|
|
||||||
|
#ifdef LED_STRIP
|
||||||
|
resetLedStripConfig(&config->ledStripConfig);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
// gps/nav stuff
|
// gps/nav stuff
|
||||||
config->gpsConfig.provider = GPS_NMEA;
|
config->gpsConfig.provider = GPS_NMEA;
|
||||||
|
@ -658,14 +693,6 @@ void createDefaultConfig(master_t *config)
|
||||||
config->customMotorMixer[i].throttle = 0.0f;
|
config->customMotorMixer[i].throttle = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LED_STRIP
|
|
||||||
applyDefaultColors(config->colors);
|
|
||||||
applyDefaultLedStripConfig(config->ledConfigs);
|
|
||||||
applyDefaultModeColors(config->modeColors);
|
|
||||||
applyDefaultSpecialColors(&(config->specialColors));
|
|
||||||
config->ledstrip_visual_beeper = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VTX
|
#ifdef VTX
|
||||||
config->vtx_band = 4; //Fatshark/Airwaves
|
config->vtx_band = 4; //Fatshark/Airwaves
|
||||||
config->vtx_channel = 1; //CH1
|
config->vtx_channel = 1; //CH1
|
||||||
|
@ -867,21 +894,6 @@ void validateAndFixConfig(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LED_STRIP) && (defined(USE_SOFTSERIAL1) || defined(USE_SOFTSERIAL2))
|
|
||||||
if (featureConfigured(FEATURE_SOFTSERIAL) && (
|
|
||||||
0
|
|
||||||
#ifdef USE_SOFTSERIAL1
|
|
||||||
|| (WS2811_TIMER == SOFTSERIAL_1_TIMER)
|
|
||||||
#endif
|
|
||||||
#ifdef USE_SOFTSERIAL2
|
|
||||||
|| (WS2811_TIMER == SOFTSERIAL_2_TIMER)
|
|
||||||
#endif
|
|
||||||
)) {
|
|
||||||
// led strip needs the same timer as softserial
|
|
||||||
featureClear(FEATURE_LED_STRIP);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(NAZE) && defined(SONAR)
|
#if defined(NAZE) && defined(SONAR)
|
||||||
if (featureConfigured(FEATURE_RX_PARALLEL_PWM) && featureConfigured(FEATURE_SONAR) && featureConfigured(FEATURE_CURRENT_METER) && masterConfig.batteryConfig.currentMeterType == CURRENT_SENSOR_ADC) {
|
if (featureConfigured(FEATURE_RX_PARALLEL_PWM) && featureConfigured(FEATURE_SONAR) && featureConfigured(FEATURE_CURRENT_METER) && masterConfig.batteryConfig.currentMeterType == CURRENT_SENSOR_ADC) {
|
||||||
featureClear(FEATURE_CURRENT_METER);
|
featureClear(FEATURE_CURRENT_METER);
|
||||||
|
@ -895,18 +907,11 @@ void validateAndFixConfig(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CC3D) && defined(DISPLAY) && defined(USE_UART3)
|
#if defined(CC3D) && defined(DISPLAY) && defined(USE_UART3)
|
||||||
if (doesConfigurationUsePort(SERIAL_PORT_USART3) && feature(FEATURE_DISPLAY)) {
|
if (doesConfigurationUsePort(SERIAL_PORT_USART3) && feature(FEATURE_DASHBOARD)) {
|
||||||
featureClear(FEATURE_DISPLAY);
|
featureClear(FEATURE_DASHBOARD);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*#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)) {
|
|
||||||
featureClear(FEATURE_LED_STRIP);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CC3D) && defined(SONAR) && defined(USE_SOFTSERIAL1) && defined(RSSI_ADC_GPIO)
|
#if defined(CC3D) && defined(SONAR) && defined(USE_SOFTSERIAL1) && defined(RSSI_ADC_GPIO)
|
||||||
// shared pin
|
// shared pin
|
||||||
if ((featureConfigured(FEATURE_SONAR) + featureConfigured(FEATURE_SOFTSERIAL) + featureConfigured(FEATURE_RSSI_ADC)) > 1) {
|
if ((featureConfigured(FEATURE_SONAR) + featureConfigured(FEATURE_SOFTSERIAL) + featureConfigured(FEATURE_RSSI_ADC)) > 1) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ typedef enum {
|
||||||
FEATURE_RX_MSP = 1 << 14,
|
FEATURE_RX_MSP = 1 << 14,
|
||||||
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_DASHBOARD = 1 << 17,
|
||||||
FEATURE_OSD = 1 << 18,
|
FEATURE_OSD = 1 << 18,
|
||||||
FEATURE_BLACKBOX = 1 << 19,
|
FEATURE_BLACKBOX = 1 << 19,
|
||||||
FEATURE_CHANNEL_FORWARDING = 1 << 20,
|
FEATURE_CHANNEL_FORWARDING = 1 << 20,
|
||||||
|
|
|
@ -62,9 +62,7 @@
|
||||||
#include "io/flashfs.h"
|
#include "io/flashfs.h"
|
||||||
#include "io/transponder_ir.h"
|
#include "io/transponder_ir.h"
|
||||||
#include "io/asyncfatfs/asyncfatfs.h"
|
#include "io/asyncfatfs/asyncfatfs.h"
|
||||||
#include "io/osd.h"
|
|
||||||
#include "io/serial_4way.h"
|
#include "io/serial_4way.h"
|
||||||
#include "io/vtx.h"
|
|
||||||
|
|
||||||
#include "msp/msp.h"
|
#include "msp/msp.h"
|
||||||
#include "msp/msp_protocol.h"
|
#include "msp/msp_protocol.h"
|
||||||
|
@ -648,10 +646,8 @@ static bool mspFcProcessOutCommand(uint8_t cmdMSP, sbuf_t *dst, mspPostProcessFn
|
||||||
sbufWriteU16(dst, 0);
|
sbufWriteU16(dst, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isMotorProtocolDshot())
|
|
||||||
sbufWriteU16(dst, constrain((motor[i] / 2) + 1000, 1000, 2000)); // This is to get it working in the configurator
|
sbufWriteU16(dst, convertMotorToExternal(motor[i]));
|
||||||
else
|
|
||||||
sbufWriteU16(dst, motor[i]);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MSP_RC:
|
case MSP_RC:
|
||||||
|
@ -934,7 +930,7 @@ static bool mspFcProcessOutCommand(uint8_t cmdMSP, sbuf_t *dst, mspPostProcessFn
|
||||||
#ifdef LED_STRIP
|
#ifdef LED_STRIP
|
||||||
case MSP_LED_COLORS:
|
case MSP_LED_COLORS:
|
||||||
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
|
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
|
||||||
hsvColor_t *color = &masterConfig.colors[i];
|
hsvColor_t *color = &masterConfig.ledStripConfig.colors[i];
|
||||||
sbufWriteU16(dst, color->h);
|
sbufWriteU16(dst, color->h);
|
||||||
sbufWriteU8(dst, color->s);
|
sbufWriteU8(dst, color->s);
|
||||||
sbufWriteU8(dst, color->v);
|
sbufWriteU8(dst, color->v);
|
||||||
|
@ -943,7 +939,7 @@ static bool mspFcProcessOutCommand(uint8_t cmdMSP, sbuf_t *dst, mspPostProcessFn
|
||||||
|
|
||||||
case MSP_LED_STRIP_CONFIG:
|
case MSP_LED_STRIP_CONFIG:
|
||||||
for (i = 0; i < LED_MAX_STRIP_LENGTH; i++) {
|
for (i = 0; i < LED_MAX_STRIP_LENGTH; i++) {
|
||||||
ledConfig_t *ledConfig = &masterConfig.ledConfigs[i];
|
ledConfig_t *ledConfig = &masterConfig.ledStripConfig.ledConfigs[i];
|
||||||
sbufWriteU32(dst, *ledConfig);
|
sbufWriteU32(dst, *ledConfig);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -953,15 +949,20 @@ static bool mspFcProcessOutCommand(uint8_t cmdMSP, sbuf_t *dst, mspPostProcessFn
|
||||||
for (int j = 0; j < LED_DIRECTION_COUNT; j++) {
|
for (int j = 0; j < LED_DIRECTION_COUNT; j++) {
|
||||||
sbufWriteU8(dst, i);
|
sbufWriteU8(dst, i);
|
||||||
sbufWriteU8(dst, j);
|
sbufWriteU8(dst, j);
|
||||||
sbufWriteU8(dst, masterConfig.modeColors[i].color[j]);
|
sbufWriteU8(dst, masterConfig.ledStripConfig.modeColors[i].color[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < LED_SPECIAL_COLOR_COUNT; j++) {
|
for (int j = 0; j < LED_SPECIAL_COLOR_COUNT; j++) {
|
||||||
sbufWriteU8(dst, LED_MODE_COUNT);
|
sbufWriteU8(dst, LED_MODE_COUNT);
|
||||||
sbufWriteU8(dst, j);
|
sbufWriteU8(dst, j);
|
||||||
sbufWriteU8(dst, masterConfig.specialColors.color[j]);
|
sbufWriteU8(dst, masterConfig.ledStripConfig.specialColors.color[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sbufWriteU8(dst, LED_AUX_CHANNEL);
|
||||||
|
sbufWriteU8(dst, 0);
|
||||||
|
sbufWriteU8(dst, masterConfig.ledStripConfig.ledstrip_aux_channel);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1009,7 +1010,7 @@ static bool mspFcProcessOutCommand(uint8_t cmdMSP, sbuf_t *dst, mspPostProcessFn
|
||||||
sbufWriteU16(dst, masterConfig.osdProfile.time_alarm);
|
sbufWriteU16(dst, masterConfig.osdProfile.time_alarm);
|
||||||
sbufWriteU16(dst, masterConfig.osdProfile.alt_alarm);
|
sbufWriteU16(dst, masterConfig.osdProfile.alt_alarm);
|
||||||
|
|
||||||
for (i = 0; i < OSD_MAX_ITEMS; i++) {
|
for (i = 0; i < OSD_ITEM_COUNT; i++) {
|
||||||
sbufWriteU16(dst, masterConfig.osdProfile.item_pos[i]);
|
sbufWriteU16(dst, masterConfig.osdProfile.item_pos[i]);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -1320,8 +1321,9 @@ static mspResult_e mspFcProcessInCommand(uint8_t cmdMSP, sbuf_t *src)
|
||||||
masterConfig.batteryConfig.vbatwarningcellvoltage = sbufReadU8(src); // vbatlevel when buzzer starts to alert
|
masterConfig.batteryConfig.vbatwarningcellvoltage = sbufReadU8(src); // vbatlevel when buzzer starts to alert
|
||||||
break;
|
break;
|
||||||
case MSP_SET_MOTOR:
|
case MSP_SET_MOTOR:
|
||||||
for (i = 0; i < 8; i++) // FIXME should this use MAX_MOTORS or MAX_SUPPORTED_MOTORS instead of 8
|
for (i = 0; i < 8; i++) { // FIXME should this use MAX_MOTORS or MAX_SUPPORTED_MOTORS instead of 8
|
||||||
motor_disarmed[i] = sbufReadU16(src);
|
motor_disarmed[i] = convertExternalToMotor(sbufReadU16(src));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MSP_SET_SERVO_CONFIGURATION:
|
case MSP_SET_SERVO_CONFIGURATION:
|
||||||
#ifdef USE_SERVOS
|
#ifdef USE_SERVOS
|
||||||
|
@ -1652,7 +1654,7 @@ static mspResult_e mspFcProcessInCommand(uint8_t cmdMSP, sbuf_t *src)
|
||||||
#ifdef LED_STRIP
|
#ifdef LED_STRIP
|
||||||
case MSP_SET_LED_COLORS:
|
case MSP_SET_LED_COLORS:
|
||||||
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
|
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
|
||||||
hsvColor_t *color = &masterConfig.colors[i];
|
hsvColor_t *color = &masterConfig.ledStripConfig.colors[i];
|
||||||
color->h = sbufReadU16(src);
|
color->h = sbufReadU16(src);
|
||||||
color->s = sbufReadU8(src);
|
color->s = sbufReadU8(src);
|
||||||
color->v = sbufReadU8(src);
|
color->v = sbufReadU8(src);
|
||||||
|
@ -1666,7 +1668,7 @@ static mspResult_e mspFcProcessInCommand(uint8_t cmdMSP, sbuf_t *src)
|
||||||
return MSP_RESULT_ERROR;
|
return MSP_RESULT_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ledConfig_t *ledConfig = &masterConfig.ledConfigs[i];
|
ledConfig_t *ledConfig = &masterConfig.ledStripConfig.ledConfigs[i];
|
||||||
*ledConfig = sbufReadU32(src);
|
*ledConfig = sbufReadU32(src);
|
||||||
reevaluateLedConfig();
|
reevaluateLedConfig();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
|
||||||
#include "common/axis.h"
|
#include "common/axis.h"
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "common/utils.h"
|
#include "common/utils.h"
|
||||||
|
@ -41,7 +43,7 @@
|
||||||
#include "flight/altitudehold.h"
|
#include "flight/altitudehold.h"
|
||||||
|
|
||||||
#include "io/beeper.h"
|
#include "io/beeper.h"
|
||||||
#include "io/display.h"
|
#include "io/dashboard.h"
|
||||||
#include "io/gps.h"
|
#include "io/gps.h"
|
||||||
#include "io/ledstrip.h"
|
#include "io/ledstrip.h"
|
||||||
#include "io/osd.h"
|
#include "io/osd.h"
|
||||||
|
@ -222,11 +224,11 @@ static void taskCalculateAltitude(uint32_t currentTime)
|
||||||
}}
|
}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
static void taskUpdateDisplay(uint32_t currentTime)
|
static void taskUpdateDashboard(uint32_t currentTime)
|
||||||
{
|
{
|
||||||
if (feature(FEATURE_DISPLAY)) {
|
if (feature(FEATURE_DASHBOARD)) {
|
||||||
displayUpdate(currentTime);
|
dashboardUpdate(currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -264,7 +266,7 @@ static void taskTransponder(uint32_t currentTime)
|
||||||
static void taskUpdateOsd(uint32_t currentTime)
|
static void taskUpdateOsd(uint32_t currentTime)
|
||||||
{
|
{
|
||||||
if (feature(FEATURE_OSD)) {
|
if (feature(FEATURE_OSD)) {
|
||||||
updateOsd(currentTime);
|
osdUpdate(currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -307,8 +309,8 @@ void fcTasksInit(void)
|
||||||
#if defined(BARO) || defined(SONAR)
|
#if defined(BARO) || defined(SONAR)
|
||||||
setTaskEnabled(TASK_ALTITUDE, sensors(SENSOR_BARO) || sensors(SENSOR_SONAR));
|
setTaskEnabled(TASK_ALTITUDE, sensors(SENSOR_BARO) || sensors(SENSOR_SONAR));
|
||||||
#endif
|
#endif
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
setTaskEnabled(TASK_DISPLAY, feature(FEATURE_DISPLAY));
|
setTaskEnabled(TASK_DASHBOARD, feature(FEATURE_DASHBOARD));
|
||||||
#endif
|
#endif
|
||||||
#ifdef TELEMETRY
|
#ifdef TELEMETRY
|
||||||
setTaskEnabled(TASK_TELEMETRY, feature(FEATURE_TELEMETRY));
|
setTaskEnabled(TASK_TELEMETRY, feature(FEATURE_TELEMETRY));
|
||||||
|
@ -329,6 +331,13 @@ void fcTasksInit(void)
|
||||||
#ifdef USE_BST
|
#ifdef USE_BST
|
||||||
setTaskEnabled(TASK_BST_MASTER_PROCESS, true);
|
setTaskEnabled(TASK_BST_MASTER_PROCESS, true);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CMS
|
||||||
|
#ifdef USE_MSP_DISPLAYPORT
|
||||||
|
setTaskEnabled(TASK_CMS, true);
|
||||||
|
#else
|
||||||
|
setTaskEnabled(TASK_CMS, feature(FEATURE_OSD) || feature(FEATURE_DASHBOARD));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
cfTask_t cfTasks[TASK_COUNT] = {
|
cfTask_t cfTasks[TASK_COUNT] = {
|
||||||
|
@ -446,10 +455,10 @@ cfTask_t cfTasks[TASK_COUNT] = {
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
[TASK_DISPLAY] = {
|
[TASK_DASHBOARD] = {
|
||||||
.taskName = "DISPLAY",
|
.taskName = "DASHBOARD",
|
||||||
.taskFunc = taskUpdateDisplay,
|
.taskFunc = taskUpdateDashboard,
|
||||||
.desiredPeriod = 1000000 / 10,
|
.desiredPeriod = 1000000 / 10,
|
||||||
.staticPriority = TASK_PRIORITY_LOW,
|
.staticPriority = TASK_PRIORITY_LOW,
|
||||||
},
|
},
|
||||||
|
@ -488,4 +497,13 @@ cfTask_t cfTasks[TASK_COUNT] = {
|
||||||
.staticPriority = TASK_PRIORITY_IDLE,
|
.staticPriority = TASK_PRIORITY_IDLE,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
[TASK_CMS] = {
|
||||||
|
.taskName = "CMS",
|
||||||
|
.taskFunc = cmsHandler,
|
||||||
|
.desiredPeriod = 1000000 / 60, // 60 Hz
|
||||||
|
.staticPriority = TASK_PRIORITY_LOW,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
#include "io/beeper.h"
|
#include "io/beeper.h"
|
||||||
#include "io/motors.h"
|
#include "io/motors.h"
|
||||||
#include "io/vtx.h"
|
#include "io/vtx.h"
|
||||||
#include "io/display.h"
|
#include "io/dashboard.h"
|
||||||
|
|
||||||
#include "sensors/barometer.h"
|
#include "sensors/barometer.h"
|
||||||
#include "sensors/battery.h"
|
#include "sensors/battery.h"
|
||||||
|
@ -291,13 +291,13 @@ void processRcStickPositions(rxConfig_t *rxConfig, throttleStatus_e throttleStat
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_LO) {
|
if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_LO) {
|
||||||
displayDisablePageCycling();
|
dashboardDisablePageCycling();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_HI) {
|
if (rcSticks == THR_LO + YAW_CE + PIT_HI + ROL_HI) {
|
||||||
displayEnablePageCycling();
|
dashboardEnablePageCycling();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,13 @@
|
||||||
#include "fc/runtime_config.h"
|
#include "fc/runtime_config.h"
|
||||||
|
|
||||||
#include "config/feature.h"
|
#include "config/feature.h"
|
||||||
|
#include "config/config_master.h"
|
||||||
|
|
||||||
|
#define EXTERNAL_DSHOT_CONVERSION_FACTOR 2
|
||||||
|
// (minimum output value(1001) - (minimum input value(48) / conversion factor(2))
|
||||||
|
#define EXTERNAL_DSHOT_CONVERSION_OFFSET 977
|
||||||
|
#define EXTERNAL_CONVERSION_MIN_VALUE 1000
|
||||||
|
#define EXTERNAL_CONVERSION_MAX_VALUE 2000
|
||||||
|
|
||||||
uint8_t motorCount;
|
uint8_t motorCount;
|
||||||
|
|
||||||
|
@ -234,21 +241,26 @@ static uint16_t disarmMotorOutput, minMotorOutputNormal, maxMotorOutputNormal, d
|
||||||
static float rcCommandThrottleRange;
|
static float rcCommandThrottleRange;
|
||||||
|
|
||||||
bool isMotorProtocolDshot(void) {
|
bool isMotorProtocolDshot(void) {
|
||||||
|
#ifdef USE_DSHOT
|
||||||
if (motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT150 || motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT300 || motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT600)
|
if (motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT150 || motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT300 || motorConfig->motorPwmProtocol == PWM_TYPE_DSHOT600)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add here scaled ESC outputs for digital protol
|
// Add here scaled ESC outputs for digital protol
|
||||||
void initEscEndpoints(void) {
|
void initEscEndpoints(void) {
|
||||||
|
#ifdef USE_DSHOT
|
||||||
if (isMotorProtocolDshot()) {
|
if (isMotorProtocolDshot()) {
|
||||||
disarmMotorOutput = DSHOT_DISARM_COMMAND;
|
disarmMotorOutput = DSHOT_DISARM_COMMAND;
|
||||||
minMotorOutputNormal = DSHOT_MIN_THROTTLE + motorConfig->digitalIdleOffset;
|
minMotorOutputNormal = DSHOT_MIN_THROTTLE + motorConfig->digitalIdleOffset;
|
||||||
maxMotorOutputNormal = DSHOT_MAX_THROTTLE;
|
maxMotorOutputNormal = DSHOT_MAX_THROTTLE;
|
||||||
deadbandMotor3dHigh = DSHOT_3D_DEADBAND_HIGH;
|
deadbandMotor3dHigh = DSHOT_3D_MIN_NEGATIVE; // TODO - Not working yet !! Mixer requires some throttle rescaling changes
|
||||||
deadbandMotor3dLow = DSHOT_3D_DEADBAND_LOW;
|
deadbandMotor3dLow = DSHOT_3D_MAX_POSITIVE; // TODO - Not working yet !! Mixer requires some throttle rescaling changes
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
disarmMotorOutput = (feature(FEATURE_3D)) ? flight3DConfig->neutral3d : motorConfig->mincommand;
|
disarmMotorOutput = (feature(FEATURE_3D)) ? flight3DConfig->neutral3d : motorConfig->mincommand;
|
||||||
minMotorOutputNormal = motorConfig->minthrottle;
|
minMotorOutputNormal = motorConfig->minthrottle;
|
||||||
maxMotorOutputNormal = motorConfig->maxthrottle;
|
maxMotorOutputNormal = motorConfig->maxthrottle;
|
||||||
|
@ -359,7 +371,7 @@ void mixerResetDisarmedMotors(void)
|
||||||
int i;
|
int i;
|
||||||
// set disarmed motor values
|
// set disarmed motor values
|
||||||
for (i = 0; i < MAX_SUPPORTED_MOTORS; i++)
|
for (i = 0; i < MAX_SUPPORTED_MOTORS; i++)
|
||||||
motor_disarmed[i] = feature(FEATURE_3D) ? flight3DConfig->neutral3d : motorConfig->mincommand;
|
motor_disarmed[i] = disarmMotorOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeMotors(void)
|
void writeMotors(void)
|
||||||
|
@ -373,7 +385,7 @@ void writeMotors(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeAllMotors(int16_t mc)
|
static void writeAllMotors(int16_t mc)
|
||||||
{
|
{
|
||||||
// Sends commands to all motors
|
// Sends commands to all motors
|
||||||
for (uint8_t i = 0; i < motorCount; i++) {
|
for (uint8_t i = 0; i < motorCount; i++) {
|
||||||
|
@ -385,7 +397,7 @@ void writeAllMotors(int16_t mc)
|
||||||
|
|
||||||
void stopMotors(void)
|
void stopMotors(void)
|
||||||
{
|
{
|
||||||
writeAllMotors(feature(FEATURE_3D) ? flight3DConfig->neutral3d : motorConfig->mincommand);
|
writeAllMotors(disarmMotorOutput);
|
||||||
|
|
||||||
delay(50); // give the timers and ESCs a chance to react.
|
delay(50); // give the timers and ESCs a chance to react.
|
||||||
}
|
}
|
||||||
|
@ -440,9 +452,10 @@ void mixTable(pidProfile_t *pidProfile)
|
||||||
throttle = constrainf((throttle - rxConfig->mincheck) / rcCommandThrottleRange, 0.0f, 1.0f);
|
throttle = constrainf((throttle - rxConfig->mincheck) / rcCommandThrottleRange, 0.0f, 1.0f);
|
||||||
throttleRange = motorOutputMax - motorOutputMin;
|
throttleRange = motorOutputMax - motorOutputMin;
|
||||||
|
|
||||||
|
float scaledAxisPIDf[3];
|
||||||
// Limit the PIDsum
|
// Limit the PIDsum
|
||||||
for (int axis = 0; axis < 3; axis++)
|
for (int axis = 0; axis < 3; axis++)
|
||||||
axisPIDf[axis] = constrainf(axisPIDf[axis] / PID_MIXER_SCALING, -pidProfile->pidSumLimit, pidProfile->pidSumLimit);
|
scaledAxisPIDf[axis] = constrainf(axisPIDf[axis] / PID_MIXER_SCALING, -pidProfile->pidSumLimit, pidProfile->pidSumLimit);
|
||||||
|
|
||||||
// Calculate voltage compensation
|
// Calculate voltage compensation
|
||||||
if (batteryConfig && pidProfile->vbatPidCompensation) vbatCompensationFactor = calculateVbatPidCompensation();
|
if (batteryConfig && pidProfile->vbatPidCompensation) vbatCompensationFactor = calculateVbatPidCompensation();
|
||||||
|
@ -450,9 +463,9 @@ void mixTable(pidProfile_t *pidProfile)
|
||||||
// Find roll/pitch/yaw desired output
|
// Find roll/pitch/yaw desired output
|
||||||
for (i = 0; i < motorCount; i++) {
|
for (i = 0; i < motorCount; i++) {
|
||||||
motorMix[i] =
|
motorMix[i] =
|
||||||
axisPIDf[PITCH] * currentMixer[i].pitch +
|
scaledAxisPIDf[PITCH] * currentMixer[i].pitch +
|
||||||
axisPIDf[ROLL] * currentMixer[i].roll +
|
scaledAxisPIDf[ROLL] * currentMixer[i].roll +
|
||||||
-mixerConfig->yaw_motor_direction * axisPIDf[YAW] * currentMixer[i].yaw;
|
-mixerConfig->yaw_motor_direction * scaledAxisPIDf[YAW] * currentMixer[i].yaw;
|
||||||
|
|
||||||
if (vbatCompensationFactor > 1.0f) motorMix[i] *= vbatCompensationFactor; // Add voltage compensation
|
if (vbatCompensationFactor > 1.0f) motorMix[i] *= vbatCompensationFactor; // Add voltage compensation
|
||||||
|
|
||||||
|
@ -511,14 +524,31 @@ void mixTable(pidProfile_t *pidProfile)
|
||||||
// Disarmed mode
|
// Disarmed mode
|
||||||
if (!ARMING_FLAG(ARMED)) {
|
if (!ARMING_FLAG(ARMED)) {
|
||||||
for (i = 0; i < motorCount; i++) {
|
for (i = 0; i < motorCount; i++) {
|
||||||
if (isMotorProtocolDshot()) {
|
|
||||||
motor[i] = (motor_disarmed[i] < motorOutputMin) ? disarmMotorOutput : motor_disarmed[i]; // Prevent getting into special reserved range
|
|
||||||
|
|
||||||
if (motor_disarmed[i] != disarmMotorOutput)
|
|
||||||
motor[i] = (motor_disarmed[i] - 1000) * 2; // TODO - Perhaps needs rescaling as it will never reach 2047 during motor tests
|
|
||||||
} else {
|
|
||||||
motor[i] = motor_disarmed[i];
|
motor[i] = motor_disarmed[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t convertExternalToMotor(uint16_t externalValue)
|
||||||
|
{
|
||||||
|
uint16_t motorValue = externalValue;
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
if (isMotorProtocolDshot()) {
|
||||||
|
motorValue = externalValue <= EXTERNAL_CONVERSION_MIN_VALUE ? DSHOT_DISARM_COMMAND : constrain((externalValue - EXTERNAL_DSHOT_CONVERSION_OFFSET) * EXTERNAL_DSHOT_CONVERSION_FACTOR, DSHOT_MIN_THROTTLE, DSHOT_MAX_THROTTLE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return motorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t convertMotorToExternal(uint16_t motorValue)
|
||||||
|
{
|
||||||
|
uint16_t externalValue = motorValue;
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
if (isMotorProtocolDshot()) {
|
||||||
|
externalValue = motorValue < DSHOT_MIN_THROTTLE ? EXTERNAL_CONVERSION_MIN_VALUE : constrain((motorValue / EXTERNAL_DSHOT_CONVERSION_FACTOR) + EXTERNAL_DSHOT_CONVERSION_OFFSET, EXTERNAL_CONVERSION_MIN_VALUE + 1, EXTERNAL_CONVERSION_MAX_VALUE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return externalValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,30 @@
|
||||||
|
|
||||||
#define QUAD_MOTOR_COUNT 4
|
#define QUAD_MOTOR_COUNT 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
DshotSettingRequest (KISS24). Spin direction, 3d and save Settings reqire 10 requests.. and the TLM Byte must always be high if 1-47 are used to send settings
|
||||||
|
0 = stop
|
||||||
|
1-5: beep
|
||||||
|
6: ESC info request (FW Version and SN sent over the tlm wire)
|
||||||
|
7: spin direction 1
|
||||||
|
8: spin direction 2
|
||||||
|
9: 3d mode off
|
||||||
|
10: 3d mode on
|
||||||
|
11: ESC settings request (saved settings over the TLM wire)
|
||||||
|
12: save Settings
|
||||||
|
|
||||||
|
3D Mode:
|
||||||
|
0 = stop
|
||||||
|
48 (low) - 1047 (high) -> positive direction
|
||||||
|
1048 (low) - 2047 (high) -> negative direction
|
||||||
|
*/
|
||||||
|
|
||||||
// Digital protocol has fixed values
|
// Digital protocol has fixed values
|
||||||
#define DSHOT_DISARM_COMMAND 0
|
#define DSHOT_DISARM_COMMAND 0
|
||||||
#define DSHOT_MIN_THROTTLE 48
|
#define DSHOT_MIN_THROTTLE 48
|
||||||
#define DSHOT_MAX_THROTTLE 2047
|
#define DSHOT_MAX_THROTTLE 2047
|
||||||
#define DSHOT_3D_DEADBAND_LOW 900 // TODO - not agreed yet
|
#define DSHOT_3D_MAX_POSITIVE 1047 // TODO - Not working yet!! Mixer requires some throttle rescaling changes
|
||||||
#define DSHOT_3D_DEADBAND_HIGH 1100 // TODO - not agreed yet
|
#define DSHOT_3D_MIN_NEGATIVE 1048// TODO - Not working yet!! Mixer requires some throttle rescaling changes
|
||||||
|
|
||||||
// Note: this is called MultiType/MULTITYPE_* in baseflight.
|
// Note: this is called MultiType/MULTITYPE_* in baseflight.
|
||||||
typedef enum mixerMode
|
typedef enum mixerMode
|
||||||
|
@ -104,7 +122,6 @@ void mixerUseConfigs(
|
||||||
airplaneConfig_t *airplaneConfigToUse,
|
airplaneConfig_t *airplaneConfigToUse,
|
||||||
struct rxConfig_s *rxConfigToUse);
|
struct rxConfig_s *rxConfigToUse);
|
||||||
|
|
||||||
void writeAllMotors(int16_t mc);
|
|
||||||
void mixerLoadMix(int index, motorMixer_t *customMixers);
|
void mixerLoadMix(int index, motorMixer_t *customMixers);
|
||||||
void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
|
void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
|
||||||
|
|
||||||
|
@ -117,4 +134,7 @@ void syncMotors(bool enabled);
|
||||||
void writeMotors(void);
|
void writeMotors(void);
|
||||||
void stopMotors(void);
|
void stopMotors(void);
|
||||||
void stopPwmAllMotors(void);
|
void stopPwmAllMotors(void);
|
||||||
|
|
||||||
bool isMotorProtocolDshot(void);
|
bool isMotorProtocolDshot(void);
|
||||||
|
uint16_t convertExternalToMotor(uint16_t externalValue);
|
||||||
|
uint16_t convertMotorToExternal(uint16_t motorValue);
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
|
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
#include "build/version.h"
|
#include "build/version.h"
|
||||||
#include "build/debug.h"
|
#include "build/debug.h"
|
||||||
|
@ -29,8 +31,11 @@
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
|
|
||||||
#include "drivers/system.h"
|
#include "drivers/system.h"
|
||||||
|
#include "drivers/display.h"
|
||||||
#include "drivers/display_ug2864hsweg01.h"
|
#include "drivers/display_ug2864hsweg01.h"
|
||||||
|
|
||||||
|
#include "cms/cms.h"
|
||||||
|
|
||||||
#include "common/printf.h"
|
#include "common/printf.h"
|
||||||
#include "common/maths.h"
|
#include "common/maths.h"
|
||||||
#include "common/axis.h"
|
#include "common/axis.h"
|
||||||
|
@ -50,6 +55,8 @@
|
||||||
#include "flight/imu.h"
|
#include "flight/imu.h"
|
||||||
#include "flight/failsafe.h"
|
#include "flight/failsafe.h"
|
||||||
|
|
||||||
|
#include "io/displayport_oled.h"
|
||||||
|
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
#include "io/gps.h"
|
#include "io/gps.h"
|
||||||
#include "flight/navigation.h"
|
#include "flight/navigation.h"
|
||||||
|
@ -58,7 +65,7 @@
|
||||||
#include "config/feature.h"
|
#include "config/feature.h"
|
||||||
#include "config/config_profile.h"
|
#include "config/config_profile.h"
|
||||||
|
|
||||||
#include "io/display.h"
|
#include "io/dashboard.h"
|
||||||
|
|
||||||
#include "rx/rx.h"
|
#include "rx/rx.h"
|
||||||
|
|
||||||
|
@ -74,9 +81,10 @@ controlRateConfig_t *getControlRateConfig(uint8_t profileIndex);
|
||||||
#define PAGE_CYCLE_FREQUENCY (MICROSECONDS_IN_A_SECOND * 5)
|
#define PAGE_CYCLE_FREQUENCY (MICROSECONDS_IN_A_SECOND * 5)
|
||||||
|
|
||||||
static uint32_t nextDisplayUpdateAt = 0;
|
static uint32_t nextDisplayUpdateAt = 0;
|
||||||
static bool displayPresent = false;
|
static bool dashboardPresent = false;
|
||||||
|
|
||||||
static rxConfig_t *rxConfig;
|
static rxConfig_t *rxConfig;
|
||||||
|
static displayPort_t *displayPort;
|
||||||
|
|
||||||
#define PAGE_TITLE_LINE_COUNT 1
|
#define PAGE_TITLE_LINE_COUNT 1
|
||||||
|
|
||||||
|
@ -98,7 +106,7 @@ static const char* const pageTitles[] = {
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
,"GPS"
|
,"GPS"
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_DEBUG_OLED_PAGE
|
#ifdef ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
,"DEBUG"
|
,"DEBUG"
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -116,7 +124,7 @@ const pageId_e cyclePageIds[] = {
|
||||||
#ifndef SKIP_TASK_STATISTICS
|
#ifndef SKIP_TASK_STATISTICS
|
||||||
,PAGE_TASKS
|
,PAGE_TASKS
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_DEBUG_OLED_PAGE
|
#ifdef ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
,PAGE_DEBUG,
|
,PAGE_DEBUG,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -144,7 +152,7 @@ typedef struct pageState_s {
|
||||||
static pageState_t pageState;
|
static pageState_t pageState;
|
||||||
|
|
||||||
void resetDisplay(void) {
|
void resetDisplay(void) {
|
||||||
displayPresent = ug2864hsweg01InitI2C();
|
dashboardPresent = ug2864hsweg01InitI2C();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCDprint(uint8_t i) {
|
void LCDprint(uint8_t i) {
|
||||||
|
@ -562,7 +570,7 @@ void showTasksPage(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUG_OLED_PAGE
|
#ifdef ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
|
|
||||||
void showDebugPage(void)
|
void showDebugPage(void)
|
||||||
{
|
{
|
||||||
|
@ -577,10 +585,16 @@ void showDebugPage(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void displayUpdate(uint32_t currentTime)
|
void dashboardUpdate(uint32_t currentTime)
|
||||||
{
|
{
|
||||||
static uint8_t previousArmedState = 0;
|
static uint8_t previousArmedState = 0;
|
||||||
|
|
||||||
|
#ifdef CMS
|
||||||
|
if (displayIsGrabbed(displayPort)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const bool updateNow = (int32_t)(currentTime - nextDisplayUpdateAt) >= 0L;
|
const bool updateNow = (int32_t)(currentTime - nextDisplayUpdateAt) >= 0L;
|
||||||
if (!updateNow) {
|
if (!updateNow) {
|
||||||
return;
|
return;
|
||||||
|
@ -623,13 +637,13 @@ void displayUpdate(uint32_t currentTime)
|
||||||
// user to power off/on the display or connect it while powered.
|
// user to power off/on the display or connect it while powered.
|
||||||
resetDisplay();
|
resetDisplay();
|
||||||
|
|
||||||
if (!displayPresent) {
|
if (!dashboardPresent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handlePageChange();
|
handlePageChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!displayPresent) {
|
if (!dashboardPresent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +680,7 @@ void displayUpdate(uint32_t currentTime)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_DEBUG_OLED_PAGE
|
#ifdef ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
case PAGE_DEBUG:
|
case PAGE_DEBUG:
|
||||||
showDebugPage();
|
showDebugPage();
|
||||||
break;
|
break;
|
||||||
|
@ -680,53 +694,57 @@ void displayUpdate(uint32_t currentTime)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void displaySetPage(pageId_e pageId)
|
void dashboardSetPage(pageId_e pageId)
|
||||||
{
|
{
|
||||||
pageState.pageId = pageId;
|
pageState.pageId = pageId;
|
||||||
pageState.pageFlags |= PAGE_STATE_FLAG_FORCE_PAGE_CHANGE;
|
pageState.pageFlags |= PAGE_STATE_FLAG_FORCE_PAGE_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayInit(rxConfig_t *rxConfigToUse)
|
void dashboardInit(rxConfig_t *rxConfigToUse)
|
||||||
{
|
{
|
||||||
delay(200);
|
delay(200);
|
||||||
resetDisplay();
|
resetDisplay();
|
||||||
delay(200);
|
delay(200);
|
||||||
|
|
||||||
|
displayPort = displayPortOledInit();
|
||||||
|
#if defined(CMS)
|
||||||
|
cmsDisplayPortRegister(displayPort);
|
||||||
|
#endif
|
||||||
|
|
||||||
rxConfig = rxConfigToUse;
|
rxConfig = rxConfigToUse;
|
||||||
|
|
||||||
memset(&pageState, 0, sizeof(pageState));
|
memset(&pageState, 0, sizeof(pageState));
|
||||||
displaySetPage(PAGE_WELCOME);
|
dashboardSetPage(PAGE_WELCOME);
|
||||||
|
|
||||||
displayUpdate(micros());
|
dashboardUpdate(micros());
|
||||||
|
|
||||||
displaySetNextPageChangeAt(micros() + (1000 * 1000 * 5));
|
dashboardSetNextPageChangeAt(micros() + (1000 * 1000 * 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayShowFixedPage(pageId_e pageId)
|
void dashboardShowFixedPage(pageId_e pageId)
|
||||||
{
|
{
|
||||||
displaySetPage(pageId);
|
dashboardSetPage(pageId);
|
||||||
displayDisablePageCycling();
|
dashboardDisablePageCycling();
|
||||||
}
|
}
|
||||||
|
|
||||||
void displaySetNextPageChangeAt(uint32_t futureMicros)
|
void dashboardSetNextPageChangeAt(uint32_t futureMicros)
|
||||||
{
|
{
|
||||||
pageState.nextPageAt = futureMicros;
|
pageState.nextPageAt = futureMicros;
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayEnablePageCycling(void)
|
void dashboardEnablePageCycling(void)
|
||||||
{
|
{
|
||||||
pageState.pageFlags |= PAGE_STATE_FLAG_CYCLE_ENABLED;
|
pageState.pageFlags |= PAGE_STATE_FLAG_CYCLE_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayResetPageCycling(void)
|
void dashboardResetPageCycling(void)
|
||||||
{
|
{
|
||||||
pageState.cycleIndex = CYCLE_PAGE_ID_COUNT - 1; // start at first page
|
pageState.cycleIndex = CYCLE_PAGE_ID_COUNT - 1; // start at first page
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayDisablePageCycling(void)
|
void dashboardDisablePageCycling(void)
|
||||||
{
|
{
|
||||||
pageState.pageFlags &= ~PAGE_STATE_FLAG_CYCLE_ENABLED;
|
pageState.pageFlags &= ~PAGE_STATE_FLAG_CYCLE_ENABLED;
|
||||||
}
|
}
|
||||||
|
#endif // USE_DASHBOARD
|
||||||
#endif
|
|
|
@ -15,7 +15,7 @@
|
||||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ENABLE_DEBUG_OLED_PAGE
|
#define ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PAGE_WELCOME,
|
PAGE_WELCOME,
|
||||||
|
@ -30,18 +30,18 @@ typedef enum {
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
PAGE_GPS,
|
PAGE_GPS,
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_DEBUG_OLED_PAGE
|
#ifdef ENABLE_DEBUG_DASHBOARD_PAGE
|
||||||
PAGE_DEBUG,
|
PAGE_DEBUG,
|
||||||
#endif
|
#endif
|
||||||
} pageId_e;
|
} pageId_e;
|
||||||
|
|
||||||
struct rxConfig_s;
|
struct rxConfig_s;
|
||||||
void displayInit(struct rxConfig_s *intialRxConfig);
|
void dashboardInit(struct rxConfig_s *intialRxConfig);
|
||||||
void displayUpdate(uint32_t currentTime);
|
void dashboardUpdate(uint32_t currentTime);
|
||||||
|
|
||||||
void displayShowFixedPage(pageId_e pageId);
|
void dashboardShowFixedPage(pageId_e pageId);
|
||||||
|
|
||||||
void displayEnablePageCycling(void);
|
void dashboardEnablePageCycling(void);
|
||||||
void displayDisablePageCycling(void);
|
void dashboardDisablePageCycling(void);
|
||||||
void displayResetPageCycling(void);
|
void dashboardResetPageCycling(void);
|
||||||
void displaySetNextPageChangeAt(uint32_t futureMicros);
|
void dashboardSetNextPageChangeAt(uint32_t futureMicros);
|
107
src/main/io/displayport_max7456.c
Normal file
107
src/main/io/displayport_max7456.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* 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 "platform.h"
|
||||||
|
|
||||||
|
#ifdef OSD
|
||||||
|
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "config/config_master.h"
|
||||||
|
|
||||||
|
#include "drivers/display.h"
|
||||||
|
#include "drivers/max7456.h"
|
||||||
|
|
||||||
|
displayPort_t max7456DisplayPort; // Referenced from osd.c
|
||||||
|
|
||||||
|
extern uint16_t refreshTimeout;
|
||||||
|
|
||||||
|
static int grab(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
osdResetAlarms();
|
||||||
|
displayPort->isGrabbed = true;
|
||||||
|
refreshTimeout = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int release(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
displayPort->isGrabbed = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clearScreen(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
max7456ClearScreen();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write(displayPort_t *displayPort, uint8_t x, uint8_t y, const char *s)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
max7456Write(x, y, s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resync(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
max7456RefreshAll();
|
||||||
|
displayPort->rows = max7456GetRowsCount();
|
||||||
|
displayPort->cols = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int heartbeat(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t txBytesFree(const displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static displayPortVTable_t max7456VTable = {
|
||||||
|
.grab = grab,
|
||||||
|
.release = release,
|
||||||
|
.clear = clearScreen,
|
||||||
|
.write = write,
|
||||||
|
.heartbeat = heartbeat,
|
||||||
|
.resync = resync,
|
||||||
|
.txBytesFree = txBytesFree,
|
||||||
|
};
|
||||||
|
|
||||||
|
displayPort_t *max7456DisplayPortInit(void)
|
||||||
|
{
|
||||||
|
max7456DisplayPort.vTable = &max7456VTable;
|
||||||
|
max7456DisplayPort.isGrabbed = false;
|
||||||
|
resync(&max7456DisplayPort);
|
||||||
|
return &max7456DisplayPort;
|
||||||
|
}
|
||||||
|
#endif // OSD
|
20
src/main/io/displayport_max7456.h
Normal file
20
src/main/io/displayport_max7456.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
displayPort_t *max7456DisplayPortInit(void);
|
119
src/main/io/displayport_msp.c
Normal file
119
src/main/io/displayport_msp.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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 <ctype.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef USE_MSP_DISPLAYPORT
|
||||||
|
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "drivers/display.h"
|
||||||
|
#include "drivers/system.h"
|
||||||
|
|
||||||
|
#include "fc/fc_msp.h"
|
||||||
|
|
||||||
|
#include "msp/msp_protocol.h"
|
||||||
|
#include "msp/msp_serial.h"
|
||||||
|
|
||||||
|
static displayPort_t mspDisplayPort;
|
||||||
|
|
||||||
|
static int output(displayPort_t *displayPort, uint8_t cmd, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return mspSerialPush(cmd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int grab(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
const uint8_t subcmd[] = { 0 };
|
||||||
|
|
||||||
|
return output(displayPort, MSP_DISPLAYPORT, subcmd, sizeof(subcmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int heartbeat(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
return grab(displayPort); // ensure display is not released by MW OSD software
|
||||||
|
}
|
||||||
|
|
||||||
|
static int release(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
const uint8_t subcmd[] = { 1 };
|
||||||
|
|
||||||
|
return output(displayPort, MSP_DISPLAYPORT, subcmd, sizeof(subcmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clear(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
const uint8_t subcmd[] = { 2 };
|
||||||
|
|
||||||
|
return output(displayPort, MSP_DISPLAYPORT, subcmd, sizeof(subcmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write(displayPort_t *displayPort, uint8_t col, uint8_t row, const char *string)
|
||||||
|
{
|
||||||
|
#define MSP_OSD_MAX_STRING_LENGTH 30
|
||||||
|
uint8_t buf[MSP_OSD_MAX_STRING_LENGTH + 4];
|
||||||
|
|
||||||
|
int len = strlen(string);
|
||||||
|
if (len >= MSP_OSD_MAX_STRING_LENGTH) {
|
||||||
|
len = MSP_OSD_MAX_STRING_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = 3;
|
||||||
|
buf[1] = row;
|
||||||
|
buf[2] = col;
|
||||||
|
buf[3] = 0;
|
||||||
|
memcpy(&buf[4], string, len);
|
||||||
|
|
||||||
|
return output(displayPort, MSP_DISPLAYPORT, buf, len + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resync(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
displayPort->rows = 13; // XXX Will reflect NTSC/PAL in the future
|
||||||
|
displayPort->cols = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t txBytesFree(const displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return mspSerialTxBytesFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const displayPortVTable_t mspDisplayPortVTable = {
|
||||||
|
.grab = grab,
|
||||||
|
.release = release,
|
||||||
|
.clear = clear,
|
||||||
|
.write = write,
|
||||||
|
.heartbeat = heartbeat,
|
||||||
|
.resync = resync,
|
||||||
|
.txBytesFree = txBytesFree
|
||||||
|
};
|
||||||
|
|
||||||
|
displayPort_t *displayPortMspInit(void)
|
||||||
|
{
|
||||||
|
mspDisplayPort.vTable = &mspDisplayPortVTable;
|
||||||
|
mspDisplayPort.isGrabbed = false;
|
||||||
|
resync(&mspDisplayPort);
|
||||||
|
return &mspDisplayPort;
|
||||||
|
}
|
||||||
|
#endif // USE_MSP_DISPLAYPORT
|
21
src/main/io/displayport_msp.h
Normal file
21
src/main/io/displayport_msp.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
struct displayPort_s;
|
||||||
|
struct displayPort_s *displayPortMspInit(void);
|
91
src/main/io/displayport_oled.c
Normal file
91
src/main/io/displayport_oled.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* 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 "platform.h"
|
||||||
|
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "drivers/display.h"
|
||||||
|
#include "drivers/display_ug2864hsweg01.h"
|
||||||
|
|
||||||
|
static displayPort_t oledDisplayPort;
|
||||||
|
|
||||||
|
static int oledGrab(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oledRelease(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oledClear(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
i2c_OLED_clear_display_quick();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oledWrite(displayPort_t *displayPort, uint8_t x, uint8_t y, const char *s)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
i2c_OLED_set_xy(x, y);
|
||||||
|
i2c_OLED_send_string(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oledHeartbeat(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oledResync(displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t oledTxBytesFree(const displayPort_t *displayPort)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const displayPortVTable_t oledVTable = {
|
||||||
|
.grab = oledGrab,
|
||||||
|
.release = oledRelease,
|
||||||
|
.clear = oledClear,
|
||||||
|
.write = oledWrite,
|
||||||
|
.heartbeat = oledHeartbeat,
|
||||||
|
.resync = oledResync,
|
||||||
|
.txBytesFree = oledTxBytesFree
|
||||||
|
};
|
||||||
|
|
||||||
|
displayPort_t *displayPortOledInit(void)
|
||||||
|
{
|
||||||
|
oledDisplayPort.vTable = &oledVTable;
|
||||||
|
oledDisplayPort.rows = SCREEN_CHARACTER_ROW_COUNT;
|
||||||
|
oledDisplayPort.cols = SCREEN_CHARACTER_COLUMN_COUNT;
|
||||||
|
oledDisplayPort.isGrabbed = false;
|
||||||
|
return &oledDisplayPort;
|
||||||
|
}
|
20
src/main/io/displayport_oled.h
Normal file
20
src/main/io/displayport_oled.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
displayPort_t *displayPortOledInit(void);
|
|
@ -39,7 +39,7 @@
|
||||||
#include "sensors/sensors.h"
|
#include "sensors/sensors.h"
|
||||||
|
|
||||||
#include "io/serial.h"
|
#include "io/serial.h"
|
||||||
#include "io/display.h"
|
#include "io/dashboard.h"
|
||||||
#include "io/gps.h"
|
#include "io/gps.h"
|
||||||
|
|
||||||
#include "flight/gps_conversion.h"
|
#include "flight/gps_conversion.h"
|
||||||
|
@ -1072,9 +1072,9 @@ static bool gpsNewFrameUBLOX(uint8_t data)
|
||||||
static void gpsHandlePassthrough(uint8_t data)
|
static void gpsHandlePassthrough(uint8_t data)
|
||||||
{
|
{
|
||||||
gpsNewData(data);
|
gpsNewData(data);
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
if (feature(FEATURE_DISPLAY)) {
|
if (feature(FEATURE_DASHBOARD)) {
|
||||||
displayUpdate(micros());
|
dashboardUpdate(micros());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1088,9 +1088,9 @@ void gpsEnablePassthrough(serialPort_t *gpsPassthroughPort)
|
||||||
if(!(gpsPort->mode & MODE_TX))
|
if(!(gpsPort->mode & MODE_TX))
|
||||||
serialSetMode(gpsPort, gpsPort->mode | MODE_TX);
|
serialSetMode(gpsPort, gpsPort->mode | MODE_TX);
|
||||||
|
|
||||||
#ifdef DISPLAY
|
#ifdef USE_DASHBOARD
|
||||||
if (feature(FEATURE_DISPLAY)) {
|
if (feature(FEATURE_DASHBOARD)) {
|
||||||
displayShowFixedPage(PAGE_GPS);
|
dashboardShowFixedPage(PAGE_GPS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,6 @@
|
||||||
#include "io/gimbal.h"
|
#include "io/gimbal.h"
|
||||||
#include "io/serial.h"
|
#include "io/serial.h"
|
||||||
#include "io/gps.h"
|
#include "io/gps.h"
|
||||||
#include "io/osd.h"
|
|
||||||
#include "io/vtx.h"
|
|
||||||
|
|
||||||
#include "flight/failsafe.h"
|
#include "flight/failsafe.h"
|
||||||
#include "flight/mixer.h"
|
#include "flight/mixer.h"
|
||||||
|
@ -88,6 +86,7 @@ PG_REGISTER_WITH_RESET_FN(specialColorIndexes_t, specialColors, PG_SPECIAL_COLOR
|
||||||
|
|
||||||
static bool ledStripInitialised = false;
|
static bool ledStripInitialised = false;
|
||||||
static bool ledStripEnabled = true;
|
static bool ledStripEnabled = true;
|
||||||
|
static ledStripConfig_t * currentLedStripConfig;
|
||||||
|
|
||||||
static void ledStripDisable(void);
|
static void ledStripDisable(void);
|
||||||
|
|
||||||
|
@ -170,6 +169,7 @@ static const specialColorIndexes_t defaultSpecialColors[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int scaledThrottle;
|
static int scaledThrottle;
|
||||||
|
static int scaledAux;
|
||||||
|
|
||||||
static void updateLedRingCounts(void);
|
static void updateLedRingCounts(void);
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ STATIC_UNIT_TESTED void determineLedStripDimensions(void)
|
||||||
int maxY = 0;
|
int maxY = 0;
|
||||||
|
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
|
|
||||||
maxX = MAX(ledGetX(ledConfig), maxX);
|
maxX = MAX(ledGetX(ledConfig), maxX);
|
||||||
maxY = MAX(ledGetY(ledConfig), maxY);
|
maxY = MAX(ledGetY(ledConfig), maxY);
|
||||||
|
@ -201,7 +201,7 @@ STATIC_UNIT_TESTED void updateLedCount(void)
|
||||||
int count = 0, countRing = 0, countScanner= 0;
|
int count = 0, countRing = 0, countScanner= 0;
|
||||||
|
|
||||||
for (int ledIndex = 0; ledIndex < LED_MAX_STRIP_LENGTH; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < LED_MAX_STRIP_LENGTH; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
|
|
||||||
if (!(*ledConfig))
|
if (!(*ledConfig))
|
||||||
break;
|
break;
|
||||||
|
@ -231,7 +231,7 @@ void reevaluateLedConfig(void)
|
||||||
// get specialColor by index
|
// get specialColor by index
|
||||||
static hsvColor_t* getSC(ledSpecialColorIds_e index)
|
static hsvColor_t* getSC(ledSpecialColorIds_e index)
|
||||||
{
|
{
|
||||||
return &masterConfig.colors[masterConfig.specialColors.color[index]];
|
return ¤tLedStripConfig->colors[currentLedStripConfig->specialColors.color[index]];
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char directionCodes[LED_DIRECTION_COUNT] = { 'N', 'E', 'S', 'W', 'U', 'D' };
|
static const char directionCodes[LED_DIRECTION_COUNT] = { 'N', 'E', 'S', 'W', 'U', 'D' };
|
||||||
|
@ -255,7 +255,7 @@ bool parseLedStripConfig(int ledIndex, const char *config)
|
||||||
};
|
};
|
||||||
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':', ':', '\0'};
|
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':', ':', '\0'};
|
||||||
|
|
||||||
ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
memset(ledConfig, 0, sizeof(ledConfig_t));
|
memset(ledConfig, 0, sizeof(ledConfig_t));
|
||||||
|
|
||||||
int x = 0, y = 0, color = 0; // initialize to prevent warnings
|
int x = 0, y = 0, color = 0; // initialize to prevent warnings
|
||||||
|
@ -374,7 +374,7 @@ typedef enum {
|
||||||
|
|
||||||
static quadrant_e getLedQuadrant(const int ledIndex)
|
static quadrant_e getLedQuadrant(const int ledIndex)
|
||||||
{
|
{
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
|
|
||||||
int x = ledGetX(ledConfig);
|
int x = ledGetX(ledConfig);
|
||||||
int y = ledGetY(ledConfig);
|
int y = ledGetY(ledConfig);
|
||||||
|
@ -416,7 +416,7 @@ static const struct {
|
||||||
|
|
||||||
static hsvColor_t* getDirectionalModeColor(const int ledIndex, const modeColorIndexes_t *modeColors)
|
static hsvColor_t* getDirectionalModeColor(const int ledIndex, const modeColorIndexes_t *modeColors)
|
||||||
{
|
{
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
|
|
||||||
quadrant_e quad = getLedQuadrant(ledIndex);
|
quadrant_e quad = getLedQuadrant(ledIndex);
|
||||||
for (unsigned i = 0; i < ARRAYLEN(directionQuadrantMap); i++) {
|
for (unsigned i = 0; i < ARRAYLEN(directionQuadrantMap); i++) {
|
||||||
|
@ -424,7 +424,7 @@ static hsvColor_t* getDirectionalModeColor(const int ledIndex, const modeColorIn
|
||||||
quadrant_e quadMask = directionQuadrantMap[i].quadrantMask;
|
quadrant_e quadMask = directionQuadrantMap[i].quadrantMask;
|
||||||
|
|
||||||
if (ledGetDirectionBit(ledConfig, dir) && (quad & quadMask))
|
if (ledGetDirectionBit(ledConfig, dir) && (quad & quadMask))
|
||||||
return &masterConfig.colors[modeColors->color[dir]];
|
return ¤tLedStripConfig->colors[modeColors->color[dir]];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ static const struct {
|
||||||
static void applyLedFixedLayers()
|
static void applyLedFixedLayers()
|
||||||
{
|
{
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
hsvColor_t color = *getSC(LED_SCOLOR_BACKGROUND);
|
hsvColor_t color = *getSC(LED_SCOLOR_BACKGROUND);
|
||||||
|
|
||||||
int fn = ledGetFunction(ledConfig);
|
int fn = ledGetFunction(ledConfig);
|
||||||
|
@ -458,13 +458,13 @@ static void applyLedFixedLayers()
|
||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case LED_FUNCTION_COLOR:
|
case LED_FUNCTION_COLOR:
|
||||||
color = masterConfig.colors[ledGetColor(ledConfig)];
|
color = currentLedStripConfig->colors[ledGetColor(ledConfig)];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LED_FUNCTION_FLIGHT_MODE:
|
case LED_FUNCTION_FLIGHT_MODE:
|
||||||
for (unsigned i = 0; i < ARRAYLEN(flightModeToLed); i++)
|
for (unsigned i = 0; i < ARRAYLEN(flightModeToLed); i++)
|
||||||
if (!flightModeToLed[i].flightMode || FLIGHT_MODE(flightModeToLed[i].flightMode)) {
|
if (!flightModeToLed[i].flightMode || FLIGHT_MODE(flightModeToLed[i].flightMode)) {
|
||||||
hsvColor_t *directionalColor = getDirectionalModeColor(ledIndex, &masterConfig.modeColors[flightModeToLed[i].ledMode]);
|
hsvColor_t *directionalColor = getDirectionalModeColor(ledIndex, ¤tLedStripConfig->modeColors[flightModeToLed[i].ledMode]);
|
||||||
if (directionalColor) {
|
if (directionalColor) {
|
||||||
color = *directionalColor;
|
color = *directionalColor;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +492,7 @@ static void applyLedFixedLayers()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ledGetOverlayBit(ledConfig, LED_OVERLAY_THROTTLE)) {
|
if (ledGetOverlayBit(ledConfig, LED_OVERLAY_THROTTLE)) {
|
||||||
hOffset += ((scaledThrottle - 10) * 4) / 3;
|
hOffset += scaledAux;
|
||||||
}
|
}
|
||||||
|
|
||||||
color.h = (color.h + hOffset) % (HSV_HUE_MAX + 1);
|
color.h = (color.h + hOffset) % (HSV_HUE_MAX + 1);
|
||||||
|
@ -505,7 +505,7 @@ static void applyLedFixedLayers()
|
||||||
static void applyLedHsv(uint32_t mask, const hsvColor_t *color)
|
static void applyLedHsv(uint32_t mask, const hsvColor_t *color)
|
||||||
{
|
{
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
if ((*ledConfig & mask) == mask)
|
if ((*ledConfig & mask) == mask)
|
||||||
setLedHsv(ledIndex, color);
|
setLedHsv(ledIndex, color);
|
||||||
}
|
}
|
||||||
|
@ -701,7 +701,7 @@ static void applyLedIndicatorLayer(bool updateNow, uint32_t *timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
if (ledGetOverlayBit(ledConfig, LED_OVERLAY_INDICATOR)) {
|
if (ledGetOverlayBit(ledConfig, LED_OVERLAY_INDICATOR)) {
|
||||||
if (getLedQuadrant(ledIndex) & quadrants)
|
if (getLedQuadrant(ledIndex) & quadrants)
|
||||||
setLedHsv(ledIndex, flashColor);
|
setLedHsv(ledIndex, flashColor);
|
||||||
|
@ -742,7 +742,7 @@ static void applyLedThrustRingLayer(bool updateNow, uint32_t *timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
if (ledGetFunction(ledConfig) == LED_FUNCTION_THRUST_RING) {
|
if (ledGetFunction(ledConfig) == LED_FUNCTION_THRUST_RING) {
|
||||||
|
|
||||||
bool applyColor;
|
bool applyColor;
|
||||||
|
@ -753,7 +753,7 @@ static void applyLedThrustRingLayer(bool updateNow, uint32_t *timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (applyColor) {
|
if (applyColor) {
|
||||||
const hsvColor_t *ringColor = &masterConfig.colors[ledGetColor(ledConfig)];
|
const hsvColor_t *ringColor = ¤tLedStripConfig->colors[ledGetColor(ledConfig)];
|
||||||
setLedHsv(ledIndex, ringColor);
|
setLedHsv(ledIndex, ringColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,7 +869,7 @@ static void applyLedAnimationLayer(bool updateNow, uint32_t *timer)
|
||||||
int nextRow = (frameCounter + 1 < animationFrames) ? frameCounter + 1 : 0;
|
int nextRow = (frameCounter + 1 < animationFrames) ? frameCounter + 1 : 0;
|
||||||
|
|
||||||
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
for (int ledIndex = 0; ledIndex < ledCounts.count; ledIndex++) {
|
||||||
const ledConfig_t *ledConfig = &masterConfig.ledConfigs[ledIndex];
|
const ledConfig_t *ledConfig = ¤tLedStripConfig->ledConfigs[ledIndex];
|
||||||
|
|
||||||
if (ledGetY(ledConfig) == previousRow) {
|
if (ledGetY(ledConfig) == previousRow) {
|
||||||
setLedHsv(ledIndex, getSC(LED_SCOLOR_ANIMATION));
|
setLedHsv(ledIndex, getSC(LED_SCOLOR_ANIMATION));
|
||||||
|
@ -931,7 +931,7 @@ void ledStripUpdate(uint32_t currentTime)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_RC_MODE_ACTIVE(BOXLEDLOW) && !(masterConfig.ledstrip_visual_beeper && isBeeperOn())) {
|
if (IS_RC_MODE_ACTIVE(BOXLEDLOW) && !(currentLedStripConfig->ledstrip_visual_beeper && isBeeperOn())) {
|
||||||
if (ledStripEnabled) {
|
if (ledStripEnabled) {
|
||||||
ledStripDisable();
|
ledStripDisable();
|
||||||
ledStripEnabled = false;
|
ledStripEnabled = false;
|
||||||
|
@ -962,6 +962,7 @@ void ledStripUpdate(uint32_t currentTime)
|
||||||
// apply all layers; triggered timed functions has to update timers
|
// apply all layers; triggered timed functions has to update timers
|
||||||
|
|
||||||
scaledThrottle = ARMING_FLAG(ARMED) ? scaleRange(rcData[THROTTLE], PWM_RANGE_MIN, PWM_RANGE_MAX, 10, 100) : 10;
|
scaledThrottle = ARMING_FLAG(ARMED) ? scaleRange(rcData[THROTTLE], PWM_RANGE_MIN, PWM_RANGE_MAX, 10, 100) : 10;
|
||||||
|
scaledAux = scaleRange(rcData[currentLedStripConfig->ledstrip_aux_channel], PWM_RANGE_MIN, PWM_RANGE_MAX, 0, HSV_HUE_MAX + 1);
|
||||||
|
|
||||||
applyLedFixedLayers();
|
applyLedFixedLayers();
|
||||||
|
|
||||||
|
@ -977,7 +978,7 @@ bool parseColor(int index, const char *colorConfig)
|
||||||
{
|
{
|
||||||
const char *remainingCharacters = colorConfig;
|
const char *remainingCharacters = colorConfig;
|
||||||
|
|
||||||
hsvColor_t *color = &masterConfig.colors[index];
|
hsvColor_t *color = ¤tLedStripConfig->colors[index];
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
static const uint16_t hsv_limit[HSV_COLOR_COMPONENT_COUNT] = {
|
static const uint16_t hsv_limit[HSV_COLOR_COMPONENT_COUNT] = {
|
||||||
|
@ -1030,11 +1031,15 @@ bool setModeColor(ledModeIndex_e modeIndex, int modeColorIndex, int colorIndex)
|
||||||
if (modeIndex < LED_MODE_COUNT) { // modeIndex_e is unsigned, so one-sided test is enough
|
if (modeIndex < LED_MODE_COUNT) { // modeIndex_e is unsigned, so one-sided test is enough
|
||||||
if(modeColorIndex < 0 || modeColorIndex >= LED_DIRECTION_COUNT)
|
if(modeColorIndex < 0 || modeColorIndex >= LED_DIRECTION_COUNT)
|
||||||
return false;
|
return false;
|
||||||
masterConfig.modeColors[modeIndex].color[modeColorIndex] = colorIndex;
|
currentLedStripConfig->modeColors[modeIndex].color[modeColorIndex] = colorIndex;
|
||||||
} else if (modeIndex == LED_SPECIAL) {
|
} else if (modeIndex == LED_SPECIAL) {
|
||||||
if (modeColorIndex < 0 || modeColorIndex >= LED_SPECIAL_COLOR_COUNT)
|
if (modeColorIndex < 0 || modeColorIndex >= LED_SPECIAL_COLOR_COUNT)
|
||||||
return false;
|
return false;
|
||||||
masterConfig.specialColors.color[modeColorIndex] = colorIndex;
|
currentLedStripConfig->specialColors.color[modeColorIndex] = colorIndex;
|
||||||
|
} else if (modeIndex == LED_AUX_CHANNEL) {
|
||||||
|
if (modeColorIndex < 0 || modeColorIndex >= 1)
|
||||||
|
return false;
|
||||||
|
currentLedStripConfig->ledstrip_aux_channel = colorIndex;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1092,21 +1097,26 @@ void applyDefaultSpecialColors(specialColorIndexes_t *specialColors)
|
||||||
memcpy_fn(specialColors, &defaultSpecialColors, sizeof(defaultSpecialColors));
|
memcpy_fn(specialColors, &defaultSpecialColors, sizeof(defaultSpecialColors));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse, modeColorIndexes_t *modeColorsToUse, specialColorIndexes_t *specialColorsToUse)
|
void ledStripInit(ledStripConfig_t *ledStripConfig)
|
||||||
{
|
{
|
||||||
ledConfigs = ledConfigsToUse;
|
currentLedStripConfig = ledStripConfig;
|
||||||
colors = colorsToUse;
|
|
||||||
modeColors = modeColorsToUse;
|
ledConfigs = currentLedStripConfig->ledConfigs;
|
||||||
specialColors = *specialColorsToUse;
|
colors = currentLedStripConfig->colors;
|
||||||
|
modeColors = currentLedStripConfig->modeColors;
|
||||||
|
specialColors = currentLedStripConfig->specialColors;
|
||||||
ledStripInitialised = false;
|
ledStripInitialised = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ledStripEnable(void)
|
void ledStripEnable(void)
|
||||||
{
|
{
|
||||||
|
if (currentLedStripConfig == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
reevaluateLedConfig();
|
reevaluateLedConfig();
|
||||||
ledStripInitialised = true;
|
ledStripInitialised = true;
|
||||||
|
|
||||||
ws2811LedStripInit();
|
ws2811LedStripInit(currentLedStripConfig->ioTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ledStripDisable(void)
|
static void ledStripDisable(void)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
|
#include "drivers/io_types.h"
|
||||||
|
|
||||||
#define LED_MAX_STRIP_LENGTH 32
|
#define LED_MAX_STRIP_LENGTH 32
|
||||||
#define LED_CONFIGURABLE_COLOR_COUNT 16
|
#define LED_CONFIGURABLE_COLOR_COUNT 16
|
||||||
|
@ -75,7 +76,8 @@ typedef enum {
|
||||||
LED_MODE_ANGLE,
|
LED_MODE_ANGLE,
|
||||||
LED_MODE_MAG,
|
LED_MODE_MAG,
|
||||||
LED_MODE_BARO,
|
LED_MODE_BARO,
|
||||||
LED_SPECIAL
|
LED_SPECIAL,
|
||||||
|
LED_AUX_CHANNEL
|
||||||
} ledModeIndex_e;
|
} ledModeIndex_e;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -134,6 +136,15 @@ typedef struct ledCounts_s {
|
||||||
uint8_t ringSeqLen;
|
uint8_t ringSeqLen;
|
||||||
} ledCounts_t;
|
} ledCounts_t;
|
||||||
|
|
||||||
|
typedef struct ledStripConfig_s {
|
||||||
|
ledConfig_t ledConfigs[LED_MAX_STRIP_LENGTH];
|
||||||
|
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_aux_channel;
|
||||||
|
ioTag_t ioTag;
|
||||||
|
} ledStripConfig_t;
|
||||||
|
|
||||||
ledConfig_t *ledConfigs;
|
ledConfig_t *ledConfigs;
|
||||||
hsvColor_t *colors;
|
hsvColor_t *colors;
|
||||||
|
@ -165,7 +176,7 @@ bool parseLedStripConfig(int ledIndex, const char *config);
|
||||||
void generateLedConfig(ledConfig_t *ledConfig, char *ledConfigBuffer, size_t bufferSize);
|
void generateLedConfig(ledConfig_t *ledConfig, char *ledConfigBuffer, size_t bufferSize);
|
||||||
void reevaluateLedConfig(void);
|
void reevaluateLedConfig(void);
|
||||||
|
|
||||||
void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse, modeColorIndexes_t *modeColorsToUse, specialColorIndexes_t *specialColorsToUse);
|
void ledStripInit(ledStripConfig_t *ledStripConfig);
|
||||||
void ledStripEnable(void);
|
void ledStripEnable(void);
|
||||||
void ledStripUpdate(uint32_t currentTime);
|
void ledStripUpdate(uint32_t currentTime);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue