int bmp280_main(int argc, char *argv[]);
PX4模块设计之四十四: bmp280模块
1. bmp280模块简介
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硬件芯片进行管理和数据采集的模块。
2. 模块入口函数
2.1 主入口bmp280_main
模块支持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
2.2 自定义子命令custom_command
注:该模块采用了纯C语言代码实现,在main函数中直接执行命令,无需ModuleBase的custom_command重载实现。
2.3 模块状态print_status【重载】
该模块采用了纯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();
}
3. bmp280模块重要函数
3.1 模块启动ThisDriver::module_start
启动过程会将以下驱动信息关联到设备实例上:
- static I2CSPIDriverBase *BMP280::instantiate(const I2CSPIDriverConfig &config, int runtime_instance)
- int BMP280::init()
- void BMP280::RunImpl()
- void I2CSPIDriver::Run() final
ThisDriver::module_start(BMP280::module_start)
└──> I2CSPIDriver::module_start
└──> I2CSPIDriverBase::module_start
注:I2CSPIDriverBase::module_start会进行第一次的Run激活(px4::WorkItemSingleShot)。
3.2 模块停止ThisDriver::module_stop
ThisDriver::module_stop(BMP280::module_stop)
└──> I2CSPIDriverBase::module_stop
注:I2CSPIDriverBase类的通用方法,不在这里展开。
3.3 模块状态ThisDriver::module_status
ThisDriver::module_status(BMP280::module_status)
└──> I2CSPIDriverBase::module_status
注:I2CSPIDriverBase类的通用方法,不在这里展开。
3.4 设备实例对象初始化BMP280::instantiate
该方法在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;
3.5 BMP280设备实例对象初始化BMP280::init
BMP280设备实例对象初始化
BMP280::init
├──> [reset sensor]
├──> [check id]
├──> [set config, recommended settings]
├──> [get calibration and pre process them]
├──> Start() // 重置模块状态机,然后触发ScheduleNow
└──> return OK
3.6 设备实例对象任务I2CSPIDriver::Run()
BMP280设备初始化时以及设置定时时间,定时轮询Run过程,并调用业务实现方法RunImpl。
I2CSPIDriver::Run
├──> static_cast<T *>(this)->RunImpl()
└──> <should_exit()>
└──> exit_and_cleanup() //优雅退出处理
3.7 BMP280设备实例对象任务BMP280::RunImpl
根据BMP280模块业务状态机变化,进行业务操作,发布sensor_baro消息。
BMP280::RunImpl
├──> <_collect_phase>
│ └──> collect(); // 获取测试数据,并发布sensor_baro消息
├──> <else>
│ └──> measure(); // 触发一次测试
└──> ScheduleDelayed(_measure_interval);
4. 总结
具体逻辑业务后续再做深入,从模块代码角度:
-
输入: 芯片(硬件:bmp280)
-
输出: sensor_baro消息
uORB::PublicationMulti<sensor_baro_s> _sensor_baro_pub{ORB_ID(sensor_baro)};
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基础知识