refactor mpu9250: use driver base class

This commit is contained in:
Beat Küng
2020-03-24 09:46:20 -04:00
committed by Daniel Agar
parent 609eafd4cd
commit 571451942d
3 changed files with 113 additions and 159 deletions
+37 -56
View File
@@ -40,9 +40,11 @@ static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
return (msb << 8u) | lsb;
}
MPU9250::MPU9250(int bus, uint32_t device, enum Rotation rotation) :
SPI(MODULE_NAME, nullptr, bus, device, SPIDEV_MODE3, SPI_SPEED),
ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id())),
MPU9250::MPU9250(I2CSPIBusOption bus_option, int bus, uint32_t device, enum Rotation rotation, int bus_frequency,
spi_mode_e spi_mode, spi_drdy_gpio_t drdy_gpio) :
SPI(MODULE_NAME, nullptr, bus, device, spi_mode, bus_frequency),
I2CSPIDriver(MODULE_NAME, px4::device_bus_to_wq(get_device_id()), bus_option, bus),
_drdy_gpio(drdy_gpio),
_px4_accel(get_device_id(), ORB_PRIO_VERY_HIGH, rotation),
_px4_gyro(get_device_id(), ORB_PRIO_VERY_HIGH, rotation)
{
@@ -55,8 +57,6 @@ MPU9250::MPU9250(int bus, uint32_t device, enum Rotation rotation) :
MPU9250::~MPU9250()
{
Stop();
perf_free(_transfer_perf);
perf_free(_bad_register_perf);
perf_free(_bad_transfer_perf);
@@ -66,36 +66,35 @@ MPU9250::~MPU9250()
perf_free(_drdy_interval_perf);
}
bool MPU9250::Init()
void MPU9250::exit_and_cleanup()
{
if (SPI::init() != PX4_OK) {
PX4_ERR("SPI::init failed");
return false;
}
return Reset();
DataReadyInterruptDisable();
I2CSPIDriverBase::exit_and_cleanup();
}
void MPU9250::Stop()
int MPU9250::init()
{
// wait until stopped
while (_state.load() != STATE::STOPPED) {
_state.store(STATE::REQUEST_STOP);
ScheduleNow();
px4_usleep(10);
int ret = SPI::init();
if (ret != PX4_OK) {
DEVICE_DEBUG("SPI::init failed (%i)", ret);
return ret;
}
return Reset() ? 0 : -1;
}
bool MPU9250::Reset()
{
_state.store(STATE::RESET);
_state = STATE::RESET;
ScheduleClear();
ScheduleNow();
return true;
}
void MPU9250::PrintInfo()
void MPU9250::print_status()
{
I2CSPIDriverBase::print_status();
PX4_INFO("FIFO empty interval: %d us (%.3f Hz)", _fifo_empty_interval_us,
static_cast<double>(1000000 / _fifo_empty_interval_us));
@@ -116,21 +115,21 @@ int MPU9250::probe()
const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
if (whoami != WHOAMI) {
PX4_WARN("unexpected WHO_AM_I 0x%02x", whoami);
DEVICE_DEBUG("unexpected WHO_AM_I 0x%02x", whoami);
return PX4_ERROR;
}
return PX4_OK;
}
void MPU9250::Run()
void MPU9250::RunImpl()
{
switch (_state.load()) {
switch (_state) {
case STATE::RESET:
// PWR_MGMT_1: Device Reset
RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::H_RESET);
_reset_timestamp = hrt_absolute_time();
_state.store(STATE::WAIT_FOR_RESET);
_state = STATE::WAIT_FOR_RESET;
ScheduleDelayed(100);
break;
@@ -142,14 +141,14 @@ void MPU9250::Run()
&& (RegisterRead(Register::PWR_MGMT_1) == 0x01)) {
// if reset succeeded then configure
_state.store(STATE::CONFIGURE);
_state = STATE::CONFIGURE;
ScheduleNow();
} else {
// RESET not complete
if (hrt_elapsed_time(&_reset_timestamp) > 10_ms) {
PX4_ERR("Reset failed, retrying");
_state.store(STATE::RESET);
_state = STATE::RESET;
ScheduleDelayed(10_ms);
} else {
@@ -163,7 +162,7 @@ void MPU9250::Run()
case STATE::CONFIGURE:
if (Configure()) {
// if configure succeeded then start reading from FIFO
_state.store(STATE::FIFO_READ);
_state = STATE::FIFO_READ;
if (DataReadyInterruptConfigure()) {
_data_ready_interrupt_enabled = true;
@@ -241,7 +240,7 @@ void MPU9250::Run()
} else {
// register check failed, force reconfigure
PX4_DEBUG("Health check failed, reconfiguring");
_state.store(STATE::CONFIGURE);
_state = STATE::CONFIGURE;
ScheduleNow();
}
@@ -255,16 +254,6 @@ void MPU9250::Run()
}
break;
case STATE::REQUEST_STOP:
DataReadyInterruptDisable();
ScheduleClear();
_state.store(STATE::STOPPED);
break;
case STATE::STOPPED:
// DO NOTHING
break;
}
}
@@ -376,29 +365,21 @@ void MPU9250::DataReady()
bool MPU9250::DataReadyInterruptConfigure()
{
int ret_setevent = -1;
if (_drdy_gpio == 0) {
return false;
}
// Setup data ready on rising edge
// TODO: cleanup horrible DRDY define mess
#if defined(GPIO_DRDY_PORTD_PIN15)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_PORTD_PIN15, true, false, true, &MPU9250::DataReadyInterruptCallback,
this);
#endif
return (ret_setevent == 0);
return px4_arch_gpiosetevent(_drdy_gpio, true, false, true, &MPU9250::DataReadyInterruptCallback, this) == 0;
}
bool MPU9250::DataReadyInterruptDisable()
{
int ret_setevent = -1;
if (_drdy_gpio == 0) {
return false;
}
// Disable data ready callback
// TODO: cleanup horrible DRDY define mess
#if defined(GPIO_DRDY_PORTD_PIN15)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_PORTD_PIN15, false, false, false, nullptr, nullptr);
#endif
return (ret_setevent == 0);
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
}
bool MPU9250::RegisterCheck(const register_config_t &reg_cfg, bool notify)
@@ -493,11 +474,11 @@ uint16_t MPU9250::FIFOReadCount()
bool MPU9250::FIFORead(const hrt_abstime &timestamp_sample, uint16_t samples)
{
FIFOTransferBuffer buffer{};
perf_begin(_transfer_perf);
FIFOTransferBuffer buffer{};
const size_t transfer_size = math::min(samples * sizeof(FIFO::DATA) + 1, FIFO::SIZE);
perf_begin(_transfer_perf);
set_frequency(SPI_SPEED_SENSOR);
if (transfer((uint8_t *)&buffer, (uint8_t *)&buffer, transfer_size) != PX4_OK) {
+22 -13
View File
@@ -49,22 +49,33 @@
#include <lib/ecl/geo/geo.h>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/atomic.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <px4_platform_common/i2c_spi_buses.h>
using namespace InvenSense_MPU9250;
class MPU9250 : public device::SPI, public px4::ScheduledWorkItem
class MPU9250 : public device::SPI, public I2CSPIDriver<MPU9250>
{
public:
MPU9250(int bus, uint32_t device, enum Rotation rotation = ROTATION_NONE);
MPU9250(I2CSPIBusOption bus_option, int bus, uint32_t device, enum Rotation rotation, int bus_frequency,
spi_mode_e spi_mode, spi_drdy_gpio_t drdy_gpio);
~MPU9250() override;
bool Init();
void Start();
void Stop();
bool Reset();
void PrintInfo();
static I2CSPIDriverBase *instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
int runtime_instance);
static void print_usage();
void print_status() override;
void RunImpl();
int init() override;
void Start();
bool Reset();
protected:
void custom_method(const BusCLIArguments &cli) override;
void exit_and_cleanup() override;
private:
// Sensor Configuration
@@ -88,8 +99,6 @@ private:
int probe() override;
void Run() override;
bool Configure();
void ConfigureAccel();
void ConfigureGyro();
@@ -116,6 +125,8 @@ private:
void ProcessGyro(const hrt_abstime &timestamp_sample, const FIFOTransferBuffer &buffer, uint8_t samples);
void UpdateTemperature();
const spi_drdy_gpio_t _drdy_gpio;
PX4Accelerometer _px4_accel;
PX4Gyroscope _px4_gyro;
@@ -142,11 +153,9 @@ private:
WAIT_FOR_RESET,
CONFIGURE,
FIFO_READ,
REQUEST_STOP,
STOPPED,
};
px4::atomic<STATE> _state{STATE::RESET};
STATE _state{STATE::RESET};
uint16_t _fifo_empty_interval_us{1000}; // 1000 us / 1000 Hz transfer interval
uint8_t _fifo_gyro_samples{static_cast<uint8_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
@@ -34,120 +34,84 @@
#include "MPU9250.hpp"
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
namespace mpu9250
void
MPU9250::print_usage()
{
MPU9250 *g_dev{nullptr};
static int start(enum Rotation rotation)
{
if (g_dev != nullptr) {
PX4_WARN("already started");
return 0;
}
// create the driver
#if defined(PX4_SPI_BUS_SENSORS) && defined(PX4_SPIDEV_MPU)
g_dev = new MPU9250(PX4_SPI_BUS_SENSORS, PX4_SPIDEV_MPU, rotation);
#elif defined(PX4_SPI_BUS_EXT) && defined(PX4_SPIDEV_EXT_MPU)
g_dev = new MPU9250(PX4_SPI_BUS_EXT, PX4_SPIDEV_EXT_MPU, rotation);
#endif
if (g_dev == nullptr) {
PX4_ERR("driver start failed");
return -1;
}
if (!g_dev->Init()) {
PX4_ERR("driver init failed");
delete g_dev;
g_dev = nullptr;
return -1;
}
return 0;
PRINT_MODULE_USAGE_NAME("mpu9520", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("imu");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(false, true);
PRINT_MODULE_USAGE_PARAM_INT('R', 0, 0, 35, "Rotation", true);
PRINT_MODULE_USAGE_COMMAND("reset");
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
static int stop()
I2CSPIDriverBase *MPU9250::instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
int runtime_instance)
{
if (g_dev == nullptr) {
PX4_WARN("driver not running");
return -1;
MPU9250 *instance = new MPU9250(iterator.configuredBusOption(), iterator.bus(), iterator.devid(), cli.rotation,
cli.bus_frequency, cli.spi_mode, iterator.DRDYGPIO());
if (!instance) {
PX4_ERR("alloc failed");
return nullptr;
}
g_dev->Stop();
delete g_dev;
g_dev = nullptr;
return 0;
}
static int reset()
{
if (g_dev == nullptr) {
PX4_WARN("driver not running");
return 0;
if (OK != instance->init()) {
delete instance;
return nullptr;
}
return g_dev->Reset();
return instance;
}
static int status()
void MPU9250::custom_method(const BusCLIArguments &cli)
{
if (g_dev == nullptr) {
PX4_INFO("driver not running");
return 0;
}
g_dev->PrintInfo();
return 0;
Reset();
}
static int usage()
{
PX4_INFO("missing command: try 'start', 'stop', 'reset', 'status'");
PX4_INFO("options:");
PX4_INFO(" -R rotation");
return 0;
}
} // namespace mpu9250
extern "C" int mpu9250_main(int argc, char *argv[])
{
enum Rotation rotation = ROTATION_NONE;
int myoptind = 1;
int ch = 0;
const char *myoptarg = nullptr;
int ch;
using ThisDriver = MPU9250;
BusCLIArguments cli{false, true};
cli.default_spi_frequency = SPI_SPEED;
// start options
while ((ch = px4_getopt(argc, argv, "R:", &myoptind, &myoptarg)) != EOF) {
while ((ch = cli.getopt(argc, argv, "R:")) != EOF) {
switch (ch) {
case 'R':
rotation = (enum Rotation)atoi(myoptarg);
cli.rotation = (enum Rotation)atoi(cli.optarg());
break;
default:
return mpu9250::usage();
}
}
const char *verb = argv[myoptind];
const char *verb = cli.optarg();
if (!strcmp(verb, "start")) {
return mpu9250::start(rotation);
} else if (!strcmp(verb, "stop")) {
return mpu9250::stop();
} else if (!strcmp(verb, "status")) {
return mpu9250::status();
} else if (!strcmp(verb, "reset")) {
return mpu9250::reset();
if (!verb) {
ThisDriver::print_usage();
return -1;
}
return mpu9250::usage();
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_IMU_DEVTYPE_MPU9250);
if (!strcmp(verb, "start")) {
return ThisDriver::module_start(cli, iterator);
}
if (!strcmp(verb, "stop")) {
return ThisDriver::module_stop(iterator);
}
if (!strcmp(verb, "status")) {
return ThisDriver::module_status(iterator);
}
if (!strcmp(verb, "reset")) {
return ThisDriver::module_custom_method(cli, iterator);
}
ThisDriver::print_usage();
return -1;
}