Skip to content

Commit b3b4f64

Browse files
sample: adc_stream: Add sample app for ADC stream
Add sample application to demonstrate new ADC stream APIs. Two tests are also added: - ad4052-stream - max32-stream Signed-off-by: Vladislav Pejic <vladislav.pejic@orioninc.com>
1 parent e2969a2 commit b3b4f64

File tree

9 files changed

+274
-0
lines changed

9 files changed

+274
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(adc_stream)
7+
8+
target_sources(app PRIVATE src/main.c)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.. zephyr:code-sample:: adc_stream
2+
:name: Generic ADC stream
3+
:relevant-api: adc_interface
4+
5+
Get data from a ADC using stream.
6+
7+
Overview
8+
********
9+
10+
This sample application demonstrates how to use ADC stream APIs.
11+
12+
Building and Running
13+
********************
14+
15+
This sample supports one ADC. ADC needs to be aliased as ``adc0`` in devicetree.
16+
For example:
17+
18+
.. code-block:: devicetree
19+
20+
/ {
21+
aliases {
22+
adc0 = &ad4052;
23+
};
24+
};
25+
26+
Make sure the aliase are in devicetree, then build and run with:
27+
28+
.. zephyr-app-commands::
29+
:zephyr-app: samples/drivers/adc/adc_stream
30+
:board: <board to use>
31+
:goals: build flash
32+
:compact:
33+
34+
Sample Output
35+
=============
36+
37+
.. code-block:: console
38+
39+
ADC data for adc405@0 (0.000074) 942995000ns
40+
ADC data for adc405@0 (0.000446) 963059000ns
41+
ADC data for adc405@0 (0.000297) 983124000ns
42+
ADC data for adc405@0 (0.000446) 1003189000ns
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) 2025 Analog Devices, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
CONFIG_SPI=y
4+
CONFIG_SPI_RTIO=y
5+
CONFIG_AD405X_STREAM=y
6+
CONFIG_COUNTER=y
7+
CONFIG_COUNTER_TIMER_MAX32=y
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright (c) 2025 Analog Devices, Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
&arduino_spi {
8+
adc4052_eval_ad4052_ardz: adc4052@0 {
9+
sampling-period = <20000>; /*uS*/
10+
};
11+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2025 Analog Devices, Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
aliases {
9+
adc0 = &adc;
10+
};
11+
12+
zephyr,user {
13+
io-channels = <&adc 0>;
14+
};
15+
};
16+
17+
&adc_clk_ext_p0_9 {
18+
power-source = <MAX32_VSEL_VDDIOH>;
19+
};
20+
21+
&adc {
22+
reg = <0x40034000 0x1000>;
23+
pinctrl-0 = <&adc_clk_ext_p0_9>;
24+
pinctrl-names = "default";
25+
26+
/* ADC parameters set up 25KSPS sampling rate */
27+
track-count = <96>;
28+
idle-count = <183>;
29+
30+
#address-cells = <1>;
31+
#size-cells = <0>;
32+
#io-channel-cells = <1>;
33+
status = "okay";
34+
compatible = "adi,max32-adc";
35+
36+
channel@0 {
37+
reg = <0>;
38+
zephyr,gain = "ADC_GAIN_1";
39+
zephyr,reference = "ADC_REF_INTERNAL";
40+
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
41+
zephyr,resolution = <12>;
42+
zephyr,vref-mv = <1250>;
43+
};
44+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright (c) 2025 Analog Devices, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
CONFIG_ADC_MAX32_STREAM=y
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_ADC=y
2+
CONFIG_GPIO=y
3+
CONFIG_ADC_STREAM=y
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
sample:
2+
name: ADC stream sample
3+
common:
4+
tags: adc
5+
harness: console
6+
harness_config:
7+
type: one_line
8+
regex:
9+
- "^ADC data for [^@]+@\\d+ \\([0-9.]+\\) \\d+n$"
10+
tests:
11+
sample.driver.adc_stream:
12+
filter: dt_alias_exists("adc0")
13+
sample.driver.adc_stream.ad4052-stream:
14+
extra_args:
15+
- SHIELD=eval_ad4052_ardz
16+
- EXTRA_CONF_FILE=ad4052-stream.conf
17+
- DTC_OVERLAY_FILE=boards/apard32690_max32690_m4_ad4052.overlay
18+
platform_allow:
19+
- apard32690/max32690/m4
20+
sample.driver.adc_stream.max32-stream:
21+
extra_args:
22+
- EXTRA_CONF_FILE=max32-stream.conf
23+
- DTC_OVERLAY_FILE=boards/apard32690_max32690_m4_max32.overlay
24+
platform_allow:
25+
- apard32690/max32690/m4
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright (c) 2024 Centro de Inovacao EDGE
3+
* Copyright (c) 2025 Analog Devices, Inc.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
10+
#include <zephyr/device.h>
11+
#include <zephyr/drivers/adc.h>
12+
#include <zephyr/sys/util_macro.h>
13+
#include <zephyr/rtio/rtio.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/dsp/print_format.h>
16+
17+
/* ADC node from the devicetree. */
18+
#define ADC_NODE DT_ALIAS(adc0)
19+
20+
#define DT_SPEC_AND_COMMA(node_id, prop, idx) ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
21+
22+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
23+
/* Data of ADC io-channels specified in devicetree. */
24+
static const struct adc_dt_spec adc_channels[] = {
25+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)
26+
};
27+
static const int adc_channels_count = ARRAY_SIZE(adc_channels);
28+
#endif
29+
30+
static void init_adc(void)
31+
{
32+
int i, ret;
33+
34+
ret = adc_is_ready_dt(&adc_channels[0]);
35+
36+
for (i = 0; i < adc_channels_count; i++) {
37+
ret = adc_channel_setup_dt(&adc_channels[i]);
38+
}
39+
}
40+
41+
#define ADC_TRIGGERS \
42+
{ADC_TRIG_FIFO_FULL, ADC_STREAM_DATA_INCLUDE}, \
43+
{ADC_TRIG_FIFO_WATERMARK, ADC_STREAM_DATA_INCLUDE}
44+
45+
ADC_DT_STREAM_IODEV(iodev, ADC_NODE, adc_channels, ADC_TRIGGERS);
46+
47+
RTIO_DEFINE_WITH_MEMPOOL(adc_ctx, 20, 20, 20, 512, sizeof(void *));
48+
49+
static int print_adc_stream(const struct device *dev, struct rtio_iodev *local_iodev)
50+
{
51+
int rc = 0;
52+
const struct adc_decoder_api *decoder;
53+
struct rtio_cqe *cqe;
54+
uint8_t *buf;
55+
uint32_t buf_len;
56+
struct rtio_sqe *handles;
57+
58+
/* Start the streams */
59+
adc_stream(local_iodev, &adc_ctx, NULL, &handles);
60+
61+
while (1) {
62+
cqe = rtio_cqe_consume_block(&adc_ctx);
63+
64+
if (cqe->result != 0) {
65+
printk("async read failed %d\n", cqe->result);
66+
return cqe->result;
67+
}
68+
69+
rc = rtio_cqe_get_mempool_buffer(&adc_ctx, cqe, &buf, &buf_len);
70+
71+
if (rc != 0) {
72+
printk("get mempool buffer failed %d\n", rc);
73+
return rc;
74+
}
75+
76+
const struct device *adc = dev;
77+
78+
rtio_cqe_release(&adc_ctx, cqe);
79+
80+
rc = adc_get_decoder(adc, &decoder);
81+
82+
if (rc != 0) {
83+
printk("sensor_get_decoder failed %d\n", rc);
84+
return rc;
85+
}
86+
87+
/* Frame iterator values when data comes from a FIFO */
88+
uint32_t adc_fit = 0;
89+
struct adc_data adc_data = {0};
90+
91+
/* Number of accelerometer data frames */
92+
uint16_t frame_count;
93+
94+
rc = decoder->get_frame_count(buf, 0, &frame_count);
95+
96+
if (rc != 0) {
97+
printk("get_frame_count failed %d\n", rc);
98+
return rc;
99+
}
100+
101+
/* Decode all available accelerometer sample frames */
102+
for (int i = 0; i < frame_count; i++) {
103+
decoder->decode(buf, 0, &adc_fit, 1, &adc_data);
104+
105+
printk("ADC data for %s (%" PRIq(6) ") %lluns\n", dev->name,
106+
PRIq_arg(adc_data.readings[0].value, 6, adc_data.shift),
107+
(adc_data.header.base_timestamp_ns
108+
+ adc_data.readings[0].timestamp_delta));
109+
}
110+
111+
rtio_release_buffer(&adc_ctx, buf, buf_len);
112+
}
113+
114+
return rc;
115+
}
116+
117+
int main(void)
118+
{
119+
int ret;
120+
struct adc_sequence sequence;
121+
struct adc_read_config *read_cfg = iodev.data;
122+
123+
read_cfg->sequence = &sequence;
124+
125+
init_adc();
126+
(void)adc_sequence_init_dt(&adc_channels[0], &sequence);
127+
128+
ret = print_adc_stream(adc_channels[0].dev, &iodev);
129+
130+
return ret;
131+
}

0 commit comments

Comments
 (0)