{"id":12456,"date":"2021-08-27T19:08:31","date_gmt":"2021-08-27T19:08:31","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/icm-20948-9-axis-sensor-part-ii"},"modified":"2025-01-15T20:34:22","modified_gmt":"2025-01-15T20:34:22","slug":"icm-20948-9-axis-sensor-part-ii","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii","title":{"rendered":"ICM-20948 9-Axis Sensor Part II"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">About this post<\/h2>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg\" alt=\"\" class=\"wp-image-12064\" style=\"width:157px;height:256px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg 626w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-183x300.jpg 183w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-768x1256.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-939x1536.jpg 939w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small.jpg 1000w\" sizes=\"auto, (max-width: 626px) 100vw, 626px\" \/><\/a><\/figure>\n<\/div>\n<p>This is the continuation of the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i\" target=\"_blank\" rel=\"noopener\">first part<\/a> of my post about the 9-axis sensor ICM-20948. In the first part, I first discussed the technical characteristics. Then I started to introduce my library ICM20948_WE. You can download it <a href=\"https:\/\/github.com\/wollewald\/ICM20948_WE\" target=\"_blank\" rel=\"noopener\">here<\/a> from GitHub or install it via the library manager of the Arduino IDE.<\/p>\r\n\r\n<p>I had shown you how to retrieve data from the accelerometer, gyroscope, magnetometer and thermometer and how to use the calibration functions. In addition, I have introduced functions for measuring tilt angles.<\/p>\r\n\r\n<p>This part deals with the following topics:<\/p>\r\n<ul>\r\n \t<li>Cycle mode<\/li>\r\n \t<li>Interrupts<\/li>\r\n \t<li>FIFO buffer<\/li>\r\n<\/ul>\r\n<p>As in the first part, I present the functions of my library using example sketches.<\/p>\n\n<h2 class=\"wp-block-heading\">ICM20948_08_cycle.ino<\/h2>\n\n<p>In cycle mode, the sensors sleep between measurements. This saves you valuable energy in battery-powered projects. For the following example sketch I have measured a power consumption of 2.3 mA. With the cycle mode deactivated, the current consumption was 4.4 mA.<\/p>\r\n<p>You activate the cycle mode with <code>enableCycle(parameter)<\/code>. The parameter (see sketch) defines which sensors should go into cycle mode.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_08_cycle.ino \" data-enlighter-title=\"ICM20948_08_cycle.ino \">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n\r\n  if (!myIMU.initMagnetometer()) {\r\n    Serial.println(\"Magnetometer does not respond\");\r\n  }\r\n  else {\r\n    Serial.println(\"Magnetometer is connected\");\r\n  }\r\n\r\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \r\n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \r\n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\r\n   *  The parameters are floats. \r\n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point is \r\n   *  set as (min + max)\/2.\r\n   *\/\r\n\/\/  myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16640.0, 16560.0);\r\n    \r\n  \/*  The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \r\n   *  The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \r\n   *  x,y-plane. The more you deviate from this, the less accurate will be your results.\r\n   *  It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\r\n   *  The function also measures the offset of the gyroscope data. The gyroscope offset does not   \r\n   *  depend on the positioning.\r\n   *  This function needs to be called after setAccOffsets but before other settings since it will \r\n   *  overwrite settings!\r\n   *  You can query the offsets with the functions:\r\n   *  xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\r\n   *  You can apply the offsets using:\r\n   *  setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\r\n   *\/\r\n\/\/  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\r\n\/\/  delay(1000);\r\n\/\/  myIMU.autoOffsets();\r\n\/\/  Serial.println(\"Done!\"); \r\n  \r\n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \r\n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\r\n   *  using the +\/- 250 degrees\/s range. \r\n   *  Use either autoOffset or setGyrOffsets, not both.\r\n   *\/\r\n\/\/  myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\r\n  \r\n  \r\n  \/* enables or disables the acceleration sensor, default: enabled *\/\r\n  \/\/myIMU.enableAcc(false);\r\n\r\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\r\n   *  ICM20948_ACC_RANGE_4G      4 g\r\n   *  ICM20948_ACC_RANGE_8G      8 g   \r\n   *  ICM20948_ACC_RANGE_16G    16 g\r\n   *\/\r\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF\r\n   *  \r\n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              246.0               1125\/(1+ASRD) \r\n   *    1              246.0               1125\/(1+ASRD)\r\n   *    2              111.4               1125\/(1+ASRD)\r\n   *    3               50.4               1125\/(1+ASRD)\r\n   *    4               23.9               1125\/(1+ASRD)\r\n   *    5               11.5               1125\/(1+ASRD)\r\n   *    6                5.7               1125\/(1+ASRD) \r\n   *    7              473.0               1125\/(1+ASRD)\r\n   *    OFF           1209.0               4500\r\n   *    \r\n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setAccDLPF(ICM20948_DLPF_7);    \r\n  \r\n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not off!\r\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setAccSampleRateDivider(2048);\r\n  \r\n  \/* enables or disables the gyroscope sensor, default: enabled *\/\r\n  \/\/myIMU.enableGyr(false);\r\n\r\n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\r\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\r\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\r\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\r\n   *\/\r\n \/\/ myIMU.setGyrRange(ICM20948_GYRO_RANGE_250);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              196.6               1125\/(1+GSRD) \r\n   *    1              151.8               1125\/(1+GSRD)\r\n   *    2              119.5               1125\/(1+GSRD)\r\n   *    3               51.2               1125\/(1+GSRD)\r\n   *    4               23.9               1125\/(1+GSRD)\r\n   *    5               11.6               1125\/(1+GSRD)\r\n   *    6                5.7               1125\/(1+GSRD) \r\n   *    7              361.4               1125\/(1+GSRD)\r\n   *    OFF          12106.0               9000\r\n   *    \r\n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setGyrDLPF(ICM20948_DLPF_6);  \r\n  \r\n  \/*  Gyroscope sample rate divider divides the output rate of the gyroscope.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not OFF!\r\n   *  Divider is a number 0...255\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setGyrSampleRateDivider(255);\r\n\r\n  \/* In cycle mode the sensors wake up in the frequency of sample rate. You can define \r\n   * which sensors shall work in cycle mode. \r\n   * \r\n   *  ICM20948_NO_CYCLE          \r\n   *  ICM20948_GYR_CYCLE           \r\n   *  ICM20948_ACC_CYCLE           \r\n   *  ICM20948_ACC_GYR_CYCLE       \r\n   *  ICM20948_ACC_GYR_I2C_MST_CYCLE \r\n   *\/\r\n  myIMU.enableCycle(ICM20948_ACC_GYR_I2C_MST_CYCLE);\r\n  \r\n  \/* The Low Power Mode does not work if DLPF is enabled *\/\r\n  \/\/myIMU.enableLowPower(true);\r\n    \r\n  \/* In cycle mode you need to set the number of measured values for the gyroscope \r\n   * to be averaged. You can select 1,2,4,8,16,32,64 or 128: \r\n   * ICM20948_GYR_AVG_1, ICM20948_GYR_AVG_2, ..... , ICM20948_GYR_AVG_128 \r\n   * The on-time for measurements increases with the number of samples to be averaged:\r\n   * 1 -&gt; 1.15 ms, 2 -&gt; 1.59 ms, .... , 128 -&gt; 57.59 ms (see data sheet)\r\n   *\/\r\n  myIMU.setGyrAverageInCycleMode(ICM20948_GYR_AVG_1);\r\n\r\n  \/* In cycle mode you need to set the number of measured values for the accelerometer \r\n   * to be averaged. You can select 4,8,16,32: \r\n   * ICM20948_ACC_AVG_4, ICM20948_ACC_AVG_8, ICM20948_ACC_AVG_16, ICM20948_ACC_AVG_32 \r\n   * The on-time for measurements increases with the number of samples to be averaged:\r\n   * 4 -&gt; 1.488 ms, 8 -&gt; 2.377 ms, 16 -&gt; 4.154 ms , 32 -&gt; 7.71 ms (see data sheet)\r\n   * If DLPF is OFF, then with ICM20948_ACC_AVG_4 only one sample is taken!\r\n   *\/\r\n  myIMU.setAccAverageInCycleMode(ICM20948_ACC_AVG_4);\r\n\r\n  \/* setI2CMstSampleRate sets the rate of the devices controlled by the I2C master,\r\n   * i.e. the magnetometer. It is not the internal sample rate of the magnetometer, but\r\n   * the output rate of the I2C master. Allowed values are x = 0...15. The sample rate is\r\n   * 1.1 kHz \/ (2^x). Example: x = 13 =&gt; Sample rate = 1.1 kHz \/ 8192 = ~0.1343 Hz, \r\n   * or: data output every ~7.45 seconds.\r\n   *\/\r\n  myIMU.setI2CMstSampleRate(13); \r\n}\r\n\r\nvoid loop() {\r\n  xyzFloat gValue; \r\n  xyzFloat gyrValue; \r\n  xyzFloat magValue; \r\n  myIMU.readSensor();\r\n  myIMU.getGValues(&amp;gValue);\r\n  myIMU.getGyrValues(&amp;gyrValue);\r\n  myIMU.getMagValues(&amp;magValue); \r\n      \r\n  Serial.println(\"g-values (x,y,z):\");\r\n  Serial.print(gValue.x);\r\n  Serial.print(\"   \");\r\n  Serial.print(gValue.y);\r\n  Serial.print(\"   \");\r\n  Serial.println(gValue.z);\r\n\r\n  Serial.println(\"Gyroscope (x,y,z):\");\r\n  Serial.print(gyrValue.x);\r\n  Serial.print(\"   \");\r\n  Serial.print(gyrValue.y);\r\n  Serial.print(\"   \");\r\n  Serial.println(gyrValue.z);\r\n\r\n  Serial.println(\"Magnetometer Data in \u00b5Tesla: \");\r\n  Serial.print(magValue.x);\r\n  Serial.print(\"   \");\r\n  Serial.print(magValue.y);\r\n  Serial.print(\"   \");\r\n  Serial.println(magValue.z);\r\n\r\n  Serial.println();\r\n\r\n  delay(500);\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\r\n\n<p><code>setAccAverageInCycleMode()<\/code> and <code>setGyrAverageInCycleMode()<\/code> determine the number of individual measurements from which the result is averaged. However, you have to keep in mind that too many individual measurements dilute the energy-saving effect.<\/p>\r\n<p>There are still a few points to consider:<\/p>\r\n<ul>\r\n<li>When DLPF is activated, the accelerometer measures incorrect values in cycle mode.<\/li>\r\n<li>According to the data sheet, the sample rate divider of the accelerometer should not work when DLPF is switched off &#8211; but it does!<\/li>\r\n<li>In addition to the cycle mode, you can (de-)activate a low-power mode using <code>enableLowPower(true\/false)<\/code>. This resulted in a further 0.2 mA savings in the sketch above. The function only has an effect when the cycle mode is active. I did not find out what the energy-saving mode does exactly, except save power.<\/li>\r\n<li><code>setI2CSampleMasterRate(x)<\/code> determines the frequency with which the measured values of the sensors addressed via the I2C auxiliary interface are queried. The frequency is 1100\/2<sup>x<\/sup> kHz (0.134 Hz in the example sketch). This function also saves you power.<br>\r\n<ul>\r\n<li>In my library, it is only relevant for the magnetometer.<\/li>\r\n<\/ul>\r\n<\/li>\r\n<\/ul>\r\n\n<h2 class=\"wp-block-heading\">Using interrupts of the ICM-20948<\/h2>\n\n<p>I have implemented the following interrupts of the ICM-20948:<\/p>\r\n<ul>\r\n<li><strong>Data ready<\/strong>: triggers when new readings are available.<\/li>\r\n<li><strong>Wake-on-motion<\/strong> (&#8220;WOM&#8221;): triggers when an acceleration value set by you is exceeded.<\/li>\r\n<li><strong>FIFO Overflow<\/strong>: triggers when the FIFO buffer is full (512 bytes \/ 4096 bytes).<\/li>\r\n<li><strong>FSYNC<\/strong>: if activated, you choose if it triggers when a HIGH or a LOW level is detected at FSYNC.<\/li>\r\n<\/ul>\r\n\n<h3 class=\"wp-block-heading\">ICM20948_09_data_ready_interrupt.ino<\/h3>\n\n<p>In the following sketch, the data ready interrupt controls the output frequency of the measured values. I have enabled the accelerometer only. The sample rate divider is set to 4095 and the DLPF level is 1. This results in an output frequency of 1125 \/ 4096 = ~0.27 Hz.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_09_data_ready_interrupt.ino\" data-enlighter-title=\"ICM20948_09_data_ready_interrupt.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nconst int intPin = 2;\r\nvolatile bool dataReady = false;\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n\r\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \r\n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \r\n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\r\n   *  The parameters are floats. \r\n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point is \r\n   *  set as (min + max)\/2.\r\n   *\/\r\n\/\/  myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\r\n    \r\n  \/*  The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \r\n   *  The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \r\n   *  x,y-plane. The more you deviate from this, the less accurate will be your results.\r\n   *  It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\r\n   *  The function also measures the offset of the gyroscope data. The gyroscope offset does not   \r\n   *  depend on the positioning.\r\n   *  This function needs to be called after setAccOffsets but before other settings since it will \r\n   *  overwrite settings!\r\n   *  You can query the offsets with the functions:\r\n   *  xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\r\n   *  You can apply the offsets using:\r\n   *  setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\r\n   *\/\r\n\/\/  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\r\n\/\/  delay(1000);\r\n\/\/  myIMU.autoOffsets();\r\n\/\/  Serial.println(\"Done!\"); \r\n  \r\n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \r\n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\r\n   *  using the +\/- 250 degrees\/s range. \r\n   *  Use either autoOffset or setGyrOffsets, not both.\r\n   *\/\r\n\/\/  myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\r\n  \r\n  \r\n  \/* enables or disables the acceleration sensor, default: enabled *\/\r\n  \/\/myIMU.enableAcc(false);\r\n\r\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\r\n   *  ICM20948_ACC_RANGE_4G      4 g\r\n   *  ICM20948_ACC_RANGE_8G      8 g   \r\n   *  ICM20948_ACC_RANGE_16G    16 g\r\n   *\/\r\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              246.0               1125\/(1+ASRD) \r\n   *    1              246.0               1125\/(1+ASRD)\r\n   *    2              111.4               1125\/(1+ASRD)\r\n   *    3               50.4               1125\/(1+ASRD)\r\n   *    4               23.9               1125\/(1+ASRD)\r\n   *    5               11.5               1125\/(1+ASRD)\r\n   *    6                5.7               1125\/(1+ASRD) \r\n   *    7              473.0               1125\/(1+ASRD)\r\n   *    OFF           1209.0               4500\r\n   *    \r\n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setAccDLPF(ICM20948_DLPF_1);    \r\n  \r\n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not off!\r\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setAccSampleRateDivider(4095);\r\n  \r\n  \/* enables or disables the gyroscope sensor, default: enabled *\/\r\n  myIMU.enableGyr(false);\r\n\r\n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\r\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\r\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\r\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\r\n   *\/\r\n \/\/ myIMU.setGyrRange(ICM20948_GYRO_RANGE_250);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              196.6               1125\/(1+GSRD) \r\n   *    1              151.8               1125\/(1+GSRD)\r\n   *    2              119.5               1125\/(1+GSRD)\r\n   *    3               51.2               1125\/(1+GSRD)\r\n   *    4               23.9               1125\/(1+GSRD)\r\n   *    5               11.6               1125\/(1+GSRD)\r\n   *    6                5.7               1125\/(1+GSRD) \r\n   *    7              361.4               1125\/(1+GSRD)\r\n   *    OFF          12106.0               9000\r\n   *    \r\n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setGyrDLPF(ICM20948_DLPF_1);  \r\n  \r\n  \/*  Gyroscope sample rate divider divides the output rate of the gyroscope.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not OFF!\r\n   *  Divider is a number 0...255\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setGyrSampleRateDivider(255);\r\n\r\n  \/* Set the interrupt pin:\r\n   * ICM20948_ACT_LOW  = active-low\r\n   * ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n   \/*  If latch is enabled the interrupt pin level is held until the interrupt status \r\n   *  is cleared. If latch is disabled the interrupt pulse is ~50\u00b5s (default).\r\n   *\/\r\n   myIMU.enableIntLatch(true);\r\n\r\n  \/* The interrupts ICM20948_FSYNC_INT, ICM20948_WOM_INT and ICM20948_DMP_INT can be \r\n   * cleared by any read or will only be cleared if the interrupt status register is \r\n   * read (default).\r\n   *\/\r\n   \/\/myIMU.enableClearIntByAnyRead(true);\r\n\r\n  \/* Set the FSync interrupt pin:\r\n   *  ICM20948_ACT_LOW  = active-low\r\n   *  ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setFSyncIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n   \/* The following interrupts can be enabled or disabled:\r\n    *  ICM20948_FSYNC_INT        FSYNC pin interrupt, can't propagate to the INT pin  \r\n    *  ICM20948_WOM_INT          Wake on motion\r\n    *  ICM20948_DATA_READY_INT   New data available\r\n    *  ICM20948_FIFO_OVF_INT     FIFO overflow\r\n    *\/\r\n    myIMU.enableInterrupt(ICM20948_DATA_READY_INT);\r\n    \/\/myIMU.disableInterrupt(ICM20948_DATA_READY_INT);\r\n  \r\n  dataReady = false;\r\n  attachInterrupt(digitalPinToInterrupt(intPin), dataReadyISR, RISING);\r\n  myIMU.readAndClearInterrupts();\r\n  \r\n}\r\n\r\nvoid loop() {\r\n  if(dataReady){\r\n    byte source = myIMU.readAndClearInterrupts();\r\n    if(myIMU.checkInterrupt(source, ICM20948_DATA_READY_INT)){\r\n      Serial.println(\"Interrupt Type: Data Ready\");\r\n      printData();\r\n    }\r\n    dataReady = false;\r\n    myIMU.readAndClearInterrupts(); \/\/ if additional interrupts have occured in the meantime\r\n  }\r\n}\r\n\r\nvoid printData(){\r\n  xyzFloat gValue;\r\n  xyzFloat gyrValue;\r\n  myIMU.readSensor();\r\n  myIMU.getGValues(&amp;gValue);\r\n  myIMU.getGyrValues(&amp;gyrValue);\r\n      \r\n  Serial.println(\"g-values (x,y,z):\");\r\n  Serial.print(gValue.x);\r\n  Serial.print(\"   \");\r\n  Serial.print(gValue.y);\r\n  Serial.print(\"   \");\r\n  Serial.println(gValue.z);\r\n\r\n\/\/  Uncomment after you have enabled the gyroscope\r\n\/\/  Serial.println(\"Gyroscope (x,y,z):\");\r\n\/\/  Serial.print(gyrValue.x);\r\n\/\/  Serial.print(\"   \");\r\n\/\/  Serial.print(gyrValue.y);\r\n\/\/  Serial.print(\"   \");\r\n\/\/  Serial.println(gyrValue.z);\r\n\r\n  Serial.println();\r\n}\r\n\r\nvoid dataReadyISR() {\r\n  dataReady = true;\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\r\n\n<p>I&#8217;m using the following new functions for interrupt control:<\/p>\r\n<ul>\r\n<li><code>setIntPinPolarity()<\/code> sets whether the interrupt pin is active-high or active-low.<\/li>\r\n<li><code>enableIntLatch(true\/false)<\/code> controls whether the interrupt is output as a short signal at the interrupt pin, or whether the signal remains permanently at interrupt level until the interrupt is cleared.<\/li>\r\n<li>With <code>enableClearIntByAnyRead()<\/code>, you set whether the interrupt is cleared with any read operation or by reading the interrupt status register only. Activation only makes sense in combination with <code>enableLatch()<\/code>.<\/li>\r\n<li>With <code>enableInterrupt(type)<\/code> you choose which interrupt type you want to activate. If you want to enable multiple interrupts, then just call the function multiple times.<\/li>\r\n<li><code>disableInterrupt(type)<\/code> deactivates an interrupt.<\/li>\r\n<li><code>readAndClearInterrupts()<\/code> reads the various interrupt status registers and deletes the active interrupt (if latch is activated). The function save the triggered interrupts in a variable (source).<\/li>\r\n<li><code>checkInterrupt(source, type)<\/code> can be used to check if a particular interrupt has been triggered. You can also evaluate the value returned by <code>readAndClearInterrupt()<\/code>. However, in order to &#8220;translate&#8221; it, you have to look in ICM20948_WE.h how this is defined. The enum variable ICM20948_INT_TYPE contains the key which bit of the variable source is set for which interrupt.<\/li>\r\n<\/ul>\r\n\n<h4 class=\"wp-block-heading\">Output of ICM20948_09_data_ready_interrupt.ino<\/h4>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_data_ready_int.png\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_data_ready_int.png\" alt=\"ICM-20948 - Output of ICM20948_09_data_ready_interrupt.ino\" class=\"wp-image-12134\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_data_ready_int.png 887w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_data_ready_int-300x118.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_data_ready_int-768x302.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_09_data_ready_interrupt.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">ICM20948_10_wom_interrupt.ino<\/h3>\n\n<p>&#8220;Wake-on-Motion&#8221; suggests that the ICM-20948 could wake up from sleep mode using this interrupt. However, this is not the case. Rather, it is a simple acceleration interrupt.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_10_wom_interrupt.ino\" data-enlighter-title=\"ICM20948_10_wom_interrupt.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nconst int intPin = 2;\r\nvolatile bool motion = false;\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n\r\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \r\n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \r\n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\r\n   *  The parameters are floats. \r\n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point is \r\n   *  set as (min + max)\/2.\r\n   *\/\r\n  \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\r\n    \r\n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \r\n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \r\n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\r\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\r\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \r\n   * depend on the positioning.\r\n   * This function needs to be called after setAccOffsets but before other settings since it will \r\n   * overwrite settings!\r\n   * You can query the offsets with the functions:\r\n   * xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\r\n   * You can apply the offsets using:\r\n   * setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\r\n   *\/\r\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\r\n  delay(1000);\r\n  myIMU.autoOffsets();\r\n  Serial.println(\"Done!\"); \r\n  \r\n  \/* enables or disables the acceleration sensor, default: enabled *\/\r\n  \/\/ myIMU.enableAcc(true);\r\n\r\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\r\n   *  ICM20948_ACC_RANGE_4G      4 g\r\n   *  ICM20948_ACC_RANGE_8G      8 g   \r\n   *  ICM20948_ACC_RANGE_16G    16 g\r\n   *\/\r\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              246.0               1125\/(1+ASRD) \r\n   *    1              246.0               1125\/(1+ASRD)\r\n   *    2              111.4               1125\/(1+ASRD)\r\n   *    3               50.4               1125\/(1+ASRD)\r\n   *    4               23.9               1125\/(1+ASRD)\r\n   *    5               11.5               1125\/(1+ASRD)\r\n   *    6                5.7               1125\/(1+ASRD) \r\n   *    7              473.0               1125\/(1+ASRD)\r\n   *    OFF           1209.0               4500\r\n   *    \r\n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \r\n  \r\n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not off!\r\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setAccSampleRateDivider(10);\r\n  \r\n  \/*  Set the interrupt pin:\r\n   *  ICM20948_ACT_LOW  = active-low\r\n   *  ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n   \/*  If latch is enabled the interrupt pin level is held until the interrupt status \r\n   *  is cleared. If latch is disabled the interrupt pulse is ~50\u00b5s (default).\r\n   *\/\r\n  myIMU.enableIntLatch(true);\r\n\r\n  \/*  The interrupts ICM20948_FSYNC_INT, ICM20948_WOM_INT and ICM20948_DMP_INT can be \r\n   *  cleared by any read or will only be cleared if the interrupt status register is \r\n   *  read (default).\r\n   *\/\r\n\/\/  myIMU.enableClearIntByAnyRead(true);\r\n\r\n  \/*  Set the FSync interrupt pin:\r\n   *  ICM20948_ACT_LOW  = active-low\r\n   *  ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setFSyncIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n  \/* The following interrupts can be enabled or disabled:\r\n   *  ICM20948_FSYNC_INT        FSYNC pin interrupt, can't propagate to the INT pin  \r\n   *  ICM20948_WOM_INT          Wake on motion\r\n   *  ICM20948_DATA_READY_INT   New data available\r\n   *  ICM20948_FIFO_OVF_INT     FIFO overflow\r\n   *\/\r\n  myIMU.enableInterrupt(ICM20948_WOM_INT);\r\n  \/\/myIMU.disableInterrupt(ICM20948_WOM_INT);\r\n\r\n  \/* setWakeOnMotionThreshold sets the limit (first argument) for a wake on \r\n   * motion interrupt and defines the WOM mode (second argument). The limit \r\n   * is a number between 1 and 255 with 1 = 4 mg (milli-g) and 255 = 1020 mg. \r\n   * You can choose from two modes:\r\n   * ICM20948_WOM_COMP_DISABLE = compare the sample with the initial sample (default). \r\n   * ICM20948_WOM_COMP_ENABLE = compare the sampe with the previous sample.\r\n   *\/\r\n  myIMU.setWakeOnMotionThreshold(128, ICM20948_WOM_COMP_DISABLE);\r\n  attachInterrupt(digitalPinToInterrupt(intPin), motionISR, RISING);\r\n  Serial.println(\"Turn your ICM-20948 and see what happens...\");\r\n  myIMU.readAndClearInterrupts();\r\n  motion = false;\r\n }\r\n\r\nvoid loop() {\r\n  xyzFloat gValue;\r\n\r\n  if((millis()%1000) == 0){\r\n    myIMU.readSensor();\r\n    myIMU.getGValues(&amp;gValue);\r\n    \r\n    Serial.print(gValue.x);\r\n    Serial.print(\"   \");\r\n    Serial.print(gValue.y);\r\n    Serial.print(\"   \");\r\n    Serial.println(gValue.z);\r\n  }\r\n  if(motion){\r\n    byte source = myIMU.readAndClearInterrupts();\r\n    Serial.println(\"Interrupt!\");\r\n    if(myIMU.checkInterrupt(source, ICM20948_WOM_INT)){\r\n      Serial.println(\"Interrupt Type: Motion\");\r\n      delay(1000);\r\n    }\r\n    motion = false;\r\n    \/\/ if additional interrupts have occured in the meantime:\r\n    myIMU.readAndClearInterrupts(); \r\n  }\r\n}\r\n\r\nvoid motionISR() {\r\n  motion = true;\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\r\n\n<p>Only one new function is used in the sketch. <code>setWakeOnMotionThreshold(value, comp)<\/code> expects 2 arguments. &#8220;value&#8221; is the difference between the current measured value and a reference value at which the interrupt is triggered. Strictly speaking, &#8220;value&#8221; is the absolute value of the difference. This means that both positive and negative accelerations trigger the interrupt. You can choose a value between 1 (= 0.004 g) and 255 (1.02 g).&nbsp; The second argument determines the comparison value. This is either the initial value when activating the interrupt or it is the last reading.<\/p>\r\n<p>The WOM interrupt is not axis-specific. This means that each axis on which the condition is fulfilled triggers the interrupt.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Output of ICM20948_10_wom_interrupt.ino<\/h4>\n\n<p>For the following output, I slowly straightened up the x-axis of the ICM-20948.<\/p>\r\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_wom_int.png\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_wom_int.png\" alt=\"ICM-20948 Sample Sketch - Output of ICM20948_10_wom_interrupt.ino\" class=\"wp-image-12138\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_wom_int.png 887w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_wom_int-300x118.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_wom_int-768x302.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_10_wom_interrupt.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">ICM20948_11_fsync_interrupt.ino<\/h3>\n\n<p>Here, the FSYNC pin is set up as an interrupt pin, which is triggered either on HIGH or LOW level. Depending on the setting, you must install a pull-up or pull-down resistor on FSYNC.&nbsp; Unlike the other interrupts, the FSYNC interrupt is not output at the interrupt pin. So you need to actively query the status.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_11_fsync_interrupt.ino\" data-enlighter-title=\"ICM20948_11_fsync_interrupt.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nconst int intPin = 2;\r\nvolatile bool fsyncEvent = false;\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n \r\n  \/* Set the interrupt pin:\r\n   * ICM20948_ACT_LOW  = active-low\r\n   * ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n  \/*  If latch is enabled the interrupt pin level is held until the interrupt status \r\n   *  is cleared. If latch is disabled the interrupt pulse is ~50\u00b5s (default).\r\n   *\/\r\n   myIMU.enableIntLatch(true);\r\n\r\n  \/* The interrupts ICM20948_FSYNC_INT, ICM20948_WOM_INT and ICM20948_DMP_INT can be \r\n   * cleared by any read or will only be cleared if the interrupt status register is \r\n   * read (default).\r\n   *\/\r\n   \/\/myIMU.enableClearIntByAnyRead(true);\r\n\r\n  \/* Set the FSync interrupt pin:\r\n   *  ICM20948_ACT_LOW  = interrupt if low\r\n   *  ICM20948_ACT_HIGH = interrupt if high (default) \r\n   *\/\r\n   \/\/myIMU.setFSyncIntPolarity(ICM20948_ACT_LOW);\r\n\r\n  \/* The following interrupts can be enabled or disabled:\r\n   *  ICM20948_FSYNC_INT        FSYNC pin interrupt, can't propagate to the INT pin  \r\n   *  ICM20948_WOM_INT          Wake on motion\r\n   *  ICM20948_DATA_READY_INT   New data available\r\n   *  ICM20948_FIFO_OVF_INT     FIFO overflow\r\n   *\/\r\n  myIMU.enableInterrupt(ICM20948_FSYNC_INT);\r\n  \/\/myIMU.disableInterrupt(ICM20948_DATA_READY_INT);\r\n\r\n  Serial.println(\"Pull down the FSYNC pin with a 10kOhm resistor.\");\r\n  Serial.println(\"A HIGH signal to pin FSYNC will then cause an interrupt - try it!\");\r\n}\r\n\r\nvoid loop() {\r\n  byte source = myIMU.readAndClearInterrupts();\r\n  if(myIMU.checkInterrupt(source, ICM20948_FSYNC_INT)){\r\n    Serial.println(\"Interrupt! Type: FSync Pin Interrupt\");\r\n  }\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\r\n\n<p>The sketch uses only one new function, which is <code>setFSyncIntPolarity()<\/code>. This determines whether the interrupt triggers at HIGH or LOW.<\/p>\r\n\n<h2 class=\"wp-block-heading\">FIFO functions of the ICM-20948<\/h2>\n\n<p>The FIFO (first in, first out) is a kind of recorder for measurement data. The data that the ICM-20948 writes in first, it reads first &#8211; hence its name. According to the data sheet, the FIFO has a size of 512 bytes. However, I did not implement the DMP function. As a result, the FIFO grows to a comfortable 4096 bytes.<\/p>\r\n<p>You define which data is written to the FIFO. This determines how many data records can be stored in the FIFO. An acceleration or gyroscope value is two bytes. It is always the raw data which stored. An x,y,z data triple therefore requires 6 bytes. I have implemented the following options:<\/p>\r\n<ul>\r\n<li>Acceleration values as complete triples &#8211; 682 complete triples fit (4096 \/ 6 = 682, rest 4) in the FIFO.<\/li>\r\n<li>Gyroscope values as complete triples &#8211; 682 complete triples fit.<\/li>\r\n<li>Acceleration and gyroscope values &#8211; max. 341 complete data sets (4096 \/ 12 = 341, rest 4).<\/li>\r\n<li>The ICM-20948 can also store gyroscope data from individual axes, temperatures or data from external sensors. However, I did not implement this to keep things simple.<\/li>\r\n<\/ul>\r\n<p>If the FIFO is read, all FIFO data are shifted one after the other into a data register with a width of one byte. From there, the bytes are read one at a time (as when cigarette packs are taken from a cigarette vending machine) and &#8220;assembled&#8221; into meaningful data. However, for the individual bytes, it is not recognizable whether it is the MSB or LSB of an acceleration or a gyroscope value. So, you have to count and read the data in the right order. This can only be automated to a certain extent. And in order not to make it too complex and thus error-prone for the user, I did not implement all options.<\/p>\r\n\n<h3 class=\"wp-block-heading\">ICM20948_12_FIFO_stop_when_full.ino<\/h3>\n\n<p>In this first FIFO sketch, the ICM-20948 stops data saving when the FIFO is full. This means that you specify the start of the recording. The recording duration depends on the data rate and the recorded data types. By the way, a combination of FIFO and cycle mode does not work.<\/p>\r\n<p>When the FIFO is full, you can be informed about it by the FIFO overflow interrupt.<\/p>\r\n<p>When recording acceleration and gyroscope data, the ICM-20948 always writes the acceleration data to the FIFO first. Since it stops in this example when the FIFO is full, the FIFO data begins with an acceleration value. This is different in the next example. For proper reading this is important!<\/p>\r\n<p>In my example sketch, I record accelerometer and gyroscope data. The data rate of the gyroscope has priority. The sample rate divider is set to 20. Thus, the data rate is 1125\/20 = 56.25 Hz. Since 341 records are recorded, the FIFO buffer overflows after about 6 seconds.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_12_FIFO_stop_when_full.ino\" data-enlighter-title=\"ICM20948_12_FIFO_stop_when_full.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nconst int intPin = 2;\r\nvolatile bool fifoFull = false;\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n\r\n \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\r\n    \r\n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \r\n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \r\n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\r\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\r\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \r\n   * depend on the positioning.\r\n   * This function needs to be called after setAccOffsets but before other settings since it will \r\n   * overwrite settings!\r\n   * You can query the offsets with the functions:\r\n   * xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\r\n   * You can apply the offsets using:\r\n   * setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\r\n   *\/\r\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\r\n  delay(1000);\r\n  myIMU.autoOffsets();\r\n  Serial.println(\"Done!\"); \r\n  \r\n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \r\n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\r\n   *  using the +\/- 250 degrees\/s range. \r\n   *  Use either autoOffset or setGyrOffsets, not both.\r\n   *\/\r\n  \/\/myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\r\n  \r\n  \/* enables or disables the acceleration sensor, default: enabled *\/\r\n  \/\/myIMU.enableAcc(true);\r\n\r\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\r\n   *  ICM20948_ACC_RANGE_4G      4 g\r\n   *  ICM20948_ACC_RANGE_8G      8 g   \r\n   *  ICM20948_ACC_RANGE_16G    16 g\r\n   *\/\r\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              246.0               1125\/(1+ASRD) \r\n   *    1              246.0               1125\/(1+ASRD)\r\n   *    2              111.4               1125\/(1+ASRD)\r\n   *    3               50.4               1125\/(1+ASRD)\r\n   *    4               23.9               1125\/(1+ASRD)\r\n   *    5               11.5               1125\/(1+ASRD)\r\n   *    6                5.7               1125\/(1+ASRD) \r\n   *    7              473.0               1125\/(1+ASRD)\r\n   *    OFF           1209.0               4500\r\n   *    \r\n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \r\n  \r\n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not off!\r\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setAccSampleRateDivider(20);\r\n  \r\n  \/* enables or disables the gyroscope sensor, default: enabled *\/\r\n  \/\/ myIMU.enableGyr(false);\r\n\r\n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\r\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\r\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\r\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\r\n   *\/\r\n  myIMU.setGyrRange(ICM20948_GYRO_RANGE_250);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              196.6               1125\/(1+GSRD) \r\n   *    1              151.8               1125\/(1+GSRD)\r\n   *    2              119.5               1125\/(1+GSRD)\r\n   *    3               51.2               1125\/(1+GSRD)\r\n   *    4               23.9               1125\/(1+GSRD)\r\n   *    5               11.6               1125\/(1+GSRD)\r\n   *    6                5.7               1125\/(1+GSRD) \r\n   *    7              361.4               1125\/(1+GSRD)\r\n   *    OFF          12106.0               9000\r\n   *    \r\n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setGyrDLPF(ICM20948_DLPF_6);  \r\n  \r\n  \/*  Gyroscope sample rate divider divides the output rate of the gyroscope.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not OFF!\r\n   *  Divider is a number 0...255\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setGyrSampleRateDivider(20);\r\n\r\n  \/*  Set the interrupt pin:\r\n   *  ICM20948_ACT_LOW  = active-low\r\n   *  ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n   \/\/myIMU.setIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n  \/*  If latch is enabled the interrupt pin level is held until the interrupt status \r\n   *  is cleared. If latch is disabled the interrupt pulse is ~50\u00b5s (default).\r\n   *\/\r\n  myIMU.enableIntLatch(true);\r\n\r\n  \/*  The interrupts ICM20948_FSYNC_INT, ICM20948_WOM_INT and ICM20948_DMP_INT can be \r\n   *  cleared by any read or will only be cleared if the interrupt status register is \r\n   *  read (default).\r\n   *\/\r\n  \/\/myIMU.enableClearIntByAnyRead(true);\r\n\r\n  \/* The following interrupts can be enabled or disabled:\r\n   *  ICM20948_FSYNC_INT        FSYNC pin interrupt, can't propagate to the INT pin  \r\n   *  ICM20948_WOM_INT          Wake on motion\r\n   *  ICM20948_DATA_READY_INT   New data available\r\n   *  ICM20948_FIFO_OVF_INT     FIFO overflow\r\n   *\/\r\n  myIMU.enableInterrupt(ICM20948_FIFO_OVF_INT);\r\n  \/\/myIMU.disableInterrupt(ICM20948_WOM_INT);\r\n\r\n  \/* enables the FIFO function, default: disabled *\/\r\n  \/\/myIMU.enableFifo(true);\r\n\r\n  \/* There are two different FIFO modes:\r\n   *  ICM20948_CONTINUOUS --&gt; samples are continuously stored in FIFO. If FIFO is full \r\n   *  new data will replace the oldest.\r\n   *  ICM20948_STOP_WHEN_FULL --&gt; self-explaining\r\n   *\/\r\n  \/\/myIMU.setFifoMode(ICM20948_STOP_WHEN_FULL); \/\/ used below, but explained here\r\n  \r\n  \/* The argument of startFifo defines the data stored in the FIFO\r\n   * ICM20948_FIFO_ACC --&gt; Acceleration Data ist stored in FIFO  \r\n   * ICM20948_FIFO_GYR --&gt; Gyroscope data is stored in FIFO   \r\n   * ICM20948_FIFO_ACC_GYR --&gt; Acceleration and Gyroscope Data is stored in FIFO\r\n   * The library does not (yet) support storing single gyroscope axes data, temperature \r\n   * or data from slaves. \r\n   *\/\r\n  \/\/myIMU.startFifo(ICM20948_FIFO_ACC); \/\/ used below, but explained here\r\n  \r\n  \/* stopFifo(): \r\n   * - stops additional writes into Fifo \r\n   * - clears the data type written into Fifo (acceleration and\/or gyroscope\r\n   *\/\r\n  \/\/myIMU.stopFifo(); \r\n\r\n  \/* sets the Fifo counter to zero *\/ \r\n  \/\/myIMU.resetFifo(); \r\n\r\n\r\n  attachInterrupt(digitalPinToInterrupt(intPin), eventISR, RISING);\r\n  myIMU.setFifoMode(ICM20948_STOP_WHEN_FULL);\r\n  myIMU.enableFifo(true);\r\n  delay(100); \/\/ in some cases a delay after enabling Fifo makes sense\r\n}\r\n\r\nvoid loop() { \r\n  countDown();\r\n  myIMU.readAndClearInterrupts();\r\n  fifoFull = false;\r\n  myIMU.startFifo(ICM20948_FIFO_ACC_GYR);\r\n  while(!fifoFull){}\r\n  myIMU.stopFifo();\r\n  printFifo();\r\n  myIMU.resetFifo();\r\n\r\n  Serial.println(\"For another series of measurements, enter any key and send\");\r\n  \r\n  while(!(Serial.available())){}\r\n  Serial.read();\r\n  Serial.println();\r\n }\r\n\r\nvoid printFifo(){\r\n  int count = myIMU.getFifoCount();\r\n  int dataSets = myIMU.getNumberOfFifoDataSets(); \r\n  Serial.print(\"Bytes in Fifo: \");\r\n  Serial.println(count);\r\n  Serial.print(\"Data Sets: \");\r\n  Serial.println(dataSets);\r\n\r\n  for(int i=0; i&lt;dataSets; i++){\r\n    xyzFloat gValue;\r\n    xyzFloat gyr;\r\n    myIMU.getGValuesFromFifo(&amp;gValue);\r\n    myIMU.getGyrValuesFromFifo(&amp;gyr);\r\n    Serial.print(\"Data set \");\r\n    Serial.print(i+1);\r\n    Serial.println(\":\");\r\n    \r\n    Serial.print(gValue.x);\r\n    Serial.print(\"   \");\r\n    Serial.print(gValue.y);\r\n    Serial.print(\"   \");\r\n    Serial.println(gValue.z);\r\n\r\n    Serial.print(gyr.x);\r\n    Serial.print(\"   \");\r\n    Serial.print(gyr.y);\r\n    Serial.print(\"   \");\r\n    Serial.println(gyr.z);\r\n  }\r\n}\r\n\r\nvoid countDown(){\r\n  Serial.println(\"Move\/turn your ICM20948 to obtain interesting data\");\r\n  Serial.println();\r\n  delay(1000);\r\n  Serial.print(\"Fifo collection begins in 3, \"); \r\n  delay(1000);\r\n  Serial.print(\"2, \"); \r\n  delay(1000);\r\n  Serial.print(\"1, \"); \r\n  delay(1000);\r\n  Serial.println(\"Now!\");\r\n}\r\n\r\nvoid eventISR() {\r\n  fifoFull = true;\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\r\n\n<p>In my example, a countdown starts the FIFO. You can also choose other triggers, such as a WOM interrupt.<\/p>\r\n<p>When the FIFO is full, this is indicated by an interrupt. Then the data is read and output. Then you can start a new FIFO recording by sending a character via the serial monitor.<\/p>\r\n\n<h4 class=\"wp-block-heading\">New functions<\/h4>\n\n<p>The following new functions are used:<\/p>\r\n<ul>\r\n<li><code>enableFifo()<\/code> enables or disables the FIFO.<\/li>\r\n<li>With <code>setFifoMode()<\/code>, you determine whether you use the continuous or the &#8220;stop-when-full&#8221; mode.<\/li>\r\n<li>You pass <code>startFiFo()<\/code> the data types you want to write to the FIFO. This call of this function also starts the counter.<\/li>\r\n<li>With <code>stopFifo()<\/code>, you prevent that further data is written to the FIFO. This process is stopped anyway when the FIFO is full, but only temporarily. As soon as you start reading, free space is created in the FIFO. And that would be filled immediately with new data if you don&#8217;t call <code>stopFifo()<\/code>.&nbsp;<\/li>\r\n<li><code>getFifoCount()<\/code> returns the number of bytes in the FIFO. If the FIFO is full, that&#8217;s 4096. But you could theoretically stop writing to the FIFO before it&#8217;s full.<\/li>\r\n<li><code>getNumberOfFifoDataSets()<\/code> calculates the number of records in the FIFO. In this example, a data record consists of an x,y,z acceleration data triple and an x,y,z gyroscope data triple and that is 12 bytes.&nbsp;<\/li>\r\n<li><code>getGValuesFromFifo()<\/code> reads an x,y,z triple of acceleration data and converts it into a g-value triple. Since the FIFO contains raw data, you must not change the parameters (i.e. range or offsets) between recording and reading.<\/li>\r\n<li><code>getGyrValuesFromFifo()<\/code> reads an x,y,z gyroscope data triple (raw data) and converts it to rotation values (\u00b0\/s).<\/li>\r\n<li><code>resetFifo()<\/code> sets the FIFO counter to zero.<\/li>\r\n<\/ul>\r\n<p>I need to stress once again that you must follow the order when reading the FIFO. In this example, you&#8217;ll alternately read acceleration data and gyroscope data and start with the acceleration data.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Output of ICM20949_12_FIFO_stop_when_full.ino<\/h4>\n\n<p>This is an excerpt of the output:<\/p>\r\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_stop_when_full.png\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_stop_when_full.png\" alt=\"ICM-20948 - Output of ICM20948_12_stop_when_full.ino\" class=\"wp-image-12145\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_stop_when_full.png 887w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_stop_when_full-300x118.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_stop_when_full-768x302.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_12_stop_when_full.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">ICM20948_13_FIFO_continuous.ino <\/h3>\n\n<p>With this method, the FIFO continuously records the data types you have specified. So, here you do not determine the start, but the end. If the FIFO is full before you stop, it deletes the oldest data in favor of the new data.<\/p>\r\n<p>The ICM-20948 always writes complete records to the FIFO. This means you have a defined end. The first data record, on the other hand, is incomplete. This is because the FIFO does not delete complete data sets. At 4096 bytes is brutally capped. Therefore, an additional function is needed in this case. It finds the beginning of the first complete data set when reading the FIFO.<\/p>\r\n<p>The example sketch uses a WOM interrupt as the stop signal for the FIFO. Rotate the ICM-20948 to trigger the interrupt. Here I have set the sample rate divider to 10. This results in a data rate of 1125 \/ 11 = ~100 Hz. This means that under these conditions the FIFO contains the data of the last 3.4 seconds.&nbsp;<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_13_FIFO_continuous.ino\" data-enlighter-title=\"ICM20948_13_FIFO_continuous.ino\">#include &lt;Wire.h&gt;\r\n#include &lt;ICM20948_WE.h&gt;\r\n#define ICM20948_ADDR 0x68\r\n\r\n\/* There are several ways to create your ICM20948 object:\r\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\r\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\r\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\r\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\r\n *\/\r\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\r\n\r\nconst int intPin = 2;\r\nvolatile bool womEvent = false;\r\n\r\nvoid setup() {\r\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\r\n  Wire.begin();\r\n  Serial.begin(115200);\r\n  while(!Serial) {}\r\n  \r\n  if(!myIMU.init()){\r\n    Serial.println(\"ICM20948 does not respond\");\r\n  }\r\n  else{\r\n    Serial.println(\"ICM20948 is connected\");\r\n  }\r\n\r\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \r\n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \r\n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\r\n   *  The parameters are floats. \r\n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point is \r\n   *  set as (min + max)\/2.\r\n   *\/\r\n  \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\r\n    \r\n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \r\n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \r\n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\r\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\r\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \r\n   * depend on the positioning.\r\n   * This function needs to be called after setAccOffsets but before other settings since it will \r\n   * overwrite settings!\r\n   * You can query the offsets with the functions:\r\n   * xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\r\n   * You can apply the offsets using:\r\n   * setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\r\n   *\/\r\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\r\n  delay(1000);\r\n  myIMU.autoOffsets();\r\n  Serial.println(\"Done!\"); \r\n  \r\n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \r\n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\r\n   *  using the +\/- 250 degrees\/s range. \r\n   *  Use either autoOffset or setGyrOffsets, not both.\r\n   *\/\r\n  \/\/myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\r\n    \r\n  \/* enables or disables the acceleration sensor, default: enabled *\/\r\n  \/\/ myIMU.enableAcc(true);\r\n\r\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\r\n   *  ICM20948_ACC_RANGE_4G      4 g\r\n   *  ICM20948_ACC_RANGE_8G      8 g   \r\n   *  ICM20948_ACC_RANGE_16G    16 g\r\n   *\/\r\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              246.0               1125\/(1+ASRD) \r\n   *    1              246.0               1125\/(1+ASRD)\r\n   *    2              111.4               1125\/(1+ASRD)\r\n   *    3               50.4               1125\/(1+ASRD)\r\n   *    4               23.9               1125\/(1+ASRD)\r\n   *    5               11.5               1125\/(1+ASRD)\r\n   *    6                5.7               1125\/(1+ASRD) \r\n   *    7              473.0               1125\/(1+ASRD)\r\n   *    OFF           1209.0               4500\r\n   *    \r\n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \r\n  \r\n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not off!\r\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setAccSampleRateDivider(10);\r\n  \r\n  \/* enables or disables the gyroscope sensor, default: enabled *\/\r\n  \/\/ myIMU.enableGyr(false);\r\n\r\n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\r\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\r\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\r\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\r\n   *\/\r\n  \/\/myIMU.setGyrRange(ICM20948_GYRO_RANGE_250);\r\n  \r\n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \r\n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \r\n   *  \r\n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\r\n   *    0              196.6               1125\/(1+GSRD) \r\n   *    1              151.8               1125\/(1+GSRD)\r\n   *    2              119.5               1125\/(1+GSRD)\r\n   *    3               51.2               1125\/(1+GSRD)\r\n   *    4               23.9               1125\/(1+GSRD)\r\n   *    5               11.6               1125\/(1+GSRD)\r\n   *    6                5.7               1125\/(1+GSRD) \r\n   *    7              361.4               1125\/(1+GSRD)\r\n   *    OFF          12106.0               9000\r\n   *    \r\n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\r\n   *    You achieve lowest noise using level 6  \r\n   *\/\r\n  myIMU.setGyrDLPF(ICM20948_DLPF_6);  \r\n  \r\n  \/*  Gyroscope sample rate divider divides the output rate of the gyroscope.\r\n   *  Sample rate = Basic sample rate \/ (1 + divider) \r\n   *  It can only be applied if the corresponding DLPF is not OFF!\r\n   *  Divider is a number 0...255\r\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\r\n   *  sample rate has priority.\r\n   *\/\r\n  myIMU.setGyrSampleRateDivider(10);\r\n \r\n  \/*  Set the interrupt pin:\r\n   *  ICM20948_ACT_LOW  = active-low\r\n   *  ICM20948_ACT_HIGH = active-high (default) \r\n   *\/\r\n  \/\/myIMU.setIntPinPolarity(ICM20948_ACT_LOW);\r\n\r\n  \/*  If latch is enabled the interrupt pin level is held until the interrupt status \r\n   *  is cleared. If latch is disabled the interrupt pulse is ~50\u00b5s (default).\r\n   *\/\r\n  myIMU.enableIntLatch(true);\r\n\r\n  \/*  The interrupts ICM20948_FSYNC_INT, ICM20948_WOM_INT and ICM20948_DMP_INT can be \r\n   *  cleared by any read or will only be cleared if the interrupt status register is \r\n   *  read (default).\r\n   *\/\r\n  \/\/myIMU.enableClearIntByAnyRead(true);\r\n\r\n  \/* The following interrupts can be enabled or disabled:\r\n   *  ICM20948_FSYNC_INT        FSYNC pin interrupt, can't propagate to the INT pin  \r\n   *  ICM20948_WOM_INT          Wake on motion\r\n   *  ICM20948_DATA_READY_INT   New data available\r\n   *  ICM20948_FIFO_OVF_INT     FIFO overflow\r\n   *\/\r\n  myIMU.enableInterrupt(ICM20948_WOM_INT);\r\n  \/\/myIMU.disableInterrupt(ICM20948_WOM_INT);\r\n\r\n  \/* setWakeOnMotionThreshold sets the limit (first argument) for a wake on \r\n   * motion interrupt and defines the WOM mode (second argument). The limit \r\n   * is a number between 1 and 255 with 1 = 4 mg (milli-g) and 255 = 1020 mg. \r\n   * You can choose from two modes:\r\n   * ICM20948_WOM_COMP_DISABLE = compare the sample with the initial sample (default). \r\n   * ICM20948_WOM_COMP_ENABLE = compare the sampe with the previous sample.\r\n   *\/\r\n  myIMU.setWakeOnMotionThreshold(128, ICM20948_WOM_COMP_DISABLE);\r\n  \r\n  \/* enables the FIFO function, default: disabled *\/\r\n  \/\/ myIMU.enableFifo(true); \/\/ explained here, used below\r\n\r\n  \/* There are two different FIFO modes:\r\n   *  ICM20948_CONTINUOUS --&gt; samples are continuously stored in FIFO. If FIFO is full \r\n   *  new data will replace the oldest.\r\n   *  ICM20948_STOP_WHEN_FULL --&gt; self-explaining\r\n   *\/\r\n  \/\/myIMU.setFifoMode(ICM20948_STOP_WHEN_FULL); \/\/ used below, but explained here\r\n  \r\n  \/* The argument of startFifo defines the data stored in the FIFO\r\n   * ICM20948_FIFO_ACC --&gt; Acceleration Data ist stored in FIFO  \r\n   * ICM20948_FIFO_GYR --&gt; Gyroscope data is stored in FIFO   \r\n   * ICM20948_FIFO_ACC_GYR --&gt; Acceleration and Gyroscope Data is stored in FIFO\r\n   * The library does not (yet) support storing single gyroscope axes data, temperature \r\n   * or data from slaves. \r\n   *\/\r\n  \/\/myIMU.startFifo(ICM20948_FIFO_ACC); \/\/ used below, but explained here\r\n  \r\n  \/* stopFifo(): \r\n   * - stops additional writes into Fifo \r\n   * - clears the data type written into Fifo (acceleration and\/or gyroscope)\r\n   *\/\r\n  \/\/myIMU.stopFifo(); \/\/ explained here, used below\r\n\r\n  \/* sets the Fifo counter to zero *\/ \r\n  \/\/myIMU.resetFifo(); \/\/ explained here, used below\r\n\r\n  attachInterrupt(digitalPinToInterrupt(intPin), eventISR, RISING);\r\n  myIMU.readAndClearInterrupts();\r\n  womEvent = false;\r\n  myIMU.setFifoMode(ICM20948_CONTINUOUS);\r\n  myIMU.enableFifo(true);\r\n  delay(100); \/\/ in some cases a delay after enabling Fifo makes sense\r\n  myIMU.startFifo(ICM20948_FIFO_ACC_GYR);\r\n  Serial.println(\"Turn your ICM20948 around the x or y axis.\");\r\n  Serial.println(\"Waiting for wake-on-motion event...\");\r\n}\r\n\r\nvoid loop() {\r\n  if(womEvent){\r\n    myIMU.stopFifo();\r\n    printFifo();\r\n    myIMU.resetFifo();\r\n    myIMU.startFifo(ICM20948_FIFO_ACC_GYR);\r\n   \r\n    Serial.println(\"For another series of measurements, enter any key and send\");\r\n    \r\n    while(!(Serial.available())){}\r\n    Serial.read();\r\n    Serial.println();\r\n    myIMU.readAndClearInterrupts();\r\n    womEvent = false;\r\n  }\r\n}\r\n\r\nvoid printFifo(){\r\n  myIMU.findFifoBegin(); \/* this is needed for continuous Fifo mode. The Fifo buffer ends with a \r\n  complete data set, but it starts is within a data set. *\/\r\n  int count = myIMU.getFifoCount();\r\n  int dataSets = myIMU.getNumberOfFifoDataSets(); \r\n  Serial.print(\"Bytes in Fifo: \");\r\n  Serial.println(count);\r\n  Serial.print(\"Data Sets: \");\r\n  Serial.println(dataSets);\r\n\r\n  for(int i=0; i&lt;dataSets; i++){\r\n    \/* if you read acceleration (g) and gyroscope values you need to start with g values *\/\r\n    xyzFloat gValue;\r\n    xyzFloat gyr;\r\n    myIMU.getGValuesFromFifo(&amp;gValue);\r\n    myIMU.getGyrValuesFromFifo(&amp;gyr);\r\n    Serial.print(\"Data set \");\r\n    Serial.print(i+1);\r\n    Serial.println(\":\");\r\n    \r\n    Serial.print(gValue.x);\r\n    Serial.print(\"   \");\r\n    Serial.print(gValue.y);\r\n    Serial.print(\"   \");\r\n    Serial.println(gValue.z);\r\n\r\n    Serial.print(gyr.x);\r\n    Serial.print(\"   \");\r\n    Serial.print(gyr.y);\r\n    Serial.print(\"   \");\r\n    Serial.println(gyr.z);\r\n  }\r\n}\r\n\r\nvoid eventISR() {\r\n  womEvent = true;\r\n}<\/pre>\r\n<p>\u00a0<\/p>\r\n<\/div>\n\n<p>The sketch uses only one new function, which is <code>findFifoBegin()<\/code>. It calculates where the first complete record begins in the FIFO. Then it reads the data up to that point and discards it. Therefore, <code>getFifoCount()<\/code> &#8211; after calling <code>findFifoBegin()<\/code> &#8211; won&#8217;t return 4096. Just try and call <code>getFifoCount()<\/code> before <code>findFifoBegin()<\/code> and see what happens.<\/p>\r\n\n<h4 class=\"wp-block-heading\">Output of ICM20948_13_FIFO_continuous.ino<\/h4>\n\n<p>This is an excerpt of the output on the serial monitor:<\/p>\r\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_continuous.png\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_continuous.png\" alt=\"Output of ICM20948_13_FIFO_continuous.ino\" class=\"wp-image-12148\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_continuous.png 887w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_continuous-300x118.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_fifo_continuous-768x302.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_13_FIFO_continuous.ino<\/figcaption><\/figure>\n\n<p>If you feel like it, play around a bit with the FIFO parameters. For example, you could select a different sample rate or stop the FIFO before it&#8217;s full. For the latter, you will see that reading still works. Or try to only write acceleration or gyroscope data to the FIFO.<\/p>\r\n\n<h3 class=\"wp-block-heading\">ICM20948_14_blank_all_settings<\/h3>\n\n<p>This is not a finished sketch that does anything special. Here I have just listed all the functions for setting the ICM-20948. I thought this could be a good basis for your sketches.&nbsp;<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.<\/p>\n","protected":false},"author":1,"featured_media":12154,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[919,572],"tags":[556,1351,1517,691,558,1539,1538],"class_list":["post-12456","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-acceleration","category-sensors","tag-arduino-en-2","tag-fifo-en","tag-icm-20948-en","tag-interrupt-en-2","tag-library-en-2","tag-wake-on-motion-en","tag-wom-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2021-08-27T19:08:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-01-15T20:34:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"39 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"ICM-20948 9-Axis Sensor Part II\",\"datePublished\":\"2021-08-27T19:08:31+00:00\",\"dateModified\":\"2025-01-15T20:34:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii\"},\"wordCount\":2012,\"commentCount\":15,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"keywords\":[\"Arduino\",\"FIFO\",\"ICM-20948\",\"Interrupt\",\"Library\",\"wake-on-motion\",\"WOM\"],\"articleSection\":[\"Acceleration\",\"Sensors\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii\",\"name\":\"ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"datePublished\":\"2021-08-27T19:08:31+00:00\",\"dateModified\":\"2025-01-15T20:34:22+00:00\",\"description\":\"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"width\":1100,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-ii#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ICM-20948 9-Axis Sensor Part II\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste","description":"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii","og_locale":"en_US","og_type":"article","og_title":"ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste","og_description":"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii","og_site_name":"Wolles Elektronikkiste","article_published_time":"2021-08-27T19:08:31+00:00","article_modified_time":"2025-01-15T20:34:22+00:00","og_image":[{"width":1100,"height":1100,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","type":"image\/png"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"39 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"ICM-20948 9-Axis Sensor Part II","datePublished":"2021-08-27T19:08:31+00:00","dateModified":"2025-01-15T20:34:22+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii"},"wordCount":2012,"commentCount":15,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","keywords":["Arduino","FIFO","ICM-20948","Interrupt","Library","wake-on-motion","WOM"],"articleSection":["Acceleration","Sensors"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii","url":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii","name":"ICM-20948 9-Axis Sensor Part II &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","datePublished":"2021-08-27T19:08:31+00:00","dateModified":"2025-01-15T20:34:22+00:00","description":"This is the second part of my article about the 9-axis sensor ICM-20948. I continue with the presentation of my associated library.","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","width":1100,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"ICM-20948 9-Axis Sensor Part II"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12456","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=12456"}],"version-history":[{"count":2,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12456\/revisions"}],"predecessor-version":[{"id":23010,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12456\/revisions\/23010"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/12154"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=12456"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=12456"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=12456"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}