fxos8701cq: sample at nyquist rate, drop duplicates, throttle temperature updates

This commit is contained in:
Daniel Agar 2020-05-19 13:54:31 -04:00
parent e73380f726
commit e577c3b610
2 changed files with 43 additions and 44 deletions

View File

@ -259,15 +259,13 @@ FXOS8701CQ::accel_set_samplerate(unsigned frequency)
return OK;
}
void
FXOS8701CQ::start()
void FXOS8701CQ::start()
{
// start polling at the specified rate
ScheduleOnInterval(1000000 / (FXOS8701C_ACCEL_DEFAULT_RATE) - FXOS8701C_TIMER_REDUCTION, 10000);
ScheduleOnInterval((1_s / FXOS8701C_ACCEL_DEFAULT_RATE) / 2);
}
void
FXOS8701CQ::check_registers(void)
void FXOS8701CQ::check_registers()
{
uint8_t v;
@ -296,15 +294,11 @@ FXOS8701CQ::check_registers(void)
_checked_next = (_checked_next + 1) % FXOS8701C_NUM_CHECKED_REGISTERS;
}
void
FXOS8701CQ::RunImpl()
void FXOS8701CQ::RunImpl()
{
// start the performance counter
perf_begin(_accel_sample_perf);
// status register and data as read back from the device
RawAccelMagReport raw_accel_mag_report{};
check_registers();
if (_register_wait != 0) {
@ -316,6 +310,7 @@ FXOS8701CQ::RunImpl()
}
/* fetch data from the sensor */
RawAccelMagReport raw_accel_mag_report{};
const hrt_abstime timestamp_sample = hrt_absolute_time();
_interface->read(FXOS8701CQ_DR_STATUS, (uint8_t *)&raw_accel_mag_report, sizeof(raw_accel_mag_report));
@ -326,28 +321,41 @@ FXOS8701CQ::RunImpl()
return;
}
/*
* Eight-bit 2s complement sensor temperature value with 0.96 °C/LSB sensitivity.
* Temperature data is only valid between 40 °C and 125 °C. The temperature sensor
* output is only valid when M_CTRL_REG1[m_hms] > 0b00. Please note that the
* temperature sensor is uncalibrated and its output for a given temperature will vary from
* one device to the next
*/
float temperature = (read_reg(FXOS8701CQ_TEMP)) * 0.96f;
_px4_accel.set_temperature(temperature);
// report the error count as the sum of the number of bad
// register reads and bad values. This allows the higher level
// code to decide if it should use this sensor based on
// whether it has had failures
_px4_accel.set_error_count(perf_event_count(_bad_registers));
int16_t x = swap16RightJustify14(raw_accel_mag_report.x);
int16_t y = swap16RightJustify14(raw_accel_mag_report.y);
int16_t z = swap16RightJustify14(raw_accel_mag_report.z);
// don't publish duplicated reads
if ((x == _accel_prev[0]) && (y == _accel_prev[1]) && (z == _accel_prev[2])) {
perf_count(_accel_duplicates);
perf_end(_accel_sample_perf);
return;
} else {
_accel_prev[0] = x;
_accel_prev[1] = y;
_accel_prev[2] = z;
}
// report the error count as the sum of the number of bad register reads and bad values.
_px4_accel.set_error_count(perf_event_count(_bad_registers));
_px4_accel.update(timestamp_sample, x, y, z);
if (hrt_elapsed_time(&_last_temperature_update) > 100_ms) {
/*
* Eight-bit 2s complement sensor temperature value with 0.96 °C/LSB sensitivity.
* Temperature data is only valid between 40 °C and 125 °C. The temperature sensor
* output is only valid when M_CTRL_REG1[m_hms] > 0b00. Please note that the
* temperature sensor is uncalibrated and its output for a given temperature will vary from
* one device to the next
*/
_last_temperature_update = timestamp_sample;
float temperature = (read_reg(FXOS8701CQ_TEMP)) * 0.96f;
_px4_accel.set_temperature(temperature);
}
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
if (hrt_elapsed_time(&_mag_last_measure) >= 10_ms) {

View File

@ -124,24 +124,17 @@ struct RawAccelMagReport {
int16_t x;
int16_t y;
int16_t z;
#if !defined(BOARD_HAS_NOISY_FXOS8700_MAG)
int16_t mx;
int16_t my;
int16_t mz;
#endif // !BOARD_HAS_NOISY_FXOS8700_MAG
};
#pragma pack(pop)
extern device::Device *FXOS8701CQ_SPI_interface(int bus, uint32_t chip_select, int bus_frequency, spi_mode_e spi_mode);
extern device::Device *FXOS8701CQ_I2C_interface(int bus, int bus_frequency, int i2c_address);
/*
we set the timer interrupt to run a bit faster than the desired
sample rate and then throw away duplicates using the data ready bit.
This time reduction is enough to cope with worst case timing jitter
due to other timers
*/
#define FXOS8701C_TIMER_REDUCTION 240
class FXOS8701CQ : public I2CSPIDriver<FXOS8701CQ>
{
public:
@ -181,10 +174,7 @@ private:
* @param The register to read.
* @return The value that was read.
*/
inline uint8_t read_reg(unsigned reg)
{
return _interface->read_reg(reg);
}
inline uint8_t read_reg(unsigned reg) { return _interface->read_reg(reg); }
/**
* Write a register in the FXOS8701C
@ -193,10 +183,7 @@ private:
* @param value The new value to write.
* @return OK on success, negative errno otherwise.
*/
inline int write_reg(unsigned reg, uint8_t value)
{
return _interface->write_reg(reg, value);
}
inline int write_reg(unsigned reg, uint8_t value) { return _interface->write_reg(reg, value); }
/**
* Modify a register in the FXOS8701C
@ -254,12 +241,16 @@ private:
perf_counter_t _mag_sample_perf;
#endif
hrt_abstime _last_temperature_update{0};
unsigned _accel_samplerate{FXOS8701C_ACCEL_DEFAULT_RATE};
perf_counter_t _accel_sample_perf;
perf_counter_t _bad_registers;
perf_counter_t _accel_duplicates;
int16_t _accel_prev[3] {};
uint8_t _register_wait{0};
// this is used to support runtime checking of key