refactor icm20689: use driver base class

This commit is contained in:
Beat Küng 2020-03-18 17:41:16 +01:00 committed by Daniel Agar
parent 1df0fe03d7
commit c4a19c8852
5 changed files with 116 additions and 158 deletions

View File

@ -9,7 +9,7 @@ adc start
mpu6000 -R 10 -s -T 20602 start
# Internal ICM-20689
#icm20689 -R 10 20689 start
#icm20689 -s -R 10 start
# Internal SPI bus BMI088 accel
bmi088 -A -R 10 -s start

View File

@ -11,11 +11,11 @@ mpu6000 -R 8 -s -T 20602 start
# Internal SPI bus ICM-20689
mpu6000 -R 8 -s -T 20689 start
#icm20689 -R 6 start
#icm20689 -s -R 6 start
# new sensor drivers (in testing)
#icm20602 -s start
#icm20689 start
#icm20689 -s start
# Internal SPI bus BMI055 accel
bmi055 -A -R 10 -s start

View File

@ -40,13 +40,16 @@ static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
return (msb << 8u) | lsb;
}
ICM20689::ICM20689(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())),
ICM20689::ICM20689(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)
{
set_device_type(DRV_IMU_DEVTYPE_ICM20689);
_px4_accel.set_device_type(DRV_IMU_DEVTYPE_ICM20689);
_px4_gyro.set_device_type(DRV_IMU_DEVTYPE_ICM20689);
@ -55,8 +58,6 @@ ICM20689::ICM20689(int bus, uint32_t device, enum Rotation rotation) :
ICM20689::~ICM20689()
{
Stop();
perf_free(_transfer_perf);
perf_free(_bad_register_perf);
perf_free(_bad_transfer_perf);
@ -66,36 +67,35 @@ ICM20689::~ICM20689()
perf_free(_drdy_interval_perf);
}
bool ICM20689::Init()
int ICM20689::init()
{
if (SPI::init() != PX4_OK) {
PX4_ERR("SPI::init failed");
return false;
int ret = SPI::init();
if (ret != PX4_OK) {
DEVICE_DEBUG("SPI::init failed (%i)", ret);
return ret;
}
return Reset();
}
void ICM20689::Stop()
{
// wait until stopped
while (_state.load() != STATE::STOPPED) {
_state.store(STATE::REQUEST_STOP);
ScheduleNow();
px4_usleep(10);
}
return Reset() ? 0 : -1;
}
bool ICM20689::Reset()
{
_state.store(STATE::RESET);
_state = STATE::RESET;
ScheduleClear();
ScheduleNow();
return true;
}
void ICM20689::PrintInfo()
void ICM20689::exit_and_cleanup()
{
DataReadyInterruptDisable();
I2CSPIDriverBase::exit_and_cleanup();
}
void ICM20689::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 +116,21 @@ int ICM20689::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 ICM20689::Run()
void ICM20689::RunImpl()
{
switch (_state.load()) {
switch (_state) {
case STATE::RESET:
// PWR_MGMT_1: Device Reset
RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::DEVICE_RESET);
_reset_timestamp = hrt_absolute_time();
_state.store(STATE::WAIT_FOR_RESET);
_state = STATE::WAIT_FOR_RESET;
ScheduleDelayed(100);
break;
@ -142,14 +142,14 @@ void ICM20689::Run()
&& (RegisterRead(Register::PWR_MGMT_1) == 0x40)) {
// 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 +163,7 @@ void ICM20689::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 +241,7 @@ void ICM20689::Run()
} else {
// register check failed, force reconfigure
PX4_DEBUG("Health check failed, reconfiguring");
_state.store(STATE::CONFIGURE);
_state = STATE::CONFIGURE;
ScheduleNow();
}
@ -255,16 +255,6 @@ void ICM20689::Run()
}
break;
case STATE::REQUEST_STOP:
DataReadyInterruptDisable();
ScheduleClear();
_state.store(STATE::STOPPED);
break;
case STATE::STOPPED:
// DO NOTHING
break;
}
}
@ -376,29 +366,21 @@ void ICM20689::DataReady()
bool ICM20689::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_SPI1_DRDY1_ICM20689)
ret_setevent = px4_arch_gpiosetevent(GPIO_SPI1_DRDY1_ICM20689, true, false, true, &ICM20689::DataReadyInterruptCallback,
this);
#endif
return (ret_setevent == 0);
return px4_arch_gpiosetevent(_drdy_gpio, true, false, true, &ICM20689::DataReadyInterruptCallback, this) == 0;
}
bool ICM20689::DataReadyInterruptDisable()
{
int ret_setevent = -1;
if (_drdy_gpio == 0) {
return false;
}
// Disable data ready callback
// TODO: cleanup horrible DRDY define mess
#if defined(GPIO_SPI1_DRDY1_ICM20689)
ret_setevent = px4_arch_gpiosetevent(GPIO_SPI1_DRDY1_ICM20689, false, false, false, nullptr, nullptr);
#endif
return (ret_setevent == 0);
return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
}
bool ICM20689::RegisterCheck(const register_config_t &reg_cfg, bool notify)

View File

@ -49,22 +49,32 @@
#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_ICM20689;
class ICM20689 : public device::SPI, public px4::ScheduledWorkItem
class ICM20689 : public device::SPI, public I2CSPIDriver<ICM20689>
{
public:
ICM20689(int bus, uint32_t device, enum Rotation rotation = ROTATION_NONE);
ICM20689(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);
~ICM20689() 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 RunImpl();
int init() override;
void print_status() override;
void Start();
bool Reset();
protected:
void custom_method(const BusCLIArguments &cli) override;
void exit_and_cleanup() override;
private:
// Sensor Configuration
@ -88,8 +98,6 @@ private:
int probe() override;
void Run() override;
bool Configure();
void ConfigureAccel();
void ConfigureGyro();
@ -116,6 +124,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 +152,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))};

View File

@ -34,116 +34,84 @@
#include "ICM20689.hpp"
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
namespace icm20689
void
ICM20689::print_usage()
{
ICM20689 *g_dev{nullptr};
static int start(enum Rotation rotation)
{
if (g_dev != nullptr) {
PX4_WARN("already started");
return 0;
}
// create the driver
g_dev = new ICM20689(PX4_SPI_BUS_SENSORS, PX4_SPIDEV_ICM_20689, rotation);
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("icm20689", "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 *ICM20689::instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
int runtime_instance)
{
if (g_dev == nullptr) {
PX4_WARN("driver not running");
return -1;
ICM20689 *instance = new ICM20689(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 ICM20689::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 icm20689
extern "C" int icm20689_main(int argc, char *argv[])
{
enum Rotation rotation = ROTATION_NONE;
int myoptind = 1;
int ch = 0;
const char *myoptarg = nullptr;
int ch;
using ThisDriver = ICM20689;
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 icm20689::usage();
}
}
const char *verb = argv[myoptind];
const char *verb = cli.optarg();
if (!strcmp(verb, "start")) {
return icm20689::start(rotation);
} else if (!strcmp(verb, "stop")) {
return icm20689::stop();
} else if (!strcmp(verb, "status")) {
return icm20689::status();
} else if (!strcmp(verb, "reset")) {
return icm20689::reset();
if (!verb) {
ThisDriver::print_usage();
return -1;
}
return icm20689::usage();
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_IMU_DEVTYPE_ICM20689);
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;
}