int bmp280_main(int argc, char *argv[]);
bmp280 <command> [arguments...] Commands: start [-I] Internal I2C bus(es) [-X] External I2C bus(es) [-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) [-a <val>] I2C address default: 118 [-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) stop status print status info
注1:print_usage函数是具体对应实现。
class BMP280 : public I2CSPIDriver<BMP280> 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 *> BMP280 //类继承关系 └──> I2CSPIDriver └──> I2CSPIDriverBase ├──> px4::ScheduledWorkItem │ └──> WorkItem │ ├──> IntrusiveSortedListNode │ └──> IntrusiveQueueNode └──> I2CSPIInstance └──> ListNode
注2:BMP280模块就是针对BMP280硬件芯片进行管理和数据采集的模块。
模块支持start/stop/status命令,除此以外支持BusCLIArguments的I2C/SPI默认参数选项"RXIa:Ssc: m:kb:f:q"。
bmp280_main ├──> using ThisDriver = BMP280; ├──> BusCLIArguments cli{true, true}; ├──> <CONFIG_I2C> │ ├──> cli.i2c_address = 0x76; │ └──> cli.default_i2c_frequency = 100 * 1000; ├──> <CONFIG_SPI> │ └──> cli.default_spi_frequency = 10 * 1000 * 1000; ├──> const char *verb = cli.parseDefaultArguments(argc, argv) ├──> <!verb> │ ├──> ThisDriver::print_usage() │ └──> return -1 ├──> BusInstanceIterator iterator(MODULE_NAME, cli, DRV_BARO_DEVTYPE_BMP280) ├──> <!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
注:该模块采用了纯C语言代码实现,在main函数中直接执行命令,无需ModuleBase的custom_command重载实现。
该模块采用了纯C语言代码实现,在main函数中直接执行ThisDriver::print_usage()函数,无需ModuleBase的模块状态print_status重载实现。
void
BMP280::print_usage()
{
PRINT_MODULE_USAGE_NAME("bmp280", "driver");
PRINT_MODULE_USAGE_SUBCATEGORY("baro");
PRINT_MODULE_USAGE_COMMAND("start");
#if defined(CONFIG_I2C)
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, true);
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x76);
#else
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(false, true);
#endif
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
启动过程会将以下驱动信息关联到设备实例上:
ThisDriver::module_start(BMP280::module_start)
└──> I2CSPIDriver::module_start
└──> I2CSPIDriverBase::module_start
注:I2CSPIDriverBase::module_start会进行第一次的Run激活(px4::WorkItemSingleShot)。
ThisDriver::module_stop(BMP280::module_stop)
└──> I2CSPIDriverBase::module_stop
注:I2CSPIDriverBase类的通用方法,不在这里展开。
ThisDriver::module_status(BMP280::module_status)
└──> I2CSPIDriverBase::module_status
注:I2CSPIDriverBase类的通用方法,不在这里展开。
该方法在I2CSPIDriverBase::module_start函数里面调用,其目的是新建一个设备对象实例,并进行初始化。
BMP280::instantiate ├──> bmp280::IBMP280 *interface = nullptr; ├──> <CONFIG_I2C><config.bus_type == BOARD_I2C_BUS> │ └──> interface = bmp280_i2c_interface(config.bus, config.i2c_address, config.bus_frequency); ├──> <CONFIG_SPI><config.bus_type == BOARD_SPI_BUS> │ └──> interface = bmp280_spi_interface(config.bus, config.spi_devid, config.bus_frequency, config.spi_mode); ├──> <interface == nullptr> │ ├──> PX4_ERR("failed creating interface for bus %i", config.bus); │ └──> return nullptr; ├──> <interface->init() != OK> // I2C/SPI总线初始化 │ ├──> delete interface; │ ├──> PX4_DEBUG("no device on bus %i", config.bus); │ └──> return nullptr; ├──> BMP280 *dev = new BMP280(config, interface); // 新建一个BMP280设备对象实例 ├──> <dev == nullptr> │ ├──> delete interface; │ └──> return nullptr; ├──> <OK != dev->init()> // BMP280设备对象实例初始化 │ ├──> delete dev; │ └──> return nullptr; └──> return dev;
BMP280设备实例对象初始化
BMP280::init
├──> [reset sensor]
├──> [check id]
├──> [set config, recommended settings]
├──> [get calibration and pre process them]
├──> Start() // 重置模块状态机,然后触发ScheduleNow
└──> return OK
BMP280设备初始化时以及设置定时时间,定时轮询Run过程,并调用业务实现方法RunImpl。
I2CSPIDriver::Run
├──> static_cast<T *>(this)->RunImpl()
└──> <should_exit()>
└──> exit_and_cleanup() //优雅退出处理
根据BMP280模块业务状态机变化,进行业务操作,发布sensor_baro消息。
BMP280::RunImpl
├──> <_collect_phase>
│ └──> collect(); // 获取测试数据,并发布sensor_baro消息
├──> <else>
│ └──> measure(); // 触发一次测试
└──> ScheduleDelayed(_measure_interval);
具体逻辑业务后续再做深入,从模块代码角度:
输入: 芯片(硬件:bmp280)
输出: sensor_baro消息
uORB::PublicationMulti<sensor_baro_s> _sensor_baro_pub{ORB_ID(sensor_baro)};
【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基础知识
联系客服