Hey there,
I have a problem with the ICM 20948 driver: The function inv_device_setup of the driver package returns -1.
First the driver seems to flash the content of Invn/Images/icm_img.dmpa.h in register 7D where the bank selection of the DMP occurs with the write in register 7C. There is a validation of the flashed memory in inv_icm_firmware_load (line 63) which returns -1 in my case because the data_cmp does not contain the correct bytes.
I am testing on an STMF discovery with libopencm and the whole driver in the Invn folder. Am I doing something wrong?
My integration source code:
#include "icm20948.h"#define I2C_ADDRESS 0x69
static uint64_t writes = 0;
static uint64_t reads = 0;
static uint64_t byte_writes = 0;
static uint64_t byte_reads = 0;
static inv_device_icm20948_t device_icm20948;
static const inv_host_serif_t my_serif_instance = {
icm20948_open,
icm20948_close,
icm20948_read, /* callback to read_reg low level method */
icm20948_write, /* callback to read_reg low level method */
0,
1024,
1024,
INV_SERIF_HAL_TYPE_I2C, /* type of the serial interface (between SPI or I2C) */
};
static const inv_sensor_listener_t sensor_listener = {
icm20948_sensor_event_cb, /* callback that will receive sensor events */
0 /* some pointer passed to the callback */
};
static const uint8_t dmp3_image[] = {
#include "Invn/Images/icm20948_img.dmp3a.h"
};
static const struct {
uint8_t type;
uint32_t period_us;
} sensor_list[] = {
{INV_SENSOR_TYPE_RAW_ACCELEROMETER, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_RAW_GYROSCOPE, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_ACCELEROMETER, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_GYROSCOPE, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_MAGNETOMETER, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_UNCAL_GYROSCOPE, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_UNCAL_MAGNETOMETER, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_GAME_ROTATION_VECTOR, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_ROTATION_VECTOR, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_GEOMAG_ROTATION_VECTOR, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_ORIENTATION, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_STEP_COUNTER, 0},
{INV_SENSOR_TYPE_STEP_DETECTOR, 0},
{INV_SENSOR_TYPE_SMD, 0},
{INV_SENSOR_TYPE_BAC, 0},
{INV_SENSOR_TYPE_TILT_DETECTOR, 0},
{INV_SENSOR_TYPE_PICK_UP_GESTURE, 0},
{INV_SENSOR_TYPE_GRAVITY, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_LINEAR_ACCELERATION, 50000 /* 20 Hz */},
{INV_SENSOR_TYPE_B2S, 0},
};
int start_sensor(void)
{
/* Open the host serif */
if (inv_host_serif_open(&my_serif_instance) != 0) {
printf("Unable to open device.\n");
return -1;
}
toggle_led(ORANGE);
/* Create icm20948 Device */
inv_device_icm20948_init(&device_icm20948, &my_serif_instance, &sensor_listener, dmp3_image, sizeof(dmp3_image));
toggle_led(RED);
/* Get generic device handle from icm20948 Device */
inv_device_t * device = inv_device_icm20948_get_base(&device_icm20948);
/* Get the whoami */
uint8_t whoami;
if (inv_device_whoami(device, &whoami) != 0) {
printf("Unable to get whoami.\n");
return -1;
}
printf("Whoami: %x\n", whoami);
if (whoami != 0xea) {
printf("Wrong whoami, stopping.\n");
return -1;
}
int ret = 0;
// Setup the device
ret = inv_device_setup(device);
if (ret != 0) {
printf("Could not setup device: %d\n", ret);
return -1;
}
printf("Device setup successful.\n");
// Setup the device
ret = inv_device_load(device, 0, dmp3_image, sizeof(dmp3_image), true, 0);
if (ret != 0) {
printf("Could not load device image: %d\n", ret);
return -1;
}
printf("Device image loaded.\n");
uint64_t available_sensor_mask; /* To keep track of available sensors*/
unsigned i;
/* Check sensor availibitlity
* if rc value is 0, it means sensor is available,
* if rc value is INV_ERROR or INV_ERROR_BAD_ARG, sensor is NA */
available_sensor_mask = 0;
for (i = 0; i < sizeof(sensor_list) / sizeof(sensor_list[0]); ++i) {
const int rc = inv_device_ping_sensor(device, sensor_list[i].type);
printf("Ping %s %s\n", inv_sensor_2str(sensor_list[i].type), (rc == 0) ? "OK" : "KO");
if (rc == 0) {
available_sensor_mask |= (1ULL << sensor_list[i].type);
}
}
/* Start all available sensors from the sensor list */
for (i = 0; i < sizeof(sensor_list) / sizeof(sensor_list[0]); ++i) {
if (available_sensor_mask & (1ULL << sensor_list[i].type)) {
printf("Starting %s @ %lu us\n", inv_sensor_2str(sensor_list[i].type), sensor_list[i].period_us);
ret = inv_device_set_sensor_period_us(device, sensor_list[i].type, sensor_list[i].period_us);
if (ret != 0) {
printf("Error settings sensor period: %s, %ld us\n", inv_sensor_2str(sensor_list[i].type),
sensor_list[i].period_us);
return -1;
}
ret = inv_device_start_sensor(device, sensor_list[i].type);
if (ret != 0) {
printf("Error starting sensor: %s\n", inv_sensor_2str(sensor_list[i].type));
return -1;
}
}
}
/* Poll device for data */
while (1) {
ret = inv_device_poll(device);
if (ret != 0) {
printf("Could not poll from device: %d\n", ret);
}
}
/* Close the host serif */
if (inv_host_serif_close(&my_serif_instance) != 0) {
printf("Unable to close device.\n");
return -1;
}
return 0;
}
/* High resolution sleep implementation for Icm20948. Used at initilization
* stage. ~100us is sufficient. */
void inv_icm20948_sleep_us(int us)
{
printf("Sleep: %d us\n", us);
msleep(us);
}
/* Time implementation for Icm20948. */
uint64_t inv_icm20948_get_time_us(void)
{
return mtime();
}
int icm20948_open(void)
{
setup_i2c();
return 0;
}
int icm20948_close(void)
{
stop_i2c();
return 0;
}
int icm20948_read(uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
{
uint32_t i = 0;
for (i = 0; i < rlen; i++) {
rbuffer[i] = i2c_read(I2C_ADDRESS, reg);
}
reads++;
byte_reads += rlen;
return 0;
}
int icm20948_write(uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
{
uint32_t i = 0;
for (i = 0; i < wlen; i++) {
i2c_write(I2C_ADDRESS, reg, wbuffer[i]);
}
writes++;
byte_writes += wlen;
return 0;
}
const char * activityName(int act)
{
switch (act) {
case INV_SENSOR_BAC_EVENT_ACT_IN_VEHICLE_BEGIN:
return "BEGIN IN_VEHICLE";
case INV_SENSOR_BAC_EVENT_ACT_WALKING_BEGIN:
return "BEGIN WALKING";
case INV_SENSOR_BAC_EVENT_ACT_RUNNING_BEGIN:
return "BEGIN RUNNING";
case INV_SENSOR_BAC_EVENT_ACT_ON_BICYCLE_BEGIN:
return "BEGIN ON_BICYCLE";
case INV_SENSOR_BAC_EVENT_ACT_TILT_BEGIN:
return "BEGIN TILT";
case INV_SENSOR_BAC_EVENT_ACT_STILL_BEGIN:
return "BEGIN STILL";
case INV_SENSOR_BAC_EVENT_ACT_IN_VEHICLE_END:
return "END IN_VEHICLE";
case INV_SENSOR_BAC_EVENT_ACT_WALKING_END:
return "END WALKING";
case INV_SENSOR_BAC_EVENT_ACT_RUNNING_END:
return "END RUNNING";
case INV_SENSOR_BAC_EVENT_ACT_ON_BICYCLE_END:
return "END ON_BICYCLE";
case INV_SENSOR_BAC_EVENT_ACT_TILT_END:
return "END TILT";
case INV_SENSOR_BAC_EVENT_ACT_STILL_END:
return "END STILL";
default:
return "unknown activity!";
}
}
void icm20948_sensor_event_cb(const inv_sensor_event_t * event, void * arg)
{
/* arg will contained the value provided at init time */
(void)arg;
if (event->status == INV_SENSOR_STATUS_DATA_UPDATED) {
switch (INV_SENSOR_ID_TO_TYPE(event->sensor)) {
case INV_SENSOR_TYPE_RAW_ACCELEROMETER:
case INV_SENSOR_TYPE_RAW_GYROSCOPE:
printf("data event %s (lsb): %llu %d %d %d", inv_sensor_str(event->sensor),
(unsigned long long)event->timestamp, (int)event->data.raw3d.vect[0],
(int)event->data.raw3d.vect[1], (int)event->data.raw3d.vect[2]);
break;
case INV_SENSOR_TYPE_ACCELEROMETER:
case INV_SENSOR_TYPE_LINEAR_ACCELERATION:
case INV_SENSOR_TYPE_GRAVITY:
printf("data event %s (mg): %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.acc.vect[0] * 1000), (int)(event->data.acc.vect[1] * 1000),
(int)(event->data.acc.vect[2] * 1000));
break;
case INV_SENSOR_TYPE_GYROSCOPE:
printf("data event %s (mdps): %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.gyr.vect[0] * 1000), (int)(event->data.gyr.vect[1] * 1000),
(int)(event->data.gyr.vect[2] * 1000));
break;
case INV_SENSOR_TYPE_MAGNETOMETER:
printf("data event %s (nT): %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.mag.vect[0] * 1000), (int)(event->data.mag.vect[1] * 1000),
(int)(event->data.mag.vect[2] * 1000));
break;
case INV_SENSOR_TYPE_UNCAL_GYROSCOPE:
printf("data event %s (mdps): %d %d %d %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.gyr.vect[0] * 1000), (int)(event->data.gyr.vect[1] * 1000),
(int)(event->data.gyr.vect[2] * 1000), (int)(event->data.gyr.bias[0] * 1000),
(int)(event->data.gyr.bias[1] * 1000), (int)(event->data.gyr.bias[2] * 1000));
break;
case INV_SENSOR_TYPE_UNCAL_MAGNETOMETER:
printf("data event %s (nT): %d %d %d %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.mag.vect[0] * 1000), (int)(event->data.mag.vect[1] * 1000),
(int)(event->data.mag.vect[2] * 1000), (int)(event->data.mag.bias[0] * 1000),
(int)(event->data.mag.bias[1] * 1000), (int)(event->data.mag.bias[2] * 1000));
break;
case INV_SENSOR_TYPE_GAME_ROTATION_VECTOR:
case INV_SENSOR_TYPE_ROTATION_VECTOR:
case INV_SENSOR_TYPE_GEOMAG_ROTATION_VECTOR:
printf("data event %s (e-3): %d %d %d %d ", inv_sensor_str(event->sensor),
(int)(event->data.quaternion.quat[0] * 1000), (int)(event->data.quaternion.quat[1] * 1000),
(int)(event->data.quaternion.quat[2] * 1000), (int)(event->data.quaternion.quat[3] * 1000));
break;
case INV_SENSOR_TYPE_ORIENTATION:
printf("data event %s (e-3): %d %d %d", inv_sensor_str(event->sensor),
(int)(event->data.orientation.x * 1000), (int)(event->data.orientation.y * 1000),
(int)(event->data.orientation.z * 1000));
break;
case INV_SENSOR_TYPE_BAC:
printf("data event %s : %d %s", inv_sensor_str(event->sensor), event->data.bac.event,
activityName(event->data.bac.event));
break;
case INV_SENSOR_TYPE_STEP_COUNTER:
printf("data event %s : %lu", inv_sensor_str(event->sensor), (unsigned long)event->data.step.count);
break;
case INV_SENSOR_TYPE_PICK_UP_GESTURE:
case INV_SENSOR_TYPE_STEP_DETECTOR:
case INV_SENSOR_TYPE_SMD:
case INV_SENSOR_TYPE_B2S:
case INV_SENSOR_TYPE_TILT_DETECTOR:
default:
printf("data event %s : ...", inv_sensor_str(event->sensor));
break;
}
}
}