This commit is contained in:
Lorenz Meier 2013-07-20 08:31:52 +02:00
commit bbecaa7de3
17 changed files with 681 additions and 159 deletions

View File

@ -174,7 +174,7 @@ clean:
distclean: clean
$(Q) $(REMOVE) $(ARCHIVE_DIR)*.export
$(Q) make -C $(NUTTX_SRC) -r $(MQUIET) distclean
$(Q) (cd $(NUTTX_SRC)/configs && find . -type l -depth 1 -delete)
$(Q) (cd $(NUTTX_SRC)/configs && find . -maxdepth 1 -type l -delete)
#
# Print some help text

View File

@ -25,7 +25,7 @@ then
else
echo "using L3GD20 and LSM303D"
l3gd20 start
lsm303 start
lsm303d start
fi
#
@ -40,4 +40,4 @@ then
# Check sensors - run AFTER 'sensors start'
#
preflight_check &
fi
fi

View File

@ -18,7 +18,6 @@ MODULES += drivers/led
MODULES += drivers/px4io
MODULES += drivers/px4fmu
MODULES += drivers/boards/px4fmu
MODULES += drivers/lsm303d
MODULES += drivers/ardrone_interface
MODULES += drivers/l3gd20
MODULES += drivers/bma180

View File

@ -14,6 +14,7 @@ MODULES += drivers/device
MODULES += drivers/stm32
MODULES += drivers/stm32/adc
MODULES += drivers/stm32/tone_alarm
MODULES += drivers/led
MODULES += drivers/px4fmu
MODULES += drivers/px4io
MODULES += drivers/boards/px4fmuv2

View File

@ -242,6 +242,9 @@ CONFIG_STM32_ADC=y
CONFIG_STM32_SPI=y
CONFIG_STM32_I2C=y
CONFIG_ARCH_HAVE_LEDS=y
# CONFIG_ARCH_LEDS is not set
#
# Alternate Pin Mapping
#
@ -253,7 +256,7 @@ CONFIG_STM32_JTAG_SW_ENABLE=y
CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
# CONFIG_STM32_FORCEPOWER is not set
# CONFIG_ARCH_BOARD_STM32_CUSTOM_CLOCKCONFIG is not set
# CONFIG_STM32_CCMEXCLUDE is not set
CONFIG_STM32_CCMEXCLUDE=y
CONFIG_STM32_DMACAPABLE=y
# CONFIG_STM32_TIM1_PWM is not set
# CONFIG_STM32_TIM3_PWM is not set
@ -274,9 +277,9 @@ CONFIG_USART1_RXDMA=y
# CONFIG_USART2_RS485 is not set
CONFIG_USART2_RXDMA=y
# CONFIG_USART3_RS485 is not set
CONFIG_USART3_RXDMA=y
# CONFIG_USART3_RXDMA is not set
# CONFIG_UART4_RS485 is not set
CONFIG_UART4_RXDMA=y
# CONFIG_UART4_RXDMA is not set
# CONFIG_UART5_RXDMA is not set
# CONFIG_USART6_RS485 is not set
# CONFIG_USART6_RXDMA is not set
@ -284,6 +287,26 @@ CONFIG_UART4_RXDMA=y
CONFIG_USART8_RXDMA=y
CONFIG_STM32_USART_SINGLEWIRE=y
# Previous:
## CONFIG_USART1_RS485 is not set
#CONFIG_USART1_RXDMA=y
## CONFIG_USART2_RS485 is not set
#CONFIG_USART2_RXDMA=y
## CONFIG_USART3_RS485 is not set
#CONFIG_USART3_RXDMA=y
## CONFIG_UART4_RS485 is not set
#CONFIG_UART4_RXDMA=y
## CONFIG_UART5_RXDMA is not set
## CONFIG_USART6_RS485 is not set
## CONFIG_USART6_RXDMA is not set
## CONFIG_USART7_RXDMA is not set
#CONFIG_USART8_RXDMA=y
#CONFIG_STM32_USART_SINGLEWIRE=y
#
# SPI Configuration
#
@ -302,7 +325,23 @@ CONFIG_STM32_I2CTIMEOTICKS=500
#
# SDIO Configuration
#
CONFIG_SDIO_PRI=128
#
# Maintain legacy build behavior (revisit)
#
CONFIG_MMCSD=y
#CONFIG_MMCSD_SPI=y
CONFIG_MMCSD_SDIO=y
CONFIG_MTD=y
#
# STM32 SDIO-based MMC/SD driver
#
CONFIG_SDIO_DMA=y
CONFIG_MMCSD_MULTIBLOCK_DISABLE=y
CONFIG_MMCSD_MMCSUPPORT=n
CONFIG_MMCSD_HAVECARDDETECT=n
#
# USB Host Configuration
@ -361,6 +400,7 @@ CONFIG_ARCH_BOARD="px4fmu-v2"
#
# Common Board Options
#
CONFIG_NSH_MMCSDSLOTNO=0
CONFIG_NSH_MMCSDMINOR=0
#
@ -508,8 +548,8 @@ CONFIG_NO_SERIAL_CONSOLE=y
#
# USART1 Configuration
#
CONFIG_USART1_RXBUFSIZE=16
CONFIG_USART1_TXBUFSIZE=16
CONFIG_USART1_RXBUFSIZE=512
CONFIG_USART1_TXBUFSIZE=512
CONFIG_USART1_BAUD=115200
CONFIG_USART1_BITS=8
CONFIG_USART1_PARITY=0
@ -534,7 +574,7 @@ CONFIG_USART2_OFLOWCONTROL=y
#
CONFIG_USART3_RXBUFSIZE=512
CONFIG_USART3_TXBUFSIZE=512
CONFIG_USART3_BAUD=115200
CONFIG_USART3_BAUD=57600
CONFIG_USART3_BITS=8
CONFIG_USART3_PARITY=0
CONFIG_USART3_2STOP=0
@ -556,9 +596,9 @@ CONFIG_UART4_2STOP=0
#
# USART6 Configuration
#
CONFIG_USART6_RXBUFSIZE=16
CONFIG_USART6_TXBUFSIZE=16
CONFIG_USART6_BAUD=115200
CONFIG_USART6_RXBUFSIZE=256
CONFIG_USART6_TXBUFSIZE=256
CONFIG_USART6_BAUD=57600
CONFIG_USART6_BITS=8
CONFIG_USART6_PARITY=0
CONFIG_USART6_2STOP=0
@ -568,8 +608,8 @@ CONFIG_USART6_2STOP=0
#
# UART7 Configuration
#
CONFIG_UART7_RXBUFSIZE=128
CONFIG_UART7_TXBUFSIZE=128
CONFIG_UART7_RXBUFSIZE=256
CONFIG_UART7_TXBUFSIZE=256
CONFIG_UART7_BAUD=57600
CONFIG_UART7_BITS=8
CONFIG_UART7_PARITY=0
@ -580,8 +620,8 @@ CONFIG_UART7_2STOP=0
#
# UART8 Configuration
#
CONFIG_UART8_RXBUFSIZE=128
CONFIG_UART8_TXBUFSIZE=128
CONFIG_UART8_RXBUFSIZE=256
CONFIG_UART8_TXBUFSIZE=256
CONFIG_UART8_BAUD=57600
CONFIG_UART8_BITS=8
CONFIG_UART8_PARITY=0

View File

@ -195,6 +195,28 @@ SERIAL_HAVE_CONSOLE_DMA=y
CONFIG_USART2_RXDMA=n
CONFIG_USART3_RXDMA=y
#
# PX4IO specific driver settings
#
# CONFIG_HRT_TIMER
# Enables the high-resolution timer. The board definition must
# set HRT_TIMER and HRT_TIMER_CHANNEL to the timer and capture/
# compare channels to be used.
# CONFIG_HRT_PPM
# Enables R/C PPM input using the HRT. The board definition must
# set HRT_PPM_CHANNEL to the timer capture/compare channel to be
# used, and define GPIO_PPM_IN to configure the appropriate timer
# GPIO.
# CONFIG_PWM_SERVO
# Enables the PWM servo driver. The driver configuration must be
# supplied by the board support at initialisation time.
# Note that USART2 must be disabled on the PX4 board for this to
# be available.
#
#
CONFIG_HRT_TIMER=y
CONFIG_HRT_PPM=y
#
# General build options
#

View File

@ -187,6 +187,28 @@ CONFIG_USART1_2STOP=0
CONFIG_USART2_2STOP=0
CONFIG_USART3_2STOP=0
#
# PX4IO specific driver settings
#
# CONFIG_HRT_TIMER
# Enables the high-resolution timer. The board definition must
# set HRT_TIMER and HRT_TIMER_CHANNEL to the timer and capture/
# compare channels to be used.
# CONFIG_HRT_PPM
# Enables R/C PPM input using the HRT. The board definition must
# set HRT_PPM_CHANNEL to the timer capture/compare channel to be
# used, and define GPIO_PPM_IN to configure the appropriate timer
# GPIO.
# CONFIG_PWM_SERVO
# Enables the PWM servo driver. The driver configuration must be
# supplied by the board support at initialisation time.
# Note that USART2 must be disabled on the PX4 board for this to
# be available.
#
#
CONFIG_HRT_TIMER=y
CONFIG_HRT_PPM=y
#
# General build options
#

View File

@ -3,7 +3,8 @@
#
SRCS = px4fmu_can.c \
px4fmu_init.c \
px4fmu2_init.c \
px4fmu_pwm_servo.c \
px4fmu_spi.c \
px4fmu_usb.c
px4fmu_usb.c \
px4fmu2_led.c

View File

@ -192,9 +192,8 @@ __EXPORT int nsh_archinitialize(void)
(hrt_callout)stm32_serial_dma_poll,
NULL);
// initial LED state
// XXX need to make this work again
// drv_led_start();
/* initial LED state */
//drv_led_start();
up_ledoff(LED_AMBER);
/* Configure SPI-based devices */

View File

@ -0,0 +1,85 @@
/****************************************************************************
*
* 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.
*
****************************************************************************/
/**
* @file px4fmu2_led.c
*
* PX4FMU LED backend.
*/
#include <nuttx/config.h>
#include <stdbool.h>
#include "stm32.h"
#include "px4fmu_internal.h"
#include <arch/board/board.h>
/*
* Ideally we'd be able to get these from up_internal.h,
* but since we want to be able to disable the NuttX use
* of leds for system indication at will and there is no
* separate switch, we need to build independent of the
* CONFIG_ARCH_LEDS configuration switch.
*/
__BEGIN_DECLS
extern void led_init();
extern void led_on(int led);
extern void led_off(int led);
__END_DECLS
__EXPORT void led_init()
{
/* Configure LED1 GPIO for output */
stm32_configgpio(GPIO_LED1);
}
__EXPORT void led_on(int led)
{
if (led == 0)
{
/* Pull down to switch on */
stm32_gpiowrite(GPIO_LED1, false);
}
}
__EXPORT void led_off(int led)
{
if (led == 0)
{
/* Pull up to switch off */
stm32_gpiowrite(GPIO_LED1, true);
}
}

View File

@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
* 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
@ -110,7 +110,7 @@ LED *gLED;
}
void
drv_led_start()
drv_led_start(void)
{
if (gLED == nullptr) {
gLED = new LED;

View File

@ -0,0 +1,255 @@
#include "math.h"
#include "string.h"
#include "iirFilter.h"
///////////////////////////////////////////////////////////////////////////////
// Internal function prototypes
int btZpgcToZpgd(const TF_ZPG_t *pkZpgc, double Ts, TF_ZPG_t *pZpgd);
int btDifcToZpgd(const TF_DIF_t *pkDifc, double Ts, TF_ZPG_t *pZpgd);
int tPolydToFil(const TF_POLY_t *pkPolyd, FIL_T *pFilt);
int tZpgxToPolyx(const TF_ZPG_t *pkZpg, TF_POLY_t *pPoly);
///////////////////////////////////////////////////////////////////////////////
// external functions
int testFunction()
{
printf("TEST\n");
return 1;
}
int initFilter(const TF_DIF_t *pDifc, double Ts, FIL_T *pFilt)
{
TF_POLY_t polyd;
TF_ZPG_t zpgd;
memset(pFilt, 0, sizeof(FIL_T));
// perform bilinear transform with frequency pre warping
btDifcToZpgd(pDifc, Ts, &zpgd);
// calculate polynom
tZpgxToPolyx(&zpgd, &polyd);
// set the filter parameters
tPolydToFil(&polyd, pFilt);
return 1;
}
// run filter using inp, return output of the filter
float updateFilter(FIL_T *pFilt, float inp)
{
float outp = 0;
int idx; // index used for different things
int i; // loop variable
// Store the input to the input array
idx = pFilt->inpCnt % MAX_LENGTH;
pFilt->inpData[idx] = inp;
// calculate numData * inpData
for (i = 0; i < pFilt->numLength; i++)
{
// index of inp array
idx = (pFilt->inpCnt + i - pFilt->numLength + 1) % MAX_LENGTH;
outp += pFilt->numData[i] * pFilt->inpData[idx];
}
// calculate denData * outData
for (i = 0; i < pFilt->denLength; i++)
{
// index of inp array
idx = (pFilt->inpCnt + i - pFilt->denLength) % MAX_LENGTH;
outp -= pFilt->denData[i] * pFilt->outData[idx];
}
// store the ouput data to the output array
idx = pFilt->inpCnt % MAX_LENGTH;
pFilt->outData[idx] = outp;
pFilt->inpCnt += 1;
return outp;
}
///////////////////////////////////////////////////////////////////////////////
// Internal functions
int tPolydToFil(const TF_POLY_t *pkPolyd, FIL_T *pFilt)
{
double gain;
int i;
if (pkPolyd->Ts < 0)
{
return 0;
}
// initialize filter to 0
memset(pFilt, 0, sizeof(FIL_T));
gain = pkPolyd->denData[pkPolyd->denLength - 1];
pFilt->Ts = pkPolyd->Ts;
pFilt->denLength = pkPolyd->denLength - 1;
pFilt->numLength = pkPolyd->numLength;
for (i = 0; i < pkPolyd->numLength; i++)
{
pFilt->numData[i] = pkPolyd->numData[i] / gain;
}
for (i = 0; i < (pkPolyd->denLength - 1); i++)
{
pFilt->denData[i] = pkPolyd->denData[i] / gain;
}
}
// bilinear transformation of poles and zeros
int btDifcToZpgd(const TF_DIF_t *pkDifc,
double Ts,
TF_ZPG_t *pZpgd)
{
TF_ZPG_t zpgc;
int totDiff;
int i;
zpgc.zerosLength = 0;
zpgc.polesLength = 0;
zpgc.gain = pkDifc->gain;
zpgc.Ts = pkDifc->Ts;
// Total number of differentiators / integerators
// positive diff, negative integ, 0 for no int/diff
totDiff = pkDifc->numDiff - pkDifc->numInt + pkDifc->highpassLength;
while (zpgc.zerosLength < totDiff)
{
zpgc.zerosData[zpgc.zerosLength] = 0;
zpgc.zerosLength++;
}
while (zpgc.polesLength < -totDiff)
{
zpgc.polesData[zpgc.polesLength] = 0;
zpgc.polesLength++;
}
// The next step is to calculate the poles
// This has to be done for the highpass and lowpass filters
// As we are using bilinear transformation there will be frequency
// warping which has to be accounted for
for (i = 0; i < pkDifc->lowpassLength; i++)
{
// pre-warping:
double freq = 2.0 / Ts * tan(pkDifc->lowpassData[i] * 2.0 * M_PI * Ts / 2.0);
// calculate pole:
zpgc.polesData[zpgc.polesLength] = -freq;
// adjust gain such that lp has gain = 1 for low frequencies
zpgc.gain *= freq;
zpgc.polesLength++;
}
for (i = 0; i < pkDifc->highpassLength; i++)
{
// pre-warping
double freq = 2.0 / Ts * tan(pkDifc->highpassData[i] * 2.0 * M_PI * Ts / 2.0);
// calculate pole:
zpgc.polesData[zpgc.polesLength] = -freq;
// gain does not have to be adjusted
zpgc.polesLength++;
}
return btZpgcToZpgd(&zpgc, Ts, pZpgd);
}
// bilinear transformation of poles and zeros
int btZpgcToZpgd(const TF_ZPG_t *pkZpgc,
double Ts,
TF_ZPG_t *pZpgd)
{
int i;
// init digital gain
pZpgd->gain = pkZpgc->gain;
// transform the poles
pZpgd->polesLength = pkZpgc->polesLength;
for (i = 0; i < pkZpgc->polesLength; i++)
{
pZpgd->polesData[i] = (2.0 / Ts + pkZpgc->polesData[i]) / (2.0 / Ts - pkZpgc->polesData[i]);
pZpgd->gain /= (2.0 / Ts - pkZpgc->polesData[i]);
}
// transform the zeros
pZpgd->zerosLength = pkZpgc->zerosLength;
for (i = 0; i < pkZpgc->zerosLength; i++)
{
pZpgd->zerosData[i] = (2.0 / Ts + pkZpgc->zerosData[i]) / (2.0 / Ts + pkZpgc->zerosData[i]);
pZpgd->gain *= (2.0 / Ts - pkZpgc->zerosData[i]);
}
// if we don't have the same number of poles as zeros we have to add
// poles or zeros due to the bilinear transformation
while (pZpgd->zerosLength < pZpgd->polesLength)
{
pZpgd->zerosData[pZpgd->zerosLength] = -1.0;
pZpgd->zerosLength++;
}
while (pZpgd->zerosLength > pZpgd->polesLength)
{
pZpgd->polesData[pZpgd->polesLength] = -1.0;
pZpgd->polesLength++;
}
pZpgd->Ts = Ts;
return 1;
}
// calculate polynom from zero, pole, gain form
int tZpgxToPolyx(const TF_ZPG_t *pkZpg, TF_POLY_t *pPoly)
{
int i, j; // counter variable
double tmp0, tmp1, gain;
// copy Ts
pPoly->Ts = pkZpg->Ts;
// calculate denominator polynom
pPoly->denLength = 1;
pPoly->denData[0] = 1.0;
for (i = 0; i < pkZpg->polesLength; i++)
{
// init temporary variable
tmp0 = 0.0;
// increase the polynom by 1
pPoly->denData[pPoly->denLength] = 0;
pPoly->denLength++;
for (j = 0; j < pPoly->denLength; j++)
{
tmp1 = pPoly->denData[j];
pPoly->denData[j] = tmp1 * -pkZpg->polesData[i] + tmp0;
tmp0 = tmp1;
}
}
// calculate numerator polynom
pPoly->numLength = 1;
pPoly->numData[0] = pkZpg->gain;
for (i = 0; i < pkZpg->zerosLength; i++)
{
tmp0 = 0.0;
pPoly->numData[pPoly->numLength] = 0;
pPoly->numLength++;
for (j = 0; j < pPoly->numLength; j++)
{
tmp1 = pPoly->numData[j];
pPoly->numData[j] = tmp1 * -pkZpg->zerosData[i] + tmp0;
tmp0 = tmp1;
}
}
}

View File

@ -0,0 +1,59 @@
#ifndef IIRFILTER__H__
#define IIRFILTER__H__
__BEGIN_DECLS
#define MAX_LENGTH 4
typedef struct FILTER_s
{
float denData[MAX_LENGTH];
float numData[MAX_LENGTH];
int denLength;
int numLength;
float Ts;
float inpData[MAX_LENGTH];
float outData[MAX_LENGTH];
unsigned int inpCnt;
} FIL_T;
typedef struct TF_ZPG_s
{
int zerosLength;
double zerosData[MAX_LENGTH + 1];
int polesLength;
double polesData[MAX_LENGTH + 1];
double gain;
double Ts;
} TF_ZPG_t;
typedef struct TF_POLY_s
{
int numLength;
double numData[MAX_LENGTH];
int denLength;
double denData[MAX_LENGTH];
double Ts;
} TF_POLY_t;
typedef struct TF_DIF_s
{
int numInt;
int numDiff;
int lowpassLength;
int highpassLength;
double lowpassData[MAX_LENGTH];
int highpassData[MAX_LENGTH];
double gain;
double Ts;
} TF_DIF_t;
__EXPORT int testFunction(void);
__EXPORT float updateFilter(FIL_T *pFilt, float inp);
__EXPORT int initFilter(const TF_DIF_t *pDifc, double Ts, FIL_T *pFilt);
__END_DECLS
#endif

View File

@ -65,6 +65,7 @@
#include <drivers/drv_accel.h>
#include <drivers/drv_mag.h>
#include "iirFilter.h"
/* oddly, ERROR is not defined for c++ */
#ifdef ERROR
@ -124,7 +125,7 @@ static const int ERROR = -1;
#define REG1_RATE_800HZ_A ((1<<7) | (0<<6) | (0<<5) | (1<<4))
#define REG1_RATE_1600HZ_A ((1<<7) | (0<<6) | (1<<5) | (0<<4))
#define REG1_CONT_UPDATE_A (0<<3)
#define REG1_BDU_UPDATE (1<<3)
#define REG1_Z_ENABLE_A (1<<2)
#define REG1_Y_ENABLE_A (1<<1)
#define REG1_X_ENABLE_A (1<<0)
@ -156,11 +157,11 @@ static const int ERROR = -1;
#define REG5_RATE_100HZ_M ((1<<4) | (0<<3) | (1<<2))
#define REG5_RATE_DO_NOT_USE_M ((1<<4) | (1<<3) | (0<<2))
#define REG6_FULL_SCALE_BITS_M ((1<<7) | (1<<6))
#define REG6_FULL_SCALE_2GA_M ((0<<7) | (0<<6))
#define REG6_FULL_SCALE_4GA_M ((0<<7) | (1<<6))
#define REG6_FULL_SCALE_8GA_M ((1<<7) | (0<<6))
#define REG6_FULL_SCALE_12GA_M ((1<<7) | (1<<6))
#define REG6_FULL_SCALE_BITS_M ((1<<6) | (1<<5))
#define REG6_FULL_SCALE_2GA_M ((0<<6) | (0<<5))
#define REG6_FULL_SCALE_4GA_M ((0<<6) | (1<<5))
#define REG6_FULL_SCALE_8GA_M ((1<<6) | (0<<5))
#define REG6_FULL_SCALE_12GA_M ((1<<6) | (1<<5))
#define REG7_CONT_MODE_M ((0<<1) | (0<<0))
@ -218,6 +219,12 @@ private:
float _accel_range_m_s2;
orb_advert_t _accel_topic;
unsigned _current_samplerate;
// FIL_T _filter_x;
// FIL_T _filter_y;
// FIL_T _filter_z;
unsigned _num_mag_reports;
volatile unsigned _next_mag_report;
volatile unsigned _oldest_mag_report;
@ -393,6 +400,7 @@ LSM303D::LSM303D(int bus, const char* path, spi_dev_e device) :
_accel_range_scale(0.0f),
_accel_range_m_s2(0.0f),
_accel_topic(-1),
_current_samplerate(0),
_num_mag_reports(0),
_next_mag_report(0),
_oldest_mag_report(0),
@ -405,8 +413,6 @@ LSM303D::LSM303D(int bus, const char* path, spi_dev_e device) :
// enable debug() calls
_debug_enabled = true;
_mag_range_scale = 12.0f/32767.0f;
// default scale factors
_accel_scale.x_offset = 0;
_accel_scale.x_scale = 1.0f;
@ -476,7 +482,7 @@ LSM303D::init()
_mag_topic = orb_advertise(ORB_ID(sensor_mag), &_mag_reports[0]);
/* enable accel, XXX do this with an ioctl? */
write_reg(ADDR_CTRL_REG1, REG1_X_ENABLE_A | REG1_Y_ENABLE_A | REG1_Z_ENABLE_A);
write_reg(ADDR_CTRL_REG1, REG1_X_ENABLE_A | REG1_Y_ENABLE_A | REG1_Z_ENABLE_A | REG1_BDU_UPDATE);
/* enable mag, XXX do this with an ioctl? */
write_reg(ADDR_CTRL_REG7, REG7_CONT_MODE_M);
@ -488,6 +494,22 @@ LSM303D::init()
set_antialias_filter_bandwidth(50); /* available bandwidths: 50, 194, 362 or 773 Hz */
set_samplerate(400); /* max sample rate */
/* initiate filter */
// TF_DIF_t tf_filter;
// tf_filter.numInt = 0;
// tf_filter.numDiff = 0;
// tf_filter.lowpassLength = 2;
// tf_filter.highpassLength = 0;
// tf_filter.lowpassData[0] = 10;
// tf_filter.lowpassData[1] = 10;
// //tf_filter.highpassData[0] = ;
// tf_filter.gain = 1;
// tf_filter.Ts = 1/_current_samplerate;
//
// initFilter(&tf_filter, 1.0/(double)_current_samplerate, &_filter_x);
// initFilter(&tf_filter, 1.0/(double)_current_samplerate, &_filter_y);
// initFilter(&tf_filter, 1.0/(double)_current_samplerate, &_filter_z);
mag_set_range(4); /* XXX: take highest sensor range of 12GA? */
mag_set_samplerate(100);
@ -705,6 +727,23 @@ LSM303D::ioctl(struct file *filp, int cmd, unsigned long arg)
else
return -EINVAL;
case ACCELIOCSSCALE:
{
/* copy scale, but only if off by a few percent */
struct accel_scale *s = (struct accel_scale *) arg;
float sum = s->x_scale + s->y_scale + s->z_scale;
if (sum > 2.0f && sum < 4.0f) {
memcpy(&_accel_scale, s, sizeof(_accel_scale));
return OK;
} else {
return -EINVAL;
}
}
case ACCELIOCGSCALE:
/* copy scale out */
memcpy((struct accel_scale *) arg, &_accel_scale, sizeof(_accel_scale));
return OK;
default:
/* give it to the superclass */
@ -856,37 +895,43 @@ LSM303D::set_range(unsigned max_g)
{
uint8_t setbits = 0;
uint8_t clearbits = REG2_FULL_SCALE_BITS_A;
float new_range = 0.0f;
float new_range_g = 0.0f;
float new_scale_g_digit = 0.0f;
if (max_g == 0)
max_g = 16;
if (max_g <= 2) {
new_range = 2.0f;
new_range_g = 2.0f;
setbits |= REG2_FULL_SCALE_2G_A;
new_scale_g_digit = 0.061e-3f;
} else if (max_g <= 4) {
new_range = 4.0f;
new_range_g = 4.0f;
setbits |= REG2_FULL_SCALE_4G_A;
new_scale_g_digit = 0.122e-3f;
} else if (max_g <= 6) {
new_range = 6.0f;
new_range_g = 6.0f;
setbits |= REG2_FULL_SCALE_6G_A;
new_scale_g_digit = 0.183e-3f;
} else if (max_g <= 8) {
new_range = 8.0f;
new_range_g = 8.0f;
setbits |= REG2_FULL_SCALE_8G_A;
new_scale_g_digit = 0.244e-3f;
} else if (max_g <= 16) {
new_range = 16.0f;
new_range_g = 16.0f;
setbits |= REG2_FULL_SCALE_16G_A;
new_scale_g_digit = 0.732e-3f;
} else {
return -EINVAL;
}
_accel_range_m_s2 = new_range * 9.80665f;
_accel_range_scale = _accel_range_m_s2 / 32768.0f;
_accel_range_m_s2 = new_range_g * 9.80665f;
_accel_range_scale = new_scale_g_digit * 9.80665f;
modify_reg(ADDR_CTRL_REG2, clearbits, setbits);
@ -899,6 +944,7 @@ LSM303D::mag_set_range(unsigned max_ga)
uint8_t setbits = 0;
uint8_t clearbits = REG6_FULL_SCALE_BITS_M;
float new_range = 0.0f;
float new_scale_ga_digit = 0.0f;
if (max_ga == 0)
max_ga = 12;
@ -906,25 +952,29 @@ LSM303D::mag_set_range(unsigned max_ga)
if (max_ga <= 2) {
new_range = 2.0f;
setbits |= REG6_FULL_SCALE_2GA_M;
new_scale_ga_digit = 0.080e-3f;
} else if (max_ga <= 4) {
new_range = 4.0f;
setbits |= REG6_FULL_SCALE_4GA_M;
new_scale_ga_digit = 0.160e-3f;
} else if (max_ga <= 8) {
new_range = 8.0f;
setbits |= REG6_FULL_SCALE_8GA_M;
new_scale_ga_digit = 0.320e-3f;
} else if (max_ga <= 12) {
new_range = 12.0f;
setbits |= REG6_FULL_SCALE_12GA_M;
new_scale_ga_digit = 0.479e-3f;
} else {
return -EINVAL;
}
_mag_range_ga = new_range;
_mag_range_scale = _mag_range_ga / 32768.0f;
_mag_range_scale = new_scale_ga_digit;
modify_reg(ADDR_CTRL_REG6, clearbits, setbits);
@ -991,18 +1041,23 @@ LSM303D::set_samplerate(unsigned frequency)
if (frequency <= 100) {
setbits |= REG1_RATE_100HZ_A;
_current_samplerate = 100;
} else if (frequency <= 200) {
setbits |= REG1_RATE_200HZ_A;
_current_samplerate = 200;
} else if (frequency <= 400) {
setbits |= REG1_RATE_400HZ_A;
_current_samplerate = 400;
} else if (frequency <= 800) {
setbits |= REG1_RATE_800HZ_A;
_current_samplerate = 800;
} else if (frequency <= 1600) {
setbits |= REG1_RATE_1600HZ_A;
_current_samplerate = 1600;
} else {
return -EINVAL;
@ -1127,9 +1182,18 @@ LSM303D::measure()
accel_report->y_raw = raw_accel_report.y;
accel_report->z_raw = raw_accel_report.z;
// float x_in_new = ((accel_report->x_raw * _accel_range_scale) - _accel_scale.x_offset) * _accel_scale.x_scale;
// float y_in_new = ((accel_report->y_raw * _accel_range_scale) - _accel_scale.y_offset) * _accel_scale.y_scale;
// float z_in_new = ((accel_report->z_raw * _accel_range_scale) - _accel_scale.z_offset) * _accel_scale.z_scale;
//
// accel_report->x = updateFilter(&_filter_x, x_in_new);
// accel_report->y = updateFilter(&_filter_y, y_in_new);
// accel_report->z = updateFilter(&_filter_z, z_in_new);
accel_report->x = ((accel_report->x_raw * _accel_range_scale) - _accel_scale.x_offset) * _accel_scale.x_scale;
accel_report->y = ((accel_report->y_raw * _accel_range_scale) - _accel_scale.y_offset) * _accel_scale.y_scale;
accel_report->z = ((accel_report->z_raw * _accel_range_scale) - _accel_scale.z_offset) * _accel_scale.z_scale;
accel_report->scaling = _accel_range_scale;
accel_report->range_m_s2 = _accel_range_m_s2;
@ -1341,7 +1405,7 @@ void
test()
{
int fd_accel = -1;
struct accel_report a_report;
struct accel_report accel_report;
ssize_t sz;
int filter_bandwidth;
@ -1352,20 +1416,20 @@ test()
err(1, "%s open failed", ACCEL_DEVICE_PATH);
/* do a simple demand read */
sz = read(fd_accel, &a_report, sizeof(a_report));
sz = read(fd_accel, &accel_report, sizeof(accel_report));
if (sz != sizeof(a_report))
if (sz != sizeof(accel_report))
err(1, "immediate read failed");
warnx("accel x: \t% 9.5f\tm/s^2", (double)a_report.x);
warnx("accel y: \t% 9.5f\tm/s^2", (double)a_report.y);
warnx("accel z: \t% 9.5f\tm/s^2", (double)a_report.z);
warnx("accel x: \t%d\traw", (int)a_report.x_raw);
warnx("accel y: \t%d\traw", (int)a_report.y_raw);
warnx("accel z: \t%d\traw", (int)a_report.z_raw);
warnx("accel x: \t% 9.5f\tm/s^2", (double)accel_report.x);
warnx("accel y: \t% 9.5f\tm/s^2", (double)accel_report.y);
warnx("accel z: \t% 9.5f\tm/s^2", (double)accel_report.z);
warnx("accel x: \t%d\traw", (int)accel_report.x_raw);
warnx("accel y: \t%d\traw", (int)accel_report.y_raw);
warnx("accel z: \t%d\traw", (int)accel_report.z_raw);
warnx("accel range: %8.4f m/s^2", (double)a_report.range_m_s2);
warnx("accel range: %8.4f m/s^2", (double)accel_report.range_m_s2);
if (ERROR == (filter_bandwidth = ioctl(fd_accel, ACCELIOCGLOWPASS, 0)))
warnx("accel antialias filter bandwidth: fail");
else

View File

@ -3,4 +3,5 @@
#
MODULE_COMMAND = lsm303d
SRCS = lsm303d.cpp
SRCS = lsm303d.cpp \
iirFilter.c

View File

@ -111,8 +111,9 @@ protected:
ms5611::prom_s _prom;
struct work_s _work;
unsigned _measure_ticks;
struct hrt_call _baro_call;
unsigned _call_baro_interval;
unsigned _num_reports;
volatile unsigned _next_report;
@ -143,12 +144,12 @@ protected:
* @note This function is called at open and error time. It might make sense
* to make it more aggressive about resetting the bus in case of errors.
*/
void start_cycle();
void start();
/**
* Stop the automatic measurement state machine.
*/
void stop_cycle();
void stop();
/**
* Perform a poll cycle; collect from the previous measurement
@ -166,12 +167,11 @@ protected:
void cycle();
/**
* Static trampoline from the workq context; because we don't have a
* generic workq wrapper yet.
* Static trampoline; XXX is this needed?
*
* @param arg Instance pointer for the driver that is polling.
*/
static void cycle_trampoline(void *arg);
void cycle_trampoline(void *arg);
/**
* Issue a measurement command for the current state.
@ -184,6 +184,7 @@ protected:
* Collect the result of the most recent measurement.
*/
virtual int collect();
};
/*
@ -195,7 +196,7 @@ MS5611::MS5611(device::Device *interface, ms5611::prom_u &prom_buf) :
CDev("MS5611", BARO_DEVICE_PATH),
_interface(interface),
_prom(prom_buf.s),
_measure_ticks(0),
_call_baro_interval(0),
_num_reports(0),
_next_report(0),
_oldest_report(0),
@ -212,14 +213,13 @@ MS5611::MS5611(device::Device *interface, ms5611::prom_u &prom_buf) :
_comms_errors(perf_alloc(PC_COUNT, "ms5611_comms_errors")),
_buffer_overflows(perf_alloc(PC_COUNT, "ms5611_buffer_overflows"))
{
// work_cancel in stop_cycle called from the dtor will explode if we don't do this...
memset(&_work, 0, sizeof(_work));
}
MS5611::~MS5611()
{
/* make sure we are truly inactive */
stop_cycle();
stop();
/* free any existing reports */
if (_reports != nullptr)
@ -277,7 +277,7 @@ MS5611::read(struct file *filp, char *buffer, size_t buflen)
return -ENOSPC;
/* if automatic measurement is enabled */
if (_measure_ticks > 0) {
if (_call_baro_interval > 0) {
/*
* While there is space in the caller's buffer, and reports, copy them.
@ -298,41 +298,13 @@ MS5611::read(struct file *filp, char *buffer, size_t buflen)
/* manual measurement - run one conversion */
/* XXX really it'd be nice to lock against other readers here */
do {
_measure_phase = 0;
_oldest_report = _next_report = 0;
_measure_phase = 0;
_oldest_report = _next_report = 0;
measure();
/* do temperature first */
if (OK != measure()) {
ret = -EIO;
break;
}
usleep(MS5611_CONVERSION_INTERVAL);
if (OK != collect()) {
ret = -EIO;
break;
}
/* now do a pressure measurement */
if (OK != measure()) {
ret = -EIO;
break;
}
usleep(MS5611_CONVERSION_INTERVAL);
if (OK != collect()) {
ret = -EIO;
break;
}
/* state machine will have generated a report, copy it out */
memcpy(buffer, _reports, sizeof(*_reports));
ret = sizeof(*_reports);
} while (0);
/* state machine will have generated a report, copy it out */
memcpy(buffer, _reports, sizeof(*_reports));
ret = sizeof(*_reports);
return ret;
}
@ -347,8 +319,8 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
/* switching to manual polling */
case SENSOR_POLLRATE_MANUAL:
stop_cycle();
_measure_ticks = 0;
stop();
_call_baro_interval = 0;
return OK;
/* external signalling not supported */
@ -362,14 +334,15 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
case SENSOR_POLLRATE_MAX:
case SENSOR_POLLRATE_DEFAULT: {
/* do we need to start internal polling? */
bool want_start = (_measure_ticks == 0);
bool want_start = (_call_baro_interval == 0);
/* set interval to minimum legal value */
_baro_call.period = _call_baro_interval = MS5611_CONVERSION_INTERVAL;
/* set interval for next measurement to minimum legal value */
_measure_ticks = USEC2TICK(MS5611_CONVERSION_INTERVAL);
/* if we need to start the poll state machine, do it */
if (want_start)
start_cycle();
start();
return OK;
}
@ -377,21 +350,18 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
/* adjust to a legal polling interval in Hz */
default: {
/* do we need to start internal polling? */
bool want_start = (_measure_ticks == 0);
/* convert hz to tick interval via microseconds */
unsigned ticks = USEC2TICK(1000000 / arg);
bool want_start = (_call_baro_interval == 0);
/* check against maximum rate */
if (ticks < USEC2TICK(MS5611_CONVERSION_INTERVAL))
if (1000000/arg < MS5611_CONVERSION_INTERVAL)
return -EINVAL;
/* update interval for next measurement */
_measure_ticks = ticks;
/* update interval */
_baro_call.period = _call_baro_interval = 1000000/arg;
/* if we need to start the poll state machine, do it */
if (want_start)
start_cycle();
start();
return OK;
}
@ -399,10 +369,10 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
}
case SENSORIOCGPOLLRATE:
if (_measure_ticks == 0)
if (_call_baro_interval == 0)
return SENSOR_POLLRATE_MANUAL;
return (1000 / _measure_ticks);
return (1000 / _call_baro_interval);
case SENSORIOCSQUEUEDEPTH: {
/* add one to account for the sentinel in the ring */
@ -419,11 +389,11 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
return -ENOMEM;
/* reset the measurement state machine with the new buffer, free the old */
stop_cycle();
stop();
delete[] _reports;
_num_reports = arg;
_reports = buf;
start_cycle();
start();
return OK;
}
@ -457,30 +427,32 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
}
void
MS5611::start_cycle()
MS5611::start()
{
/* make sure we are stopped first */
stop();
/* reset the report ring and state machine */
_collect_phase = false;
_measure_phase = 0;
/* reset the report ring */
_oldest_report = _next_report = 0;
/* reset to first measure phase */
_measure_phase = 0;
/* schedule a cycle to start things */
work_queue(HPWORK, &_work, (worker_t)&MS5611::cycle_trampoline, this, 1);
hrt_call_every(&_baro_call, 1000, _call_baro_interval, (hrt_callout)&MS5611::cycle_trampoline, this);
}
void
MS5611::stop_cycle()
MS5611::stop()
{
work_cancel(HPWORK, &_work);
hrt_cancel(&_baro_call);
}
void
MS5611::cycle_trampoline(void *arg)
{
MS5611 *dev = reinterpret_cast<MS5611 *>(arg);
MS5611 *dev = (MS5611 *)arg;
dev->cycle();
cycle();
}
void
@ -504,7 +476,7 @@ MS5611::cycle()
//log("collection error %d", ret);
}
/* reset the collection state machine and try again */
start_cycle();
start();
return;
}
@ -517,14 +489,16 @@ MS5611::cycle()
* doing pressure measurements at something close to the desired rate.
*/
if ((_measure_phase != 0) &&
(_measure_ticks > USEC2TICK(MS5611_CONVERSION_INTERVAL))) {
(_call_baro_interval > USEC2TICK(MS5611_CONVERSION_INTERVAL))) {
/* schedule a fresh cycle call when we are ready to measure again */
work_queue(HPWORK,
&_work,
(worker_t)&MS5611::cycle_trampoline,
this,
_measure_ticks - USEC2TICK(MS5611_CONVERSION_INTERVAL));
// XXX maybe do something appropriate as well
// /* schedule a fresh cycle call when we are ready to measure again */
// work_queue(HPWORK,
// &_work,
// (worker_t)&MS5611::cycle_trampoline,
// this,
// _measure_ticks - USEC2TICK(MS5611_CONVERSION_INTERVAL));
return;
}
@ -535,19 +509,12 @@ MS5611::cycle()
if (ret != OK) {
//log("measure error %d", ret);
/* reset the collection state machine and try again */
start_cycle();
start();
return;
}
/* next phase is collection */
_collect_phase = true;
/* schedule a fresh cycle call when the measurement is done */
work_queue(HPWORK,
&_work,
(worker_t)&MS5611::cycle_trampoline,
this,
USEC2TICK(MS5611_CONVERSION_INTERVAL));
}
int
@ -696,13 +663,14 @@ MS5611::collect()
return OK;
}
void
MS5611::print_info()
{
perf_print_counter(_sample_perf);
perf_print_counter(_comms_errors);
perf_print_counter(_buffer_overflows);
printf("poll interval: %u ticks\n", _measure_ticks);
printf("poll interval: %u ticks\n", _call_baro_interval);
printf("report queue: %u (%u/%u @ %p)\n",
_num_reports, _oldest_report, _next_report, _reports);
printf("TEMP: %d\n", _TEMP);

View File

@ -256,7 +256,7 @@ private:
* @param offset Register offset to start writing at.
* @param values Pointer to array of values to write.
* @param num_values The number of values to write.
* @return Zero if all values were successfully written.
* @return OK if all values were successfully written.
*/
int io_reg_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values);
@ -266,7 +266,7 @@ private:
* @param page Register page to write to.
* @param offset Register offset to write to.
* @param value Value to write.
* @return Zero if the value was written successfully.
* @return OK if the value was written successfully.
*/
int io_reg_set(uint8_t page, uint8_t offset, const uint16_t value);
@ -277,7 +277,7 @@ private:
* @param offset Register offset to start reading from.
* @param values Pointer to array where values should be stored.
* @param num_values The number of values to read.
* @return Zero if all values were successfully read.
* @return OK if all values were successfully read.
*/
int io_reg_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_values);
@ -1149,9 +1149,11 @@ PX4IO::io_reg_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned
}
int ret = _interface->write((page << 8) | offset, (void *)values, num_values);
if (ret != num_values)
if (ret != num_values) {
debug("io_reg_set(%u,%u,%u): error %d", page, offset, num_values, ret);
return ret;
return -1;
}
return OK;
}
int
@ -1169,10 +1171,12 @@ PX4IO::io_reg_get(uint8_t page, uint8_t offset, uint16_t *values, unsigned num_v
return -EINVAL;
}
int ret = _interface->read((page << 8) | offset, reinterpret_cast<void *>(values), num_values);
if (ret != num_values)
int ret = _interface->read((page << 8) | offset, reinterpret_cast<void *>(values), num_values);
if (ret != num_values) {
debug("io_reg_get(%u,%u,%u): data error %d", page, offset, num_values, ret);
return ret;
return -1;
}
return OK;
}
uint32_t
@ -1180,7 +1184,7 @@ PX4IO::io_reg_get(uint8_t page, uint8_t offset)
{
uint16_t value;
if (io_reg_get(page, offset, &value, 1))
if (io_reg_get(page, offset, &value, 1) != OK)
return _io_reg_get_error;
return value;
@ -1193,7 +1197,7 @@ PX4IO::io_reg_modify(uint8_t page, uint8_t offset, uint16_t clearbits, uint16_t
uint16_t value;
ret = io_reg_get(page, offset, &value, 1);
if (ret)
if (ret != OK)
return ret;
value &= ~clearbits;
value |= setbits;
@ -1500,9 +1504,9 @@ PX4IO::ioctl(file * /*filep*/, int cmd, unsigned long arg)
unsigned channel = cmd - PWM_SERVO_GET_RATEGROUP(0);
uint32_t value = io_reg_get(PX4IO_PAGE_PWM_INFO, PX4IO_RATE_MAP_BASE + channel);
*(uint32_t *)arg = value;
*(uint32_t *)arg = io_reg_get(PX4IO_PAGE_PWM_INFO, PX4IO_RATE_MAP_BASE + channel);
if (*(uint32_t *)arg == _io_reg_get_error)
ret = -EIO;
break;
}
@ -1890,7 +1894,7 @@ px4io_main(int argc, char *argv[])
}
PX4IO_Uploader *up;
const char *fn[3];
const char *fn[5];
/* work out what we're uploading... */
if (argc > 2) {
@ -1900,7 +1904,9 @@ px4io_main(int argc, char *argv[])
} else {
fn[0] = "/fs/microsd/px4io.bin";
fn[1] = "/etc/px4io.bin";
fn[2] = nullptr;
fn[2] = "/fs/microsd/px4io2.bin";
fn[3] = "/etc/px4io2.bin";
fn[4] = nullptr;
}
up = new PX4IO_Uploader;