Merge remote-tracking branch 'upstream/master' into new_state_machine

Conflicts:
	src/examples/fixedwing_control/main.c
This commit is contained in:
Julian Oes 2013-06-12 12:24:52 +02:00
commit 7f90ebf537
329 changed files with 5893 additions and 121390 deletions

80
.gitignore vendored
View File

@ -1,62 +1,26 @@
.built
.context
*.context
*.bdat
*.pdat
.depend
.updated
.config
.config-e
.version
.project
.cproject
apps/builtin/builtin_list.h
apps/builtin/builtin_proto.h
Make.dep
*.pyc
*.o
*.a
*.d *.d
*~
*.dSYM
Images/*.bin
Images/*.px4
nuttx/Make.defs
nuttx/setenv.sh
nuttx/arch/arm/include/board
nuttx/arch/arm/include/chip
nuttx/arch/arm/src/board
nuttx/arch/arm/src/chip
nuttx/include/apps
nuttx/include/arch
nuttx/include/math.h
nuttx/include/nuttx/config.h
nuttx/include/nuttx/version.h
nuttx/tools/mkconfig
nuttx/tools/mkconfig.exe
nuttx/tools/mkversion
nuttx/tools/mkversion.exe
nuttx/nuttx
nuttx/System.map
nuttx/nuttx.bin
nuttx/nuttx.hex
.configured
.settings
Firmware.sublime-workspace
.DS_Store
cscope.out
.configX-e
nuttx-export.zip
.~lock.*
dot.gdbinit
mavlink/include/mavlink/v0.9/
.*.swp
.swp
core
.gdbinit
mkdeps
Archives
Build
!ROMFS/*/*.d !ROMFS/*/*.d
!ROMFS/*/*/*.d !ROMFS/*/*/*.d
!ROMFS/*/*/*/*.d !ROMFS/*/*/*/*.d
*.dSYM
*.o
*.pyc
*~
.*.swp
.context
.cproject
.DS_Store
.gdbinit
.project
.settings
.swp
.~lock.*
Archives/*
Build/*
core
cscope.out
dot.gdbinit
Firmware.sublime-workspace
Images/*.bin
Images/*.px4
mavlink/include/mavlink/v0.9/

View File

@ -95,9 +95,14 @@ all: $(STAGED_FIRMWARES)
# #
# Copy FIRMWARES into the image directory. # Copy FIRMWARES into the image directory.
# #
# XXX copying the .bin files is a hack to work around the PX4IO uploader
# not supporting .px4 files, and it should be deprecated onced that
# is taken care of.
#
$(STAGED_FIRMWARES): $(IMAGE_DIR)%.px4: $(BUILD_DIR)%.build/firmware.px4 $(STAGED_FIRMWARES): $(IMAGE_DIR)%.px4: $(BUILD_DIR)%.build/firmware.px4
@echo %% Copying $@ @echo %% Copying $@
$(Q) $(COPY) $< $@ $(Q) $(COPY) $< $@
$(Q) $(COPY) $(patsubst %.px4,%.bin,$<) $(patsubst %.px4,%.bin,$@)
# #
# Generate FIRMWARES. # Generate FIRMWARES.

View File

@ -0,0 +1,53 @@
Helicopter 120 degree Cyclic-Collective-Pitch Mixing (CCPM) for PX4FMU
==================================================
Output 0 - Rear Servo Mixer
----------------
Rear Servo = Collective (Thrust - 3) + Elevator (Pitch - 1)
M: 2
O: 10000 10000 0 -10000 10000
S: 0 3 10000 10000 0 -10000 10000
S: 0 1 10000 10000 0 -10000 10000
Output 1 - Left Servo Mixer
-----------------
Left Servo = Collective (Thurst - 3) - 0.5 * Elevator (Pitch - 1) + 0.866 * Aileron (Roll - 0)
M: 3
O: 10000 10000 0 -10000 10000
S: 0 3 -10000 -10000 0 -10000 10000
S: 0 1 -5000 -5000 0 -10000 10000
S: 0 0 8660 8660 0 -10000 10000
Output 2 - Right Servo Mixer
----------------
Right Servo = Collective (Thurst - 3) - 0.5 * Elevator (Pitch - 1) - 0.866 * Aileron (Roll - 0)
M: 3
O: 10000 10000 0 -10000 10000
S: 0 3 -10000 -10000 0 -10000 10000
S: 0 1 -5000 -5000 0 -10000 10000
S: 0 0 -8660 -8660 0 -10000 10000
Output 3 - Tail Servo Mixer
----------------
Tail Servo = Yaw (control index = 2)
M: 1
O: 10000 10000 0 -10000 10000
S: 0 2 10000 10000 0 -10000 10000
Output 4 - Motor speed mixer
-----------------
This would be the motor speed control output from governor power demand- not sure what index to use here?
M: 1
O: 10000 10000 0 -10000 10000
S: 0 4 0 20000 -10000 -10000 10000

View File

@ -0,0 +1,38 @@
Passthrough mixer for PX4IO
============================
This file defines passthrough mixers suitable for testing.
Channel group 0, channels 0-7 are passed directly through to the outputs.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 0 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 1 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 2 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 3 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 4 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 5 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 6 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 7 10000 10000 0 -10000 10000

59
Tools/logconv.py Normal file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
"""Convert binary log generated by sdlog to CSV format
Usage: python logconv.py <log.bin>"""
__author__ = "Anton Babushkin"
__version__ = "0.1"
import struct, sys
def _unpack_packet(data):
s = ""
s += "Q" #.timestamp = buf.raw.timestamp,
s += "fff" #.gyro = {buf.raw.gyro_rad_s[0], buf.raw.gyro_rad_s[1], buf.raw.gyro_rad_s[2]},
s += "fff" #.accel = {buf.raw.accelerometer_m_s2[0], buf.raw.accelerometer_m_s2[1], buf.raw.accelerometer_m_s2[2]},
s += "fff" #.mag = {buf.raw.magnetometer_ga[0], buf.raw.magnetometer_ga[1], buf.raw.magnetometer_ga[2]},
s += "f" #.baro = buf.raw.baro_pres_mbar,
s += "f" #.baro_alt = buf.raw.baro_alt_meter,
s += "f" #.baro_temp = buf.raw.baro_temp_celcius,
s += "ffff" #.control = {buf.act_controls.control[0], buf.act_controls.control[1], buf.act_controls.control[2], buf.act_controls.control[3]},
s += "ffffffff" #.actuators = {buf.act_outputs.output[0], buf.act_outputs.output[1], buf.act_outputs.output[2], buf.act_outputs.output[3], buf.act_outputs.output[4], buf.act_outputs.output[5], buf.act_outputs.output[6], buf.act_outputs.output[7]},
s += "f" #.vbat = buf.batt.voltage_v,
s += "f" #.bat_current = buf.batt.current_a,
s += "f" #.bat_discharged = buf.batt.discharged_mah,
s += "ffff" #.adc = {buf.raw.adc_voltage_v[0], buf.raw.adc_voltage_v[1], buf.raw.adc_voltage_v[2], buf.raw.adc_voltage_v[3]},
s += "fff" #.local_position = {buf.local_pos.x, buf.local_pos.y, buf.local_pos.z},
s += "iii" #.gps_raw_position = {buf.gps_pos.lat, buf.gps_pos.lon, buf.gps_pos.alt},
s += "fff" #.attitude = {buf.att.pitch, buf.att.roll, buf.att.yaw},
s += "fffffffff" #.rotMatrix = {buf.att.R[0][0], buf.att.R[0][1], buf.att.R[0][2], buf.att.R[1][0], buf.att.R[1][1], buf.att.R[1][2], buf.att.R[2][0], buf.att.R[2][1], buf.att.R[2][2]},
s += "fff" #.vicon = {buf.vicon_pos.x, buf.vicon_pos.y, buf.vicon_pos.z, buf.vicon_pos.roll, buf.vicon_pos.pitch, buf.vicon_pos.yaw},
s += "ffff" #.control_effective = {buf.act_controls_effective.control_effective[0], buf.act_controls_effective.control_effective[1], buf.act_controls_effective.control_effective[2], buf.act_controls_effective.control_effective[3]},
s += "ffffff" #.flow = {buf.flow.flow_raw_x, buf.flow.flow_raw_y, buf.flow.flow_comp_x_m, buf.flow.flow_comp_y_m, buf.flow.ground_distance_m, buf.flow.quality},
s += "f" #.diff_pressure = buf.diff_pres.differential_pressure_pa,
s += "f" #.ind_airspeed = buf.airspeed.indicated_airspeed_m_s,
s += "f" #.true_airspeed = buf.airspeed.true_airspeed_m_s
s += "iii" # to align to 280
d = struct.unpack(s, data)
return d
def _main():
if len(sys.argv) < 2:
print "Usage:\npython logconv.py <log.bin>"
return
fn = sys.argv[1]
sysvector_size = 280
f = open(fn, "r")
while True:
data = f.read(sysvector_size)
if len(data) < sysvector_size:
break
a = []
for i in _unpack_packet(data):
a.append(str(i))
print ";".join(a)
f.close()
if __name__ == "__main__":
_main()

293
Tools/sdlog2_dump.py Normal file
View File

@ -0,0 +1,293 @@
#!/usr/bin/env python
"""Dump binary log generated by sdlog2 or APM as CSV
Usage: python sdlog2_dump.py <log.bin> [-v] [-e] [-d delimiter] [-n null] [-m MSG[.field1,field2,...]]
-v Use plain debug output instead of CSV.
-e Recover from errors.
-d Use "delimiter" in CSV. Default is ",".
-n Use "null" as placeholder for empty values in CSV. Default is empty.
-m MSG[.field1,field2,...]
Dump only messages of specified type, and only specified fields.
Multiple -m options allowed."""
__author__ = "Anton Babushkin"
__version__ = "1.2"
import struct, sys
class SDLog2Parser:
BLOCK_SIZE = 8192
MSG_HEADER_LEN = 3
MSG_HEAD1 = 0xA3
MSG_HEAD2 = 0x95
MSG_FORMAT_PACKET_LEN = 89
MSG_FORMAT_STRUCT = "BB4s16s64s"
MSG_TYPE_FORMAT = 0x80
FORMAT_TO_STRUCT = {
"b": ("b", None),
"B": ("B", None),
"h": ("h", None),
"H": ("H", None),
"i": ("i", None),
"I": ("I", None),
"f": ("f", None),
"n": ("4s", None),
"N": ("16s", None),
"Z": ("64s", None),
"c": ("h", 0.01),
"C": ("H", 0.01),
"e": ("i", 0.01),
"E": ("I", 0.01),
"L": ("i", 0.0000001),
"M": ("b", None),
"q": ("q", None),
"Q": ("Q", None),
}
__csv_delim = ","
__csv_null = ""
__msg_filter = []
__time_msg = None
__debug_out = False
__correct_errors = False
def __init__(self):
return
def reset(self):
self.__msg_descrs = {} # message descriptions by message type map
self.__msg_labels = {} # message labels by message name map
self.__msg_names = [] # message names in the same order as FORMAT messages
self.__buffer = "" # buffer for input binary data
self.__ptr = 0 # read pointer in buffer
self.__csv_columns = [] # CSV file columns in correct order in format "MSG.label"
self.__csv_data = {} # current values for all columns
self.__csv_updated = False
self.__msg_filter_map = {} # filter in form of map, with '*" expanded to full list of fields
def setCSVDelimiter(self, csv_delim):
self.__csv_delim = csv_delim
def setCSVNull(self, csv_null):
self.__csv_null = csv_null
def setMsgFilter(self, msg_filter):
self.__msg_filter = msg_filter
def setTimeMsg(self, time_msg):
self.__time_msg = time_msg
def setDebugOut(self, debug_out):
self.__debug_out = debug_out
def setCorrectErrors(self, correct_errors):
self.__correct_errors = correct_errors
def process(self, fn):
self.reset()
if self.__debug_out:
# init __msg_filter_map
for msg_name, show_fields in self.__msg_filter:
self.__msg_filter_map[msg_name] = show_fields
first_data_msg = True
f = open(fn, "r")
bytes_read = 0
while True:
chunk = f.read(self.BLOCK_SIZE)
if len(chunk) == 0:
break
self.__buffer = self.__buffer[self.__ptr:] + chunk
self.__ptr = 0
while self.__bytesLeft() >= self.MSG_HEADER_LEN:
head1 = ord(self.__buffer[self.__ptr])
head2 = ord(self.__buffer[self.__ptr+1])
if (head1 != self.MSG_HEAD1 or head2 != self.MSG_HEAD2):
if self.__correct_errors:
self.__ptr += 1
continue
else:
raise Exception("Invalid header at %i (0x%X): %02X %02X, must be %02X %02X" % (bytes_read + self.__ptr, bytes_read + self.__ptr, head1, head2, self.MSG_HEAD1, self.MSG_HEAD2))
msg_type = ord(self.__buffer[self.__ptr+2])
if msg_type == self.MSG_TYPE_FORMAT:
# parse FORMAT message
if self.__bytesLeft() < self.MSG_FORMAT_PACKET_LEN:
break
self.__parseMsgDescr()
else:
# parse data message
msg_descr = self.__msg_descrs[msg_type]
if msg_descr == None:
raise Exception("Unknown msg type: %i" % msg_type)
msg_length = msg_descr[0]
if self.__bytesLeft() < msg_length:
break
if first_data_msg:
# build CSV columns and init data map
self.__initCSV()
first_data_msg = False
self.__parseMsg(msg_descr)
bytes_read += self.__ptr
if not self.__debug_out and self.__time_msg != None and self.__csv_updated:
self.__printCSVRow()
f.close()
def __bytesLeft(self):
return len(self.__buffer) - self.__ptr
def __filterMsg(self, msg_name):
show_fields = "*"
if len(self.__msg_filter_map) > 0:
show_fields = self.__msg_filter_map.get(msg_name)
return show_fields
def __initCSV(self):
if len(self.__msg_filter) == 0:
for msg_name in self.__msg_names:
self.__msg_filter.append((msg_name, "*"))
for msg_name, show_fields in self.__msg_filter:
if show_fields == "*":
show_fields = self.__msg_labels.get(msg_name, [])
self.__msg_filter_map[msg_name] = show_fields
for field in show_fields:
full_label = msg_name + "." + field
self.__csv_columns.append(full_label)
self.__csv_data[full_label] = None
print self.__csv_delim.join(self.__csv_columns)
def __printCSVRow(self):
s = []
for full_label in self.__csv_columns:
v = self.__csv_data[full_label]
if v == None:
v = self.__csv_null
else:
v = str(v)
s.append(v)
print self.__csv_delim.join(s)
def __parseMsgDescr(self):
data = struct.unpack(self.MSG_FORMAT_STRUCT, self.__buffer[self.__ptr + 3 : self.__ptr + self.MSG_FORMAT_PACKET_LEN])
msg_type = data[0]
if msg_type != self.MSG_TYPE_FORMAT:
msg_length = data[1]
msg_name = data[2].strip("\0")
msg_format = data[3].strip("\0")
msg_labels = data[4].strip("\0").split(",")
# Convert msg_format to struct.unpack format string
msg_struct = ""
msg_mults = []
for c in msg_format:
try:
f = self.FORMAT_TO_STRUCT[c]
msg_struct += f[0]
msg_mults.append(f[1])
except KeyError as e:
raise Exception("Unsupported format char: %s in message %s (%i)" % (c, msg_name, msg_type))
msg_struct = "<" + msg_struct # force little-endian
self.__msg_descrs[msg_type] = (msg_length, msg_name, msg_format, msg_labels, msg_struct, msg_mults)
self.__msg_labels[msg_name] = msg_labels
self.__msg_names.append(msg_name)
if self.__debug_out:
if self.__filterMsg(msg_name) != None:
print "MSG FORMAT: type = %i, length = %i, name = %s, format = %s, labels = %s, struct = %s, mults = %s" % (
msg_type, msg_length, msg_name, msg_format, str(msg_labels), msg_struct, msg_mults)
self.__ptr += self.MSG_FORMAT_PACKET_LEN
def __parseMsg(self, msg_descr):
msg_length, msg_name, msg_format, msg_labels, msg_struct, msg_mults = msg_descr
if not self.__debug_out and self.__time_msg != None and msg_name == self.__time_msg and self.__csv_updated:
self.__printCSVRow()
self.__csv_updated = False
show_fields = self.__filterMsg(msg_name)
if (show_fields != None):
data = list(struct.unpack(msg_struct, self.__buffer[self.__ptr+self.MSG_HEADER_LEN:self.__ptr+msg_length]))
for i in xrange(len(data)):
if type(data[i]) is str:
data[i] = data[i].strip("\0")
m = msg_mults[i]
if m != None:
data[i] = data[i] * m
if self.__debug_out:
s = []
for i in xrange(len(data)):
label = msg_labels[i]
if show_fields == "*" or label in show_fields:
s.append(label + "=" + str(data[i]))
print "MSG %s: %s" % (msg_name, ", ".join(s))
else:
# update CSV data buffer
for i in xrange(len(data)):
label = msg_labels[i]
if label in show_fields:
self.__csv_data[msg_name + "." + label] = data[i]
if self.__time_msg != None and msg_name != self.__time_msg:
self.__csv_updated = True
if self.__time_msg == None:
self.__printCSVRow()
self.__ptr += msg_length
def _main():
if len(sys.argv) < 2:
print "Usage: python sdlog2_dump.py <log.bin> [-v] [-e] [-d delimiter] [-n null] [-m MSG[.field1,field2,...]] [-t TIME_MSG_NAME]\n"
print "\t-v\tUse plain debug output instead of CSV.\n"
print "\t-e\tRecover from errors.\n"
print "\t-d\tUse \"delimiter\" in CSV. Default is \",\".\n"
print "\t-n\tUse \"null\" as placeholder for empty values in CSV. Default is empty.\n"
print "\t-m MSG[.field1,field2,...]\n\t\tDump only messages of specified type, and only specified fields.\n\t\tMultiple -m options allowed."
print "\t-t\tSpecify TIME message name to group data messages by time and significantly reduce duplicate output.\n"
return
fn = sys.argv[1]
debug_out = False
correct_errors = False
msg_filter = []
csv_null = ""
csv_delim = ","
time_msg = None
opt = None
for arg in sys.argv[2:]:
if opt != None:
if opt == "d":
csv_delim = arg
elif opt == "n":
csv_null = arg
elif opt == "t":
time_msg = arg
elif opt == "m":
show_fields = "*"
a = arg.split(".")
if len(a) > 1:
show_fields = a[1].split(",")
msg_filter.append((a[0], show_fields))
opt = None
else:
if arg == "-v":
debug_out = True
elif arg == "-e":
correct_errors = True
elif arg == "-d":
opt = "d"
elif arg == "-n":
opt = "n"
elif arg == "-m":
opt = "m"
elif arg == "-t":
opt = "t"
if csv_delim == "\\t":
csv_delim = "\t"
parser = SDLog2Parser()
parser.setCSVDelimiter(csv_delim)
parser.setCSVNull(csv_null)
parser.setMsgFilter(msg_filter)
parser.setTimeMsg(time_msg)
parser.setDebugOut(debug_out)
parser.setCorrectErrors(correct_errors)
parser.process(fn)
if __name__ == "__main__":
_main()

10
apps/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
*.a
*.bdat
*.pdat
.built
.config
.depend
.updated
builtin/builtin_list.h
builtin/builtin_proto.h
Make.dep

View File

@ -56,12 +56,14 @@ MODULES += systemcmds/tests
MODULES += modules/commander MODULES += modules/commander
MODULES += modules/mavlink MODULES += modules/mavlink
MODULES += modules/mavlink_onboard MODULES += modules/mavlink_onboard
MODULES += modules/gpio_led
# #
# Estimation modules (EKF / other filters) # Estimation modules (EKF / other filters)
# #
MODULES += modules/attitude_estimator_ekf MODULES += modules/attitude_estimator_ekf
MODULES += modules/position_estimator_mc MODULES += modules/attitude_estimator_so3_comp
#MODULES += modules/position_estimator_mc
MODULES += modules/position_estimator MODULES += modules/position_estimator
MODULES += modules/att_pos_estimator_ekf MODULES += modules/att_pos_estimator_ekf
@ -78,17 +80,22 @@ MODULES += modules/multirotor_pos_control
# Logging # Logging
# #
MODULES += modules/sdlog MODULES += modules/sdlog
MODULES += modules/sdlog2
# #
# Libraries # Library modules
# #
MODULES += modules/systemlib MODULES += modules/systemlib
MODULES += modules/systemlib/mixer MODULES += modules/systemlib/mixer
MODULES += modules/mathlib MODULES += modules/mathlib
MODULES += modules/mathlib/CMSIS
MODULES += modules/controllib MODULES += modules/controllib
MODULES += modules/uORB MODULES += modules/uORB
#
# Libraries
#
LIBRARIES += modules/mathlib/CMSIS
# #
# Demo apps # Demo apps
# #

View File

@ -177,20 +177,14 @@ GLOBAL_DEPS += $(MAKEFILE_LIST)
EXTRA_CLEANS = EXTRA_CLEANS =
################################################################################ ################################################################################
# Modules # NuttX libraries and paths
################################################################################ ################################################################################
# include $(PX4_MK_DIR)/nuttx.mk
# We don't actually know what a module is called; all we have is a path fragment
# that we can search for, and where we expect to find a module.mk file. ################################################################################
# # Modules
# As such, we replicate the successfully-found path inside WORK_DIR for the ################################################################################
# module's build products in order to keep modules separated from each other.
#
# XXX If this becomes unwieldy or breaks for other reasons, we will need to
# move to allocating directory names and keeping tabs on makefiles via
# the directory name. That will involve arithmetic (it'd probably be time
# for GMSL).
# where to look for modules # where to look for modules
MODULE_SEARCH_DIRS += $(WORK_DIR) $(MODULE_SRC) $(PX4_MODULE_SRC) MODULE_SEARCH_DIRS += $(WORK_DIR) $(MODULE_SRC) $(PX4_MODULE_SRC)
@ -249,10 +243,64 @@ $(MODULE_CLEANS):
clean clean
################################################################################ ################################################################################
# NuttX libraries and paths # Libraries
################################################################################ ################################################################################
include $(PX4_MK_DIR)/nuttx.mk # where to look for libraries
LIBRARY_SEARCH_DIRS += $(WORK_DIR) $(MODULE_SRC) $(PX4_MODULE_SRC)
# sort and unique the library list
LIBRARIES := $(sort $(LIBRARIES))
# locate the first instance of a library by full path or by looking on the
# library search path
define LIBRARY_SEARCH
$(firstword $(abspath $(wildcard $(1)/library.mk)) \
$(abspath $(foreach search_dir,$(LIBRARY_SEARCH_DIRS),$(wildcard $(search_dir)/$(1)/library.mk))) \
MISSING_$1)
endef
# make a list of library makefiles and check that we found them all
LIBRARY_MKFILES := $(foreach library,$(LIBRARIES),$(call LIBRARY_SEARCH,$(library)))
MISSING_LIBRARIES := $(subst MISSING_,,$(filter MISSING_%,$(LIBRARY_MKFILES)))
ifneq ($(MISSING_LIBRARIES),)
$(error Can't find library(s): $(MISSING_LIBRARIES))
endif
# Make a list of the archive files we expect to build from libraries
# Note that this path will typically contain a double-slash at the WORK_DIR boundary; this must be
# preserved as it is used below to get the absolute path for the library.mk file correct.
#
LIBRARY_LIBS := $(foreach path,$(dir $(LIBRARY_MKFILES)),$(WORK_DIR)$(path)library.a)
# rules to build module objects
.PHONY: $(LIBRARY_LIBS)
$(LIBRARY_LIBS): relpath = $(patsubst $(WORK_DIR)%,%,$@)
$(LIBRARY_LIBS): mkfile = $(patsubst %library.a,%library.mk,$(relpath))
$(LIBRARY_LIBS): workdir = $(@D)
$(LIBRARY_LIBS): $(GLOBAL_DEPS) $(NUTTX_CONFIG_HEADER)
$(Q) $(MKDIR) -p $(workdir)
$(Q) $(MAKE) -r -f $(PX4_MK_DIR)library.mk \
-C $(workdir) \
LIBRARY_WORK_DIR=$(workdir) \
LIBRARY_LIB=$@ \
LIBRARY_MK=$(mkfile) \
LIBRARY_NAME=$(lastword $(subst /, ,$(workdir))) \
library
# make a list of phony clean targets for modules
LIBRARY_CLEANS := $(foreach path,$(dir $(LIBRARY_MKFILES)),$(WORK_DIR)$(path)/clean)
# rules to clean modules
.PHONY: $(LIBRARY_CLEANS)
$(LIBRARY_CLEANS): relpath = $(patsubst $(WORK_DIR)%,%,$@)
$(LIBRARY_CLEANS): mkfile = $(patsubst %clean,%library.mk,$(relpath))
$(LIBRARY_CLEANS):
@$(ECHO) %% cleaning using $(mkfile)
$(Q) $(MAKE) -r -f $(PX4_MK_DIR)library.mk \
LIBRARY_WORK_DIR=$(dir $@) \
LIBRARY_MK=$(mkfile) \
clean
################################################################################ ################################################################################
# ROMFS generation # ROMFS generation
@ -420,8 +468,8 @@ $(PRODUCT_BUNDLE): $(PRODUCT_BIN)
$(PRODUCT_BIN): $(PRODUCT_ELF) $(PRODUCT_BIN): $(PRODUCT_ELF)
$(call SYM_TO_BIN,$<,$@) $(call SYM_TO_BIN,$<,$@)
$(PRODUCT_ELF): $(OBJS) $(MODULE_OBJS) $(GLOBAL_DEPS) $(LINK_DEPS) $(MODULE_MKFILES) $(PRODUCT_ELF): $(OBJS) $(MODULE_OBJS) $(LIBRARY_LIBS) $(GLOBAL_DEPS) $(LINK_DEPS) $(MODULE_MKFILES)
$(call LINK,$@,$(OBJS) $(MODULE_OBJS)) $(call LINK,$@,$(OBJS) $(MODULE_OBJS) $(LIBRARY_LIBS))
# #
# Utility rules # Utility rules

169
makefiles/library.mk Normal file
View File

@ -0,0 +1,169 @@
#
# Copyright (c) 2013 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# Framework makefile for PX4 libraries
#
# This makefile is invoked by firmware.mk to build each of the linraries
# that will subsequently be linked into the firmware image.
#
# Applications are built as standard ar archives. Unlike modules,
# all public symbols in library objects are visible across the entire
# firmware stack.
#
# In general, modules should be preferred to libraries when possible.
# Libraries may also be pre-built.
#
# IMPORTANT NOTE:
#
# This makefile assumes it is being invoked in the library's output directory.
#
#
# Variables that can be set by the library's library.mk:
#
#
# SRCS (optional)
#
# Lists the .c, cpp and .S files that should be compiled/assembled to
# produce the library.
#
# PREBUILT_LIB (optional)
#
# Names the prebuilt library in the source directory that should be
# linked into the firmware.
#
# INCLUDE_DIRS (optional, must be appended, ignored if SRCS not set)
#
# The list of directories searched for include files. If non-standard
# includes (e.g. those from another module) are required, paths to search
# can be added here.
#
#
#
# Variables visible to the library's library.mk:
#
# CONFIG
# BOARD
# LIBRARY_WORK_DIR
# LIBRARY_LIB
# LIBRARY_MK
# Anything set in setup.mk, board_$(BOARD).mk and the toolchain file.
# Anything exported from config_$(CONFIG).mk
#
################################################################################
# No user-serviceable parts below.
################################################################################
ifeq ($(LIBRARY_MK),)
$(error No library makefile specified)
endif
$(info %% LIBRARY_MK = $(LIBRARY_MK))
#
# Get the board/toolchain config
#
include $(PX4_MK_DIR)/board_$(BOARD).mk
#
# Get the library's config
#
include $(LIBRARY_MK)
LIBRARY_SRC := $(dir $(LIBRARY_MK))
$(info % LIBRARY_NAME = $(LIBRARY_NAME))
$(info % LIBRARY_SRC = $(LIBRARY_SRC))
$(info % LIBRARY_LIB = $(LIBRARY_LIB))
$(info % LIBRARY_WORK_DIR = $(LIBRARY_WORK_DIR))
#
# Things that, if they change, might affect everything
#
GLOBAL_DEPS += $(MAKEFILE_LIST)
################################################################################
# Build rules
################################################################################
#
# What we're going to build
#
library: $(LIBRARY_LIB)
ifneq ($(PREBUILT_LIB),)
VPATH = $(LIBRARY_SRC)
$(LIBRARY_LIB): $(PREBUILT_LIB) $(GLOBAL_DEPS)
@$(ECHO) "PREBUILT: $(PREBUILT_LIB)"
$(Q) $(COPY) $< $@
else
##
## Object files we will generate from sources
##
OBJS = $(addsuffix .o,$(SRCS))
#
# SRCS -> OBJS rules
#
$(OBJS): $(GLOBAL_DEPS)
vpath %.c $(LIBRARY_SRC)
$(filter %.c.o,$(OBJS)): %.c.o: %.c $(GLOBAL_DEPS)
$(call COMPILE,$<,$@)
vpath %.cpp $(LIBRARY_SRC)
$(filter %.cpp.o,$(OBJS)): %.cpp.o: %.cpp $(GLOBAL_DEPS)
$(call COMPILEXX,$<,$@)
vpath %.S $(LIBRARY_SRC)
$(filter %.S.o,$(OBJS)): %.S.o: %.S $(GLOBAL_DEPS)
$(call ASSEMBLE,$<,$@)
#
# Built product rules
#
$(LIBRARY_LIB): $(OBJS) $(GLOBAL_DEPS)
$(call ARCHIVE,$@,$(OBJS))
endif
#
# Utility rules
#
clean:
$(Q) $(REMOVE) $(LIBRARY_LIB) $(OBJS)

View File

@ -35,7 +35,7 @@
# This makefile is invoked by firmware.mk to build each of the modules # This makefile is invoked by firmware.mk to build each of the modules
# that will subsequently be linked into the firmware image. # that will subsequently be linked into the firmware image.
# #
# Applications are built as prelinked objects with a limited set of exported # Modules are built as prelinked objects with a limited set of exported
# symbols, as the global namespace is shared between all modules. Normally an # symbols, as the global namespace is shared between all modules. Normally an
# module will just export one or more <command>_main functions. # module will just export one or more <command>_main functions.
# #
@ -183,30 +183,15 @@ CXXFLAGS += -fvisibility=$(DEFAULT_VISIBILITY) -include $(PX4_INCLUDE_DIR)visibi
# #
module: $(MODULE_OBJ) $(MODULE_COMMAND_FILES) module: $(MODULE_OBJ) $(MODULE_COMMAND_FILES)
##
## Locate sources (allows relative source paths in module.mk)
##
#define SRC_SEARCH
# $(abspath $(firstword $(wildcard $1) $(wildcard $(MODULE_SRC)/$1) MISSING_$1))
#endef
# #
#ABS_SRCS ?= $(foreach src,$(SRCS),$(call SRC_SEARCH,$(src))) # Object files we will generate from sources
#MISSING_SRCS := $(subst MISSING_,,$(filter MISSING_%,$(ABS_SRCS)))
#ifneq ($(MISSING_SRCS),)
#$(error $(MODULE_MK): missing in SRCS: $(MISSING_SRCS))
#endif
#ifeq ($(ABS_SRCS),)
#$(error $(MODULE_MK): nothing to compile in SRCS)
#endif
# #
## OBJS = $(addsuffix .o,$(SRCS))
## Object files we will generate from sources
##
#OBJS := $(foreach src,$(ABS_SRCS),$(MODULE_WORK_DIR)$(src).o)
OBJS = $(addsuffix .o,$(SRCS)) #
$(info SRCS $(SRCS)) # Dependency files that will be auto-generated
$(info OBJS $(OBJS)) #
DEPS = $(addsuffix .d,$(SRCS))
# #
# SRCS -> OBJS rules # SRCS -> OBJS rules
@ -239,3 +224,5 @@ $(MODULE_OBJ): $(OBJS) $(GLOBAL_DEPS)
clean: clean:
$(Q) $(REMOVE) $(MODULE_PRELINK) $(OBJS) $(Q) $(REMOVE) $(MODULE_PRELINK) $(OBJS)
-include $(DEPS)

View File

@ -69,10 +69,14 @@ INCLUDE_DIRS += $(NUTTX_EXPORT_DIR)include \
LIB_DIRS += $(NUTTX_EXPORT_DIR)libs LIB_DIRS += $(NUTTX_EXPORT_DIR)libs
LIBS += -lapps -lnuttx LIBS += -lapps -lnuttx
LINK_DEPS += $(NUTTX_EXPORT_DIR)libs/libapps.a \ NUTTX_LIBS = $(NUTTX_EXPORT_DIR)libs/libapps.a \
$(NUTTX_EXPORT_DIR)libs/libnuttx.a $(NUTTX_EXPORT_DIR)libs/libnuttx.a
LINK_DEPS += $(NUTTX_LIBS)
$(NUTTX_CONFIG_HEADER): $(NUTTX_ARCHIVE) $(NUTTX_CONFIG_HEADER): $(NUTTX_ARCHIVE)
@$(ECHO) %% Unpacking $(NUTTX_ARCHIVE) @$(ECHO) %% Unpacking $(NUTTX_ARCHIVE)
$(Q) $(UNZIP_CMD) -q -o -d $(WORK_DIR) $(NUTTX_ARCHIVE) $(Q) $(UNZIP_CMD) -q -o -d $(WORK_DIR) $(NUTTX_ARCHIVE)
$(Q) $(TOUCH) $@ $(Q) $(TOUCH) $@
$(LDSCRIPT): $(NUTTX_CONFIG_HEADER)
$(NUTTX_LIBS): $(NUTTX_CONFIG_HEADER)

View File

@ -50,7 +50,7 @@ OBJDUMP = $(CROSSDEV)objdump
# XXX this is pulled pretty directly from the fmu Make.defs - needs cleanup # XXX this is pulled pretty directly from the fmu Make.defs - needs cleanup
MAXOPTIMIZATION = -O3 MAXOPTIMIZATION ?= -O3
# Base CPU flags for each of the supported architectures. # Base CPU flags for each of the supported architectures.
# #
@ -70,6 +70,14 @@ ARCHCPUFLAGS_CORTEXM3 = -mcpu=cortex-m3 \
-march=armv7-m \ -march=armv7-m \
-mfloat-abi=soft -mfloat-abi=soft
ARCHINSTRUMENTATIONDEFINES_CORTEXM4F = -finstrument-functions \
-ffixed-r10
ARCHINSTRUMENTATIONDEFINES_CORTEXM4 = -finstrument-functions \
-ffixed-r10
ARCHINSTRUMENTATIONDEFINES_CORTEXM3 =
# Pick the right set of flags for the architecture. # Pick the right set of flags for the architecture.
# #
ARCHCPUFLAGS = $(ARCHCPUFLAGS_$(CONFIG_ARCH)) ARCHCPUFLAGS = $(ARCHCPUFLAGS_$(CONFIG_ARCH))
@ -91,8 +99,8 @@ ARCHOPTIMIZATION = $(MAXOPTIMIZATION) \
# enable precise stack overflow tracking # enable precise stack overflow tracking
# note - requires corresponding support in NuttX # note - requires corresponding support in NuttX
INSTRUMENTATIONDEFINES = -finstrument-functions \ INSTRUMENTATIONDEFINES = $(ARCHINSTRUMENTATIONDEFINES_$(CONFIG_ARCH))
-ffixed-r10
# Language-specific flags # Language-specific flags
# #
ARCHCFLAGS = -std=gnu99 ARCHCFLAGS = -std=gnu99
@ -219,7 +227,7 @@ endef
define PRELINK define PRELINK
@$(ECHO) "PRELINK: $1" @$(ECHO) "PRELINK: $1"
@$(MKDIR) -p $(dir $1) @$(MKDIR) -p $(dir $1)
$(Q) $(LD) -Ur -o $1 $2 && $(OBJCOPY) --localize-hidden $1 $(Q) $(LD) -Ur -Map $1.map -o $1 $2 && $(OBJCOPY) --localize-hidden $1
endef endef
# Update the archive $1 with the files in $2 # Update the archive $1 with the files in $2
@ -235,7 +243,7 @@ endef
define LINK define LINK
@$(ECHO) "LINK: $1" @$(ECHO) "LINK: $1"
@$(MKDIR) -p $(dir $1) @$(MKDIR) -p $(dir $1)
$(Q) $(LD) $(LDFLAGS) -o $1 --start-group $2 $(LIBS) $(EXTRA_LIBS) $(LIBGCC) --end-group $(Q) $(LD) $(LDFLAGS) -Map $1.map -o $1 --start-group $2 $(LIBS) $(EXTRA_LIBS) $(LIBGCC) --end-group
endef endef
# Convert $1 from a linked object to a raw binary in $2 # Convert $1 from a linked object to a raw binary in $2
@ -280,6 +288,7 @@ define BIN_TO_OBJ
$(Q) $(OBJCOPY) $2 \ $(Q) $(OBJCOPY) $2 \
--redefine-sym $(call BIN_SYM_PREFIX,$1)_start=$3 \ --redefine-sym $(call BIN_SYM_PREFIX,$1)_start=$3 \
--redefine-sym $(call BIN_SYM_PREFIX,$1)_size=$3_len \ --redefine-sym $(call BIN_SYM_PREFIX,$1)_size=$3_len \
--strip-symbol $(call BIN_SYM_PREFIX,$1)_end --strip-symbol $(call BIN_SYM_PREFIX,$1)_end \
--rename-section .data=.rodata
$(Q) $(REMOVE) $2.c $2.c.o $(Q) $(REMOVE) $2.c $2.c.o
endef endef

28
nuttx/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
*.a
.config
.config-e
.configX-e
.depend
.version
arch/arm/include/board
arch/arm/include/chip
arch/arm/src/board
arch/arm/src/chip
include/apps
include/arch
include/math.h
include/nuttx/config.h
include/nuttx/version.h
Make.defs
Make.dep
mkdeps
nuttx
nuttx-export.zip
nuttx.bin
nuttx.hex
setenv.sh
System.map
tools/mkconfig
tools/mkconfig.exe
tools/mkversion
tools/mkversion.exe

View File

@ -243,7 +243,7 @@ endif
ifeq ($(CONFIG_ARMV7M_TOOLCHAIN),GNU_EABI) ifeq ($(CONFIG_ARMV7M_TOOLCHAIN),GNU_EABI)
CROSSDEV ?= arm-none-eabi- CROSSDEV ?= arm-none-eabi-
ARCROSSDEV ?= arm-none-eabi- ARCROSSDEV ?= arm-none-eabi-
MAXOPTIMIZATION = -O3 MAXOPTIMIZATION ?= -O3
ifeq ($(CONFIG_ARCH_CORTEXM4),y) ifeq ($(CONFIG_ARCH_CORTEXM4),y)
ifeq ($(CONFIG_ARCH_FPU),y) ifeq ($(CONFIG_ARCH_FPU),y)
ARCHCPUFLAGS = -mcpu=cortex-m4 -mthumb -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard ARCHCPUFLAGS = -mcpu=cortex-m4 -mthumb -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard

View File

@ -58,7 +58,7 @@ NM = $(CROSSDEV)nm
OBJCOPY = $(CROSSDEV)objcopy OBJCOPY = $(CROSSDEV)objcopy
OBJDUMP = $(CROSSDEV)objdump OBJDUMP = $(CROSSDEV)objdump
MAXOPTIMIZATION = -O3 MAXOPTIMIZATION ?= -O3
ARCHCPUFLAGS = -mcpu=cortex-m4 \ ARCHCPUFLAGS = -mcpu=cortex-m4 \
-mthumb \ -mthumb \
-march=armv7e-m \ -march=armv7e-m \

12
nuttx/configs/px4fmu/nsh/defconfig Executable file → Normal file
View File

@ -248,7 +248,7 @@ CONFIG_SERIAL_TERMIOS=y
CONFIG_SERIAL_CONSOLE_REINIT=y CONFIG_SERIAL_CONSOLE_REINIT=y
CONFIG_STANDARD_SERIAL=y CONFIG_STANDARD_SERIAL=y
CONFIG_USART1_SERIAL_CONSOLE=y CONFIG_USART1_SERIAL_CONSOLE=n
CONFIG_USART2_SERIAL_CONSOLE=n CONFIG_USART2_SERIAL_CONSOLE=n
CONFIG_USART3_SERIAL_CONSOLE=n CONFIG_USART3_SERIAL_CONSOLE=n
CONFIG_UART4_SERIAL_CONSOLE=n CONFIG_UART4_SERIAL_CONSOLE=n
@ -561,7 +561,7 @@ CONFIG_START_MONTH=1
CONFIG_START_DAY=1 CONFIG_START_DAY=1
CONFIG_GREGORIAN_TIME=n CONFIG_GREGORIAN_TIME=n
CONFIG_JULIAN_TIME=n CONFIG_JULIAN_TIME=n
CONFIG_DEV_CONSOLE=y CONFIG_DEV_CONSOLE=n
CONFIG_DEV_LOWCONSOLE=n CONFIG_DEV_LOWCONSOLE=n
CONFIG_MUTEX_TYPES=n CONFIG_MUTEX_TYPES=n
CONFIG_PRIORITY_INHERITANCE=y CONFIG_PRIORITY_INHERITANCE=y
@ -717,7 +717,7 @@ CONFIG_ARCH_BZERO=n
# zero for all dynamic allocations. # zero for all dynamic allocations.
# #
CONFIG_MAX_TASKS=32 CONFIG_MAX_TASKS=32
CONFIG_MAX_TASK_ARGS=8 CONFIG_MAX_TASK_ARGS=10
CONFIG_NPTHREAD_KEYS=4 CONFIG_NPTHREAD_KEYS=4
CONFIG_NFILE_DESCRIPTORS=32 CONFIG_NFILE_DESCRIPTORS=32
CONFIG_NFILE_STREAMS=25 CONFIG_NFILE_STREAMS=25
@ -925,7 +925,7 @@ CONFIG_USBDEV_TRACE_NRECORDS=512
# Size of the serial receive/transmit buffers. Default 256. # Size of the serial receive/transmit buffers. Default 256.
# #
CONFIG_CDCACM=y CONFIG_CDCACM=y
CONFIG_CDCACM_CONSOLE=n CONFIG_CDCACM_CONSOLE=y
#CONFIG_CDCACM_EP0MAXPACKET #CONFIG_CDCACM_EP0MAXPACKET
CONFIG_CDCACM_EPINTIN=1 CONFIG_CDCACM_EPINTIN=1
#CONFIG_CDCACM_EPINTIN_FSSIZE #CONFIG_CDCACM_EPINTIN_FSSIZE
@ -955,7 +955,7 @@ CONFIG_CDCACM_PRODUCTSTR="PX4 FMU v1.6"
# CONFIG_NSH_FILEIOSIZE - Size of a static I/O buffer # CONFIG_NSH_FILEIOSIZE - Size of a static I/O buffer
# CONFIG_NSH_STRERROR - Use strerror(errno) # CONFIG_NSH_STRERROR - Use strerror(errno)
# CONFIG_NSH_LINELEN - Maximum length of one command line # CONFIG_NSH_LINELEN - Maximum length of one command line
# CONFIG_NSH_MAX_ARGUMENTS - Maximum number of arguments for command line # CONFIG_NSH_MAXARGUMENTS - Maximum number of arguments for command line
# CONFIG_NSH_NESTDEPTH - Max number of nested if-then[-else]-fi # CONFIG_NSH_NESTDEPTH - Max number of nested if-then[-else]-fi
# CONFIG_NSH_DISABLESCRIPT - Disable scripting support # CONFIG_NSH_DISABLESCRIPT - Disable scripting support
# CONFIG_NSH_DISABLEBG - Disable background commands # CONFIG_NSH_DISABLEBG - Disable background commands
@ -988,7 +988,7 @@ CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512 CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_STRERROR=y CONFIG_NSH_STRERROR=y
CONFIG_NSH_LINELEN=128 CONFIG_NSH_LINELEN=128
CONFIG_NSH_MAX_ARGUMENTS=12 CONFIG_NSH_MAXARGUMENTS=12
CONFIG_NSH_NESTDEPTH=8 CONFIG_NSH_NESTDEPTH=8
CONFIG_NSH_DISABLESCRIPT=n CONFIG_NSH_DISABLESCRIPT=n
CONFIG_NSH_DISABLEBG=n CONFIG_NSH_DISABLEBG=n

View File

@ -58,7 +58,7 @@ NM = $(CROSSDEV)nm
OBJCOPY = $(CROSSDEV)objcopy OBJCOPY = $(CROSSDEV)objcopy
OBJDUMP = $(CROSSDEV)objdump OBJDUMP = $(CROSSDEV)objdump
MAXOPTIMIZATION = -O3 MAXOPTIMIZATION ?= -O3
ARCHCPUFLAGS = -mcpu=cortex-m3 \ ARCHCPUFLAGS = -mcpu=cortex-m3 \
-mthumb \ -mthumb \
-march=armv7-m -march=armv7-m

View File

@ -739,7 +739,7 @@ UBX::configure_message_rate(uint8_t msg_class, uint8_t msg_id, uint8_t rate)
msg.msg_class = msg_class; msg.msg_class = msg_class;
msg.msg_id = msg_id; msg.msg_id = msg_id;
msg.rate = rate; msg.rate = rate;
send_message(CFG, UBX_MESSAGE_CFG_MSG, &msg, sizeof(msg)); send_message(UBX_CLASS_CFG, UBX_MESSAGE_CFG_MSG, &msg, sizeof(msg));
} }
void void

View File

@ -329,7 +329,7 @@ HMC5883::HMC5883(int bus) :
_calibrated(false) _calibrated(false)
{ {
// enable debug() calls // enable debug() calls
_debug_enabled = true; _debug_enabled = false;
// default scaling // default scaling
_scale.x_offset = 0; _scale.x_offset = 0;

View File

@ -53,6 +53,7 @@
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#include <systemlib/err.h>
#include <systemlib/systemlib.h> #include <systemlib/systemlib.h>
#include "messages.h" #include "messages.h"
@ -60,56 +61,44 @@
static int thread_should_exit = false; /**< Deamon exit flag */ static int thread_should_exit = false; /**< Deamon exit flag */
static int thread_running = false; /**< Deamon status flag */ static int thread_running = false; /**< Deamon status flag */
static int deamon_task; /**< Handle of deamon task / thread */ static int deamon_task; /**< Handle of deamon task / thread */
static char *daemon_name = "hott_telemetry"; static const char daemon_name[] = "hott_telemetry";
static char *commandline_usage = "usage: hott_telemetry start|status|stop [-d <device>]"; static const char commandline_usage[] = "usage: hott_telemetry start|status|stop [-d <device>]";
/* A little console messaging experiment - console helper macro */
#define FATAL_MSG(_msg) fprintf(stderr, "[%s] %s\n", daemon_name, _msg); exit(1);
#define ERROR_MSG(_msg) fprintf(stderr, "[%s] %s\n", daemon_name, _msg);
#define INFO_MSG(_msg) printf("[%s] %s\n", daemon_name, _msg);
/** /**
* Deamon management function. * Deamon management function.
*/ */
__EXPORT int hott_telemetry_main(int argc, char *argv[]); __EXPORT int hott_telemetry_main(int argc, char *argv[]);
/** /**
* Mainloop of deamon. * Mainloop of daemon.
*/ */
int hott_telemetry_thread_main(int argc, char *argv[]); int hott_telemetry_thread_main(int argc, char *argv[]);
static int read_data(int uart, int *id); static int recv_req_id(int uart, uint8_t *id);
static int send_data(int uart, uint8_t *buffer, int size); static int send_data(int uart, uint8_t *buffer, size_t size);
static int open_uart(const char *device, struct termios *uart_config_original) static int
open_uart(const char *device, struct termios *uart_config_original)
{ {
/* baud rate */ /* baud rate */
int speed = B19200; static const speed_t speed = B19200;
int uart;
/* open uart */ /* open uart */
uart = open(device, O_RDWR | O_NOCTTY); const int uart = open(device, O_RDWR | O_NOCTTY);
if (uart < 0) { if (uart < 0) {
char msg[80]; err(1, "Error opening port: %s", device);
sprintf(msg, "Error opening port: %s\n", device);
FATAL_MSG(msg);
} }
/* Try to set baud rate */ /* Back up the original uart configuration to restore it after exit */
struct termios uart_config;
int termios_state; int termios_state;
/* Back up the original uart configuration to restore it after exit */
char msg[80];
if ((termios_state = tcgetattr(uart, uart_config_original)) < 0) { if ((termios_state = tcgetattr(uart, uart_config_original)) < 0) {
sprintf(msg, "Error getting baudrate / termios config for %s: %d\n", device, termios_state);
close(uart); close(uart);
FATAL_MSG(msg); err(1, "Error getting baudrate / termios config for %s: %d", device, termios_state);
} }
/* Fill the struct for the new configuration */ /* Fill the struct for the new configuration */
struct termios uart_config;
tcgetattr(uart, &uart_config); tcgetattr(uart, &uart_config);
/* Clear ONLCR flag (which appends a CR for every LF) */ /* Clear ONLCR flag (which appends a CR for every LF) */
@ -117,16 +106,14 @@ static int open_uart(const char *device, struct termios *uart_config_original)
/* Set baud rate */ /* Set baud rate */
if (cfsetispeed(&uart_config, speed) < 0 || cfsetospeed(&uart_config, speed) < 0) { if (cfsetispeed(&uart_config, speed) < 0 || cfsetospeed(&uart_config, speed) < 0) {
sprintf(msg, "Error setting baudrate / termios config for %s: %d (cfsetispeed, cfsetospeed)\n",
device, termios_state);
close(uart); close(uart);
FATAL_MSG(msg); err(1, "Error setting baudrate / termios config for %s: %d (cfsetispeed, cfsetospeed)",
device, termios_state);
} }
if ((termios_state = tcsetattr(uart, TCSANOW, &uart_config)) < 0) { if ((termios_state = tcsetattr(uart, TCSANOW, &uart_config)) < 0) {
sprintf(msg, "Error setting baudrate / termios config for %s (tcsetattr)\n", device);
close(uart); close(uart);
FATAL_MSG(msg); err(1, "Error setting baudrate / termios config for %s (tcsetattr)", device);
} }
/* Activate single wire mode */ /* Activate single wire mode */
@ -135,39 +122,41 @@ static int open_uart(const char *device, struct termios *uart_config_original)
return uart; return uart;
} }
int read_data(int uart, int *id) int
recv_req_id(int uart, uint8_t *id)
{ {
const int timeout = 1000; static const int timeout_ms = 1000; // TODO make it a define
struct pollfd fds[] = { { .fd = uart, .events = POLLIN } }; struct pollfd fds[] = { { .fd = uart, .events = POLLIN } };
char mode; uint8_t mode;
if (poll(fds, 1, timeout) > 0) { if (poll(fds, 1, timeout_ms) > 0) {
/* Get the mode: binary or text */ /* Get the mode: binary or text */
read(uart, &mode, 1); read(uart, &mode, sizeof(mode));
/* Read the device ID being polled */
read(uart, id, 1);
/* if we have a binary mode request */ /* if we have a binary mode request */
if (mode != BINARY_MODE_REQUEST_ID) { if (mode != BINARY_MODE_REQUEST_ID) {
return ERROR; return ERROR;
} }
/* Read the device ID being polled */
read(uart, id, sizeof(*id));
} else { } else {
ERROR_MSG("UART timeout on TX/RX port"); warnx("UART timeout on TX/RX port");
return ERROR; return ERROR;
} }
return OK; return OK;
} }
int send_data(int uart, uint8_t *buffer, int size) int
send_data(int uart, uint8_t *buffer, size_t size)
{ {
usleep(POST_READ_DELAY_IN_USECS); usleep(POST_READ_DELAY_IN_USECS);
uint16_t checksum = 0; uint16_t checksum = 0;
for (int i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (i == size - 1) { if (i == size - 1) {
/* Set the checksum: the first uint8_t is taken as the checksum. */ /* Set the checksum: the first uint8_t is taken as the checksum. */
buffer[i] = checksum & 0xff; buffer[i] = checksum & 0xff;
@ -176,7 +165,7 @@ int send_data(int uart, uint8_t *buffer, int size)
checksum += buffer[i]; checksum += buffer[i];
} }
write(uart, &buffer[i], 1); write(uart, &buffer[i], sizeof(buffer[i]));
/* Sleep before sending the next byte. */ /* Sleep before sending the next byte. */
usleep(POST_WRITE_DELAY_IN_USECS); usleep(POST_WRITE_DELAY_IN_USECS);
@ -190,13 +179,14 @@ int send_data(int uart, uint8_t *buffer, int size)
return OK; return OK;
} }
int hott_telemetry_thread_main(int argc, char *argv[]) int
hott_telemetry_thread_main(int argc, char *argv[])
{ {
INFO_MSG("starting"); warnx("starting");
thread_running = true; thread_running = true;
char *device = "/dev/ttyS1"; /**< Default telemetry port: USART2 */ const char *device = "/dev/ttyS1"; /**< Default telemetry port: USART2 */
/* read commandline arguments */ /* read commandline arguments */
for (int i = 0; i < argc && argv[i]; i++) { for (int i = 0; i < argc && argv[i]; i++) {
@ -206,45 +196,55 @@ int hott_telemetry_thread_main(int argc, char *argv[])
} else { } else {
thread_running = false; thread_running = false;
ERROR_MSG("missing parameter to -d"); errx(1, "missing parameter to -d\n%s", commandline_usage);
ERROR_MSG(commandline_usage);
exit(1);
} }
} }
} }
/* enable UART, writes potentially an empty buffer, but multiplexing is disabled */ /* enable UART, writes potentially an empty buffer, but multiplexing is disabled */
struct termios uart_config_original; struct termios uart_config_original;
int uart = open_uart(device, &uart_config_original); const int uart = open_uart(device, &uart_config_original);
if (uart < 0) { if (uart < 0) {
ERROR_MSG("Failed opening HoTT UART, exiting."); errx(1, "Failed opening HoTT UART, exiting.");
thread_running = false; thread_running = false;
exit(ERROR);
} }
messages_init(); messages_init();
uint8_t buffer[MESSAGE_BUFFER_SIZE]; uint8_t buffer[MESSAGE_BUFFER_SIZE];
int size = 0; size_t size = 0;
int id = 0; uint8_t id = 0;
bool connected = true;
while (!thread_should_exit) { while (!thread_should_exit) {
if (read_data(uart, &id) == OK) { if (recv_req_id(uart, &id) == OK) {
if (!connected) {
connected = true;
warnx("OK");
}
switch (id) { switch (id) {
case ELECTRIC_AIR_MODULE: case EAM_SENSOR_ID:
build_eam_response(buffer, &size); build_eam_response(buffer, &size);
break; break;
case GPS_SENSOR_ID:
build_gps_response(buffer, &size);
break;
default: default:
continue; // Not a module we support. continue; // Not a module we support.
} }
send_data(uart, buffer, size); send_data(uart, buffer, size);
} else {
connected = false;
warnx("syncing");
} }
} }
INFO_MSG("exiting"); warnx("exiting");
close(uart); close(uart);
@ -256,23 +256,22 @@ int hott_telemetry_thread_main(int argc, char *argv[])
/** /**
* Process command line arguments and tart the daemon. * Process command line arguments and tart the daemon.
*/ */
int hott_telemetry_main(int argc, char *argv[]) int
hott_telemetry_main(int argc, char *argv[])
{ {
if (argc < 1) { if (argc < 1) {
ERROR_MSG("missing command"); errx(1, "missing command\n%s", commandline_usage);
ERROR_MSG(commandline_usage);
exit(1);
} }
if (!strcmp(argv[1], "start")) { if (!strcmp(argv[1], "start")) {
if (thread_running) { if (thread_running) {
INFO_MSG("deamon already running"); warnx("deamon already running");
exit(0); exit(0);
} }
thread_should_exit = false; thread_should_exit = false;
deamon_task = task_spawn("hott_telemetry", deamon_task = task_spawn(daemon_name,
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 40, SCHED_PRIORITY_MAX - 40,
2048, 2048,
@ -288,19 +287,14 @@ int hott_telemetry_main(int argc, char *argv[])
if (!strcmp(argv[1], "status")) { if (!strcmp(argv[1], "status")) {
if (thread_running) { if (thread_running) {
INFO_MSG("daemon is running"); warnx("daemon is running");
} else { } else {
INFO_MSG("daemon not started"); warnx("daemon not started");
} }
exit(0); exit(0);
} }
ERROR_MSG("unrecognized command"); errx(1, "unrecognized command\n%s", commandline_usage);
ERROR_MSG(commandline_usage);
exit(1);
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* *
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved. * Copyright (C) 2012 PX4 Development Team. All rights reserved.
* Author: Simon Wilks <sjwilks@gmail.com> * Author: @author Simon Wilks <sjwilks@gmail.com>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -34,30 +34,44 @@
/** /**
* @file messages.c * @file messages.c
* @author Simon Wilks <sjwilks@gmail.com> *
*/ */
#include "messages.h" #include "messages.h"
#include <math.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <systemlib/systemlib.h> #include <systemlib/geo/geo.h>
#include <unistd.h> #include <unistd.h>
#include <uORB/topics/airspeed.h>
#include <uORB/topics/battery_status.h> #include <uORB/topics/battery_status.h>
#include <uORB/topics/home_position.h>
#include <uORB/topics/sensor_combined.h> #include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_gps_position.h>
/* The board is very roughly 5 deg warmer than the surrounding air */
#define BOARD_TEMP_OFFSET_DEG 5
static int airspeed_sub = -1;
static int battery_sub = -1; static int battery_sub = -1;
static int gps_sub = -1;
static int home_sub = -1;
static int sensor_sub = -1; static int sensor_sub = -1;
void messages_init(void) static bool home_position_set = false;
static double home_lat = 0.0d;
static double home_lon = 0.0d;
void
messages_init(void)
{ {
battery_sub = orb_subscribe(ORB_ID(battery_status)); battery_sub = orb_subscribe(ORB_ID(battery_status));
gps_sub = orb_subscribe(ORB_ID(vehicle_gps_position));
home_sub = orb_subscribe(ORB_ID(home_position));
sensor_sub = orb_subscribe(ORB_ID(sensor_combined)); sensor_sub = orb_subscribe(ORB_ID(sensor_combined));
airspeed_sub = orb_subscribe(ORB_ID(airspeed));
} }
void build_eam_response(uint8_t *buffer, int *size) void
build_eam_response(uint8_t *buffer, size_t *size)
{ {
/* get a local copy of the current sensor values */ /* get a local copy of the current sensor values */
struct sensor_combined_s raw; struct sensor_combined_s raw;
@ -74,26 +88,144 @@ void build_eam_response(uint8_t *buffer, int *size)
memset(&msg, 0, *size); memset(&msg, 0, *size);
msg.start = START_BYTE; msg.start = START_BYTE;
msg.eam_sensor_id = ELECTRIC_AIR_MODULE; msg.eam_sensor_id = EAM_SENSOR_ID;
msg.sensor_id = EAM_SENSOR_ID; msg.sensor_id = EAM_SENSOR_TEXT_ID;
msg.temperature1 = (uint8_t)(raw.baro_temp_celcius + 20); msg.temperature1 = (uint8_t)(raw.baro_temp_celcius + 20);
msg.temperature2 = TEMP_ZERO_CELSIUS; msg.temperature2 = msg.temperature1 - BOARD_TEMP_OFFSET_DEG;
msg.main_voltage_L = (uint8_t)(battery.voltage_v * 10); msg.main_voltage_L = (uint8_t)(battery.voltage_v * 10);
uint16_t alt = (uint16_t)(raw.baro_alt_meter + 500); uint16_t alt = (uint16_t)(raw.baro_alt_meter + 500);
msg.altitude_L = (uint8_t)alt & 0xff; msg.altitude_L = (uint8_t)alt & 0xff;
msg.altitude_H = (uint8_t)(alt >> 8) & 0xff; msg.altitude_H = (uint8_t)(alt >> 8) & 0xff;
/* get a local copy of the current sensor values */ msg.stop = STOP_BYTE;
struct airspeed_s airspeed; memcpy(buffer, &msg, *size);
memset(&airspeed, 0, sizeof(airspeed)); }
orb_copy(ORB_ID(airspeed), airspeed_sub, &airspeed);
uint16_t speed = (uint16_t)(airspeed.indicated_airspeed_m_s * 3.6); void
msg.speed_L = (uint8_t)speed & 0xff; build_gps_response(uint8_t *buffer, size_t *size)
msg.speed_H = (uint8_t)(speed >> 8) & 0xff; {
/* get a local copy of the current sensor values */
struct sensor_combined_s raw;
memset(&raw, 0, sizeof(raw));
orb_copy(ORB_ID(sensor_combined), sensor_sub, &raw);
/* get a local copy of the battery data */
struct vehicle_gps_position_s gps;
memset(&gps, 0, sizeof(gps));
orb_copy(ORB_ID(vehicle_gps_position), gps_sub, &gps);
struct gps_module_msg msg = { 0 };
*size = sizeof(msg);
memset(&msg, 0, *size);
msg.start = START_BYTE;
msg.sensor_id = GPS_SENSOR_ID;
msg.sensor_text_id = GPS_SENSOR_TEXT_ID;
msg.gps_num_sat = gps.satellites_visible;
/* The GPS fix type: 0 = none, 2 = 2D, 3 = 3D */
msg.gps_fix_char = (uint8_t)(gps.fix_type + 48);
msg.gps_fix = (uint8_t)(gps.fix_type + 48);
/* No point collecting more data if we don't have a 3D fix yet */
if (gps.fix_type > 2) {
/* Current flight direction */
msg.flight_direction = (uint8_t)(gps.cog_rad * M_RAD_TO_DEG_F);
/* GPS speed */
uint16_t speed = (uint16_t)(gps.vel_m_s * 3.6);
msg.gps_speed_L = (uint8_t)speed & 0xff;
msg.gps_speed_H = (uint8_t)(speed >> 8) & 0xff;
/* Get latitude in degrees, minutes and seconds */
double lat = ((double)(gps.lat))*1e-7d;
/* Set the N or S specifier */
msg.latitude_ns = 0;
if (lat < 0) {
msg.latitude_ns = 1;
lat = abs(lat);
}
int deg;
int min;
int sec;
convert_to_degrees_minutes_seconds(lat, &deg, &min, &sec);
uint16_t lat_min = (uint16_t)(deg * 100 + min);
msg.latitude_min_L = (uint8_t)lat_min & 0xff;
msg.latitude_min_H = (uint8_t)(lat_min >> 8) & 0xff;
uint16_t lat_sec = (uint16_t)(sec);
msg.latitude_sec_L = (uint8_t)lat_sec & 0xff;
msg.latitude_sec_H = (uint8_t)(lat_sec >> 8) & 0xff;
/* Get longitude in degrees, minutes and seconds */
double lon = ((double)(gps.lon))*1e-7d;
/* Set the E or W specifier */
msg.longitude_ew = 0;
if (lon < 0) {
msg.longitude_ew = 1;
lon = abs(lon);
}
convert_to_degrees_minutes_seconds(lon, &deg, &min, &sec);
uint16_t lon_min = (uint16_t)(deg * 100 + min);
msg.longitude_min_L = (uint8_t)lon_min & 0xff;
msg.longitude_min_H = (uint8_t)(lon_min >> 8) & 0xff;
uint16_t lon_sec = (uint16_t)(sec);
msg.longitude_sec_L = (uint8_t)lon_sec & 0xff;
msg.longitude_sec_H = (uint8_t)(lon_sec >> 8) & 0xff;
/* Altitude */
uint16_t alt = (uint16_t)(gps.alt*1e-3 + 500.0f);
msg.altitude_L = (uint8_t)alt & 0xff;
msg.altitude_H = (uint8_t)(alt >> 8) & 0xff;
/* Get any (and probably only ever one) home_sub postion report */
bool updated;
orb_check(home_sub, &updated);
if (updated) {
/* get a local copy of the home position data */
struct home_position_s home;
memset(&home, 0, sizeof(home));
orb_copy(ORB_ID(home_position), home_sub, &home);
home_lat = ((double)(home.lat))*1e-7d;
home_lon = ((double)(home.lon))*1e-7d;
home_position_set = true;
}
/* Distance from home */
if (home_position_set) {
uint16_t dist = (uint16_t)get_distance_to_next_waypoint(home_lat, home_lon, lat, lon);
msg.distance_L = (uint8_t)dist & 0xff;
msg.distance_H = (uint8_t)(dist >> 8) & 0xff;
/* Direction back to home */
uint16_t bearing = (uint16_t)(get_bearing_to_next_waypoint(home_lat, home_lon, lat, lon) * M_RAD_TO_DEG_F);
msg.home_direction = (uint8_t)bearing >> 1;
}
}
msg.stop = STOP_BYTE; msg.stop = STOP_BYTE;
memcpy(buffer, &msg, *size); memcpy(buffer, &msg, *size);
} }
void
convert_to_degrees_minutes_seconds(double val, int *deg, int *min, int *sec)
{
*deg = (int)val;
double delta = val - *deg;
const double min_d = delta * 60.0d;
*min = (int)min_d;
delta = min_d - *min;
*sec = (int)(delta * 10000.0d);
}

View File

@ -44,11 +44,6 @@
#include <stdlib.h> #include <stdlib.h>
/* The buffer size used to store messages. This must be at least as big as the number of
* fields in the largest message struct.
*/
#define MESSAGE_BUFFER_SIZE 50
/* The HoTT receiver demands a minimum 5ms period of silence after delivering its request. /* The HoTT receiver demands a minimum 5ms period of silence after delivering its request.
* Note that the value specified here is lower than 5000 (5ms) as time is lost constucting * Note that the value specified here is lower than 5000 (5ms) as time is lost constucting
* the message after the read which takes some milliseconds. * the message after the read which takes some milliseconds.
@ -66,18 +61,18 @@
#define TEMP_ZERO_CELSIUS 0x14 #define TEMP_ZERO_CELSIUS 0x14
/* Electric Air Module (EAM) constants. */ /* Electric Air Module (EAM) constants. */
#define ELECTRIC_AIR_MODULE 0x8e #define EAM_SENSOR_ID 0x8e
#define EAM_SENSOR_ID 0xe0 #define EAM_SENSOR_TEXT_ID 0xe0
/* The Electric Air Module message. */ /* The Electric Air Module message. */
struct eam_module_msg { struct eam_module_msg {
uint8_t start; /**< Start byte */ uint8_t start; /**< Start byte */
uint8_t eam_sensor_id; /**< EAM sensor ID */ uint8_t eam_sensor_id; /**< EAM sensor */
uint8_t warning; uint8_t warning;
uint8_t sensor_id; /**< Sensor ID, why different? */ uint8_t sensor_id; /**< Sensor ID, why different? */
uint8_t alarm_inverse1; uint8_t alarm_inverse1;
uint8_t alarm_inverse2; uint8_t alarm_inverse2;
uint8_t cell1_L; /**< Lipo cell voltages. Not supported. */ uint8_t cell1_L; /**< Lipo cell voltages. Not supported. */
uint8_t cell2_L; uint8_t cell2_L;
uint8_t cell3_L; uint8_t cell3_L;
uint8_t cell4_L; uint8_t cell4_L;
@ -95,30 +90,107 @@ struct eam_module_msg {
uint8_t batt1_voltage_H; uint8_t batt1_voltage_H;
uint8_t batt2_voltage_L; /**< Battery 2 voltage, lower 8-bits in steps of 0.02V */ uint8_t batt2_voltage_L; /**< Battery 2 voltage, lower 8-bits in steps of 0.02V */
uint8_t batt2_voltage_H; uint8_t batt2_voltage_H;
uint8_t temperature1; /**< Temperature sensor 1. 20 = 0 degrees */ uint8_t temperature1; /**< Temperature sensor 1. 20 = 0 degrees */
uint8_t temperature2; uint8_t temperature2;
uint8_t altitude_L; /**< Attitude (meters) lower 8-bits. 500 = 0 meters */ uint8_t altitude_L; /**< Attitude (meters) lower 8-bits. 500 = 0 meters */
uint8_t altitude_H; uint8_t altitude_H;
uint8_t current_L; /**< Current (mAh) lower 8-bits in steps of 0.1V */ uint8_t current_L; /**< Current (mAh) lower 8-bits in steps of 0.1V */
uint8_t current_H; uint8_t current_H;
uint8_t main_voltage_L; /**< Main power voltage lower 8-bits in steps of 0.1V */ uint8_t main_voltage_L; /**< Main power voltage lower 8-bits in steps of 0.1V */
uint8_t main_voltage_H; uint8_t main_voltage_H;
uint8_t battery_capacity_L; /**< Used battery capacity in steps of 10mAh */ uint8_t battery_capacity_L; /**< Used battery capacity in steps of 10mAh */
uint8_t battery_capacity_H; uint8_t battery_capacity_H;
uint8_t climbrate_L; /**< Climb rate in 0.01m/s. 0m/s = 30000 */ uint8_t climbrate_L; /**< Climb rate in 0.01m/s. 0m/s = 30000 */
uint8_t climbrate_H; uint8_t climbrate_H;
uint8_t climbrate_3s; /**< Climb rate in m/3sec. 0m/3sec = 120 */ uint8_t climbrate_3s; /**< Climb rate in m/3sec. 0m/3sec = 120 */
uint8_t rpm_L; /**< RPM Lower 8-bits In steps of 10 U/min */ uint8_t rpm_L; /**< RPM Lower 8-bits In steps of 10 U/min */
uint8_t rpm_H; uint8_t rpm_H;
uint8_t electric_min; /**< Flight time in minutes. */ uint8_t electric_min; /**< Flight time in minutes. */
uint8_t electric_sec; /**< Flight time in seconds. */ uint8_t electric_sec; /**< Flight time in seconds. */
uint8_t speed_L; /**< Airspeed in km/h in steps of 1 km/h */ uint8_t speed_L; /**< Airspeed in km/h in steps of 1 km/h */
uint8_t speed_H; uint8_t speed_H;
uint8_t stop; /**< Stop byte */ uint8_t stop; /**< Stop byte */
uint8_t checksum; /**< Lower 8-bits of all bytes summed. */ uint8_t checksum; /**< Lower 8-bits of all bytes summed. */
}; };
/**
* The maximum buffer size required to store a HoTT message.
*/
#define MESSAGE_BUFFER_SIZE sizeof(union { \
struct eam_module_msg eam; \
})
/* GPS sensor constants. */
#define GPS_SENSOR_ID 0x8A
#define GPS_SENSOR_TEXT_ID 0xA0
/**
* The GPS sensor message
* Struct based on: https://code.google.com/p/diy-hott-gps/downloads
*/
struct gps_module_msg {
uint8_t start; /**< Start byte */
uint8_t sensor_id; /**< GPS sensor ID*/
uint8_t warning; /**< Byte 3: 0…= warning beeps */
uint8_t sensor_text_id; /**< GPS Sensor text mode ID */
uint8_t alarm_inverse1; /**< Byte 5: 01 inverse status */
uint8_t alarm_inverse2; /**< Byte 6: 00 inverse status status 1 = no GPS Signal */
uint8_t flight_direction; /**< Byte 7: 119 = Flightdir./dir. 1 = 2°; 0° (North), 9 0° (East), 180° (South), 270° (West) */
uint8_t gps_speed_L; /**< Byte 8: 8 = /GPS speed low byte 8km/h */
uint8_t gps_speed_H; /**< Byte 9: 0 = /GPS speed high byte */
uint8_t latitude_ns; /**< Byte 10: 000 = N = 48°39988 */
uint8_t latitude_min_L; /**< Byte 11: 231 0xE7 = 0x12E7 = 4839 */
uint8_t latitude_min_H; /**< Byte 12: 018 18 = 0x12 */
uint8_t latitude_sec_L; /**< Byte 13: 171 220 = 0xDC = 0x03DC =0988 */
uint8_t latitude_sec_H; /**< Byte 14: 016 3 = 0x03 */
uint8_t longitude_ew; /**< Byte 15: 000 = E= 9° 259360 */
uint8_t longitude_min_L; /**< Byte 16: 150 157 = 0x9D = 0x039D = 0925 */
uint8_t longitude_min_H; /**< Byte 17: 003 3 = 0x03 */
uint8_t longitude_sec_L; /**< Byte 18: 056 144 = 0x90 0x2490 = 9360*/
uint8_t longitude_sec_H; /**< Byte 19: 004 36 = 0x24 */
uint8_t distance_L; /**< Byte 20: 027 123 = /distance low byte 6 = 6 m */
uint8_t distance_H; /**< Byte 21: 036 35 = /distance high byte */
uint8_t altitude_L; /**< Byte 22: 243 244 = /Altitude low byte 500 = 0m */
uint8_t altitude_H; /**< Byte 23: 001 1 = /Altitude high byte */
uint8_t resolution_L; /**< Byte 24: 48 = Low Byte m/s resolution 0.01m 48 = 30000 = 0.00m/s (1=0.01m/s) */
uint8_t resolution_H; /**< Byte 25: 117 = High Byte m/s resolution 0.01m */
uint8_t unknown1; /**< Byte 26: 120 = 0m/3s */
uint8_t gps_num_sat; /**< Byte 27: GPS.Satellites (number of satelites) (1 byte) */
uint8_t gps_fix_char; /**< Byte 28: GPS.FixChar. (GPS fix character. display, if DGPS, 2D oder 3D) (1 byte) */
uint8_t home_direction; /**< Byte 29: HomeDirection (direction from starting point to Model position) (1 byte) */
uint8_t angle_x_direction; /**< Byte 30: angle x-direction (1 byte) */
uint8_t angle_y_direction; /**< Byte 31: angle y-direction (1 byte) */
uint8_t angle_z_direction; /**< Byte 32: angle z-direction (1 byte) */
uint8_t gyro_x_L; /**< Byte 33: gyro x low byte (2 bytes) */
uint8_t gyro_x_H; /**< Byte 34: gyro x high byte */
uint8_t gyro_y_L; /**< Byte 35: gyro y low byte (2 bytes) */
uint8_t gyro_y_H; /**< Byte 36: gyro y high byte */
uint8_t gyro_z_L; /**< Byte 37: gyro z low byte (2 bytes) */
uint8_t gyro_z_H; /**< Byte 38: gyro z high byte */
uint8_t vibration; /**< Byte 39: vibration (1 bytes) */
uint8_t ascii4; /**< Byte 40: 00 ASCII Free Character [4] */
uint8_t ascii5; /**< Byte 41: 00 ASCII Free Character [5] */
uint8_t gps_fix; /**< Byte 42: 00 ASCII Free Character [6], we use it for GPS FIX */
uint8_t version; /**< Byte 43: 00 version number */
uint8_t stop; /**< Byte 44: 0x7D Ende byte */
uint8_t checksum; /**< Byte 45: Parity Byte */
};
/**
* The maximum buffer size required to store a HoTT message.
*/
#define GPS_MESSAGE_BUFFER_SIZE sizeof(union { \
struct gps_module_msg gps; \
})
void messages_init(void); void messages_init(void);
void build_eam_response(uint8_t *buffer, int *size); void build_eam_response(uint8_t *buffer, size_t *size);
void build_gps_response(uint8_t *buffer, size_t *size);
float _get_distance_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next);
void convert_to_degrees_minutes_seconds(double lat, int *deg, int *min, int *sec);
#endif /* MESSAGES_H_ */ #endif /* MESSAGES_H_ */

View File

@ -76,7 +76,6 @@
#include <uORB/topics/actuator_outputs.h> #include <uORB/topics/actuator_outputs.h>
#include <systemlib/err.h> #include <systemlib/err.h>
#include <systemlib/ppm_decode.h>
#define I2C_BUS_SPEED 400000 #define I2C_BUS_SPEED 400000
#define UPDATE_RATE 400 #define UPDATE_RATE 400
@ -114,6 +113,7 @@ public:
virtual int ioctl(file *filp, int cmd, unsigned long arg); virtual int ioctl(file *filp, int cmd, unsigned long arg);
virtual int init(unsigned motors); virtual int init(unsigned motors);
virtual ssize_t write(file *filp, const char *buffer, size_t len);
int set_mode(Mode mode); int set_mode(Mode mode);
int set_pwm_rate(unsigned rate); int set_pwm_rate(unsigned rate);
@ -177,9 +177,10 @@ private:
int gpio_ioctl(file *filp, int cmd, unsigned long arg); int gpio_ioctl(file *filp, int cmd, unsigned long arg);
int mk_servo_arm(bool status); int mk_servo_arm(bool status);
int mk_servo_set(unsigned int chan, float val); int mk_servo_set(unsigned int chan, short val);
int mk_servo_set_test(unsigned int chan, float val); int mk_servo_set_value(unsigned int chan, short val);
int mk_servo_test(unsigned int chan); int mk_servo_test(unsigned int chan);
short scaling(float val, float inMin, float inMax, float outMin, float outMax);
}; };
@ -207,20 +208,20 @@ const int blctrlAddr_octo_x[] = { 1, 4, 0, 1, -4, 1, 1, -4 }; // Addresstranslat
const int blctrlAddr_px4[] = { 0, 0, 0, 0, 0, 0, 0, 0}; const int blctrlAddr_px4[] = { 0, 0, 0, 0, 0, 0, 0, 0};
int addrTranslator[] = {0,0,0,0,0,0,0,0}; int addrTranslator[] = {0, 0, 0, 0, 0, 0, 0, 0};
struct MotorData_t struct MotorData_t {
{
unsigned int Version; // the version of the BL (0 = old) unsigned int Version; // the version of the BL (0 = old)
unsigned int SetPoint; // written by attitude controller unsigned int SetPoint; // written by attitude controller
unsigned int SetPointLowerBits; // for higher Resolution of new BLs unsigned int SetPointLowerBits; // for higher Resolution of new BLs
unsigned int State; // 7 bit for I2C error counter, highest bit indicates if motor is present unsigned int State; // 7 bit for I2C error counter, highest bit indicates if motor is present
unsigned int ReadMode; // select data to read unsigned int ReadMode; // select data to read
// the following bytes must be exactly in that order! unsigned short RawPwmValue; // length of PWM pulse
unsigned int Current; // in 0.1 A steps, read back from BL // the following bytes must be exactly in that order!
unsigned int MaxPWM; // read back from BL is less than 255 if BL is in current limit unsigned int Current; // in 0.1 A steps, read back from BL
unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in unsigned int MaxPWM; // read back from BL is less than 255 if BL is in current limit
unsigned int RoundCount; unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in
unsigned int RoundCount;
}; };
MotorData_t Motor[MAX_MOTORS]; MotorData_t Motor[MAX_MOTORS];
@ -314,7 +315,7 @@ MK::init(unsigned motors)
/* start the IO interface task */ /* start the IO interface task */
_task = task_spawn("mkblctrl", _task = task_spawn("mkblctrl",
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_MAX -20, SCHED_PRIORITY_MAX - 20,
2048, 2048,
(main_t)&MK::task_main_trampoline, (main_t)&MK::task_main_trampoline,
nullptr); nullptr);
@ -346,27 +347,11 @@ MK::set_mode(Mode mode)
*/ */
switch (mode) { switch (mode) {
case MODE_2PWM: case MODE_2PWM:
if(_num_outputs == 4) {
//debug("MODE_QUAD");
} else if(_num_outputs == 6) {
//debug("MODE_HEXA");
} else if(_num_outputs == 8) {
//debug("MODE_OCTO");
}
//up_pwm_servo_init(0x3);
up_pwm_servo_deinit(); up_pwm_servo_deinit();
_update_rate = UPDATE_RATE; /* default output rate */ _update_rate = UPDATE_RATE; /* default output rate */
break; break;
case MODE_4PWM: case MODE_4PWM:
if(_num_outputs == 4) {
//debug("MODE_QUADRO");
} else if(_num_outputs == 6) {
//debug("MODE_HEXA");
} else if(_num_outputs == 8) {
//debug("MODE_OCTO");
}
//up_pwm_servo_init(0xf);
up_pwm_servo_deinit(); up_pwm_servo_deinit();
_update_rate = UPDATE_RATE; /* default output rate */ _update_rate = UPDATE_RATE; /* default output rate */
break; break;
@ -412,45 +397,55 @@ MK::set_frametype(int frametype)
int int
MK::set_motor_count(unsigned count) MK::set_motor_count(unsigned count)
{ {
if(count > 0) { if (count > 0) {
_num_outputs = count; _num_outputs = count;
if(_px4mode == MAPPING_MK) { if (_px4mode == MAPPING_MK) {
if(_frametype == FRAME_PLUS) { if (_frametype == FRAME_PLUS) {
fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: +\n"); fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: +\n");
} else if(_frametype == FRAME_X) {
} else if (_frametype == FRAME_X) {
fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: X\n"); fprintf(stderr, "[mkblctrl] addresstanslator for Mikrokopter addressing used. Frametype: X\n");
} }
if(_num_outputs == 4) {
if(_frametype == FRAME_PLUS) { if (_num_outputs == 4) {
if (_frametype == FRAME_PLUS) {
memcpy(&addrTranslator, &blctrlAddr_quad_plus, sizeof(blctrlAddr_quad_plus)); memcpy(&addrTranslator, &blctrlAddr_quad_plus, sizeof(blctrlAddr_quad_plus));
} else if(_frametype == FRAME_X) {
} else if (_frametype == FRAME_X) {
memcpy(&addrTranslator, &blctrlAddr_quad_x, sizeof(blctrlAddr_quad_x)); memcpy(&addrTranslator, &blctrlAddr_quad_x, sizeof(blctrlAddr_quad_x));
} }
} else if(_num_outputs == 6) {
if(_frametype == FRAME_PLUS) { } else if (_num_outputs == 6) {
if (_frametype == FRAME_PLUS) {
memcpy(&addrTranslator, &blctrlAddr_hexa_plus, sizeof(blctrlAddr_hexa_plus)); memcpy(&addrTranslator, &blctrlAddr_hexa_plus, sizeof(blctrlAddr_hexa_plus));
} else if(_frametype == FRAME_X) {
} else if (_frametype == FRAME_X) {
memcpy(&addrTranslator, &blctrlAddr_hexa_x, sizeof(blctrlAddr_hexa_x)); memcpy(&addrTranslator, &blctrlAddr_hexa_x, sizeof(blctrlAddr_hexa_x));
} }
} else if(_num_outputs == 8) {
if(_frametype == FRAME_PLUS) { } else if (_num_outputs == 8) {
if (_frametype == FRAME_PLUS) {
memcpy(&addrTranslator, &blctrlAddr_octo_plus, sizeof(blctrlAddr_octo_plus)); memcpy(&addrTranslator, &blctrlAddr_octo_plus, sizeof(blctrlAddr_octo_plus));
} else if(_frametype == FRAME_X) {
} else if (_frametype == FRAME_X) {
memcpy(&addrTranslator, &blctrlAddr_octo_x, sizeof(blctrlAddr_octo_x)); memcpy(&addrTranslator, &blctrlAddr_octo_x, sizeof(blctrlAddr_octo_x));
} }
} }
} else { } else {
fprintf(stderr, "[mkblctrl] PX4 native addressing used.\n"); fprintf(stderr, "[mkblctrl] PX4 native addressing used.\n");
memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4)); memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4));
} }
if(_num_outputs == 4) { if (_num_outputs == 4) {
fprintf(stderr, "[mkblctrl] Quadrocopter Mode (4)\n"); fprintf(stderr, "[mkblctrl] Quadrocopter Mode (4)\n");
} else if(_num_outputs == 6) {
} else if (_num_outputs == 6) {
fprintf(stderr, "[mkblctrl] Hexacopter Mode (6)\n"); fprintf(stderr, "[mkblctrl] Hexacopter Mode (6)\n");
} else if(_num_outputs == 8) {
} else if (_num_outputs == 8) {
fprintf(stderr, "[mkblctrl] Octocopter Mode (8)\n"); fprintf(stderr, "[mkblctrl] Octocopter Mode (8)\n");
} }
@ -469,16 +464,35 @@ MK::set_motor_test(bool motortest)
return OK; return OK;
} }
short
MK::scaling(float val, float inMin, float inMax, float outMin, float outMax)
{
short retVal = 0;
retVal = (val - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
if (retVal < outMin) {
retVal = outMin;
} else if (retVal > outMax) {
retVal = outMax;
}
return retVal;
}
void void
MK::task_main() MK::task_main()
{ {
long update_rate_in_us = 0;
float tmpVal = 0;
/* /*
* Subscribe to the appropriate PWM output topic based on whether we are the * Subscribe to the appropriate PWM output topic based on whether we are the
* primary PWM output or not. * primary PWM output or not.
*/ */
_t_actuators = orb_subscribe(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS : _t_actuators = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
ORB_ID(actuator_controls_1));
/* force a reset of the update rate */ /* force a reset of the update rate */
_current_update_rate = 0; _current_update_rate = 0;
@ -492,6 +506,8 @@ MK::task_main()
_t_outputs = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_CONTROLS : ORB_ID(actuator_outputs_1), _t_outputs = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_CONTROLS : ORB_ID(actuator_outputs_1),
&outputs); &outputs);
/* advertise the effective control inputs */ /* advertise the effective control inputs */
actuator_controls_effective_s controls_effective; actuator_controls_effective_s controls_effective;
memset(&controls_effective, 0, sizeof(controls_effective)); memset(&controls_effective, 0, sizeof(controls_effective));
@ -499,21 +515,14 @@ MK::task_main()
_t_actuators_effective = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS_EFFECTIVE : ORB_ID(actuator_controls_effective_1), _t_actuators_effective = orb_advertise(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS_EFFECTIVE : ORB_ID(actuator_controls_effective_1),
&controls_effective); &controls_effective);
pollfd fds[2]; pollfd fds[2];
fds[0].fd = _t_actuators; fds[0].fd = _t_actuators;
fds[0].events = POLLIN; fds[0].events = POLLIN;
fds[1].fd = _t_armed; fds[1].fd = _t_armed;
fds[1].events = POLLIN; fds[1].events = POLLIN;
// rc input, published to ORB
struct rc_input_values rc_in;
orb_advert_t to_input_rc = 0;
memset(&rc_in, 0, sizeof(rc_in));
rc_in.input_source = RC_INPUT_SOURCE_PX4FMU_PPM;
log("starting"); log("starting");
long update_rate_in_us = 0;
/* loop until killed */ /* loop until killed */
while (!_task_should_exit) { while (!_task_should_exit) {
@ -528,6 +537,7 @@ MK::task_main()
update_rate_in_ms = 2; update_rate_in_ms = 2;
_update_rate = 500; _update_rate = 500;
} }
/* reject slower than 50 Hz updates */ /* reject slower than 50 Hz updates */
if (update_rate_in_ms > 20) { if (update_rate_in_ms > 20) {
update_rate_in_ms = 20; update_rate_in_ms = 20;
@ -539,8 +549,8 @@ MK::task_main()
_current_update_rate = _update_rate; _current_update_rate = _update_rate;
} }
/* sleep waiting for data, but no more than a second */ /* sleep waiting for data max 100ms */
int ret = ::poll(&fds[0], 2, 1000); int ret = ::poll(&fds[0], 2, 100);
/* this would be bad... */ /* this would be bad... */
if (ret < 0) { if (ret < 0) {
@ -553,7 +563,7 @@ MK::task_main()
if (fds[0].revents & POLLIN) { if (fds[0].revents & POLLIN) {
/* get controls - must always do this to avoid spinning */ /* get controls - must always do this to avoid spinning */
orb_copy(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS : ORB_ID(actuator_controls_1), _t_actuators, &_controls); orb_copy(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, _t_actuators, &_controls);
/* can we mix? */ /* can we mix? */
if (_mixers != nullptr) { if (_mixers != nullptr) {
@ -565,53 +575,52 @@ MK::task_main()
// XXX output actual limited values // XXX output actual limited values
memcpy(&controls_effective, &_controls, sizeof(controls_effective)); memcpy(&controls_effective, &_controls, sizeof(controls_effective));
orb_publish(_primary_pwm_device ? ORB_ID_VEHICLE_ATTITUDE_CONTROLS_EFFECTIVE : ORB_ID(actuator_controls_effective_1), _t_actuators_effective, &controls_effective);
/* iterate actuators */ /* iterate actuators */
for (unsigned int i = 0; i < _num_outputs; i++) { for (unsigned int i = 0; i < _num_outputs; i++) {
/* last resort: catch NaN, INF and out-of-band errors */ /* last resort: catch NaN, INF and out-of-band errors */
if (i < outputs.noutputs && if (i < outputs.noutputs &&
isfinite(outputs.output[i]) && isfinite(outputs.output[i]) &&
outputs.output[i] >= -1.0f && outputs.output[i] >= -1.0f &&
outputs.output[i] <= 1.0f) { outputs.output[i] <= 1.0f) {
/* scale for PWM output 900 - 2100us */ /* scale for PWM output 900 - 2100us */
//outputs.output[i] = 1500 + (600 * outputs.output[i]); /* nothing to do here */
//outputs.output[i] = 127 + (127 * outputs.output[i]);
} else { } else {
/* /*
* Value is NaN, INF or out of band - set to the minimum value. * Value is NaN, INF or out of band - set to the minimum value.
* This will be clearly visible on the servo status and will limit the risk of accidentally * This will be clearly visible on the servo status and will limit the risk of accidentally
* spinning motors. It would be deadly in flight. * spinning motors. It would be deadly in flight.
*/ */
if(outputs.output[i] < -1.0f) { if (outputs.output[i] < -1.0f) {
outputs.output[i] = -1.0f; outputs.output[i] = -1.0f;
} else if(outputs.output[i] > 1.0f) {
} else if (outputs.output[i] > 1.0f) {
outputs.output[i] = 1.0f; outputs.output[i] = 1.0f;
} else { } else {
outputs.output[i] = -1.0f; outputs.output[i] = -1.0f;
} }
} }
/* don't go under BLCTRL_MIN_VALUE */ /* don't go under BLCTRL_MIN_VALUE */
if(outputs.output[i] < BLCTRL_MIN_VALUE) { if (outputs.output[i] < BLCTRL_MIN_VALUE) {
outputs.output[i] = BLCTRL_MIN_VALUE; outputs.output[i] = BLCTRL_MIN_VALUE;
} }
//_motortest = true;
/* output to BLCtrl's */
if(_motortest == true) {
mk_servo_test(i);
} else {
//mk_servo_set(i, outputs.output[i]);
mk_servo_set_test(i, outputs.output[i]); // 8Bit
}
/* output to BLCtrl's */
if (_motortest == true) {
mk_servo_test(i);
} else {
mk_servo_set_value(i, scaling(outputs.output[i], -1.0f, 1.0f, 0, 1024)); // scale the output to 0 - 1024 and sent to output routine
}
} }
/* and publish for anyone that cares to see */
orb_publish(_primary_pwm_device ? ORB_ID_VEHICLE_CONTROLS : ORB_ID(actuator_outputs_1), _t_outputs, &outputs);
} }
} }
/* how about an arming update? */ /* how about an arming update? */
@ -622,29 +631,9 @@ MK::task_main()
orb_copy(ORB_ID(actuator_armed), _t_armed, &aa); orb_copy(ORB_ID(actuator_armed), _t_armed, &aa);
/* update PWM servo armed status if armed and not locked down */ /* update PWM servo armed status if armed and not locked down */
////up_pwm_servo_arm(aa.armed && !aa.lockdown);
mk_servo_arm(aa.armed && !aa.lockdown); mk_servo_arm(aa.armed && !aa.lockdown);
} }
// see if we have new PPM input data
if (ppm_last_valid_decode != rc_in.timestamp) {
// we have a new PPM frame. Publish it.
rc_in.channel_count = ppm_decoded_channels;
if (rc_in.channel_count > RC_INPUT_MAX_CHANNELS) {
rc_in.channel_count = RC_INPUT_MAX_CHANNELS;
}
for (uint8_t i=0; i<rc_in.channel_count; i++) {
rc_in.values[i] = ppm_buffer[i];
}
rc_in.timestamp = ppm_last_valid_decode;
/* lazily advertise on first publication */
if (to_input_rc == 0) {
to_input_rc = orb_advertise(ORB_ID(input_rc), &rc_in);
} else {
orb_publish(ORB_ID(input_rc), to_input_rc, &rc_in);
}
}
} }
@ -666,7 +655,7 @@ MK::task_main()
} }
int int
MK::mk_servo_arm(bool status) MK::mk_servo_arm(bool status)
{ {
_armed = status; _armed = status;
@ -680,12 +669,13 @@ MK::mk_check_for_blctrl(unsigned int count, bool showOutput)
_retries = 50; _retries = 50;
uint8_t foundMotorCount = 0; uint8_t foundMotorCount = 0;
for(unsigned i=0; i<MAX_MOTORS; i++) { for (unsigned i = 0; i < MAX_MOTORS; i++) {
Motor[i].Version = 0; Motor[i].Version = 0;
Motor[i].SetPoint = 0; Motor[i].SetPoint = 0;
Motor[i].SetPointLowerBits = 0; Motor[i].SetPointLowerBits = 0;
Motor[i].State = 0; Motor[i].State = 0;
Motor[i].ReadMode = 0; Motor[i].ReadMode = 0;
Motor[i].RawPwmValue = 0;
Motor[i].Current = 0; Motor[i].Current = 0;
Motor[i].MaxPWM = 0; Motor[i].MaxPWM = 0;
Motor[i].Temperature = 0; Motor[i].Temperature = 0;
@ -695,34 +685,37 @@ MK::mk_check_for_blctrl(unsigned int count, bool showOutput)
uint8_t msg = 0; uint8_t msg = 0;
uint8_t result[3]; uint8_t result[3];
for(unsigned i=0; i< count; i++) { for (unsigned i = 0; i < count; i++) {
result[0] = 0; result[0] = 0;
result[1] = 0; result[1] = 0;
result[2] = 0; result[2] = 0;
set_address( BLCTRL_BASE_ADDR + i ); set_address(BLCTRL_BASE_ADDR + i);
if (OK == transfer(&msg, 1, &result[0], 3)) { if (OK == transfer(&msg, 1, &result[0], 3)) {
Motor[i].Current = result[0]; Motor[i].Current = result[0];
Motor[i].MaxPWM = result[1]; Motor[i].MaxPWM = result[1];
Motor[i].Temperature = result[2]; Motor[i].Temperature = result[2];
Motor[i].State |= MOTOR_STATE_PRESENT_MASK; // set present bit; Motor[i].State |= MOTOR_STATE_PRESENT_MASK; // set present bit;
foundMotorCount++; foundMotorCount++;
if(Motor[i].MaxPWM == 250) {
if (Motor[i].MaxPWM == 250) {
Motor[i].Version = BLCTRL_NEW; Motor[i].Version = BLCTRL_NEW;
} else { } else {
Motor[i].Version = BLCTRL_OLD; Motor[i].Version = BLCTRL_OLD;
} }
} }
} }
if(showOutput) { if (showOutput) {
fprintf(stderr, "[mkblctrl] MotorsFound: %i\n",foundMotorCount); fprintf(stderr, "[mkblctrl] MotorsFound: %i\n", foundMotorCount);
for(unsigned i=0; i< foundMotorCount; i++) {
fprintf(stderr, "[mkblctrl] blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i\n", i,Motor[i].State, Motor[i].Version, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature); for (unsigned i = 0; i < foundMotorCount; i++) {
fprintf(stderr, "[mkblctrl] blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i\n", i, Motor[i].State, Motor[i].Version, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature);
} }
if(foundMotorCount != 4 && foundMotorCount != 6 && foundMotorCount != 8) { if (foundMotorCount != 4 && foundMotorCount != 6 && foundMotorCount != 8) {
_task_should_exit = true; _task_should_exit = true;
} }
} }
@ -734,122 +727,136 @@ MK::mk_check_for_blctrl(unsigned int count, bool showOutput)
int int
MK::mk_servo_set(unsigned int chan, float val) MK::mk_servo_set(unsigned int chan, short val)
{ {
float tmpVal = 0; short tmpVal = 0;
_retries = 0; _retries = 0;
uint8_t result[3] = { 0,0,0 }; uint8_t result[3] = { 0, 0, 0 };
uint8_t msg[2] = { 0,0 }; uint8_t msg[2] = { 0, 0 };
uint8_t rod=0; uint8_t rod = 0;
uint8_t bytesToSendBL2 = 2; uint8_t bytesToSendBL2 = 2;
tmpVal = val;
tmpVal = (1023 + (1023 * val)); if (tmpVal > 1024) {
if(tmpVal > 2047) { tmpVal = 1024;
tmpVal = 2047;
} else if (tmpVal < 0) {
tmpVal = 0;
} }
Motor[chan].SetPoint = (uint8_t)(tmpVal / 4);
//Motor[chan].SetPointLowerBits = (uint8_t) tmpVal % 4;
Motor[chan].SetPoint = (uint8_t) tmpVal / 3; // divide 8
Motor[chan].SetPointLowerBits = (uint8_t) tmpVal % 8; // rest of divide 8
//rod = (uint8_t) tmpVal % 8;
//Motor[chan].SetPointLowerBits = rod<<1; // rest of divide 8
Motor[chan].SetPointLowerBits = 0; Motor[chan].SetPointLowerBits = 0;
if(_armed == false) { if (_armed == false) {
Motor[chan].SetPoint = 0; Motor[chan].SetPoint = 0;
Motor[chan].SetPointLowerBits = 0; Motor[chan].SetPointLowerBits = 0;
} }
//if(Motor[chan].State & MOTOR_STATE_PRESENT_MASK) { //if(Motor[chan].State & MOTOR_STATE_PRESENT_MASK) {
set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan])); set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan]));
if (Motor[chan].Version == BLCTRL_OLD) {
/*
* Old BL-Ctrl 8Bit served. Version < 2.0
*/
msg[0] = Motor[chan].SetPoint;
if (Motor[chan].RoundCount >= 16) {
// on each 16th cyle we read out the status messages from the blctrl
if (OK == transfer(&msg[0], 1, &result[0], 2)) {
Motor[chan].Current = result[0];
Motor[chan].MaxPWM = result[1];
Motor[chan].Temperature = 255;;
if(Motor[chan].Version == BLCTRL_OLD) {
/*
* Old BL-Ctrl 8Bit served. Version < 2.0
*/
msg[0] = Motor[chan].SetPoint;
if(Motor[chan].RoundCount >= 16) {
// on each 16th cyle we read out the status messages from the blctrl
if (OK == transfer(&msg[0], 1, &result[0], 2)) {
Motor[chan].Current = result[0];
Motor[chan].MaxPWM = result[1];
Motor[chan].Temperature = 255;;
} else {
if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
Motor[chan].RoundCount = 0;
} else { } else {
if (OK != transfer(&msg[0], 1, nullptr, 0)) { if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
} }
Motor[chan].RoundCount = 0;
} else { } else {
/* if (OK != transfer(&msg[0], 1, nullptr, 0)) {
* New BL-Ctrl 11Bit served. Version >= 2.0 if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
*/
msg[0] = Motor[chan].SetPoint;
msg[1] = Motor[chan].SetPointLowerBits;
if(Motor[chan].SetPointLowerBits == 0) {
bytesToSendBL2 = 1; // if setpoint lower bits are zero, we send only the higher bits - this saves time
} }
if(Motor[chan].RoundCount >= 16) {
// on each 16th cyle we read out the status messages from the blctrl
if (OK == transfer(&msg[0], bytesToSendBL2, &result[0], 3)) {
Motor[chan].Current = result[0];
Motor[chan].MaxPWM = result[1];
Motor[chan].Temperature = result[2];
} else {
if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
Motor[chan].RoundCount = 0;
} else {
if (OK != transfer(&msg[0], bytesToSendBL2, nullptr, 0)) {
if((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
}
} }
Motor[chan].RoundCount++; } else {
/*
* New BL-Ctrl 11Bit served. Version >= 2.0
*/
msg[0] = Motor[chan].SetPoint;
msg[1] = Motor[chan].SetPointLowerBits;
if (Motor[chan].SetPointLowerBits == 0) {
bytesToSendBL2 = 1; // if setpoint lower bits are zero, we send only the higher bits - this saves time
}
if (Motor[chan].RoundCount >= 16) {
// on each 16th cyle we read out the status messages from the blctrl
if (OK == transfer(&msg[0], bytesToSendBL2, &result[0], 3)) {
Motor[chan].Current = result[0];
Motor[chan].MaxPWM = result[1];
Motor[chan].Temperature = result[2];
} else {
if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
Motor[chan].RoundCount = 0;
} else {
if (OK != transfer(&msg[0], bytesToSendBL2, nullptr, 0)) {
if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) Motor[chan].State++; // error
}
}
}
Motor[chan].RoundCount++;
//} //}
if(showDebug == true) { if (showDebug == true) {
debugCounter++; debugCounter++;
if(debugCounter == 2000) {
if (debugCounter == 2000) {
debugCounter = 0; debugCounter = 0;
for(int i=0; i<_num_outputs; i++){
if(Motor[i].State & MOTOR_STATE_PRESENT_MASK) { for (int i = 0; i < _num_outputs; i++) {
if (Motor[i].State & MOTOR_STATE_PRESENT_MASK) {
fprintf(stderr, "[mkblctrl] #%i:\tVer: %i\tVal: %i\tCurr: %i\tMaxPWM: %i\tTemp: %i\tState: %i\n", i, Motor[i].Version, Motor[i].SetPoint, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature, Motor[i].State); fprintf(stderr, "[mkblctrl] #%i:\tVer: %i\tVal: %i\tCurr: %i\tMaxPWM: %i\tTemp: %i\tState: %i\n", i, Motor[i].Version, Motor[i].SetPoint, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature, Motor[i].State);
} }
} }
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
} }
return 0; return 0;
} }
int int
MK::mk_servo_set_test(unsigned int chan, float val) MK::mk_servo_set_value(unsigned int chan, short val)
{ {
_retries = 0; _retries = 0;
int ret; int ret;
short tmpVal = 0;
uint8_t msg[2] = { 0, 0 };
float tmpVal = 0; tmpVal = val;
uint8_t msg[2] = { 0,0 }; if (tmpVal > 1024) {
tmpVal = 1024;
tmpVal = (1023 + (1023 * val)); } else if (tmpVal < 0) {
if(tmpVal > 2048) { tmpVal = 0;
tmpVal = 2048;
} }
Motor[chan].SetPoint = (uint8_t) (tmpVal / 8); Motor[chan].SetPoint = (uint8_t)(tmpVal / 4);
if(_armed == false) { if (_armed == false) {
Motor[chan].SetPoint = 0; Motor[chan].SetPoint = 0;
Motor[chan].SetPointLowerBits = 0; Motor[chan].SetPointLowerBits = 0;
} }
@ -860,7 +867,6 @@ MK::mk_servo_set_test(unsigned int chan, float val)
ret = transfer(&msg[0], 1, nullptr, 0); ret = transfer(&msg[0], 1, nullptr, 0);
ret = OK; ret = OK;
return ret; return ret;
} }
@ -868,59 +874,61 @@ MK::mk_servo_set_test(unsigned int chan, float val)
int int
MK::mk_servo_test(unsigned int chan) MK::mk_servo_test(unsigned int chan)
{ {
int ret=0; int ret = 0;
float tmpVal = 0; float tmpVal = 0;
float val = -1; float val = -1;
_retries = 0; _retries = 0;
uint8_t msg[2] = { 0,0 }; uint8_t msg[2] = { 0, 0 };
if(debugCounter >= MOTOR_SPINUP_COUNTER) { if (debugCounter >= MOTOR_SPINUP_COUNTER) {
debugCounter = 0; debugCounter = 0;
_motor++; _motor++;
if(_motor < _num_outputs) { if (_motor < _num_outputs) {
fprintf(stderr, "[mkblctrl] Motortest - #%i:\tspinup\n", _motor); fprintf(stderr, "[mkblctrl] Motortest - #%i:\tspinup\n", _motor);
} }
if(_motor >= _num_outputs) { if (_motor >= _num_outputs) {
_motor = -1; _motor = -1;
_motortest = false; _motortest = false;
} }
} }
debugCounter++; debugCounter++;
if(_motor == chan) { if (_motor == chan) {
val = BLCTRL_MIN_VALUE; val = BLCTRL_MIN_VALUE;
} else { } else {
val = -1; val = -1;
} }
tmpVal = (1023 + (1023 * val)); tmpVal = (511 + (511 * val));
if(tmpVal > 2048) {
tmpVal = 2048; if (tmpVal > 1024) {
tmpVal = 1024;
} }
//Motor[chan].SetPoint = (uint8_t) (tmpVal / 8); Motor[chan].SetPoint = (uint8_t)(tmpVal / 4);
//Motor[chan].SetPointLowerBits = (uint8_t) (tmpVal % 8) & 0x07;
Motor[chan].SetPoint = (uint8_t) tmpVal>>3;
Motor[chan].SetPointLowerBits = (uint8_t) tmpVal & 0x07;
if(_motor != chan) { if (_motor != chan) {
Motor[chan].SetPoint = 0; Motor[chan].SetPoint = 0;
Motor[chan].SetPointLowerBits = 0; Motor[chan].SetPointLowerBits = 0;
} }
if(Motor[chan].Version == BLCTRL_OLD) { if (Motor[chan].Version == BLCTRL_OLD) {
msg[0] = Motor[chan].SetPoint; msg[0] = Motor[chan].SetPoint;
} else { } else {
msg[0] = Motor[chan].SetPoint; msg[0] = Motor[chan].SetPoint;
msg[1] = Motor[chan].SetPointLowerBits; msg[1] = Motor[chan].SetPointLowerBits;
} }
set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan])); set_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan]));
if(Motor[chan].Version == BLCTRL_OLD) {
if (Motor[chan].Version == BLCTRL_OLD) {
ret = transfer(&msg[0], 1, nullptr, 0); ret = transfer(&msg[0], 1, nullptr, 0);
} else { } else {
ret = transfer(&msg[0], 2, nullptr, 0); ret = transfer(&msg[0], 2, nullptr, 0);
} }
@ -931,9 +939,9 @@ MK::mk_servo_test(unsigned int chan)
int int
MK::control_callback(uintptr_t handle, MK::control_callback(uintptr_t handle,
uint8_t control_group, uint8_t control_group,
uint8_t control_index, uint8_t control_index,
float &input) float &input)
{ {
const actuator_controls_s *controls = (actuator_controls_s *)handle; const actuator_controls_s *controls = (actuator_controls_s *)handle;
@ -947,7 +955,6 @@ MK::ioctl(file *filp, int cmd, unsigned long arg)
int ret; int ret;
// XXX disabled, confusing users // XXX disabled, confusing users
//debug("ioctl 0x%04x 0x%08x", cmd, arg);
/* try it as a GPIO ioctl first */ /* try it as a GPIO ioctl first */
ret = gpio_ioctl(filp, cmd, arg); ret = gpio_ioctl(filp, cmd, arg);
@ -978,32 +985,37 @@ int
MK::pwm_ioctl(file *filp, int cmd, unsigned long arg) MK::pwm_ioctl(file *filp, int cmd, unsigned long arg)
{ {
int ret = OK; int ret = OK;
int channel;
lock(); lock();
switch (cmd) { switch (cmd) {
case PWM_SERVO_ARM: case PWM_SERVO_ARM:
////up_pwm_servo_arm(true);
mk_servo_arm(true); mk_servo_arm(true);
break; break;
case PWM_SERVO_SET_ARM_OK:
case PWM_SERVO_CLEAR_ARM_OK:
// these are no-ops, as no safety switch
break;
case PWM_SERVO_DISARM: case PWM_SERVO_DISARM:
////up_pwm_servo_arm(false);
mk_servo_arm(false); mk_servo_arm(false);
break; break;
case PWM_SERVO_SET_UPDATE_RATE: case PWM_SERVO_SET_UPDATE_RATE:
set_pwm_rate(arg); ret = OK;
break;
case PWM_SERVO_SELECT_UPDATE_RATE:
ret = OK;
break; break;
case PWM_SERVO_SET(0) ... PWM_SERVO_SET(_max_actuators - 1): case PWM_SERVO_SET(0) ... PWM_SERVO_SET(_max_actuators - 1):
if (arg < 2150) {
Motor[cmd - PWM_SERVO_SET(0)].RawPwmValue = (unsigned short)arg;
mk_servo_set_value(cmd - PWM_SERVO_SET(0), scaling(arg, 1010, 2100, 0, 1024));
/* fake an update to the selected 'servo' channel */
if ((arg >= 0) && (arg <= 255)) {
channel = cmd - PWM_SERVO_SET(0);
//mk_servo_set(channel, arg);
} else { } else {
ret = -EINVAL; ret = -EINVAL;
} }
@ -1012,20 +1024,20 @@ MK::pwm_ioctl(file *filp, int cmd, unsigned long arg)
case PWM_SERVO_GET(0) ... PWM_SERVO_GET(_max_actuators - 1): case PWM_SERVO_GET(0) ... PWM_SERVO_GET(_max_actuators - 1):
/* copy the current output value from the channel */ /* copy the current output value from the channel */
*(servo_position_t *)arg = cmd - PWM_SERVO_GET(0); *(servo_position_t *)arg = Motor[cmd - PWM_SERVO_SET(0)].RawPwmValue;
break; break;
case PWM_SERVO_GET_RATEGROUP(0):
case PWM_SERVO_GET_RATEGROUP(1):
case PWM_SERVO_GET_RATEGROUP(2):
case PWM_SERVO_GET_RATEGROUP(3):
//*(uint32_t *)arg = up_pwm_servo_get_rate_group(cmd - PWM_SERVO_GET_RATEGROUP(0));
break;
case PWM_SERVO_GET_COUNT:
case MIXERIOCGETOUTPUTCOUNT: case MIXERIOCGETOUTPUTCOUNT:
/*
if (_mode == MODE_4PWM) {
*(unsigned *)arg = 4;
} else {
*(unsigned *)arg = 2;
}
*/
*(unsigned *)arg = _num_outputs; *(unsigned *)arg = _num_outputs;
break; break;
case MIXERIOCRESET: case MIXERIOCRESET:
@ -1078,6 +1090,7 @@ MK::pwm_ioctl(file *filp, int cmd, unsigned long arg)
ret = -EINVAL; ret = -EINVAL;
} }
} }
break; break;
} }
@ -1091,6 +1104,38 @@ MK::pwm_ioctl(file *filp, int cmd, unsigned long arg)
return ret; return ret;
} }
/*
this implements PWM output via a write() method, for compatibility
with px4io
*/
ssize_t
MK::write(file *filp, const char *buffer, size_t len)
{
unsigned count = len / 2;
// loeschen uint16_t values[4];
uint16_t values[8];
// loeschen if (count > 4) {
// loeschen // we only have 4 PWM outputs on the FMU
// loeschen count = 4;
// loeschen }
if (count > _num_outputs) {
// we only have 8 I2C outputs in the driver
count = _num_outputs;
}
// allow for misaligned values
memcpy(values, buffer, count * 2);
for (uint8_t i = 0; i < count; i++) {
Motor[i].RawPwmValue = (unsigned short)values[i];
mk_servo_set_value(i, scaling(values[i], 1010, 2100, 0, 1024));
}
return count * 2;
}
void void
MK::gpio_reset(void) MK::gpio_reset(void)
{ {
@ -1229,10 +1274,10 @@ enum MappingMode {
MAPPING_PX4, MAPPING_PX4,
}; };
enum FrameType { enum FrameType {
FRAME_PLUS = 0, FRAME_PLUS = 0,
FRAME_X, FRAME_X,
}; };
PortMode g_port_mode; PortMode g_port_mode;
@ -1297,18 +1342,17 @@ mk_new_mode(PortMode new_mode, int update_rate, int motorcount, bool motortest,
g_mk->set_motor_test(motortest); g_mk->set_motor_test(motortest);
/* (re)set count of used motors */
////g_mk->set_motor_count(motorcount);
/* count used motors */ /* count used motors */
do { do {
if(g_mk->mk_check_for_blctrl(8, false) != 0) { if (g_mk->mk_check_for_blctrl(8, false) != 0) {
shouldStop = 4; shouldStop = 4;
} else { } else {
shouldStop++; shouldStop++;
} }
sleep(1); sleep(1);
} while ( shouldStop < 3); } while (shouldStop < 3);
g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, true)); g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, true));
@ -1375,7 +1419,8 @@ mkblctrl_main(int argc, char *argv[])
if (argc > i + 1) { if (argc > i + 1) {
bus = atoi(argv[i + 1]); bus = atoi(argv[i + 1]);
newMode = true; newMode = true;
} else {
} else {
errx(1, "missing argument for i2c bus (-b)"); errx(1, "missing argument for i2c bus (-b)");
return 1; return 1;
} }
@ -1384,17 +1429,21 @@ mkblctrl_main(int argc, char *argv[])
/* look for the optional frame parameter */ /* look for the optional frame parameter */
if (strcmp(argv[i], "-mkmode") == 0 || strcmp(argv[i], "--mkmode") == 0) { if (strcmp(argv[i], "-mkmode") == 0 || strcmp(argv[i], "--mkmode") == 0) {
if (argc > i + 1) { if (argc > i + 1) {
if(strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) { if (strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) {
px4mode = MAPPING_MK; px4mode = MAPPING_MK;
newMode = true; newMode = true;
if(strcmp(argv[i + 1], "+") == 0) {
if (strcmp(argv[i + 1], "+") == 0) {
frametype = FRAME_PLUS; frametype = FRAME_PLUS;
} else { } else {
frametype = FRAME_X; frametype = FRAME_X;
} }
} else { } else {
errx(1, "only + or x for frametype supported !"); errx(1, "only + or x for frametype supported !");
} }
} else { } else {
errx(1, "missing argument for mkmode (-mkmode)"); errx(1, "missing argument for mkmode (-mkmode)");
return 1; return 1;
@ -1409,12 +1458,12 @@ mkblctrl_main(int argc, char *argv[])
/* look for the optional -h --help parameter */ /* look for the optional -h --help parameter */
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
showHelp == true; showHelp = true;
} }
} }
if(showHelp) { if (showHelp) {
fprintf(stderr, "mkblctrl: help:\n"); fprintf(stderr, "mkblctrl: help:\n");
fprintf(stderr, " [-mkmode frame{+/x}] [-b i2c_bus_number] [-t motortest] [-h / --help]\n"); fprintf(stderr, " [-mkmode frame{+/x}] [-b i2c_bus_number] [-t motortest] [-h / --help]\n");
exit(1); exit(1);
@ -1424,6 +1473,7 @@ mkblctrl_main(int argc, char *argv[])
if (g_mk == nullptr) { if (g_mk == nullptr) {
if (mk_start(bus, motorcount) != OK) { if (mk_start(bus, motorcount) != OK) {
errx(1, "failed to start the MK-BLCtrl driver"); errx(1, "failed to start the MK-BLCtrl driver");
} else { } else {
newMode = true; newMode = true;
} }

View File

@ -106,7 +106,7 @@ public:
* @param rate The rate in Hz actuator outpus are sent to IO. * @param rate The rate in Hz actuator outpus are sent to IO.
* Min 10 Hz, max 400 Hz * Min 10 Hz, max 400 Hz
*/ */
int set_update_rate(int rate); int set_update_rate(int rate);
/** /**
* Set the battery current scaling and bias * Set the battery current scaling and bias
@ -114,7 +114,15 @@ public:
* @param amp_per_volt * @param amp_per_volt
* @param amp_bias * @param amp_bias
*/ */
void set_battery_current_scaling(float amp_per_volt, float amp_bias); void set_battery_current_scaling(float amp_per_volt, float amp_bias);
/**
* Push failsafe values to IO.
*
* @param vals Failsafe control inputs: in us PPM (900 for zero, 1500 for centered, 2100 for full)
* @param len Number of channels, could up to 8
*/
int set_failsafe_values(const uint16_t *vals, unsigned len);
/** /**
* Print the current status of IO * Print the current status of IO
@ -326,11 +334,11 @@ PX4IO::PX4IO() :
_to_actuators_effective(0), _to_actuators_effective(0),
_to_outputs(0), _to_outputs(0),
_to_battery(0), _to_battery(0),
_primary_pwm_device(false),
_battery_amp_per_volt(90.0f/5.0f), // this matches the 3DR current sensor _battery_amp_per_volt(90.0f/5.0f), // this matches the 3DR current sensor
_battery_amp_bias(0), _battery_amp_bias(0),
_battery_mamphour_total(0), _battery_mamphour_total(0),
_battery_last_timestamp(0), _battery_last_timestamp(0)
_primary_pwm_device(false)
{ {
/* we need this potentially before it could be set in task_main */ /* we need this potentially before it could be set in task_main */
g_dev = this; g_dev = this;
@ -689,6 +697,19 @@ PX4IO::io_set_control_state()
return io_reg_set(PX4IO_PAGE_CONTROLS, 0, regs, _max_controls); return io_reg_set(PX4IO_PAGE_CONTROLS, 0, regs, _max_controls);
} }
int
PX4IO::set_failsafe_values(const uint16_t *vals, unsigned len)
{
uint16_t regs[_max_actuators];
if (len > _max_actuators)
/* fail with error */
return E2BIG;
/* copy values to registers in IO */
return io_reg_set(PX4IO_PAGE_FAILSAFE_PWM, 0, vals, len);
}
int int
PX4IO::io_set_arming_state() PX4IO::io_set_arming_state()
{ {
@ -1250,7 +1271,7 @@ PX4IO::print_status()
printf("%u bytes free\n", printf("%u bytes free\n",
io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FREEMEM)); io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FREEMEM));
uint16_t flags = io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FLAGS); uint16_t flags = io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_FLAGS);
printf("status 0x%04x%s%s%s%s%s%s%s%s%s%s%s\n", printf("status 0x%04x%s%s%s%s%s%s%s%s%s%s%s%s\n",
flags, flags,
((flags & PX4IO_P_STATUS_FLAGS_ARMED) ? " ARMED" : ""), ((flags & PX4IO_P_STATUS_FLAGS_ARMED) ? " ARMED" : ""),
((flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) ? " OVERRIDE" : ""), ((flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) ? " OVERRIDE" : ""),
@ -1262,7 +1283,8 @@ PX4IO::print_status()
((flags & PX4IO_P_STATUS_FLAGS_RAW_PWM) ? " RAW_PPM" : ""), ((flags & PX4IO_P_STATUS_FLAGS_RAW_PWM) ? " RAW_PPM" : ""),
((flags & PX4IO_P_STATUS_FLAGS_MIXER_OK) ? " MIXER_OK" : " MIXER_FAIL"), ((flags & PX4IO_P_STATUS_FLAGS_MIXER_OK) ? " MIXER_OK" : " MIXER_FAIL"),
((flags & PX4IO_P_STATUS_FLAGS_ARM_SYNC) ? " ARM_SYNC" : " ARM_NO_SYNC"), ((flags & PX4IO_P_STATUS_FLAGS_ARM_SYNC) ? " ARM_SYNC" : " ARM_NO_SYNC"),
((flags & PX4IO_P_STATUS_FLAGS_INIT_OK) ? " INIT_OK" : " INIT_FAIL")); ((flags & PX4IO_P_STATUS_FLAGS_INIT_OK) ? " INIT_OK" : " INIT_FAIL"),
((flags & PX4IO_P_STATUS_FLAGS_FAILSAFE) ? " FAILSAFE" : ""));
uint16_t alarms = io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_ALARMS); uint16_t alarms = io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_ALARMS);
printf("alarms 0x%04x%s%s%s%s%s%s%s\n", printf("alarms 0x%04x%s%s%s%s%s%s%s\n",
alarms, alarms,
@ -1273,11 +1295,14 @@ PX4IO::print_status()
((alarms & PX4IO_P_STATUS_ALARMS_FMU_LOST) ? " FMU_LOST" : ""), ((alarms & PX4IO_P_STATUS_ALARMS_FMU_LOST) ? " FMU_LOST" : ""),
((alarms & PX4IO_P_STATUS_ALARMS_RC_LOST) ? " RC_LOST" : ""), ((alarms & PX4IO_P_STATUS_ALARMS_RC_LOST) ? " RC_LOST" : ""),
((alarms & PX4IO_P_STATUS_ALARMS_PWM_ERROR) ? " PWM_ERROR" : "")); ((alarms & PX4IO_P_STATUS_ALARMS_PWM_ERROR) ? " PWM_ERROR" : ""));
/* now clear alarms */
io_reg_set(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_ALARMS, 0xFFFF);
printf("vbatt %u ibatt %u vbatt scale %u\n", printf("vbatt %u ibatt %u vbatt scale %u\n",
io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_VBATT), io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_VBATT),
io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_IBATT), io_reg_get(PX4IO_PAGE_STATUS, PX4IO_P_STATUS_IBATT),
io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE)); io_reg_get(PX4IO_PAGE_SETUP, PX4IO_P_SETUP_VBATT_SCALE));
printf("amp_per_volt %.3f amp_offset %.3f mAhDischarged %.3f\n", printf("amp_per_volt %.3f amp_offset %.3f mAh discharged %.3f\n",
(double)_battery_amp_per_volt, (double)_battery_amp_per_volt,
(double)_battery_amp_bias, (double)_battery_amp_bias,
(double)_battery_mamphour_total); (double)_battery_mamphour_total);
@ -1471,7 +1496,7 @@ PX4IO::ioctl(file *filep, int cmd, unsigned long arg)
case MIXERIOCLOADBUF: { case MIXERIOCLOADBUF: {
const char *buf = (const char *)arg; const char *buf = (const char *)arg;
ret = mixer_send(buf, strnlen(buf, 1024)); ret = mixer_send(buf, strnlen(buf, 2048));
break; break;
} }
@ -1612,6 +1637,13 @@ test(void)
if (ioctl(fd, PWM_SERVO_ARM, 0)) if (ioctl(fd, PWM_SERVO_ARM, 0))
err(1, "failed to arm servos"); err(1, "failed to arm servos");
/* Open console directly to grab CTRL-C signal */
int console = open("/dev/console", O_NONBLOCK | O_RDONLY | O_NOCTTY);
if (!console)
err(1, "failed opening console");
warnx("Press CTRL-C or 'c' to abort.");
for (;;) { for (;;) {
/* sweep all servos between 1000..2000 */ /* sweep all servos between 1000..2000 */
@ -1646,6 +1678,16 @@ test(void)
if (value != servos[i]) if (value != servos[i])
errx(1, "servo %d readback error, got %u expected %u", i, value, servos[i]); errx(1, "servo %d readback error, got %u expected %u", i, value, servos[i]);
} }
/* Check if user wants to quit */
char c;
if (read(console, &c, 1) == 1) {
if (c == 0x03 || c == 0x63) {
warnx("User abort\n");
close(console);
exit(0);
}
}
} }
} }
@ -1715,6 +1757,41 @@ px4io_main(int argc, char *argv[])
exit(0); exit(0);
} }
if (!strcmp(argv[1], "failsafe")) {
if (argc < 3) {
errx(1, "failsafe command needs at least one channel value (ppm)");
}
if (g_dev != nullptr) {
/* set values for first 8 channels, fill unassigned channels with 1500. */
uint16_t failsafe[8];
for (int i = 0; i < sizeof(failsafe) / sizeof(failsafe[0]); i++)
{
/* set channel to commanline argument or to 900 for non-provided channels */
if (argc > i + 2) {
failsafe[i] = atoi(argv[i+2]);
if (failsafe[i] < 800 || failsafe[i] > 2200) {
errx(1, "value out of range of 800 < value < 2200. Aborting.");
}
} else {
/* a zero value will result in stopping to output any pulse */
failsafe[i] = 0;
}
}
int ret = g_dev->set_failsafe_values(failsafe, sizeof(failsafe) / sizeof(failsafe[0]));
if (ret != OK)
errx(ret, "failed setting failsafe values");
} else {
errx(1, "not loaded");
}
exit(0);
}
if (!strcmp(argv[1], "recovery")) { if (!strcmp(argv[1], "recovery")) {
if (g_dev != nullptr) { if (g_dev != nullptr) {
@ -1842,5 +1919,5 @@ px4io_main(int argc, char *argv[])
monitor(); monitor();
out: out:
errx(1, "need a command, try 'start', 'stop', 'status', 'test', 'monitor', 'debug', 'recovery', 'limit', 'current' or 'update'"); errx(1, "need a command, try 'start', 'stop', 'status', 'test', 'monitor', 'debug', 'recovery', 'limit', 'current', 'failsafe' or 'update'");
} }

View File

@ -330,7 +330,7 @@ static void hrt_call_invoke(void);
/* /*
* PPM decoder tuning parameters * PPM decoder tuning parameters
*/ */
# define PPM_MAX_PULSE_WIDTH 500 /* maximum width of a pulse */ # define PPM_MAX_PULSE_WIDTH 550 /* maximum width of a valid pulse */
# define PPM_MIN_CHANNEL_VALUE 800 /* shortest valid channel signal */ # define PPM_MIN_CHANNEL_VALUE 800 /* shortest valid channel signal */
# define PPM_MAX_CHANNEL_VALUE 2200 /* longest valid channel signal */ # define PPM_MAX_CHANNEL_VALUE 2200 /* longest valid channel signal */
# define PPM_MIN_START 2500 /* shortest valid start gap */ # define PPM_MIN_START 2500 /* shortest valid start gap */

View File

@ -33,10 +33,13 @@
****************************************************************************/ ****************************************************************************/
/** /**
* @file main.c * @file main.c
* Implementation of a fixed wing attitude controller. This file is a complete *
* fixed wing controller flying manual attitude control or auto waypoint control. * Example implementation of a fixed wing attitude controller. This file is a complete
* fixed wing controller for manual attitude control or auto waypoint control.
* There is no need to touch any other system components to extend / modify the * There is no need to touch any other system components to extend / modify the
* complete control architecture. * complete control architecture.
*
* @author Lorenz Meier <lm@inf.ethz.ch>
*/ */
#include <nuttx/config.h> #include <nuttx/config.h>
@ -60,7 +63,6 @@
#include <uORB/topics/actuator_controls.h> #include <uORB/topics/actuator_controls.h>
#include <uORB/topics/vehicle_rates_setpoint.h> #include <uORB/topics/vehicle_rates_setpoint.h>
#include <uORB/topics/vehicle_global_position.h> #include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/debug_key_value.h>
#include <uORB/topics/parameter_update.h> #include <uORB/topics/parameter_update.h>
#include <systemlib/param/param.h> #include <systemlib/param/param.h>
#include <systemlib/pid/pid.h> #include <systemlib/pid/pid.h>
@ -73,8 +75,15 @@
#include "params.h" #include "params.h"
/* Prototypes */ /* Prototypes */
/** /**
* Daemon management function. * Daemon management function.
*
* This function allows to start / stop the background task (daemon).
* The purpose of it is to be able to start the controller on the
* command line, query its status and stop it, without giving up
* the command line to one particular process or the need for bg/fg
* ^Z support by the shell.
*/ */
__EXPORT int ex_fixedwing_control_main(int argc, char *argv[]); __EXPORT int ex_fixedwing_control_main(int argc, char *argv[]);
@ -88,10 +97,34 @@ int fixedwing_control_thread_main(int argc, char *argv[]);
*/ */
static void usage(const char *reason); static void usage(const char *reason);
/**
* Control roll and pitch angle.
*
* This very simple roll and pitch controller takes the current roll angle
* of the system and compares it to a reference. Pitch is controlled to zero and yaw remains
* uncontrolled (tutorial code, not intended for flight).
*
* @param att_sp The current attitude setpoint - the values the system would like to reach.
* @param att The current attitude. The controller should make the attitude match the setpoint
* @param speed_body The velocity of the system. Currently unused.
* @param rates_sp The angular rate setpoint. This is the output of the controller.
*/
void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att, void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att,
float speed_body[], float gyro[], struct vehicle_rates_setpoint_s *rates_sp, float speed_body[], struct vehicle_rates_setpoint_s *rates_sp,
struct actuator_controls_s *actuators); struct actuator_controls_s *actuators);
/**
* Control heading.
*
* This very simple heading to roll angle controller outputs the desired roll angle based on
* the current position of the system, the desired position (the setpoint) and the current
* heading.
*
* @param pos The current position of the system
* @param sp The current position setpoint
* @param att The current attitude
* @param att_sp The attitude setpoint. This is the output of the controller
*/
void control_heading(const struct vehicle_global_position_s *pos, const struct vehicle_global_position_setpoint_s *sp, void control_heading(const struct vehicle_global_position_s *pos, const struct vehicle_global_position_setpoint_s *sp,
const struct vehicle_attitude_s *att, struct vehicle_attitude_setpoint_s *att_sp); const struct vehicle_attitude_s *att, struct vehicle_attitude_setpoint_s *att_sp);
@ -103,7 +136,7 @@ static struct params p;
static struct param_handles ph; static struct param_handles ph;
void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att, void control_attitude(const struct vehicle_attitude_setpoint_s *att_sp, const struct vehicle_attitude_s *att,
float speed_body[], float gyro[], struct vehicle_rates_setpoint_s *rates_sp, float speed_body[], struct vehicle_rates_setpoint_s *rates_sp,
struct actuator_controls_s *actuators) struct actuator_controls_s *actuators)
{ {
@ -148,13 +181,23 @@ void control_heading(const struct vehicle_global_position_s *pos, const struct v
* Calculate heading error of current position to desired position * Calculate heading error of current position to desired position
*/ */
/* PX4 uses 1e7 scaled integers to represent global coordinates for max resolution */ /*
* PX4 uses 1e7 scaled integers to represent global coordinates for max resolution,
* so they need to be scaled by 1e7 and converted to IEEE double precision floating point.
*/
float bearing = get_bearing_to_next_waypoint(pos->lat/1e7d, pos->lon/1e7d, sp->lat/1e7d, sp->lon/1e7d); float bearing = get_bearing_to_next_waypoint(pos->lat/1e7d, pos->lon/1e7d, sp->lat/1e7d, sp->lon/1e7d);
/* calculate heading error */ /* calculate heading error */
float yaw_err = att->yaw - bearing; float yaw_err = att->yaw - bearing;
/* apply control gain */ /* apply control gain */
att_sp->roll_body = yaw_err * p.hdng_p; float roll_command = yaw_err * p.hdng_p;
/* limit output, this commonly is a tuning parameter, too */
if (att_sp->roll_body < -0.6f) {
att_sp->roll_body = -0.6f;
} else if (att_sp->roll_body > 0.6f) {
att_sp->roll_body = 0.6f;
}
} }
/* Main Thread */ /* Main Thread */
@ -176,7 +219,32 @@ int fixedwing_control_thread_main(int argc, char *argv[])
parameters_init(&ph); parameters_init(&ph);
parameters_update(&ph, &p); parameters_update(&ph, &p);
/* declare and safely initialize all structs to zero */
/*
* PX4 uses a publish/subscribe design pattern to enable
* multi-threaded communication.
*
* The most elegant aspect of this is that controllers and
* other processes can either 'react' to new data, or run
* at their own pace.
*
* PX4 developer guide:
* https://pixhawk.ethz.ch/px4/dev/shared_object_communication
*
* Wikipedia description:
* http://en.wikipedia.org/wiki/Publishsubscribe_pattern
*
*/
/*
* Declare and safely initialize all structs to zero.
*
* These structs contain the system state and things
* like attitude, position, the current waypoint, etc.
*/
struct vehicle_attitude_s att; struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att)); memset(&att, 0, sizeof(att));
struct vehicle_attitude_setpoint_s att_sp; struct vehicle_attitude_setpoint_s att_sp;
@ -192,20 +260,24 @@ int fixedwing_control_thread_main(int argc, char *argv[])
struct vehicle_global_position_setpoint_s global_sp; struct vehicle_global_position_setpoint_s global_sp;
memset(&global_sp, 0, sizeof(global_sp)); memset(&global_sp, 0, sizeof(global_sp));
/* output structs */ /* output structs - this is what is sent to the mixer */
struct actuator_controls_s actuators; struct actuator_controls_s actuators;
memset(&actuators, 0, sizeof(actuators)); memset(&actuators, 0, sizeof(actuators));
/* publish actuator controls */ /* publish actuator controls with zero values */
for (unsigned i = 0; i < NUM_ACTUATOR_CONTROLS; i++) { for (unsigned i = 0; i < NUM_ACTUATOR_CONTROLS; i++) {
actuators.control[i] = 0.0f; actuators.control[i] = 0.0f;
} }
/*
* Advertise that this controller will publish actuator
* control values and the rate setpoint
*/
orb_advert_t actuator_pub = orb_advertise(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, &actuators); orb_advert_t actuator_pub = orb_advertise(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, &actuators);
orb_advert_t rates_pub = orb_advertise(ORB_ID(vehicle_rates_setpoint), &rates_sp); orb_advert_t rates_pub = orb_advertise(ORB_ID(vehicle_rates_setpoint), &rates_sp);
/* subscribe */ /* subscribe to topics. */
int att_sub = orb_subscribe(ORB_ID(vehicle_attitude)); int att_sub = orb_subscribe(ORB_ID(vehicle_attitude));
int att_sp_sub = orb_subscribe(ORB_ID(vehicle_attitude_setpoint)); int att_sp_sub = orb_subscribe(ORB_ID(vehicle_attitude_setpoint));
int global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position)); int global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position));
@ -215,8 +287,9 @@ int fixedwing_control_thread_main(int argc, char *argv[])
int param_sub = orb_subscribe(ORB_ID(parameter_update)); int param_sub = orb_subscribe(ORB_ID(parameter_update));
/* Setup of loop */ /* Setup of loop */
float gyro[3] = {0.0f, 0.0f, 0.0f};
float speed_body[3] = {0.0f, 0.0f, 0.0f}; float speed_body[3] = {0.0f, 0.0f, 0.0f};
/* RC failsafe check */
bool throttle_half_once = false;
struct pollfd fds[2] = {{ .fd = param_sub, .events = POLLIN }, struct pollfd fds[2] = {{ .fd = param_sub, .events = POLLIN },
{ .fd = att_sub, .events = POLLIN }}; { .fd = att_sub, .events = POLLIN }};
@ -235,7 +308,10 @@ int fixedwing_control_thread_main(int argc, char *argv[])
int ret = poll(fds, 2, 500); int ret = poll(fds, 2, 500);
if (ret < 0) { if (ret < 0) {
/* poll error, this will not really happen in practice */ /*
* Poll error, this will not really happen in practice,
* but its good design practice to make output an error message.
*/
warnx("poll error"); warnx("poll error");
} else if (ret == 0) { } else if (ret == 0) {
@ -261,6 +337,8 @@ int fixedwing_control_thread_main(int argc, char *argv[])
orb_check(global_pos_sub, &pos_updated); orb_check(global_pos_sub, &pos_updated);
bool global_sp_updated; bool global_sp_updated;
orb_check(global_sp_sub, &global_sp_updated); orb_check(global_sp_sub, &global_sp_updated);
bool manual_sp_updated;
orb_check(manual_sp_sub, &manual_sp_updated);
/* get a local copy of attitude */ /* get a local copy of attitude */
orb_copy(ORB_ID(vehicle_attitude), att_sub, &att); orb_copy(ORB_ID(vehicle_attitude), att_sub, &att);
@ -268,6 +346,7 @@ int fixedwing_control_thread_main(int argc, char *argv[])
if (global_sp_updated) if (global_sp_updated)
orb_copy(ORB_ID(vehicle_global_position_setpoint), global_sp_sub, &global_sp); orb_copy(ORB_ID(vehicle_global_position_setpoint), global_sp_sub, &global_sp);
/* currently speed in body frame is not used, but here for reference */
if (pos_updated) { if (pos_updated) {
orb_copy(ORB_ID(vehicle_global_position), global_pos_sub, &global_pos); orb_copy(ORB_ID(vehicle_global_position), global_pos_sub, &global_pos);
@ -285,12 +364,19 @@ int fixedwing_control_thread_main(int argc, char *argv[])
} }
} }
orb_copy(ORB_ID(manual_control_setpoint), manual_sp_sub, &manual_sp); if (manual_sp_updated)
orb_copy(ORB_ID(vehicle_status), vstatus_sub, &vstatus); /* get the RC (or otherwise user based) input */
orb_copy(ORB_ID(manual_control_setpoint), manual_sp_sub, &manual_sp);
gyro[0] = att.rollspeed; /* check if the throttle was ever more than 50% - go later only to failsafe if yes */
gyro[1] = att.pitchspeed; if (isfinite(manual_sp.throttle) &&
gyro[2] = att.yawspeed; (manual_sp.throttle >= 0.6f) &&
(manual_sp.throttle <= 1.0f)) {
throttle_half_once = true;
}
/* get the system status and the flight mode we're in */
orb_copy(ORB_ID(vehicle_status), vstatus_sub, &vstatus);
/* control */ /* control */
@ -307,7 +393,7 @@ int fixedwing_control_thread_main(int argc, char *argv[])
actuators.control[2] = 0.0f; actuators.control[2] = 0.0f;
/* simple attitude control */ /* simple attitude control */
control_attitude(&att_sp, &att, speed_body, gyro, &rates_sp, &actuators); control_attitude(&att_sp, &att, speed_body, &rates_sp, &actuators);
/* pass through throttle */ /* pass through throttle */
actuators.control[3] = att_sp.thrust; actuators.control[3] = att_sp.thrust;
@ -316,10 +402,12 @@ int fixedwing_control_thread_main(int argc, char *argv[])
actuators.control[4] = 0.0f; actuators.control[4] = 0.0f;
} else if (vstatus.navigation_state == NAVIGATION_STATE_MANUAL) { } else if (vstatus.navigation_state == NAVIGATION_STATE_MANUAL) {
/* if in manual mode, decide between attitude stabilization (SAS) and full manual pass-through */
} else if (vstatus.state_machine == SYSTEM_STATE_MANUAL) {
if (vstatus.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS) { if (vstatus.manual_control_mode == VEHICLE_MANUAL_CONTROL_MODE_SAS) {
/* if the RC signal is lost, try to stay level and go slowly back down to ground */ /* if the RC signal is lost, try to stay level and go slowly back down to ground */
if (vstatus.rc_signal_lost) { if (vstatus.rc_signal_lost && throttle_half_once) {
/* put plane into loiter */ /* put plane into loiter */
att_sp.roll_body = 0.3f; att_sp.roll_body = 0.3f;
@ -350,7 +438,7 @@ int fixedwing_control_thread_main(int argc, char *argv[])
att_sp.timestamp = hrt_absolute_time(); att_sp.timestamp = hrt_absolute_time();
/* attitude control */ /* attitude control */
control_attitude(&att_sp, &att, speed_body, gyro, &rates_sp, &actuators); control_attitude(&att_sp, &att, speed_body, &rates_sp, &actuators);
/* pass through throttle */ /* pass through throttle */
actuators.control[3] = att_sp.thrust; actuators.control[3] = att_sp.thrust;

View File

@ -45,7 +45,7 @@
/** /**
* *
*/ */
PARAM_DEFINE_FLOAT(EXFW_HDNG_P, 0.2f); PARAM_DEFINE_FLOAT(EXFW_HDNG_P, 0.1f);
/** /**
* *

View File

@ -1,7 +1,6 @@
/**************************************************************************** /****************************************************************************
* *
* Copyright (C) 2012 PX4 Development Team. All rights reserved. * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
* Author: @author Example User <mail@example.com>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -33,27 +32,33 @@
****************************************************************************/ ****************************************************************************/
/** /**
* @file px4_deamon_app.c * @file px4_daemon_app.c
* Deamon application example for PX4 autopilot * daemon application example for PX4 autopilot
*
* @author Example User <mail@example.com>
*/ */
#include <nuttx/config.h> #include <nuttx/config.h>
#include <nuttx/sched.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
static bool thread_should_exit = false; /**< Deamon exit flag */ #include <systemlib/systemlib.h>
static bool thread_running = false; /**< Deamon status flag */ #include <systemlib/err.h>
static int deamon_task; /**< Handle of deamon task / thread */
static bool thread_should_exit = false; /**< daemon exit flag */
static bool thread_running = false; /**< daemon status flag */
static int daemon_task; /**< Handle of daemon task / thread */
/** /**
* Deamon management function. * daemon management function.
*/ */
__EXPORT int px4_deamon_app_main(int argc, char *argv[]); __EXPORT int px4_daemon_app_main(int argc, char *argv[]);
/** /**
* Mainloop of deamon. * Mainloop of daemon.
*/ */
int px4_deamon_thread_main(int argc, char *argv[]); int px4_daemon_thread_main(int argc, char *argv[]);
/** /**
* Print the correct usage. * Print the correct usage.
@ -64,20 +69,19 @@ static void
usage(const char *reason) usage(const char *reason)
{ {
if (reason) if (reason)
fprintf(stderr, "%s\n", reason); warnx("%s\n", reason);
fprintf(stderr, "usage: deamon {start|stop|status} [-p <additional params>]\n\n"); errx(1, "usage: daemon {start|stop|status} [-p <additional params>]\n\n");
exit(1);
} }
/** /**
* The deamon app only briefly exists to start * The daemon app only briefly exists to start
* the background job. The stack size assigned in the * the background job. The stack size assigned in the
* Makefile does only apply to this management task. * Makefile does only apply to this management task.
* *
* The actual stack size should be set in the call * The actual stack size should be set in the call
* to task_create(). * to task_create().
*/ */
int px4_deamon_app_main(int argc, char *argv[]) int px4_daemon_app_main(int argc, char *argv[])
{ {
if (argc < 1) if (argc < 1)
usage("missing command"); usage("missing command");
@ -85,17 +89,17 @@ int px4_deamon_app_main(int argc, char *argv[])
if (!strcmp(argv[1], "start")) { if (!strcmp(argv[1], "start")) {
if (thread_running) { if (thread_running) {
printf("deamon already running\n"); warnx("daemon already running\n");
/* this is not an error */ /* this is not an error */
exit(0); exit(0);
} }
thread_should_exit = false; thread_should_exit = false;
deamon_task = task_spawn("deamon", daemon_task = task_spawn("daemon",
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT, SCHED_PRIORITY_DEFAULT,
4096, 4096,
px4_deamon_thread_main, px4_daemon_thread_main,
(argv) ? (const char **)&argv[2] : (const char **)NULL); (argv) ? (const char **)&argv[2] : (const char **)NULL);
exit(0); exit(0);
} }
@ -107,9 +111,9 @@ int px4_deamon_app_main(int argc, char *argv[])
if (!strcmp(argv[1], "status")) { if (!strcmp(argv[1], "status")) {
if (thread_running) { if (thread_running) {
printf("\tdeamon app is running\n"); warnx("\trunning\n");
} else { } else {
printf("\tdeamon app not started\n"); warnx("\tnot started\n");
} }
exit(0); exit(0);
} }
@ -118,18 +122,18 @@ int px4_deamon_app_main(int argc, char *argv[])
exit(1); exit(1);
} }
int px4_deamon_thread_main(int argc, char *argv[]) { int px4_daemon_thread_main(int argc, char *argv[]) {
printf("[deamon] starting\n"); warnx("[daemon] starting\n");
thread_running = true; thread_running = true;
while (!thread_should_exit) { while (!thread_should_exit) {
printf("Hello Deamon!\n"); warnx("Hello daemon!\n");
sleep(10); sleep(10);
} }
printf("[deamon] exiting.\n"); warnx("[daemon] exiting.\n");
thread_running = false; thread_running = false;

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
* *
* Copyright (C) 2012 PX4 Development Team. All rights reserved. * Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
* Author: Lorenz Meier <lm@inf.ethz.ch> * Author: Lorenz Meier <lm@inf.ethz.ch>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -47,27 +47,42 @@
*/ */
#include <sys/ioctl.h> #include <sys/ioctl.h>
/* /**
* The mavlink log device node; must be opened before messages * The mavlink log device node; must be opened before messages
* can be logged. * can be logged.
*/ */
#define MAVLINK_LOG_DEVICE "/dev/mavlink" #define MAVLINK_LOG_DEVICE "/dev/mavlink"
/**
* The maximum string length supported.
*/
#define MAVLINK_LOG_MAXLEN 50
#define MAVLINK_IOC_SEND_TEXT_INFO _IOC(0x1100, 1) #define MAVLINK_IOC_SEND_TEXT_INFO _IOC(0x1100, 1)
#define MAVLINK_IOC_SEND_TEXT_CRITICAL _IOC(0x1100, 2) #define MAVLINK_IOC_SEND_TEXT_CRITICAL _IOC(0x1100, 2)
#define MAVLINK_IOC_SEND_TEXT_EMERGENCY _IOC(0x1100, 3) #define MAVLINK_IOC_SEND_TEXT_EMERGENCY _IOC(0x1100, 3)
#ifdef __cplusplus
extern "C" {
#endif
__EXPORT void mavlink_vasprintf(int _fd, int severity, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
/*
* The va_args implementation here is not beautiful, but obviously we run into the same issues
* the GCC devs saw, and are using their solution:
*
* http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
*/
/** /**
* Send a mavlink emergency message. * Send a mavlink emergency message.
* *
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#ifdef __cplusplus #define mavlink_log_emergency(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_EMERGENCY, _text, ##__VA_ARGS__);
#define mavlink_log_emergency(_fd, _text) ::ioctl(_fd, MAVLINK_IOC_SEND_TEXT_EMERGENCY, (unsigned long)_text);
#else
#define mavlink_log_emergency(_fd, _text) ioctl(_fd, MAVLINK_IOC_SEND_TEXT_EMERGENCY, (unsigned long)_text);
#endif
/** /**
* Send a mavlink critical message. * Send a mavlink critical message.
@ -75,11 +90,7 @@
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#ifdef __cplusplus #define mavlink_log_critical(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_CRITICAL, _text, ##__VA_ARGS__);
#define mavlink_log_critical(_fd, _text) ::ioctl(_fd, MAVLINK_IOC_SEND_TEXT_CRITICAL, (unsigned long)_text);
#else
#define mavlink_log_critical(_fd, _text) ioctl(_fd, MAVLINK_IOC_SEND_TEXT_CRITICAL, (unsigned long)_text);
#endif
/** /**
* Send a mavlink info message. * Send a mavlink info message.
@ -87,14 +98,10 @@
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#ifdef __cplusplus #define mavlink_log_info(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_INFO, _text, ##__VA_ARGS__);
#define mavlink_log_info(_fd, _text) ::ioctl(_fd, MAVLINK_IOC_SEND_TEXT_INFO, (unsigned long)_text);
#else
#define mavlink_log_info(_fd, _text) ioctl(_fd, MAVLINK_IOC_SEND_TEXT_INFO, (unsigned long)_text);
#endif
struct mavlink_logmessage { struct mavlink_logmessage {
char text[51]; char text[MAVLINK_LOG_MAXLEN + 1];
unsigned char severity; unsigned char severity;
}; };
@ -116,5 +123,7 @@ void mavlink_logbuffer_write(struct mavlink_logbuffer *lb, const struct mavlink_
int mavlink_logbuffer_read(struct mavlink_logbuffer *lb, struct mavlink_logmessage *elem); int mavlink_logbuffer_read(struct mavlink_logbuffer *lb, struct mavlink_logmessage *elem);
void mavlink_logbuffer_vasprintf(struct mavlink_logbuffer *lb, int severity, const char *fmt, ...);
#endif #endif

View File

@ -683,7 +683,8 @@ int KalmanNav::correctPos()
// fault detetcion // fault detetcion
float beta = y.dot(S.inverse() * y); float beta = y.dot(S.inverse() * y);
if (beta > _faultPos.get()) { static int counter = 0;
if (beta > _faultPos.get() && (counter % 10 == 0)) {
printf("fault in gps: beta = %8.4f\n", (double)beta); printf("fault in gps: beta = %8.4f\n", (double)beta);
printf("Y/N: vN: %8.4f, vE: %8.4f, lat: %8.4f, lon: %8.4f, alt: %8.4f\n", printf("Y/N: vN: %8.4f, vE: %8.4f, lat: %8.4f, lon: %8.4f, alt: %8.4f\n",
double(y(0) / sqrtf(RPos(0, 0))), double(y(0) / sqrtf(RPos(0, 0))),
@ -693,6 +694,7 @@ int KalmanNav::correctPos()
double(y(4) / sqrtf(RPos(4, 4))), double(y(4) / sqrtf(RPos(4, 4))),
double(y(5) / sqrtf(RPos(5, 5)))); double(y(5) / sqrtf(RPos(5, 5))));
} }
counter++;
return ret_ok; return ret_ok;
} }

View File

@ -44,6 +44,7 @@
#include <string.h> #include <string.h>
#include <systemlib/systemlib.h> #include <systemlib/systemlib.h>
#include <systemlib/param/param.h> #include <systemlib/param/param.h>
#include <systemlib/err.h>
#include <drivers/drv_hrt.h> #include <drivers/drv_hrt.h>
#include <math.h> #include <math.h>
#include "KalmanNav.hpp" #include "KalmanNav.hpp"
@ -73,7 +74,7 @@ usage(const char *reason)
if (reason) if (reason)
fprintf(stderr, "%s\n", reason); fprintf(stderr, "%s\n", reason);
fprintf(stderr, "usage: kalman_demo {start|stop|status} [-p <additional params>]\n\n"); warnx("usage: att_pos_estimator_ekf {start|stop|status} [-p <additional params>]");
exit(1); exit(1);
} }
@ -94,13 +95,13 @@ int att_pos_estimator_ekf_main(int argc, char *argv[])
if (!strcmp(argv[1], "start")) { if (!strcmp(argv[1], "start")) {
if (thread_running) { if (thread_running) {
printf("kalman_demo already running\n"); warnx("already running");
/* this is not an error */ /* this is not an error */
exit(0); exit(0);
} }
thread_should_exit = false; thread_should_exit = false;
deamon_task = task_spawn("kalman_demo", deamon_task = task_spawn("att_pos_estimator_ekf",
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 5, SCHED_PRIORITY_MAX - 5,
4096, 4096,
@ -116,10 +117,10 @@ int att_pos_estimator_ekf_main(int argc, char *argv[])
if (!strcmp(argv[1], "status")) { if (!strcmp(argv[1], "status")) {
if (thread_running) { if (thread_running) {
printf("\tkalman_demo app is running\n"); warnx("is running\n");
} else { } else {
printf("\tkalman_demo app not started\n"); warnx("not started\n");
} }
exit(0); exit(0);
@ -132,7 +133,7 @@ int att_pos_estimator_ekf_main(int argc, char *argv[])
int kalman_demo_thread_main(int argc, char *argv[]) int kalman_demo_thread_main(int argc, char *argv[])
{ {
printf("[kalman_demo] starting\n"); warnx("starting\n");
using namespace math; using namespace math;
@ -144,7 +145,7 @@ int kalman_demo_thread_main(int argc, char *argv[])
nav.update(); nav.update();
} }
printf("[kalman_demo] exiting.\n"); printf("exiting.\n");
thread_running = false; thread_running = false;

View File

@ -0,0 +1,5 @@
Synopsis
nsh> attitude_estimator_so3_comp start -d /dev/ttyS1 -b 115200
Option -d is for debugging packet. See code for detailed packet structure.

View File

@ -0,0 +1,833 @@
/*
* Author: Hyon Lim <limhyon@gmail.com, hyonlim@snu.ac.kr>
*
* @file attitude_estimator_so3_comp_main.c
*
* Implementation of nonlinear complementary filters on the SO(3).
* This code performs attitude estimation by using accelerometer, gyroscopes and magnetometer.
* Result is provided as quaternion, 1-2-3 Euler angle and rotation matrix.
*
* Theory of nonlinear complementary filters on the SO(3) is based on [1].
* Quaternion realization of [1] is based on [2].
* Optmized quaternion update code is based on Sebastian Madgwick's implementation.
*
* References
* [1] Mahony, R.; Hamel, T.; Pflimlin, Jean-Michel, "Nonlinear Complementary Filters on the Special Orthogonal Group," Automatic Control, IEEE Transactions on , vol.53, no.5, pp.1203,1218, June 2008
* [2] Euston, M.; Coote, P.; Mahony, R.; Jonghyuk Kim; Hamel, T., "A complementary filter for attitude estimation of a fixed-wing UAV," Intelligent Robots and Systems, 2008. IROS 2008. IEEE/RSJ International Conference on , vol., no., pp.340,345, 22-26 Sept. 2008
*/
#include <nuttx/config.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <poll.h>
#include <fcntl.h>
#include <float.h>
#include <nuttx/sched.h>
#include <sys/prctl.h>
#include <termios.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <uORB/uORB.h>
#include <uORB/topics/debug_key_value.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/vehicle_status.h>
#include <uORB/topics/parameter_update.h>
#include <drivers/drv_hrt.h>
#include <systemlib/systemlib.h>
#include <systemlib/perf_counter.h>
#include <systemlib/err.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "attitude_estimator_so3_comp_params.h"
#ifdef __cplusplus
}
#endif
extern "C" __EXPORT int attitude_estimator_so3_comp_main(int argc, char *argv[]);
static bool thread_should_exit = false; /**< Deamon exit flag */
static bool thread_running = false; /**< Deamon status flag */
static int attitude_estimator_so3_comp_task; /**< Handle of deamon task / thread */
static float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
static float dq0 = 0.0f, dq1 = 0.0f, dq2 = 0.0f, dq3 = 0.0f; /** quaternion of sensor frame relative to auxiliary frame */
static float gyro_bias[3] = {0.0f, 0.0f, 0.0f}; /** bias estimation */
static bool bFilterInit = false;
//! Auxiliary variables to reduce number of repeated operations
static float q0q0, q0q1, q0q2, q0q3;
static float q1q1, q1q2, q1q3;
static float q2q2, q2q3;
static float q3q3;
//! Serial packet related
static int uart;
static int baudrate;
/**
* Mainloop of attitude_estimator_so3_comp.
*/
int attitude_estimator_so3_comp_thread_main(int argc, char *argv[]);
/**
* Print the correct usage.
*/
static void usage(const char *reason);
static void
usage(const char *reason)
{
if (reason)
fprintf(stderr, "%s\n", reason);
fprintf(stderr, "usage: attitude_estimator_so3_comp {start|stop|status} [-d <devicename>] [-b <baud rate>]\n"
"-d and -b options are for separate visualization with raw data (quaternion packet) transfer\n"
"ex) attitude_estimator_so3_comp start -d /dev/ttyS1 -b 115200\n");
exit(1);
}
/**
* The attitude_estimator_so3_comp app only briefly exists to start
* the background job. The stack size assigned in the
* Makefile does only apply to this management task.
*
* The actual stack size should be set in the call
* to task_create().
*/
int attitude_estimator_so3_comp_main(int argc, char *argv[])
{
if (argc < 1)
usage("missing command");
if (!strcmp(argv[1], "start")) {
if (thread_running) {
printf("attitude_estimator_so3_comp already running\n");
/* this is not an error */
exit(0);
}
thread_should_exit = false;
attitude_estimator_so3_comp_task = task_spawn("attitude_estimator_so3_comp",
SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 5,
12400,
attitude_estimator_so3_comp_thread_main,
(const char **)argv);
exit(0);
}
if (!strcmp(argv[1], "stop")) {
thread_should_exit = true;
while(thread_running){
usleep(200000);
printf(".");
}
printf("terminated.");
exit(0);
}
if (!strcmp(argv[1], "status")) {
if (thread_running) {
printf("\tattitude_estimator_so3_comp app is running\n");
} else {
printf("\tattitude_estimator_so3_comp app not started\n");
}
exit(0);
}
usage("unrecognized command");
exit(1);
}
//---------------------------------------------------------------------------------------------------
// Fast inverse square-root
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
float invSqrt(float number) {
volatile long i;
volatile float x, y;
volatile const float f = 1.5F;
x = number * 0.5F;
y = number;
i = * (( long * ) &y);
i = 0x5f375a86 - ( i >> 1 );
y = * (( float * ) &i);
y = y * ( f - ( x * y * y ) );
return y;
}
//! Using accelerometer, sense the gravity vector.
//! Using magnetometer, sense yaw.
void NonlinearSO3AHRSinit(float ax, float ay, float az, float mx, float my, float mz)
{
float initialRoll, initialPitch;
float cosRoll, sinRoll, cosPitch, sinPitch;
float magX, magY;
float initialHdg, cosHeading, sinHeading;
initialRoll = atan2(-ay, -az);
initialPitch = atan2(ax, -az);
cosRoll = cosf(initialRoll);
sinRoll = sinf(initialRoll);
cosPitch = cosf(initialPitch);
sinPitch = sinf(initialPitch);
magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch;
magY = my * cosRoll - mz * sinRoll;
initialHdg = atan2f(-magY, magX);
cosRoll = cosf(initialRoll * 0.5f);
sinRoll = sinf(initialRoll * 0.5f);
cosPitch = cosf(initialPitch * 0.5f);
sinPitch = sinf(initialPitch * 0.5f);
cosHeading = cosf(initialHdg * 0.5f);
sinHeading = sinf(initialHdg * 0.5f);
q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading;
q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading;
q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading;
q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading;
// auxillary variables to reduce number of repeated operations, for 1st pass
q0q0 = q0 * q0;
q0q1 = q0 * q1;
q0q2 = q0 * q2;
q0q3 = q0 * q3;
q1q1 = q1 * q1;
q1q2 = q1 * q2;
q1q3 = q1 * q3;
q2q2 = q2 * q2;
q2q3 = q2 * q3;
q3q3 = q3 * q3;
}
void NonlinearSO3AHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float twoKp, float twoKi, float dt) {
float recipNorm;
float halfex = 0.0f, halfey = 0.0f, halfez = 0.0f;
//! Make filter converge to initial solution faster
//! This function assumes you are in static position.
//! WARNING : in case air reboot, this can cause problem. But this is very
//! unlikely happen.
if(bFilterInit == false)
{
NonlinearSO3AHRSinit(ax,ay,az,mx,my,mz);
bFilterInit = true;
}
//! If magnetometer measurement is available, use it.
if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {
float hx, hy, hz, bx, bz;
float halfwx, halfwy, halfwz;
// Normalise magnetometer measurement
// Will sqrt work better? PX4 system is powerful enough?
recipNorm = invSqrt(mx * mx + my * my + mz * mz);
mx *= recipNorm;
my *= recipNorm;
mz *= recipNorm;
// Reference direction of Earth's magnetic field
hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
hz = 2 * mx * (q1q3 - q0q2) + 2 * my * (q2q3 + q0q1) + 2 * mz * (0.5 - q1q1 - q2q2);
bx = sqrt(hx * hx + hy * hy);
bz = hz;
// Estimated direction of magnetic field
halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);
// Error is sum of cross product between estimated direction and measured direction of field vectors
halfex += (my * halfwz - mz * halfwy);
halfey += (mz * halfwx - mx * halfwz);
halfez += (mx * halfwy - my * halfwx);
}
// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
float halfvx, halfvy, halfvz;
// Normalise accelerometer measurement
recipNorm = invSqrt(ax * ax + ay * ay + az * az);
ax *= recipNorm;
ay *= recipNorm;
az *= recipNorm;
// Estimated direction of gravity and magnetic field
halfvx = q1q3 - q0q2;
halfvy = q0q1 + q2q3;
halfvz = q0q0 - 0.5f + q3q3;
// Error is sum of cross product between estimated direction and measured direction of field vectors
halfex += ay * halfvz - az * halfvy;
halfey += az * halfvx - ax * halfvz;
halfez += ax * halfvy - ay * halfvx;
}
// Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) {
// Compute and apply integral feedback if enabled
if(twoKi > 0.0f) {
gyro_bias[0] += twoKi * halfex * dt; // integral error scaled by Ki
gyro_bias[1] += twoKi * halfey * dt;
gyro_bias[2] += twoKi * halfez * dt;
gx += gyro_bias[0]; // apply integral feedback
gy += gyro_bias[1];
gz += gyro_bias[2];
}
else {
gyro_bias[0] = 0.0f; // prevent integral windup
gyro_bias[1] = 0.0f;
gyro_bias[2] = 0.0f;
}
// Apply proportional feedback
gx += twoKp * halfex;
gy += twoKp * halfey;
gz += twoKp * halfez;
}
//! Integrate rate of change of quaternion
#if 0
gx *= (0.5f * dt); // pre-multiply common factors
gy *= (0.5f * dt);
gz *= (0.5f * dt);
#endif
// Time derivative of quaternion. q_dot = 0.5*q\otimes omega.
//! q_k = q_{k-1} + dt*\dot{q}
//! \dot{q} = 0.5*q \otimes P(\omega)
dq0 = 0.5f*(-q1 * gx - q2 * gy - q3 * gz);
dq1 = 0.5f*(q0 * gx + q2 * gz - q3 * gy);
dq2 = 0.5f*(q0 * gy - q1 * gz + q3 * gx);
dq3 = 0.5f*(q0 * gz + q1 * gy - q2 * gx);
q0 += dt*dq0;
q1 += dt*dq1;
q2 += dt*dq2;
q3 += dt*dq3;
// Normalise quaternion
recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
q0 *= recipNorm;
q1 *= recipNorm;
q2 *= recipNorm;
q3 *= recipNorm;
// Auxiliary variables to avoid repeated arithmetic
q0q0 = q0 * q0;
q0q1 = q0 * q1;
q0q2 = q0 * q2;
q0q3 = q0 * q3;
q1q1 = q1 * q1;
q1q2 = q1 * q2;
q1q3 = q1 * q3;
q2q2 = q2 * q2;
q2q3 = q2 * q3;
q3q3 = q3 * q3;
}
void send_uart_byte(char c)
{
write(uart,&c,1);
}
void send_uart_bytes(uint8_t *data, int length)
{
write(uart,data,(size_t)(sizeof(uint8_t)*length));
}
void send_uart_float(float f) {
uint8_t * b = (uint8_t *) &f;
//! Assume float is 4-bytes
for(int i=0; i<4; i++) {
uint8_t b1 = (b[i] >> 4) & 0x0f;
uint8_t b2 = (b[i] & 0x0f);
uint8_t c1 = (b1 < 10) ? ('0' + b1) : 'A' + b1 - 10;
uint8_t c2 = (b2 < 10) ? ('0' + b2) : 'A' + b2 - 10;
send_uart_bytes(&c1,1);
send_uart_bytes(&c2,1);
}
}
void send_uart_float_arr(float *arr, int length)
{
for(int i=0;i<length;++i)
{
send_uart_float(arr[i]);
send_uart_byte(',');
}
}
int open_uart(int baud, const char *uart_name, struct termios *uart_config_original, bool *is_usb)
{
int speed;
switch (baud) {
case 0: speed = B0; break;
case 50: speed = B50; break;
case 75: speed = B75; break;
case 110: speed = B110; break;
case 134: speed = B134; break;
case 150: speed = B150; break;
case 200: speed = B200; break;
case 300: speed = B300; break;
case 600: speed = B600; break;
case 1200: speed = B1200; break;
case 1800: speed = B1800; break;
case 2400: speed = B2400; break;
case 4800: speed = B4800; break;
case 9600: speed = B9600; break;
case 19200: speed = B19200; break;
case 38400: speed = B38400; break;
case 57600: speed = B57600; break;
case 115200: speed = B115200; break;
case 230400: speed = B230400; break;
case 460800: speed = B460800; break;
case 921600: speed = B921600; break;
default:
printf("ERROR: Unsupported baudrate: %d\n\tsupported examples:\n\n\t9600\n19200\n38400\n57600\n115200\n230400\n460800\n921600\n\n", baud);
return -EINVAL;
}
printf("[so3_comp_filt] UART is %s, baudrate is %d\n", uart_name, baud);
uart = open(uart_name, O_RDWR | O_NOCTTY);
/* Try to set baud rate */
struct termios uart_config;
int termios_state;
*is_usb = false;
/* make some wild guesses including that USB serial is indicated by either /dev/ttyACM0 or /dev/console */
if (strcmp(uart_name, "/dev/ttyACM0") != OK && strcmp(uart_name, "/dev/console") != OK) {
/* Back up the original uart configuration to restore it after exit */
if ((termios_state = tcgetattr(uart, uart_config_original)) < 0) {
printf("ERROR getting baudrate / termios config for %s: %d\n", uart_name, termios_state);
close(uart);
return -1;
}
/* Fill the struct for the new configuration */
tcgetattr(uart, &uart_config);
/* Clear ONLCR flag (which appends a CR for every LF) */
uart_config.c_oflag &= ~ONLCR;
/* Set baud rate */
if (cfsetispeed(&uart_config, speed) < 0 || cfsetospeed(&uart_config, speed) < 0) {
printf("ERROR setting baudrate / termios config for %s: %d (cfsetispeed, cfsetospeed)\n", uart_name, termios_state);
close(uart);
return -1;
}
if ((termios_state = tcsetattr(uart, TCSANOW, &uart_config)) < 0) {
printf("ERROR setting baudrate / termios config for %s (tcsetattr)\n", uart_name);
close(uart);
return -1;
}
} else {
*is_usb = true;
}
return uart;
}
/*
* [Rot_matrix,x_aposteriori,P_aposteriori] = attitudeKalmanfilter(dt,z_k,x_aposteriori_k,P_aposteriori_k,knownConst)
*/
/*
* EKF Attitude Estimator main function.
*
* Estimates the attitude recursively once started.
*
* @param argc number of commandline arguments (plus command name)
* @param argv strings containing the arguments
*/
int attitude_estimator_so3_comp_thread_main(int argc, char *argv[])
{
const unsigned int loop_interval_alarm = 6500; // loop interval in microseconds
//! Serial debug related
int ch;
struct termios uart_config_original;
bool usb_uart;
bool debug_mode = false;
char *device_name = "/dev/ttyS2";
baudrate = 115200;
//! Time constant
float dt = 0.005f;
/* output euler angles */
float euler[3] = {0.0f, 0.0f, 0.0f};
float Rot_matrix[9] = {1.f, 0, 0,
0, 1.f, 0,
0, 0, 1.f
}; /**< init: identity matrix */
float acc[3] = {0.0f, 0.0f, 0.0f};
float gyro[3] = {0.0f, 0.0f, 0.0f};
float mag[3] = {0.0f, 0.0f, 0.0f};
/* work around some stupidity in task_create's argv handling */
argc -= 2;
argv += 2;
//! -d <device_name>, default : /dev/ttyS2
//! -b <baud_rate>, default : 115200
while ((ch = getopt(argc,argv,"d:b:")) != EOF){
switch(ch){
case 'b':
baudrate = strtoul(optarg, NULL, 10);
if(baudrate == 0)
printf("invalid baud rate '%s'",optarg);
break;
case 'd':
device_name = optarg;
debug_mode = true;
break;
default:
usage("invalid argument");
}
}
if(debug_mode){
printf("Opening debugging port for 3D visualization\n");
uart = open_uart(baudrate, device_name, &uart_config_original, &usb_uart);
if (uart < 0)
printf("could not open %s", device_name);
else
printf("Open port success\n");
}
// print text
printf("Nonlinear SO3 Attitude Estimator initialized..\n\n");
fflush(stdout);
int overloadcounter = 19;
/* store start time to guard against too slow update rates */
uint64_t last_run = hrt_absolute_time();
struct sensor_combined_s raw;
memset(&raw, 0, sizeof(raw));
//! Initialize attitude vehicle uORB message.
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));
struct vehicle_status_s state;
memset(&state, 0, sizeof(state));
uint64_t last_data = 0;
uint64_t last_measurement = 0;
/* subscribe to raw data */
int sub_raw = orb_subscribe(ORB_ID(sensor_combined));
/* rate-limit raw data updates to 200Hz */
orb_set_interval(sub_raw, 4);
/* subscribe to param changes */
int sub_params = orb_subscribe(ORB_ID(parameter_update));
/* subscribe to system state*/
int sub_state = orb_subscribe(ORB_ID(vehicle_status));
/* advertise attitude */
orb_advert_t pub_att = orb_advertise(ORB_ID(vehicle_attitude), &att);
int loopcounter = 0;
int printcounter = 0;
thread_running = true;
/* advertise debug value */
// struct debug_key_value_s dbg = { .key = "", .value = 0.0f };
// orb_advert_t pub_dbg = -1;
float sensor_update_hz[3] = {0.0f, 0.0f, 0.0f};
// XXX write this out to perf regs
/* keep track of sensor updates */
uint32_t sensor_last_count[3] = {0, 0, 0};
uint64_t sensor_last_timestamp[3] = {0, 0, 0};
struct attitude_estimator_so3_comp_params so3_comp_params;
struct attitude_estimator_so3_comp_param_handles so3_comp_param_handles;
/* initialize parameter handles */
parameters_init(&so3_comp_param_handles);
uint64_t start_time = hrt_absolute_time();
bool initialized = false;
float gyro_offsets[3] = { 0.0f, 0.0f, 0.0f };
unsigned offset_count = 0;
/* register the perf counter */
perf_counter_t so3_comp_loop_perf = perf_alloc(PC_ELAPSED, "attitude_estimator_so3_comp");
/* Main loop*/
while (!thread_should_exit) {
struct pollfd fds[2];
fds[0].fd = sub_raw;
fds[0].events = POLLIN;
fds[1].fd = sub_params;
fds[1].events = POLLIN;
int ret = poll(fds, 2, 1000);
if (ret < 0) {
/* XXX this is seriously bad - should be an emergency */
} else if (ret == 0) {
/* check if we're in HIL - not getting sensor data is fine then */
orb_copy(ORB_ID(vehicle_status), sub_state, &state);
if (!state.flag_hil_enabled) {
fprintf(stderr,
"[att so3_comp] WARNING: Not getting sensors - sensor app running?\n");
}
} else {
/* only update parameters if they changed */
if (fds[1].revents & POLLIN) {
/* read from param to clear updated flag */
struct parameter_update_s update;
orb_copy(ORB_ID(parameter_update), sub_params, &update);
/* update parameters */
parameters_update(&so3_comp_param_handles, &so3_comp_params);
}
/* only run filter if sensor values changed */
if (fds[0].revents & POLLIN) {
/* get latest measurements */
orb_copy(ORB_ID(sensor_combined), sub_raw, &raw);
if (!initialized) {
gyro_offsets[0] += raw.gyro_rad_s[0];
gyro_offsets[1] += raw.gyro_rad_s[1];
gyro_offsets[2] += raw.gyro_rad_s[2];
offset_count++;
if (hrt_absolute_time() - start_time > 3000000LL) {
initialized = true;
gyro_offsets[0] /= offset_count;
gyro_offsets[1] /= offset_count;
gyro_offsets[2] /= offset_count;
}
} else {
perf_begin(so3_comp_loop_perf);
/* Calculate data time difference in seconds */
dt = (raw.timestamp - last_measurement) / 1000000.0f;
last_measurement = raw.timestamp;
uint8_t update_vect[3] = {0, 0, 0};
/* Fill in gyro measurements */
if (sensor_last_count[0] != raw.gyro_counter) {
update_vect[0] = 1;
sensor_last_count[0] = raw.gyro_counter;
sensor_update_hz[0] = 1e6f / (raw.timestamp - sensor_last_timestamp[0]);
sensor_last_timestamp[0] = raw.timestamp;
}
gyro[0] = raw.gyro_rad_s[0] - gyro_offsets[0];
gyro[1] = raw.gyro_rad_s[1] - gyro_offsets[1];
gyro[2] = raw.gyro_rad_s[2] - gyro_offsets[2];
/* update accelerometer measurements */
if (sensor_last_count[1] != raw.accelerometer_counter) {
update_vect[1] = 1;
sensor_last_count[1] = raw.accelerometer_counter;
sensor_update_hz[1] = 1e6f / (raw.timestamp - sensor_last_timestamp[1]);
sensor_last_timestamp[1] = raw.timestamp;
}
acc[0] = raw.accelerometer_m_s2[0];
acc[1] = raw.accelerometer_m_s2[1];
acc[2] = raw.accelerometer_m_s2[2];
/* update magnetometer measurements */
if (sensor_last_count[2] != raw.magnetometer_counter) {
update_vect[2] = 1;
sensor_last_count[2] = raw.magnetometer_counter;
sensor_update_hz[2] = 1e6f / (raw.timestamp - sensor_last_timestamp[2]);
sensor_last_timestamp[2] = raw.timestamp;
}
mag[0] = raw.magnetometer_ga[0];
mag[1] = raw.magnetometer_ga[1];
mag[2] = raw.magnetometer_ga[2];
uint64_t now = hrt_absolute_time();
unsigned int time_elapsed = now - last_run;
last_run = now;
if (time_elapsed > loop_interval_alarm) {
//TODO: add warning, cpu overload here
// if (overloadcounter == 20) {
// printf("CPU OVERLOAD DETECTED IN ATTITUDE ESTIMATOR EKF (%lu > %lu)\n", time_elapsed, loop_interval_alarm);
// overloadcounter = 0;
// }
overloadcounter++;
}
static bool const_initialized = false;
/* initialize with good values once we have a reasonable dt estimate */
if (!const_initialized && dt < 0.05f && dt > 0.005f) {
dt = 0.005f;
parameters_update(&so3_comp_param_handles, &so3_comp_params);
const_initialized = true;
}
/* do not execute the filter if not initialized */
if (!const_initialized) {
continue;
}
uint64_t timing_start = hrt_absolute_time();
// NOTE : Accelerometer is reversed.
// Because proper mount of PX4 will give you a reversed accelerometer readings.
NonlinearSO3AHRSupdate(gyro[0],gyro[1],gyro[2],-acc[0],-acc[1],-acc[2],mag[0],mag[1],mag[2],so3_comp_params.Kp,so3_comp_params.Ki, dt);
// Convert q->R.
Rot_matrix[0] = q0q0 + q1q1 - q2q2 - q3q3;// 11
Rot_matrix[1] = 2.0 * (q1*q2 + q0*q3); // 12
Rot_matrix[2] = 2.0 * (q1*q3 - q0*q2); // 13
Rot_matrix[3] = 2.0 * (q1*q2 - q0*q3); // 21
Rot_matrix[4] = q0q0 - q1q1 + q2q2 - q3q3;// 22
Rot_matrix[5] = 2.0 * (q2*q3 + q0*q1); // 23
Rot_matrix[6] = 2.0 * (q1*q3 + q0*q2); // 31
Rot_matrix[7] = 2.0 * (q2*q3 - q0*q1); // 32
Rot_matrix[8] = q0q0 - q1q1 - q2q2 + q3q3;// 33
//1-2-3 Representation.
//Equation (290)
//Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors, James Diebel.
// Existing PX4 EKF code was generated by MATLAB which uses coloum major order matrix.
euler[0] = atan2f(Rot_matrix[5], Rot_matrix[8]); //! Roll
euler[1] = -asinf(Rot_matrix[2]); //! Pitch
euler[2] = atan2f(Rot_matrix[1],Rot_matrix[0]); //! Yaw
/* swap values for next iteration, check for fatal inputs */
if (isfinite(euler[0]) && isfinite(euler[1]) && isfinite(euler[2])) {
/* Do something */
} else {
/* due to inputs or numerical failure the output is invalid, skip it */
continue;
}
if (last_data > 0 && raw.timestamp - last_data > 12000) printf("[attitude estimator so3_comp] sensor data missed! (%llu)\n", raw.timestamp - last_data);
last_data = raw.timestamp;
/* send out */
att.timestamp = raw.timestamp;
// XXX Apply the same transformation to the rotation matrix
att.roll = euler[0] - so3_comp_params.roll_off;
att.pitch = euler[1] - so3_comp_params.pitch_off;
att.yaw = euler[2] - so3_comp_params.yaw_off;
//! Euler angle rate. But it needs to be investigated again.
/*
att.rollspeed = 2.0f*(-q1*dq0 + q0*dq1 - q3*dq2 + q2*dq3);
att.pitchspeed = 2.0f*(-q2*dq0 + q3*dq1 + q0*dq2 - q1*dq3);
att.yawspeed = 2.0f*(-q3*dq0 -q2*dq1 + q1*dq2 + q0*dq3);
*/
att.rollspeed = gyro[0];
att.pitchspeed = gyro[1];
att.yawspeed = gyro[2];
att.rollacc = 0;
att.pitchacc = 0;
att.yawacc = 0;
//! Quaternion
att.q[0] = q0;
att.q[1] = q1;
att.q[2] = q2;
att.q[3] = q3;
att.q_valid = true;
/* TODO: Bias estimation required */
memcpy(&att.rate_offsets, &(gyro_bias), sizeof(att.rate_offsets));
/* copy rotation matrix */
memcpy(&att.R, Rot_matrix, sizeof(Rot_matrix));
att.R_valid = true;
if (isfinite(att.roll) && isfinite(att.pitch) && isfinite(att.yaw)) {
// Broadcast
orb_publish(ORB_ID(vehicle_attitude), pub_att, &att);
} else {
warnx("NaN in roll/pitch/yaw estimate!");
}
perf_end(so3_comp_loop_perf);
//! This will print out debug packet to visualization software
if(debug_mode)
{
float quat[4];
quat[0] = q0;
quat[1] = q1;
quat[2] = q2;
quat[3] = q3;
send_uart_float_arr(quat,4);
send_uart_byte('\n');
}
}
}
}
loopcounter++;
}// while
thread_running = false;
/* Reset the UART flags to original state */
if (!usb_uart)
tcsetattr(uart, TCSANOW, &uart_config_original);
return 0;
}

View File

@ -0,0 +1,63 @@
/*
* Author: Hyon Lim <limhyon@gmail.com, hyonlim@snu.ac.kr>
*
* @file attitude_estimator_so3_comp_params.c
*
* Implementation of nonlinear complementary filters on the SO(3).
* This code performs attitude estimation by using accelerometer, gyroscopes and magnetometer.
* Result is provided as quaternion, 1-2-3 Euler angle and rotation matrix.
*
* Theory of nonlinear complementary filters on the SO(3) is based on [1].
* Quaternion realization of [1] is based on [2].
* Optmized quaternion update code is based on Sebastian Madgwick's implementation.
*
* References
* [1] Mahony, R.; Hamel, T.; Pflimlin, Jean-Michel, "Nonlinear Complementary Filters on the Special Orthogonal Group," Automatic Control, IEEE Transactions on , vol.53, no.5, pp.1203,1218, June 2008
* [2] Euston, M.; Coote, P.; Mahony, R.; Jonghyuk Kim; Hamel, T., "A complementary filter for attitude estimation of a fixed-wing UAV," Intelligent Robots and Systems, 2008. IROS 2008. IEEE/RSJ International Conference on , vol., no., pp.340,345, 22-26 Sept. 2008
*/
#include "attitude_estimator_so3_comp_params.h"
/* This is filter gain for nonlinear SO3 complementary filter */
/* NOTE : How to tune the gain? First of all, stick with this default gain. And let the quad in stable place.
Log the steady state reponse of filter. If it is too slow, increase SO3_COMP_KP.
If you are flying from ground to high altitude in short amount of time, please increase SO3_COMP_KI which
will compensate gyro bias which depends on temperature and vibration of your vehicle */
PARAM_DEFINE_FLOAT(SO3_COMP_KP, 1.0f); //! This parameter will give you about 15 seconds convergence time.
//! You can set this gain higher if you want more fast response.
//! But note that higher gain will give you also higher overshoot.
PARAM_DEFINE_FLOAT(SO3_COMP_KI, 0.05f); //! This gain will incorporate slow time-varying bias (e.g., temperature change)
//! This gain is depend on your vehicle status.
/* offsets in roll, pitch and yaw of sensor plane and body */
PARAM_DEFINE_FLOAT(ATT_ROLL_OFFS, 0.0f);
PARAM_DEFINE_FLOAT(ATT_PITCH_OFFS, 0.0f);
PARAM_DEFINE_FLOAT(ATT_YAW_OFFS, 0.0f);
int parameters_init(struct attitude_estimator_so3_comp_param_handles *h)
{
/* Filter gain parameters */
h->Kp = param_find("SO3_COMP_KP");
h->Ki = param_find("SO3_COMP_KI");
/* Attitude offset (WARNING: Do not change if you do not know what exactly this variable wil lchange) */
h->roll_off = param_find("ATT_ROLL_OFFS");
h->pitch_off = param_find("ATT_PITCH_OFFS");
h->yaw_off = param_find("ATT_YAW_OFFS");
return OK;
}
int parameters_update(const struct attitude_estimator_so3_comp_param_handles *h, struct attitude_estimator_so3_comp_params *p)
{
/* Update filter gain */
param_get(h->Kp, &(p->Kp));
param_get(h->Ki, &(p->Ki));
/* Update attitude offset */
param_get(h->roll_off, &(p->roll_off));
param_get(h->pitch_off, &(p->pitch_off));
param_get(h->yaw_off, &(p->yaw_off));
return OK;
}

View File

@ -0,0 +1,44 @@
/*
* Author: Hyon Lim <limhyon@gmail.com, hyonlim@snu.ac.kr>
*
* @file attitude_estimator_so3_comp_params.h
*
* Implementation of nonlinear complementary filters on the SO(3).
* This code performs attitude estimation by using accelerometer, gyroscopes and magnetometer.
* Result is provided as quaternion, 1-2-3 Euler angle and rotation matrix.
*
* Theory of nonlinear complementary filters on the SO(3) is based on [1].
* Quaternion realization of [1] is based on [2].
* Optmized quaternion update code is based on Sebastian Madgwick's implementation.
*
* References
* [1] Mahony, R.; Hamel, T.; Pflimlin, Jean-Michel, "Nonlinear Complementary Filters on the Special Orthogonal Group," Automatic Control, IEEE Transactions on , vol.53, no.5, pp.1203,1218, June 2008
* [2] Euston, M.; Coote, P.; Mahony, R.; Jonghyuk Kim; Hamel, T., "A complementary filter for attitude estimation of a fixed-wing UAV," Intelligent Robots and Systems, 2008. IROS 2008. IEEE/RSJ International Conference on , vol., no., pp.340,345, 22-26 Sept. 2008
*/
#include <systemlib/param/param.h>
struct attitude_estimator_so3_comp_params {
float Kp;
float Ki;
float roll_off;
float pitch_off;
float yaw_off;
};
struct attitude_estimator_so3_comp_param_handles {
param_t Kp, Ki;
param_t roll_off, pitch_off, yaw_off;
};
/**
* Initialize all parameter handles and values
*
*/
int parameters_init(struct attitude_estimator_so3_comp_param_handles *h);
/**
* Update all parameters
*
*/
int parameters_update(const struct attitude_estimator_so3_comp_param_handles *h, struct attitude_estimator_so3_comp_params *p);

View File

@ -0,0 +1,8 @@
#
# Attitude estimator (Nonlinear SO3 complementary Filter)
#
MODULE_COMMAND = attitude_estimator_so3_comp
SRCS = attitude_estimator_so3_comp_main.cpp \
attitude_estimator_so3_comp_params.c

View File

@ -47,6 +47,7 @@
#include <systemlib/systemlib.h> #include <systemlib/systemlib.h>
#include <controllib/fixedwing.hpp> #include <controllib/fixedwing.hpp>
#include <systemlib/param/param.h> #include <systemlib/param/param.h>
#include <systemlib/err.h>
#include <drivers/drv_hrt.h> #include <drivers/drv_hrt.h>
#include <math.h> #include <math.h>
@ -80,7 +81,7 @@ usage(const char *reason)
if (reason) if (reason)
fprintf(stderr, "%s\n", reason); fprintf(stderr, "%s\n", reason);
fprintf(stderr, "usage: control_demo {start|stop|status} [-p <additional params>]\n\n"); fprintf(stderr, "usage: fixedwing_backside {start|stop|status} [-p <additional params>]\n\n");
exit(1); exit(1);
} }
@ -101,13 +102,13 @@ int fixedwing_backside_main(int argc, char *argv[])
if (!strcmp(argv[1], "start")) { if (!strcmp(argv[1], "start")) {
if (thread_running) { if (thread_running) {
printf("control_demo already running\n"); warnx("already running");
/* this is not an error */ /* this is not an error */
exit(0); exit(0);
} }
thread_should_exit = false; thread_should_exit = false;
deamon_task = task_spawn("control_demo", deamon_task = task_spawn("fixedwing_backside",
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 10, SCHED_PRIORITY_MAX - 10,
5120, 5120,
@ -128,10 +129,10 @@ int fixedwing_backside_main(int argc, char *argv[])
if (!strcmp(argv[1], "status")) { if (!strcmp(argv[1], "status")) {
if (thread_running) { if (thread_running) {
printf("\tcontrol_demo app is running\n"); warnx("is running");
} else { } else {
printf("\tcontrol_demo app not started\n"); warnx("not started");
} }
exit(0); exit(0);
@ -144,7 +145,7 @@ int fixedwing_backside_main(int argc, char *argv[])
int control_demo_thread_main(int argc, char *argv[]) int control_demo_thread_main(int argc, char *argv[])
{ {
printf("[control_Demo] starting\n"); warnx("starting");
using namespace control; using namespace control;
@ -156,7 +157,7 @@ int control_demo_thread_main(int argc, char *argv[])
autopilot.update(); autopilot.update();
} }
printf("[control_demo] exiting.\n"); warnx("exiting.");
thread_running = false; thread_running = false;
@ -165,6 +166,6 @@ int control_demo_thread_main(int argc, char *argv[])
void test() void test()
{ {
printf("beginning control lib test\n"); warnx("beginning control lib test");
control::basicBlocksTest(); control::basicBlocksTest();
} }

View File

@ -37,4 +37,5 @@
MODULE_COMMAND = fixedwing_backside MODULE_COMMAND = fixedwing_backside
SRCS = fixedwing_backside_main.cpp SRCS = fixedwing_backside_main.cpp \
params.c

View File

@ -0,0 +1,217 @@
/****************************************************************************
*
* Copyright (c) 2013 PX4 Development Team. All rights reserved.
* Author: Anton Babushkin <anton.babushkin@me.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file gpio_led.c
*
* Status LED via GPIO driver.
*
* @author Anton Babushkin <anton.babushkin@me.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdbool.h>
#include <nuttx/wqueue.h>
#include <nuttx/clock.h>
#include <systemlib/systemlib.h>
#include <systemlib/err.h>
#include <uORB/uORB.h>
#include <uORB/topics/vehicle_status.h>
#include <poll.h>
#include <drivers/drv_gpio.h>
struct gpio_led_s {
struct work_s work;
int gpio_fd;
int pin;
struct vehicle_status_s status;
int vehicle_status_sub;
bool led_state;
int counter;
};
static struct gpio_led_s gpio_led_data;
static bool gpio_led_started = false;
__EXPORT int gpio_led_main(int argc, char *argv[]);
void gpio_led_start(FAR void *arg);
void gpio_led_cycle(FAR void *arg);
int gpio_led_main(int argc, char *argv[])
{
int pin = GPIO_EXT_1;
if (argc < 2) {
errx(1, "no argument provided. Try 'start' or 'stop' [-p 1/2]");
} else {
/* START COMMAND HANDLING */
if (!strcmp(argv[1], "start")) {
if (argc > 2) {
if (!strcmp(argv[1], "-p")) {
if (!strcmp(argv[2], "1")) {
pin = GPIO_EXT_1;
} else if (!strcmp(argv[2], "2")) {
pin = GPIO_EXT_2;
} else {
warnx("[gpio_led] Unsupported pin: %s\n", argv[2]);
exit(1);
}
}
}
memset(&gpio_led_data, 0, sizeof(gpio_led_data));
gpio_led_data.pin = pin;
int ret = work_queue(LPWORK, &gpio_led_data.work, gpio_led_start, &gpio_led_data, 0);
if (ret != 0) {
warnx("[gpio_led] Failed to queue work: %d\n", ret);
exit(1);
} else {
gpio_led_started = true;
}
exit(0);
/* STOP COMMAND HANDLING */
} else if (!strcmp(argv[1], "stop")) {
gpio_led_started = false;
/* INVALID COMMAND */
} else {
errx(1, "unrecognized command '%s', only supporting 'start' or 'stop'", argv[1]);
}
}
}
void gpio_led_start(FAR void *arg)
{
FAR struct gpio_led_s *priv = (FAR struct gpio_led_s *)arg;
/* open GPIO device */
priv->gpio_fd = open(GPIO_DEVICE_PATH, 0);
if (priv->gpio_fd < 0) {
warnx("[gpio_led] GPIO: open fail\n");
return;
}
/* configure GPIO pin */
ioctl(priv->gpio_fd, GPIO_SET_OUTPUT, priv->pin);
/* subscribe to vehicle status topic */
memset(&priv->status, 0, sizeof(priv->status));
priv->vehicle_status_sub = orb_subscribe(ORB_ID(vehicle_status));
/* add worker to queue */
int ret = work_queue(LPWORK, &priv->work, gpio_led_cycle, priv, 0);
if (ret != 0) {
warnx("[gpio_led] Failed to queue work: %d\n", ret);
return;
}
warnx("[gpio_led] Started, using pin GPIO_EXT%i\n", priv->pin);
}
void gpio_led_cycle(FAR void *arg)
{
FAR struct gpio_led_s *priv = (FAR struct gpio_led_s *)arg;
/* check for status updates*/
bool status_updated;
orb_check(priv->vehicle_status_sub, &status_updated);
if (status_updated)
orb_copy(ORB_ID(vehicle_status), priv->vehicle_status_sub, &priv->status);
/* select pattern for current status */
int pattern = 0;
if (priv->status.flag_system_armed) {
if (priv->status.battery_warning == VEHICLE_BATTERY_WARNING_NONE) {
pattern = 0x3f; // ****** solid (armed)
} else {
pattern = 0x2A; // *_*_*_ fast blink (armed, battery warning)
}
} else {
if (priv->status.state_machine == SYSTEM_STATE_PREFLIGHT) {
pattern = 0x00; // ______ off (disarmed, preflight check)
} else if (priv->status.state_machine == SYSTEM_STATE_STANDBY &&
priv->status.battery_warning == VEHICLE_BATTERY_WARNING_NONE) {
pattern = 0x38; // ***___ slow blink (disarmed, ready)
} else {
pattern = 0x28; // *_*___ slow double blink (disarmed, not good to arm)
}
}
/* blink pattern */
bool led_state_new = (pattern & (1 << priv->counter)) != 0;
if (led_state_new != priv->led_state) {
priv->led_state = led_state_new;
if (led_state_new) {
ioctl(priv->gpio_fd, GPIO_SET, priv->pin);
} else {
ioctl(priv->gpio_fd, GPIO_CLEAR, priv->pin);
}
}
priv->counter++;
if (priv->counter > 5)
priv->counter = 0;
/* repeat cycle at 5 Hz*/
if (gpio_led_started)
work_queue(LPWORK, &priv->work, gpio_led_cycle, priv, USEC2TICK(200000));
}

View File

@ -0,0 +1,39 @@
############################################################################
#
# Copyright (C) 2013 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
#
# Status LED via GPIO driver
#
MODULE_COMMAND = gpio_led
SRCS = gpio_led.c

View File

@ -1,159 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_abs_f32.c
*
* Description: Vector absolute value.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
#include <math.h>
/**
* @ingroup groupMath
*/
/**
* @defgroup BasicAbs Vector Absolute Value
*
* Computes the absolute value of a vector on an element-by-element basis.
*
* <pre>
* pDst[n] = abs(pSrcA[n]), 0 <= n < blockSize.
* </pre>
*
* The operation can be done in-place by setting the input and output pointers to the same buffer.
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup BasicAbs
* @{
*/
/**
* @brief Floating-point vector absolute value.
* @param[in] *pSrc points to the input buffer
* @param[out] *pDst points to the output buffer
* @param[in] blockSize number of samples in each vector
* @return none.
*/
void arm_abs_f32(
float32_t * pSrc,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t in1, in2, in3, in4; /* temporary variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = |A| */
/* Calculate absolute and then store the results in the destination buffer. */
/* read sample from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
/* find absolute value */
in1 = fabsf(in1);
/* read sample from source */
in4 = *(pSrc + 3);
/* find absolute value */
in2 = fabsf(in2);
/* read sample from source */
*pDst = in1;
/* find absolute value */
in3 = fabsf(in3);
/* find absolute value */
in4 = fabsf(in4);
/* store result to destination */
*(pDst + 1) = in2;
/* store result to destination */
*(pDst + 2) = in3;
/* store result to destination */
*(pDst + 3) = in4;
/* Update source pointer to process next sampels */
pSrc += 4u;
/* Update destination pointer to process next sampels */
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = |A| */
/* Calculate absolute and then store the results in the destination buffer. */
*pDst++ = fabsf(*pSrc++);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of BasicAbs group
*/

View File

@ -1,173 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_abs_q15.c
*
* Description: Q15 vector absolute value.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAbs
* @{
*/
/**
* @brief Q15 vector absolute value.
* @param[in] *pSrc points to the input buffer
* @param[out] *pDst points to the output buffer
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.
*/
void arm_abs_q15(
q15_t * pSrc,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q15_t in1; /* Input value1 */
q15_t in2; /* Input value2 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = |A| */
/* Read two inputs */
in1 = *pSrc++;
in2 = *pSrc++;
/* Store the Absolute result in the destination buffer by packing the two values, in a single cycle */
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ =
__PKHBT(((in1 > 0) ? in1 : __QSUB16(0, in1)),
((in2 > 0) ? in2 : __QSUB16(0, in2)), 16);
#else
*__SIMD32(pDst)++ =
__PKHBT(((in2 > 0) ? in2 : __QSUB16(0, in2)),
((in1 > 0) ? in1 : __QSUB16(0, in1)), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
in1 = *pSrc++;
in2 = *pSrc++;
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ =
__PKHBT(((in1 > 0) ? in1 : __QSUB16(0, in1)),
((in2 > 0) ? in2 : __QSUB16(0, in2)), 16);
#else
*__SIMD32(pDst)++ =
__PKHBT(((in2 > 0) ? in2 : __QSUB16(0, in2)),
((in1 > 0) ? in1 : __QSUB16(0, in1)), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = |A| */
/* Read the input */
in1 = *pSrc++;
/* Calculate absolute value of input and then store the result in the destination buffer. */
*pDst++ = (in1 > 0) ? in1 : __QSUB16(0, in1);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
q15_t in; /* Temporary input variable */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = |A| */
/* Read the input */
in = *pSrc++;
/* Calculate absolute value of input and then store the result in the destination buffer. */
*pDst++ = (in > 0) ? in : ((in == (q15_t) 0x8000) ? 0x7fff : -in);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicAbs group
*/

View File

@ -1,125 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_abs_q31.c
*
* Description: Q31 vector absolute value.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAbs
* @{
*/
/**
* @brief Q31 vector absolute value.
* @param[in] *pSrc points to the input buffer
* @param[out] *pDst points to the output buffer
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.
*/
void arm_abs_q31(
q31_t * pSrc,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
q31_t in; /* Input value */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2, in3, in4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = |A| */
/* Calculate absolute of input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */
in1 = *pSrc++;
in2 = *pSrc++;
in3 = *pSrc++;
in4 = *pSrc++;
*pDst++ = (in1 > 0) ? in1 : __QSUB(0, in1);
*pDst++ = (in2 > 0) ? in2 : __QSUB(0, in2);
*pDst++ = (in3 > 0) ? in3 : __QSUB(0, in3);
*pDst++ = (in4 > 0) ? in4 : __QSUB(0, in4);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = |A| */
/* Calculate absolute value of the input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */
in = *pSrc++;
*pDst++ = (in > 0) ? in : ((in == 0x80000000) ? 0x7fffffff : -in);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of BasicAbs group
*/

View File

@ -1,152 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_abs_q7.c
*
* Description: Q7 vector absolute value.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAbs
* @{
*/
/**
* @brief Q7 vector absolute value.
* @param[in] *pSrc points to the input buffer
* @param[out] *pDst points to the output buffer
* @param[in] blockSize number of samples in each vector
* @return none.
*
* \par Conditions for optimum performance
* Input and output buffers should be aligned by 32-bit
*
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.
*/
void arm_abs_q7(
q7_t * pSrc,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
q7_t in; /* Input value1 */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2, in3, in4; /* temporary input variables */
q31_t out1, out2, out3, out4; /* temporary output variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = |A| */
/* Read inputs */
in1 = (q31_t) * pSrc;
in2 = (q31_t) * (pSrc + 1);
in3 = (q31_t) * (pSrc + 2);
/* find absolute value */
out1 = (in1 > 0) ? in1 : __QSUB8(0, in1);
/* read input */
in4 = (q31_t) * (pSrc + 3);
/* find absolute value */
out2 = (in2 > 0) ? in2 : __QSUB8(0, in2);
/* store result to destination */
*pDst = (q7_t) out1;
/* find absolute value */
out3 = (in3 > 0) ? in3 : __QSUB8(0, in3);
/* find absolute value */
out4 = (in4 > 0) ? in4 : __QSUB8(0, in4);
/* store result to destination */
*(pDst + 1) = (q7_t) out2;
/* store result to destination */
*(pDst + 2) = (q7_t) out3;
/* store result to destination */
*(pDst + 3) = (q7_t) out4;
/* update pointers to process next samples */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = blockSize;
#endif // #define ARM_MATH_CM0
while(blkCnt > 0u)
{
/* C = |A| */
/* Read the input */
in = *pSrc++;
/* Store the Absolute result in the destination buffer */
*pDst++ = (in > 0) ? in : ((in == (q7_t) 0x80) ? 0x7f : -in);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of BasicAbs group
*/

View File

@ -1,145 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_add_f32.c
*
* Description: Floating-point vector addition.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup BasicAdd Vector Addition
*
* Element-by-element addition of two vectors.
*
* <pre>
* pDst[n] = pSrcA[n] + pSrcB[n], 0 <= n < blockSize.
* </pre>
*
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup BasicAdd
* @{
*/
/**
* @brief Floating-point vector addition.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*/
void arm_add_f32(
float32_t * pSrcA,
float32_t * pSrcB,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t inA1, inA2, inA3, inA4; /* temporary input variabels */
float32_t inB1, inB2, inB3, inB4; /* temporary input variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
/* read four inputs from sourceA and four inputs from sourceB */
inA1 = *pSrcA;
inB1 = *pSrcB;
inA2 = *(pSrcA + 1);
inB2 = *(pSrcB + 1);
inA3 = *(pSrcA + 2);
inB3 = *(pSrcB + 2);
inA4 = *(pSrcA + 3);
inB4 = *(pSrcB + 3);
/* C = A + B */
/* add and store result to destination */
*pDst = inA1 + inB1;
*(pDst + 1) = inA2 + inB2;
*(pDst + 2) = inA3 + inB3;
*(pDst + 3) = inA4 + inB4;
/* update pointers to process next samples */
pSrcA += 4u;
pSrcB += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (*pSrcA++) + (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of BasicAdd group
*/

View File

@ -1,135 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_add_q15.c
*
* Description: Q15 vector addition
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAdd
* @{
*/
/**
* @brief Q15 vector addition.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.
*/
void arm_add_q15(
q15_t * pSrcA,
q15_t * pSrcB,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inB1, inB2;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
inA1 = *__SIMD32(pSrcA)++;
inA2 = *__SIMD32(pSrcA)++;
inB1 = *__SIMD32(pSrcB)++;
inB2 = *__SIMD32(pSrcB)++;
*__SIMD32(pDst)++ = __QADD16(inA1, inB1);
*__SIMD32(pDst)++ = __QADD16(inA2, inB2);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (q15_t) __QADD16(*pSrcA++, *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (q15_t) __SSAT(((q31_t) * pSrcA++ + *pSrcB++), 16);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicAdd group
*/

View File

@ -1,143 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_add_q31.c
*
* Description: Q31 vector addition.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAdd
* @{
*/
/**
* @brief Q31 vector addition.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] will be saturated.
*/
void arm_add_q31(
q31_t * pSrcA,
q31_t * pSrcB,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inA3, inA4;
q31_t inB1, inB2, inB3, inB4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
inA1 = *pSrcA++;
inA2 = *pSrcA++;
inB1 = *pSrcB++;
inB2 = *pSrcB++;
inA3 = *pSrcA++;
inA4 = *pSrcA++;
inB3 = *pSrcB++;
inB4 = *pSrcB++;
*pDst++ = __QADD(inA1, inB1);
*pDst++ = __QADD(inA2, inB2);
*pDst++ = __QADD(inA3, inB3);
*pDst++ = __QADD(inA4, inB4);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = __QADD(*pSrcA++, *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrcA++ + *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicAdd group
*/

View File

@ -1,129 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_add_q7.c
*
* Description: Q7 vector addition.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicAdd
* @{
*/
/**
* @brief Q7 vector addition.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.
*/
void arm_add_q7(
q7_t * pSrcA,
q7_t * pSrcB,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*__SIMD32(pDst)++ = __QADD8(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (q7_t) __SSAT(*pSrcA++ + *pSrcB++, 8);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + B */
/* Add and then store the results in the destination buffer. */
*pDst++ = (q7_t) __SSAT((q15_t) * pSrcA++ + *pSrcB++, 8);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicAdd group
*/

View File

@ -1,125 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_dot_prod_f32.c
*
* Description: Floating-point dot product.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup dot_prod Vector Dot Product
*
* Computes the dot product of two vectors.
* The vectors are multiplied element-by-element and then summed.
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup dot_prod
* @{
*/
/**
* @brief Dot product of floating-point vectors.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[in] blockSize number of samples in each vector
* @param[out] *result output result returned here
* @return none.
*/
void arm_dot_prod_f32(
float32_t * pSrcA,
float32_t * pSrcB,
uint32_t blockSize,
float32_t * result)
{
float32_t sum = 0.0f; /* Temporary result storage */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the result in a temporary buffer */
sum += (*pSrcA++) * (*pSrcB++);
sum += (*pSrcA++) * (*pSrcB++);
sum += (*pSrcA++) * (*pSrcB++);
sum += (*pSrcA++) * (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the result in a temporary buffer. */
sum += (*pSrcA++) * (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
/* Store the result back in the destination buffer */
*result = sum;
}
/**
* @} end of dot_prod group
*/

View File

@ -1,135 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_dot_prod_q15.c
*
* Description: Q15 dot product.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup dot_prod
* @{
*/
/**
* @brief Dot product of Q15 vectors.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[in] blockSize number of samples in each vector
* @param[out] *result output result returned here
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The intermediate multiplications are in 1.15 x 1.15 = 2.30 format and these
* results are added to a 64-bit accumulator in 34.30 format.
* Nonsaturating additions are used and given that there are 33 guard bits in the accumulator
* there is no risk of overflow.
* The return result is in 34.30 format.
*/
void arm_dot_prod_q15(
q15_t * pSrcA,
q15_t * pSrcB,
uint32_t blockSize,
q63_t * result)
{
q63_t sum = 0; /* Temporary result storage */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the result in a temporary buffer. */
sum = __SMLALD(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++, sum);
sum = __SMLALD(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++, sum);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the results in a temporary buffer. */
sum = __SMLALD(*pSrcA++, *pSrcB++, sum);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the results in a temporary buffer. */
sum += (q63_t) ((q31_t) * pSrcA++ * *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
/* Store the result in the destination buffer in 34.30 format */
*result = sum;
}
/**
* @} end of dot_prod group
*/

View File

@ -1,138 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_dot_prod_q31.c
*
* Description: Q31 dot product.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup dot_prod
* @{
*/
/**
* @brief Dot product of Q31 vectors.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[in] blockSize number of samples in each vector
* @param[out] *result output result returned here
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The intermediate multiplications are in 1.31 x 1.31 = 2.62 format and these
* are truncated to 2.48 format by discarding the lower 14 bits.
* The 2.48 result is then added without saturation to a 64-bit accumulator in 16.48 format.
* There are 15 guard bits in the accumulator and there is no risk of overflow as long as
* the length of the vectors is less than 2^16 elements.
* The return result is in 16.48 format.
*/
void arm_dot_prod_q31(
q31_t * pSrcA,
q31_t * pSrcB,
uint32_t blockSize,
q63_t * result)
{
q63_t sum = 0; /* Temporary result storage */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inA3, inA4;
q31_t inB1, inB2, inB3, inB4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the result in a temporary buffer. */
inA1 = *pSrcA++;
inA2 = *pSrcA++;
inA3 = *pSrcA++;
inA4 = *pSrcA++;
inB1 = *pSrcB++;
inB2 = *pSrcB++;
inB3 = *pSrcB++;
inB4 = *pSrcB++;
sum += ((q63_t) inA1 * inB1) >> 14u;
sum += ((q63_t) inA2 * inB2) >> 14u;
sum += ((q63_t) inA3 * inB3) >> 14u;
sum += ((q63_t) inA4 * inB4) >> 14u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Calculate dot product and then store the result in a temporary buffer. */
sum += ((q63_t) * pSrcA++ * *pSrcB++) >> 14u;
/* Decrement the loop counter */
blkCnt--;
}
/* Store the result in the destination buffer in 16.48 format */
*result = sum;
}
/**
* @} end of dot_prod group
*/

View File

@ -1,154 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_dot_prod_q7.c
*
* Description: Q7 dot product.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup dot_prod
* @{
*/
/**
* @brief Dot product of Q7 vectors.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[in] blockSize number of samples in each vector
* @param[out] *result output result returned here
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The intermediate multiplications are in 1.7 x 1.7 = 2.14 format and these
* results are added to an accumulator in 18.14 format.
* Nonsaturating additions are used and there is no danger of wrap around as long as
* the vectors are less than 2^18 elements long.
* The return result is in 18.14 format.
*/
void arm_dot_prod_q7(
q7_t * pSrcA,
q7_t * pSrcB,
uint32_t blockSize,
q31_t * result)
{
uint32_t blkCnt; /* loop counter */
q31_t sum = 0; /* Temporary variables to store output */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t input1, input2; /* Temporary variables to store input */
q31_t inA1, inA2, inB1, inB2; /* Temporary variables to store input */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read 4 samples at a time from sourceA */
input1 = *__SIMD32(pSrcA)++;
/* read 4 samples at a time from sourceB */
input2 = *__SIMD32(pSrcB)++;
/* extract two q7_t samples to q15_t samples */
inA1 = __SXTB16(__ROR(input1, 8));
/* extract reminaing two samples */
inA2 = __SXTB16(input1);
/* extract two q7_t samples to q15_t samples */
inB1 = __SXTB16(__ROR(input2, 8));
/* extract reminaing two samples */
inB2 = __SXTB16(input2);
/* multiply and accumulate two samples at a time */
sum = __SMLAD(inA1, inB1, sum);
sum = __SMLAD(inA2, inB2, sum);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Dot product and then store the results in a temporary buffer. */
sum = __SMLAD(*pSrcA++, *pSrcB++, sum);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
/* Dot product and then store the results in a temporary buffer. */
sum += (q31_t) ((q15_t) * pSrcA++ * *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
/* Store the result in the destination buffer in 18.14 format */
*result = sum;
}
/**
* @} end of dot_prod group
*/

View File

@ -1,172 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_mult_f32.c
*
* Description: Floating-point vector multiplication.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.5 2010/04/26
* incorporated review comments and updated with latest CMSIS layer
*
* Version 0.0.3 2010/03/10
* Initial version
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup BasicMult Vector Multiplication
*
* Element-by-element multiplication of two vectors.
*
* <pre>
* pDst[n] = pSrcA[n] * pSrcB[n], 0 <= n < blockSize.
* </pre>
*
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup BasicMult
* @{
*/
/**
* @brief Floating-point vector multiplication.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*/
void arm_mult_f32(
float32_t * pSrcA,
float32_t * pSrcB,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t inA1, inA2, inA3, inA4; /* temporary input variables */
float32_t inB1, inB2, inB3, inB4; /* temporary input variables */
float32_t out1, out2, out3, out4; /* temporary output variables */
/* loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and store the results in output buffer */
/* read sample from sourceA */
inA1 = *pSrcA;
/* read sample from sourceB */
inB1 = *pSrcB;
/* read sample from sourceA */
inA2 = *(pSrcA + 1);
/* read sample from sourceB */
inB2 = *(pSrcB + 1);
/* out = sourceA * sourceB */
out1 = inA1 * inB1;
/* read sample from sourceA */
inA3 = *(pSrcA + 2);
/* read sample from sourceB */
inB3 = *(pSrcB + 2);
/* out = sourceA * sourceB */
out2 = inA2 * inB2;
/* read sample from sourceA */
inA4 = *(pSrcA + 3);
/* store result to destination buffer */
*pDst = out1;
/* read sample from sourceB */
inB4 = *(pSrcB + 3);
/* out = sourceA * sourceB */
out3 = inA3 * inB3;
/* store result to destination buffer */
*(pDst + 1) = out2;
/* out = sourceA * sourceB */
out4 = inA4 * inB4;
/* store result to destination buffer */
*(pDst + 2) = out3;
/* store result to destination buffer */
*(pDst + 3) = out4;
/* update pointers to process next samples */
pSrcA += 4u;
pSrcB += 4u;
pDst += 4u;
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and store the results in output buffer */
*pDst++ = (*pSrcA++) * (*pSrcB++);
/* Decrement the blockSize loop counter */
blkCnt--;
}
}
/**
* @} end of BasicMult group
*/

View File

@ -1,152 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_mult_q15.c
*
* Description: Q15 vector multiplication.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.5 2010/04/26
* incorporated review comments and updated with latest CMSIS layer
*
* Version 0.0.3 2010/03/10
* Initial version
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicMult
* @{
*/
/**
* @brief Q15 vector multiplication
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.
*/
void arm_mult_q15(
q15_t * pSrcA,
q15_t * pSrcB,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inB1, inB2; /* temporary input variables */
q15_t out1, out2, out3, out4; /* temporary output variables */
q31_t mul1, mul2, mul3, mul4; /* temporary variables */
/* loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read two samples at a time from sourceA */
inA1 = *__SIMD32(pSrcA)++;
/* read two samples at a time from sourceB */
inB1 = *__SIMD32(pSrcB)++;
/* read two samples at a time from sourceA */
inA2 = *__SIMD32(pSrcA)++;
/* read two samples at a time from sourceB */
inB2 = *__SIMD32(pSrcB)++;
/* multiply mul = sourceA * sourceB */
mul1 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1 >> 16));
mul2 = (q31_t) ((q15_t) inA1 * (q15_t) inB1);
mul3 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) (inB2 >> 16));
mul4 = (q31_t) ((q15_t) inA2 * (q15_t) inB2);
/* saturate result to 16 bit */
out1 = (q15_t) __SSAT(mul1 >> 15, 16);
out2 = (q15_t) __SSAT(mul2 >> 15, 16);
out3 = (q15_t) __SSAT(mul3 >> 15, 16);
out4 = (q15_t) __SSAT(mul4 >> 15, 16);
/* store the result */
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ = __PKHBT(out2, out1, 16);
*__SIMD32(pDst)++ = __PKHBT(out4, out3, 16);
#else
*__SIMD32(pDst)++ = __PKHBT(out2, out1, 16);
*__SIMD32(pDst)++ = __PKHBT(out4, out3, 16);
#endif // #ifndef ARM_MATH_BIG_ENDIAN
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and store the result in the destination buffer */
*pDst++ = (q15_t) __SSAT((((q31_t) (*pSrcA++) * (*pSrcB++)) >> 15), 16);
/* Decrement the blockSize loop counter */
blkCnt--;
}
}
/**
* @} end of BasicMult group
*/

View File

@ -1,143 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_mult_q31.c
*
* Description: Q31 vector multiplication.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.5 2010/04/26
* incorporated review comments and updated with latest CMSIS layer
*
* Version 0.0.3 2010/03/10
* Initial version
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicMult
* @{
*/
/**
* @brief Q31 vector multiplication.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] will be saturated.
*/
void arm_mult_q31(
q31_t * pSrcA,
q31_t * pSrcB,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inA3, inA4; /* temporary input variables */
q31_t inB1, inB2, inB3, inB4; /* temporary input variables */
q31_t out1, out2, out3, out4; /* temporary output variables */
/* loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and then store the results in the destination buffer. */
inA1 = *pSrcA++;
inA2 = *pSrcA++;
inA3 = *pSrcA++;
inA4 = *pSrcA++;
inB1 = *pSrcB++;
inB2 = *pSrcB++;
inB3 = *pSrcB++;
inB4 = *pSrcB++;
out1 = ((q63_t) inA1 * inB1) >> 32;
out2 = ((q63_t) inA2 * inB2) >> 32;
out3 = ((q63_t) inA3 * inB3) >> 32;
out4 = ((q63_t) inA4 * inB4) >> 32;
out1 = __SSAT(out1, 31);
out2 = __SSAT(out2, 31);
out3 = __SSAT(out3, 31);
out4 = __SSAT(out4, 31);
*pDst++ = out1 << 1u;
*pDst++ = out2 << 1u;
*pDst++ = out3 << 1u;
*pDst++ = out4 << 1u;
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and then store the results in the destination buffer. */
*pDst++ =
(q31_t) clip_q63_to_q31(((q63_t) (*pSrcA++) * (*pSrcB++)) >> 31);
/* Decrement the blockSize loop counter */
blkCnt--;
}
}
/**
* @} end of BasicMult group
*/

View File

@ -1,128 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_mult_q7.c
*
* Description: Q7 vector multiplication.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
*
* Version 0.0.5 2010/04/26
* incorporated review comments and updated with latest CMSIS layer
*
* Version 0.0.3 2010/03/10 DP
* Initial version
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicMult
* @{
*/
/**
* @brief Q7 vector multiplication
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.
*/
void arm_mult_q7(
q7_t * pSrcA,
q7_t * pSrcB,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q7_t out1, out2, out3, out4; /* Temporary variables to store the product */
/* loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and store the results in temporary variables */
out1 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
out2 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
out3 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
out4 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
/* Store the results of 4 inputs in the destination buffer in single cycle by packing */
*__SIMD32(pDst)++ = __PACKq7(out1, out2, out3, out4);
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * B */
/* Multiply the inputs and store the result in the destination buffer */
*pDst++ = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
/* Decrement the blockSize loop counter */
blkCnt--;
}
}
/**
* @} end of BasicMult group
*/

View File

@ -1,137 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_negate_f32.c
*
* Description: Negates floating-point vectors.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup negate Vector Negate
*
* Negates the elements of a vector.
*
* <pre>
* pDst[n] = -pSrc[n], 0 <= n < blockSize.
* </pre>
*/
/**
* @addtogroup negate
* @{
*/
/**
* @brief Negates the elements of a floating-point vector.
* @param[in] *pSrc points to the input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*/
void arm_negate_f32(
float32_t * pSrc,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t in1, in2, in3, in4; /* temporary variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read inputs from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
/* negate the input */
in1 = -in1;
in2 = -in2;
in3 = -in3;
in4 = -in4;
/* store the result to destination */
*pDst = in1;
*(pDst + 1) = in2;
*(pDst + 2) = in3;
*(pDst + 3) = in4;
/* update pointers to process next samples */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = -A */
/* Negate and then store the results in the destination buffer. */
*pDst++ = -*pSrc++;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of negate group
*/

View File

@ -1,137 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_negate_q15.c
*
* Description: Negates Q15 vectors.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup negate
* @{
*/
/**
* @brief Negates the elements of a Q15 vector.
* @param[in] *pSrc points to the input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* \par Conditions for optimum performance
* Input and output buffers should be aligned by 32-bit
*
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.
*/
void arm_negate_q15(
q15_t * pSrc,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
q15_t in;
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2; /* Temporary variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = -A */
/* Read two inputs at a time */
in1 = _SIMD32_OFFSET(pSrc);
in2 = _SIMD32_OFFSET(pSrc + 2);
/* negate two samples at a time */
in1 = __QSUB16(0, in1);
/* negate two samples at a time */
in2 = __QSUB16(0, in2);
/* store the result to destination 2 samples at a time */
_SIMD32_OFFSET(pDst) = in1;
/* store the result to destination 2 samples at a time */
_SIMD32_OFFSET(pDst + 2) = in2;
/* update pointers to process next samples */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = -A */
/* Negate and then store the result in the destination buffer. */
in = *pSrc++;
*pDst++ = (in == (q15_t) 0x8000) ? 0x7fff : -in;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of negate group
*/

View File

@ -1,124 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_negate_q31.c
*
* Description: Negates Q31 vectors.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup negate
* @{
*/
/**
* @brief Negates the elements of a Q31 vector.
* @param[in] *pSrc points to the input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.
*/
void arm_negate_q31(
q31_t * pSrc,
q31_t * pDst,
uint32_t blockSize)
{
q31_t in; /* Temporary variable */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2, in3, in4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = -A */
/* Negate and then store the results in the destination buffer. */
in1 = *pSrc++;
in2 = *pSrc++;
in3 = *pSrc++;
in4 = *pSrc++;
*pDst++ = __QSUB(0, in1);
*pDst++ = __QSUB(0, in2);
*pDst++ = __QSUB(0, in3);
*pDst++ = __QSUB(0, in4);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = -A */
/* Negate and then store the result in the destination buffer. */
in = *pSrc++;
*pDst++ = (in == 0x80000000) ? 0x7fffffff : -in;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of negate group
*/

View File

@ -1,120 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_negate_q7.c
*
* Description: Negates Q7 vectors.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup negate
* @{
*/
/**
* @brief Negates the elements of a Q7 vector.
* @param[in] *pSrc points to the input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.
*/
void arm_negate_q7(
q7_t * pSrc,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
q7_t in;
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t input; /* Input values1-4 */
q31_t zero = 0x00000000;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = -A */
/* Read four inputs */
input = *__SIMD32(pSrc)++;
/* Store the Negated results in the destination buffer in a single cycle by packing the results */
*__SIMD32(pDst)++ = __QSUB8(zero, input);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = -A */
/* Negate and then store the results in the destination buffer. */ \
in = *pSrc++;
*pDst++ = (in == (q7_t) 0x80) ? 0x7f : -in;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of negate group
*/

View File

@ -1,158 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_offset_f32.c
*
* Description: Floating-point vector offset.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup offset Vector Offset
*
* Adds a constant offset to each element of a vector.
*
* <pre>
* pDst[n] = pSrc[n] + offset, 0 <= n < blockSize.
* </pre>
*
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup offset
* @{
*/
/**
* @brief Adds a constant offset to a floating-point vector.
* @param[in] *pSrc points to the input vector
* @param[in] offset is the offset to be added
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*/
void arm_offset_f32(
float32_t * pSrc,
float32_t offset,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t in1, in2, in3, in4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination buffer. */
/* read samples from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
/* add offset to input */
in1 = in1 + offset;
/* read samples from source */
in3 = *(pSrc + 2);
/* add offset to input */
in2 = in2 + offset;
/* read samples from source */
in4 = *(pSrc + 3);
/* add offset to input */
in3 = in3 + offset;
/* store result to destination */
*pDst = in1;
/* add offset to input */
in4 = in4 + offset;
/* store result to destination */
*(pDst + 1) = in2;
/* store result to destination */
*(pDst + 2) = in3;
/* store result to destination */
*(pDst + 3) = in4;
/* update pointers to process next samples */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the result in the destination buffer. */
*pDst++ = (*pSrc++) + offset;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of offset group
*/

View File

@ -1,131 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_offset_q15.c
*
* Description: Q15 vector offset.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup offset
* @{
*/
/**
* @brief Adds a constant offset to a Q15 vector.
* @param[in] *pSrc points to the input vector
* @param[in] offset is the offset to be added
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] are saturated.
*/
void arm_offset_q15(
q15_t * pSrc,
q15_t offset,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t offset_packed; /* Offset packed to 32 bit */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* Offset is packed to 32 bit in order to use SIMD32 for addition */
offset_packed = __PKHBT(offset, offset, 16);
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination buffer, 2 samples at a time. */
*__SIMD32(pDst)++ = __QADD16(*__SIMD32(pSrc)++, offset_packed);
*__SIMD32(pDst)++ = __QADD16(*__SIMD32(pSrc)++, offset_packed);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination buffer. */
*pDst++ = (q15_t) __QADD16(*pSrc++, offset);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination buffer. */
*pDst++ = (q15_t) __SSAT(((q31_t) * pSrc++ + offset), 16);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of offset group
*/

View File

@ -1,135 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_offset_q31.c
*
* Description: Q31 vector offset.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup offset
* @{
*/
/**
* @brief Adds a constant offset to a Q31 vector.
* @param[in] *pSrc points to the input vector
* @param[in] offset is the offset to be added
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] are saturated.
*/
void arm_offset_q31(
q31_t * pSrc,
q31_t offset,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2, in3, in4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination buffer. */
in1 = *pSrc++;
in2 = *pSrc++;
in3 = *pSrc++;
in4 = *pSrc++;
*pDst++ = __QADD(in1, offset);
*pDst++ = __QADD(in2, offset);
*pDst++ = __QADD(in3, offset);
*pDst++ = __QADD(in4, offset);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the result in the destination buffer. */
*pDst++ = __QADD(*pSrc++, offset);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the result in the destination buffer. */
*pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of offset group
*/

View File

@ -1,130 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_offset_q7.c
*
* Description: Q7 vector offset.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup offset
* @{
*/
/**
* @brief Adds a constant offset to a Q7 vector.
* @param[in] *pSrc points to the input vector
* @param[in] offset is the offset to be added
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q7 range [0x80 0x7F] are saturated.
*/
void arm_offset_q7(
q7_t * pSrc,
q7_t offset,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t offset_packed; /* Offset packed to 32 bit */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* Offset is packed to 32 bit in order to use SIMD32 for addition */
offset_packed = __PACKq7(offset, offset, offset, offset);
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the results in the destination bufferfor 4 samples at a time. */
*__SIMD32(pDst)++ = __QADD8(*__SIMD32(pSrc)++, offset_packed);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the result in the destination buffer. */
*pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A + offset */
/* Add offset and then store the result in the destination buffer. */
*pDst++ = (q7_t) __SSAT((q15_t) * pSrc++ + offset, 8);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of offset group
*/

View File

@ -1,161 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_scale_f32.c
*
* Description: Multiplies a floating-point vector by a scalar.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup scale Vector Scale
*
* Multiply a vector by a scalar value. For floating-point data, the algorithm used is:
*
* <pre>
* pDst[n] = pSrc[n] * scale, 0 <= n < blockSize.
* </pre>
*
* In the fixed-point Q7, Q15, and Q31 functions, <code>scale</code> is represented by
* a fractional multiplication <code>scaleFract</code> and an arithmetic shift <code>shift</code>.
* The shift allows the gain of the scaling operation to exceed 1.0.
* The algorithm used with fixed-point data is:
*
* <pre>
* pDst[n] = (pSrc[n] * scaleFract) << shift, 0 <= n < blockSize.
* </pre>
*
* The overall scale factor applied to the fixed-point data is
* <pre>
* scale = scaleFract * 2^shift.
* </pre>
*/
/**
* @addtogroup scale
* @{
*/
/**
* @brief Multiplies a floating-point vector by a scalar.
* @param[in] *pSrc points to the input vector
* @param[in] scale scale factor to be applied
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*/
void arm_scale_f32(
float32_t * pSrc,
float32_t scale,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t in1, in2, in3, in4; /* temporary variabels */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the results in the destination buffer. */
/* read input samples from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
/* multiply with scaling factor */
in1 = in1 * scale;
/* read input sample from source */
in3 = *(pSrc + 2);
/* multiply with scaling factor */
in2 = in2 * scale;
/* read input sample from source */
in4 = *(pSrc + 3);
/* multiply with scaling factor */
in3 = in3 * scale;
in4 = in4 * scale;
/* store the result to destination */
*pDst = in1;
*(pDst + 1) = in2;
*(pDst + 2) = in3;
*(pDst + 3) = in4;
/* update pointers to process next samples */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
*pDst++ = (*pSrc++) * scale;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of scale group
*/

View File

@ -1,157 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_scale_q15.c
*
* Description: Multiplies a Q15 vector by a scalar.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup scale
* @{
*/
/**
* @brief Multiplies a Q15 vector by a scalar.
* @param[in] *pSrc points to the input vector
* @param[in] scaleFract fractional portion of the scale value
* @param[in] shift number of bits to shift the result by
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.15 format.
* These are multiplied to yield a 2.30 intermediate result and this is shifted with saturation to 1.15 format.
*/
void arm_scale_q15(
q15_t * pSrc,
q15_t scaleFract,
int8_t shift,
q15_t * pDst,
uint32_t blockSize)
{
int8_t kShift = 15 - shift; /* shift to apply after scaling */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q15_t in1, in2, in3, in4;
q31_t inA1, inA2; /* Temporary variables */
q31_t out1, out2, out3, out4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* Reading 2 inputs from memory */
inA1 = *__SIMD32(pSrc)++;
inA2 = *__SIMD32(pSrc)++;
/* C = A * scale */
/* Scale the inputs and then store the 2 results in the destination buffer
* in single cycle by packing the outputs */
out1 = (q31_t) ((q15_t) (inA1 >> 16) * scaleFract);
out2 = (q31_t) ((q15_t) inA1 * scaleFract);
out3 = (q31_t) ((q15_t) (inA2 >> 16) * scaleFract);
out4 = (q31_t) ((q15_t) inA2 * scaleFract);
/* apply shifting */
out1 = out1 >> kShift;
out2 = out2 >> kShift;
out3 = out3 >> kShift;
out4 = out4 >> kShift;
/* saturate the output */
in1 = (q15_t) (__SSAT(out1, 16));
in2 = (q15_t) (__SSAT(out2, 16));
in3 = (q15_t) (__SSAT(out3, 16));
in4 = (q15_t) (__SSAT(out4, 16));
/* store the result to destination */
*__SIMD32(pDst)++ = __PKHBT(in2, in1, 16);
*__SIMD32(pDst)++ = __PKHBT(in4, in3, 16);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
*pDst++ = (q15_t) (__SSAT(((*pSrc++) * scaleFract) >> kShift, 16));
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
*pDst++ = (q15_t) (__SSAT(((q31_t) * pSrc++ * scaleFract) >> kShift, 16));
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of scale group
*/

View File

@ -1,221 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_scale_q31.c
*
* Description: Multiplies a Q31 vector by a scalar.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup scale
* @{
*/
/**
* @brief Multiplies a Q31 vector by a scalar.
* @param[in] *pSrc points to the input vector
* @param[in] scaleFract fractional portion of the scale value
* @param[in] shift number of bits to shift the result by
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.31 format.
* These are multiplied to yield a 2.62 intermediate result and this is shifted with saturation to 1.31 format.
*/
void arm_scale_q31(
q31_t * pSrc,
q31_t scaleFract,
int8_t shift,
q31_t * pDst,
uint32_t blockSize)
{
int8_t kShift = shift + 1; /* Shift to apply after scaling */
int8_t sign = (kShift & 0x80);
uint32_t blkCnt; /* loop counter */
q31_t in, out;
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t in1, in2, in3, in4; /* temporary input variables */
q31_t out1, out2, out3, out4; /* temporary output variabels */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
if(sign == 0u)
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read four inputs from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
/* multiply input with scaler value */
in1 = ((q63_t) in1 * scaleFract) >> 32;
in2 = ((q63_t) in2 * scaleFract) >> 32;
in3 = ((q63_t) in3 * scaleFract) >> 32;
in4 = ((q63_t) in4 * scaleFract) >> 32;
/* apply shifting */
out1 = in1 << kShift;
out2 = in2 << kShift;
/* saturate the results. */
if(in1 != (out1 >> kShift))
out1 = 0x7FFFFFFF ^ (in1 >> 31);
if(in2 != (out2 >> kShift))
out2 = 0x7FFFFFFF ^ (in2 >> 31);
out3 = in3 << kShift;
out4 = in4 << kShift;
*pDst = out1;
*(pDst + 1) = out2;
if(in3 != (out3 >> kShift))
out3 = 0x7FFFFFFF ^ (in3 >> 31);
if(in4 != (out4 >> kShift))
out4 = 0x7FFFFFFF ^ (in4 >> 31);
/* Store result destination */
*(pDst + 2) = out3;
*(pDst + 3) = out4;
/* Update pointers to process next sampels */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
kShift = -kShift;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read four inputs from source */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
/* multiply input with scaler value */
in1 = ((q63_t) in1 * scaleFract) >> 32;
in2 = ((q63_t) in2 * scaleFract) >> 32;
in3 = ((q63_t) in3 * scaleFract) >> 32;
in4 = ((q63_t) in4 * scaleFract) >> 32;
/* apply shifting */
out1 = in1 >> kShift;
out2 = in2 >> kShift;
out3 = in3 >> kShift;
out4 = in4 >> kShift;
/* Store result destination */
*pDst = out1;
*(pDst + 1) = out2;
*(pDst + 2) = out3;
*(pDst + 3) = out4;
/* Update pointers to process next sampels */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
in = *pSrc++;
in = ((q63_t) in * scaleFract) >> 32;
if(sign == 0)
{
out = in << kShift;
if(in != (out >> kShift))
out = 0x7FFFFFFF ^ (in >> 31);
}
else
{
out = in >> kShift;
}
*pDst++ = out;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of scale group
*/

View File

@ -1,144 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_scale_q7.c
*
* Description: Multiplies a Q7 vector by a scalar.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup scale
* @{
*/
/**
* @brief Multiplies a Q7 vector by a scalar.
* @param[in] *pSrc points to the input vector
* @param[in] scaleFract fractional portion of the scale value
* @param[in] shift number of bits to shift the result by
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The input data <code>*pSrc</code> and <code>scaleFract</code> are in 1.7 format.
* These are multiplied to yield a 2.14 intermediate result and this is shifted with saturation to 1.7 format.
*/
void arm_scale_q7(
q7_t * pSrc,
q7_t scaleFract,
int8_t shift,
q7_t * pDst,
uint32_t blockSize)
{
int8_t kShift = 7 - shift; /* shift to apply after scaling */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q7_t in1, in2, in3, in4, out1, out2, out3, out4; /* Temporary variables to store input & output */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* Reading 4 inputs from memory */
in1 = *pSrc++;
in2 = *pSrc++;
in3 = *pSrc++;
in4 = *pSrc++;
/* C = A * scale */
/* Scale the inputs and then store the results in the temporary variables. */
out1 = (q7_t) (__SSAT(((in1) * scaleFract) >> kShift, 8));
out2 = (q7_t) (__SSAT(((in2) * scaleFract) >> kShift, 8));
out3 = (q7_t) (__SSAT(((in3) * scaleFract) >> kShift, 8));
out4 = (q7_t) (__SSAT(((in4) * scaleFract) >> kShift, 8));
/* Packing the individual outputs into 32bit and storing in
* destination buffer in single write */
*__SIMD32(pDst)++ = __PACKq7(out1, out2, out3, out4);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
*pDst++ = (q7_t) (__SSAT(((*pSrc++) * scaleFract) >> kShift, 8));
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A * scale */
/* Scale the input and then store the result in the destination buffer. */
*pDst++ = (q7_t) (__SSAT((((q15_t) * pSrc++ * scaleFract) >> kShift), 8));
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of scale group
*/

View File

@ -1,243 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_shift_q15.c
*
* Description: Shifts the elements of a Q15 vector by a specified number of bits.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup shift
* @{
*/
/**
* @brief Shifts the elements of a Q15 vector a specified number of bits.
* @param[in] *pSrc points to the input vector
* @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right.
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.
*/
void arm_shift_q15(
q15_t * pSrc,
int8_t shiftBits,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
uint8_t sign; /* Sign of shiftBits */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q15_t in1, in2; /* Temporary variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* Getting the sign of shiftBits */
sign = (shiftBits & 0x80);
/* If the shift value is positive then do right shift else left shift */
if(sign == 0u)
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* Read 2 inputs */
in1 = *pSrc++;
in2 = *pSrc++;
/* C = A << shiftBits */
/* Shift the inputs and then store the results in the destination buffer. */
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ = __PKHBT(__SSAT((in1 << shiftBits), 16),
__SSAT((in2 << shiftBits), 16), 16);
#else
*__SIMD32(pDst)++ = __PKHBT(__SSAT((in2 << shiftBits), 16),
__SSAT((in1 << shiftBits), 16), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
in1 = *pSrc++;
in2 = *pSrc++;
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ = __PKHBT(__SSAT((in1 << shiftBits), 16),
__SSAT((in2 << shiftBits), 16), 16);
#else
*__SIMD32(pDst)++ = __PKHBT(__SSAT((in2 << shiftBits), 16),
__SSAT((in1 << shiftBits), 16), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Shift and then store the results in the destination buffer. */
*pDst++ = __SSAT((*pSrc++ << shiftBits), 16);
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* Read 2 inputs */
in1 = *pSrc++;
in2 = *pSrc++;
/* C = A >> shiftBits */
/* Shift the inputs and then store the results in the destination buffer. */
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ = __PKHBT((in1 >> -shiftBits),
(in2 >> -shiftBits), 16);
#else
*__SIMD32(pDst)++ = __PKHBT((in2 >> -shiftBits),
(in1 >> -shiftBits), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
in1 = *pSrc++;
in2 = *pSrc++;
#ifndef ARM_MATH_BIG_ENDIAN
*__SIMD32(pDst)++ = __PKHBT((in1 >> -shiftBits),
(in2 >> -shiftBits), 16);
#else
*__SIMD32(pDst)++ = __PKHBT((in2 >> -shiftBits),
(in1 >> -shiftBits), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Shift the inputs and then store the results in the destination buffer. */
*pDst++ = (*pSrc++ >> -shiftBits);
/* Decrement the loop counter */
blkCnt--;
}
}
#else
/* Run the below code for Cortex-M0 */
/* Getting the sign of shiftBits */
sign = (shiftBits & 0x80);
/* If the shift value is positive then do right shift else left shift */
if(sign == 0u)
{
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Shift and then store the results in the destination buffer. */
*pDst++ = __SSAT(((q31_t) * pSrc++ << shiftBits), 16);
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Shift the inputs and then store the results in the destination buffer. */
*pDst++ = (*pSrc++ >> -shiftBits);
/* Decrement the loop counter */
blkCnt--;
}
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of shift group
*/

View File

@ -1,195 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_shift_q31.c
*
* Description: Shifts the elements of a Q31 vector by a specified number of bits.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup shift Vector Shift
*
* Shifts the elements of a fixed-point vector by a specified number of bits.
* There are separate functions for Q7, Q15, and Q31 data types.
* The underlying algorithm used is:
*
* <pre>
* pDst[n] = pSrc[n] << shift, 0 <= n < blockSize.
* </pre>
*
* If <code>shift</code> is positive then the elements of the vector are shifted to the left.
* If <code>shift</code> is negative then the elements of the vector are shifted to the right.
*/
/**
* @addtogroup shift
* @{
*/
/**
* @brief Shifts the elements of a Q31 vector a specified number of bits.
* @param[in] *pSrc points to the input vector
* @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right.
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] will be saturated.
*/
void arm_shift_q31(
q31_t * pSrc,
int8_t shiftBits,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
uint8_t sign = (shiftBits & 0x80); /* Sign of shiftBits */
#ifndef ARM_MATH_CM0
q31_t in1, in2, in3, in4; /* Temporary input variables */
q31_t out1, out2, out3, out4; /* Temporary output variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
if(sign == 0u)
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Shift the input and then store the results in the destination buffer. */
in1 = *pSrc;
in2 = *(pSrc + 1);
out1 = in1 << shiftBits;
in3 = *(pSrc + 2);
out2 = in2 << shiftBits;
in4 = *(pSrc + 3);
if(in1 != (out1 >> shiftBits))
out1 = 0x7FFFFFFF ^ (in1 >> 31);
if(in2 != (out2 >> shiftBits))
out2 = 0x7FFFFFFF ^ (in2 >> 31);
*pDst = out1;
out3 = in3 << shiftBits;
*(pDst + 1) = out2;
out4 = in4 << shiftBits;
if(in3 != (out3 >> shiftBits))
out3 = 0x7FFFFFFF ^ (in3 >> 31);
if(in4 != (out4 >> shiftBits))
out4 = 0x7FFFFFFF ^ (in4 >> 31);
*(pDst + 2) = out3;
*(pDst + 3) = out4;
/* Update destination pointer to process next sampels */
pSrc += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Shift the input and then store the results in the destination buffer. */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
*pDst = (in1 >> -shiftBits);
*(pDst + 1) = (in2 >> -shiftBits);
*(pDst + 2) = (in3 >> -shiftBits);
*(pDst + 3) = (in4 >> -shiftBits);
pSrc += 4u;
pDst += 4u;
blkCnt--;
}
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A (>> or <<) shiftBits */
/* Shift the input and then store the result in the destination buffer. */
*pDst++ = (sign == 0u) ? clip_q63_to_q31((q63_t) * pSrc++ << shiftBits) :
(*pSrc++ >> -shiftBits);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of shift group
*/

View File

@ -1,215 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_shift_q7.c
*
* Description: Processing function for the Q7 Shifting
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup shift
* @{
*/
/**
* @brief Shifts the elements of a Q7 vector a specified number of bits.
* @param[in] *pSrc points to the input vector
* @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right.
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in the vector
* @return none.
*
* \par Conditions for optimum performance
* Input and output buffers should be aligned by 32-bit
*
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q7 range [0x8 0x7F] will be saturated.
*/
void arm_shift_q7(
q7_t * pSrc,
int8_t shiftBits,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
uint8_t sign; /* Sign of shiftBits */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q7_t in1; /* Input value1 */
q7_t in2; /* Input value2 */
q7_t in3; /* Input value3 */
q7_t in4; /* Input value4 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* Getting the sign of shiftBits */
sign = (shiftBits & 0x80);
/* If the shift value is positive then do right shift else left shift */
if(sign == 0u)
{
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Read 4 inputs */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
/* Store the Shifted result in the destination buffer in single cycle by packing the outputs */
*__SIMD32(pDst)++ = __PACKq7(__SSAT((in1 << shiftBits), 8),
__SSAT((in2 << shiftBits), 8),
__SSAT((in3 << shiftBits), 8),
__SSAT((in4 << shiftBits), 8));
/* Update source pointer to process next sampels */
pSrc += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Shift the input and then store the result in the destination buffer. */
*pDst++ = (q7_t) __SSAT((*pSrc++ << shiftBits), 8);
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
shiftBits = -shiftBits;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Read 4 inputs */
in1 = *pSrc;
in2 = *(pSrc + 1);
in3 = *(pSrc + 2);
in4 = *(pSrc + 3);
/* Store the Shifted result in the destination buffer in single cycle by packing the outputs */
*__SIMD32(pDst)++ = __PACKq7((in1 >> shiftBits), (in2 >> shiftBits),
(in3 >> shiftBits), (in4 >> shiftBits));
pSrc += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Shift the input and then store the result in the destination buffer. */
in1 = *pSrc++;
*pDst++ = (in1 >> shiftBits);
/* Decrement the loop counter */
blkCnt--;
}
}
#else
/* Run the below code for Cortex-M0 */
/* Getting the sign of shiftBits */
sign = (shiftBits & 0x80);
/* If the shift value is positive then do right shift else left shift */
if(sign == 0u)
{
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A << shiftBits */
/* Shift the input and then store the result in the destination buffer. */
*pDst++ = (q7_t) __SSAT(((q15_t) * pSrc++ << shiftBits), 8);
/* Decrement the loop counter */
blkCnt--;
}
}
else
{
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A >> shiftBits */
/* Shift the input and then store the result in the destination buffer. */
*pDst++ = (*pSrc++ >> -shiftBits);
/* Decrement the loop counter */
blkCnt--;
}
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of shift group
*/

View File

@ -1,145 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_sub_f32.c
*
* Description: Floating-point vector subtraction.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @defgroup BasicSub Vector Subtraction
*
* Element-by-element subtraction of two vectors.
*
* <pre>
* pDst[n] = pSrcA[n] - pSrcB[n], 0 <= n < blockSize.
* </pre>
*
* There are separate functions for floating-point, Q7, Q15, and Q31 data types.
*/
/**
* @addtogroup BasicSub
* @{
*/
/**
* @brief Floating-point vector subtraction.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*/
void arm_sub_f32(
float32_t * pSrcA,
float32_t * pSrcB,
float32_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t inA1, inA2, inA3, inA4; /* temporary variables */
float32_t inB1, inB2, inB3, inB4; /* temporary variables */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the results in the destination buffer. */
/* Read 4 input samples from sourceA and sourceB */
inA1 = *pSrcA;
inB1 = *pSrcB;
inA2 = *(pSrcA + 1);
inB2 = *(pSrcB + 1);
inA3 = *(pSrcA + 2);
inB3 = *(pSrcB + 2);
inA4 = *(pSrcA + 3);
inB4 = *(pSrcB + 3);
/* dst = srcA - srcB */
/* subtract and store the result */
*pDst = inA1 - inB1;
*(pDst + 1) = inA2 - inB2;
*(pDst + 2) = inA3 - inB3;
*(pDst + 3) = inA4 - inB4;
/* Update pointers to process next sampels */
pSrcA += 4u;
pSrcB += 4u;
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the results in the destination buffer. */
*pDst++ = (*pSrcA++) - (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of BasicSub group
*/

View File

@ -1,135 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_sub_q15.c
*
* Description: Q15 vector subtraction.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicSub
* @{
*/
/**
* @brief Q15 vector subtraction.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.
*/
void arm_sub_q15(
q15_t * pSrcA,
q15_t * pSrcB,
q15_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2;
q31_t inB1, inB2;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the results in the destination buffer two samples at a time. */
inA1 = *__SIMD32(pSrcA)++;
inA2 = *__SIMD32(pSrcA)++;
inB1 = *__SIMD32(pSrcB)++;
inB2 = *__SIMD32(pSrcB)++;
*__SIMD32(pDst)++ = __QSUB16(inA1, inB1);
*__SIMD32(pDst)++ = __QSUB16(inA2, inB2);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = (q15_t) __QSUB16(*pSrcA++, *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = (q15_t) __SSAT(((q31_t) * pSrcA++ - *pSrcB++), 16);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicSub group
*/

View File

@ -1,141 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_sub_q31.c
*
* Description: Q31 vector subtraction.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicSub
* @{
*/
/**
* @brief Q31 vector subtraction.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] will be saturated.
*/
void arm_sub_q31(
q31_t * pSrcA,
q31_t * pSrcB,
q31_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inA1, inA2, inA3, inA4;
q31_t inB1, inB2, inB3, inB4;
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the results in the destination buffer. */
inA1 = *pSrcA++;
inA2 = *pSrcA++;
inB1 = *pSrcB++;
inB2 = *pSrcB++;
inA3 = *pSrcA++;
inA4 = *pSrcA++;
inB3 = *pSrcB++;
inB4 = *pSrcB++;
*pDst++ = __QSUB(inA1, inB1);
*pDst++ = __QSUB(inA2, inB2);
*pDst++ = __QSUB(inA3, inB3);
*pDst++ = __QSUB(inA4, inB4);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = __QSUB(*pSrcA++, *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrcA++ - *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicSub group
*/

View File

@ -1,126 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_sub_q7.c
*
* Description: Q7 vector subtraction.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
*
* Version 0.0.7 2010/06/10
* Misra-C changes done
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupMath
*/
/**
* @addtogroup BasicSub
* @{
*/
/**
* @brief Q7 vector subtraction.
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] blockSize number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.
*/
void arm_sub_q7(
q7_t * pSrcA,
q7_t * pSrcB,
q7_t * pDst,
uint32_t blockSize)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/*loop Unrolling */
blkCnt = blockSize >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the results in the destination buffer 4 samples at a time. */
*__SIMD32(pDst)++ = __QSUB8(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = blockSize % 0x4u;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = __SSAT(*pSrcA++ - *pSrcB++, 8);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* Initialize blkCnt with number of samples */
blkCnt = blockSize;
while(blkCnt > 0u)
{
/* C = A - B */
/* Subtract and then store the result in the destination buffer. */
*pDst++ = (q7_t) __SSAT((q15_t) * pSrcA++ - *pSrcB++, 8);
/* Decrement the loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of BasicSub group
*/

View File

@ -1,174 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_conj_f32.c
*
* Description: Floating-point complex conjugate.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup cmplx_conj Complex Conjugate
*
* Conjugates the elements of a complex data vector.
*
* The <code>pSrc</code> points to the source data and
* <code>pDst</code> points to the where the result should be written.
* <code>numSamples</code> specifies the number of complex samples
* and the data in each array is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* Each array has a total of <code>2*numSamples</code> values.
* The underlying algorithm is used:
*
* <pre>
* for(n=0; n<numSamples; n++) {
* pDst[(2*n)+0)] = pSrc[(2*n)+0]; // real part
* pDst[(2*n)+1)] = -pSrc[(2*n)+1]; // imag part
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup cmplx_conj
* @{
*/
/**
* @brief Floating-point complex conjugate.
* @param *pSrc points to the input vector
* @param *pDst points to the output vector
* @param numSamples number of complex samples in each vector
* @return none.
*/
void arm_cmplx_conj_f32(
float32_t * pSrc,
float32_t * pDst,
uint32_t numSamples)
{
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t inR1, inR2, inR3, inR4;
float32_t inI1, inI2, inI3, inI4;
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0]+jC[1] = A[0]+ j (-1) A[1] */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
/* read real input samples */
inR1 = pSrc[0];
/* store real samples to destination */
pDst[0] = inR1;
inR2 = pSrc[2];
pDst[2] = inR2;
inR3 = pSrc[4];
pDst[4] = inR3;
inR4 = pSrc[6];
pDst[6] = inR4;
/* read imaginary input samples */
inI1 = pSrc[1];
inI2 = pSrc[3];
/* conjugate input */
inI1 = -inI1;
/* read imaginary input samples */
inI3 = pSrc[5];
/* conjugate input */
inI2 = -inI2;
/* read imaginary input samples */
inI4 = pSrc[7];
/* conjugate input */
inI3 = -inI3;
/* store imaginary samples to destination */
pDst[1] = inI1;
pDst[3] = inI2;
/* conjugate input */
inI4 = -inI4;
/* store imaginary samples to destination */
pDst[5] = inI3;
/* increment source pointer by 8 to process next sampels */
pSrc += 8u;
/* store imaginary sample to destination */
pDst[7] = inI4;
/* increment destination pointer by 8 to store next samples */
pDst += 8u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* realOut + j (imagOut) = realIn + j (-1) imagIn */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
*pDst++ = *pSrc++;
*pDst++ = -*pSrc++;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of cmplx_conj group
*/

View File

@ -1,153 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_conj_q15.c
*
* Description: Q15 complex conjugate.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_conj
* @{
*/
/**
* @brief Q15 complex conjugate.
* @param *pSrc points to the input vector
* @param *pDst points to the output vector
* @param numSamples number of complex samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.
*/
void arm_cmplx_conj_q15(
q15_t * pSrc,
q15_t * pDst,
uint32_t numSamples)
{
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
q31_t in1, in2, in3, in4;
q31_t zero = 0;
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0]+jC[1] = A[0]+ j (-1) A[1] */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
in1 = *__SIMD32(pSrc)++;
in2 = *__SIMD32(pSrc)++;
in3 = *__SIMD32(pSrc)++;
in4 = *__SIMD32(pSrc)++;
#ifndef ARM_MATH_BIG_ENDIAN
in1 = __QASX(zero, in1);
in2 = __QASX(zero, in2);
in3 = __QASX(zero, in3);
in4 = __QASX(zero, in4);
#else
in1 = __QSAX(zero, in1);
in2 = __QSAX(zero, in2);
in3 = __QSAX(zero, in3);
in4 = __QSAX(zero, in4);
#endif // #ifndef ARM_MATH_BIG_ENDIAN
in1 = ((uint32_t) in1 >> 16) | ((uint32_t) in1 << 16);
in2 = ((uint32_t) in2 >> 16) | ((uint32_t) in2 << 16);
in3 = ((uint32_t) in3 >> 16) | ((uint32_t) in3 << 16);
in4 = ((uint32_t) in4 >> 16) | ((uint32_t) in4 << 16);
*__SIMD32(pDst)++ = in1;
*__SIMD32(pDst)++ = in2;
*__SIMD32(pDst)++ = in3;
*__SIMD32(pDst)++ = in4;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[0]+jC[1] = A[0]+ j (-1) A[1] */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
*pDst++ = *pSrc++;
*pDst++ = __SSAT(-*pSrc++, 16);
/* Decrement the loop counter */
blkCnt--;
}
#else
q15_t in;
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* realOut + j (imagOut) = realIn+ j (-1) imagIn */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
*pDst++ = *pSrc++;
in = *pSrc++;
*pDst++ = (in == (q15_t) 0x8000) ? 0x7fff : -in;
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of cmplx_conj group
*/

View File

@ -1,172 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_conj_q31.c
*
* Description: Q31 complex conjugate.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_conj
* @{
*/
/**
* @brief Q31 complex conjugate.
* @param *pSrc points to the input vector
* @param *pDst points to the output vector
* @param numSamples number of complex samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.
*/
void arm_cmplx_conj_q31(
q31_t * pSrc,
q31_t * pDst,
uint32_t numSamples)
{
uint32_t blkCnt; /* loop counter */
q31_t in; /* Input value */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t inR1, inR2, inR3, inR4; /* Temporary real variables */
q31_t inI1, inI2, inI3, inI4; /* Temporary imaginary variables */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0]+jC[1] = A[0]+ j (-1) A[1] */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
/* Saturated to 0x7fffffff if the input is -1(0x80000000) */
/* read real input sample */
inR1 = pSrc[0];
/* store real input sample */
pDst[0] = inR1;
/* read imaginary input sample */
inI1 = pSrc[1];
/* read real input sample */
inR2 = pSrc[2];
/* store real input sample */
pDst[2] = inR2;
/* read imaginary input sample */
inI2 = pSrc[3];
/* negate imaginary input sample */
inI1 = __QSUB(0, inI1);
/* read real input sample */
inR3 = pSrc[4];
/* store real input sample */
pDst[4] = inR3;
/* read imaginary input sample */
inI3 = pSrc[5];
/* negate imaginary input sample */
inI2 = __QSUB(0, inI2);
/* read real input sample */
inR4 = pSrc[6];
/* store real input sample */
pDst[6] = inR4;
/* negate imaginary input sample */
inI3 = __QSUB(0, inI3);
/* store imaginary input sample */
inI4 = pSrc[7];
/* store imaginary input samples */
pDst[1] = inI1;
/* negate imaginary input sample */
inI4 = __QSUB(0, inI4);
/* store imaginary input samples */
pDst[3] = inI2;
/* increment source pointer by 8 to proecess next samples */
pSrc += 8u;
/* store imaginary input samples */
pDst[5] = inI3;
pDst[7] = inI4;
/* increment destination pointer by 8 to process next samples */
pDst += 8u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C[0]+jC[1] = A[0]+ j (-1) A[1] */
/* Calculate Complex Conjugate and then store the results in the destination buffer. */
/* Saturated to 0x7fffffff if the input is -1(0x80000000) */
*pDst++ = *pSrc++;
in = *pSrc++;
*pDst++ = (in == 0x80000000) ? 0x7fffffff : -in;
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of cmplx_conj group
*/

View File

@ -1,160 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_dot_prod_f32.c
*
* Description: Floating-point complex dot product
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup cmplx_dot_prod Complex Dot Product
*
* Computes the dot product of two complex vectors.
* The vectors are multiplied element-by-element and then summed.
*
* The <code>pSrcA</code> points to the first complex input vector and
* <code>pSrcB</code> points to the second complex input vector.
* <code>numSamples</code> specifies the number of complex samples
* and the data in each array is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* Each array has a total of <code>2*numSamples</code> values.
*
* The underlying algorithm is used:
* <pre>
* realResult=0;
* imagResult=0;
* for(n=0; n<numSamples; n++) {
* realResult += pSrcA[(2*n)+0]*pSrcB[(2*n)+0] - pSrcA[(2*n)+1]*pSrcB[(2*n)+1];
* imagResult += pSrcA[(2*n)+0]*pSrcB[(2*n)+1] + pSrcA[(2*n)+1]*pSrcB[(2*n)+0];
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup cmplx_dot_prod
* @{
*/
/**
* @brief Floating-point complex dot product
* @param *pSrcA points to the first input vector
* @param *pSrcB points to the second input vector
* @param numSamples number of complex samples in each vector
* @param *realResult real part of the result returned here
* @param *imagResult imaginary part of the result returned here
* @return none.
*/
void arm_cmplx_dot_prod_f32(
float32_t * pSrcA,
float32_t * pSrcB,
uint32_t numSamples,
float32_t * realResult,
float32_t * imagResult)
{
float32_t real_sum = 0.0f, imag_sum = 0.0f; /* Temporary result storage */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += (*pSrcA++) * (*pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += (*pSrcA++) * (*pSrcB++);
real_sum += (*pSrcA++) * (*pSrcB++);
imag_sum += (*pSrcA++) * (*pSrcB++);
real_sum += (*pSrcA++) * (*pSrcB++);
imag_sum += (*pSrcA++) * (*pSrcB++);
real_sum += (*pSrcA++) * (*pSrcB++);
imag_sum += (*pSrcA++) * (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += (*pSrcA++) * (*pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += (*pSrcA++) * (*pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += (*pSrcA++) * (*pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += (*pSrcA++) * (*pSrcB++);
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
/* Store the real and imaginary results in the destination buffers */
*realResult = real_sum;
*imagResult = imag_sum;
}
/**
* @} end of cmplx_dot_prod group
*/

View File

@ -1,144 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_dot_prod_q15.c
*
* Description: Processing function for the Q15 Complex Dot product
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_dot_prod
* @{
*/
/**
* @brief Q15 complex dot product
* @param *pSrcA points to the first input vector
* @param *pSrcB points to the second input vector
* @param numSamples number of complex samples in each vector
* @param *realResult real part of the result returned here
* @param *imagResult imaginary part of the result returned here
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function is implemented using an internal 64-bit accumulator.
* The intermediate 1.15 by 1.15 multiplications are performed with full precision and yield a 2.30 result.
* These are accumulated in a 64-bit accumulator with 34.30 precision.
* As a final step, the accumulators are converted to 8.24 format.
* The return results <code>realResult</code> and <code>imagResult</code> are in 8.24 format.
*/
void arm_cmplx_dot_prod_q15(
q15_t * pSrcA,
q15_t * pSrcB,
uint32_t numSamples,
q31_t * realResult,
q31_t * imagResult)
{
q63_t real_sum = 0, imag_sum = 0; /* Temporary result storage */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += ((q31_t) * pSrcA++ * *pSrcB++);
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
/* Store the real and imaginary results in 8.24 format */
/* Convert real data in 34.30 to 8.24 by 6 right shifts */
*realResult = (q31_t) (real_sum) >> 6;
/* Convert imaginary data in 34.30 to 8.24 by 6 right shifts */
*imagResult = (q31_t) (imag_sum) >> 6;
}
/**
* @} end of cmplx_dot_prod group
*/

View File

@ -1,145 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_dot_prod_q31.c
*
* Description: Q31 complex dot product
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_dot_prod
* @{
*/
/**
* @brief Q31 complex dot product
* @param *pSrcA points to the first input vector
* @param *pSrcB points to the second input vector
* @param numSamples number of complex samples in each vector
* @param *realResult real part of the result returned here
* @param *imagResult imaginary part of the result returned here
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function is implemented using an internal 64-bit accumulator.
* The intermediate 1.31 by 1.31 multiplications are performed with 64-bit precision and then shifted to 16.48 format.
* The internal real and imaginary accumulators are in 16.48 format and provide 15 guard bits.
* Additions are nonsaturating and no overflow will occur as long as <code>numSamples</code> is less than 32768.
* The return results <code>realResult</code> and <code>imagResult</code> are in 16.48 format.
* Input down scaling is not required.
*/
void arm_cmplx_dot_prod_q31(
q31_t * pSrcA,
q31_t * pSrcB,
uint32_t numSamples,
q63_t * realResult,
q63_t * imagResult)
{
q63_t real_sum = 0, imag_sum = 0; /* Temporary result storage */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
/* Convert real data in 2.62 to 16.48 by 14 right shifts */
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
/* Convert imag data in 2.62 to 16.48 by 14 right shifts */
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* CReal = A[0]* B[0] + A[2]* B[2] + A[4]* B[4] + .....+ A[numSamples-2]* B[numSamples-2] */
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* CImag = A[1]* B[1] + A[3]* B[3] + A[5]* B[5] + .....+ A[numSamples-1]* B[numSamples-1] */
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* outReal = realA[0]* realB[0] + realA[2]* realB[2] + realA[4]* realB[4] + .....+ realA[numSamples-2]* realB[numSamples-2] */
real_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* outImag = imagA[1]* imagB[1] + imagA[3]* imagB[3] + imagA[5]* imagB[5] + .....+ imagA[numSamples-1]* imagB[numSamples-1] */
imag_sum += (q63_t) * pSrcA++ * (*pSrcB++) >> 14;
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
/* Store the real and imaginary results in 16.48 format */
*realResult = real_sum;
*imagResult = imag_sum;
}
/**
* @} end of cmplx_dot_prod group
*/

View File

@ -1,157 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_f32.c
*
* Description: Floating-point complex magnitude.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup cmplx_mag Complex Magnitude
*
* Computes the magnitude of the elements of a complex data vector.
*
* The <code>pSrc</code> points to the source data and
* <code>pDst</code> points to the where the result should be written.
* <code>numSamples</code> specifies the number of complex samples
* in the input array and the data is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* The input array has a total of <code>2*numSamples</code> values;
* the output array has a total of <code>numSamples</code> values.
* The underlying algorithm is used:
*
* <pre>
* for(n=0; n<numSamples; n++) {
* pDst[n] = sqrt(pSrc[(2*n)+0]^2 + pSrc[(2*n)+1]^2);
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup cmplx_mag
* @{
*/
/**
* @brief Floating-point complex magnitude.
* @param[in] *pSrc points to complex input buffer
* @param[out] *pDst points to real output buffer
* @param[in] numSamples number of complex samples in the input vector
* @return none.
*
*/
void arm_cmplx_mag_f32(
float32_t * pSrc,
float32_t * pDst,
uint32_t numSamples)
{
float32_t realIn, imagIn; /* Temporary variables to hold input values */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
realIn = *pSrc++;
imagIn = *pSrc++;
/* store the result in the destination buffer. */
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
realIn = *pSrc++;
imagIn = *pSrc++;
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
realIn = *pSrc++;
imagIn = *pSrc++;
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
realIn = *pSrc++;
imagIn = *pSrc++;
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
realIn = *pSrc++;
imagIn = *pSrc++;
/* store the result in the destination buffer. */
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* out = sqrt((real * real) + (imag * imag)) */
realIn = *pSrc++;
imagIn = *pSrc++;
/* store the result in the destination buffer. */
arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of cmplx_mag group
*/

View File

@ -1,145 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_q15.c
*
* Description: Q15 complex magnitude.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_mag
* @{
*/
/**
* @brief Q15 complex magnitude
* @param *pSrc points to the complex input vector
* @param *pDst points to the real output vector
* @param numSamples number of complex samples in the input vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.15 by 1.15 multiplications and finally output is converted into 2.14 format.
*/
void arm_cmplx_mag_q15(
q15_t * pSrc,
q15_t * pDst,
uint32_t numSamples)
{
q31_t acc0, acc1; /* Accumulators */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
q31_t in1, in2, in3, in4;
q31_t acc2, acc3;
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
in1 = *__SIMD32(pSrc)++;
in2 = *__SIMD32(pSrc)++;
in3 = *__SIMD32(pSrc)++;
in4 = *__SIMD32(pSrc)++;
acc0 = __SMUAD(in1, in1);
acc1 = __SMUAD(in2, in2);
acc2 = __SMUAD(in3, in3);
acc3 = __SMUAD(in4, in4);
/* store the result in 2.14 format in the destination buffer. */
arm_sqrt_q15((q15_t) ((acc0) >> 17), pDst++);
arm_sqrt_q15((q15_t) ((acc1) >> 17), pDst++);
arm_sqrt_q15((q15_t) ((acc2) >> 17), pDst++);
arm_sqrt_q15((q15_t) ((acc3) >> 17), pDst++);
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
in1 = *__SIMD32(pSrc)++;
acc0 = __SMUAD(in1, in1);
/* store the result in 2.14 format in the destination buffer. */
arm_sqrt_q15((q15_t) (acc0 >> 17), pDst++);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
q15_t real, imag; /* Temporary variables to hold input values */
while(numSamples > 0u)
{
/* out = sqrt(real * real + imag * imag) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (real * real);
acc1 = (imag * imag);
/* store the result in 2.14 format in the destination buffer. */
arm_sqrt_q15((q15_t) (((q63_t) acc0 + acc1) >> 17), pDst++);
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of cmplx_mag group
*/

View File

@ -1,177 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_q31.c
*
* Description: Q31 complex magnitude
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_mag
* @{
*/
/**
* @brief Q31 complex magnitude
* @param *pSrc points to the complex input vector
* @param *pDst points to the real output vector
* @param numSamples number of complex samples in the input vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.31 by 1.31 multiplications and finally output is converted into 2.30 format.
* Input down scaling is not required.
*/
void arm_cmplx_mag_q31(
q31_t * pSrc,
q31_t * pDst,
uint32_t numSamples)
{
q31_t real, imag; /* Temporary variables to hold input values */
q31_t acc0, acc1; /* Accumulators */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
q31_t real1, real2, imag1, imag2; /* Temporary variables to hold input values */
q31_t out1, out2, out3, out4; /* Accumulators */
q63_t mul1, mul2, mul3, mul4; /* Temporary variables */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* read complex input from source buffer */
real1 = pSrc[0];
imag1 = pSrc[1];
real2 = pSrc[2];
imag2 = pSrc[3];
/* calculate power of input values */
mul1 = (q63_t) real1 *real1;
mul2 = (q63_t) imag1 *imag1;
mul3 = (q63_t) real2 *real2;
mul4 = (q63_t) imag2 *imag2;
/* get the result to 3.29 format */
out1 = (q31_t) (mul1 >> 33);
out2 = (q31_t) (mul2 >> 33);
out3 = (q31_t) (mul3 >> 33);
out4 = (q31_t) (mul4 >> 33);
/* add real and imaginary accumulators */
out1 = out1 + out2;
out3 = out3 + out4;
/* read complex input from source buffer */
real1 = pSrc[4];
imag1 = pSrc[5];
real2 = pSrc[6];
imag2 = pSrc[7];
/* calculate square root */
arm_sqrt_q31(out1, &pDst[0]);
/* calculate power of input values */
mul1 = (q63_t) real1 *real1;
/* calculate square root */
arm_sqrt_q31(out3, &pDst[1]);
/* calculate power of input values */
mul2 = (q63_t) imag1 *imag1;
mul3 = (q63_t) real2 *real2;
mul4 = (q63_t) imag2 *imag2;
/* get the result to 3.29 format */
out1 = (q31_t) (mul1 >> 33);
out2 = (q31_t) (mul2 >> 33);
out3 = (q31_t) (mul3 >> 33);
out4 = (q31_t) (mul4 >> 33);
/* add real and imaginary accumulators */
out1 = out1 + out2;
out3 = out3 + out4;
/* calculate square root */
arm_sqrt_q31(out1, &pDst[2]);
/* increment destination by 8 to process next samples */
pSrc += 8u;
/* calculate square root */
arm_sqrt_q31(out3, &pDst[3]);
/* increment destination by 4 to process next samples */
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 2.30 format in the destination buffer. */
arm_sqrt_q31(acc0 + acc1, pDst++);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of cmplx_mag group
*/

View File

@ -1,207 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_squared_f32.c
*
* Description: Floating-point complex magnitude squared.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup cmplx_mag_squared Complex Magnitude Squared
*
* Computes the magnitude squared of the elements of a complex data vector.
*
* The <code>pSrc</code> points to the source data and
* <code>pDst</code> points to the where the result should be written.
* <code>numSamples</code> specifies the number of complex samples
* in the input array and the data is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* The input array has a total of <code>2*numSamples</code> values;
* the output array has a total of <code>numSamples</code> values.
*
* The underlying algorithm is used:
*
* <pre>
* for(n=0; n<numSamples; n++) {
* pDst[n] = pSrc[(2*n)+0]^2 + pSrc[(2*n)+1]^2;
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup cmplx_mag_squared
* @{
*/
/**
* @brief Floating-point complex magnitude squared
* @param[in] *pSrc points to the complex input vector
* @param[out] *pDst points to the real output vector
* @param[in] numSamples number of complex samples in the input vector
* @return none.
*/
void arm_cmplx_mag_squared_f32(
float32_t * pSrc,
float32_t * pDst,
uint32_t numSamples)
{
float32_t real, imag; /* Temporary variables to store real and imaginary values */
uint32_t blkCnt; /* loop counter */
#ifndef ARM_MATH_CM0
float32_t real1, real2, real3, real4; /* Temporary variables to hold real values */
float32_t imag1, imag2, imag3, imag4; /* Temporary variables to hold imaginary values */
float32_t mul1, mul2, mul3, mul4; /* Temporary variables */
float32_t mul5, mul6, mul7, mul8; /* Temporary variables */
float32_t out1, out2, out3, out4; /* Temporary variables to hold output values */
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
/* read real input sample from source buffer */
real1 = pSrc[0];
/* read imaginary input sample from source buffer */
imag1 = pSrc[1];
/* calculate power of real value */
mul1 = real1 * real1;
/* read real input sample from source buffer */
real2 = pSrc[2];
/* calculate power of imaginary value */
mul2 = imag1 * imag1;
/* read imaginary input sample from source buffer */
imag2 = pSrc[3];
/* calculate power of real value */
mul3 = real2 * real2;
/* read real input sample from source buffer */
real3 = pSrc[4];
/* calculate power of imaginary value */
mul4 = imag2 * imag2;
/* read imaginary input sample from source buffer */
imag3 = pSrc[5];
/* calculate power of real value */
mul5 = real3 * real3;
/* calculate power of imaginary value */
mul6 = imag3 * imag3;
/* read real input sample from source buffer */
real4 = pSrc[6];
/* accumulate real and imaginary powers */
out1 = mul1 + mul2;
/* read imaginary input sample from source buffer */
imag4 = pSrc[7];
/* accumulate real and imaginary powers */
out2 = mul3 + mul4;
/* calculate power of real value */
mul7 = real4 * real4;
/* calculate power of imaginary value */
mul8 = imag4 * imag4;
/* store output to destination */
pDst[0] = out1;
/* accumulate real and imaginary powers */
out3 = mul5 + mul6;
/* store output to destination */
pDst[1] = out2;
/* accumulate real and imaginary powers */
out4 = mul7 + mul8;
/* store output to destination */
pDst[2] = out3;
/* increment destination pointer by 8 to process next samples */
pSrc += 8u;
/* store output to destination */
pDst[3] = out4;
/* increment destination pointer by 4 to process next samples */
pDst += 4u;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
real = *pSrc++;
imag = *pSrc++;
/* out = (real * real) + (imag * imag) */
/* store the result in the destination buffer. */
*pDst++ = (real * real) + (imag * imag);
/* Decrement the loop counter */
blkCnt--;
}
}
/**
* @} end of cmplx_mag_squared group
*/

View File

@ -1,140 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_squared_q15.c
*
* Description: Q15 complex magnitude squared.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_mag_squared
* @{
*/
/**
* @brief Q15 complex magnitude squared
* @param *pSrc points to the complex input vector
* @param *pDst points to the real output vector
* @param numSamples number of complex samples in the input vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.15 by 1.15 multiplications and finally output is converted into 3.13 format.
*/
void arm_cmplx_mag_squared_q15(
q15_t * pSrc,
q15_t * pDst,
uint32_t numSamples)
{
q31_t acc0, acc1; /* Accumulators */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
q31_t in1, in2, in3, in4;
q31_t acc2, acc3;
/*loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
in1 = *__SIMD32(pSrc)++;
in2 = *__SIMD32(pSrc)++;
in3 = *__SIMD32(pSrc)++;
in4 = *__SIMD32(pSrc)++;
acc0 = __SMUAD(in1, in1);
acc1 = __SMUAD(in2, in2);
acc2 = __SMUAD(in3, in3);
acc3 = __SMUAD(in4, in4);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ = (q15_t) (acc0 >> 17);
*pDst++ = (q15_t) (acc1 >> 17);
*pDst++ = (q15_t) (acc2 >> 17);
*pDst++ = (q15_t) (acc3 >> 17);
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
in1 = *__SIMD32(pSrc)++;
acc0 = __SMUAD(in1, in1);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ = (q15_t) (acc0 >> 17);
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
q15_t real, imag; /* Temporary variables to store real and imaginary values */
while(numSamples > 0u)
{
/* out = ((real * real) + (imag * imag)) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (real * real);
acc1 = (imag * imag);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ = (q15_t) (((q63_t) acc0 + acc1) >> 17);
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of cmplx_mag_squared group
*/

View File

@ -1,153 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mag_squared_q31.c
*
* Description: Q31 complex magnitude squared.
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ---------------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup cmplx_mag_squared
* @{
*/
/**
* @brief Q31 complex magnitude squared
* @param *pSrc points to the complex input vector
* @param *pDst points to the real output vector
* @param numSamples number of complex samples in the input vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.31 by 1.31 multiplications and finally output is converted into 3.29 format.
* Input down scaling is not required.
*/
void arm_cmplx_mag_squared_q31(
q31_t * pSrc,
q31_t * pDst,
uint32_t numSamples)
{
q31_t real, imag; /* Temporary variables to store real and imaginary values */
q31_t acc0, acc1; /* Accumulators */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counter */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
/* Decrement the loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[0] = (A[0] * A[0] + A[1] * A[1]) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
/* Decrement the loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* out = ((real * real) + (imag * imag)) */
real = *pSrc++;
imag = *pSrc++;
acc0 = (q31_t) (((q63_t) real * real) >> 33);
acc1 = (q31_t) (((q63_t) imag * imag) >> 33);
/* store the result in 3.29 format in the destination buffer. */
*pDst++ = acc0 + acc1;
/* Decrement the loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of cmplx_mag_squared group
*/

View File

@ -1,199 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_cmplx_f32.c
*
* Description: Floating-point complex-by-complex multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup CmplxByCmplxMult Complex-by-Complex Multiplication
*
* Multiplies a complex vector by another complex vector and generates a complex result.
* The data in the complex arrays is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* The parameter <code>numSamples</code> represents the number of complex
* samples processed. The complex arrays have a total of <code>2*numSamples</code>
* real values.
*
* The underlying algorithm is used:
*
* <pre>
* for(n=0; n<numSamples; n++) {
* pDst[(2*n)+0] = pSrcA[(2*n)+0] * pSrcB[(2*n)+0] - pSrcA[(2*n)+1] * pSrcB[(2*n)+1];
* pDst[(2*n)+1] = pSrcA[(2*n)+0] * pSrcB[(2*n)+1] + pSrcA[(2*n)+1] * pSrcB[(2*n)+0];
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup CmplxByCmplxMult
* @{
*/
/**
* @brief Floating-point complex-by-complex multiplication
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] numSamples number of complex samples in each vector
* @return none.
*/
void arm_cmplx_mult_cmplx_f32(
float32_t * pSrcA,
float32_t * pSrcB,
float32_t * pDst,
uint32_t numSamples)
{
float32_t a1, b1, c1, d1; /* Temporary variables to store real and imaginary values */
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t a2, b2, c2, d2; /* Temporary variables to store real and imaginary values */
float32_t acc1, acc2, acc3, acc4;
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a1 = *pSrcA; /* A[2 * i] */
c1 = *pSrcB; /* B[2 * i] */
b1 = *(pSrcA + 1); /* A[2 * i + 1] */
acc1 = a1 * c1; /* acc1 = A[2 * i] * B[2 * i] */
a2 = *(pSrcA + 2); /* A[2 * i + 2] */
acc2 = (b1 * c1); /* acc2 = A[2 * i + 1] * B[2 * i] */
d1 = *(pSrcB + 1); /* B[2 * i + 1] */
c2 = *(pSrcB + 2); /* B[2 * i + 2] */
acc1 -= b1 * d1; /* acc1 = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1] */
d2 = *(pSrcB + 3); /* B[2 * i + 3] */
acc3 = a2 * c2; /* acc3 = A[2 * i + 2] * B[2 * i + 2] */
b2 = *(pSrcA + 3); /* A[2 * i + 3] */
acc2 += (a1 * d1); /* acc2 = A[2 * i + 1] * B[2 * i] + A[2 * i] * B[2 * i + 1] */
a1 = *(pSrcA + 4); /* A[2 * i + 4] */
acc4 = (a2 * d2); /* acc4 = A[2 * i + 2] * B[2 * i + 3] */
c1 = *(pSrcB + 4); /* B[2 * i + 4] */
acc3 -= (b2 * d2); /* acc3 = A[2 * i + 2] * B[2 * i + 2] - A[2 * i + 3] * B[2 * i + 3] */
*pDst = acc1; /* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1] */
b1 = *(pSrcA + 5); /* A[2 * i + 5] */
acc4 += b2 * c2; /* acc4 = A[2 * i + 2] * B[2 * i + 3] + A[2 * i + 3] * B[2 * i + 2] */
*(pDst + 1) = acc2; /* C[2 * i + 1] = A[2 * i + 1] * B[2 * i] + A[2 * i] * B[2 * i + 1] */
acc1 = (a1 * c1);
d1 = *(pSrcB + 5);
acc2 = (b1 * c1);
*(pDst + 2) = acc3;
*(pDst + 3) = acc4;
a2 = *(pSrcA + 6);
acc1 -= (b1 * d1);
c2 = *(pSrcB + 6);
acc2 += (a1 * d1);
b2 = *(pSrcA + 7);
acc3 = (a2 * c2);
d2 = *(pSrcB + 7);
acc4 = (b2 * c2);
*(pDst + 4) = acc1;
pSrcA += 8u;
acc3 -= (b2 * d2);
acc4 += (a2 * d2);
*(pDst + 5) = acc2;
pSrcB += 8u;
*(pDst + 6) = acc3;
*(pDst + 7) = acc4;
pDst += 8u;
/* Decrement the numSamples loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a1 = *pSrcA++;
b1 = *pSrcA++;
c1 = *pSrcB++;
d1 = *pSrcB++;
/* store the result in the destination buffer. */
*pDst++ = (a1 * c1) - (b1 * d1);
*pDst++ = (a1 * d1) + (b1 * c1);
/* Decrement the numSamples loop counter */
blkCnt--;
}
}
/**
* @} end of CmplxByCmplxMult group
*/

View File

@ -1,185 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_cmplx_q15.c
*
* Description: Q15 complex-by-complex multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup CmplxByCmplxMult
* @{
*/
/**
* @brief Q15 complex-by-complex multiplication
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] numSamples number of complex samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.15 by 1.15 multiplications and finally output is converted into 3.13 format.
*/
void arm_cmplx_mult_cmplx_q15(
q15_t * pSrcA,
q15_t * pSrcB,
q15_t * pDst,
uint32_t numSamples)
{
q15_t a, b, c, d; /* Temporary variables to store real and imaginary values */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counters */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
/* Decrement the blockSize loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * c) >> 17) - (((q31_t) b * d) >> 17);
/* store the result in 3.13 format in the destination buffer. */
*pDst++ =
(q15_t) (q31_t) (((q31_t) a * d) >> 17) + (((q31_t) b * c) >> 17);
/* Decrement the blockSize loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of CmplxByCmplxMult group
*/

View File

@ -1,318 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_cmplx_q31.c
*
* Description: Q31 complex-by-complex multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup CmplxByCmplxMult
* @{
*/
/**
* @brief Q31 complex-by-complex multiplication
* @param[in] *pSrcA points to the first input vector
* @param[in] *pSrcB points to the second input vector
* @param[out] *pDst points to the output vector
* @param[in] numSamples number of complex samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function implements 1.31 by 1.31 multiplications and finally output is converted into 3.29 format.
* Input down scaling is not required.
*/
void arm_cmplx_mult_cmplx_q31(
q31_t * pSrcA,
q31_t * pSrcB,
q31_t * pDst,
uint32_t numSamples)
{
q31_t a, b, c, d; /* Temporary variables to store real and imaginary values */
uint32_t blkCnt; /* loop counters */
q31_t mul1, mul2, mul3, mul4;
q31_t out1, out2;
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
/* Decrement the blockSize loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
/* loop Unrolling */
blkCnt = numSamples >> 1u;
/* First part of the processing with loop unrolling. Compute 2 outputs at a time.
** a second loop below computes the remaining 1 sample. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
/* Decrement the blockSize loop counter */
blkCnt--;
}
/* If the blockSize is not a multiple of 2, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x2u;
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[2 * i] - A[2 * i + 1] * B[2 * i + 1]. */
/* C[2 * i + 1] = A[2 * i] * B[2 * i + 1] + A[2 * i + 1] * B[2 * i]. */
a = *pSrcA++;
b = *pSrcA++;
c = *pSrcB++;
d = *pSrcB++;
mul1 = (q31_t) (((q63_t) a * c) >> 32);
mul2 = (q31_t) (((q63_t) b * d) >> 32);
mul3 = (q31_t) (((q63_t) a * d) >> 32);
mul4 = (q31_t) (((q63_t) b * c) >> 32);
mul1 = (mul1 >> 1);
mul2 = (mul2 >> 1);
mul3 = (mul3 >> 1);
mul4 = (mul4 >> 1);
out1 = mul1 - mul2;
out2 = mul3 + mul4;
/* store the real result in 3.29 format in the destination buffer. */
*pDst++ = out1;
/* store the imag result in 3.29 format in the destination buffer. */
*pDst++ = out2;
/* Decrement the blockSize loop counter */
blkCnt--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of CmplxByCmplxMult group
*/

View File

@ -1,217 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_real_f32.c
*
* Description: Floating-point complex by real multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @defgroup CmplxByRealMult Complex-by-Real Multiplication
*
* Multiplies a complex vector by a real vector and generates a complex result.
* The data in the complex arrays is stored in an interleaved fashion
* (real, imag, real, imag, ...).
* The parameter <code>numSamples</code> represents the number of complex
* samples processed. The complex arrays have a total of <code>2*numSamples</code>
* real values while the real array has a total of <code>numSamples</code>
* real values.
*
* The underlying algorithm is used:
*
* <pre>
* for(n=0; n<numSamples; n++) {
* pCmplxDst[(2*n)+0] = pSrcCmplx[(2*n)+0] * pSrcReal[n];
* pCmplxDst[(2*n)+1] = pSrcCmplx[(2*n)+1] * pSrcReal[n];
* }
* </pre>
*
* There are separate functions for floating-point, Q15, and Q31 data types.
*/
/**
* @addtogroup CmplxByRealMult
* @{
*/
/**
* @brief Floating-point complex-by-real multiplication
* @param[in] *pSrcCmplx points to the complex input vector
* @param[in] *pSrcReal points to the real input vector
* @param[out] *pCmplxDst points to the complex output vector
* @param[in] numSamples number of samples in each vector
* @return none.
*/
void arm_cmplx_mult_real_f32(
float32_t * pSrcCmplx,
float32_t * pSrcReal,
float32_t * pCmplxDst,
uint32_t numSamples)
{
float32_t in; /* Temporary variable to store input value */
uint32_t blkCnt; /* loop counters */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
float32_t inA1, inA2, inA3, inA4; /* Temporary variables to hold input data */
float32_t inA5, inA6, inA7, inA8; /* Temporary variables to hold input data */
float32_t inB1, inB2, inB3, inB4; /* Temporary variables to hold input data */
float32_t out1, out2, out3, out4; /* Temporary variables to hold output data */
float32_t out5, out6, out7, out8; /* Temporary variables to hold output data */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
/* read input from complex input buffer */
inA1 = pSrcCmplx[0];
inA2 = pSrcCmplx[1];
/* read input from real input buffer */
inB1 = pSrcReal[0];
/* read input from complex input buffer */
inA3 = pSrcCmplx[2];
/* multiply complex buffer real input with real buffer input */
out1 = inA1 * inB1;
/* read input from complex input buffer */
inA4 = pSrcCmplx[3];
/* multiply complex buffer imaginary input with real buffer input */
out2 = inA2 * inB1;
/* read input from real input buffer */
inB2 = pSrcReal[1];
/* read input from complex input buffer */
inA5 = pSrcCmplx[4];
/* multiply complex buffer real input with real buffer input */
out3 = inA3 * inB2;
/* read input from complex input buffer */
inA6 = pSrcCmplx[5];
/* read input from real input buffer */
inB3 = pSrcReal[2];
/* multiply complex buffer imaginary input with real buffer input */
out4 = inA4 * inB2;
/* read input from complex input buffer */
inA7 = pSrcCmplx[6];
/* multiply complex buffer real input with real buffer input */
out5 = inA5 * inB3;
/* read input from complex input buffer */
inA8 = pSrcCmplx[7];
/* multiply complex buffer imaginary input with real buffer input */
out6 = inA6 * inB3;
/* read input from real input buffer */
inB4 = pSrcReal[3];
/* store result to destination bufer */
pCmplxDst[0] = out1;
/* multiply complex buffer real input with real buffer input */
out7 = inA7 * inB4;
/* store result to destination bufer */
pCmplxDst[1] = out2;
/* multiply complex buffer imaginary input with real buffer input */
out8 = inA8 * inB4;
/* store result to destination bufer */
pCmplxDst[2] = out3;
pCmplxDst[3] = out4;
pCmplxDst[4] = out5;
/* incremnet complex input buffer by 8 to process next samples */
pSrcCmplx += 8u;
/* store result to destination bufer */
pCmplxDst[5] = out6;
/* increment real input buffer by 4 to process next samples */
pSrcReal += 4u;
/* store result to destination bufer */
pCmplxDst[6] = out7;
pCmplxDst[7] = out8;
/* increment destination buffer by 8 to process next sampels */
pCmplxDst += 8u;
/* Decrement the numSamples loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
#else
/* Run the below code for Cortex-M0 */
blkCnt = numSamples;
#endif /* #ifndef ARM_MATH_CM0 */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
in = *pSrcReal++;
/* store the result in the destination buffer. */
*pCmplxDst++ = (*pSrcCmplx++) * (in);
*pCmplxDst++ = (*pSrcCmplx++) * (in);
/* Decrement the numSamples loop counter */
blkCnt--;
}
}
/**
* @} end of CmplxByRealMult group
*/

View File

@ -1,195 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_real_q15.c
*
* Description: Q15 complex by real multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup CmplxByRealMult
* @{
*/
/**
* @brief Q15 complex-by-real multiplication
* @param[in] *pSrcCmplx points to the complex input vector
* @param[in] *pSrcReal points to the real input vector
* @param[out] *pCmplxDst points to the complex output vector
* @param[in] numSamples number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.
*/
void arm_cmplx_mult_real_q15(
q15_t * pSrcCmplx,
q15_t * pSrcReal,
q15_t * pCmplxDst,
uint32_t numSamples)
{
q15_t in; /* Temporary variable to store input value */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counters */
q31_t inA1, inA2; /* Temporary variables to hold input data */
q31_t inB1; /* Temporary variables to hold input data */
q15_t out1, out2, out3, out4; /* Temporary variables to hold output data */
q31_t mul1, mul2, mul3, mul4; /* Temporary variables to hold intermediate data */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
/* read complex number both real and imaginary from complex input buffer */
inA1 = *__SIMD32(pSrcCmplx)++;
/* read two real values at a time from real input buffer */
inB1 = *__SIMD32(pSrcReal)++;
/* read complex number both real and imaginary from complex input buffer */
inA2 = *__SIMD32(pSrcCmplx)++;
/* multiply complex number with real numbers */
#ifndef ARM_MATH_BIG_ENDIAN
mul1 = (q31_t) ((q15_t) (inA1) * (q15_t) (inB1));
mul2 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1));
mul3 = (q31_t) ((q15_t) (inA2) * (q15_t) (inB1 >> 16));
mul4 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) (inB1 >> 16));
#else
mul2 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1 >> 16));
mul1 = (q31_t) ((q15_t) inA1 * (q15_t) (inB1 >> 16));
mul4 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) inB1);
mul3 = (q31_t) ((q15_t) inA2 * (q15_t) inB1);
#endif // #ifndef ARM_MATH_BIG_ENDIAN
/* saturate the result */
out1 = (q15_t) __SSAT(mul1 >> 15u, 16);
out2 = (q15_t) __SSAT(mul2 >> 15u, 16);
out3 = (q15_t) __SSAT(mul3 >> 15u, 16);
out4 = (q15_t) __SSAT(mul4 >> 15u, 16);
/* pack real and imaginary outputs and store them to destination */
*__SIMD32(pCmplxDst)++ = __PKHBT(out1, out2, 16);
*__SIMD32(pCmplxDst)++ = __PKHBT(out3, out4, 16);
inA1 = *__SIMD32(pSrcCmplx)++;
inB1 = *__SIMD32(pSrcReal)++;
inA2 = *__SIMD32(pSrcCmplx)++;
#ifndef ARM_MATH_BIG_ENDIAN
mul1 = (q31_t) ((q15_t) (inA1) * (q15_t) (inB1));
mul2 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1));
mul3 = (q31_t) ((q15_t) (inA2) * (q15_t) (inB1 >> 16));
mul4 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) (inB1 >> 16));
#else
mul2 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1 >> 16));
mul1 = (q31_t) ((q15_t) inA1 * (q15_t) (inB1 >> 16));
mul4 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) inB1);
mul3 = (q31_t) ((q15_t) inA2 * (q15_t) inB1);
#endif // #ifndef ARM_MATH_BIG_ENDIAN
out1 = (q15_t) __SSAT(mul1 >> 15u, 16);
out2 = (q15_t) __SSAT(mul2 >> 15u, 16);
out3 = (q15_t) __SSAT(mul3 >> 15u, 16);
out4 = (q15_t) __SSAT(mul4 >> 15u, 16);
*__SIMD32(pCmplxDst)++ = __PKHBT(out1, out2, 16);
*__SIMD32(pCmplxDst)++ = __PKHBT(out3, out4, 16);
/* Decrement the numSamples loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
in = *pSrcReal++;
/* store the result in the destination buffer. */
*pCmplxDst++ =
(q15_t) __SSAT((((q31_t) (*pSrcCmplx++) * (in)) >> 15), 16);
*pCmplxDst++ =
(q15_t) __SSAT((((q31_t) (*pSrcCmplx++) * (in)) >> 15), 16);
/* Decrement the numSamples loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* realOut = realA * realB. */
/* imagOut = imagA * realB. */
in = *pSrcReal++;
/* store the result in the destination buffer. */
*pCmplxDst++ =
(q15_t) __SSAT((((q31_t) (*pSrcCmplx++) * (in)) >> 15), 16);
*pCmplxDst++ =
(q15_t) __SSAT((((q31_t) (*pSrcCmplx++) * (in)) >> 15), 16);
/* Decrement the numSamples loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of CmplxByRealMult group
*/

View File

@ -1,215 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_cmplx_mult_real_q31.c
*
* Description: Q31 complex by real multiplication
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @ingroup groupCmplxMath
*/
/**
* @addtogroup CmplxByRealMult
* @{
*/
/**
* @brief Q31 complex-by-real multiplication
* @param[in] *pSrcCmplx points to the complex input vector
* @param[in] *pSrcReal points to the real input vector
* @param[out] *pCmplxDst points to the complex output vector
* @param[in] numSamples number of samples in each vector
* @return none.
*
* <b>Scaling and Overflow Behavior:</b>
* \par
* The function uses saturating arithmetic.
* Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] will be saturated.
*/
void arm_cmplx_mult_real_q31(
q31_t * pSrcCmplx,
q31_t * pSrcReal,
q31_t * pCmplxDst,
uint32_t numSamples)
{
q31_t inA1; /* Temporary variable to store input value */
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
uint32_t blkCnt; /* loop counters */
q31_t inA2, inA3, inA4; /* Temporary variables to hold input data */
q31_t inB1, inB2; /* Temporary variabels to hold input data */
q31_t out1, out2, out3, out4; /* Temporary variables to hold output data */
/* loop Unrolling */
blkCnt = numSamples >> 2u;
/* First part of the processing with loop unrolling. Compute 4 outputs at a time.
** a second loop below computes the remaining 1 to 3 samples. */
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
/* read real input from complex input buffer */
inA1 = *pSrcCmplx++;
inA2 = *pSrcCmplx++;
/* read input from real input bufer */
inB1 = *pSrcReal++;
inB2 = *pSrcReal++;
/* read imaginary input from complex input buffer */
inA3 = *pSrcCmplx++;
inA4 = *pSrcCmplx++;
/* multiply complex input with real input */
out1 = ((q63_t) inA1 * inB1) >> 32;
out2 = ((q63_t) inA2 * inB1) >> 32;
out3 = ((q63_t) inA3 * inB2) >> 32;
out4 = ((q63_t) inA4 * inB2) >> 32;
/* sature the result */
out1 = __SSAT(out1, 31);
out2 = __SSAT(out2, 31);
out3 = __SSAT(out3, 31);
out4 = __SSAT(out4, 31);
/* get result in 1.31 format */
out1 = out1 << 1;
out2 = out2 << 1;
out3 = out3 << 1;
out4 = out4 << 1;
/* store the result to destination buffer */
*pCmplxDst++ = out1;
*pCmplxDst++ = out2;
*pCmplxDst++ = out3;
*pCmplxDst++ = out4;
/* read real input from complex input buffer */
inA1 = *pSrcCmplx++;
inA2 = *pSrcCmplx++;
/* read input from real input bufer */
inB1 = *pSrcReal++;
inB2 = *pSrcReal++;
/* read imaginary input from complex input buffer */
inA3 = *pSrcCmplx++;
inA4 = *pSrcCmplx++;
/* multiply complex input with real input */
out1 = ((q63_t) inA1 * inB1) >> 32;
out2 = ((q63_t) inA2 * inB1) >> 32;
out3 = ((q63_t) inA3 * inB2) >> 32;
out4 = ((q63_t) inA4 * inB2) >> 32;
/* sature the result */
out1 = __SSAT(out1, 31);
out2 = __SSAT(out2, 31);
out3 = __SSAT(out3, 31);
out4 = __SSAT(out4, 31);
/* get result in 1.31 format */
out1 = out1 << 1;
out2 = out2 << 1;
out3 = out3 << 1;
out4 = out4 << 1;
/* store the result to destination buffer */
*pCmplxDst++ = out1;
*pCmplxDst++ = out2;
*pCmplxDst++ = out3;
*pCmplxDst++ = out4;
/* Decrement the numSamples loop counter */
blkCnt--;
}
/* If the numSamples is not a multiple of 4, compute any remaining output samples here.
** No loop unrolling is used. */
blkCnt = numSamples % 0x4u;
while(blkCnt > 0u)
{
/* C[2 * i] = A[2 * i] * B[i]. */
/* C[2 * i + 1] = A[2 * i + 1] * B[i]. */
/* read real input from complex input buffer */
inA1 = *pSrcCmplx++;
inA2 = *pSrcCmplx++;
/* read input from real input bufer */
inB1 = *pSrcReal++;
/* multiply complex input with real input */
out1 = ((q63_t) inA1 * inB1) >> 32;
out2 = ((q63_t) inA2 * inB1) >> 32;
/* sature the result */
out1 = __SSAT(out1, 31);
out2 = __SSAT(out2, 31);
/* get result in 1.31 format */
out1 = out1 << 1;
out2 = out2 << 1;
/* store the result to destination buffer */
*pCmplxDst++ = out1;
*pCmplxDst++ = out2;
/* Decrement the numSamples loop counter */
blkCnt--;
}
#else
/* Run the below code for Cortex-M0 */
while(numSamples > 0u)
{
/* realOut = realA * realB. */
/* imagReal = imagA * realB. */
inA1 = *pSrcReal++;
/* store the result in the destination buffer. */
*pCmplxDst++ =
(q31_t) clip_q63_to_q31(((q63_t) * pSrcCmplx++ * inA1) >> 31);
*pCmplxDst++ =
(q31_t) clip_q63_to_q31(((q63_t) * pSrcCmplx++ * inA1) >> 31);
/* Decrement the numSamples loop counter */
numSamples--;
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of CmplxByRealMult group
*/

View File

@ -1,79 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_pid_init_f32.c
*
* Description: Floating-point PID Control initialization function
*
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @addtogroup PID
* @{
*/
/**
* @brief Initialization function for the floating-point PID Control.
* @param[in,out] *S points to an instance of the PID structure.
* @param[in] resetStateFlag flag to reset the state. 0 = no change in state & 1 = reset the state.
* @return none.
* \par Description:
* \par
* The <code>resetStateFlag</code> specifies whether to set state to zero or not. \n
* The function computes the structure fields: <code>A0</code>, <code>A1</code> <code>A2</code>
* using the proportional gain( \c Kp), integral gain( \c Ki) and derivative gain( \c Kd)
* also sets the state variables to all zeros.
*/
void arm_pid_init_f32(
arm_pid_instance_f32 * S,
int32_t resetStateFlag)
{
/* Derived coefficient A0 */
S->A0 = S->Kp + S->Ki + S->Kd;
/* Derived coefficient A1 */
S->A1 = (-S->Kp) - ((float32_t) 2.0 * S->Kd);
/* Derived coefficient A2 */
S->A2 = S->Kd;
/* Check whether state needs reset or not */
if(resetStateFlag)
{
/* Clear the state buffer. The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(float32_t));
}
}
/**
* @} end of PID group
*/

View File

@ -1,114 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_pid_init_q15.c
*
* Description: Q15 PID Control initialization function
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @addtogroup PID
* @{
*/
/**
* @details
* @param[in,out] *S points to an instance of the Q15 PID structure.
* @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state.
* @return none.
* \par Description:
* \par
* The <code>resetStateFlag</code> specifies whether to set state to zero or not. \n
* The function computes the structure fields: <code>A0</code>, <code>A1</code> <code>A2</code>
* using the proportional gain( \c Kp), integral gain( \c Ki) and derivative gain( \c Kd)
* also sets the state variables to all zeros.
*/
void arm_pid_init_q15(
arm_pid_instance_q15 * S,
int32_t resetStateFlag)
{
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/* Derived coefficient A0 */
S->A0 = __QADD16(__QADD16(S->Kp, S->Ki), S->Kd);
/* Derived coefficients and pack into A1 */
#ifndef ARM_MATH_BIG_ENDIAN
S->A1 = __PKHBT(-__QADD16(__QADD16(S->Kd, S->Kd), S->Kp), S->Kd, 16);
#else
S->A1 = __PKHBT(S->Kd, -__QADD16(__QADD16(S->Kd, S->Kd), S->Kp), 16);
#endif /* #ifndef ARM_MATH_BIG_ENDIAN */
/* Check whether state needs reset or not */
if(resetStateFlag)
{
/* Clear the state buffer. The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(q15_t));
}
#else
/* Run the below code for Cortex-M0 */
q31_t temp; /*to store the sum */
/* Derived coefficient A0 */
temp = S->Kp + S->Ki + S->Kd;
S->A0 = (q15_t) __SSAT(temp, 16);
/* Derived coefficients and pack into A1 */
temp = -(S->Kd + S->Kd + S->Kp);
S->A1 = (q15_t) __SSAT(temp, 16);
S->A2 = S->Kd;
/* Check whether state needs reset or not */
if(resetStateFlag)
{
/* Clear the state buffer. The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(q15_t));
}
#endif /* #ifndef ARM_MATH_CM0 */
}
/**
* @} end of PID group
*/

View File

@ -1,99 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_pid_init_q31.c
*
* Description: Q31 PID Control initialization function
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @addtogroup PID
* @{
*/
/**
* @brief Initialization function for the Q31 PID Control.
* @param[in,out] *S points to an instance of the Q31 PID structure.
* @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state.
* @return none.
* \par Description:
* \par
* The <code>resetStateFlag</code> specifies whether to set state to zero or not. \n
* The function computes the structure fields: <code>A0</code>, <code>A1</code> <code>A2</code>
* using the proportional gain( \c Kp), integral gain( \c Ki) and derivative gain( \c Kd)
* also sets the state variables to all zeros.
*/
void arm_pid_init_q31(
arm_pid_instance_q31 * S,
int32_t resetStateFlag)
{
#ifndef ARM_MATH_CM0
/* Run the below code for Cortex-M4 and Cortex-M3 */
/* Derived coefficient A0 */
S->A0 = __QADD(__QADD(S->Kp, S->Ki), S->Kd);
/* Derived coefficient A1 */
S->A1 = -__QADD(__QADD(S->Kd, S->Kd), S->Kp);
#else
/* Run the below code for Cortex-M0 */
q31_t temp;
/* Derived coefficient A0 */
temp = clip_q63_to_q31((q63_t) S->Kp + S->Ki);
S->A0 = clip_q63_to_q31((q63_t) temp + S->Kd);
/* Derived coefficient A1 */
temp = clip_q63_to_q31((q63_t) S->Kd + S->Kd);
S->A1 = -clip_q63_to_q31((q63_t) temp + S->Kp);
#endif /* #ifndef ARM_MATH_CM0 */
/* Derived coefficient A2 */
S->A2 = S->Kd;
/* Check whether state needs reset or not */
if(resetStateFlag)
{
/* Clear the state buffer. The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(q31_t));
}
}
/**
* @} end of PID group
*/

View File

@ -1,57 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_pid_reset_f32.c
*
* Description: Floating-point PID Control reset function
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* ------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @addtogroup PID
* @{
*/
/**
* @brief Reset function for the floating-point PID Control.
* @param[in] *S Instance pointer of PID control data structure.
* @return none.
* \par Description:
* The function resets the state buffer to zeros.
*/
void arm_pid_reset_f32(
arm_pid_instance_f32 * S)
{
/* Clear the state buffer. The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(float32_t));
}
/**
* @} end of PID group
*/

View File

@ -1,56 +0,0 @@
/* ----------------------------------------------------------------------
* Copyright (C) 2010 ARM Limited. All rights reserved.
*
* $Date: 15. February 2012
* $Revision: V1.1.0
*
* Project: CMSIS DSP Library
* Title: arm_pid_reset_q15.c
*
* Description: Q15 PID Control reset function
*
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*
* Version 1.1.0 2012/02/15
* Updated with more optimizations, bug fixes and minor API changes.
*
* Version 1.0.10 2011/7/15
* Big Endian support added and Merged M0 and M3/M4 Source code.
*
* Version 1.0.3 2010/11/29
* Re-organized the CMSIS folders and updated documentation.
*
* Version 1.0.2 2010/11/11
* Documentation updated.
*
* Version 1.0.1 2010/10/05
* Production release and review comments incorporated.
*
* Version 1.0.0 2010/09/20
* Production release and review comments incorporated.
* -------------------------------------------------------------------- */
#include "arm_math.h"
/**
* @addtogroup PID
* @{
*/
/**
* @brief Reset function for the Q15 PID Control.
* @param[in] *S Instance pointer of PID control data structure.
* @return none.
* \par Description:
* The function resets the state buffer to zeros.
*/
void arm_pid_reset_q15(
arm_pid_instance_q15 * S)
{
/* Reset state to zero, The size will be always 3 samples */
memset(S->state, 0, 3u * sizeof(q15_t));
}
/**
* @} end of PID group
*/

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