43 #include <px4_platform_common/px4_config.h> 44 #include <px4_platform_common/defines.h> 45 #include <px4_platform_common/getopt.h> 47 #include <sys/types.h> 51 #include <semaphore.h> 60 #include <nuttx/arch.h> 61 #include <nuttx/clock.h> 63 #include <board_config.h> 79 #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> 87 #define IST8310_CONVERSION_INTERVAL (1000000 / 100) 89 #define IST8310_BUS_I2C_ADDR 0xE 90 #define IST8310_DEFAULT_BUS_SPEED 400000 99 #define IST8310_RESOLUTION 0.3 109 # define WAI_EXPECTED_VALUE 0x10 111 #define ADDR_STAT1 0x02 112 # define STAT1_DRDY_SHFITS 0x0 113 # define STAT1_DRDY (1 << STAT1_DRDY_SHFITS) 114 # define STAT1_DRO_SHFITS 0x1 115 # define STAT1_DRO (1 << STAT1_DRO_SHFITS) 117 #define ADDR_DATA_OUT_X_LSB 0x03 118 #define ADDR_DATA_OUT_X_MSB 0x04 119 #define ADDR_DATA_OUT_Y_LSB 0x05 120 #define ADDR_DATA_OUT_Y_MSB 0x06 121 #define ADDR_DATA_OUT_Z_LSB 0x07 122 #define ADDR_DATA_OUT_Z_MSB 0x08 124 #define ADDR_STAT2 0x09 125 # define STAT2_INT_SHFITS 3 126 # define STAT2_INT (1 << STAT2_INT_SHFITS) 128 #define ADDR_CTRL1 0x0a 129 # define CTRL1_MODE_SHFITS 0 130 # define CTRL1_MODE_STDBY (0 << CTRL1_MODE_SHFITS) 131 # define CTRL1_MODE_SINGLE (1 << CTRL1_MODE_SHFITS) 133 #define ADDR_CTRL2 0x0b 134 # define CTRL2_SRST_SHFITS 0 135 # define CTRL2_SRST (1 << CTRL2_SRST_SHFITS) 136 # define CTRL2_DRP_SHIFTS 2 137 # define CTRL2_DRP (1 << CTRL2_DRP_SHIFTS) 138 # define CTRL2_DREN_SHIFTS 3 139 # define CTRL2_DREN (1 << CTRL2_DREN_SHIFTS) 141 #define ADDR_CTRL3 0x41 142 # define CTRL3_SAMPLEAVG_16 0x24 143 # define CTRL3_SAMPLEAVG_8 0x1b 144 # define CTRL3_SAMPLEAVG_4 0x12 145 # define CTRL3_SAMPLEAVG_2 0x09 147 #define ADDR_CTRL4 0x42 148 # define CTRL4_SRPD 0xC0 150 #define ADDR_STR 0x0c 151 # define STR_SELF_TEST_SHFITS 6 152 # define STR_SELF_TEST_ON (1 << STR_SELF_TEST_SHFITS) 153 # define STR_SELF_TEST_OFF (0 << STR_SELF_TEST_SHFITS) 155 #define ADDR_Y11_Low 0x9c 156 #define ADDR_Y11_High 0x9d 157 #define ADDR_Y12_Low 0x9e 158 #define ADDR_Y12_High 0x9f 159 #define ADDR_Y13_Low 0xa0 160 #define ADDR_Y13_High 0xa1 161 #define ADDR_Y21_Low 0xa2 162 #define ADDR_Y21_High 0xa3 163 #define ADDR_Y22_Low 0xa4 164 #define ADDR_Y22_High 0xa5 165 #define ADDR_Y23_Low 0xa6 166 #define ADDR_Y23_High 0xa7 167 #define ADDR_Y31_Low 0xa8 168 #define ADDR_Y31_High 0xa9 169 #define ADDR_Y32_Low 0xaa 170 #define ADDR_Y32_High 0xab 171 #define ADDR_Y33_Low 0xac 172 #define ADDR_Y33_High 0xad 174 #define ADDR_TEMPL 0x1c 175 #define ADDR_TEMPH 0x1d 186 class IST8310 :
public device::I2C,
public px4::ScheduledWorkItem
189 IST8310(
int bus_number,
int address,
const char *path,
enum Rotation rotation);
194 virtual ssize_t
read(
struct file *filp,
char *buffer,
size_t buflen);
195 virtual int ioctl(
struct file *filp,
int cmd,
unsigned long arg);
305 int write(
unsigned address,
void *
data,
unsigned count);
314 int read_reg(uint8_t reg, uint8_t &val);
324 int read(
unsigned address,
void *data,
unsigned count);
380 ScheduledWorkItem(MODULE_NAME,
px4::device_bus_to_wq(get_device_id())),
454 if (
sizeof(buf) < (count + 1)) {
459 memcpy(&buf[1], data, count);
461 return transfer(&buf[0], count + 1,
nullptr, 0);
467 uint8_t cmd = address;
468 return transfer(&cmd, 1, (uint8_t *)data, count);
481 uint8_t ctrl_reg_in = 0;
518 unsigned count = buflen /
sizeof(
struct mag_report);
542 return ret ? ret : -EAGAIN;
606 unsigned interval = (1000000 / arg);
650 return CDev::ioctl(filp, cmd, arg);
691 uint8_t
data[1] = {0};
769 #pragma pack(push, 1) 781 uint8_t check_counter;
785 const bool sensor_is_external = external();
793 new_report.is_external = sensor_is_external;
796 new_report.device_id = _device_id.devid;
815 report.x = (((int16_t)report_buffer.x[1]) << 8) | (int16_t)report_buffer.x[0];
816 report.y = (((int16_t)report_buffer.y[1]) << 8) | (int16_t)report_buffer.y[0];
817 report.z = (((int16_t)report_buffer.z[1]) << 8) | (int16_t)report_buffer.z[0];
833 new_report.temperature = 0;
841 new_report.x_raw = report.y;
842 new_report.y_raw = report.x;
843 new_report.z_raw = report.z;
856 if (!(_pub_blocked)) {
889 if (check_counter == 128) {
905 float total_x = 0.0f;
906 float total_y = 0.0f;
907 float total_z = 0.0f;
910 int fd = (int)enable;
922 float sum_in_test[3] = {0.0f, 0.0f, 0.0f};
923 float sum_in_normal[3] = {0.0f, 0.0f, 0.0f};
924 float *sum = &sum_in_normal[0];
927 PX4_WARN(
"FAILED: MAGIOCGSCALE 1");
933 PX4_WARN(
"FAILED: MAGIOCSSCALE 1");
940 PX4_WARN(
"FAILED: SENSORIOCSPOLLRATE 50Hz");
948 for (uint8_t p = 0; p < 2; p++) {
955 PX4_WARN(
"FAILED: MAGIOCEXSTRAP 1");
960 sum = &sum_in_test[0];
964 for (uint8_t i = 0; i < 30; i++) {
972 ret = ::poll(&fds, 1, 2000);
975 PX4_WARN(
"ERROR: TIMEOUT 2");
981 sz =
::read(fd, &report,
sizeof(report));
983 if (sz !=
sizeof(report)) {
984 PX4_WARN(
"ERROR: READ 2");
990 sum[0] += report.x_raw;
991 sum[1] += report.y_raw;
992 sum[2] += report.z_raw;
997 total_x = fabsf(sum_in_test[0] - sum_in_normal[0]);
998 total_y = fabsf(sum_in_test[1] - sum_in_normal[1]);
999 total_z = fabsf(sum_in_test[2] - sum_in_normal[2]);
1001 ret = ((total_x + total_y + total_z) < (
float)0.000001);
1006 PX4_WARN(
"FAILED: MAGIOCSSCALE 2");
1012 PX4_WARN(
"FAILED: MAGIOCEXSTRAP 0");
1018 PX4_WARN(
"FAILED: SCALE");
1023 PX4_ERR(
"FAILED: CALIBRATION SCALE %d, %d, %d", (
int)total_x, (
int)total_y, (
int)total_z);
1042 offset_valid =
false;
1045 offset_valid =
true;
1049 return !offset_valid;
1077 uint8_t str_reg_ret = 0;
1080 return !(str == str_reg_ret);
1087 return write(reg, &buf, 1);
1094 int ret =
read(reg, &buf, 1);
1120 _reports->print_info(
"report queue");
1139 #ifdef PX4_I2C_BUS_EXPANSION1 1142 #ifdef PX4_I2C_BUS_EXPANSION2 1145 #ifdef PX4_I2C_BUS_ONBOARD 1149 #define NUM_BUS_OPTIONS (sizeof(bus_options)/sizeof(bus_options[0])) 1152 bool start_bus(
struct ist8310_bus_option &bus,
int address,
enum Rotation rotation);
1166 if (bus.
dev !=
nullptr) {
1167 errx(1,
"bus option already started");
1170 IST8310 *
interface = new IST8310(bus.busnum, address, bus.devpath, rotation);
1172 if (interface->init() !=
OK) {
1174 PX4_INFO(
"no device on bus %u", (
unsigned)bus.busid);
1178 bus.dev = interface;
1180 int fd = open(bus.devpath, O_RDONLY);
1188 errx(1,
"Failed to setup poll rate");
1206 bool started =
false;
1239 errx(1,
"bus %u not started", (
unsigned)busid);
1255 const char *path = bus.
devpath;
1257 int fd = open(path, O_RDONLY);
1260 err(1,
"%s open failed (try 'ist8310 start')", path);
1264 sz =
read(fd, &report,
sizeof(report));
1266 if (sz !=
sizeof(report)) {
1267 err(1,
"immediate read failed");
1270 print_message(report);
1274 errx(1,
"failed to get if mag is onboard or external");
1278 for (
unsigned i = 0; i < 5; i++) {
1283 fds.events = POLLIN;
1284 ret = poll(&fds, 1, 2000);
1287 errx(1,
"timed out waiting for sensor data");
1291 sz =
read(fd, &report,
sizeof(report));
1293 if (sz !=
sizeof(report)) {
1294 err(1,
"periodic read failed");
1297 print_message(report);
1333 const char *path = bus.
devpath;
1335 int fd = open(path, O_RDONLY);
1338 err(1,
"%s open failed (try 'ist8310 start' if the driver is not running", path);
1342 PX4_WARN(
"failed to enable sensor calibration mode");
1357 const char *path = bus.
devpath;
1359 int fd = open(path, O_RDONLY);
1366 err(1,
"driver reset failed");
1370 err(1,
"driver poll restart failed");
1387 PX4_INFO(
"running on bus: %u (%s)\n", (
unsigned)bus.
busid, bus.
devpath);
1395 PX4_INFO(
"missing command: try 'start', 'info', 'test', 'reset', 'calibrate'");
1396 PX4_INFO(
"options:");
1397 PX4_INFO(
" -R rotation");
1398 PX4_INFO(
" -C calibrate on start");
1415 const char *myoptarg =
nullptr;
1417 while ((ch = px4_getopt(argc, argv,
"R:Ca:b:", &myoptind, &myoptarg)) != EOF) {
1420 rotation = (
enum Rotation)atoi(myoptarg);
1424 i2c_addr = (int)strtol(myoptarg, NULL, 0);
1428 i2c_busid = (
IST8310_BUS)strtol(myoptarg, NULL, 0);
1441 if (myoptind >= argc) {
1446 const char *verb = argv[myoptind];
1451 if (!strcmp(verb,
"start")) {
1455 PX4_ERR(
"calibration only feasible against one bus");
1459 PX4_ERR(
"calibration failed");
1469 if (!strcmp(verb,
"test")) {
1476 if (!strcmp(verb,
"reset")) {
1483 if (!strcmp(verb,
"info") || !strcmp(verb,
"status")) {
1490 if (!strcmp(verb,
"calibrate")) {
1492 PX4_INFO(
"calibration successful");
1496 PX4_ERR(
"calibration failed");
perf_counter_t _conf_errors
#define CTRL3_SAMPLEAVG_16
#define MAGIOCGSCALE
copy the mag scaling constants to the structure pointed to by (arg)
#define CTRL1_MODE_SINGLE
#define MAGIOCGEXTERNAL
determine if mag is external or onboard
#define IST8310_DEFAULT_BUS_SPEED
perf_counter_t _range_errors
void start(enum IST8310_BUS busid, int address, enum Rotation rotation)
Start the driver.
void check_conf(void)
check the sensor configuration.
measure the time elapsed performing an event
API for the uORB lightweight object broker.
__EXPORT int ist8310_main(int argc, char *argv[])
perf_counter_t _comms_errors
#define MAGIOCEXSTRAP
excite strap
#define SENSOR_POLLRATE_DEFAULT
poll at driver normal rate
__EXPORT void rotate_3f(enum Rotation rot, float &x, float &y, float &z)
rotate a 3 element float vector in-place
void usage(const char *reason)
Print the correct usage.
virtual int ioctl(struct file *filp, int cmd, unsigned long arg)
int write_reg(uint8_t reg, uint8_t val)
Write a register.
mag scaling factors; Vout = (Vin * Vscale) + Voffset
void start()
Initialise the automatic measurement state machine and start it.
int calibrate(struct file *filp, unsigned enable)
Perform the on-sensor scale calibration routine.
int check_scale()
Check the current scale calibration.
count the number of times an event occurs
static const int16_t IST8310_MAX_VAL_Z
High-resolution timer with callouts and timekeeping.
int reset()
Reset the device.
int info(enum IST8310_BUS busid)
Print a little info about the driver.
void usage()
Prints info about the driver argument usage.
void test(enum IST8310_BUS busid)
Perform some basic functional tests on the driver; make sure we can collect data from the sensor in p...
#define IST8310_BUS_I2C_ADDR
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
Generic device / sensor interface.
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
#define IST8310_CONVERSION_INTERVAL
sensor_mag_s _last_report
used for info()
void perf_count(perf_counter_t handle)
Count a performance event.
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
void perf_free(perf_counter_t handle)
Free a counter.
#define MAG_BASE_DEVICE_PATH
void init()
Activates/configures the hardware registers.
#define MAGIOCCALIBRATE
perform self-calibration, update scale factors to canonical units
int write(unsigned address, void *data, unsigned count)
Write to a register block.
Local functions in support of the shell command.
void stop()
Stop the automatic measurement state machine.
#define IST8310_RESOLUTION
int set_selftest(unsigned enable)
Place the device in self test mode.
Rotation
Enum for board and external compass rotations.
static const int16_t IST8310_MAX_VAL_XY
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
void reset(enum IST8310_BUS busid)
Reset the driver.
bool _calibrated
the calibration is valid
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
int calibrate(enum IST8310_BUS busid)
Automatic scale calibration.
void perf_end(perf_counter_t handle)
End a performance event.
perf_counter_t _sample_perf
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
#define ADDR_DATA_OUT_X_LSB
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
IST8310 operator=(const IST8310 &)
bool start_bus(struct ist8310_bus_option &bus, int address, enum Rotation rotation)
start driver for a specific bus option
static const int16_t IST8310_MIN_VAL_XY
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen)
void print_info()
Diagnostics - print some basic information about the driver.
struct @83::@85::@87 file
IST8310(int bus_number, int address, const char *path, enum Rotation rotation)
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
#define SENSORIOCRESET
Reset the sensor to its default configuration.
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
struct ist8310_bus_option & find_bus(enum IST8310_BUS busid)
find a bus structure for a busid
int check_offset()
Check the current offset calibration.
float meas_to_float(uint8_t in[2])
Convert a big-endian signed 16-bit value to a float.
bool _sensor_ok
sensor was found and reports ok
ringbuffer::RingBuffer * _reports
int collect()
Collect the result of the most recent measurement.
static const int16_t IST8310_MIN_VAL_Z
#define WAI_EXPECTED_VALUE
int read_reg(uint8_t reg, uint8_t &val)
Read a register.
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
void Run() override
Perform a poll cycle; collect from the previous measurement and start a new one.
void perf_begin(perf_counter_t handle)
Begin a performance event.
struct ist8310::ist8310_bus_option bus_options[]
#define DEVICE_DEBUG(FMT,...)
#define DRV_MAG_DEVTYPE_IST8310
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
unsigned _measure_interval
Performance measuring tools.
int measure()
Issue a measurement command.
Base class for devices connected via I2C.