Skip to content

Commit 38c4fbc

Browse files
samples: sensor: TDK APEX generic sample
It reports Advanced Pedometer and Event Detection features, such as Pedometer, Tilt detection, Wake on Motion and Significant Motion Detector. Device tree options. Signed-off-by: Aurelie Fontaine <[email protected]>
1 parent a42f4d4 commit 38c4fbc

File tree

7 files changed

+391
-0
lines changed

7 files changed

+391
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# Copyright (c) 2024 TDK Invensense
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
9+
project(tdk_apex)
10+
11+
FILE(GLOB app_sources src/*.c)
12+
target_sources(app PRIVATE ${app_sources})

samples/sensor/tdk_apex/README.rst

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
.. zephyr:code-sample:: tdk_apex
2+
:name: TDK Advanced Pedometer and Event Detection (APEX)
3+
:relevant-api: sensor_interface
4+
5+
Get TDK APEX event detection (trigger mode).
6+
7+
Overview
8+
********
9+
10+
This sample application shows how to use the APEX (Advanced Pedometer
11+
and Event Detection) features of TDK Invensense sensors. It consists of:
12+
** Pedometer: Tracks step count, and provide details such as the cadence
13+
and the estimated activity type (Walk, Run, Unknown).
14+
** Tilt Detection: Detects the Tilt when tilting the board with an angle
15+
of 30 degrees or more. The tilt event is generated when the
16+
position is held for 4 seconds.
17+
** Wake on Motion (WoM): Detects motion per axis exceeding 195 mg threshold.
18+
** Significant Motion Detector (SMD): Detects when the user has moved
19+
significantly.
20+
APEX features support are configured through devicetree.
21+
22+
References
23+
**********
24+
25+
- https://invensense.tdk.com/download-pdf/an-000271-icm-42607x-and-icm-42670x-apex-motion-functions-description-and-usage/
26+
27+
Driver configuration
28+
********************
29+
30+
The APEX is based on accelerometer data only. The TDK Sensor driver configures
31+
accelerometer low power mode and the APEX operating frequency (25Hz or 50Hz).
32+
33+
Wiring
34+
*******
35+
36+
This sample uses an external breakout for the sensor. A devicetree
37+
overlay must be provided to identify the TDK sensor, the SPI or I2C bus interface and the interrupt
38+
sensor GPIO.
39+
40+
Building and Running
41+
********************
42+
43+
This sample supports TDK IMU devices. Each device needs
44+
to be aliased as ``tdk-apex-sensorN`` where ``N`` goes from ``0`` to ``9``. For example:
45+
46+
.. code-block:: devicetree
47+
48+
/ {
49+
aliases {
50+
tdk-apex-sensor0 = &icm42670p;
51+
};
52+
};
53+
54+
This sample supports APEX feature of TDK device. It needs to be specified as bellow:
55+
56+
.. code-block:: devicetree
57+
58+
icm42670p: icm42670p@0 {
59+
apex = "pedometer";
60+
}
61+
62+
Make sure the apex feature used is in devicetree, then build and run with:
63+
64+
.. zephyr-app-commands::
65+
:zephyr-app: samples/sensor/tdk_apex
66+
:board: nrf52dk/nrf52832
67+
:goals: build flash
68+
69+
Sample Output
70+
=============
71+
72+
.. code-block:: devicetree
73+
74+
icm42670p: icm42670p@0 {
75+
apex = "pedometer";
76+
}
77+
78+
.. code-block:: console
79+
80+
Found device "icm42670p@68", getting sensor data
81+
[0:00:09.287]: STEP_DET count: 6 steps cadence: 2.0 steps/s activity: Unknown
82+
[0:00:09.689]: STEP_DET count: 7 steps cadence: 2.1 steps/s activity: Walk
83+
[0:00:10.051]: STEP_DET count: 8 steps cadence: 2.2 steps/s activity: Walk
84+
[0:00:10.433]: STEP_DET count: 9 steps cadence: 2.2 steps/s activity: Walk
85+
[0:00:10.835]: STEP_DET count: 10 steps cadence: 2.3 steps/s activity: Walk
86+
87+
<repeats endlessly>
88+
89+
.. code-block:: devicetree
90+
91+
icm42670p: icm42670p@0 {
92+
apex = "tilt";
93+
}
94+
95+
.. code-block:: console
96+
97+
Found device "icm42670p@68", getting sensor data
98+
[0:00:15.249]: TILT
99+
[0:00:21.479]: TILT
100+
[0:00:26.765]: TILT
101+
102+
<repeats endlessly>
103+
104+
.. code-block:: devicetree
105+
106+
icm42670p: icm42670p@0 {
107+
apex = "wom";
108+
}
109+
110+
.. code-block:: console
111+
112+
Found device "icm42670p@68", getting sensor data
113+
[0:00:02.555]: WOM x=1 y=0 z=1
114+
[0:00:02.636]: WOM x=0 y=0 z=1
115+
[0:00:02.797]: WOM x=0 y=1 z=0
116+
[0:00:02.877]: WOM x=0 y=0 z=1
117+
[0:00:02.957]: WOM x=1 y=1 z=1
118+
119+
<repeats endlessly>
120+
121+
.. code-block:: devicetree
122+
123+
icm42670p: icm42670p@0 {
124+
apex = "smd";
125+
}
126+
127+
.. code-block:: console
128+
129+
Found device "icm42670@68", getting sensor data
130+
[0:00:04.622]: SMD
131+
[0:00:05.084]: SMD
132+
[0:00:05.566]: SMD
133+
134+
<repeats endlessly>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2024, TDK Invensense
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*
8+
* Get a node identifier for TDK IMU sensor supporting APEX feature.
9+
*/
10+
/ {
11+
aliases {
12+
tdk-apex-sensor0 = &icm42670p;
13+
};
14+
};
15+
16+
/*
17+
* Example configuration of a ICM42670-P device on i2c0 compatible with an Arduino I2C bus.
18+
*
19+
* Device address 0x68 is assumed. Your device may have a different
20+
* address; check your device documentation if unsure.
21+
*/
22+
&arduino_i2c {
23+
status = "okay";
24+
icm42670p: icm42670p@68 {
25+
compatible = "invensense,icm42670p";
26+
reg = <0x68>;
27+
int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */
28+
accel-hz = <50>;
29+
gyro-hz = <50>;
30+
accel-fs = <16>;
31+
gyro-fs = <2000>;
32+
apex = "pedometer";
33+
};
34+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2024, TDK Invensense
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*
8+
* Get a node identifier for TDK IMU sensor supporting APEX feature.
9+
*/
10+
/ {
11+
aliases {
12+
tdk-apex-sensor0 = &icm42670p;
13+
};
14+
};
15+
16+
/*
17+
* Example configuration of a ICM42670-P device on spi2 compatible with an Arduino SPI bus.
18+
*/
19+
&arduino_spi {
20+
status = "okay";
21+
cs-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
22+
icm42670p: icm42670p@0 {
23+
compatible = "invensense,icm42670p";
24+
reg = <0>;
25+
spi-max-frequency = <1000000>; /* conservatively set to 1MHz */
26+
int-gpios = <&arduino_header 8 GPIO_ACTIVE_HIGH>; /* D2 */
27+
accel-hz = <50>;
28+
gyro-hz = <50>;
29+
accel-fs = <16>;
30+
gyro-fs = <2000>;
31+
apex = "pedometer";
32+
};
33+
};

samples/sensor/tdk_apex/prj.conf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Copyright (c) 2024 TDK Invensense
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
CONFIG_SENSOR=y
8+
CONFIG_LOG=y
9+
CONFIG_SENSOR_LOG_LEVEL_DBG=n
10+
11+
# Floating point format support
12+
# Selecting this increases stack size requirements slightly, but increases code size significantly.
13+
CONFIG_CBPRINTF_FP_SUPPORT=y
14+
15+
# nrf52dk/nrf52832 specific
16+
CONFIG_USE_SEGGER_RTT=n
17+
18+
# Trigger mode: sample is using interrupt triggering
19+
CONFIG_ICM42670_TRIGGER_OWN_THREAD=y
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sample:
2+
name: TDK Sensor APEX sample
3+
tests:
4+
sample.sensor.icm42670.apex:
5+
build_only: true
6+
tags: sensors
7+
filter: dt_alias_exists("tdk_apex_sensor0")
8+
integration_platforms:
9+
- nrf52dk/nrf52832

samples/sensor/tdk_apex/src/main.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2024 TDK Invensense
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/devicetree.h>
10+
#include <zephyr/drivers/sensor.h>
11+
#include <zephyr/drivers/sensor/tdk_apex.h>
12+
#include <stdio.h>
13+
14+
static struct sensor_trigger data_trigger;
15+
16+
/* Flag set from IMU device irq handler */
17+
static volatile int irq_from_device;
18+
19+
/*
20+
* Get a device structure from a devicetree node from alias
21+
* "tdk_apex_sensor0".
22+
*/
23+
static const struct device *get_tdk_apex_device(void)
24+
{
25+
const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(tdk_apex_sensor0));
26+
27+
if (!device_is_ready(dev)) {
28+
printk("\nError: Device \"%s\" is not ready; "
29+
"check the driver initialization logs for errors.\n",
30+
dev->name);
31+
return NULL;
32+
}
33+
34+
printk("Found device \"%s\", getting sensor data\n", dev->name);
35+
return dev;
36+
}
37+
38+
static const char *now_str(void)
39+
{
40+
static char buf[16]; /* ...HH:MM:SS.MMM */
41+
uint32_t now = k_uptime_get_32();
42+
unsigned int ms = now % MSEC_PER_SEC;
43+
unsigned int s;
44+
unsigned int min;
45+
unsigned int h;
46+
47+
now /= MSEC_PER_SEC;
48+
s = now % 60U;
49+
now /= 60U;
50+
min = now % 60U;
51+
now /= 60U;
52+
h = now;
53+
54+
snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u", h, min, s, ms);
55+
return buf;
56+
}
57+
58+
static void handle_tdk_apex_drdy(const struct device *dev, const struct sensor_trigger *trig)
59+
{
60+
if (trig->type == SENSOR_TRIG_MOTION) {
61+
int rc = sensor_sample_fetch_chan(dev, trig->chan);
62+
63+
if (rc < 0) {
64+
printf("sample fetch failed: %d\n", rc);
65+
printf("cancelling trigger due to failure: %d\n", rc);
66+
(void)sensor_trigger_set(dev, trig, NULL);
67+
return;
68+
} else if (rc == 0) {
69+
irq_from_device = 1;
70+
}
71+
}
72+
}
73+
74+
int main(void)
75+
{
76+
const struct device *dev = get_tdk_apex_device();
77+
struct sensor_value apex_mode;
78+
79+
if (dev == NULL) {
80+
return 0;
81+
}
82+
83+
sensor_attr_get(dev, SENSOR_CHAN_APEX_MOTION, SENSOR_ATTR_CONFIGURATION, &apex_mode);
84+
if (apex_mode.val1 == TDK_APEX_PEDOMETER) {
85+
printf("Pedometer data sample.\n");
86+
} else if (apex_mode.val1 == TDK_APEX_TILT) {
87+
printf("Tilt data sample.\n");
88+
} else if (apex_mode.val1 == TDK_APEX_WOM) {
89+
printf("WOM data sample.\n");
90+
} else if (apex_mode.val1 == TDK_APEX_SMD) {
91+
printf("SMD data sample.\n");
92+
}
93+
apex_mode.val2 = 0;
94+
sensor_attr_set(dev, SENSOR_CHAN_APEX_MOTION, SENSOR_ATTR_CONFIGURATION, &apex_mode);
95+
96+
data_trigger = (struct sensor_trigger){
97+
.type = SENSOR_TRIG_MOTION,
98+
.chan = SENSOR_CHAN_APEX_MOTION,
99+
};
100+
if (sensor_trigger_set(dev, &data_trigger, handle_tdk_apex_drdy) < 0) {
101+
printf("Cannot configure data trigger!!!\n");
102+
return 0;
103+
}
104+
105+
printf("Configured for APEX data collecting.\n");
106+
107+
k_sleep(K_MSEC(1000));
108+
109+
while (1) {
110+
111+
if (irq_from_device) {
112+
if (apex_mode.val1 == TDK_APEX_PEDOMETER) {
113+
struct sensor_value apex_pedometer[3];
114+
115+
sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, apex_pedometer);
116+
117+
printf("[%s]: STEP_DET count: %d steps cadence: %.1f steps/s "
118+
"activity: %s\n",
119+
now_str(), apex_pedometer[0].val1,
120+
sensor_value_to_double(&apex_pedometer[2]),
121+
apex_pedometer[1].val1 == 1 ? "Walk"
122+
: apex_pedometer[1].val1 == 2 ? "Run"
123+
: "Unknown");
124+
} else if (apex_mode.val1 == TDK_APEX_TILT) {
125+
struct sensor_value apex_tilt;
126+
127+
sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, &apex_tilt);
128+
129+
printf("[%s]: %s\n", now_str(),
130+
apex_tilt.val1 ? "TILT" : "Unknown trig");
131+
} else if (apex_mode.val1 == TDK_APEX_WOM) {
132+
struct sensor_value apex_wom[3];
133+
134+
sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, apex_wom);
135+
136+
printf("[%s]: WOM x=%d y=%d z=%d\n", now_str(), apex_wom[0].val1,
137+
apex_wom[1].val1, apex_wom[2].val1);
138+
} else if (apex_mode.val1 == TDK_APEX_SMD) {
139+
struct sensor_value apex_smd;
140+
141+
sensor_channel_get(dev, SENSOR_CHAN_APEX_MOTION, &apex_smd);
142+
143+
printf("[%s]: %s\n", now_str(),
144+
apex_smd.val1 ? "SMD" : "Unknown trig");
145+
}
146+
irq_from_device = 0;
147+
}
148+
}
149+
return 0;
150+
}

0 commit comments

Comments
 (0)