Skip to content

Commit 9e2b603

Browse files
committed
Adding setGyroSF
1 parent 46ce7b8 commit 9e2b603

File tree

6 files changed

+142
-18
lines changed

6 files changed

+142
-18
lines changed

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ writeDMPmems KEYWORD2
9494
readDMPmems KEYWORD2
9595
setDMPODRrate KEYWORD2
9696
readDMPdataFromFIFO KEYWORD2
97+
setGyroSF KEYWORD2
9798
begin KEYWORD2
9899

99100
#######################################
@@ -164,6 +165,7 @@ INV_ICM20948_SENSOR_GRAVITY LITERAL1
164165
INV_ICM20948_SENSOR_LINEAR_ACCELERATION LITERAL1
165166
INV_ICM20948_SENSOR_ORIENTATION LITERAL1
166167
INV_ICM20948_SENSOR_B2S LITERAL1
168+
INV_ICM20948_SENSOR_RAW_MAGNETOMETER LITERAL1
167169
DMP_header_bitmap_Header2 LITERAL1
168170
DMP_header_bitmap_Step_Detector LITERAL1
169171
DMP_header_bitmap_Compass_Calibr LITERAL1

src/ICM_20948.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,15 @@ ICM_20948_Status_e ICM_20948::enableDMPSensor(enum inv_icm20948_sensor sensor, b
10261026
if (_device._dmp_firmware_available == true) // Should we attempt to enable the sensor?
10271027
{
10281028
status = inv_icm20948_enable_dmp_sensor(&_device, sensor, enable == true ? 1 : 0);
1029+
debugPrint(F("ICM_20948::enableDMPSensor: _DATA_OUT_CTL1: "));
1030+
debugPrintf((int)_device._DATA_OUT_CTL1);
1031+
debugPrint(F(" _DATA_OUT_CTL2: "));
1032+
debugPrintf((int)_device._DATA_OUT_CTL2);
1033+
debugPrint(F(" _DATA_RDY_STATUS: "));
1034+
debugPrintf((int)_device._DATA_RDY_STATUS);
1035+
debugPrint(F(" _MOTION_EVENT_CTL: "));
1036+
debugPrintf((int)_device._MOTION_EVENT_CTL);
1037+
debugPrintln(F(""));
10291038
return status;
10301039
}
10311040
return ICM_20948_Stat_DMPNotSupported;
@@ -1061,7 +1070,7 @@ ICM_20948_Status_e ICM_20948::readDMPmems(unsigned short reg, unsigned int lengt
10611070
return ICM_20948_Stat_DMPNotSupported;
10621071
}
10631072

1064-
ICM_20948_Status_e ICM_20948::setDMPODRrate(enum DMP_ODR_Registers odr_reg, int rate)
1073+
ICM_20948_Status_e ICM_20948::setDMPODRrate(enum DMP_ODR_Registers odr_reg, int interval)
10651074
{
10661075
if (_device._dmp_firmware_available == true) // Should we attempt to set the DMP ODR?
10671076
{
@@ -1070,11 +1079,6 @@ ICM_20948_Status_e ICM_20948::setDMPODRrate(enum DMP_ODR_Registers odr_reg, int
10701079
// Value = (DMP running rate (225Hz) / ODR ) - 1
10711080
// E.g. For a 25Hz ODR rate, value= (225/25) - 1 = 8.
10721081

1073-
if (rate <= 0) // Check rate is valid
1074-
rate = 1;
1075-
if (rate > 225)
1076-
rate = 225;
1077-
uint16_t interval = (225 / rate) - 1;
10781082
status = inv_icm20948_set_dmp_sensor_period(&_device, odr_reg, interval);
10791083
return status;
10801084
}
@@ -1091,6 +1095,21 @@ ICM_20948_Status_e ICM_20948::readDMPdataFromFIFO(icm_20948_DMP_data_t *data)
10911095
return ICM_20948_Stat_DMPNotSupported;
10921096
}
10931097

1098+
ICM_20948_Status_e ICM_20948::setGyroSF(unsigned char div, int gyro_level)
1099+
{
1100+
if (_device._dmp_firmware_available == true) // Should we attempt to set the Gyro SF?
1101+
{
1102+
status = inv_icm20948_set_gyro_sf(&_device, div, gyro_level);
1103+
debugPrint(F("ICM_20948::setGyroSF: pll: "));
1104+
debugPrintf((int)_device._gyroSFpll);
1105+
debugPrint(F(" Gyro SF is: "));
1106+
debugPrintf((int)_device._gyroSF);
1107+
debugPrintln(F(""));
1108+
return status;
1109+
}
1110+
return ICM_20948_Stat_DMPNotSupported;
1111+
}
1112+
10941113
// I2C
10951114
ICM_20948_I2C::ICM_20948_I2C()
10961115
{
@@ -1140,6 +1159,12 @@ ICM_20948_Status_e ICM_20948_I2C::begin(TwoWire &wirePort, bool ad0val, uint8_t
11401159
_device._firmware_loaded = false; // Initialize _firmware_loaded
11411160
_device._last_bank = 255; // Initialize _last_bank. Make it invalid. It will be set by the first call of ICM_20948_set_bank.
11421161
_device._last_mems_bank = 255; // Initialize _last_mems_bank. Make it invalid. It will be set by the first call of inv_icm20948_write_mems.
1162+
_device._gyroSF = 0; // Use this to record the GyroSF, calculated by inv_icm20948_set_gyro_sf
1163+
_device._gyroSFpll = 0;
1164+
_device._DATA_OUT_CTL1 = 0; // Keep a record of what sensors are enabled
1165+
_device._DATA_OUT_CTL2 = 0; // Keep a record of what header2 items are enabled
1166+
_device._DATA_RDY_STATUS = 0; // Keep a record of how Data Ready Status is configured
1167+
_device._MOTION_EVENT_CTL = 0; // Keep a record of how Motion Event Ctrl is configured
11431168

11441169
// Perform default startup
11451170
// Do a minimal startupDefault if using the DMP. User can always call startupDefault(false) manually if required.
@@ -1321,6 +1346,12 @@ ICM_20948_Status_e ICM_20948_SPI::begin(uint8_t csPin, SPIClass &spiPort, uint32
13211346
_device._firmware_loaded = false; // Initialize _firmware_loaded
13221347
_device._last_bank = 255; // Initialize _last_bank. Make it invalid. It will be set by the first call of ICM_20948_set_bank.
13231348
_device._last_mems_bank = 255; // Initialize _last_mems_bank. Make it invalid. It will be set by the first call of inv_icm20948_write_mems.
1349+
_device._gyroSF = 0; // Use this to record the GyroSF, calculated by inv_icm20948_set_gyro_sf
1350+
_device._gyroSFpll = 0;
1351+
_device._DATA_OUT_CTL1 = 0; // Keep a record of what sensors are enabled
1352+
_device._DATA_OUT_CTL2 = 0; // Keep a record of what header2 items are enabled
1353+
_device._DATA_RDY_STATUS = 0; // Keep a record of how Data Ready Status is configured
1354+
_device._MOTION_EVENT_CTL = 0; // Keep a record of how Motion Event Ctrl is configured
13241355

13251356
// Perform default startup
13261357
// Do a minimal startupDefault if using the DMP. User can always call startupDefault(false) manually if required.

src/ICM_20948.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,9 @@ class ICM_20948
206206
ICM_20948_Status_e enableDMPSensorInt(enum inv_icm20948_sensor sensor, bool enable = true);
207207
ICM_20948_Status_e writeDMPmems(unsigned short reg, unsigned int length, const unsigned char *data);
208208
ICM_20948_Status_e readDMPmems(unsigned short reg, unsigned int length, unsigned char *data);
209-
ICM_20948_Status_e setDMPODRrate(enum DMP_ODR_Registers odr_reg, int rate);
209+
ICM_20948_Status_e setDMPODRrate(enum DMP_ODR_Registers odr_reg, int interval);
210210
ICM_20948_Status_e readDMPdataFromFIFO(icm_20948_DMP_data_t *data);
211+
ICM_20948_Status_e setGyroSF(unsigned char div, int gyro_level);
211212

212213
};
213214

src/util/ICM_20948_C.c

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ ICM_20948_Status_e inv_icm20948_write_mems(ICM_20948_Device_t *pdev, unsigned sh
13001300
ICM_20948_Status_e inv_icm20948_read_mems(ICM_20948_Device_t *pdev, unsigned short reg, unsigned int length, unsigned char *data)
13011301
{
13021302
ICM_20948_Status_e result = ICM_20948_Stat_Ok;
1303-
unsigned int bytesWritten = 0;
1303+
unsigned int bytesRead = 0;
13041304
unsigned int thisLen;
13051305
unsigned char lBankSelected;
13061306
unsigned char lStartAddrSelected;
@@ -1318,13 +1318,17 @@ ICM_20948_Status_e inv_icm20948_read_mems(ICM_20948_Device_t *pdev, unsigned sho
13181318

13191319
lBankSelected = (reg >> 8);
13201320

1321-
result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_BANK_SEL, &lBankSelected, 1);
1322-
if (result != ICM_20948_Stat_Ok)
1321+
if (lBankSelected != pdev->_last_mems_bank)
13231322
{
1324-
return result;
1323+
pdev->_last_mems_bank = lBankSelected;
1324+
result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_BANK_SEL, &lBankSelected, 1);
1325+
if (result != ICM_20948_Stat_Ok)
1326+
{
1327+
return result;
1328+
}
13251329
}
13261330

1327-
while (bytesWritten < length)
1331+
while (bytesRead < length)
13281332
{
13291333
lStartAddrSelected = (reg & 0xff);
13301334

@@ -1339,20 +1343,20 @@ ICM_20948_Status_e inv_icm20948_read_mems(ICM_20948_Device_t *pdev, unsigned sho
13391343
return result;
13401344
}
13411345

1342-
if (length-bytesWritten <= INV_MAX_SERIAL_READ)
1343-
thisLen = length-bytesWritten;
1346+
if (length-bytesRead <= INV_MAX_SERIAL_READ)
1347+
thisLen = length-bytesRead;
13441348
else
13451349
thisLen = INV_MAX_SERIAL_READ;
13461350

13471351
/* Read data */
13481352

1349-
result = ICM_20948_execute_r(pdev, AGB0_REG_MEM_R_W, &data[bytesWritten], thisLen);
1353+
result = ICM_20948_execute_r(pdev, AGB0_REG_MEM_R_W, &data[bytesRead], thisLen);
13501354
if (result != ICM_20948_Stat_Ok)
13511355
{
13521356
return result;
13531357
}
13541358

1355-
bytesWritten += thisLen;
1359+
bytesRead += thisLen;
13561360
reg += thisLen;
13571361
}
13581362

@@ -1361,7 +1365,7 @@ ICM_20948_Status_e inv_icm20948_read_mems(ICM_20948_Device_t *pdev, unsigned sho
13611365

13621366
ICM_20948_Status_e inv_icm20948_set_dmp_sensor_period(ICM_20948_Device_t *pdev, enum DMP_ODR_Registers odr_reg, uint16_t interval)
13631367
{
1364-
// Set the ODR registersand clear the ODR counter
1368+
// Set the ODR registers and clear the ODR counter
13651369

13661370
// In order to set an ODR for a given sensor data, write 2-byte value to DMP using key defined above for a particular sensor.
13671371
// Setting value can be calculated as follows:
@@ -1529,6 +1533,10 @@ ICM_20948_Status_e inv_icm20948_enable_dmp_sensor(ICM_20948_Device_t *pdev, enum
15291533
}
15301534
// TO DO: Add DMP_Data_Output_Control_2_Pickup etc. if required
15311535

1536+
// Keep a record of DATA_OUT_CTL1 so multiple sensors can be configured
1537+
delta |= pdev->_DATA_OUT_CTL1;
1538+
pdev->_DATA_OUT_CTL1 = delta;
1539+
15321540
// Write the sensor control bits into memory address DATA_OUT_CTL1
15331541
unsigned char data_output_control_reg[2];
15341542
data_output_control_reg[0] = (unsigned char)(delta >> 8);
@@ -1539,6 +1547,10 @@ ICM_20948_Status_e inv_icm20948_enable_dmp_sensor(ICM_20948_Device_t *pdev, enum
15391547
return result;
15401548
}
15411549

1550+
// Keep a record of DATA_OUT_CTL2 so multiple sensors can be configured
1551+
delta2 |= pdev->_DATA_OUT_CTL2;
1552+
pdev->_DATA_OUT_CTL2 = delta2;
1553+
15421554
// Write the 'header2' sensor control bits into memory address DATA_OUT_CTL2
15431555
data_output_control_reg[0] = (unsigned char)(delta2 >> 8);
15441556
data_output_control_reg[1] = (unsigned char)(delta2 & 0xff);
@@ -1589,6 +1601,11 @@ ICM_20948_Status_e inv_icm20948_enable_dmp_sensor(ICM_20948_Device_t *pdev, enum
15891601
inv_event_control |= DMP_Motion_Event_Control_Compass_Calibr;
15901602
}
15911603
}
1604+
1605+
// Keep a record of _DATA_RDY_STATUS so multiple sensors can be configured
1606+
data_rdy_status |= pdev->_DATA_RDY_STATUS;
1607+
pdev->_DATA_RDY_STATUS = data_rdy_status;
1608+
15921609
data_output_control_reg[0] = (unsigned char)(data_rdy_status >> 8);
15931610
data_output_control_reg[1] = (unsigned char)(data_rdy_status & 0xff);
15941611
result = inv_icm20948_write_mems(pdev, DATA_RDY_STATUS, 2, (const unsigned char *)&data_output_control_reg);
@@ -1611,6 +1628,11 @@ ICM_20948_Status_e inv_icm20948_enable_dmp_sensor(ICM_20948_Device_t *pdev, enum
16111628
{
16121629
inv_event_control |= DMP_Motion_Event_Control_Geomag;
16131630
}
1631+
1632+
// Keep a record of _MOTION_EVENT_CTL so multiple sensors can be configured
1633+
inv_event_control |= pdev->_MOTION_EVENT_CTL;
1634+
pdev->_MOTION_EVENT_CTL = inv_event_control;
1635+
16141636
data_output_control_reg[0] = (unsigned char)(inv_event_control >> 8);
16151637
data_output_control_reg[1] = (unsigned char)(inv_event_control & 0xff);
16161638
result = inv_icm20948_write_mems(pdev, MOTION_EVENT_CTL, 2, (const unsigned char *)&data_output_control_reg);
@@ -2171,6 +2193,7 @@ static uint8_t sensor_type_2_android_sensor(enum inv_icm20948_sensor sensor)
21712193
case INV_ICM20948_SENSOR_LINEAR_ACCELERATION: return ANDROID_SENSOR_LINEAR_ACCELERATION; // 10
21722194
case INV_ICM20948_SENSOR_ORIENTATION: return ANDROID_SENSOR_ORIENTATION; // 3
21732195
case INV_ICM20948_SENSOR_B2S: return ANDROID_SENSOR_B2S; // 45
2196+
case INV_ICM20948_SENSOR_RAW_MAGNETOMETER: return ANDROID_SENSOR_WAKEUP_MAGNETIC_FIELD_UNCALIBRATED; // 34
21742197
default: return ANDROID_SENSOR_NUM_MAX;
21752198
}
21762199
}
@@ -2198,6 +2221,65 @@ enum inv_icm20948_sensor inv_icm20948_sensor_android_2_sensor_type(int sensor)
21982221
case ANDROID_SENSOR_LINEAR_ACCELERATION: return INV_ICM20948_SENSOR_LINEAR_ACCELERATION;
21992222
case ANDROID_SENSOR_ORIENTATION: return INV_ICM20948_SENSOR_ORIENTATION;
22002223
case ANDROID_SENSOR_B2S: return INV_ICM20948_SENSOR_B2S;
2224+
case ANDROID_SENSOR_WAKEUP_MAGNETIC_FIELD_UNCALIBRATED: return INV_ICM20948_SENSOR_RAW_MAGNETOMETER;
22012225
default: return INV_ICM20948_SENSOR_MAX;
22022226
}
22032227
}
2228+
2229+
ICM_20948_Status_e inv_icm20948_set_gyro_sf(ICM_20948_Device_t *pdev, unsigned char div, int gyro_level)
2230+
{
2231+
ICM_20948_Status_e result = ICM_20948_Stat_Ok;
2232+
2233+
if (pdev->_dmp_firmware_available == false)
2234+
return ICM_20948_Stat_DMPNotSupported;
2235+
2236+
// gyro_level should be set to 4 regardless of fullscale, due to the addition of API dmp_icm20648_set_gyro_fsr()
2237+
gyro_level = 4;
2238+
2239+
// First read the TIMEBASE_CORRECTION_PLL register from Bank 1
2240+
int8_t pll; // Signed. Typical value is 0x18
2241+
result = ICM_20948_set_bank(pdev, 1);
2242+
result = ICM_20948_execute_r(pdev, AGB1_REG_TIMEBASE_CORRECTION_PLL, (uint8_t *)&pll, 1);
2243+
if (result != ICM_20948_Stat_Ok)
2244+
{
2245+
return result;
2246+
}
2247+
2248+
pdev->_gyroSFpll = pll; // Record the PLL value so we can debug print it
2249+
2250+
// Now calculate the Gyro SF using code taken from the InvenSense example (inv_icm20948_set_gyro_sf)
2251+
2252+
long gyro_sf;
2253+
2254+
unsigned long long const MagicConstant = 264446880937391LL;
2255+
unsigned long long const MagicConstantScale = 100000LL;
2256+
unsigned long long ResultLL;
2257+
2258+
if (pll & 0x80) {
2259+
ResultLL = (MagicConstant * (long long)(1ULL << gyro_level) * (1 + div) / (1270 - (pll & 0x7F)) / MagicConstantScale);
2260+
}
2261+
else {
2262+
ResultLL = (MagicConstant * (long long)(1ULL << gyro_level) * (1 + div) / (1270 + pll) / MagicConstantScale);
2263+
}
2264+
/*
2265+
In above deprecated FP version, worst case arguments can produce a result that overflows a signed long.
2266+
Here, for such cases, we emulate the FP behavior of setting the result to the maximum positive value, as
2267+
the compiler's conversion of a u64 to an s32 is simple truncation of the u64's high half, sadly....
2268+
*/
2269+
if (ResultLL > 0x7FFFFFFF)
2270+
gyro_sf = 0x7FFFFFFF;
2271+
else
2272+
gyro_sf = (long)ResultLL;
2273+
2274+
pdev->_gyroSF = gyro_sf; // Record value so we can debug print it
2275+
2276+
// Finally, write the value to the DMP GYRO_SF register
2277+
unsigned char gyro_sf_reg[4];
2278+
gyro_sf_reg[0] = (unsigned char)(gyro_sf >> 24);
2279+
gyro_sf_reg[1] = (unsigned char)(gyro_sf >> 16);
2280+
gyro_sf_reg[2] = (unsigned char)(gyro_sf >> 8);
2281+
gyro_sf_reg[3] = (unsigned char)(gyro_sf & 0xff);
2282+
result = inv_icm20948_write_mems(pdev, GYRO_SF, 4, (const unsigned char *)&gyro_sf_reg);
2283+
2284+
return result;
2285+
}

src/util/ICM_20948_C.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ extern int memcmp(const void *, const void *, size_t); // Avoid compiler warning
161161
bool _firmware_loaded; // Indicates if DMP has been loaded
162162
uint8_t _last_bank; // Keep track of which bank was selected last - to avoid unnecessary writes
163163
uint8_t _last_mems_bank; // Keep track of which bank was selected last - to avoid unnecessary writes
164+
int32_t _gyroSF; // Use this to record the GyroSF, calculated by inv_icm20948_set_gyro_sf
165+
int8_t _gyroSFpll;
166+
uint16_t _DATA_OUT_CTL1; // Keep a record of what sensors are enabled
167+
uint16_t _DATA_OUT_CTL2; // Keep a record of what header2 items are enabled
168+
uint16_t _DATA_RDY_STATUS; // Keep a record of how Data Ready Status is configured
169+
uint16_t _MOTION_EVENT_CTL; // Keep a record of how Motion Event Ctrl is configured
164170
} ICM_20948_Device_t; // Definition of device struct type
165171

166172
/*
@@ -268,6 +274,7 @@ extern int memcmp(const void *, const void *, size_t); // Avoid compiler warning
268274
enum inv_icm20948_sensor inv_icm20948_sensor_android_2_sensor_type(int sensor);
269275

270276
ICM_20948_Status_e inv_icm20948_read_dmp_data(ICM_20948_Device_t *pdev, icm_20948_DMP_data_t *data);
277+
ICM_20948_Status_e inv_icm20948_set_gyro_sf(ICM_20948_Device_t *pdev, unsigned char div, int gyro_level);
271278

272279
// ToDo:
273280

src/util/ICM_20948_DMP.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ extern "C" {
116116
#define ACCEL_ACCURACY (97 * 16)
117117
#define ACCEL_CAL_RESET (77 * 16)
118118
#define ACCEL_VARIANCE_THRESH (93 * 16)
119-
#define ACCEL_CAL_RATE (94 * 16 + 4) // 16-bit
119+
#define ACCEL_CAL_RATE (94 * 16 + 4) // 16-bit: 0 (225Hz, 112Hz, 56Hz)
120120
#define ACCEL_PRE_SENSOR_DATA (97 * 16 + 4)
121121
#define ACCEL_COVARIANCE (101 * 16 + 8)
122122
#define ACCEL_ALPHA_VAR (91 * 16) // 32-bit: 1026019965 (225Hz) 977872018 (112Hz) 882002213 (56Hz)
@@ -327,6 +327,7 @@ enum inv_icm20948_sensor {
327327
INV_ICM20948_SENSOR_LINEAR_ACCELERATION,
328328
INV_ICM20948_SENSOR_ORIENTATION,
329329
INV_ICM20948_SENSOR_B2S,
330+
INV_ICM20948_SENSOR_RAW_MAGNETOMETER,
330331
INV_ICM20948_SENSOR_MAX,
331332
};
332333

0 commit comments

Comments
 (0)