refactor icm20608g: use driver base class

This commit is contained in:
Beat Küng
2020-03-18 17:43:48 +01:00
committed by Daniel Agar
parent c4a19c8852
commit 924f46ee28
5 changed files with 114 additions and 162 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ fi
if ! icm20602 -s -R 8 start if ! icm20602 -s -R 8 start
then then
# ICM20608 internal SPI bus ICM-20602-G is rotated 90 deg yaw # ICM20608 internal SPI bus ICM-20602-G is rotated 90 deg yaw
icm20608g -R 8 start icm20608g -s -R 8 start
fi fi
# For Teal One airframe # For Teal One airframe
+1 -1
View File
@@ -8,7 +8,7 @@ rgbled start -I
adc start adc start
# Internal SPI bus ICM-20608-G # Internal SPI bus ICM-20608-G
icm20608g -R 8 start icm20608g -s -R 8 start
# Internal SPI bus ICM-20602 # Internal SPI bus ICM-20602
icm20602 -s -R 8 start icm20602 -s -R 8 start
@@ -40,9 +40,11 @@ static constexpr int16_t combine(uint8_t msb, uint8_t lsb)
return (msb << 8u) | lsb; return (msb << 8u) | lsb;
} }
ICM20608G::ICM20608G(int bus, uint32_t device, enum Rotation rotation) : ICM20608G::ICM20608G(I2CSPIBusOption bus_option, int bus, uint32_t device, enum Rotation rotation, int bus_frequency,
SPI(MODULE_NAME, nullptr, bus, device, SPIDEV_MODE3, SPI_SPEED), spi_mode_e spi_mode, spi_drdy_gpio_t drdy_gpio) :
ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id())), 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_accel(get_device_id(), ORB_PRIO_VERY_HIGH, rotation),
_px4_gyro(get_device_id(), ORB_PRIO_VERY_HIGH, rotation) _px4_gyro(get_device_id(), ORB_PRIO_VERY_HIGH, rotation)
{ {
@@ -56,8 +58,6 @@ ICM20608G::ICM20608G(int bus, uint32_t device, enum Rotation rotation) :
ICM20608G::~ICM20608G() ICM20608G::~ICM20608G()
{ {
Stop();
perf_free(_transfer_perf); perf_free(_transfer_perf);
perf_free(_bad_register_perf); perf_free(_bad_register_perf);
perf_free(_bad_transfer_perf); perf_free(_bad_transfer_perf);
@@ -67,36 +67,35 @@ ICM20608G::~ICM20608G()
perf_free(_drdy_interval_perf); perf_free(_drdy_interval_perf);
} }
bool ICM20608G::Init() int ICM20608G::init()
{ {
if (SPI::init() != PX4_OK) { int ret = SPI::init();
PX4_ERR("SPI::init failed");
return false; if (ret != PX4_OK) {
DEVICE_DEBUG("SPI::init failed (%i)", ret);
return ret;
} }
return Reset(); return Reset() ? 0 : -1;
}
void ICM20608G::Stop()
{
// wait until stopped
while (_state.load() != STATE::STOPPED) {
_state.store(STATE::REQUEST_STOP);
ScheduleNow();
px4_usleep(10);
}
} }
bool ICM20608G::Reset() bool ICM20608G::Reset()
{ {
_state.store(STATE::RESET); _state = STATE::RESET;
ScheduleClear(); ScheduleClear();
ScheduleNow(); ScheduleNow();
return true; return true;
} }
void ICM20608G::PrintInfo() void ICM20608G::exit_and_cleanup()
{ {
DataReadyInterruptDisable();
I2CSPIDriverBase::exit_and_cleanup();
}
void ICM20608G::print_status()
{
I2CSPIDriverBase::print_status();
PX4_INFO("FIFO empty interval: %d us (%.3f Hz)", _fifo_empty_interval_us, PX4_INFO("FIFO empty interval: %d us (%.3f Hz)", _fifo_empty_interval_us,
static_cast<double>(1000000 / _fifo_empty_interval_us)); static_cast<double>(1000000 / _fifo_empty_interval_us));
@@ -117,21 +116,21 @@ int ICM20608G::probe()
const uint8_t whoami = RegisterRead(Register::WHO_AM_I); const uint8_t whoami = RegisterRead(Register::WHO_AM_I);
if (whoami != WHOAMI) { 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_ERROR;
} }
return PX4_OK; return PX4_OK;
} }
void ICM20608G::Run() void ICM20608G::RunImpl()
{ {
switch (_state.load()) { switch (_state) {
case STATE::RESET: case STATE::RESET:
// PWR_MGMT_1: Device Reset // PWR_MGMT_1: Device Reset
RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::DEVICE_RESET); RegisterWrite(Register::PWR_MGMT_1, PWR_MGMT_1_BIT::DEVICE_RESET);
_reset_timestamp = hrt_absolute_time(); _reset_timestamp = hrt_absolute_time();
_state.store(STATE::WAIT_FOR_RESET); _state = STATE::WAIT_FOR_RESET;
ScheduleDelayed(100); ScheduleDelayed(100);
break; break;
@@ -143,14 +142,14 @@ void ICM20608G::Run()
&& (RegisterRead(Register::PWR_MGMT_1) == 0x40)) { && (RegisterRead(Register::PWR_MGMT_1) == 0x40)) {
// if reset succeeded then configure // if reset succeeded then configure
_state.store(STATE::CONFIGURE); _state = STATE::CONFIGURE;
ScheduleNow(); ScheduleNow();
} else { } else {
// RESET not complete // RESET not complete
if (hrt_elapsed_time(&_reset_timestamp) > 10_ms) { if (hrt_elapsed_time(&_reset_timestamp) > 10_ms) {
PX4_ERR("Reset failed, retrying"); PX4_ERR("Reset failed, retrying");
_state.store(STATE::RESET); _state = STATE::RESET;
ScheduleDelayed(10_ms); ScheduleDelayed(10_ms);
} else { } else {
@@ -164,7 +163,7 @@ void ICM20608G::Run()
case STATE::CONFIGURE: case STATE::CONFIGURE:
if (Configure()) { if (Configure()) {
// if configure succeeded then start reading from FIFO // if configure succeeded then start reading from FIFO
_state.store(STATE::FIFO_READ); _state = STATE::FIFO_READ;
if (DataReadyInterruptConfigure()) { if (DataReadyInterruptConfigure()) {
_data_ready_interrupt_enabled = true; _data_ready_interrupt_enabled = true;
@@ -242,7 +241,7 @@ void ICM20608G::Run()
} else { } else {
// register check failed, force reconfigure // register check failed, force reconfigure
PX4_DEBUG("Health check failed, reconfiguring"); PX4_DEBUG("Health check failed, reconfiguring");
_state.store(STATE::CONFIGURE); _state = STATE::CONFIGURE;
ScheduleNow(); ScheduleNow();
} }
@@ -256,16 +255,6 @@ void ICM20608G::Run()
} }
break; break;
case STATE::REQUEST_STOP:
DataReadyInterruptDisable();
ScheduleClear();
_state.store(STATE::STOPPED);
break;
case STATE::STOPPED:
// DO NOTHING
break;
} }
} }
@@ -377,34 +366,21 @@ void ICM20608G::DataReady()
bool ICM20608G::DataReadyInterruptConfigure() bool ICM20608G::DataReadyInterruptConfigure()
{ {
int ret_setevent = -1; if (_drdy_gpio == 0) {
return false;
}
// Setup data ready on rising edge // Setup data ready on rising edge
// TODO: cleanup horrible DRDY define mess return px4_arch_gpiosetevent(_drdy_gpio, true, false, true, &ICM20608G::DataReadyInterruptCallback, this) == 0;
#if defined(GPIO_DRDY_PORTC_PIN14)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_PORTC_PIN14, true, false, true, &ICM20608G::DataReadyInterruptCallback,
this);
#elif defined(GPIO_DRDY_ICM_2060X)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_ICM_2060X, true, false, true, &ICM20608G::DataReadyInterruptCallback,
this);
#endif
return (ret_setevent == 0);
} }
bool ICM20608G::DataReadyInterruptDisable() bool ICM20608G::DataReadyInterruptDisable()
{ {
int ret_setevent = -1; if (_drdy_gpio == 0) {
return false;
}
// Disable data ready callback return px4_arch_gpiosetevent(_drdy_gpio, false, false, false, nullptr, nullptr) == 0;
// TODO: cleanup horrible DRDY define mess
#if defined(GPIO_DRDY_PORTC_PIN14)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_PORTC_PIN14, false, false, false, nullptr, nullptr);
#elif defined(GPIO_DRDY_ICM_2060X)
ret_setevent = px4_arch_gpiosetevent(GPIO_DRDY_ICM_2060X, false, false, false, nullptr, nullptr);
#endif
return (ret_setevent == 0);
} }
bool ICM20608G::RegisterCheck(const register_config_t &reg_cfg, bool notify) bool ICM20608G::RegisterCheck(const register_config_t &reg_cfg, bool notify)
@@ -49,22 +49,32 @@
#include <lib/ecl/geo/geo.h> #include <lib/ecl/geo/geo.h>
#include <lib/perf/perf_counter.h> #include <lib/perf/perf_counter.h>
#include <px4_platform_common/atomic.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_ICM20608G; using namespace InvenSense_ICM20608G;
class ICM20608G : public device::SPI, public px4::ScheduledWorkItem class ICM20608G : public device::SPI, public I2CSPIDriver<ICM20608G>
{ {
public: public:
ICM20608G(int bus, uint32_t device, enum Rotation rotation = ROTATION_NONE); ICM20608G(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);
~ICM20608G() override; ~ICM20608G() override;
bool Init(); static I2CSPIDriverBase *instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
void Start(); int runtime_instance);
void Stop(); static void print_usage();
bool Reset();
void PrintInfo();
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: private:
// Sensor Configuration // Sensor Configuration
@@ -88,8 +98,6 @@ private:
int probe() override; int probe() override;
void Run() override;
bool Configure(); bool Configure();
void ConfigureAccel(); void ConfigureAccel();
void ConfigureGyro(); void ConfigureGyro();
@@ -116,6 +124,8 @@ private:
void ProcessGyro(const hrt_abstime &timestamp_sample, const FIFOTransferBuffer &buffer, uint8_t samples); void ProcessGyro(const hrt_abstime &timestamp_sample, const FIFOTransferBuffer &buffer, uint8_t samples);
void UpdateTemperature(); void UpdateTemperature();
const spi_drdy_gpio_t _drdy_gpio;
PX4Accelerometer _px4_accel; PX4Accelerometer _px4_accel;
PX4Gyroscope _px4_gyro; PX4Gyroscope _px4_gyro;
@@ -142,11 +152,9 @@ private:
WAIT_FOR_RESET, WAIT_FOR_RESET,
CONFIGURE, CONFIGURE,
FIFO_READ, 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 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))}; uint8_t _fifo_gyro_samples{static_cast<uint8_t>(_fifo_empty_interval_us / (1000000 / GYRO_RATE))};
@@ -34,116 +34,84 @@
#include "ICM20608G.hpp" #include "ICM20608G.hpp"
#include <px4_platform_common/getopt.h> #include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
namespace icm20608g void
ICM20608G::print_usage()
{ {
ICM20608G *g_dev{nullptr}; PRINT_MODULE_USAGE_NAME("icm20608g", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("imu");
static int start(enum Rotation rotation) PRINT_MODULE_USAGE_COMMAND("start");
{ PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(false, true);
if (g_dev != nullptr) { PRINT_MODULE_USAGE_PARAM_INT('R', 0, 0, 35, "Rotation", true);
PX4_WARN("already started"); PRINT_MODULE_USAGE_COMMAND("reset");
return 0; PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
// create the driver
g_dev = new ICM20608G(PX4_SPI_BUS_SENSORS, PX4_SPIDEV_ICM_20608, 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;
} }
static int stop() I2CSPIDriverBase *ICM20608G::instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
int runtime_instance)
{ {
if (g_dev == nullptr) { ICM20608G *instance = new ICM20608G(iterator.configuredBusOption(), iterator.bus(), iterator.devid(), cli.rotation,
PX4_WARN("driver not running"); cli.bus_frequency, cli.spi_mode, iterator.DRDYGPIO());
return -1;
if (!instance) {
PX4_ERR("alloc failed");
return nullptr;
} }
g_dev->Stop(); if (OK != instance->init()) {
delete g_dev; delete instance;
g_dev = nullptr; return nullptr;
return 0;
}
static int reset()
{
if (g_dev == nullptr) {
PX4_WARN("driver not running");
return 0;
} }
return g_dev->Reset(); return instance;
} }
static int status() void ICM20608G::custom_method(const BusCLIArguments &cli)
{ {
if (g_dev == nullptr) { Reset();
PX4_INFO("driver not running");
return 0;
}
g_dev->PrintInfo();
return 0;
} }
static int usage()
{
PX4_INFO("missing command: try 'start', 'stop', 'reset', 'status'");
PX4_INFO("options:");
PX4_INFO(" -R rotation");
return 0;
}
} // namespace icm20608g
extern "C" int icm20608g_main(int argc, char *argv[]) extern "C" int icm20608g_main(int argc, char *argv[])
{ {
enum Rotation rotation = ROTATION_NONE; int ch;
int myoptind = 1; using ThisDriver = ICM20608G;
int ch = 0; BusCLIArguments cli{false, true};
const char *myoptarg = nullptr; cli.default_spi_frequency = SPI_SPEED;
// start options while ((ch = cli.getopt(argc, argv, "R:")) != EOF) {
while ((ch = px4_getopt(argc, argv, "R:", &myoptind, &myoptarg)) != EOF) {
switch (ch) { switch (ch) {
case 'R': case 'R':
rotation = (enum Rotation)atoi(myoptarg); cli.rotation = (enum Rotation)atoi(cli.optarg());
break; break;
default:
return icm20608g::usage();
} }
} }
const char *verb = argv[myoptind]; const char *verb = cli.optarg();
if (!strcmp(verb, "start")) { if (!verb) {
return icm20608g::start(rotation); ThisDriver::print_usage();
return -1;
} else if (!strcmp(verb, "stop")) {
return icm20608g::stop();
} else if (!strcmp(verb, "status")) {
return icm20608g::status();
} else if (!strcmp(verb, "reset")) {
return icm20608g::reset();
} }
return icm20608g::usage(); BusInstanceIterator iterator(MODULE_NAME, cli, DRV_IMU_DEVTYPE_ICM20608);
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;
} }