PX4模块设计之四十三:icm20689模块
Posted lida2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PX4模块设计之四十三:icm20689模块相关的知识,希望对你有一定的参考价值。
PX4模块设计之四十三:icm20689模块
1. icm20689模块简介
icm20689 <command> [arguments...]
Commands:
start
[-s] Internal SPI bus(es)
[-S] External SPI bus(es)
[-b <val>] board-specific bus (default=all) (external SPI: n-th bus
(default=1))
[-c <val>] chip-select pin (for internal SPI) or index (for external SPI)
[-m <val>] SPI mode
[-f <val>] bus frequency in kHz
[-q] quiet startup (no message if no device found)
[-R <val>] Rotation
default: 0
stop
status print status info
注1:print_usage函数是具体对应实现。
class ICM20689 : public device::SPI, public I2CSPIDriver<ICM20689>
class I2CSPIDriver : public I2CSPIDriverBase
class I2CSPIDriverBase : public px4::ScheduledWorkItem, public I2CSPIInstance
class ScheduledWorkItem : public WorkItem
class WorkItem : public IntrusiveSortedListNode<WorkItem *>, public IntrusiveQueueNode<WorkItem *>
class I2CSPIInstance : public ListNode<I2CSPIInstance *>
ICM20689 //类继承关系
├──> I2CSPIDriver
│ └──> I2CSPIDriverBase
│ ├──> px4::ScheduledWorkItem
│ │ └──> WorkItem
│ │ ├──> IntrusiveSortedListNode
│ │ └──> IntrusiveQueueNode
│ └──> I2CSPIInstance
│ └──> ListNode
└──> device::SPI
注2:ICM20689模块就是针对ICM20689硬件芯片进行管理和数据采集的模块。
2. 模块入口函数
2.1 主入口icm20689_main
模块支持start/stop/status命令,除此以外支持BusCLIArguments的I2C/SPI默认参数选项"RXIa:SscⓂ️kb:f:q"。
icm20689_main
├──> using ThisDriver = ICM20689
├──> BusCLIArguments clifalse, true
├──> cli.default_spi_frequency = SPI_SPEED
├──> <while ((ch = cli.getOpt(argc, argv, "R:")) != EOF)>
│ └──> <case 'R'>
│ ├──> cli.rotation = (enum Rotation)atoi(cli.optArg())
│ └──> break
├──> const char *verb = cli.optArg()
├──> <!verb>
│ ├──> ThisDriver::print_usage()
│ └──> return -1
├──> BusInstanceIterator iterator(MODULE_NAME, cli, DRV_IMU_DEVTYPE_ICM20689)
├──> <!strcmp(verb, "start")>
│ └──> return ThisDriver::module_start(cli, iterator) //模块启动
├──> <(!strcmp(verb, "stop")>
│ └──> return ThisDriver::module_stop(iterator) //模块停止
├──> <!strcmp(verb, "status")>
│ └──> return ThisDriver::module_status(iterator) //模块状态
├──> ThisDriver::print_usage()
└──> return -1
2.2 自定义子命令custom_command
注:该模块采用了纯C语言代码实现,在main函数中直接执行命令,无需ModuleBase的custom_command重载实现。
2.3 模块状态print_status【重载】
该模块采用了纯C语言代码实现,在main函数中直接执行ThisDriver::print_usage()函数,无需ModuleBase的模块状态print_status重载实现。
void ICM20689::print_usage()
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_DEFAULT_COMMANDS();
3. ICM20689模块重要函数
3.1 模块启动ThisDriver::module_start
启动过程会将以下驱动信息关联到设备实例上:
- static I2CSPIDriverBase *I2CSPIDriver::instantiate_default(const I2CSPIDriverConfig &config, int runtime_instance)
- int ICM20689::init()
- void ICM20689::RunImpl()
- void I2CSPIDriver::Run() final
ThisDriver::module_start(ICM20689::module_start)
└──> I2CSPIDriver::module_start
└──> I2CSPIDriverBase::module_start
注:I2CSPIDriverBase::module_start会进行第一次的Run激活(px4::WorkItemSingleShot)。
3.2 模块停止ThisDriver::module_stop
ThisDriver::module_stop(ICM20689::module_stop)
└──> I2CSPIDriverBase::module_stop
注:I2CSPIDriverBase类的通用方法,不在这里展开。
3.3 模块状态ThisDriver::module_status
ThisDriver::module_status(ICM20689::module_status)
└──> I2CSPIDriverBase::module_status
注:I2CSPIDriverBase类的通用方法,不在这里展开。
3.4 设备实例对象初始化I2CSPIDriver::instantiate_default
该方法在I2CSPIDriverBase::module_start函数里面调用,其目的是新建一个设备对象实例,并进行初始化。
I2CSPIDriver::instantiate_default
├──> instance = new T(config) // 新建一个ICM20689设备对象实例
├──> <!instance>
│ ├──> PX4_ERR("alloc failed")
│ └──> return nullptr
├──> <OK != instance->init()> // ICM20689设备对象实例初始化
│ ├──> delete instance
│ └──> return nullptr
└──> return instance
3.5 ICM20689设备实例对象初始化ICM20689::init
ICM20689设备实例对象初始化
ICM20689::init
├──> int ret = SPI::init() // SPI总线初始化
├──> <ret != PX4_OK>
│ ├──> DEVICE_DEBUG("SPI::init failed (%i)", ret)
│ └──> return ret
└──> return Reset() ? 0 : -1 // 重置模块,然后触发ScheduleNow
3.6 设备实例对象任务I2CSPIDriver::Run()
ICM20689设备初始化时以及设置定时时间,定时轮询Run过程,并调用业务实现方法RunImpl。
I2CSPIDriver::Run
├──> static_cast<T *>(this)->RunImpl()
└──> <should_exit()>
└──> exit_and_cleanup() //优雅退出处理
3.7 ICM20689设备实例对象任务ICM20689::RunImpl
根据ICM20689模块业务状态机变化,进行业务操作,发布gyro, accel, temperature消息
ICM20689::RunImpl
├──> const hrt_abstime now = hrt_absolute_time()
└──> switch (_state)
├──> <case STATE::RESET>
│ ├──> [PWR_MGMT_1: Device Reset ]
│ └──> ScheduleDelayed(100_ms)
├──> <case STATE::WAIT_FOR_RESET>
│ ├──> <Reset OK??? (RegisterRead(Register::WHO_AM_I) == WHOAMI) && (RegisterRead(Register::PWR_MGMT_1) == 0x40)>
│ │ ├──> [offset registers (factory calibration) should not change during normal operation]
│ │ ├──> [Wakeup and reset digital signal path
│ │ ├──> [_state = STATE::CONFIGURE // if reset succeeded then configure
│ │ └──> ScheduleDelayed(35_ms) // max 35 ms start-up time from sleep
│ └──> <else Reset failed> // RESET not complete
│ ├──> <hrt_elapsed_time(&_reset_timestamp) > 1000_ms> // Reset failed, retrying
│ │ ├──> _state = STATE::RESET
│ │ └──> ScheduleDelayed(100_ms)
│ └──> <else> // Reset not complete, check again in 10 ms
│ └──> ScheduleDelayed(10_ms)
├──> <case STATE::CONFIGURE>
│ ├──> <Configure()> // if configure succeeded then start reading from FIFO
│ │ ├──> _state = STATE::FIFO_READ
│ │ │ ├──> <DataReadyInterruptConfigure()>
│ │ │ │ ├──> _data_ready_interrupt_enabled = true
│ │ │ │ └──> ScheduleDelayed(100_ms) // backup schedule as a watchdog timeout
│ │ │ └──> <else>
│ │ │ ├──> _data_ready_interrupt_enabled = false
│ │ │ └──> ScheduleOnInterval(_fifo_empty_interval_us, _fifo_empty_interval_us)
│ │ └──> FIFOReset()
│ └──> <else > // CONFIGURE not complete
│ ├──> <hrt_elapsed_time(&_reset_timestamp) > 1000_ms> // Configure failed, resetting
│ │ └──> _state = STATE::RESET
│ ├──> <else> // Configure failed, retrying
│ └──> ScheduleDelayed(100_ms)
└──> <case STATE::FIFO_READ>
├──> [Execption handling procedures]
├──> [Update temperature readings]
└──> [Update gyro and accel] //FIFORead function and ProcessGyro/ProcessAccel
4. 总结
具体逻辑业务后续再做深入,从模块代码角度:
-
输入: 芯片(硬件)
-
输出: 修改OSD显示内容
uORB::PublicationMulti<sensor_gyro_s> _sensor_pubORB_ID(sensor_gyro);
uORB::PublicationMulti<sensor_gyro_fifo_s> _sensor_fifo_pubORB_ID(sensor_gyro_fifo);
uORB::PublicationMulti<sensor_accel_s> _sensor_pubORB_ID(sensor_accel);
uORB::PublicationMulti<sensor_accel_fifo_s> _sensor_fifo_pubORB_ID(sensor_accel_fifo);
注1:参考class PX4Accelerometer和class PX4Gyroscope。
注2:参考ICM 20689芯片规格书: DS-000143-ICM-20689-TYP-v1.1.pdf
5. 参考资料
【1】PX4开源软件框架简明简介
【2】PX4模块设计之十一:Built-In框架
【3】PX4模块设计之十二:High Resolution Timer设计
【4】PX4模块设计之十三:WorkQueue设计
【5】PX4模块设计之十七:ModuleBase模块
【6】PX4模块设计之三十:Hysteresis类
【7】PX4 modules_main
【8】PX4模块设计之四十一:I2C/SPI Bus Instance基础知识
以上是关于PX4模块设计之四十三:icm20689模块的主要内容,如果未能解决你的问题,请参考以下文章