PX4 Firmware
PX4 Autopilot Software http://px4.io
icm20948_main.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file main.cpp
36  *
37  * Driver for the Invensense icm20948 connected via I2C or SPI.
38  *
39  * based on the icm20948 driver
40  */
41 
42 #include <px4_platform_common/px4_config.h>
43 #include <px4_platform_common/getopt.h>
44 #include <lib/perf/perf_counter.h>
46 #include <board_config.h>
47 #include <drivers/drv_hrt.h>
48 #include <drivers/device/spi.h>
50 
51 #include "icm20948.h"
52 
53 /** driver 'main' command */
54 extern "C" { __EXPORT int icm20948_main(int argc, char *argv[]); }
55 
62 };
63 
64 /**
65  * Local functions in support of the shell command.
66  */
67 namespace icm20948
68 {
69 
70 // list of supported bus configurations
75  uint8_t busnum;
76  uint32_t address;
78 } bus_options[] = {
79 
80 #if defined(PX4_SPIDEV_ICM_20948) && defined(PX4_SPI_BUS_1)
81  { ICM20948_BUS_SPI_INTERNAL, &ICM20948_SPI_interface, true, PX4_SPI_BUS_1, PX4_SPIDEV_ICM_20948, nullptr },
82 #endif
83 
84 #if defined (USE_I2C)
85 # if defined(PX4_I2C_BUS_EXPANSION)
86  { ICM20948_BUS_I2C_EXTERNAL, &ICM20948_I2C_interface, false, PX4_I2C_BUS_EXPANSION, PX4_I2C_EXT_ICM20948_1, nullptr },
87 # endif
88 #endif
89 };
90 
91 #define NUM_BUS_OPTIONS (sizeof(bus_options)/sizeof(bus_options[0]))
92 
93 
94 bool start_bus(icm20948_bus_option &bus, enum Rotation rotation);
95 icm20948_bus_option *find_bus(enum ICM20948_BUS busid);
96 
97 int start(enum ICM20948_BUS busid, enum Rotation rotation);
98 int stop(enum ICM20948_BUS busid);
99 int info(enum ICM20948_BUS busid);
100 int usage();
101 
102 /**
103  * find a bus structure for a busid
104  */
106 {
107  for (uint8_t i = 0; i < NUM_BUS_OPTIONS; i++) {
108  if ((busid == ICM20948_BUS_ALL ||
109  busid == bus_options[i].busid) && bus_options[i].dev != nullptr) {
110  return &bus_options[i];
111  }
112  }
113 
114  PX4_ERR("bus %u not started", (unsigned)busid);
115  return nullptr;
116 }
117 
118 /**
119  * start driver for a specific bus option
120  */
121 bool
123 {
124  PX4_INFO("Bus probed: %d", bus.busid);
125 
126  if (bus.dev != nullptr) {
127  PX4_ERR("SPI %d not available", bus.busid);
128  return false;
129  }
130 
131  device::Device *interface = bus.interface_constructor(bus.busnum, bus.address);
132 
133  if (interface == nullptr) {
134  PX4_WARN("no device on bus %u", (unsigned)bus.busid);
135  return false;
136  }
137 
138  if (interface->init() != OK) {
139  delete interface;
140  PX4_WARN("no device on bus %u", (unsigned)bus.busid);
141  return false;
142  }
143 
144  device::Device *mag_interface = nullptr;
145 
146 #ifdef USE_I2C
147  /* For i2c interfaces, connect to the magnetomer directly */
148  const bool is_i2c = bus.busid == ICM20948_BUS_I2C_INTERNAL || bus.busid == ICM20948_BUS_I2C_EXTERNAL;
149 
150  if (is_i2c) {
151  mag_interface = AK09916_I2C_interface(bus.busnum);
152  }
153 
154 #endif
155 
156  bus.dev = new ICM20948(interface, mag_interface, rotation);
157 
158  if (bus.dev == nullptr) {
159  delete interface;
160 
161  if (mag_interface != nullptr) {
162  delete mag_interface;
163  }
164 
165  return false;
166  }
167 
168  if (OK != bus.dev->init()) {
169  goto fail;
170  }
171 
172  return true;
173 
174 fail:
175 
176  if (bus.dev != nullptr) {
177  delete (bus.dev);
178  bus.dev = nullptr;
179  }
180 
181  PX4_ERR("driver start failed");
182 
183  return false;
184 }
185 
186 /**
187  * Start the driver.
188  *
189  * This function only returns if the driver is up and running
190  * or failed to detect the sensor.
191  */
192 int
193 start(enum ICM20948_BUS busid, enum Rotation rotation)
194 {
195  bool started = false;
196 
197  for (unsigned i = 0; i < NUM_BUS_OPTIONS; i++) {
198  if (bus_options[i].dev != nullptr) {
199  // this device is already started
200  continue;
201  }
202 
203  if (busid != ICM20948_BUS_ALL && bus_options[i].busid != busid) {
204  // not the one that is asked for
205  continue;
206  }
207 
208  started |= start_bus(bus_options[i], rotation);
209 
210  if (started) { break; }
211  }
212 
213  return PX4_OK;
214 }
215 
216 int
218 {
219  icm20948_bus_option *bus = find_bus(busid);
220 
221  if (bus != nullptr && bus->dev != nullptr) {
222  delete bus->dev;
223  bus->dev = nullptr;
224 
225  } else {
226  /* warn, but not an error */
227  PX4_WARN("already stopped.");
228  }
229 
230  return PX4_OK;
231 }
232 
233 /**
234  * Print a little info about the driver.
235  */
236 int
238 {
239  icm20948_bus_option *bus = find_bus(busid);
240 
241  if (bus != nullptr && bus->dev != nullptr) {
242  PX4_WARN("driver not running");
243  return PX4_ERROR;
244  }
245 
246  bus->dev->print_info();
247 
248  return PX4_OK;
249 }
250 
251 int
253 {
254  PX4_INFO("missing command: try 'start', 'stop', 'info'");
255  PX4_INFO("options:");
256  PX4_INFO(" -X (i2c external bus)");
257  PX4_INFO(" -I (i2c internal bus)");
258  PX4_INFO(" -s (spi internal bus)");
259  PX4_INFO(" -S (spi external bus)");
260  PX4_INFO(" -t (spi internal bus, 2nd instance)");
261  PX4_INFO(" -R rotation");
262 
263  return PX4_OK;
264 }
265 
266 } // namespace icm20948
267 
268 int
269 icm20948_main(int argc, char *argv[])
270 {
271  int myoptind = 1;
272  int ch;
273  const char *myoptarg = nullptr;
274 
276  enum Rotation rotation = ROTATION_NONE;
277 
278  while ((ch = px4_getopt(argc, argv, "XISstMR:", &myoptind, &myoptarg)) != EOF) {
279  switch (ch) {
280  case 'X':
282  break;
283 
284  case 'R':
285  rotation = (enum Rotation)atoi(myoptarg);
286  break;
287 
288  default:
289  return icm20948::usage();
290  }
291  }
292 
293  if (myoptind >= argc) {
294  return icm20948::usage();
295  }
296 
297  const char *verb = argv[myoptind];
298 
299  /*
300  * Start/load the driver.
301  */
302  if (!strcmp(verb, "start")) {
303  return icm20948::start(busid, rotation);
304  }
305 
306  if (!strcmp(verb, "stop")) {
307  return icm20948::stop(busid);
308  }
309 
310  /*
311  * Print driver information.
312  */
313  if (!strcmp(verb, "info")) {
314  return icm20948::info(busid);
315  }
316 
317  return icm20948::usage();
318 }
int usage()
Prints info about the driver argument usage.
#define PX4_I2C_EXT_ICM20948_1
Definition: icm20948.h:190
Local functions in support of the shell command.
bool start_bus(icm20948_bus_option &bus, enum Rotation rotation)
start driver for a specific bus option
Definition: I2C.hpp:51
Vector rotation library.
High-resolution timer with callouts and timekeeping.
ICM20948_BUS
device::Device * AK09916_I2C_interface(int bus)
int start(enum ICM20948_BUS busid, enum Rotation rotation)
Start the driver.
Definition of commonly used conversions.
#define NUM_BUS_OPTIONS
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
device::Device * ICM20948_SPI_interface(int bus, uint32_t cs)
ICM20948_constructor interface_constructor
int info(enum ICM20948_BUS busid)
Print a little info about the driver.
device::Device * ICM20948_I2C_interface(int bus, uint32_t address)
device::Device *(* ICM20948_constructor)(int, uint32_t)
Definition: icm20948.h:346
Fundamental base class for all physical drivers (I2C, SPI).
Definition: Device.hpp:65
int stop(enum ICM20948_BUS busid)
#define OK
Definition: uavcan_main.cpp:71
struct icm20948::icm20948_bus_option bus_options[]
void print_info()
Diagnostics - print some basic information about the driver.
Definition: icm20948.cpp:857
icm20948_bus_option * find_bus(enum ICM20948_BUS busid)
find a bus structure for a busid
__EXPORT int icm20948_main(int argc, char *argv[])
driver &#39;main&#39; command
Performance measuring tools.